pytorrentinfo/pytorrentinfo.py

123 lines
4.6 KiB
Python
Executable File

#!/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] <directory|filename>'.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)