diff --git a/deluge/core/core.py b/deluge/core/core.py index 786bbaa44..21d900f75 100644 --- a/deluge/core/core.py +++ b/deluge/core/core.py @@ -376,7 +376,7 @@ class Core( } - def export_add_torrent_url(self, url, save_path, options): + def export_add_torrent_url(self, url, options): log.info("Attempting to add url %s", url) # Get the actual filename of the torrent from the url provided. @@ -398,6 +398,14 @@ class Core( return self.export_add_torrent_file( filename, filedump, options) + def export_add_torrent_magnets(self, uris, options): + for uri in uris: + log.debug("Attempting to add by magnet uri: %s", uri) + torrent_id = self.torrents.add(magnet=uri, options=options[uris.index(uri)]) + + # Run the plugin hooks for 'post_torrent_add' + self.plugins.run_post_torrent_add(torrent_id) + def export_remove_torrent(self, torrent_ids, remove_torrent, remove_data): log.debug("Removing torrent %s from the core.", torrent_ids) for torrent_id in torrent_ids: diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index b6e9bebd1..dd858b9a0 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -80,12 +80,20 @@ class Torrent: self.torrent_id = str(handle.info_hash()) # We store the filename just in case we need to make a copy of the torrentfile + if not filename: + # If no filename was provided, then just use the infohash + filename = self.torrent_id + self.filename = filename # Holds status info so that we don't need to keep getting it from lt self.status = self.handle.status() - self.torrent_info = self.handle.get_torrent_info() + try: + self.torrent_info = self.handle.get_torrent_info() + except RuntimeError: + self.torrent_info = None + # Files dictionary self.files = self.get_files() @@ -188,12 +196,13 @@ class Torrent: def set_prioritize_first_last(self, prioritize): self.options["prioritize_first_last_pieces"] = prioritize if prioritize: - if self.handle.get_torrent_info().num_files() == 1: - # We only do this if one file is in the torrent - priorities = [1] * self.handle.get_torrent_info().num_pieces() - priorities[0] = 7 - priorities[-1] = 7 - self.handle.prioritize_pieces(priorities) + if self.handle.has_metadata(): + if self.handle.get_torrent_info().num_files() == 1: + # We only do this if one file is in the torrent + priorities = [1] * self.handle.get_torrent_info().num_pieces() + priorities[0] = 7 + priorities[-1] = 7 + self.handle.prioritize_pieces(priorities) def set_auto_managed(self, auto_managed): self.options["auto_managed"] = auto_managed @@ -348,11 +357,14 @@ class Torrent: def get_files(self): """Returns a list of files this torrent contains""" - if self.torrent_info == None: + if self.torrent_info == None and self.handle.has_metadata(): torrent_info = self.handle.get_torrent_info() else: torrent_info = self.torrent_info - + + if not torrent_info: + return [] + ret = [] files = torrent_info.files() for index, file in enumerate(files): @@ -438,7 +450,8 @@ class Torrent: """Returns the status of the torrent based on the keys provided""" # Create the full dictionary self.status = self.handle.status() - self.torrent_info = self.handle.get_torrent_info() + if self.handle.has_metadata(): + self.torrent_info = self.handle.get_torrent_info() # Adjust progress to be 0-100 value progress = self.status.progress * 100 @@ -490,14 +503,39 @@ class Torrent: "move_on_completed": self.options["move_completed"], "move_on_completed_path": self.options["move_completed_path"] } - + + def ti_name(): + if self.handle.has_metadata(): + return self.torrent_info.name() + return self.torrent_id + def ti_priv(): + if self.handle.has_metadata(): + return self.torrent_info.priv() + return False + def ti_total_size(): + if self.handle.has_metadata(): + return self.torrent_info.total_size() + return 0 + def ti_num_files(): + if self.handle.has_metadata(): + return self.torrent_info.num_files() + return 0 + def ti_num_pieces(): + if self.handle.has_metadata(): + return self.torrent_info.num_pieces() + return 0 + def ti_piece_length(): + if self.handle.has_metadata(): + return self.torrent_info.piece_length() + return 0 + fns = { - "name": self.torrent_info.name, - "private": self.torrent_info.priv, - "total_size": self.torrent_info.total_size, - "num_files": self.torrent_info.num_files, - "num_pieces": self.torrent_info.num_pieces, - "piece_length": self.torrent_info.piece_length, + "name": ti_name, + "private": ti_priv, + "total_size": ti_total_size, + "num_files": ti_num_files, + "num_pieces": ti_num_pieces, + "piece_length": ti_piece_length, "eta": self.get_eta, "ratio": self.get_ratio, "file_progress": self.get_file_progress, @@ -507,9 +545,6 @@ class Torrent: "tracker_host": self.get_tracker_host } - self.status = None - self.torrent_info = None - # Create the desired status dictionary and return it status_dict = {} @@ -524,6 +559,9 @@ class Torrent: elif key in fns: status_dict[key] = fns[key]() + self.status = None + self.torrent_info = None + return status_dict def apply_options(self): diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py index fe8f20154..2cd74ffd1 100644 --- a/deluge/core/torrentmanager.py +++ b/deluge/core/torrentmanager.py @@ -239,11 +239,11 @@ class TorrentManager(component.Component): return str(fastresume) def add(self, torrent_info=None, state=None, options=None, save_state=True, - filedump=None, filename=None): + filedump=None, filename=None, magnet=None): """Add a torrent to the manager and returns it's torrent_id""" - if torrent_info is None and state is None and filedump is None: - log.debug("You must specify a valid torrent_info or a torrent state object!") + if torrent_info is None and state is None and filedump is None and magnet is None: + log.debug("You must specify a valid torrent_info, torrent state or magnet.") return log.debug("torrentmanager.add") @@ -255,12 +255,12 @@ class TorrentManager(component.Component): except Exception, e: log.error("Unable to decode torrent file!: %s", e) - if torrent_info is None: + if torrent_info is None and state: # We have no torrent_info so we need to add the torrent with information # from the state object. # Populate the options dict from state - options = OPTIONS + options = OPTIONS.copy() options["max_connections"] = state.max_connections options["max_upload_slots"] = state.max_upload_slots options["max_upload_speed"] = state.max_upload_speed @@ -284,9 +284,9 @@ class TorrentManager(component.Component): # We have a torrent_info object so we're not loading from state. # Check if options is None and load defaults if options == None: - options = OPTIONS + options = OPTIONS.copy() else: - o = OPTIONS + o = OPTIONS.copy() o.update(options) options = o @@ -316,7 +316,10 @@ class TorrentManager(component.Component): handle = None try: - handle = self.session.add_torrent(add_torrent_params) + if magnet: + handle = lt.add_magnet_uri(self.session, magnet, add_torrent_params) + else: + handle = self.session.add_torrent(add_torrent_params) except RuntimeError, e: log.warning("Error adding torrent: %s", e) diff --git a/deluge/ui/client.py b/deluge/ui/client.py index 68fb5c989..69662a3f9 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -169,7 +169,7 @@ class BaseClient(object): "set_torrent_prioritize_first_last", "set_torrent_auto_managed", "set_torrent_stop_ratio", "set_torrent_stop_at_ratio", "set_torrent_remove_at_ratio", "set_torrent_move_on_completed", - "set_torrent_move_on_completed_path"] + "set_torrent_move_on_completed_path", "add_torrent_magnets"] def __init__(self): self.core = _core diff --git a/deluge/ui/gtkui/addtorrentdialog.py b/deluge/ui/gtkui/addtorrentdialog.py index 134e3a97c..133a3696d 100644 --- a/deluge/ui/gtkui/addtorrentdialog.py +++ b/deluge/ui/gtkui/addtorrentdialog.py @@ -61,6 +61,7 @@ class AddTorrentDialog(component.Component): "on_button_file_clicked": self._on_button_file_clicked, "on_button_url_clicked": self._on_button_url_clicked, "on_button_hash_clicked": self._on_button_hash_clicked, + "on_button_magnet_clicked": self._on_button_magnet_clicked, "on_button_remove_clicked": self._on_button_remove_clicked, "on_button_trackers_clicked": self._on_button_trackers_clicked, "on_button_cancel_clicked": self._on_button_cancel_clicked, @@ -69,6 +70,9 @@ class AddTorrentDialog(component.Component): "on_button_revert_clicked": self._on_button_revert_clicked }) + self.glade.get_widget("image_magnet").set_from_file( + deluge.common.get_pixmap("magnet.png")) + self.torrent_liststore = gtk.ListStore(str, str, str) #download?, path, filesize, sequence number, inconsistent? self.files_treestore = gtk.TreeStore(bool, str, gobject.TYPE_UINT64, @@ -229,6 +233,29 @@ class AddTorrentDialog(component.Component): if not row and new_row: self.listview_torrents.get_selection().select_iter(new_row) + def add_from_magnets(self, uris): + import base64 + new_row = None + + for uri in uris: + info_hash = base64.b32decode(uri.split("&")[0][20:]).encode("hex") + if info_hash in self.infos: + log.debug("Torrent already in list!") + continue + name = None + for i in uri.split("&"): + if i[:3] == "dn=": + name = "%s (%s)" % (i.split("=")[1], uri) + if not name: + name = uri + new_row = self.torrent_liststore.append( + [info_hash, name, uri]) + self.files[info_hash] = [] + self.infos[info_hash] = None + (model, row) = self.listview_torrents.get_selection().get_selected() + if not row and new_row: + self.listview_torrents.get_selection().select_iter(new_row) + def _on_torrent_changed(self, treeselection): (model, row) = treeselection.get_selected() self.files_treestore.clear() @@ -346,8 +373,6 @@ class AddTorrentDialog(component.Component): self.glade.get_widget("chk_paused").get_active() options["prioritize_first_last_pieces"] = \ self.glade.get_widget("chk_prioritize").get_active() - options["default_private"] = \ - self.glade.get_widget("chk_private").get_active() self.options[torrent_id] = options @@ -542,6 +567,46 @@ class AddTorrentDialog(component.Component): def _on_button_hash_clicked(self, widget): log.debug("_on_button_hash_clicked") + def _on_button_magnet_clicked(self, widget): + log.debug("_on_button_magnet_clicked") + dialog = self.glade.get_widget("dialog_magnet") + entry = self.glade.get_widget("entry_magnet") + self.glade.get_widget("image_dialog_magnet").set_from_file( + deluge.common.get_pixmap("magnet.png")) + + dialog.set_default_response(gtk.RESPONSE_OK) + dialog.set_transient_for(self.dialog) + entry.grab_focus() + + if deluge.common.windows_check(): + import win32clipboard as clip + import win32con + clip.OpenClipboard() + text = clip.GetClipboardData(win32con.CF_UNICODETEXT) + clip.CloseClipboard() + else: + clip = gtk.clipboard_get(selection='PRIMARY') + text = clip.wait_for_text() + if text: + text = text.strip() + if text[:20] == "magnet:?xt=urn:btih:": + entry.set_text(text) + + dialog.show_all() + response = dialog.run() + + if response == gtk.RESPONSE_OK: + uri = entry.get_text().decode("utf_8") + else: + uri = None + + log.debug("magnet uri: %s", uri) + if uri: + self.add_from_magnets([uri]) + + entry.set_text("") + dialog.hide() + def _on_button_remove_clicked(self, widget): log.debug("_on_button_remove_clicked") (model, row) = self.listview_torrents.get_selection().get_selected() @@ -569,6 +634,8 @@ class AddTorrentDialog(component.Component): self.save_torrent_options(row) torrent_filenames = [] + torrent_magnets = [] + torrent_magnet_options = [] torrent_options = [] row = self.torrent_liststore.get_iter_first() @@ -583,14 +650,23 @@ class AddTorrentDialog(component.Component): file_priorities = self.get_file_priorities(torrent_id) if options != None: options["file_priorities"] = file_priorities - - torrent_filenames.append(filename) - torrent_options.append(options) + + if filename[:20] == "magnet:?xt=urn:btih:": + torrent_magnets.append(filename) + del options["file_priorities"] + torrent_magnet_options.append(options) + else: + torrent_filenames.append(filename) + torrent_options.append(options) row = self.torrent_liststore.iter_next(row) - - client.add_torrent_file(torrent_filenames, torrent_options) - client.force_call() + + if torrent_filenames: + client.add_torrent_file(torrent_filenames, torrent_options) + if torrent_magnets: + client.add_torrent_magnets(torrent_magnets, torrent_magnet_options) + + client.force_call(False) self.hide() def _on_button_apply_clicked(self, widget): diff --git a/deluge/ui/gtkui/glade/add_torrent_dialog.glade b/deluge/ui/gtkui/glade/add_torrent_dialog.glade index 53eea8a74..305c367f6 100644 --- a/deluge/ui/gtkui/glade/add_torrent_dialog.glade +++ b/deluge/ui/gtkui/glade/add_torrent_dialog.glade @@ -1,6 +1,6 @@ - + 560 @@ -142,7 +142,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - From _File + _File True @@ -189,7 +189,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - From _URL + _URL True @@ -209,6 +209,7 @@ + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -236,7 +237,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - From _Hash + Info_hash True @@ -254,6 +255,39 @@ 2 + + + True + True + True + 0 + + + + True + + + True + + + + + True + _Magnet URI + True + True + + + 1 + + + + + + + 3 + + True @@ -297,7 +331,7 @@ False False - 3 + 4 @@ -537,7 +571,7 @@ 2 10 - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -547,78 +581,8 @@ 1 2 - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Max Down Speed: - - - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Max Up Speed: - - - 1 - 2 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Max Connections: - - - 2 - 3 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Max Upload Slots: - - 3 4 - GTK_FILL - - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 1 - -1 -1 9999 1 10 10 - GTK_UPDATE_IF_VALID - - - 1 - 2 - 1 - 2 @@ -641,7 +605,79 @@ - + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 1 + -1 -1 9999 1 10 10 + GTK_UPDATE_IF_VALID + + + 1 + 2 + 1 + 2 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Max Upload Slots: + + + 3 + 4 + GTK_FILL + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Max Connections: + + + 2 + 3 + GTK_FILL + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Max Up Speed: + + + 1 + 2 + GTK_FILL + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Max Down Speed: + + + GTK_FILL + + + + + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -651,8 +687,6 @@ 1 2 - 3 - 4 @@ -726,79 +760,6 @@ 1 - - - True - False - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Private - 0 - True - - - False - False - 2 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - GTK_BUTTONBOX_START - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-edit - - - False - False - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Edit Trackers - True - - - False - False - 5 - 1 - - - - - - - False - False - - - - - False - False - 3 - - @@ -1007,7 +968,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-cancel + gtk-cancel True 0 @@ -1041,7 +1002,7 @@ 462 GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 - Add Tracker + Add URL GTK_WIN_POS_CENTER_ON_PARENT True GDK_WINDOW_TYPE_HINT_DIALOG @@ -1154,7 +1115,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-cancel + gtk-cancel True -6 @@ -1167,7 +1128,153 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - gtk-ok + gtk-ok + True + -5 + + + 1 + + + + + False + GTK_PACK_END + + + + + + + 462 + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Add Magnet URI + GTK_WIN_POS_CENTER_ON_PARENT + True + GDK_WINDOW_TYPE_HINT_DIALOG + False + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + False + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>From Magnet URI</b> + True + + + False + False + 1 + + + + + False + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + False + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + URI: + + + False + False + + + + + True + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + + + 1 + + + + + False + False + 2 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-cancel + True + -6 + + + + + True + True + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-ok True -5 diff --git a/libtorrent/bindings/python/src/magnet_uri.cpp b/libtorrent/bindings/python/src/magnet_uri.cpp new file mode 100644 index 000000000..89c128bb9 --- /dev/null +++ b/libtorrent/bindings/python/src/magnet_uri.cpp @@ -0,0 +1,54 @@ +// Copyright Andrew Resch 2008. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include "gil.hpp" + +using namespace boost::python; +using namespace libtorrent; + +namespace { + + torrent_handle _add_magnet_uri(session& s, std::string uri, dict params) + { + add_torrent_params p; + + std::string url; + if (params.has_key("tracker_url")) + { + url = extract(params["tracker_url"]); + p.tracker_url = url.c_str(); + } + std::string name; + if (params.has_key("name")) + { + name = extract(params["name"]); + p.name = name.c_str(); + } + p.save_path = fs::path(extract(params["save_path"])); + + std::vector resume_buf; + if (params.has_key("resume_data")) + { + std::string resume = extract(params["resume_data"]); + resume_buf.resize(resume.size()); + std::memcpy(&resume_buf[0], &resume[0], resume.size()); + p.resume_data = &resume_buf; + } + p.storage_mode = extract(params["storage_mode"]); + p.paused = params["paused"]; + p.auto_managed = params["auto_managed"]; + p.duplicate_is_error = params["duplicate_is_error"]; + + return add_magnet_uri(s, uri, p); + } +} + +void bind_magnet_uri() +{ + def("add_magnet_uri", &_add_magnet_uri); +} diff --git a/libtorrent/bindings/python/src/module.cpp b/libtorrent/bindings/python/src/module.cpp index ea718388e..7539449cb 100755 --- a/libtorrent/bindings/python/src/module.cpp +++ b/libtorrent/bindings/python/src/module.cpp @@ -22,6 +22,7 @@ void bind_peer_plugin(); void bind_torrent(); void bind_peer_info(); void bind_ip_filter(); +void bind_magnet_uri(); BOOST_PYTHON_MODULE(libtorrent) { @@ -46,5 +47,6 @@ BOOST_PYTHON_MODULE(libtorrent) bind_torrent(); bind_peer_info(); bind_ip_filter(); + bind_magnet_uri(); }