# -*- coding: utf-8 -*- # # Original file from BitTorrent-5.3-GPL.tar.gz # Copyright (C) Bram Cohen # # Modifications for use in Deluge: # Copyright (C) 2007 Andrew Resch # # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # from __future__ import division, unicode_literals import logging import os.path import time from hashlib import sha1 as sha import deluge.component as component from deluge.bencode import bencode from deluge.common import utf8_encode_structure from deluge.event import CreateTorrentProgressEvent log = logging.getLogger(__name__) ignore = ['core', 'CVS', 'Thumbs.db', 'desktop.ini'] noncharacter_translate = {} for i in range(0xD800, 0xE000): noncharacter_translate[i] = ord('-') for i in range(0xFDD0, 0xFDF0): noncharacter_translate[i] = ord('-') for i in (0xFFFE, 0xFFFF): noncharacter_translate[i] = ord('-') def gmtime(): return time.mktime(time.gmtime()) def dummy(*v): pass class RemoteFileProgress(object): def __init__(self, session_id): self.session_id = session_id def __call__(self, piece_count, num_pieces): component.get('RPCServer').emit_event_for_session_id( self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces) ) def make_meta_file( path, url, piece_length, progress=None, title=None, comment=None, safe=None, content_type=None, target=None, webseeds=None, name=None, private=False, created_by=None, trackers=None, ): data = {'creation date': int(gmtime())} if url: data['announce'] = url.strip() a, b = os.path.split(path) if not target: if b == '': f = a + '.torrent' else: f = os.path.join(a, b + '.torrent') else: f = target if progress is None: progress = dummy try: session_id = component.get('RPCServer').get_session_id() except KeyError: pass else: if session_id: progress = RemoteFileProgress(session_id) info = makeinfo(path, piece_length, progress, name, content_type, private) # check_info(info) data['info'] = info if title: data['title'] = title.encode('utf8') if comment: data['comment'] = comment.encode('utf8') if safe: data['safe'] = safe.encode('utf8') httpseeds = [] url_list = [] if webseeds: for webseed in webseeds: if webseed.endswith('.php'): httpseeds.append(webseed) else: url_list.append(webseed) if url_list: data['url-list'] = url_list if httpseeds: data['httpseeds'] = httpseeds if created_by: data['created by'] = created_by.encode('utf8') if trackers and (len(trackers[0]) > 1 or len(trackers) > 1): data['announce-list'] = trackers data['encoding'] = 'UTF-8' with open(f, 'wb') as file_: file_.write(bencode(utf8_encode_structure(data))) def calcsize(path): total = 0 for s in subfiles(os.path.abspath(path)): total += os.path.getsize(s[1]) return total def makeinfo(path, piece_length, progress, name=None, content_type=None, private=False): # HEREDAVE. If path is directory, how do we assign content type? path = os.path.abspath(path) piece_count = 0 if os.path.isdir(path): subs = sorted(subfiles(path)) pieces = [] sh = sha() done = 0 fs = [] totalsize = 0.0 totalhashed = 0 for p, f in subs: totalsize += os.path.getsize(f) if totalsize >= piece_length: import math num_pieces = math.ceil(totalsize / piece_length) else: num_pieces = 1 for p, f in subs: pos = 0 size = os.path.getsize(f) p2 = [n.encode('utf8') for n in p] if content_type: fs.append( {'length': size, 'path': p2, 'content_type': content_type} ) # HEREDAVE. bad for batch! else: fs.append({'length': size, 'path': p2}) with open(f, 'rb') as file_: while pos < size: a = min(size - pos, piece_length - done) sh.update(file_.read(a)) done += a pos += a totalhashed += a if done == piece_length: pieces.append(sh.digest()) piece_count += 1 done = 0 sh = sha() progress(piece_count, num_pieces) if done > 0: pieces.append(sh.digest()) piece_count += 1 progress(piece_count, num_pieces) if not name: name = os.path.split(path)[1] return { 'pieces': b''.join(pieces), 'piece length': piece_length, 'files': fs, 'name': name.encode('utf8'), 'private': private, } else: size = os.path.getsize(path) if size >= piece_length: num_pieces = size // piece_length else: num_pieces = 1 pieces = [] p = 0 with open(path, 'rb') as _file: while p < size: x = _file.read(min(piece_length, size - p)) pieces.append(sha(x).digest()) piece_count += 1 p += piece_length if p > size: p = size progress(piece_count, num_pieces) name = os.path.split(path)[1].encode('utf8') if content_type is not None: return { 'pieces': b''.join(pieces), 'piece length': piece_length, 'length': size, 'name': name, 'content_type': content_type, 'private': private, } return { 'pieces': b''.join(pieces), 'piece length': piece_length, 'length': size, 'name': name, 'private': private, } def subfiles(d): r = [] stack = [([], d)] while stack: p, n = stack.pop() if os.path.isdir(n): for s in os.listdir(n): if s not in ignore and not s.startswith('.'): stack.append((p + [s], os.path.join(n, s))) else: r.append((p, n)) return r