Added TorrentDetails component to GtkUI, but it is currently not
optimized. Added more status fields to Torrent.
This commit is contained in:
parent
0d12b1e0cf
commit
be5855dcd6
|
@ -66,23 +66,6 @@ def get_default_plugin_dir():
|
||||||
|
|
||||||
## Formatting text functions
|
## Formatting text functions
|
||||||
|
|
||||||
def estimate_eta(total_size, total_done, download_rate):
|
|
||||||
"""Returns a string with the estimated ETA and will return 'Unlimited'
|
|
||||||
if the torrent is complete
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return ftime(get_eta(total_size, total_done, download_rate))
|
|
||||||
except ZeroDivisionError:
|
|
||||||
return "Infinity"
|
|
||||||
|
|
||||||
def get_eta(size, done, speed):
|
|
||||||
"""Returns the ETA in seconds
|
|
||||||
Will raise an exception if the torrent is completed
|
|
||||||
"""
|
|
||||||
if (size - done) == 0:
|
|
||||||
raise ZeroDivisionError
|
|
||||||
return (size - done) / speed
|
|
||||||
|
|
||||||
def fsize(fsize_b):
|
def fsize(fsize_b):
|
||||||
"""Returns formatted string describing filesize
|
"""Returns formatted string describing filesize
|
||||||
fsize_b should be in bytes
|
fsize_b should be in bytes
|
||||||
|
@ -105,16 +88,14 @@ def fspeed(bps):
|
||||||
"""Returns a formatted string representing transfer speed"""
|
"""Returns a formatted string representing transfer speed"""
|
||||||
return '%s/s' % (fsize(bps))
|
return '%s/s' % (fsize(bps))
|
||||||
|
|
||||||
def fseed(num_seeds, total_seeds):
|
|
||||||
"""Returns a formatted string num_seeds (total_seeds)"""
|
|
||||||
return str(str(num_seeds) + " (" + str(total_seeds) + ")")
|
|
||||||
|
|
||||||
def fpeer(num_peers, total_peers):
|
def fpeer(num_peers, total_peers):
|
||||||
"""Returns a formatted string num_peers (total_peers)"""
|
"""Returns a formatted string num_peers (total_peers)"""
|
||||||
return str(str(num_peers) + " (" + str(total_peers) + ")")
|
return str(str(num_peers) + " (" + str(total_peers) + ")")
|
||||||
|
|
||||||
def ftime(seconds):
|
def ftime(seconds):
|
||||||
"""Returns a formatted time string"""
|
"""Returns a formatted time string"""
|
||||||
|
if seconds is 0:
|
||||||
|
return "Infinity"
|
||||||
if seconds < 60:
|
if seconds < 60:
|
||||||
return '%ds' % (seconds)
|
return '%ds' % (seconds)
|
||||||
minutes = int(seconds/60)
|
minutes = int(seconds/60)
|
||||||
|
|
|
@ -43,6 +43,8 @@ class Torrent:
|
||||||
self.handle = handle
|
self.handle = handle
|
||||||
# Set the torrent_id for this torrent
|
# Set the torrent_id for this torrent
|
||||||
self.torrent_id = str(handle.info_hash())
|
self.torrent_id = str(handle.info_hash())
|
||||||
|
# This is for saving the total uploaded between sessions
|
||||||
|
self.total_uploaded = 0
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
"""Returns the state of this torrent for saving to the session state"""
|
"""Returns the state of this torrent for saving to the session state"""
|
||||||
|
@ -63,6 +65,22 @@ class Torrent:
|
||||||
|
|
||||||
return eta
|
return eta
|
||||||
|
|
||||||
|
def get_ratio(self):
|
||||||
|
"""Returns the ratio for this torrent"""
|
||||||
|
up = self.total_uploaded + self.handle.status().total_payload_upload
|
||||||
|
down = self.handle.status().total_done
|
||||||
|
|
||||||
|
# Convert 'up' and 'down' to floats for proper calculation
|
||||||
|
up = float(up)
|
||||||
|
down = float(down)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ratio = up / down
|
||||||
|
except ZeroDivisionError:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return ratio
|
||||||
|
|
||||||
def get_status(self, keys):
|
def get_status(self, keys):
|
||||||
"""Returns the status of the torrent based on the keys provided"""
|
"""Returns the status of the torrent based on the keys provided"""
|
||||||
# Create the full dictionary
|
# Create the full dictionary
|
||||||
|
@ -71,10 +89,26 @@ class Torrent:
|
||||||
# Adjust progress to be 0-100 value
|
# Adjust progress to be 0-100 value
|
||||||
progress = status.progress*100
|
progress = status.progress*100
|
||||||
|
|
||||||
|
# Get the total number of seeds and peers
|
||||||
|
if status.num_complete is -1:
|
||||||
|
total_seeds = status.num_seeds
|
||||||
|
else:
|
||||||
|
total_seeds = status.num_complete
|
||||||
|
|
||||||
|
if status.num_incomplete is -1:
|
||||||
|
total_peers = status.num_peers - status.num_seeds
|
||||||
|
else:
|
||||||
|
total_peers = status.num_incomplete
|
||||||
|
|
||||||
full_status = {
|
full_status = {
|
||||||
"name": self.handle.torrent_info().name(),
|
"name": self.handle.torrent_info().name(),
|
||||||
"total_size": self.handle.torrent_info().total_size(),
|
"total_size": self.handle.torrent_info().total_size(),
|
||||||
"num_pieces": self.handle.status().num_pieces,
|
"num_files": self.handle.torrent_info().num_files(),
|
||||||
|
"num_pieces": self.handle.torrent_info().num_pieces(),
|
||||||
|
"piece_length": self.handle.torrent_info().piece_length(),
|
||||||
|
"distributed_copies": status.distributed_copies,
|
||||||
|
"total_done": status.total_done,
|
||||||
|
"total_uploaded": self.total_uploaded + status.total_payload_upload,
|
||||||
"state": int(status.state),
|
"state": int(status.state),
|
||||||
"paused": status.paused,
|
"paused": status.paused,
|
||||||
"progress": progress,
|
"progress": progress,
|
||||||
|
@ -83,11 +117,14 @@ class Torrent:
|
||||||
"total_payload_upload": status.total_payload_upload,
|
"total_payload_upload": status.total_payload_upload,
|
||||||
"download_payload_rate": status.download_payload_rate,
|
"download_payload_rate": status.download_payload_rate,
|
||||||
"upload_payload_rate": status.upload_payload_rate,
|
"upload_payload_rate": status.upload_payload_rate,
|
||||||
"num_peers": status.num_peers,
|
"num_peers": status.num_peers - status.num_seeds,
|
||||||
"num_seeds": status.num_seeds,
|
"num_seeds": status.num_seeds,
|
||||||
|
"total_peers": total_peers,
|
||||||
|
"total_seeds": total_seeds,
|
||||||
"total_wanted": status.total_wanted,
|
"total_wanted": status.total_wanted,
|
||||||
"eta": self.get_eta(),
|
"eta": self.get_eta(),
|
||||||
"ratio": 0.0
|
"ratio": self.get_ratio(),
|
||||||
|
"tracker": status.current_tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create the desired status dictionary and return it
|
# Create the desired status dictionary and return it
|
||||||
|
|
|
@ -40,6 +40,7 @@ import pkg_resources
|
||||||
from menubar import MenuBar
|
from menubar import MenuBar
|
||||||
from toolbar import ToolBar
|
from toolbar import ToolBar
|
||||||
from torrentview import TorrentView
|
from torrentview import TorrentView
|
||||||
|
from torrentdetails import TorrentDetails
|
||||||
|
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
|
|
||||||
|
@ -56,11 +57,13 @@ class MainWindow:
|
||||||
self.menubar = MenuBar(self)
|
self.menubar = MenuBar(self)
|
||||||
self.toolbar = ToolBar(self)
|
self.toolbar = ToolBar(self)
|
||||||
self.torrentview = TorrentView(self)
|
self.torrentview = TorrentView(self)
|
||||||
|
self.torrentdetails = TorrentDetails(self)
|
||||||
|
|
||||||
gobject.timeout_add(1000, self.update)
|
gobject.timeout_add(1000, self.update)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.torrentview.update()
|
self.torrentview.update()
|
||||||
|
self.torrentdetails.update()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
#
|
||||||
|
# torrentdetails.py
|
||||||
|
#
|
||||||
|
# Copyright (C) 2007 Andrew Resch ('andar') <andrewresch@gmail.com>
|
||||||
|
#
|
||||||
|
# Deluge is free software.
|
||||||
|
#
|
||||||
|
# You may redistribute it and/or modify it under the terms of the
|
||||||
|
# GNU General Public License, as published by the Free Software
|
||||||
|
# Foundation; either version 2 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# deluge is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with deluge. If not, write to:
|
||||||
|
# The Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# In addition, as a special exception, the copyright holders give
|
||||||
|
# permission to link the code of portions of this program with the OpenSSL
|
||||||
|
# library.
|
||||||
|
# You must obey the GNU General Public License in all respects for all of
|
||||||
|
# the code used other than OpenSSL. If you modify file(s) with this
|
||||||
|
# exception, you may extend this exception to your version of the file(s),
|
||||||
|
# but you are not obligated to do so. If you do not wish to do so, delete
|
||||||
|
# this exception statement from your version. If you delete this exception
|
||||||
|
# statement from all source files in the program, then also delete it here.
|
||||||
|
|
||||||
|
"""The torrent details component shows info about the selected torrent."""
|
||||||
|
|
||||||
|
import pygtk
|
||||||
|
pygtk.require('2.0')
|
||||||
|
import gtk, gtk.glade
|
||||||
|
import gettext
|
||||||
|
|
||||||
|
import deluge.ui.functions as functions
|
||||||
|
import deluge.common
|
||||||
|
from deluge.log import LOG as log
|
||||||
|
|
||||||
|
class TorrentDetails:
|
||||||
|
def __init__(self, window):
|
||||||
|
self.window = window
|
||||||
|
glade = self.window.main_glade
|
||||||
|
|
||||||
|
self.core = functions.get_core()
|
||||||
|
|
||||||
|
self.notebook = glade.get_widget("torrent_info")
|
||||||
|
self.details_tab = glade.get_widget("torrentdetails_tab")
|
||||||
|
|
||||||
|
# Get the labels we need to update.
|
||||||
|
self.progress_bar = glade.get_widget("progressbar")
|
||||||
|
self.name = glade.get_widget("summary_name")
|
||||||
|
self.total_size = glade.get_widget("summary_total_size")
|
||||||
|
self.num_files = glade.get_widget("summary_num_files")
|
||||||
|
self.pieces = glade.get_widget("summary_pieces")
|
||||||
|
self.availability = glade.get_widget("summary_availability")
|
||||||
|
self.total_downloaded = glade.get_widget("summary_total_downloaded")
|
||||||
|
self.total_uploaded = glade.get_widget("summary_total_uploaded")
|
||||||
|
self.download_speed = glade.get_widget("summary_download_speed")
|
||||||
|
self.upload_speed = glade.get_widget("summary_upload_speed")
|
||||||
|
self.seeders = glade.get_widget("summary_seeders")
|
||||||
|
self.peers = glade.get_widget("summary_peers")
|
||||||
|
self.percentage_done = glade.get_widget("summary_percentage_done")
|
||||||
|
self.share_ratio = glade.get_widget("summary_share_ratio")
|
||||||
|
self.tracker = glade.get_widget("summary_tracker")
|
||||||
|
self.tracker_status = glade.get_widget("summary_tracker_status")
|
||||||
|
self.next_announce = glade.get_widget("summary_next_announce")
|
||||||
|
self.eta = glade.get_widget("summary_eta")
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
# Only update if this page is showing
|
||||||
|
if self.notebook.page_num(self.details_tab) is \
|
||||||
|
self.notebook.get_current_page():
|
||||||
|
# Get the first selected torrent
|
||||||
|
selected = self.window.torrentview.get_selected_torrents()
|
||||||
|
|
||||||
|
# Only use the first torrent in the list or return if None selected
|
||||||
|
if selected is not None:
|
||||||
|
selected = selected[0]
|
||||||
|
else:
|
||||||
|
# No torrent is selected in the torrentview
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the torrent status
|
||||||
|
status_keys = ["progress", "name", "total_size", "num_files",
|
||||||
|
"num_pieces", "piece_length", "distributed_copies",
|
||||||
|
"total_done", "total_payload_download", "total_uploaded",
|
||||||
|
"total_payload_upload", "download_payload_rate",
|
||||||
|
"upload_payload_rate", "num_peers", "num_seeds", "total_peers",
|
||||||
|
"total_seeds", "eta", "ratio", "tracker", "next_announce"]
|
||||||
|
status = functions.get_torrent_status(self.core,
|
||||||
|
selected,
|
||||||
|
status_keys)
|
||||||
|
|
||||||
|
# We need to adjust the value core gives us for progress
|
||||||
|
progress = status["progress"]/100
|
||||||
|
self.progress_bar.set_fraction(progress)
|
||||||
|
self.progress_bar.set_text(deluge.common.fpcnt(progress))
|
||||||
|
|
||||||
|
self.name.set_text(status["name"])
|
||||||
|
self.total_size.set_text(deluge.common.fsize(status["total_size"]))
|
||||||
|
self.num_files.set_text(str(status["num_files"]))
|
||||||
|
self.pieces.set_text("%s (%s)" % (status["num_pieces"],
|
||||||
|
deluge.common.fsize(status["piece_length"])))
|
||||||
|
self.availability.set_text("%.3f" % status["distributed_copies"])
|
||||||
|
self.total_downloaded.set_text("%s (%s)" % \
|
||||||
|
(deluge.common.fsize(status["total_done"]),
|
||||||
|
deluge.common.fsize(status["total_payload_download"])))
|
||||||
|
self.total_uploaded.set_text("%s (%s)" % \
|
||||||
|
(deluge.common.fsize(status["total_uploaded"]),
|
||||||
|
deluge.common.fsize(status["total_payload_upload"])))
|
||||||
|
self.download_speed.set_text(
|
||||||
|
deluge.common.fspeed(status["download_payload_rate"]))
|
||||||
|
self.upload_speed.set_text(
|
||||||
|
deluge.common.fspeed(status["upload_payload_rate"]))
|
||||||
|
self.seeders.set_text(deluge.common.fpeer(status["num_seeds"],
|
||||||
|
status["total_seeds"]))
|
||||||
|
self.peers.set_text(deluge.common.fpeer(status["num_peers"],
|
||||||
|
status["total_peers"]))
|
||||||
|
self.eta.set_text(deluge.common.ftime(status["eta"]))
|
||||||
|
self.share_ratio.set_text("%.3f" % status["ratio"])
|
||||||
|
self.tracker.set_text(status["tracker"])
|
||||||
|
self.next_announce.set_text(
|
||||||
|
deluge.common.ftime(status["next_announce"]))
|
||||||
|
|
|
@ -63,11 +63,13 @@ class TorrentView(listview.ListView):
|
||||||
self.add_func_column("Seeders",
|
self.add_func_column("Seeders",
|
||||||
listview.cell_data_peer,
|
listview.cell_data_peer,
|
||||||
[int, int],
|
[int, int],
|
||||||
status_field=["num_seeds", "num_seeds"])
|
status_field=["num_seeds",
|
||||||
|
"total_seeds"])
|
||||||
self.add_func_column("Peers",
|
self.add_func_column("Peers",
|
||||||
listview.cell_data_peer,
|
listview.cell_data_peer,
|
||||||
[int, int],
|
[int, int],
|
||||||
status_field=["num_peers", "num_peers"])
|
status_field=["num_peers",
|
||||||
|
"total_peers"])
|
||||||
self.add_func_column("Down Speed",
|
self.add_func_column("Down Speed",
|
||||||
listview.cell_data_speed,
|
listview.cell_data_speed,
|
||||||
[float],
|
[float],
|
||||||
|
@ -201,6 +203,11 @@ class TorrentView(listview.ListView):
|
||||||
torrent_ids.append(
|
torrent_ids.append(
|
||||||
self.liststore.get_value(
|
self.liststore.get_value(
|
||||||
self.liststore.get_iter(path), 0))
|
self.liststore.get_iter(path), 0))
|
||||||
|
|
||||||
|
if len(torrent_ids) is 0:
|
||||||
|
# Only return a list if there is something in it.
|
||||||
|
return None
|
||||||
|
|
||||||
return torrent_ids
|
return torrent_ids
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
Loading…
Reference in New Issue