Added support for adding torrents by infohash

Fixes to magnet uri stuff
This commit is contained in:
Andrew Resch 2008-09-12 08:47:33 +00:00
parent 3afb542f06
commit ee9a5a19c1
8 changed files with 234 additions and 163 deletions

View File

@ -319,6 +319,12 @@ def is_url(url):
import re import re
return bool(re.search('^(https?|ftp)://', url)) return bool(re.search('^(https?|ftp)://', url))
def is_magnet(uri):
"""Returns True if uri is a valid bittorrent magnet uri."""
if uri[:20] == "magnet:?xt=urn:btih:":
return True
return False
def fetch_url(url): def fetch_url(url):
"""Downloads a torrent file from a given """Downloads a torrent file from a given
URL and checks the file's validity.""" URL and checks the file's validity."""
@ -351,3 +357,16 @@ def pythonize(var):
if isinstance(var, klass): if isinstance(var, klass):
return klass(var) return klass(var)
return var return var
def create_magnet_uri(infohash, name=None, trackers=[]):
from base64 import b32encode
uri = "magnet:?xt=urn:btih:" + b32encode(infohash.decode("hex"))
if name:
uri = uri + "&dn=" + name
if trackers:
for t in trackers:
uri = uri + "&tr=" + t
return uri

View File

@ -401,7 +401,12 @@ class Core(
def export_add_torrent_magnets(self, uris, options): def export_add_torrent_magnets(self, uris, options):
for uri in uris: for uri in uris:
log.debug("Attempting to add by magnet uri: %s", uri) log.debug("Attempting to add by magnet uri: %s", uri)
torrent_id = self.torrents.add(magnet=uri, options=options[uris.index(uri)]) try:
option = options[uris.index(uri)]
except IndexError:
option = None
torrent_id = self.torrents.add(magnet=uri, options=option)
# Run the plugin hooks for 'post_torrent_add' # Run the plugin hooks for 'post_torrent_add'
self.plugins.run_post_torrent_add(torrent_id) self.plugins.run_post_torrent_add(torrent_id)

View File

@ -419,6 +419,9 @@ class Torrent:
def get_file_progress(self): def get_file_progress(self):
"""Returns the file progress as a list of floats.. 0.0 -> 1.0""" """Returns the file progress as a list of floats.. 0.0 -> 1.0"""
if not self.handle.has_metadata():
return 0.0
file_progress = self.handle.file_progress() file_progress = self.handle.file_progress()
ret = [] ret = []
for i,f in enumerate(self.files): for i,f in enumerate(self.files):

View File

@ -61,7 +61,6 @@ class AddTorrentDialog(component.Component):
"on_button_file_clicked": self._on_button_file_clicked, "on_button_file_clicked": self._on_button_file_clicked,
"on_button_url_clicked": self._on_button_url_clicked, "on_button_url_clicked": self._on_button_url_clicked,
"on_button_hash_clicked": self._on_button_hash_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_remove_clicked": self._on_button_remove_clicked,
"on_button_trackers_clicked": self._on_button_trackers_clicked, "on_button_trackers_clicked": self._on_button_trackers_clicked,
"on_button_cancel_clicked": self._on_button_cancel_clicked, "on_button_cancel_clicked": self._on_button_cancel_clicked,
@ -70,9 +69,6 @@ class AddTorrentDialog(component.Component):
"on_button_revert_clicked": self._on_button_revert_clicked "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) self.torrent_liststore = gtk.ListStore(str, str, str)
#download?, path, filesize, sequence number, inconsistent? #download?, path, filesize, sequence number, inconsistent?
self.files_treestore = gtk.TreeStore(bool, str, gobject.TYPE_UINT64, self.files_treestore = gtk.TreeStore(bool, str, gobject.TYPE_UINT64,
@ -258,11 +254,14 @@ class AddTorrentDialog(component.Component):
def _on_torrent_changed(self, treeselection): def _on_torrent_changed(self, treeselection):
(model, row) = treeselection.get_selected() (model, row) = treeselection.get_selected()
self.files_treestore.clear()
if row is None: if row is None:
self.files_treestore.clear()
return return
# Save the previous torrents options
self.save_torrent_options()
# Update files list # Update files list
files_list = self.files[model.get_value(row, 0)] files_list = self.files[model.get_value(row, 0)]
@ -271,32 +270,33 @@ class AddTorrentDialog(component.Component):
if self.core_config == {}: if self.core_config == {}:
self.update_core_config() self.update_core_config()
# Save the previous torrents options
self.save_torrent_options()
# Update the options frame # Update the options frame
self.update_torrent_options(model.get_value(row, 0)) self.update_torrent_options(model.get_value(row, 0))
self.previous_selected_torrent = row self.previous_selected_torrent = row
def prepare_file_store(self, files): def prepare_file_store(self, files):
self.listview_files.set_model(None)
self.files_treestore.clear()
split_files = { } split_files = { }
i = 0 i = 0
for file in files: for file in files:
self.prepare_file(file, file["path"], i, split_files) self.prepare_file(file, file["path"], i, file["download"], split_files)
i += 1 i += 1
self.add_files(None, split_files) self.add_files(None, split_files)
self.listview_files.set_model(self.files_treestore)
self.listview_files.expand_row("0", False)
def prepare_file(self, file, file_name, file_num, files_storage): def prepare_file(self, file, file_name, file_num, download, files_storage):
log.debug("file_name: %s", file_name)
first_slash_index = file_name.find("/") first_slash_index = file_name.find("/")
if first_slash_index == -1: if first_slash_index == -1:
files_storage[file_name] = (file_num, file) files_storage[file_name] = (file_num, file, download)
else: else:
file_name_chunk = file_name[:first_slash_index+1] file_name_chunk = file_name[:first_slash_index+1]
if file_name_chunk not in files_storage: if file_name_chunk not in files_storage:
files_storage[file_name_chunk] = { } files_storage[file_name_chunk] = { }
self.prepare_file(file, file_name[first_slash_index+1:], self.prepare_file(file, file_name[first_slash_index+1:],
file_num, files_storage[file_name_chunk]) file_num, download, files_storage[file_name_chunk])
def add_files(self, parent_iter, split_files): def add_files(self, parent_iter, split_files):
ret = 0 ret = 0
@ -308,8 +308,29 @@ class AddTorrentDialog(component.Component):
self.files_treestore.set(chunk_iter, 2, chunk_size) self.files_treestore.set(chunk_iter, 2, chunk_size)
ret += chunk_size ret += chunk_size
else: else:
self.files_treestore.append(parent_iter, [True, key, self.files_treestore.append(parent_iter, [value[2], key,
value[1]["size"], value[0], False, gtk.STOCK_FILE]) value[1]["size"], value[0], False, gtk.STOCK_FILE])
# Iterate through the children and see what we should label the
# folder, download true, download false or inconsistent.
itr = self.files_treestore.iter_children(parent_iter)
download = []
download_value = False
inconsistent = False
while itr:
download.append(self.files_treestore.get_value(itr, 0))
itr = self.files_treestore.iter_next(itr)
if sum(download) == len(download):
download_value = True
elif sum(download) == 0:
download_value = False
else:
inconsistent = True
self.files_treestore.set_value(parent_iter, 0, download_value)
self.files_treestore.set_value(parent_iter, 4, inconsistent)
ret += value[1]["size"] ret += value[1]["size"]
return ret return ret
@ -379,9 +400,11 @@ class AddTorrentDialog(component.Component):
# Save the file priorities # Save the file priorities
files_priorities = self.build_priorities( files_priorities = self.build_priorities(
self.files_treestore.get_iter_first(), {}) self.files_treestore.get_iter_first(), {})
log.debug("fp: %s", len(files_priorities))
for i, file_dict in enumerate(self.files[torrent_id]): if len(files_priorities) > 0:
file_dict["download"] = files_priorities[i] for i, file_dict in enumerate(self.files[torrent_id]):
file_dict["download"] = files_priorities[i]
def build_priorities(self, iter, priorities): def build_priorities(self, iter, priorities):
while iter is not None: while iter is not None:
@ -532,7 +555,7 @@ class AddTorrentDialog(component.Component):
text = clip.wait_for_text() text = clip.wait_for_text()
if text: if text:
text = text.strip() text = text.strip()
if deluge.common.is_url(text): if deluge.common.is_url(text) or deluge.common.is_magnet(text):
entry.set_text(text) entry.set_text(text)
dialog.show_all() dialog.show_all()
@ -547,7 +570,10 @@ class AddTorrentDialog(component.Component):
# add it to the list. # add it to the list.
log.debug("url: %s", url) log.debug("url: %s", url)
if url != None: if url != None:
self.add_from_url(url) if deluge.common.is_url(url):
self.add_from_url(url)
elif deluge.common.is_magnet(url):
self.add_from_magnets([url])
entry.set_text("") entry.set_text("")
dialog.hide() dialog.hide()
@ -566,45 +592,34 @@ class AddTorrentDialog(component.Component):
def _on_button_hash_clicked(self, widget): def _on_button_hash_clicked(self, widget):
log.debug("_on_button_hash_clicked") log.debug("_on_button_hash_clicked")
dialog = self.glade.get_widget("dialog_infohash")
def _on_button_magnet_clicked(self, widget): entry = self.glade.get_widget("entry_hash")
log.debug("_on_button_magnet_clicked") textview = self.glade.get_widget("text_trackers")
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_default_response(gtk.RESPONSE_OK)
dialog.set_transient_for(self.dialog) dialog.set_transient_for(self.dialog)
entry.grab_focus() 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() dialog.show_all()
response = dialog.run() response = dialog.run()
if response == gtk.RESPONSE_OK and len(entry.get_text()) == 40:
if response == gtk.RESPONSE_OK: trackers = []
uri = entry.get_text().decode("utf_8") b = textview.get_buffer()
else: lines = b.get_text(b.get_start_iter(), b.get_end_iter()).strip().split("\n")
uri = None log.debug("lines: %s", lines)
for l in lines:
log.debug("magnet uri: %s", uri) if deluge.common.is_url(l):
if uri: trackers.append(l)
self.add_from_magnets([uri]) # Convert the information to a magnet uri, this is just easier to
# handle this way.
log.debug("trackers: %s", trackers)
magnet = deluge.common.create_magnet_uri(
infohash=entry.get_text().decode("utf_8"),
trackers=trackers)
log.debug("magnet uri: %s", magnet)
self.add_from_magnets([magnet])
entry.set_text("") entry.set_text("")
textview.get_buffer().set_text("")
dialog.hide() dialog.hide()
def _on_button_remove_clicked(self, widget): def _on_button_remove_clicked(self, widget):
@ -651,7 +666,7 @@ class AddTorrentDialog(component.Component):
if options != None: if options != None:
options["file_priorities"] = file_priorities options["file_priorities"] = file_priorities
if filename[:20] == "magnet:?xt=urn:btih:": if deluge.common.is_magnet(filename):
torrent_magnets.append(filename) torrent_magnets.append(filename)
del options["file_priorities"] del options["file_priorities"]
torrent_magnet_options.append(options) torrent_magnet_options.append(options)

View File

@ -61,8 +61,10 @@ class DbusInterface(dbus.service.Object, component.Component):
# Convert the paths to absolutes # Convert the paths to absolutes
new_args = [] new_args = []
for arg in args: for arg in args:
if not deluge.common.is_url(arg): if not deluge.common.is_url(arg) and not deluge.common.is_magnet(arg):
new_args.append(os.path.abspath(arg)) new_args.append(os.path.abspath(arg))
else:
new_args.append(arg)
args = new_args args = new_args
# Send the args to the running session # Send the args to the running session

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Tue Sep 9 03:09:06 2008 --> <!--Generated with glade3 3.4.5 on Thu Sep 11 23:06:35 2008 -->
<glade-interface> <glade-interface>
<widget class="GtkDialog" id="dialog_add_torrent"> <widget class="GtkDialog" id="dialog_add_torrent">
<property name="height_request">560</property> <property name="height_request">560</property>
@ -255,39 +255,6 @@
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </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> <child>
<widget class="GtkButton" id="button_remove"> <widget class="GtkButton" id="button_remove">
<property name="visible">True</property> <property name="visible">True</property>
@ -331,7 +298,7 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">4</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
</widget> </widget>
@ -571,7 +538,7 @@
<property name="n_columns">2</property> <property name="n_columns">2</property>
<property name="column_spacing">10</property> <property name="column_spacing">10</property>
<child> <child>
<widget class="GtkSpinButton" id="spin_maxupslots"> <widget class="GtkSpinButton" id="spin_maxdown">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@ -581,26 +548,61 @@
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</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="x_options"></property>
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkSpinButton" id="spin_maxconnections"> <widget class="GtkLabel" id="label11">
<property name="visible">True</property> <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="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="xalign">0</property>
<property name="adjustment">-1 -1 9999 1 10 10</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> </widget>
<packing> <packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property> <property name="top_attach">2</property>
<property name="bottom_attach">3</property> <property name="bottom_attach">3</property>
<property name="x_options"></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> <property name="y_options"></property>
</packing> </packing>
</child> </child>
@ -623,61 +625,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkLabel" id="label14"> <widget class="GtkSpinButton" id="spin_maxconnections">
<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="visible">True</property>
<property name="can_focus">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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@ -687,6 +635,25 @@
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
<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>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 9999 1 10 10</property>
</widget>
<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="x_options"></property>
<property name="y_options"></property> <property name="y_options"></property>
</packing> </packing>
@ -1145,11 +1112,11 @@
</widget> </widget>
</child> </child>
</widget> </widget>
<widget class="GtkDialog" id="dialog_magnet"> <widget class="GtkDialog" id="dialog_infohash">
<property name="width_request">462</property> <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="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="border_width">5</property>
<property name="title" translatable="yes">Add Magnet URI</property> <property name="title" translatable="yes">Add Infohash</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="destroy_with_parent">True</property> <property name="destroy_with_parent">True</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
@ -1174,6 +1141,7 @@
<widget class="GtkImage" id="image_dialog_magnet"> <widget class="GtkImage" id="image_dialog_magnet">
<property name="visible">True</property> <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="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-revert-to-saved</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -1184,7 +1152,7 @@
<widget class="GtkLabel" id="label16"> <widget class="GtkLabel" id="label16">
<property name="visible">True</property> <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="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="label" translatable="yes">&lt;b&gt;From Infohash&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</widget> </widget>
<packing> <packing>
@ -1218,7 +1186,7 @@
<widget class="GtkLabel" id="label23"> <widget class="GtkLabel" id="label23">
<property name="visible">True</property> <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="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> <property name="label" translatable="yes">Infohash:</property>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -1226,7 +1194,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkEntry" id="entry_magnet"> <widget class="GtkEntry" id="entry_hash">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="has_focus">True</property> <property name="has_focus">True</property>
@ -1245,6 +1213,44 @@
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkHBox" id="hbox15">
<property name="visible">True</property>
<property name="spacing">5</property>
<child>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">Trackers:</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkTextView" id="text_trackers">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">3</property>
</packing>
</child>
</widget> </widget>
<packing> <packing>
<property name="position">1</property> <property name="position">1</property>

View File

@ -88,6 +88,7 @@ def process_args(args):
return return
config = ConfigManager("gtkui.conf") config = ConfigManager("gtkui.conf")
for arg in args: for arg in args:
log.debug("arg: %s", arg)
if deluge.common.is_url(arg): if deluge.common.is_url(arg):
log.debug("Attempting to add %s from external source..", log.debug("Attempting to add %s from external source..",
arg) arg)
@ -95,7 +96,14 @@ def process_args(args):
component.get("AddTorrentDialog").add_from_url(arg) component.get("AddTorrentDialog").add_from_url(arg)
component.get("AddTorrentDialog").show(config["focus_add_dialog"]) component.get("AddTorrentDialog").show(config["focus_add_dialog"])
else: else:
client.add_torrent_url(arg) client.add_torrent_url(arg, None)
elif deluge.common.is_magnet(arg):
log.debug("Attempting to add %s from external source..", arg)
if config["interactive_add"]:
component.get("AddTorrentDialog").add_from_magnets([arg])
component.get("AddTorrentDialog").show(config["focus_add_dialog"])
else:
client.add_torrent_magnets([arg], [])
else: else:
# Just a file # Just a file
log.debug("Attempting to add %s from external source..", log.debug("Attempting to add %s from external source..",

View File

@ -168,11 +168,24 @@ class QueuedTorrents(component.Component):
# Add all the torrents in the liststore # Add all the torrents in the liststore
def add_torrent(model, path, iter, data): def add_torrent(model, path, iter, data):
torrent_path = model.get_value(iter, 1) torrent_path = model.get_value(iter, 1)
if self.config["interactive_add"]: if deluge.common.is_url(torrent_path):
component.get("AddTorrentDialog").add_from_files([torrent_path]) if self.config["interactive_add"]:
component.get("AddTorrentDialog").show(self.config["focus_add_dialog"]) component.get("AddTorrentDialog").add_from_url(torrent_path)
component.get("AddTorrentDialog").show(self.config["focus_add_dialog"])
else:
client.add_torrent_url(torrent_path, None)
elif deluge.common.is_magnet(torrent_path):
if self.config["interactive_add"]:
component.get("AddTorrentDialog").add_from_magnets([torrent_path])
component.get("AddTorrentDialog").show(self.config["focus_add_dialog"])
else:
client.add_magnet_uris([torrent_path], [])
else: else:
client.add_torrent_file([torrent_path]) if self.config["interactive_add"]:
component.get("AddTorrentDialog").add_from_files([torrent_path])
component.get("AddTorrentDialog").show(self.config["focus_add_dialog"])
else:
client.add_torrent_file([torrent_path])
self.liststore.foreach(add_torrent, None) self.liststore.foreach(add_torrent, None)
del self.queue[:] del self.queue[:]