diff --git a/test.py b/test.py index 9add257..f86908f 100644 --- a/test.py +++ b/test.py @@ -26,24 +26,18 @@ class Test(unittest.TestCase): def test_parse_correctness(self): data = parse_torrent_file(self.TEST_FILENAME) - self.assertIn(['udp://p4p.arenabg.ch:1337/announce'], + self.assertIn(['udp://tracker.publicbt.com:80/announce'], data['announce-list']) - self.assertEqual(data['comment'], - 'Torrent downloaded from https://rarbg.to') - self.assertEqual(data['creation date'], 1472762993) + self.assertEqual(data['creation date'], 1409254242) def test_parse_two_times(self): with open(self.TEST_FILENAME, 'rb') as fp: parser = TorrentFileParser(fp) data = parser.parse() - self.assertIn(['udp://p4p.arenabg.ch:1337/announce'], + self.assertIn(['udp://tracker.publicbt.com:80/announce'], data['announce-list']) - self.assertEqual(data['comment'], - 'Torrent downloaded from https://rarbg.to') - self.assertEqual(data['creation date'], 1472762993) + self.assertEqual(data['creation date'], 1409254242) data = parser.parse() - self.assertIn(['udp://p4p.arenabg.ch:1337/announce'], + self.assertIn(['udp://tracker.publicbt.com:80/announce'], data['announce-list']) - self.assertEqual(data['comment'], - 'Torrent downloaded from https://rarbg.to') - self.assertEqual(data['creation date'], 1472762993) + self.assertEqual(data['creation date'], 1409254242) diff --git a/test.torrent b/test.torrent index fc49690..1343392 100644 Binary files a/test.torrent and b/test.torrent differ diff --git a/torrent_parser.py b/torrent_parser.py index 9e41049..e4f4b30 100644 --- a/torrent_parser.py +++ b/torrent_parser.py @@ -7,9 +7,9 @@ A .torrent file parser for both Python 2 and 3 Usage: data = parse_torrent_file(filename) - + # or - + with open(filename, 'rb') as f: # the binary mode 'b' is necessary data = TorrentFileParser(f).parse() """ @@ -62,7 +62,7 @@ class TorrentFileParser(object): def __init__(self, fp, use_ordered_dict=False, encoding='utf-8'): """ - :param fp: a **binary** file-like object to parse, + :param fp: a **binary** file-like object to parse, which means need 'b' mode when use built-in open function :param encoding: file content encoding, default utf-8 :param use_ordered_dict: Use collections.OrderedDict as dict container @@ -126,7 +126,11 @@ class TorrentFileParser(object): except InvalidTorrentFileException: return if k == 'pieces': - v = self._pieces() + v = self._next_hash() + elif k == 'ed2k': + v = self._next_hash(16, False) + elif k == 'filehash': + v = self._next_hash(20, False) else: v = self._next_element() if k == 'encoding': @@ -173,14 +177,19 @@ class TorrentFileParser(object): def __to_hex(v): return hex(ord(v) if isinstance(v, str) else v)[2:].rjust(2, str(0)) - def _pieces(self): + def _next_hash(self, p_len=20, need_list=True): raw = self._next_string(decode=False) - if len(raw) % 20 != 0: + if len(raw) % p_len != 0: raise InvalidTorrentFileException(self._pos) - return [ + res = [ ''.join([self.__to_hex(c) for c in h]) - for h in (raw[x:x+20] for x in range(0, len(raw), 20)) + for h in (raw[x:x+p_len] for x in range(0, len(raw), p_len)) ] + if len(res) == 0 and not need_list: + return '' + if len(res) == 1 and not need_list: + return res[0] + return res def _next_end(self): raise InvalidTorrentFileException(self._pos) @@ -206,7 +215,7 @@ class TorrentFileParser(object): def parse_torrent_file(filename, use_ordered_dict=False): """ Shortcut function for parse torrent object use TorrentFileParser - + :param string filename: torrent filename :param bool use_ordered_dict: see :any:`TorrentFileParser.__init__` :rtype: dict if ``use_ordered_dict`` is false, @@ -229,6 +238,8 @@ def __main(): parser.add_argument('--ascii', '-a', action='store_true', default=False, help='ensure output json use ascii char, ' 'escape other char use \\u') + parser.add_argument('--coding', '-c', default='utf-8', + help='string encoding, default utf-8') parser.add_argument('--version', '-v', action='store_true', default=False, help='print version and exit') args = parser.parse_args() @@ -249,7 +260,7 @@ def __main(): exit(1) # noinspection PyUnboundLocalVariable - data = TorrentFileParser(target_file, not args.dict).parse() + data = TorrentFileParser(target_file, not args.dict, args.coding).parse() data = json.dumps( data, ensure_ascii=args.ascii,