mirror of
https://git.deluge-torrent.org/deluge
synced 2025-04-21 03:54:50 +00:00
Can now remove torrents.
Torrent view is now updating in timer.
This commit is contained in:
parent
c4e688b450
commit
ca5297e20d
11 changed files with 238 additions and 52 deletions
|
@ -143,7 +143,21 @@ class Core(dbus.service.Object):
|
|||
self.torrent_added(torrent_id)
|
||||
|
||||
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
|
||||
in_signature="s", out_signature="(six)")
|
||||
in_signature="s", out_signature="")
|
||||
def remove_torrent(self, torrent_id):
|
||||
log.debug("Removing torrent %s from the core.", torrent_id)
|
||||
try:
|
||||
# Remove from libtorrent session
|
||||
self.session.remove_torrent(self.torrents[torrent_id].handle)
|
||||
# Remove from TorrentManager
|
||||
self.torrents.remove(torrent_id)
|
||||
# Emit the torrent_removed signal
|
||||
self.torrent_removed(torrent_id)
|
||||
except RuntimeError, KeyError:
|
||||
log.warning("Error removing torrent")
|
||||
|
||||
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
|
||||
in_signature="s", out_signature="(sxi)")
|
||||
def get_torrent_info(self, torrent_id):
|
||||
# Get the info tuple from the torrent and return it
|
||||
return self.torrents[torrent_id].get_info()
|
||||
|
@ -154,6 +168,20 @@ class Core(dbus.service.Object):
|
|||
def get_torrent_status(self, torrent_id):
|
||||
# Get the status tuple from the torrent and return it
|
||||
return self.torrents[torrent_id].get_status()
|
||||
|
||||
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
|
||||
in_signature="",
|
||||
out_signature="as")
|
||||
def get_torrent_status_template(self):
|
||||
# A list of strings the correspond to the status tuple
|
||||
return self.torrents.get_status_template()
|
||||
|
||||
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
|
||||
in_signature="",
|
||||
out_signature="as")
|
||||
def get_torrent_info_template(self):
|
||||
# A list of strings the correspond to the info tuple
|
||||
return self.torrents.get_info_template()
|
||||
|
||||
## Queueing functions ######
|
||||
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
|
||||
|
@ -162,8 +190,6 @@ class Core(dbus.service.Object):
|
|||
# If the queue method returns True, then we should emit a signal
|
||||
if self.queue.top(torrent_id):
|
||||
self.torrent_queue_top()
|
||||
# Store the new torrent position in the torrent object
|
||||
# self.torrents[torrent_id].set_position(self.queue[torrent_id])
|
||||
|
||||
@dbus.service.method(dbus_interface="org.deluge_torrent.Deluge",
|
||||
in_signature="s", out_signature="")
|
||||
|
@ -199,6 +225,12 @@ class Core(dbus.service.Object):
|
|||
"""Emitted when a new torrent fails addition to the session"""
|
||||
log.debug("torrent_add_failed signal emitted")
|
||||
|
||||
@dbus.service.signal(dbus_interface="org.deluge_torrent.Deluge",
|
||||
signature="s")
|
||||
def torrent_removed(self, torrent_id):
|
||||
"""Emitted when a torrent has been removed from the core"""
|
||||
log.debug("torrent_remove signal emitted")
|
||||
|
||||
@dbus.service.signal(dbus_interface="org.deluge_torrent.Deluge",
|
||||
signature="s")
|
||||
def torrent_queue_top(self, torrent_id):
|
||||
|
|
|
@ -31,8 +31,13 @@
|
|||
# this exception statement from your version. If you delete this exception
|
||||
# statement from all source files in the program, then also delete it here.
|
||||
|
||||
import logging
|
||||
|
||||
import deluge.libtorrent as lt
|
||||
|
||||
# Get the logger
|
||||
log = logging.getLogger("deluge")
|
||||
|
||||
class Torrent:
|
||||
def __init__(self, handle, queue):
|
||||
# Set the libtorrent handle
|
||||
|
@ -42,17 +47,20 @@ class Torrent:
|
|||
# Set the torrent_id for this torrent
|
||||
self.torrent_id = str(handle.info_hash())
|
||||
|
||||
def __del__(self):
|
||||
self.queue.remove(self.torrent_id)
|
||||
|
||||
def get_eta(self):
|
||||
"""Returns the ETA in seconds for this torrent"""
|
||||
left = self.handle.status().total_wanted \
|
||||
- self.handle.status().total_done
|
||||
|
||||
# The torrent file is done
|
||||
if left == 0:
|
||||
return 0
|
||||
|
||||
# Calculate the ETA in seconds and return it
|
||||
return (left / self.handle.status().download_payload_rate)
|
||||
try:
|
||||
eta = left / self.handle.status().download_payload_rate
|
||||
except ZeroDivisionError:
|
||||
eta = 0
|
||||
|
||||
return eta
|
||||
|
||||
def get_info(self):
|
||||
"""Returns the torrents info.. stuff that remains constant, such as
|
||||
|
@ -83,3 +91,4 @@ class Torrent:
|
|||
self.get_eta(),
|
||||
self.queue[self.torrent_id]
|
||||
)
|
||||
|
||||
|
|
|
@ -59,3 +59,37 @@ class TorrentManager:
|
|||
# Add the torrent to the queue
|
||||
self.queue.append(torrent.torrent_id)
|
||||
return torrent.torrent_id
|
||||
|
||||
def remove(self, torrent_id):
|
||||
"""Remove a torrent from the manager"""
|
||||
try:
|
||||
del self.torrents[torrent_id]
|
||||
except KeyError, ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_info_template(self):
|
||||
"""Returns a list of strings that correspond to the info tuple"""
|
||||
return [
|
||||
"name",
|
||||
"total_size",
|
||||
"num_pieces"
|
||||
]
|
||||
|
||||
def get_status_template(self):
|
||||
"""Returns a list of strings that correspond to the status tuple"""
|
||||
return [
|
||||
"state",
|
||||
"paused",
|
||||
"progress",
|
||||
"next_announce",
|
||||
"total_payload_download",
|
||||
"total_payload_upload",
|
||||
"download_payload_rate",
|
||||
"upload_payload_rate",
|
||||
"num_peers",
|
||||
"num_seeds",
|
||||
"total_wanted",
|
||||
"eta",
|
||||
"position"
|
||||
]
|
||||
|
|
|
@ -54,7 +54,11 @@ class TorrentQueue:
|
|||
"""Prepend torrent_id to the top of the queue"""
|
||||
log.debug("Prepend torrent %s to queue..", torrent_id)
|
||||
self.queue.insert(0, torrent_id)
|
||||
|
||||
|
||||
def remove(self, torrent_id):
|
||||
"""Removes torrent_id from the list"""
|
||||
self.queue.remove(torrent_id)
|
||||
|
||||
def up(self, torrent_id):
|
||||
"""Move torrent_id up one in the queue"""
|
||||
if torrent_id not in self.queue:
|
||||
|
|
|
@ -62,7 +62,7 @@ def cell_data_time(column, cell, model, iter, data):
|
|||
time_str = _("Infinity")
|
||||
else:
|
||||
time_str = deluge.common.ftime(time)
|
||||
cell.set_property('text', time_str)
|
||||
cell.set_property('text', time_str)
|
||||
|
||||
def cell_data_ratio(column, cell, model, iter, data):
|
||||
ratio = float(model.get_value(iter, data))
|
||||
|
|
|
@ -85,3 +85,28 @@ def add_torrent_file():
|
|||
(path, filename) = os.path.split(torrent_file)
|
||||
core.add_torrent_file(filename, f.read())
|
||||
f.close()
|
||||
|
||||
def remove_torrent(torrent_ids):
|
||||
"""Removes torrent_ids from the core.. Expects a list of torrent_ids"""
|
||||
log.debug("Attempting to removing torrents: %s", torrent_ids)
|
||||
core = get_core()
|
||||
for torrent_id in torrent_ids:
|
||||
core.remove_torrent(torrent_id)
|
||||
|
||||
def get_torrent_status_dict(core, torrent_id):
|
||||
"""Builds and returns a status dictionary using the status template"""
|
||||
status = core.get_torrent_status(torrent_id)
|
||||
template = core.get_torrent_status_template()
|
||||
status_dict = {}
|
||||
for string in template:
|
||||
status_dict[string] = status[template.index(string)]
|
||||
return status_dict
|
||||
|
||||
def get_torrent_info_dict(core, torrent_id):
|
||||
"""Builds and returns an info dictionary using the info template"""
|
||||
info = core.get_torrent_info(torrent_id)
|
||||
template = core.get_torrent_info_template()
|
||||
info_dict = {}
|
||||
for string in template:
|
||||
info_dict[string] = info[template.index(string)]
|
||||
return info_dict
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<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">_Remove Torrent</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="remove_torrent"/>
|
||||
<signal name="activate" handler="on_menuitem_remove_activate"/>
|
||||
<child internal-child="image">
|
||||
<widget class="GtkImage" id="menu-item-image9">
|
||||
<property name="visible">True</property>
|
||||
|
|
|
@ -36,6 +36,7 @@ import logging
|
|||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk, gtk.glade
|
||||
import gobject
|
||||
import pkg_resources
|
||||
|
||||
from menubar import MenuBar
|
||||
|
@ -58,7 +59,13 @@ class MainWindow:
|
|||
self.menubar = MenuBar(self)
|
||||
self.toolbar = ToolBar(self)
|
||||
self.torrentview = TorrentView(self)
|
||||
|
||||
gobject.timeout_add(1000, self.update)
|
||||
|
||||
def update(self):
|
||||
self.torrentview.update()
|
||||
return True
|
||||
|
||||
def show(self):
|
||||
self.window.show_all()
|
||||
|
||||
|
|
|
@ -125,6 +125,8 @@ class MenuBar:
|
|||
log.debug("on_menuitem_edittrackers_activate")
|
||||
def on_menuitem_remove_activate(self, data=None):
|
||||
log.debug("on_menuitem_remove_activate")
|
||||
functions.remove_torrent(
|
||||
self.window.torrentview.get_selected_torrents())
|
||||
def on_menuitem_queuetop_activate(self, data=None):
|
||||
log.debug("on_menuitem_queuetop_activate")
|
||||
def on_menuitem_queueup_activate(self, data=None):
|
||||
|
|
|
@ -61,11 +61,17 @@ class Signals:
|
|||
self.ui = ui
|
||||
self.core = functions.get_core()
|
||||
self.core.connect_to_signal("torrent_added", self.torrent_added_signal)
|
||||
self.core.connect_to_signal("torrent_removed",
|
||||
self.torrent_removed_signal)
|
||||
|
||||
def torrent_added_signal(self, torrent_id):
|
||||
log.debug("torrent_added signal received..")
|
||||
log.debug("torrent id: %s", torrent_id)
|
||||
# Add the torrent to the treeview
|
||||
self.ui.main_window.torrentview.add_torrent(torrent_id,
|
||||
self.core.get_torrent_info(torrent_id),
|
||||
self.core.get_torrent_status(torrent_id))
|
||||
self.ui.main_window.torrentview.add_row(torrent_id)
|
||||
|
||||
def torrent_removed_signal(self, torrent_id):
|
||||
log.debug("torrent_remove signal received..")
|
||||
log.debug("torrent id: %s", torrent_id)
|
||||
# Remove the torrent from the treeview
|
||||
self.ui.main_window.torrentview.remove_row(torrent_id)
|
||||
|
|
|
@ -40,14 +40,33 @@ import gobject
|
|||
import gettext
|
||||
|
||||
import columns
|
||||
import functions
|
||||
|
||||
# Get the logger
|
||||
log = logging.getLogger("deluge")
|
||||
|
||||
# Initializes the columns for the torrent_view
|
||||
(TORRENT_VIEW_COL_UID,
|
||||
TORRENT_VIEW_COL_QUEUE,
|
||||
TORRENT_VIEW_COL_STATUSICON,
|
||||
TORRENT_VIEW_COL_NAME,
|
||||
TORRENT_VIEW_COL_SIZE,
|
||||
TORRENT_VIEW_COL_PROGRESS,
|
||||
TORRENT_VIEW_COL_STATUS,
|
||||
TORRENT_VIEW_COL_CONNECTED_SEEDS,
|
||||
TORRENT_VIEW_COL_SEEDS,
|
||||
TORRENT_VIEW_COL_CONNECTED_PEERS,
|
||||
TORRENT_VIEW_COL_PEERS,
|
||||
TORRENT_VIEW_COL_DOWNLOAD,
|
||||
TORRENT_VIEW_COL_UPLOAD,
|
||||
TORRENT_VIEW_COL_ETA,
|
||||
TORRENT_VIEW_COL_RATIO) = range(15)
|
||||
|
||||
class TorrentView:
|
||||
def __init__(self, window):
|
||||
log.debug("TorrentView Init..")
|
||||
self.window = window
|
||||
self.core = functions.get_core()
|
||||
# Get the torrent_view widget
|
||||
self.torrent_view = self.window.main_glade.get_widget("torrent_view")
|
||||
|
||||
|
@ -63,23 +82,6 @@ class TorrentView:
|
|||
self.torrent_view.set_reorderable(True)
|
||||
self.torrent_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||
|
||||
# Initializes the columns for the torrent_view
|
||||
(TORRENT_VIEW_COL_UID,
|
||||
TORRENT_VIEW_COL_QUEUE,
|
||||
TORRENT_VIEW_COL_STATUSICON,
|
||||
TORRENT_VIEW_COL_NAME,
|
||||
TORRENT_VIEW_COL_SIZE,
|
||||
TORRENT_VIEW_COL_PROGRESS,
|
||||
TORRENT_VIEW_COL_STATUS,
|
||||
TORRENT_VIEW_COL_CONNECTED_SEEDS,
|
||||
TORRENT_VIEW_COL_SEEDS,
|
||||
TORRENT_VIEW_COL_CONNECTED_PEERS,
|
||||
TORRENT_VIEW_COL_PEERS,
|
||||
TORRENT_VIEW_COL_DOWNLOAD,
|
||||
TORRENT_VIEW_COL_UPLOAD,
|
||||
TORRENT_VIEW_COL_ETA,
|
||||
TORRENT_VIEW_COL_RATIO) = range(15)
|
||||
|
||||
self.queue_column = columns.add_text_column(
|
||||
self.torrent_view, "#",
|
||||
TORRENT_VIEW_COL_QUEUE)
|
||||
|
@ -149,32 +151,97 @@ class TorrentView:
|
|||
self.torrent_view.get_selection().connect("changed",
|
||||
self.on_selection_changed)
|
||||
|
||||
def add_torrent(self, torrent_id, info, status):
|
||||
def update(self):
|
||||
"""Update the view, this is likely called by a timer"""
|
||||
# Iterate through the torrent_model and update rows
|
||||
row = self.torrent_model.get_iter_first()
|
||||
while row is not None:
|
||||
torrent_id = self.torrent_model.get_value(row, 0)
|
||||
status = functions.get_torrent_status_dict(self.core, torrent_id)
|
||||
# Set values for each column in the row
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_QUEUE,
|
||||
status["position"]+1)
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_PROGRESS,
|
||||
status["progress"]*100)
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_STATUS,
|
||||
status["state"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_CONNECTED_SEEDS,
|
||||
status["num_seeds"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_SEEDS,
|
||||
status["num_seeds"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_CONNECTED_PEERS,
|
||||
status["num_peers"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_PEERS,
|
||||
status["num_peers"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_DOWNLOAD,
|
||||
status["download_payload_rate"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_UPLOAD,
|
||||
status["upload_payload_rate"])
|
||||
self.torrent_model.set_value(row, TORRENT_VIEW_COL_ETA,
|
||||
status["eta"])
|
||||
row = self.torrent_model.iter_next(row)
|
||||
|
||||
def add_row(self, torrent_id):
|
||||
"""Adds a new torrent row to the treeview"""
|
||||
# UID, Q#, Status Icon, Name, Size, Progress, Message, Seeders, Peers,
|
||||
# DL, UL, ETA, Share
|
||||
self.torrent_model.insert(status[12], [
|
||||
# Get the status and info dictionaries
|
||||
status = functions.get_torrent_status_dict(self.core, torrent_id)
|
||||
info = functions.get_torrent_info_dict(self.core, torrent_id)
|
||||
|
||||
# Insert the row with info provided from core
|
||||
self.torrent_model.insert(status["position"], [
|
||||
torrent_id,
|
||||
status[12]+1,
|
||||
None, ## Status Icon
|
||||
info[0],
|
||||
info[2],
|
||||
status[2],
|
||||
status[0],
|
||||
status[9],
|
||||
status[9],
|
||||
status[8],
|
||||
status[8],
|
||||
status[6],
|
||||
status[7],
|
||||
status[11],
|
||||
0.0
|
||||
status["position"]+1,
|
||||
None,
|
||||
info["name"],
|
||||
info["total_size"],
|
||||
status["progress"]*100,
|
||||
status["state"],
|
||||
status["num_seeds"],
|
||||
status["num_seeds"],
|
||||
status["num_peers"],
|
||||
status["num_peers"],
|
||||
status["download_payload_rate"],
|
||||
status["upload_payload_rate"],
|
||||
status["eta"],
|
||||
0.0
|
||||
])
|
||||
|
||||
def remove_row(self, torrent_id):
|
||||
"""Removes a row with torrent_id"""
|
||||
row = self.torrent_model.get_iter_first()
|
||||
while row is not None:
|
||||
# Check if this row is the row we want to remove
|
||||
if self.torrent_model.get_value(row, 0) == torrent_id:
|
||||
self.torrent_model.remove(row)
|
||||
# Force an update of the torrentview
|
||||
self.update()
|
||||
break
|
||||
row = self.torrent_model.iter_next(row)
|
||||
|
||||
def get_selected_torrents(self):
|
||||
"""Returns a list of selected torrents or None"""
|
||||
torrent_ids = []
|
||||
paths = self.torrent_view.get_selection().get_selected_rows()[1]
|
||||
|
||||
try:
|
||||
for path in paths:
|
||||
torrent_ids.append(
|
||||
self.torrent_model.get_value(
|
||||
self.torrent_model.get_iter(path), 0))
|
||||
return torrent_ids
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
### Callbacks ###
|
||||
def on_button_press_event(self, widget, event, data):
|
||||
def on_button_press_event(self, widget, event):
|
||||
log.debug("on_button_press_event")
|
||||
# We only care about right-clicks
|
||||
if event.button == 3:
|
||||
# Show the Torrent menu from the MenuBar
|
||||
torrentmenu = self.window.menubar.torrentmenu.get_widget(
|
||||
"torrent_menu")
|
||||
torrentmenu.popup(None, None, None, event.button, event.time)
|
||||
|
||||
def on_selection_changed(self, treeselection, data):
|
||||
def on_selection_changed(self, treeselection):
|
||||
log.debug("on_selection_changed")
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue