summaryrefslogtreecommitdiffstats
path: root/deluge/metafile.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/metafile.py')
-rw-r--r--deluge/metafile.py246
1 files changed, 246 insertions, 0 deletions
diff --git a/deluge/metafile.py b/deluge/metafile.py
new file mode 100644
index 0000000..8c28c7e
--- /dev/null
+++ b/deluge/metafile.py
@@ -0,0 +1,246 @@
+# -*- 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 <andrewresch@gmail.com>
+#
+# 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