mirror of
https://git.deluge-torrent.org/deluge
synced 2025-08-02 22:48:40 +00:00
Use new torrent states instead of using libtorrent's.
This commit is contained in:
parent
e2eaa9abb4
commit
9469610aca
7 changed files with 251 additions and 197 deletions
|
@ -39,18 +39,26 @@ import pkg_resources
|
||||||
import xdg, xdg.BaseDirectory
|
import xdg, xdg.BaseDirectory
|
||||||
|
|
||||||
|
|
||||||
TORRENT_STATE = [
|
LT_TORRENT_STATE = {
|
||||||
"Queued",
|
"Queued": 0,
|
||||||
"Checking",
|
"Checking": 1,
|
||||||
"Connecting",
|
"Connecting": 2,
|
||||||
"Downloading Metadata",
|
"Downloading Metadata": 3,
|
||||||
"Downloading",
|
"Downloading": 4,
|
||||||
"Finished",
|
"Finished": 5,
|
||||||
"Seeding",
|
"Seeding": 6,
|
||||||
"Allocating",
|
"Allocating": 7,
|
||||||
"Paused"
|
"Paused": 8
|
||||||
]
|
}
|
||||||
|
|
||||||
|
TORRENT_STATE = {
|
||||||
|
"Allocating": 0,
|
||||||
|
"Checking": 1,
|
||||||
|
"Downloading": 2,
|
||||||
|
"Seeding": 3,
|
||||||
|
"Paused": 4,
|
||||||
|
"Error": 5
|
||||||
|
}
|
||||||
def get_version():
|
def get_version():
|
||||||
"""Returns the program version from the egg metadata"""
|
"""Returns the program version from the egg metadata"""
|
||||||
return pkg_resources.require("Deluge")[0].version.split("r")[0]
|
return pkg_resources.require("Deluge")[0].version.split("r")[0]
|
||||||
|
|
|
@ -344,17 +344,17 @@ class Core(
|
||||||
|
|
||||||
def export_force_reannounce(self, torrent_id):
|
def export_force_reannounce(self, torrent_id):
|
||||||
log.debug("Forcing reannouncment to trackers of torrent %s", torrent_id)
|
log.debug("Forcing reannouncment to trackers of torrent %s", torrent_id)
|
||||||
self.torrents.force_reannounce(torrent_id)
|
self.torrents[torrent_id].force_reannounce()
|
||||||
|
|
||||||
def export_pause_torrent(self, torrent_id):
|
def export_pause_torrent(self, torrent_id):
|
||||||
log.debug("Pausing torrent %s", torrent_id)
|
log.debug("Pausing torrent %s", torrent_id)
|
||||||
if not self.torrents.pause(torrent_id):
|
if not self.torrents[torrent_id].pause():
|
||||||
log.warning("Error pausing torrent %s", torrent_id)
|
log.warning("Error pausing torrent %s", torrent_id)
|
||||||
|
|
||||||
def export_move_torrent(self, torrent_id, folder):
|
def export_move_torrent(self, torrent_id, dest):
|
||||||
log.debug("Moving torrent %s to %s", torrent_id, folder)
|
log.debug("Moving torrent %s to %s", torrent_id, dest)
|
||||||
if not self.torrents.move(torrent_id, folder):
|
if not self.torrents[torrent_id].move(dest):
|
||||||
log.warning("Error moving torrent %s to %s", torrent_id, folder)
|
log.warning("Error moving torrent %s to %s", torrent_id, dest)
|
||||||
|
|
||||||
def export_pause_all_torrents(self):
|
def export_pause_all_torrents(self):
|
||||||
"""Pause all torrents in the session"""
|
"""Pause all torrents in the session"""
|
||||||
|
@ -369,7 +369,7 @@ class Core(
|
||||||
|
|
||||||
def export_resume_torrent(self, torrent_id):
|
def export_resume_torrent(self, torrent_id):
|
||||||
log.debug("Resuming torrent %s", torrent_id)
|
log.debug("Resuming torrent %s", torrent_id)
|
||||||
if self.torrents.resume(torrent_id):
|
if self.torrents[torrent_id].resume():
|
||||||
self.torrent_resumed(torrent_id)
|
self.torrent_resumed(torrent_id)
|
||||||
|
|
||||||
def export_get_torrent_status(self, torrent_id, keys):
|
def export_get_torrent_status(self, torrent_id, keys):
|
||||||
|
@ -477,7 +477,7 @@ class Core(
|
||||||
|
|
||||||
def export_set_torrent_trackers(self, torrent_id, trackers):
|
def export_set_torrent_trackers(self, torrent_id, trackers):
|
||||||
"""Sets a torrents tracker list. trackers will be [{"url", "tier"}]"""
|
"""Sets a torrents tracker list. trackers will be [{"url", "tier"}]"""
|
||||||
return self.torrents.set_trackers(torrent_id, trackers)
|
return self.torrents[torrent_id].set_trackers(trackers)
|
||||||
|
|
||||||
# Signals
|
# Signals
|
||||||
def torrent_added(self, torrent_id):
|
def torrent_added(self, torrent_id):
|
||||||
|
|
|
@ -33,13 +33,23 @@
|
||||||
|
|
||||||
"""Internal Torrent class"""
|
"""Internal Torrent class"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import deluge.libtorrent as lt
|
||||||
import deluge.common
|
import deluge.common
|
||||||
|
from deluge.configmanager import ConfigManager
|
||||||
|
from deluge.log import LOG as log
|
||||||
|
|
||||||
|
TORRENT_STATE = deluge.common.TORRENT_STATE
|
||||||
|
|
||||||
class Torrent:
|
class Torrent:
|
||||||
"""Torrent holds information about torrents added to the libtorrent session.
|
"""Torrent holds information about torrents added to the libtorrent session.
|
||||||
"""
|
"""
|
||||||
def __init__(self, filename, handle, compact, save_path, total_uploaded=0,
|
def __init__(self, filename, handle, compact, save_path, total_uploaded=0,
|
||||||
trackers=None):
|
trackers=None):
|
||||||
|
# Get the core config
|
||||||
|
self.config = ConfigManager("core.conf")
|
||||||
|
|
||||||
# Set the filename
|
# Set the filename
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
# Set the libtorrent handle
|
# Set the libtorrent handle
|
||||||
|
@ -52,7 +62,22 @@ class Torrent:
|
||||||
self.compact = compact
|
self.compact = compact
|
||||||
# Where the torrent is being saved to
|
# Where the torrent is being saved to
|
||||||
self.save_path = save_path
|
self.save_path = save_path
|
||||||
|
# The state of the torrent
|
||||||
|
self.state = None
|
||||||
|
|
||||||
|
# Holds status info so that we don't need to keep getting it from lt
|
||||||
|
self.status = self.handle.status()
|
||||||
|
self.torrent_info = self.handle.torrent_info()
|
||||||
|
|
||||||
|
# Set the initial state
|
||||||
|
if self.status.state == deluge.common.LT_TORRENT_STATE["Allocating"]:
|
||||||
|
self.set_state("Allocating")
|
||||||
|
elif self.status.state == deluge.common.LT_TORRENT_STATE["Checking"]:
|
||||||
|
self.set_state("Checking")
|
||||||
|
else:
|
||||||
|
self.set_state("Paused")
|
||||||
|
|
||||||
|
# Various torrent options
|
||||||
self.max_connections = -1
|
self.max_connections = -1
|
||||||
self.max_upload_slots = -1
|
self.max_upload_slots = -1
|
||||||
self.max_upload_speed = -1
|
self.max_upload_speed = -1
|
||||||
|
@ -73,10 +98,6 @@ class Torrent:
|
||||||
self.trackers.append(tracker)
|
self.trackers.append(tracker)
|
||||||
else:
|
else:
|
||||||
self.trackers = trackers
|
self.trackers = trackers
|
||||||
|
|
||||||
# Holds status info so that we don't need to keep getting it from lt
|
|
||||||
self.status = None
|
|
||||||
self.torrent_info = None
|
|
||||||
|
|
||||||
# Files dictionary
|
# Files dictionary
|
||||||
self.files = self.get_files()
|
self.files = self.get_files()
|
||||||
|
@ -114,8 +135,21 @@ class Torrent:
|
||||||
def set_file_priorities(self, file_priorities):
|
def set_file_priorities(self, file_priorities):
|
||||||
self.file_priorities = file_priorities
|
self.file_priorities = file_priorities
|
||||||
self.handle.prioritize_files(file_priorities)
|
self.handle.prioritize_files(file_priorities)
|
||||||
|
|
||||||
def get_state(self):
|
def set_state(self, state):
|
||||||
|
"""Accepts state strings, ie, "Paused", "Seeding", etc."""
|
||||||
|
|
||||||
|
# Only set 'Downloading' or 'Seeding' state if not paused
|
||||||
|
if state == "Downloading" or state == "Seeding":
|
||||||
|
if self.handle.is_paused():
|
||||||
|
state = "Paused"
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.state = TORRENT_STATE[state]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_save_info(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"""
|
||||||
status = self.handle.status()
|
status = self.handle.status()
|
||||||
return (self.torrent_id, self.filename, self.compact, status.paused,
|
return (self.torrent_id, self.filename, self.compact, status.paused,
|
||||||
|
@ -188,11 +222,6 @@ class Torrent:
|
||||||
# Adjust progress to be 0-100 value
|
# Adjust progress to be 0-100 value
|
||||||
progress = self.status.progress * 100
|
progress = self.status.progress * 100
|
||||||
|
|
||||||
# Set the state to 'Paused' if the torrent is paused.
|
|
||||||
state = self.status.state
|
|
||||||
if self.status.paused:
|
|
||||||
state = deluge.common.TORRENT_STATE.index("Paused")
|
|
||||||
|
|
||||||
# Adjust status.distributed_copies to return a non-negative value
|
# Adjust status.distributed_copies to return a non-negative value
|
||||||
distributed_copies = self.status.distributed_copies
|
distributed_copies = self.status.distributed_copies
|
||||||
if distributed_copies < 0:
|
if distributed_copies < 0:
|
||||||
|
@ -207,7 +236,7 @@ class Torrent:
|
||||||
"distributed_copies": distributed_copies,
|
"distributed_copies": distributed_copies,
|
||||||
"total_done": self.status.total_done,
|
"total_done": self.status.total_done,
|
||||||
"total_uploaded": self.total_uploaded + self.status.total_payload_upload,
|
"total_uploaded": self.total_uploaded + self.status.total_payload_upload,
|
||||||
"state": int(state),
|
"state": self.state,
|
||||||
"paused": self.status.paused,
|
"paused": self.status.paused,
|
||||||
"progress": progress,
|
"progress": progress,
|
||||||
"next_announce": self.status.next_announce.seconds,
|
"next_announce": self.status.next_announce.seconds,
|
||||||
|
@ -242,3 +271,139 @@ class Torrent:
|
||||||
status_dict[key] = full_status[key]
|
status_dict[key] = full_status[key]
|
||||||
|
|
||||||
return status_dict
|
return status_dict
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
"""Pause this torrent"""
|
||||||
|
try:
|
||||||
|
self.handle.pause()
|
||||||
|
except Exception, e:
|
||||||
|
log.debug("Unable to pause torrent: %s", e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def resume(self):
|
||||||
|
"""Resumes this torrent"""
|
||||||
|
if self.state != TORRENT_STATE["Paused"]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.handle.resume()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Set the state
|
||||||
|
if self.handle.is_seed():
|
||||||
|
self.set_state("Seeding")
|
||||||
|
else:
|
||||||
|
self.set_state("Downloading")
|
||||||
|
|
||||||
|
status = self.get_status(["total_done", "total_wanted"])
|
||||||
|
|
||||||
|
# Only delete the .fastresume file if we're still downloading stuff
|
||||||
|
if status["total_done"] < status["total_wanted"]:
|
||||||
|
self.delete_fastresume()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def move_storage(self, dest):
|
||||||
|
"""Move a torrent's storage location"""
|
||||||
|
try:
|
||||||
|
self.handle.move_storage(dest)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def write_fastresume(self):
|
||||||
|
"""Writes the .fastresume file for the torrent"""
|
||||||
|
resume_data = lt.bencode(self.handle.write_resume_data())
|
||||||
|
path = "%s/%s.fastresume" % (
|
||||||
|
self.config["torrentfiles_location"],
|
||||||
|
self.filename)
|
||||||
|
log.debug("Saving fastresume file: %s", path)
|
||||||
|
try:
|
||||||
|
fastresume = open(path, "wb")
|
||||||
|
fastresume.write(resume_data)
|
||||||
|
fastresume.close()
|
||||||
|
except IOError:
|
||||||
|
log.warning("Error trying to save fastresume file")
|
||||||
|
|
||||||
|
def delete_fastresume(self):
|
||||||
|
"""Deletes the .fastresume file"""
|
||||||
|
path = "%s/%s.fastresume" % (
|
||||||
|
self.config["torrentfiles_location"],
|
||||||
|
self.filename)
|
||||||
|
log.debug("Deleting fastresume file: %s", path)
|
||||||
|
try:
|
||||||
|
os.remove(path)
|
||||||
|
except Exception, e:
|
||||||
|
log.warning("Unable to delete the fastresume file: %s", e)
|
||||||
|
|
||||||
|
def force_reannounce(self):
|
||||||
|
"""Force a tracker reannounce"""
|
||||||
|
try:
|
||||||
|
self.handle.force_reannounce()
|
||||||
|
except Exception, e:
|
||||||
|
log.debug("Unable to force reannounce: %s", e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def scrape_tracker(self):
|
||||||
|
"""Scrape the tracker"""
|
||||||
|
try:
|
||||||
|
self.handle.scrape_tracker()
|
||||||
|
except Exception, e:
|
||||||
|
log.debug("Unable to scrape tracker: %s", e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_trackers(self, trackers):
|
||||||
|
"""Sets trackers"""
|
||||||
|
if trackers == None:
|
||||||
|
trackers = []
|
||||||
|
|
||||||
|
log.debug("Setting trackers for %s: %s", self.torrent_id, trackers)
|
||||||
|
tracker_list = []
|
||||||
|
|
||||||
|
for tracker in trackers:
|
||||||
|
new_entry = lt.announce_entry(tracker["url"])
|
||||||
|
new_entry.tier = tracker["tier"]
|
||||||
|
tracker_list.append(new_entry)
|
||||||
|
|
||||||
|
self.handle.replace_trackers(tracker_list)
|
||||||
|
|
||||||
|
# Print out the trackers
|
||||||
|
for t in self.handle.trackers():
|
||||||
|
log.debug("tier: %s tracker: %s", t.tier, t.url)
|
||||||
|
# Set the tracker list in the torrent object
|
||||||
|
self.trackers = trackers
|
||||||
|
if len(trackers) > 0:
|
||||||
|
# Force a reannounce if there is at least 1 tracker
|
||||||
|
self.force_reannounce()
|
||||||
|
|
||||||
|
def save_torrent_file(self, filedump=None):
|
||||||
|
"""Saves a torrent file"""
|
||||||
|
log.debug("Attempting to save torrent file: %s", self.filename)
|
||||||
|
# Test if the torrentfiles_location is accessible
|
||||||
|
if os.access(
|
||||||
|
os.path.join(self.config["torrentfiles_location"]), os.F_OK) \
|
||||||
|
is False:
|
||||||
|
# The directory probably doesn't exist, so lets create it
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.join(self.config["torrentfiles_location"]))
|
||||||
|
except IOError, e:
|
||||||
|
log.warning("Unable to create torrent files directory: %s", e)
|
||||||
|
|
||||||
|
# Write the .torrent file to the torrent directory
|
||||||
|
try:
|
||||||
|
save_file = open(os.path.join(self.config["torrentfiles_location"],
|
||||||
|
self.filename),
|
||||||
|
"wb")
|
||||||
|
if filedump == None:
|
||||||
|
filedump = self.handle.torrent_info().create_torrent()
|
||||||
|
save_file.write(lt.bencode(filedump))
|
||||||
|
save_file.close()
|
||||||
|
except IOError, e:
|
||||||
|
log.warning("Unable to save torrent file: %s", e)
|
||||||
|
|
|
@ -93,6 +93,8 @@ class TorrentManager(component.Component):
|
||||||
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)
|
||||||
|
self.alerts.register_handler("torrent_checked_alert",
|
||||||
|
self.on_alert_torrent_checked)
|
||||||
self.alerts.register_handler("tracker_reply_alert",
|
self.alerts.register_handler("tracker_reply_alert",
|
||||||
self.on_alert_tracker_reply)
|
self.on_alert_tracker_reply)
|
||||||
self.alerts.register_handler("tracker_announce_alert",
|
self.alerts.register_handler("tracker_announce_alert",
|
||||||
|
@ -116,7 +118,7 @@ class TorrentManager(component.Component):
|
||||||
# Pause all torrents and save the .fastresume files
|
# Pause all torrents and save the .fastresume files
|
||||||
self.pause_all()
|
self.pause_all()
|
||||||
for key in self.torrents.keys():
|
for key in self.torrents.keys():
|
||||||
self.write_fastresume(key)
|
self.torrents[key].write_fastresume()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
self.stop()
|
self.stop()
|
||||||
|
@ -228,7 +230,7 @@ class TorrentManager(component.Component):
|
||||||
|
|
||||||
# Set the trackers
|
# Set the trackers
|
||||||
if trackers != None:
|
if trackers != None:
|
||||||
self.set_trackers(str(handle.info_hash()), trackers)
|
torrent.set_trackers(trackers)
|
||||||
|
|
||||||
# Set per-torrent options
|
# Set per-torrent options
|
||||||
torrent.set_max_connections(options["max_connections_per_torrent"])
|
torrent.set_max_connections(options["max_connections_per_torrent"])
|
||||||
|
@ -250,34 +252,11 @@ class TorrentManager(component.Component):
|
||||||
handle.resume()
|
handle.resume()
|
||||||
|
|
||||||
# Save the torrent file
|
# Save the torrent file
|
||||||
self.save_torrent(filename, filedump)
|
torrent.save_torrent_file(filedump)
|
||||||
|
|
||||||
# Save the session state
|
# Save the session state
|
||||||
self.save_state()
|
self.save_state()
|
||||||
return torrent.torrent_id
|
return torrent.torrent_id
|
||||||
|
|
||||||
def save_torrent(self, filename, filedump):
|
|
||||||
"""Saves a torrent file"""
|
|
||||||
log.debug("Attempting to save torrent file: %s", filename)
|
|
||||||
# Test if the torrentfiles_location is accessible
|
|
||||||
if os.access(
|
|
||||||
os.path.join(self.config["torrentfiles_location"]), os.F_OK) \
|
|
||||||
is False:
|
|
||||||
# The directory probably doesn't exist, so lets create it
|
|
||||||
try:
|
|
||||||
os.makedirs(os.path.join(self.config["torrentfiles_location"]))
|
|
||||||
except IOError, e:
|
|
||||||
log.warning("Unable to create torrent files directory: %s", e)
|
|
||||||
|
|
||||||
# Write the .torrent file to the torrent directory
|
|
||||||
try:
|
|
||||||
save_file = open(os.path.join(self.config["torrentfiles_location"],
|
|
||||||
filename),
|
|
||||||
"wb")
|
|
||||||
save_file.write(lt.bencode(filedump))
|
|
||||||
save_file.close()
|
|
||||||
except IOError, e:
|
|
||||||
log.warning("Unable to save torrent file: %s", e)
|
|
||||||
|
|
||||||
def load_torrent(self, filename):
|
def load_torrent(self, filename):
|
||||||
"""Load a torrent file and return it's torrent info"""
|
"""Load a torrent file and return it's torrent info"""
|
||||||
|
@ -322,7 +301,7 @@ class TorrentManager(component.Component):
|
||||||
log.warning("Unable to remove .torrent file: %s", e)
|
log.warning("Unable to remove .torrent file: %s", e)
|
||||||
|
|
||||||
# Remove the .fastresume if it exists
|
# Remove the .fastresume if it exists
|
||||||
self.delete_fastresume(torrent_id)
|
self.torrents[torrent_id].delete_fastresume()
|
||||||
|
|
||||||
# Remove the torrent from deluge's session
|
# Remove the torrent from deluge's session
|
||||||
try:
|
try:
|
||||||
|
@ -333,24 +312,6 @@ class TorrentManager(component.Component):
|
||||||
# Save the session state
|
# Save the session state
|
||||||
self.save_state()
|
self.save_state()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def pause(self, torrent_id):
|
|
||||||
"""Pause a torrent"""
|
|
||||||
try:
|
|
||||||
self.torrents[torrent_id].handle.pause()
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def move(self, torrent_id, folder):
|
|
||||||
"""Move a torrent"""
|
|
||||||
try:
|
|
||||||
self.torrents[torrent_id].handle.move_storage(folder)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def pause_all(self):
|
def pause_all(self):
|
||||||
"""Pauses all torrents.. Returns a list of torrents paused."""
|
"""Pauses all torrents.. Returns a list of torrents paused."""
|
||||||
|
@ -363,24 +324,9 @@ class TorrentManager(component.Component):
|
||||||
log.warning("Unable to pause torrent %s", key)
|
log.warning("Unable to pause torrent %s", key)
|
||||||
|
|
||||||
return torrent_was_paused
|
return torrent_was_paused
|
||||||
|
|
||||||
def resume(self, torrent_id):
|
|
||||||
"""Resume a torrent"""
|
|
||||||
try:
|
|
||||||
self.torrents[torrent_id].handle.resume()
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
status = self.torrents[torrent_id].get_status(
|
|
||||||
["total_done", "total_wanted"])
|
|
||||||
|
|
||||||
# Only delete the .fastresume file if we're still downloading stuff
|
|
||||||
if status["total_done"] < status["total_wanted"]:
|
|
||||||
self.delete_fastresume(torrent_id)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def resume_all(self):
|
def resume_all(self):
|
||||||
"""Resumes all torrents.. Returns a list of torrents resumed"""
|
"""Resumes all torrents.. Returns True if at least 1 torrent is resumed"""
|
||||||
torrent_was_resumed = False
|
torrent_was_resumed = False
|
||||||
for key in self.torrents.keys():
|
for key in self.torrents.keys():
|
||||||
if self.resume(key):
|
if self.resume(key):
|
||||||
|
@ -389,50 +335,7 @@ class TorrentManager(component.Component):
|
||||||
log.warning("Unable to resume torrent %s", key)
|
log.warning("Unable to resume torrent %s", key)
|
||||||
|
|
||||||
return torrent_was_resumed
|
return torrent_was_resumed
|
||||||
|
|
||||||
def set_trackers(self, torrent_id, trackers):
|
|
||||||
"""Sets trackers"""
|
|
||||||
if trackers == None:
|
|
||||||
trackers = []
|
|
||||||
|
|
||||||
log.debug("Setting trackers for %s: %s", torrent_id, trackers)
|
|
||||||
tracker_list = []
|
|
||||||
|
|
||||||
for tracker in trackers:
|
|
||||||
new_entry = lt.announce_entry(tracker["url"])
|
|
||||||
new_entry.tier = tracker["tier"]
|
|
||||||
tracker_list.append(new_entry)
|
|
||||||
|
|
||||||
self.torrents[torrent_id].handle.replace_trackers(tracker_list)
|
|
||||||
# Print out the trackers
|
|
||||||
for t in self.torrents[torrent_id].handle.trackers():
|
|
||||||
log.debug("tier: %s tracker: %s", t.tier, t.url)
|
|
||||||
# Set the tracker list in the torrent object
|
|
||||||
self.torrents[torrent_id].trackers = trackers
|
|
||||||
if len(trackers) > 0:
|
|
||||||
# Force a reannounce if there is at least 1 tracker
|
|
||||||
self.force_reannounce(torrent_id)
|
|
||||||
|
|
||||||
def force_reannounce(self, torrent_id):
|
|
||||||
"""Force a tracker reannounce"""
|
|
||||||
try:
|
|
||||||
self.torrents[torrent_id].handle.force_reannounce()
|
|
||||||
except Exception, e:
|
|
||||||
log.debug("Unable to force reannounce: %s", e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def scrape_tracker(self, torrent_id):
|
|
||||||
"""Scrape the tracker"""
|
|
||||||
try:
|
|
||||||
self.torrents[torrent_id].handle.scrape_tracker()
|
|
||||||
except Exception, e:
|
|
||||||
log.debug("Unable to scrape tracker: %s", e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def force_recheck(self, torrent_id):
|
def force_recheck(self, torrent_id):
|
||||||
"""Forces a re-check of the torrent's data"""
|
"""Forces a re-check of the torrent's data"""
|
||||||
log.debug("Doing a forced recheck on %s", torrent_id)
|
log.debug("Doing a forced recheck on %s", torrent_id)
|
||||||
|
@ -443,7 +346,7 @@ class TorrentManager(component.Component):
|
||||||
if os.access(os.path.join(self.config["torrentfiles_location"] +\
|
if os.access(os.path.join(self.config["torrentfiles_location"] +\
|
||||||
"/" + torrent.filename), os.F_OK) is False:
|
"/" + torrent.filename), os.F_OK) is False:
|
||||||
torrent_info = torrent.handle.get_torrent_info().create_torrent()
|
torrent_info = torrent.handle.get_torrent_info().create_torrent()
|
||||||
self.save_torrent(torrent.filename, torrent_info)
|
torrent.save_torrent_file()
|
||||||
|
|
||||||
# We start by removing it from the lt session
|
# We start by removing it from the lt session
|
||||||
try:
|
try:
|
||||||
|
@ -453,7 +356,7 @@ class TorrentManager(component.Component):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Remove the fastresume file if there
|
# Remove the fastresume file if there
|
||||||
self.delete_fastresume(torrent_id)
|
torrent.delete_fastresume()
|
||||||
|
|
||||||
# Load the torrent info from file if needed
|
# Load the torrent info from file if needed
|
||||||
if torrent_info == None:
|
if torrent_info == None:
|
||||||
|
@ -481,6 +384,9 @@ class TorrentManager(component.Component):
|
||||||
# The torrent was not added to the session
|
# The torrent was not added to the session
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Set the state to Checking
|
||||||
|
torrent.set_state("Checking")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def load_state(self):
|
def load_state(self):
|
||||||
|
@ -508,7 +414,7 @@ class TorrentManager(component.Component):
|
||||||
state = TorrentManagerState()
|
state = TorrentManagerState()
|
||||||
# Create the state for each Torrent and append to the list
|
# Create the state for each Torrent and append to the list
|
||||||
for torrent in self.torrents.values():
|
for torrent in self.torrents.values():
|
||||||
torrent_state = TorrentState(*torrent.get_state())
|
torrent_state = TorrentState(*torrent.get_save_info())
|
||||||
state.torrents.append(torrent_state)
|
state.torrents.append(torrent_state)
|
||||||
|
|
||||||
# Pickle the TorrentManagerState object
|
# Pickle the TorrentManagerState object
|
||||||
|
@ -524,33 +430,6 @@ class TorrentManager(component.Component):
|
||||||
# We return True so that the timer thread will continue
|
# We return True so that the timer thread will continue
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def delete_fastresume(self, torrent_id):
|
|
||||||
"""Deletes the .fastresume file"""
|
|
||||||
torrent = self.torrents[torrent_id]
|
|
||||||
path = "%s/%s.fastresume" % (
|
|
||||||
self.config["torrentfiles_location"],
|
|
||||||
torrent.filename)
|
|
||||||
log.debug("Deleting fastresume file: %s", path)
|
|
||||||
try:
|
|
||||||
os.remove(path)
|
|
||||||
except Exception, e:
|
|
||||||
log.warning("Unable to delete the fastresume file: %s", e)
|
|
||||||
|
|
||||||
def write_fastresume(self, torrent_id):
|
|
||||||
"""Writes the .fastresume file for the torrent"""
|
|
||||||
torrent = self.torrents[torrent_id]
|
|
||||||
resume_data = lt.bencode(torrent.handle.write_resume_data())
|
|
||||||
path = "%s/%s.fastresume" % (
|
|
||||||
self.config["torrentfiles_location"],
|
|
||||||
torrent.filename)
|
|
||||||
log.debug("Saving fastresume file: %s", path)
|
|
||||||
try:
|
|
||||||
fastresume = open(path,"wb")
|
|
||||||
fastresume.write(resume_data)
|
|
||||||
fastresume.close()
|
|
||||||
except IOError:
|
|
||||||
log.warning("Error trying to save fastresume file")
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -571,16 +450,27 @@ class TorrentManager(component.Component):
|
||||||
# Get the torrent_id
|
# Get the torrent_id
|
||||||
torrent_id = str(alert.handle.info_hash())
|
torrent_id = str(alert.handle.info_hash())
|
||||||
log.debug("%s is finished..", torrent_id)
|
log.debug("%s is finished..", torrent_id)
|
||||||
|
# Set the torrent state
|
||||||
|
self.torrents[torrent_id].set_state("Seeding")
|
||||||
# Write the fastresume file
|
# Write the fastresume file
|
||||||
self.write_fastresume(torrent_id)
|
self.torrents[torrent_id].write_fastresume()
|
||||||
|
|
||||||
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
|
||||||
torrent_id = str(alert.handle.info_hash())
|
torrent_id = str(alert.handle.info_hash())
|
||||||
|
# Set the torrent state
|
||||||
|
self.torrents[torrent_id].set_state("Paused")
|
||||||
# Write the fastresume file
|
# Write the fastresume file
|
||||||
self.write_fastresume(torrent_id)
|
self.torrents[torrent_id].write_fastresume()
|
||||||
|
|
||||||
|
def on_alert_torrent_checked(self, alert):
|
||||||
|
log.debug("on_alert_torrent_checked")
|
||||||
|
# Get the torrent_id
|
||||||
|
torrent_id = str(alert.handle.info_hash())
|
||||||
|
# Set the torrent state
|
||||||
|
self.torrents[torrent_id].set_state("Downloading")
|
||||||
|
|
||||||
def on_alert_tracker_reply(self, alert):
|
def on_alert_tracker_reply(self, alert):
|
||||||
log.debug("on_alert_tracker_reply")
|
log.debug("on_alert_tracker_reply")
|
||||||
# Get the torrent_id
|
# Get the torrent_id
|
||||||
|
|
|
@ -38,6 +38,8 @@ import deluge.component as component
|
||||||
import deluge.common
|
import deluge.common
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
|
|
||||||
|
TORRENT_STATE = deluge.common.TORRENT_STATE
|
||||||
|
|
||||||
class SideBar(component.Component):
|
class SideBar(component.Component):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
component.Component.__init__(self, "SideBar")
|
component.Component.__init__(self, "SideBar")
|
||||||
|
@ -102,13 +104,11 @@ class SideBar(component.Component):
|
||||||
component.get("TorrentView").set_filter(None, None)
|
component.get("TorrentView").set_filter(None, None)
|
||||||
if value == "Downloading":
|
if value == "Downloading":
|
||||||
component.get("TorrentView").set_filter("state",
|
component.get("TorrentView").set_filter("state",
|
||||||
deluge.common.TORRENT_STATE.index("Downloading"))
|
TORRENT_STATE["Downloading"])
|
||||||
|
|
||||||
if value == "Seeding":
|
if value == "Seeding":
|
||||||
component.get("TorrentView").set_filter("state",
|
component.get("TorrentView").set_filter("state",
|
||||||
deluge.common.TORRENT_STATE.index("Seeding"))
|
TORRENT_STATE["Seeding"])
|
||||||
|
|
||||||
if value == "Paused":
|
if value == "Paused":
|
||||||
component.get("TorrentView").set_filter("state",
|
component.get("TorrentView").set_filter("state",
|
||||||
deluge.common.TORRENT_STATE.index("Paused"))
|
TORRENT_STATE["Paused"])
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,6 @@ from deluge.common import TORRENT_STATE
|
||||||
import deluge.ui.client as client
|
import deluge.ui.client as client
|
||||||
|
|
||||||
class ToolBar(component.Component):
|
class ToolBar(component.Component):
|
||||||
STATE_FINISHED = TORRENT_STATE.index("Finished")
|
|
||||||
STATE_SEEDING = TORRENT_STATE.index("Seeding")
|
|
||||||
STATE_PAUSED = TORRENT_STATE.index("Paused")
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
component.Component.__init__(self, "ToolBar")
|
component.Component.__init__(self, "ToolBar")
|
||||||
log.debug("ToolBar Init..")
|
log.debug("ToolBar Init..")
|
||||||
|
@ -175,7 +172,7 @@ class ToolBar(component.Component):
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
log.debug("Error getting torrent state: %s", e)
|
log.debug("Error getting torrent state: %s", e)
|
||||||
continue
|
continue
|
||||||
if status == self.STATE_PAUSED:
|
if status == TORRENT_STATE["Paused"]:
|
||||||
resume = True
|
resume = True
|
||||||
else:
|
else:
|
||||||
pause = True
|
pause = True
|
||||||
|
|
|
@ -48,6 +48,8 @@ import deluge.ui.client as client
|
||||||
from deluge.log import LOG as log
|
from deluge.log import LOG as log
|
||||||
import deluge.ui.gtkui.listview as listview
|
import deluge.ui.gtkui.listview as listview
|
||||||
|
|
||||||
|
TORRENT_STATE = deluge.common.TORRENT_STATE
|
||||||
|
|
||||||
# Status icons.. Create them from file only once to avoid constantly
|
# Status icons.. Create them from file only once to avoid constantly
|
||||||
# re-creating them.
|
# re-creating them.
|
||||||
icon_downloading = gtk.gdk.pixbuf_new_from_file(
|
icon_downloading = gtk.gdk.pixbuf_new_from_file(
|
||||||
|
@ -56,18 +58,17 @@ icon_seeding = gtk.gdk.pixbuf_new_from_file(
|
||||||
deluge.common.get_pixmap("seeding16.png"))
|
deluge.common.get_pixmap("seeding16.png"))
|
||||||
icon_inactive = gtk.gdk.pixbuf_new_from_file(
|
icon_inactive = gtk.gdk.pixbuf_new_from_file(
|
||||||
deluge.common.get_pixmap("inactive16.png"))
|
deluge.common.get_pixmap("inactive16.png"))
|
||||||
|
icon_alert = gtk.gdk.pixbuf_new_from_file(
|
||||||
|
deluge.common.get_pixmap("alert16.png"))
|
||||||
|
|
||||||
# Holds the info for which status icon to display based on state
|
# Holds the info for which status icon to display based on state
|
||||||
ICON_STATE = [
|
ICON_STATE = [
|
||||||
icon_inactive,
|
icon_inactive,
|
||||||
icon_downloading,
|
icon_inactive,
|
||||||
icon_downloading,
|
|
||||||
icon_downloading,
|
|
||||||
icon_downloading,
|
icon_downloading,
|
||||||
icon_seeding,
|
icon_seeding,
|
||||||
icon_seeding,
|
icon_inactive,
|
||||||
icon_downloading,
|
icon_alert
|
||||||
icon_inactive
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def cell_data_statusicon(column, cell, model, row, data):
|
def cell_data_statusicon(column, cell, model, row, data):
|
||||||
|
@ -78,23 +79,16 @@ def cell_data_statusicon(column, cell, model, row, data):
|
||||||
|
|
||||||
def cell_data_progress(column, cell, model, row, data):
|
def cell_data_progress(column, cell, model, row, data):
|
||||||
"""Display progress bar with text"""
|
"""Display progress bar with text"""
|
||||||
# Translated state strings
|
|
||||||
TORRENT_STATE = [
|
|
||||||
_("Queued"),
|
|
||||||
_("Checking"),
|
|
||||||
_("Connecting"),
|
|
||||||
_("Downloading Metadata"),
|
|
||||||
_("Downloading"),
|
|
||||||
_("Finished"),
|
|
||||||
_("Seeding"),
|
|
||||||
_("Allocating"),
|
|
||||||
_("Paused")
|
|
||||||
]
|
|
||||||
(value, text) = model.get(row, *data)
|
(value, text) = model.get(row, *data)
|
||||||
if cell.get_property("value") != value:
|
if cell.get_property("value") != value:
|
||||||
cell.set_property("value", value)
|
cell.set_property("value", value)
|
||||||
textstr = "%s" % TORRENT_STATE[text]
|
state_str = ""
|
||||||
if TORRENT_STATE[text] != "Seeding" and TORRENT_STATE[text] != "Finished":
|
for key in TORRENT_STATE.keys():
|
||||||
|
if TORRENT_STATE[key] == text:
|
||||||
|
state_str = key
|
||||||
|
break
|
||||||
|
textstr = "%s" % state_str
|
||||||
|
if state_str != "Seeding" and state_str != "Finished" and value < 100:
|
||||||
textstr = textstr + " %.2f%%" % value
|
textstr = textstr + " %.2f%%" % value
|
||||||
if cell.get_property("text") != textstr:
|
if cell.get_property("text") != textstr:
|
||||||
cell.set_property("text", textstr)
|
cell.set_property("text", textstr)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue