Start work of magnet uri and trackerless torrent support

This commit is contained in:
Andrew Resch 2008-09-09 14:06:05 +00:00
parent c906b50d11
commit ccb53e48a9
8 changed files with 482 additions and 194 deletions

View file

@ -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:

View file

@ -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):

View file

@ -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)

View file

@ -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

View file

@ -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):

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Sat Aug 23 22:29:34 2008 -->
<!--Generated with glade3 3.4.5 on Tue Sep 9 03:09:06 2008 -->
<glade-interface>
<widget class="GtkDialog" id="dialog_add_torrent">
<property name="height_request">560</property>
@ -142,7 +142,7 @@
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">From _File</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
</widget>
<packing>
@ -189,7 +189,7 @@
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">From _URL</property>
<property name="label" translatable="yes">_URL</property>
<property name="use_underline">True</property>
</widget>
<packing>
@ -209,6 +209,7 @@
</child>
<child>
<widget class="GtkButton" id="button_hash">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@ -236,7 +237,7 @@
<widget class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">From _Hash</property>
<property name="label" translatable="yes">Info_hash</property>
<property name="use_underline">True</property>
</widget>
<packing>
@ -254,6 +255,39 @@
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button_magnet">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_magnet_clicked"/>
<child>
<widget class="GtkHBox" id="hbox15">
<property name="visible">True</property>
<child>
<widget class="GtkImage" id="image_magnet">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="label" translatable="yes">_Magnet URI</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="position">3</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button_remove">
<property name="visible">True</property>
@ -297,7 +331,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
</widget>
@ -537,7 +571,7 @@
<property name="n_columns">2</property>
<property name="column_spacing">10</property>
<child>
<widget class="GtkSpinButton" id="spin_maxdown">
<widget class="GtkSpinButton" id="spin_maxupslots">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@ -547,78 +581,8 @@
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Down Speed:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Up Speed:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Connections:</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Upload Slots:</property>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_maxup">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
<property name="update_policy">GTK_UPDATE_IF_VALID</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
@ -641,7 +605,79 @@
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_maxupslots">
<widget class="GtkSpinButton" id="spin_maxup">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
<property name="update_policy">GTK_UPDATE_IF_VALID</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Upload Slots:</property>
</widget>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Connections:</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Up Speed:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Max Down Speed:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_maxdown">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@ -651,8 +687,6 @@
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
@ -726,79 +760,6 @@
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="chk_private">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Private</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">GTK_BUTTONBOX_START</property>
<child>
<widget class="GtkButton" id="button_trackers">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_trackers_clicked"/>
<child>
<widget class="GtkHBox" id="hbox8">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImage" id="image6">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-edit</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label16">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">_Edit Trackers</property>
<property name="use_underline">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</widget>
</child>
</widget>
@ -1007,7 +968,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="no">gtk-cancel</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_button_cancel_clicked"/>
@ -1041,7 +1002,7 @@
<property name="width_request">462</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Add Tracker</property>
<property name="title" translatable="yes">Add URL</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
@ -1154,7 +1115,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="no">gtk-cancel</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">-6</property>
</widget>
@ -1167,7 +1128,153 @@
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="no">gtk-ok</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">-5</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="dialog_magnet">
<property name="width_request">462</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Add Magnet URI</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="decorated">False</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox5">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">2</property>
<child>
<widget class="GtkVBox" id="vbox7">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">5</property>
<child>
<widget class="GtkHBox" id="hbox8">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">5</property>
<child>
<widget class="GtkImage" id="image_dialog_magnet">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label16">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">&lt;b&gt;From Magnet URI&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHSeparator" id="hseparator2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox16">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label23">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">URI:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="entry_magnet">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="is_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="activates_default">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area5">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="button_magnet_add_cancel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="response_id">-6</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="button_magnet_add_ok">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="response_id">-5</property>
</widget>

View file

@ -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 <libtorrent/session.hpp>
#include <libtorrent/torrent.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <boost/python.hpp>
#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<std::string>(params["tracker_url"]);
p.tracker_url = url.c_str();
}
std::string name;
if (params.has_key("name"))
{
name = extract<std::string>(params["name"]);
p.name = name.c_str();
}
p.save_path = fs::path(extract<std::string>(params["save_path"]));
std::vector<char> resume_buf;
if (params.has_key("resume_data"))
{
std::string resume = extract<std::string>(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<storage_mode_t>(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);
}

View file

@ -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();
}