diff --git a/deluge/common.py b/deluge/common.py index 8b92e014f..1cd1795b9 100644 --- a/deluge/common.py +++ b/deluge/common.py @@ -46,6 +46,7 @@ import logging import pkg_resources import gettext import locale +import base64 try: import json @@ -499,6 +500,48 @@ def is_magnet(uri): return True return False +def get_magnet_info(uri): + """ + Return information about a magnet link. + + :param uri: the magnet link + :type uri: string + + :returns: information about the magnet link: + + :: + + { + "name": the torrent name, + "info_hash": the torrents info_hash, + "files_tree": empty value for magnet links + } + + :rtype: dictionary + """ + magnet_scheme = 'magnet:?' + xt_param = 'xt=urn:btih:' + dn_param = 'dn=' + if uri.startswith(magnet_scheme): + name = None + info_hash = None + for param in uri[len(magnet_scheme):].split('&'): + if param.startswith(xt_param): + xt_hash = param[len(xt_param):] + if len(xt_hash) == 32: + info_hash = base64.b32decode(xt_hash).encode("hex") + elif len(xt_hash) == 40: + info_hash = xt_hash + else: + break + elif param.startswith(dn_param): + name = unquote_plus(param[len(dn_param):]) + + if info_hash: + if not name: + name = info_hash + return {"name":name, "info_hash":info_hash, "files_tree":''} + return False def create_magnet_uri(infohash, name=None, trackers=[]): """ diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index f6bb826a8..c5b15c9e3 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -111,6 +111,7 @@ class TorrentOptions(dict): file_priorities (list of int): The priority for files in torrent, range is [0..7] however only [0, 1, 5, 7] are normally used and correspond to [Do Not Download, Normal, High, Highest] mapped_files (dict): A mapping of the renamed filenames in 'index:filename' pairs. + name (str): The name of the torrent ''' def __init__(self): config = ConfigManager("core.conf").config @@ -139,6 +140,7 @@ class TorrentOptions(dict): self["file_priorities"] = [] self["mapped_files"] = {} self["owner"] = None + self["name"] = None class Torrent(object): @@ -252,19 +254,20 @@ class Torrent(object): options = options.copy() # set_prioritize_first_last is called by set_file_priorities so only run if not in options + skip_func = [] if "file_priorities" in options: self.options["prioritize_first_last_pieces"] = options["prioritize_first_last_pieces"] - del options["prioritize_first_last_pieces"] + skip_func.append("prioritize_first_last_pieces") for key, value in options.items(): if key in self.options: options_set_func = getattr(self, "set_" + key, None) - if options_set_func: + if options_set_func and key not in skip_func: options_set_func(value) del options[key] else: # Update config options that do not have funcs - self.options.update({key:value}) + self.options[key] = value def get_options(self): return self.options @@ -724,6 +727,22 @@ class Torrent(object): return status_dict + def get_name(self): + ''' Return the name of the torrent + + Can be set through options + :return: the name + :rtype: str + ''' + if not self.options['name']: + handle_name = self.handle.name() + if handle_name: + return decode_string(handle_name) + else: + return self.torrent_id + else: + return self.options['name'] + def update_status(self, status): """ Updates the cached status. @@ -812,24 +831,6 @@ class Torrent(object): "priority": lambda: self.status.priority, } - def get_name(self): - if self.has_metadata: - name = self.torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0] - if not name: - name = self.torrent_info.name() - return decode_string(name) - elif self.magnet: - try: - keys = dict([k.split('=') for k in self.magnet.split('?')[-1].split('&')]) - name = keys.get('dn') - if not name: - return self.torrent_id - name = unquote(name).replace('+', ' ') - return decode_string(name) - except: - pass - return self.torrent_id - def pause(self): """Pause this torrent""" # Turn off auto-management so the torrent will not be unpaused by lt queueing diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index 03239cd86..67b4c21bc 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -57,7 +57,7 @@ import deluge.component as component from deluge.configmanager import ConfigManager, get_config_dir from deluge.core.authmanager import AUTH_LEVEL_ADMIN from deluge.core.torrent import Torrent, TorrentOptions, sanitize_filepath -from deluge.common import utf8_encoded, decode_string +from deluge.common import utf8_encoded, decode_string, get_magnet_info log = logging.getLogger(__name__) @@ -89,7 +89,8 @@ class TorrentState: owner=None, shared=False, super_seeding=False, - priority=0 + priority=0, + name=None ): self.torrent_id = torrent_id self.filename = filename @@ -119,6 +120,7 @@ class TorrentState: self.super_seeding = super_seeding self.priority = priority self.owner = owner + self.name = name class TorrentManagerState: def __init__(self): @@ -358,6 +360,7 @@ class TorrentManager(component.Component): options["super_seeding"] = state.super_seeding options["priority"] = state.priority options["owner"] = state.owner + options["name"] = state.name torrent_info = self.get_torrent_info_from_file( os.path.join(self.state_dir, state.torrent_id + ".torrent")) @@ -457,7 +460,18 @@ class TorrentManager(component.Component): add_torrent_params["flags"] |= lt.add_torrent_params_flags_t.flag_seed_mode if magnet: - add_torrent_params["url"] = utf8_encoded(magnet) + magnet_info = get_magnet_info(magnet) + if magnet_info: + add_torrent_params['url'] = utf8_encoded(magnet) + add_torrent_params['name'] = magnet_info['name'] + + if options['name']: + add_torrent_params['name'] = options['name'] + elif torrent_info: + name = torrent_info.name() + if not name: + name = torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0] + add_torrent_params['name'] = name # We need to pause the AlertManager momentarily to prevent alerts # for this torrent being generated before a Torrent object is created. @@ -698,7 +712,8 @@ class TorrentManager(component.Component): torrent.options["owner"], torrent.options["shared"], torrent.options["super_seeding"], - torrent.options["priority"] + torrent.options["priority"], + torrent.options["name"] ) state.torrents.append(torrent_state)