Fix #229 add 'date added' column, with patch from Lajnold

This commit is contained in:
Andrew Resch 2008-11-02 04:41:55 +00:00
parent a2a3bd2148
commit e5cbca13dc
7 changed files with 721 additions and 667 deletions

View File

@ -68,7 +68,7 @@ STATUS_KEYS = ['active_time', 'compact', 'distributed_copies', 'download_payload
'move_on_completed_path', 'name', 'next_announce', 'num_files', 'num_peers', 'num_pieces', 'move_on_completed_path', 'name', 'next_announce', 'num_files', 'num_peers', 'num_pieces',
'num_seeds', 'paused', 'peers', 'piece_length', 'prioritize_first_last', 'private', 'progress', 'num_seeds', 'paused', 'peers', 'piece_length', 'prioritize_first_last', 'private', 'progress',
'queue', 'ratio', 'remove_at_ratio', 'save_path', 'seed_rank', 'seeding_time', 'state', 'stop_at_ratio', 'queue', 'ratio', 'remove_at_ratio', 'save_path', 'seed_rank', 'seeding_time', 'state', 'stop_at_ratio',
'stop_ratio', 'total_done', 'total_payload_download', 'total_payload_upload', 'total_peers', 'stop_ratio', 'time_added', 'total_done', 'total_payload_download', 'total_payload_upload', 'total_peers',
'total_seeds', 'total_size', 'total_uploaded', 'total_wanted', 'tracker', 'tracker_host', 'total_seeds', 'total_size', 'total_uploaded', 'total_wanted', 'tracker', 'tracker_host',
'tracker_status', 'trackers', 'upload_payload_rate'] 'tracker_status', 'trackers', 'upload_payload_rate']

View File

@ -34,6 +34,7 @@
"""Internal Torrent class""" """Internal Torrent class"""
import os import os
import time
from urlparse import urlparse from urlparse import urlparse
try: try:
@ -198,6 +199,11 @@ class Torrent:
# The tracker status # The tracker status
self.tracker_status = "" self.tracker_status = ""
if state:
self.time_added = state.time_added
else:
self.time_added = time.time()
log.debug("Torrent object created.") log.debug("Torrent object created.")
## Options methods ## ## Options methods ##
@ -566,7 +572,8 @@ class Torrent:
"stop_at_ratio": self.options["stop_at_ratio"], "stop_at_ratio": self.options["stop_at_ratio"],
"remove_at_ratio": self.options["remove_at_ratio"], "remove_at_ratio": self.options["remove_at_ratio"],
"move_on_completed": self.options["move_completed"], "move_on_completed": self.options["move_completed"],
"move_on_completed_path": self.options["move_completed_path"] "move_on_completed_path": self.options["move_completed_path"],
"time_added": self.time_added
} }
def ti_name(): def ti_name():

View File

@ -2,19 +2,19 @@
# torrentmanager.py # torrentmanager.py
# #
# Copyright (C) 2007, 2008 Andrew Resch ('andar') <andrewresch@gmail.com> # Copyright (C) 2007, 2008 Andrew Resch ('andar') <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
# You may redistribute it and/or modify it under the terms of the # You may redistribute it and/or modify it under the terms of the
# GNU General Public License, as published by the Free Software # GNU General Public License, as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) # Foundation; either version 3 of the License, or (at your option)
# any later version. # any later version.
# #
# deluge is distributed in the hope that it will be useful, # deluge is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details. # See the GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with deluge. If not, write to: # along with deluge. If not, write to:
# The Free Software Foundation, Inc., # The Free Software Foundation, Inc.,
@ -53,7 +53,7 @@ from deluge.core.torrent import TorrentOptions
import deluge.core.oldstateupgrader import deluge.core.oldstateupgrader
from deluge.log import LOG as log from deluge.log import LOG as log
class TorrentState: class TorrentState:
def __init__(self, def __init__(self,
torrent_id=None, torrent_id=None,
@ -61,7 +61,7 @@ class TorrentState:
total_uploaded=0, total_uploaded=0,
trackers=None, trackers=None,
compact=False, compact=False,
paused=False, paused=False,
save_path=None, save_path=None,
max_connections=-1, max_connections=-1,
max_upload_slots=-1, max_upload_slots=-1,
@ -75,7 +75,8 @@ class TorrentState:
stop_ratio=2.00, stop_ratio=2.00,
stop_at_ratio=False, stop_at_ratio=False,
remove_at_ratio=False, remove_at_ratio=False,
magnet=None magnet=None,
time_added=-1
): ):
self.torrent_id = torrent_id self.torrent_id = torrent_id
self.filename = filename self.filename = filename
@ -84,6 +85,7 @@ class TorrentState:
self.queue = queue self.queue = queue
self.is_finished = is_finished self.is_finished = is_finished
self.magnet = magnet self.magnet = magnet
self.time_added = time_added
# Options # Options
self.compact = compact self.compact = compact
@ -108,7 +110,7 @@ class TorrentManager(component.Component):
"""TorrentManager contains a list of torrents in the current libtorrent """TorrentManager contains a list of torrents in the current libtorrent
session. This object is also responsible for saving the state of the session. This object is also responsible for saving the state of the
session for use on restart.""" session for use on restart."""
def __init__(self, session, alerts): def __init__(self, session, alerts):
component.Component.__init__(self, "TorrentManager", interval=5000, depend=["PluginManager"]) component.Component.__init__(self, "TorrentManager", interval=5000, depend=["PluginManager"])
log.debug("TorrentManager init..") log.debug("TorrentManager init..")
@ -121,12 +123,12 @@ class TorrentManager(component.Component):
# Create the torrents dict { torrent_id: Torrent } # Create the torrents dict { torrent_id: Torrent }
self.torrents = {} self.torrents = {}
# This is a list of torrent_id when we shutdown the torrentmanager. # This is a list of torrent_id when we shutdown the torrentmanager.
# We use this list to determine if all active torrents have been paused # We use this list to determine if all active torrents have been paused
# and that their resume data has been written. # and that their resume data has been written.
self.shutdown_torrent_pause_list = [] self.shutdown_torrent_pause_list = []
# Register set functions # Register set functions
self.config.register_set_function("max_connections_per_torrent", self.config.register_set_function("max_connections_per_torrent",
self.on_set_max_connections_per_torrent) self.on_set_max_connections_per_torrent)
@ -136,9 +138,9 @@ class TorrentManager(component.Component):
self.on_set_max_upload_speed_per_torrent) self.on_set_max_upload_speed_per_torrent)
self.config.register_set_function("max_download_speed_per_torrent", self.config.register_set_function("max_download_speed_per_torrent",
self.on_set_max_download_speed_per_torrent) self.on_set_max_download_speed_per_torrent)
# Register alert functions # Register alert functions
self.alerts.register_handler("torrent_finished_alert", self.alerts.register_handler("torrent_finished_alert",
self.on_alert_torrent_finished) self.on_alert_torrent_finished)
self.alerts.register_handler("torrent_paused_alert", self.alerts.register_handler("torrent_paused_alert",
self.on_alert_torrent_paused) self.on_alert_torrent_paused)
@ -155,7 +157,7 @@ class TorrentManager(component.Component):
self.on_alert_tracker_error) self.on_alert_tracker_error)
self.alerts.register_handler("storage_moved_alert", self.alerts.register_handler("storage_moved_alert",
self.on_alert_storage_moved) self.on_alert_storage_moved)
self.alerts.register_handler("torrent_resumed_alert", self.alerts.register_handler("torrent_resumed_alert",
self.on_alert_torrent_resumed) self.on_alert_torrent_resumed)
self.alerts.register_handler("state_changed_alert", self.alerts.register_handler("state_changed_alert",
self.on_alert_state_changed) self.on_alert_state_changed)
@ -167,16 +169,16 @@ class TorrentManager(component.Component):
self.on_alert_file_renamed) self.on_alert_file_renamed)
self.alerts.register_handler("metadata_received_alert", self.alerts.register_handler("metadata_received_alert",
self.on_alert_metadata_received) self.on_alert_metadata_received)
def start(self): def start(self):
# Get the pluginmanager reference # Get the pluginmanager reference
self.plugins = component.get("PluginManager") self.plugins = component.get("PluginManager")
self.signals = component.get("SignalManager") self.signals = component.get("SignalManager")
# Run the old state upgrader before loading state # Run the old state upgrader before loading state
deluge.core.oldstateupgrader.OldStateUpgrader() deluge.core.oldstateupgrader.OldStateUpgrader()
# Try to load the state from file # Try to load the state from file
self.load_state() self.load_state()
@ -187,7 +189,7 @@ class TorrentManager(component.Component):
def stop(self): def stop(self):
# Save state on shutdown # Save state on shutdown
self.save_state() self.save_state()
for key in self.torrents.keys(): for key in self.torrents.keys():
if not self.torrents[key].handle.is_paused(): if not self.torrents[key].handle.is_paused():
# We set auto_managed false to prevent lt from resuming the torrent # We set auto_managed false to prevent lt from resuming the torrent
@ -209,7 +211,7 @@ class TorrentManager(component.Component):
time.sleep(0.01) time.sleep(0.01)
# Wait for all alerts # Wait for all alerts
self.alerts.handle_alerts(True) self.alerts.handle_alerts(True)
def update(self): def update(self):
for torrent_id, torrent in self.torrents.items(): for torrent_id, torrent in self.torrents.items():
if self.config["stop_seed_at_ratio"] or torrent.options["stop_at_ratio"]: if self.config["stop_seed_at_ratio"] or torrent.options["stop_at_ratio"]:
@ -226,11 +228,11 @@ class TorrentManager(component.Component):
def __getitem__(self, torrent_id): def __getitem__(self, torrent_id):
"""Return the Torrent with torrent_id""" """Return the Torrent with torrent_id"""
return self.torrents[torrent_id] return self.torrents[torrent_id]
def get_torrent_list(self): def get_torrent_list(self):
"""Returns a list of torrent_ids""" """Returns a list of torrent_ids"""
return self.torrents.keys() return self.torrents.keys()
def get_torrent_info_from_file(self, filepath): def get_torrent_info_from_file(self, filepath):
"""Returns a torrent_info for the file specified or None""" """Returns a torrent_info for the file specified or None"""
torrent_info = None torrent_info = None
@ -242,16 +244,16 @@ class TorrentManager(component.Component):
_file.close() _file.close()
except (IOError, RuntimeError), e: except (IOError, RuntimeError), e:
log.warning("Unable to open %s: %s", filepath, e) log.warning("Unable to open %s: %s", filepath, e)
return torrent_info return torrent_info
def get_resume_data_from_file(self, torrent_id): def get_resume_data_from_file(self, torrent_id):
"""Returns an entry with the resume data or None""" """Returns an entry with the resume data or None"""
fastresume = "" fastresume = ""
try: try:
_file = open( _file = open(
os.path.join( os.path.join(
self.config["state_location"], self.config["state_location"],
torrent_id + ".fastresume"), torrent_id + ".fastresume"),
"rb") "rb")
fastresume = _file.read() fastresume = _file.read()
@ -260,18 +262,18 @@ class TorrentManager(component.Component):
log.debug("Unable to load .fastresume: %s", e) log.debug("Unable to load .fastresume: %s", e)
return str(fastresume) return str(fastresume)
def add(self, torrent_info=None, state=None, options=None, save_state=True, def add(self, torrent_info=None, state=None, options=None, save_state=True,
filedump=None, filename=None, magnet=None): filedump=None, filename=None, magnet=None):
"""Add a torrent to the manager and returns it's torrent_id""" """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 and magnet is None: 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.") log.debug("You must specify a valid torrent_info, torrent state or magnet.")
return return
log.debug("torrentmanager.add") log.debug("torrentmanager.add")
add_torrent_params = {} add_torrent_params = {}
if filedump is not None: if filedump is not None:
try: try:
torrent_info = lt.torrent_info(lt.bdecode(filedump)) torrent_info = lt.torrent_info(lt.bdecode(filedump))
@ -294,18 +296,18 @@ class TorrentManager(component.Component):
options["download_location"] = state.save_path options["download_location"] = state.save_path
options["auto_managed"] = state.auto_managed options["auto_managed"] = state.auto_managed
options["add_paused"] = state.paused options["add_paused"] = state.paused
if not state.magnet: if not state.magnet:
add_torrent_params["ti"] =\ add_torrent_params["ti"] =\
self.get_torrent_info_from_file( self.get_torrent_info_from_file(
os.path.join(self.config["state_location"], state.torrent_id + ".torrent")) os.path.join(self.config["state_location"], state.torrent_id + ".torrent"))
if not add_torrent_params["ti"]: if not add_torrent_params["ti"]:
log.error("Unable to add torrent!") log.error("Unable to add torrent!")
return return
else: else:
magnet = state.magnet magnet = state.magnet
add_torrent_params["resume_data"] = self.get_resume_data_from_file(state.torrent_id) add_torrent_params["resume_data"] = self.get_resume_data_from_file(state.torrent_id)
else: else:
# We have a torrent_info object so we're not loading from state. # We have a torrent_info object so we're not loading from state.
@ -319,16 +321,16 @@ class TorrentManager(component.Component):
add_torrent_params["ti"] = torrent_info add_torrent_params["ti"] = torrent_info
add_torrent_params["resume_data"] = "" add_torrent_params["resume_data"] = ""
#log.info("Adding torrent: %s", filename) #log.info("Adding torrent: %s", filename)
log.debug("options: %s", options) log.debug("options: %s", options)
# Set the right storage_mode # Set the right storage_mode
if options["compact_allocation"]: if options["compact_allocation"]:
storage_mode = lt.storage_mode_t(2) storage_mode = lt.storage_mode_t(2)
else: else:
storage_mode = lt.storage_mode_t(1) storage_mode = lt.storage_mode_t(1)
# Fill in the rest of the add_torrent_params dictionary # Fill in the rest of the add_torrent_params dictionary
add_torrent_params["save_path"] = options["download_location"].encode("utf8") add_torrent_params["save_path"] = options["download_location"].encode("utf8")
@ -336,11 +338,11 @@ class TorrentManager(component.Component):
add_torrent_params["paused"] = True add_torrent_params["paused"] = True
add_torrent_params["auto_managed"] = False add_torrent_params["auto_managed"] = False
add_torrent_params["duplicate_is_error"] = True add_torrent_params["duplicate_is_error"] = True
# We need to pause the AlertManager momentarily to prevent alerts # We need to pause the AlertManager momentarily to prevent alerts
# for this torrent being generated before a Torrent object is created. # for this torrent being generated before a Torrent object is created.
component.pause("AlertManager") component.pause("AlertManager")
handle = None handle = None
try: try:
if magnet: if magnet:
@ -349,13 +351,13 @@ class TorrentManager(component.Component):
handle = self.session.add_torrent(add_torrent_params) handle = self.session.add_torrent(add_torrent_params)
except RuntimeError, e: except RuntimeError, e:
log.warning("Error adding torrent: %s", e) log.warning("Error adding torrent: %s", e)
if not handle or not handle.is_valid(): if not handle or not handle.is_valid():
log.debug("torrent handle is invalid!") log.debug("torrent handle is invalid!")
# The torrent was not added to the session # The torrent was not added to the session
component.resume("AlertManager") component.resume("AlertManager")
return return
log.debug("handle id: %s", str(handle.info_hash())) log.debug("handle id: %s", str(handle.info_hash()))
# Set auto_managed to False because the torrent is paused # Set auto_managed to False because the torrent is paused
handle.auto_managed(False) handle.auto_managed(False)
@ -365,7 +367,7 @@ class TorrentManager(component.Component):
self.torrents[torrent.torrent_id] = torrent self.torrents[torrent.torrent_id] = torrent
if self.config["queue_new_to_top"]: if self.config["queue_new_to_top"]:
handle.queue_position_top() handle.queue_position_top()
component.resume("AlertManager") component.resume("AlertManager")
# Resume the torrent if needed # Resume the torrent if needed
@ -375,7 +377,7 @@ class TorrentManager(component.Component):
# Write the .torrent file to the state directory # Write the .torrent file to the state directory
if filedump: if filedump:
try: try:
save_file = open(os.path.join(self.config["state_location"], save_file = open(os.path.join(self.config["state_location"],
torrent.torrent_id + ".torrent"), torrent.torrent_id + ".torrent"),
"wb") "wb")
save_file.write(filedump) save_file.write(filedump)
@ -398,10 +400,10 @@ class TorrentManager(component.Component):
if save_state: if save_state:
# Save the session state # Save the session state
self.save_state() self.save_state()
# Emit the torrent_added signal # Emit the torrent_added signal
self.signals.emit("torrent_added", torrent.torrent_id) self.signals.emit("torrent_added", torrent.torrent_id)
return torrent.torrent_id return torrent.torrent_id
def load_torrent(self, torrent_id): def load_torrent(self, torrent_id):
@ -412,16 +414,16 @@ class TorrentManager(component.Component):
log.debug("Attempting to open %s for add.", torrent_id) log.debug("Attempting to open %s for add.", torrent_id)
_file = open( _file = open(
os.path.join( os.path.join(
self.config["state_location"], torrent_id + ".torrent"), self.config["state_location"], torrent_id + ".torrent"),
"rb") "rb")
filedump = lt.bdecode(_file.read()) filedump = lt.bdecode(_file.read())
_file.close() _file.close()
except (IOError, RuntimeError), e: except (IOError, RuntimeError), e:
log.warning("Unable to open %s: %s", torrent_id, e) log.warning("Unable to open %s: %s", torrent_id, e)
return False return False
return filedump return filedump
def remove(self, torrent_id, remove_torrent=False, remove_data=False): def remove(self, torrent_id, remove_torrent=False, remove_data=False):
"""Remove a torrent from the manager""" """Remove a torrent from the manager"""
try: try:
@ -430,17 +432,17 @@ class TorrentManager(component.Component):
# Remove data if set # Remove data if set
if remove_data: if remove_data:
option = 1 option = 1
self.session.remove_torrent(self.torrents[torrent_id].handle, self.session.remove_torrent(self.torrents[torrent_id].handle,
option) option)
except (RuntimeError, KeyError), e: except (RuntimeError, KeyError), e:
log.warning("Error removing torrent: %s", e) log.warning("Error removing torrent: %s", e)
return False return False
# Remove the .torrent file if requested # Remove the .torrent file if requested
if remove_torrent: if remove_torrent:
try: try:
torrent_file = os.path.join( torrent_file = os.path.join(
self.config["torrentfiles_location"], self.config["torrentfiles_location"],
self.torrents[torrent_id].filename) self.torrents[torrent_id].filename)
os.remove(torrent_file) os.remove(torrent_file)
except Exception, e: except Exception, e:
@ -448,24 +450,24 @@ class TorrentManager(component.Component):
# Remove the .fastresume if it exists # Remove the .fastresume if it exists
self.torrents[torrent_id].delete_fastresume() self.torrents[torrent_id].delete_fastresume()
# Remove the .torrent file in the state # Remove the .torrent file in the state
self.torrents[torrent_id].delete_torrentfile() self.torrents[torrent_id].delete_torrentfile()
# Remove the torrent from deluge's session # Remove the torrent from deluge's session
try: try:
del self.torrents[torrent_id] del self.torrents[torrent_id]
except KeyError, ValueError: except KeyError, ValueError:
return False return False
# Save the session state # Save the session state
self.save_state() self.save_state()
# Emit the signal to the clients # Emit the signal to the clients
self.signals.emit("torrent_removed", torrent_id) self.signals.emit("torrent_removed", torrent_id)
return True return True
def load_state(self): def load_state(self):
"""Load the state of the TorrentManager from the torrents.state file""" """Load the state of the TorrentManager from the torrents.state file"""
state = TorrentManagerState() state = TorrentManagerState()
@ -478,7 +480,7 @@ class TorrentManager(component.Component):
state_file.close() state_file.close()
except (EOFError, IOError, Exception), e: except (EOFError, IOError, Exception), e:
log.warning("Unable to load state file: %s", e) log.warning("Unable to load state file: %s", e)
# Try to use an old state # Try to use an old state
try: try:
if dir(state.torrents[0]) != dir(TorrentState()): if dir(state.torrents[0]) != dir(TorrentState()):
@ -487,7 +489,7 @@ class TorrentManager(component.Component):
setattr(s, attr, getattr(TorrentState(), attr, None)) setattr(s, attr, getattr(TorrentState(), attr, None))
except Exception, e: except Exception, e:
log.warning("Unable to update state file to a compatible version: %s", e) log.warning("Unable to update state file to a compatible version: %s", e)
# Reorder the state.torrents list to add torrents in the correct queue # Reorder the state.torrents list to add torrents in the correct queue
# order. # order.
ordered_state = [] ordered_state = []
@ -498,14 +500,14 @@ class TorrentManager(component.Component):
break break
if torrent_state not in ordered_state: if torrent_state not in ordered_state:
ordered_state.append(torrent_state) ordered_state.append(torrent_state)
for torrent_state in ordered_state: for torrent_state in ordered_state:
try: try:
self.add(state=torrent_state, save_state=False) self.add(state=torrent_state, save_state=False)
except AttributeError, e: except AttributeError, e:
log.error("Torrent state file is either corrupt or incompatible!") log.error("Torrent state file is either corrupt or incompatible!")
break break
# Run the post_session_load plugin hooks # Run the post_session_load plugin hooks
self.plugins.run_post_session_load() self.plugins.run_post_session_load()
@ -517,14 +519,14 @@ class TorrentManager(component.Component):
paused = False paused = False
if torrent.state == "Paused": if torrent.state == "Paused":
paused = True paused = True
torrent_state = TorrentState( torrent_state = TorrentState(
torrent.torrent_id, torrent.torrent_id,
torrent.filename, torrent.filename,
torrent.get_status(["total_uploaded"])["total_uploaded"], torrent.get_status(["total_uploaded"])["total_uploaded"],
torrent.trackers, torrent.trackers,
torrent.options["compact_allocation"], torrent.options["compact_allocation"],
paused, paused,
torrent.options["download_location"], torrent.options["download_location"],
torrent.options["max_connections"], torrent.options["max_connections"],
torrent.options["max_upload_slots"], torrent.options["max_upload_slots"],
@ -538,21 +540,22 @@ class TorrentManager(component.Component):
torrent.options["stop_ratio"], torrent.options["stop_ratio"],
torrent.options["stop_at_ratio"], torrent.options["stop_at_ratio"],
torrent.options["remove_at_ratio"], torrent.options["remove_at_ratio"],
torrent.magnet torrent.magnet,
torrent.time_added
) )
state.torrents.append(torrent_state) state.torrents.append(torrent_state)
# Pickle the TorrentManagerState object # Pickle the TorrentManagerState object
try: try:
log.debug("Saving torrent state file.") log.debug("Saving torrent state file.")
state_file = open( state_file = open(
os.path.join(self.config["state_location"], "torrents.state"), os.path.join(self.config["state_location"], "torrents.state"),
"wb") "wb")
cPickle.dump(state, state_file) cPickle.dump(state, state_file)
state_file.close() state_file.close()
except IOError: except IOError:
log.warning("Unable to save state file.") log.warning("Unable to save state file.")
# We return True so that the timer thread will continue # We return True so that the timer thread will continue
return True return True
@ -560,7 +563,7 @@ class TorrentManager(component.Component):
"""Saves resume data for all the torrents""" """Saves resume data for all the torrents"""
for torrent in self.torrents.values(): for torrent in self.torrents.values():
torrent.save_resume_data() torrent.save_resume_data()
def queue_top(self, torrent_id): def queue_top(self, torrent_id):
"""Queue torrent to top""" """Queue torrent to top"""
if self.torrents[torrent_id].get_queue_position() == 0: if self.torrents[torrent_id].get_queue_position() == 0:
@ -581,7 +584,7 @@ class TorrentManager(component.Component):
"""Queue torrent down one position""" """Queue torrent down one position"""
if self.torrents[torrent_id].get_queue_position() == (len(self.torrents) - 1): if self.torrents[torrent_id].get_queue_position() == (len(self.torrents) - 1):
return False return False
self.torrents[torrent_id].handle.queue_position_down() self.torrents[torrent_id].handle.queue_position_down()
return True return True
@ -592,13 +595,13 @@ class TorrentManager(component.Component):
self.torrents[torrent_id].handle.queue_position_bottom() self.torrents[torrent_id].handle.queue_position_bottom()
return True return True
def on_set_max_connections_per_torrent(self, key, value): def on_set_max_connections_per_torrent(self, key, value):
"""Sets the per-torrent connection limit""" """Sets the per-torrent connection limit"""
log.debug("max_connections_per_torrent set to %s..", value) log.debug("max_connections_per_torrent set to %s..", value)
for key in self.torrents.keys(): for key in self.torrents.keys():
self.torrents[key].set_max_connections(value) self.torrents[key].set_max_connections(value)
def on_set_max_upload_slots_per_torrent(self, key, value): def on_set_max_upload_slots_per_torrent(self, key, value):
"""Sets the per-torrent upload slot limit""" """Sets the per-torrent upload slot limit"""
log.debug("max_upload_slots_per_torrent set to %s..", value) log.debug("max_upload_slots_per_torrent set to %s..", value)
@ -609,7 +612,7 @@ class TorrentManager(component.Component):
log.debug("max_upload_speed_per_torrent set to %s..", value) log.debug("max_upload_speed_per_torrent set to %s..", value)
for key in self.torrents.keys(): for key in self.torrents.keys():
self.torrents[key].set_max_upload_speed(value) self.torrents[key].set_max_upload_speed(value)
def on_set_max_download_speed_per_torrent(self, key, value): def on_set_max_download_speed_per_torrent(self, key, value):
log.debug("max_download_speed_per_torrent set to %s..", value) log.debug("max_download_speed_per_torrent set to %s..", value)
for key in self.torrents.keys(): for key in self.torrents.keys():
@ -637,7 +640,7 @@ class TorrentManager(component.Component):
torrent.update_state() torrent.update_state()
torrent.save_resume_data() torrent.save_resume_data()
component.get("SignalManager").emit("torrent_finished", torrent_id) component.get("SignalManager").emit("torrent_finished", torrent_id)
def on_alert_torrent_paused(self, alert): def on_alert_torrent_paused(self, alert):
log.debug("on_alert_torrent_paused") log.debug("on_alert_torrent_paused")
# Get the torrent_id # Get the torrent_id
@ -645,20 +648,20 @@ class TorrentManager(component.Component):
# Set the torrent state # Set the torrent state
self.torrents[torrent_id].update_state() self.torrents[torrent_id].update_state()
component.get("SignalManager").emit("torrent_paused", torrent_id) component.get("SignalManager").emit("torrent_paused", torrent_id)
# Write the fastresume file # Write the fastresume file
self.torrents[torrent_id].save_resume_data() self.torrents[torrent_id].save_resume_data()
if torrent_id in self.shutdown_torrent_pause_list: if torrent_id in self.shutdown_torrent_pause_list:
self.shutdown_torrent_pause_list.remove(torrent_id) self.shutdown_torrent_pause_list.remove(torrent_id)
def on_alert_torrent_checked(self, alert): def on_alert_torrent_checked(self, alert):
log.debug("on_alert_torrent_checked") log.debug("on_alert_torrent_checked")
# Get the torrent_id # Get the torrent_id
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
# Set the torrent state # Set the torrent state
self.torrents[torrent_id].update_state() self.torrents[torrent_id].update_state()
def on_alert_tracker_reply(self, alert): def on_alert_tracker_reply(self, alert):
log.debug("on_alert_tracker_reply: %s", alert.message()) log.debug("on_alert_tracker_reply: %s", alert.message())
# Get the torrent_id # Get the torrent_id
@ -669,7 +672,7 @@ class TorrentManager(component.Component):
self.torrents[torrent_id].set_tracker_status(_("Announce OK")) self.torrents[torrent_id].set_tracker_status(_("Announce OK"))
except KeyError: except KeyError:
log.debug("torrent_id doesn't exist.") log.debug("torrent_id doesn't exist.")
# Check to see if we got any peer information from the tracker # Check to see if we got any peer information from the tracker
if alert.handle.status().num_complete == -1 or \ if alert.handle.status().num_complete == -1 or \
alert.handle.status().num_incomplete == -1: alert.handle.status().num_incomplete == -1:
@ -684,7 +687,7 @@ class TorrentManager(component.Component):
except RuntimeError: except RuntimeError:
log.debug("Invalid torrent handle.") log.debug("Invalid torrent handle.")
return return
# Set the tracker status for the torrent # Set the tracker status for the torrent
try: try:
self.torrents[torrent_id].set_tracker_status(_("Announce Sent")) self.torrents[torrent_id].set_tracker_status(_("Announce Sent"))
@ -702,7 +705,7 @@ class TorrentManager(component.Component):
self.torrents[torrent_id].set_tracker_status(tracker_status) self.torrents[torrent_id].set_tracker_status(tracker_status)
except KeyError: except KeyError:
log.debug("torrent_id doesn't exist.") log.debug("torrent_id doesn't exist.")
def on_alert_tracker_warning(self, alert): def on_alert_tracker_warning(self, alert):
log.debug("on_alert_tracker_warning") log.debug("on_alert_tracker_warning")
# Get the torrent_id # Get the torrent_id
@ -722,7 +725,7 @@ class TorrentManager(component.Component):
torrent.set_tracker_status(tracker_status) torrent.set_tracker_status(tracker_status)
except KeyError: except KeyError:
log.debug("torrent_id doesn't exist.") log.debug("torrent_id doesn't exist.")
def on_alert_storage_moved(self, alert): def on_alert_storage_moved(self, alert):
log.debug("on_alert_storage_moved") log.debug("on_alert_storage_moved")
log.debug("save_path: %s", alert.handle.save_path()) log.debug("save_path: %s", alert.handle.save_path())
@ -739,7 +742,7 @@ class TorrentManager(component.Component):
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
torrent.is_finished = torrent.handle.is_seed() torrent.is_finished = torrent.handle.is_seed()
torrent.update_state() torrent.update_state()
def on_alert_state_changed(self, alert): def on_alert_state_changed(self, alert):
log.debug("on_alert_state_changed") log.debug("on_alert_state_changed")
torrent_id = str(alert.handle.info_hash()) torrent_id = str(alert.handle.info_hash())
@ -750,7 +753,7 @@ class TorrentManager(component.Component):
log.debug("on_alert_save_resume_data") log.debug("on_alert_save_resume_data")
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
torrent.write_resume_data(alert.resume_data) torrent.write_resume_data(alert.resume_data)
def on_alert_save_resume_data_failed(self, alert): def on_alert_save_resume_data_failed(self, alert):
log.debug("on_alert_save_resume_data_failed: %s", alert.message()) log.debug("on_alert_save_resume_data_failed: %s", alert.message())
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
@ -764,7 +767,7 @@ class TorrentManager(component.Component):
old_folder = os.path.split(torrent.files[alert.index]["path"])[0] old_folder = os.path.split(torrent.files[alert.index]["path"])[0]
new_folder = os.path.split(alert.name)[0] new_folder = os.path.split(alert.name)[0]
torrent.files[alert.index]["path"] = alert.name torrent.files[alert.index]["path"] = alert.name
if alert.index in torrent.waiting_on_folder_rename: if alert.index in torrent.waiting_on_folder_rename:
if torrent.waiting_on_folder_rename == [alert.index]: if torrent.waiting_on_folder_rename == [alert.index]:
# This is the last alert we were waiting for, time to send signal # This is the last alert we were waiting for, time to send signal
@ -778,4 +781,3 @@ class TorrentManager(component.Component):
log.debug("on_alert_metadata_received") log.debug("on_alert_metadata_received")
torrent = self.torrents[str(alert.handle.info_hash())] torrent = self.torrents[str(alert.handle.info_hash())]
torrent.write_torrentfile() torrent.write_torrentfile()

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
import cPickle import cPickle
import os.path import os.path
import time
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
@ -88,6 +89,14 @@ def cell_data_ratio(column, cell, model, row, data):
cell.set_property('text', ratio_str) cell.set_property('text', ratio_str)
def cell_data_date(column, cell, model, row, data):
"""Display value as date, eg 2008/05/05"""
time_val = model.get_value(row, data)
time_str = ""
if time_val > -1:
time_str = time.strftime("%d/%m/%y", time.localtime(time_val))
cell.set_property('text', time_str)
class ListViewColumnState: class ListViewColumnState:
"""Used for saving/loading column state""" """Used for saving/loading column state"""
def __init__(self, name, position, width, visible, sort, sort_order): def __init__(self, name, position, width, visible, sort, sort_order):

View File

@ -33,6 +33,7 @@
# statement from all source files in the program, then also delete it here. # statement from all source files in the program, then also delete it here.
import gtk, gtk.glade import gtk, gtk.glade
import time
from deluge.ui.client import aclient as client from deluge.ui.client import aclient as client
import deluge.component as component import deluge.component as component
@ -60,6 +61,11 @@ def fspeed(value, max_value=-1):
else: else:
return deluge.common.fspeed(value) return deluge.common.fspeed(value)
def fdate(value):
if value < 0:
return ""
return time.strftime("%d/%m/%y", time.localtime(value))
class StatisticsTab(Tab): class StatisticsTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self) Tab.__init__(self)
@ -88,7 +94,8 @@ class StatisticsTab(Tab):
(glade.get_widget("summary_seed_time"), deluge.common.ftime, ("seeding_time",)), (glade.get_widget("summary_seed_time"), deluge.common.ftime, ("seeding_time",)),
(glade.get_widget("summary_seed_rank"), str, ("seed_rank",)), (glade.get_widget("summary_seed_rank"), str, ("seed_rank",)),
(glade.get_widget("summary_auto_managed"), str, ("is_auto_managed",)), (glade.get_widget("summary_auto_managed"), str, ("is_auto_managed",)),
(glade.get_widget("progressbar"), fpcnt, ("progress",)) (glade.get_widget("progressbar"), fpcnt, ("progress",)),
(glade.get_widget("summary_date_added"), fdate, ("time_added",))
] ]
def update(self): def update(self):
@ -110,7 +117,7 @@ class StatisticsTab(Tab):
"total_seeds", "eta", "ratio", "next_announce", "total_seeds", "eta", "ratio", "next_announce",
"tracker_status", "max_connections", "max_upload_slots", "tracker_status", "max_connections", "max_upload_slots",
"max_upload_speed", "max_download_speed", "active_time", "max_upload_speed", "max_download_speed", "active_time",
"seeding_time", "seed_rank", "is_auto_managed"] "seeding_time", "seed_rank", "is_auto_managed", "time_added"]
client.get_torrent_status( client.get_torrent_status(
self._on_get_torrent_status, selected, status_keys) self._on_get_torrent_status, selected, status_keys)

View File

@ -180,6 +180,10 @@ class TorrentView(listview.ListView, component.Component):
listview.cell_data_ratio, listview.cell_data_ratio,
[float], [float],
status_field=["distributed_copies"]) status_field=["distributed_copies"])
self.add_func_column(_("Added"),
listview.cell_data_date,
[float],
status_field=["time_added"])
self.add_text_column(_("Tracker"), status_field=["tracker_host"]) self.add_text_column(_("Tracker"), status_field=["tracker_host"])
# Set filter to None for now # Set filter to None for now