mirror of
https://git.deluge-torrent.org/deluge
synced 2025-04-20 19:44:52 +00:00
AutoAdd plugin #1842
Fix bug #1842 and also implement "delete torrent file on torrent removal from session".
This commit is contained in:
parent
3b8ebf68a6
commit
110026edbe
3 changed files with 443 additions and 131 deletions
|
@ -44,6 +44,7 @@ from deluge.log import getPluginLogger
|
|||
from deluge.plugins.pluginbase import CorePluginBase
|
||||
import deluge.component as component
|
||||
import deluge.configmanager
|
||||
from deluge.common import AUTH_LEVEL_ADMIN
|
||||
from deluge.core.rpcserver import export
|
||||
from twisted.internet.task import LoopingCall, deferLater
|
||||
from twisted.internet import reactor
|
||||
|
@ -61,6 +62,7 @@ OPTIONS_AVAILABLE = { #option: builtin
|
|||
"path":False,
|
||||
"append_extension":False,
|
||||
"copy_torrent": False,
|
||||
"delete_copy_torrent_toggle": False,
|
||||
"abspath":False,
|
||||
"download_location":True,
|
||||
"max_download_speed":True,
|
||||
|
@ -100,6 +102,10 @@ class Core(CorePluginBase):
|
|||
self.config.save()
|
||||
self.watchdirs = self.config["watchdirs"]
|
||||
|
||||
component.get("EventManager").register_event_handler(
|
||||
"PreTorrentRemovedEvent", self.__on_pre_torrent_removed
|
||||
)
|
||||
|
||||
# Dict of Filename:Attempts
|
||||
self.invalid_torrents = {}
|
||||
# Loopingcall timers for each enabled watchdir
|
||||
|
@ -107,13 +113,16 @@ class Core(CorePluginBase):
|
|||
deferLater(reactor, 5, self.enable_looping)
|
||||
|
||||
def enable_looping(self):
|
||||
#Enable all looping calls for enabled watchdirs here
|
||||
# Enable all looping calls for enabled watchdirs here
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
if watchdir['enabled']:
|
||||
self.enable_watchdir(watchdir_id)
|
||||
|
||||
def disable(self):
|
||||
#disable all running looping calls
|
||||
component.get("EventManager").deregister_event_handler(
|
||||
"PreTorrentRemovedEvent", self.__on_pre_torrent_removed
|
||||
)
|
||||
for loopingcall in self.update_timers.itervalues():
|
||||
loopingcall.stop()
|
||||
self.config.save()
|
||||
|
@ -165,16 +174,19 @@ class Core(CorePluginBase):
|
|||
raise e
|
||||
|
||||
# Get the info to see if any exceptions are raised
|
||||
info = lt.torrent_info(lt.bdecode(filedump))
|
||||
lt.torrent_info(lt.bdecode(filedump))
|
||||
|
||||
return filedump
|
||||
|
||||
def update_watchdir(self, watchdir_id):
|
||||
"""Check the watch folder for new torrents to add."""
|
||||
log.trace("Updating watchdir id: %s", watchdir_id)
|
||||
watchdir_id = str(watchdir_id)
|
||||
watchdir = self.watchdirs[watchdir_id]
|
||||
if not watchdir['enabled']:
|
||||
# We shouldn't be updating because this watchdir is not enabled
|
||||
log.debug("Watchdir id %s is not enabled. Disabling it.",
|
||||
watchdir_id)
|
||||
self.disable_watchdir(watchdir_id)
|
||||
return
|
||||
|
||||
|
@ -193,15 +205,17 @@ class Core(CorePluginBase):
|
|||
if OPTIONS_AVAILABLE.get(option):
|
||||
if watchdir.get(option+'_toggle', True):
|
||||
opts[option] = value
|
||||
|
||||
for filename in os.listdir(watchdir["abspath"]):
|
||||
if filename.split(".")[-1] == "torrent":
|
||||
try:
|
||||
filepath = os.path.join(watchdir["abspath"], filename)
|
||||
except UnicodeDecodeError, e:
|
||||
log.error("Unable to auto add torrent due to improper "
|
||||
"filename encoding: %s", e)
|
||||
continue
|
||||
try:
|
||||
filepath = os.path.join(watchdir["abspath"], filename)
|
||||
except UnicodeDecodeError, e:
|
||||
log.error("Unable to auto add torrent due to improper "
|
||||
"filename encoding: %s", e)
|
||||
continue
|
||||
if os.path.isdir(filepath):
|
||||
# Skip directories
|
||||
continue
|
||||
elif os.path.splitext(filename)[1] == ".torrent":
|
||||
try:
|
||||
filedump = self.load_torrent(filepath)
|
||||
except (RuntimeError, Exception), e:
|
||||
|
@ -212,6 +226,9 @@ class Core(CorePluginBase):
|
|||
if filename in self.invalid_torrents:
|
||||
self.invalid_torrents[filename] += 1
|
||||
if self.invalid_torrents[filename] >= MAX_NUM_ATTEMPTS:
|
||||
log.warning("Maximum attepts reached while trying "
|
||||
"to add the torrent file with the path"
|
||||
" %s", filepath)
|
||||
os.rename(filepath, filepath + ".invalid")
|
||||
del self.invalid_torrents[filename]
|
||||
else:
|
||||
|
@ -236,14 +253,19 @@ class Core(CorePluginBase):
|
|||
component.get("TorrentManager").queue_top(torrent_id)
|
||||
else:
|
||||
component.get("TorrentManager").queue_bottom(torrent_id)
|
||||
# Rename or delete the torrent once added to deluge.
|
||||
|
||||
# Rename, copy or delete the torrent once added to deluge.
|
||||
if watchdir.get('append_extension_toggle'):
|
||||
if not watchdir.get('append_extension'):
|
||||
watchdir['append_extension'] = ".added"
|
||||
os.rename(filepath, filepath + watchdir['append_extension'])
|
||||
elif watchdir.get('copy_torrent_toggle'):
|
||||
copy_torrent_path = watchdir['copy_torrent']
|
||||
os.rename(filepath, copy_torrent_path)
|
||||
log.debug("Moving added torrent file \"%s\" to \"%s\"",
|
||||
os.path.basename(filepath), copy_torrent_path)
|
||||
os.rename(
|
||||
filepath, os.path.join(copy_torrent_path, filename)
|
||||
)
|
||||
else:
|
||||
os.remove(filepath)
|
||||
|
||||
|
@ -298,7 +320,22 @@ class Core(CorePluginBase):
|
|||
|
||||
@export
|
||||
def get_watchdirs(self):
|
||||
return self.watchdirs.keys()
|
||||
rpcserver = component.get("RPCServer")
|
||||
session_user = rpcserver.get_session_user()
|
||||
session_auth_level = rpcserver.get_session_auth_level()
|
||||
if session_auth_level == AUTH_LEVEL_ADMIN:
|
||||
log.debug("\n\nCurrent logged in user %s is an ADMIN, send all "
|
||||
"watchdirs", session_user)
|
||||
return self.watchdirs
|
||||
|
||||
watchdirs = {}
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
if watchdir.get("owner", "localclient") == session_user:
|
||||
watchdirs[watchdir_id] = watchdir
|
||||
|
||||
log.debug("\n\nCurrent logged in user %s is not an ADMIN, send only "
|
||||
"his watchdirs: %s", session_user, watchdirs.keys())
|
||||
return watchdirs
|
||||
|
||||
def _make_unicode(self, options):
|
||||
opts = {}
|
||||
|
@ -348,6 +385,30 @@ class Core(CorePluginBase):
|
|||
config['watchdirs'][watchdir_id]['owner'] = 'localclient'
|
||||
return config
|
||||
|
||||
### XXX: Handle torrent finished / remove torrent file per whatchdir
|
||||
### deluge/core/torrentmanager.py:
|
||||
### filename = self.torrents[torrent_id].filename
|
||||
def __on_pre_torrent_removed(self, torrent_id):
|
||||
try:
|
||||
torrent = component.get("TorrentManager")[torrent_id]
|
||||
except KeyError:
|
||||
log.warning("Unable to remove torrent file for torrent id %s. It"
|
||||
"was already deleted from the TorrentManager",
|
||||
torrent_id)
|
||||
return
|
||||
torrent_fname = torrent.filename
|
||||
for watchdir in self.watchdirs.itervalues():
|
||||
if not watchdir.get('copy_torrent_toggle', False):
|
||||
# This watchlist does copy torrents
|
||||
continue
|
||||
elif not watchdir.get('delete_copy_torrent_toggle', False):
|
||||
# This watchlist is not set to delete finished torrents
|
||||
continue
|
||||
copy_torrent_path = watchdir['copy_torrent']
|
||||
torrent_fname_path = os.path.join(copy_torrent_path, torrent_fname)
|
||||
if os.path.isfile(torrent_fname_path):
|
||||
try:
|
||||
os.remove(torrent_fname_path)
|
||||
log.info("Removed torrent file \"%s\" from \"%s\"",
|
||||
torrent_fname, copy_torrent_path)
|
||||
break
|
||||
except OSError, e:
|
||||
log.info("Failed to removed torrent file \"%s\" from "
|
||||
"\"%s\": %s", torrent_fname, copy_torrent_path, e)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -88,10 +88,6 @@ class OptionsDialog():
|
|||
self.watchdir_id = None
|
||||
|
||||
self.load_options(options)
|
||||
|
||||
# Not implemented feateures present in UI
|
||||
self.glade.get_widget("delete_copy_torrent_toggle").hide()
|
||||
|
||||
self.dialog.run()
|
||||
|
||||
def load_options(self, options):
|
||||
|
@ -108,6 +104,9 @@ class OptionsDialog():
|
|||
self.glade.get_widget('copy_torrent_toggle').set_active(
|
||||
options.get('copy_torrent_toggle', False)
|
||||
)
|
||||
self.glade.get_widget('delete_copy_torrent_toggle').set_active(
|
||||
options.get('delete_copy_torrent_toggle', False)
|
||||
)
|
||||
self.accounts.clear()
|
||||
self.labels.clear()
|
||||
combobox = self.glade.get_widget('OwnerCombobox')
|
||||
|
@ -162,6 +161,13 @@ class OptionsDialog():
|
|||
selected_idx = idx
|
||||
self.glade.get_widget('OwnerCombobox').set_active(selected_idx)
|
||||
|
||||
def on_accounts_failure(failure):
|
||||
log.debug("Failed to get accounts!!! %s", failure)
|
||||
iter = self.accounts.append()
|
||||
self.accounts.set_value(iter, 0, client.get_auth_user())
|
||||
self.glade.get_widget('OwnerCombobox').set_active(0)
|
||||
self.glade.get_widget('OwnerCombobox').set_sensitive(False)
|
||||
|
||||
def on_labels(labels):
|
||||
log.debug("Got Labels: %s", labels)
|
||||
for label in labels:
|
||||
|
@ -182,9 +188,15 @@ class OptionsDialog():
|
|||
self.glade.get_widget('label_toggle').set_active(False)
|
||||
|
||||
client.core.get_enabled_plugins().addCallback(on_get_enabled_plugins)
|
||||
client.core.get_known_accounts().addCallback(
|
||||
on_accounts, options.get('owner', 'localclient')
|
||||
).addErrback(on_failure)
|
||||
if client.get_auth_level() == deluge.common.AUTH_LEVEL_ADMIN:
|
||||
client.core.get_known_accounts().addCallback(
|
||||
on_accounts, options.get('owner', 'localclient')
|
||||
).addErrback(on_accounts_failure)
|
||||
else:
|
||||
iter = self.accounts.append()
|
||||
self.accounts.set_value(iter, 0, client.get_auth_user())
|
||||
self.glade.get_widget('OwnerCombobox').set_active(0)
|
||||
self.glade.get_widget('OwnerCombobox').set_sensitive(False)
|
||||
|
||||
def set_sensitive(self):
|
||||
maintoggles = ['download_location', 'append_extension',
|
||||
|
@ -255,7 +267,9 @@ class OptionsDialog():
|
|||
self.err_dialog.hide()
|
||||
|
||||
def on_add(self, Event=None):
|
||||
client.autoadd.add(self.generate_opts()).addCallbacks(self.on_added, self.on_error_show)
|
||||
client.autoadd.add(
|
||||
self.generate_opts()
|
||||
).addCallbacks(self.on_added, self.on_error_show)
|
||||
|
||||
def on_cancel(self, Event=None):
|
||||
self.dialog.destroy()
|
||||
|
@ -266,14 +280,20 @@ class OptionsDialog():
|
|||
options['enabled'] = self.glade.get_widget('enabled').get_active()
|
||||
if client.is_localhost():
|
||||
options['path'] = self.glade.get_widget('path_chooser').get_filename()
|
||||
options['download_location'] = self.glade.get_widget('download_location_chooser').get_filename()
|
||||
options['move_completed_path'] = self.glade.get_widget('move_completed_path_chooser').get_filename()
|
||||
options['copy_torrent'] = self.glade.get_widget('copy_torrent_chooser').get_filename()
|
||||
options['download_location'] = self.glade.get_widget(
|
||||
'download_location_chooser').get_filename()
|
||||
options['move_completed_path'] = self.glade.get_widget(
|
||||
'move_completed_path_chooser').get_filename()
|
||||
options['copy_torrent'] = self.glade.get_widget(
|
||||
'copy_torrent_chooser').get_filename()
|
||||
else:
|
||||
options['path'] = self.glade.get_widget('path_entry').get_text()
|
||||
options['download_location'] = self.glade.get_widget('download_location_entry').get_text()
|
||||
options['move_completed_path'] = self.glade.get_widget('move_completed_path_entry').get_text()
|
||||
options['copy_torrent'] = self.glade.get_widget('copy_torrent_entry').get_text()
|
||||
options['download_location'] = self.glade.get_widget(
|
||||
'download_location_entry').get_text()
|
||||
options['move_completed_path'] = self.glade.get_widget(
|
||||
'move_completed_path_entry').get_text()
|
||||
options['copy_torrent'] = self.glade.get_widget(
|
||||
'copy_torrent_entry').get_text()
|
||||
|
||||
options['label'] = self.glade.get_widget('label').child.get_text().lower()
|
||||
options['append_extension'] = self.glade.get_widget('append_extension').get_text()
|
||||
|
@ -281,7 +301,8 @@ class OptionsDialog():
|
|||
self.glade.get_widget('OwnerCombobox').get_active()][0]
|
||||
|
||||
for key in ['append_extension_toggle', 'download_location_toggle',
|
||||
'label_toggle', 'copy_torrent_toggle']:
|
||||
'label_toggle', 'copy_torrent_toggle',
|
||||
'delete_copy_torrent_toggle']:
|
||||
options[key] = self.glade.get_widget(key).get_active()
|
||||
|
||||
for id in self.spin_ids:
|
||||
|
@ -307,9 +328,15 @@ class GtkUI(GtkPluginBase):
|
|||
})
|
||||
self.opts_dialog = OptionsDialog()
|
||||
|
||||
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
|
||||
client.register_event_handler("AutoaddOptionsChangedEvent", self.on_options_changed_event)
|
||||
component.get("PluginManager").register_hook(
|
||||
"on_apply_prefs", self.on_apply_prefs
|
||||
)
|
||||
component.get("PluginManager").register_hook(
|
||||
"on_show_prefs", self.on_show_prefs
|
||||
)
|
||||
client.register_event_handler(
|
||||
"AutoaddOptionsChangedEvent", self.on_options_changed_event
|
||||
)
|
||||
|
||||
self.watchdirs = {}
|
||||
|
||||
|
@ -330,14 +357,20 @@ class GtkUI(GtkPluginBase):
|
|||
self.create_columns(self.treeView)
|
||||
sw.add(self.treeView)
|
||||
sw.show_all()
|
||||
component.get("Preferences").add_page("AutoAdd", self.glade.get_widget("prefs_box"))
|
||||
component.get("Preferences").add_page(
|
||||
"AutoAdd", self.glade.get_widget("prefs_box")
|
||||
)
|
||||
self.on_show_prefs()
|
||||
|
||||
|
||||
def disable(self):
|
||||
component.get("Preferences").remove_page("AutoAdd")
|
||||
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get("PluginManager").deregister_hook(
|
||||
"on_apply_prefs", self.on_apply_prefs
|
||||
)
|
||||
component.get("PluginManager").deregister_hook(
|
||||
"on_show_prefs", self.on_show_prefs
|
||||
)
|
||||
|
||||
def create_model(self):
|
||||
store = gtk.ListStore(str, bool, str, str)
|
||||
|
@ -418,14 +451,14 @@ class GtkUI(GtkPluginBase):
|
|||
client.autoadd.set_options(watchdir_id, watchdir)
|
||||
|
||||
def on_show_prefs(self):
|
||||
client.autoadd.get_config().addCallback(self.cb_get_config)
|
||||
client.autoadd.get_watchdirs().addCallback(self.cb_get_config)
|
||||
|
||||
def on_options_changed_event(self):
|
||||
client.autoadd.get_config().addCallback(self.cb_get_config)
|
||||
client.autoadd.get_watchdirs().addCallback(self.cb_get_config)
|
||||
|
||||
def cb_get_config(self, config):
|
||||
def cb_get_config(self, watchdirs):
|
||||
"""callback for on show_prefs"""
|
||||
self.watchdirs = config.get('watchdirs', {})
|
||||
self.watchdirs = watchdirs
|
||||
self.store.clear()
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
self.store.append([
|
||||
|
|
Loading…
Add table
Reference in a new issue