#!/usr/bin/env python3 import sys import os import os.path import glob from hashlib import sha1 from io import BytesIO from torrentool.api import Torrent """ 'announce_urls', 'comment', 'create_from', 'created_by', 'creation_date', 'files', 'from_file', 'from_string', 'get_magnet', 'httpseeds', 'info_hash', 'magnet_link', 'name', 'private', 'to_file', 'to_string', 'total_size', 'webseeds'] """ ARG_OPTIONS = {'short': False, 'files': False, 'existing': False, 'non-existing': False, 'validate': False} def make_blob(buffer, fileinfo): if os.path.exists(fileinfo[0]): with open(fileinfo[0], 'rb') as datafd: num_written = buffer.write(datafd.read()) else: num_written = buffer.write(b'\x00' * fileinfo[1]) return num_written def parse_torrent_file(torrentfile): buffer = BytesIO() torrent = Torrent.from_file(torrentfile) print('+- Torrent : {}'.format(os.path.basename(torrentfile))) print('| Title : {}'.format(torrent.name)) info_struct = torrent._struct.get('info') print('| Piece Len: {:,} Bytes'.format(info_struct['piece length'])) try: print('| Size : {:,} Bytes'.format(torrent.total_size)) except: print('| Size : {}'.format('n/a')) if not ARG_OPTIONS['short']: print('| Comment : {}'.format(torrent.comment or 'n/a')) print('| Created : {}'.format(torrent.creation_date or 'n/a')) print('| Hash : {}'.format(torrent.info_hash)) if torrent.comment: print('| Comment : {}'.format(torrent.comment)) if len(torrent.httpseeds) > 0: print('| httpseeds: {}'.format(torrent.httpseeds)) if len(torrent.webseeds) > 0: print('| webseeds : {}'.format(torrent.webseeds)) if ARG_OPTIONS['files']: # TODO: move to separate print file detail method num_written = 0 for index, fileinfo in enumerate(torrent.files): if ARG_OPTIONS['validate']: num_written += make_blob(buffer, fileinfo) if ARG_OPTIONS['existing']: if os.path.exists(fileinfo[0]): print('| FOUND [{:4}] name = {} (size = {:,} Bytes)'.format(index, fileinfo[0], fileinfo[1])) elif ARG_OPTIONS['non-existing']: print('| MISSING [{:4}] name = {} (size = {:,} Bytes)'.format(index, fileinfo[0], fileinfo[1])) if ARG_OPTIONS['validate']: pieceshash = info_struct['pieces'] buffer.seek(0) print('| Validation:') chunk_size = info_struct['piece length'] chunk = buffer.read(chunk_size) chunk_hashes = [] while len(chunk) > 0: hashcalc = sha1() hashcalc.update(chunk) chunk_hashes.append(hashcalc.digest()) chunk = buffer.read(chunk_size) out_wrap = 0 completed = True sys.stdout.write('| ') for digest in chunk_hashes: out_wrap += 1 if digest in pieceshash: sys.stdout.write('▒') else: completed = False sys.stdout.write('░') if not(out_wrap % 64): sys.stdout.write('\n| ') sys.stdout.write('\n') print('| Completed: {}'.format(completed)) if __name__ == '__main__': try: for option in ARG_OPTIONS.keys(): if '--' + option in sys.argv: ARG_OPTIONS[option] = not ARG_OPTIONS[option] sys.argv.remove('--' + option) if len(sys.argv) <= 1 or len(sys.argv) > 2: raise IndexError scan_path = sys.argv[-1] if os.name == 'nt': if not scan_path[-1] == '\\' and os.path.isdir(scan_path): scan_path += '\\' scan_path = scan_path.replace('\\', '\\') else: if not scan_path[-1] == '/' and os.path.isdir(scan_path): scan_path += '/' except IndexError: print('Not enough parameters.\n Usage: {} [--short|--files] '.format(sys.argv[0])) sys.exit(1) if os.path.isdir(scan_path): for index, torrentfile in enumerate(glob.glob(scan_path + '*.torrent')): parse_torrent_file(torrentfile) try: print('Found {} .torrent files.'.format(index+1)) except NameError: print('No valid files found.') sys.exit(1) else: parse_torrent_file(scan_path)