AutoAdd plugin can now recover when one of the watchfolders has an unhandled exception.

This commit is contained in:
Chase Sterling 2010-09-03 22:30:24 -04:00
commit 4b92912577
2 changed files with 56 additions and 58 deletions

View file

@ -78,9 +78,7 @@ OPTIONS_AVAILABLE = { #option: builtin
MAX_NUM_ATTEMPTS = 10 MAX_NUM_ATTEMPTS = 10
class AutoaddOptionsChangedEvent(DelugeEvent): class AutoaddOptionsChangedEvent(DelugeEvent):
""" """Emitted when the options for the plugin are changed."""
Emitted when a new command is added.
"""
def __init__(self): def __init__(self):
pass pass
@ -95,12 +93,9 @@ class Core(CorePluginBase):
self.config = deluge.configmanager.ConfigManager("autoadd.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager("autoadd.conf", DEFAULT_PREFS)
self.watchdirs = self.config["watchdirs"] self.watchdirs = self.config["watchdirs"]
self.core_cfg = deluge.configmanager.ConfigManager("core.conf") self.core_cfg = deluge.configmanager.ConfigManager("core.conf")
# Dict of Filename:Attempts
# A list of filenames self.invalid_torrents = {}
self.invalid_torrents = []
# Filename:Attempts
self.attempts = {}
# Loopingcall timers for each enabled watchdir # Loopingcall timers for each enabled watchdir
self.update_timers = {} self.update_timers = {}
# If core autoadd folder is enabled, move it to the plugin # If core autoadd folder is enabled, move it to the plugin
@ -127,16 +122,13 @@ class Core(CorePluginBase):
for loopingcall in self.update_timers.itervalues(): for loopingcall in self.update_timers.itervalues():
loopingcall.stop() loopingcall.stop()
self.config.save() self.config.save()
pass
def update(self): def update(self):
pass pass
@export() @export()
def set_options(self, watchdir_id, options): def set_options(self, watchdir_id, options):
""" """Update the options for a watch folder."""
update the options for a watch folder
"""
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
options = self._clean_unicode(options) options = self._clean_unicode(options)
CheckInput(watchdir_id in self.watchdirs , _("Watch folder does not exist.")) CheckInput(watchdir_id in self.watchdirs , _("Watch folder does not exist."))
@ -179,28 +171,25 @@ class Core(CorePluginBase):
return filedump return filedump
def update_watchdir(self, watchdir_id): def update_watchdir(self, watchdir_id):
"""Check the watch folder for new torrents to add."""
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
watchdir = self.watchdirs[watchdir_id] watchdir = self.watchdirs[watchdir_id]
if not watchdir['enabled']: if not watchdir['enabled']:
# We shouldn't be updating because this watchdir is not enabled # We shouldn't be updating because this watchdir is not enabled
#disable the looping call self.disable_watchdir(watchdir_id)
self.update_timers[watchdir_id].stop()
del self.update_timers[watchdir_id]
return return
# Check the auto add folder for new torrents to add
if not os.path.isdir(watchdir["abspath"]): if not os.path.isdir(watchdir["abspath"]):
log.warning("Invalid AutoAdd folder: %s", watchdir["abspath"]) log.warning("Invalid AutoAdd folder: %s", watchdir["abspath"])
#disable the looping call self.disable_watchdir(watchdir_id)
watchdir['enabled'] = False
self.update_timers[watchdir_id].stop()
del self.update_timers[watchdir_id]
return return
#Generate options dict for watchdir # Generate options dict for watchdir
opts={} opts = {}
if watchdir.get('stop_at_ratio_toggle'): if 'stop_at_ratio_toggle' in watchdir:
watchdir['stop_ratio_toggle'] = True watchdir['stop_ratio_toggle'] = watchdir['stop_at_ratio_toggle']
# We default to True wher reading _toggle values, so a config
# without them is valid, and applies all its settings.
for option, value in watchdir.iteritems(): for option, value in watchdir.iteritems():
if OPTIONS_AVAILABLE.get(option): if OPTIONS_AVAILABLE.get(option):
if watchdir.get(option+'_toggle', True): if watchdir.get(option+'_toggle', True):
@ -221,18 +210,17 @@ class Core(CorePluginBase):
# torrents may not be fully saved during the pass. # torrents may not be fully saved during the pass.
log.debug("Torrent is invalid: %s", e) log.debug("Torrent is invalid: %s", e)
if filename in self.invalid_torrents: if filename in self.invalid_torrents:
self.attempts[filename] += 1 self.invalid_torrents[filename] += 1
if self.attempts[filename] >= MAX_NUM_ATTEMPTS: if self.invalid_torrents[filename] >= MAX_NUM_ATTEMPTS:
os.rename(filepath, filepath + ".invalid") os.rename(filepath, filepath + ".invalid")
del self.attempts[filename] del self.invalid_torrents[filename]
self.invalid_torrents.remove(filename)
else: else:
self.invalid_torrents.append(filename) self.invalid_torrents[filename] = 1
self.attempts[filename] = 1
continue continue
# The torrent looks good, so lets add it to the session # The torrent looks good, so lets add it to the session.
torrent_id = component.get("TorrentManager").add(filedump=filedump, filename=filename, options=opts) torrent_id = component.get("TorrentManager").add(filedump=filedump, filename=filename, options=opts)
# If the torrent added successfully, set the extra options.
if torrent_id: if torrent_id:
if 'Label' in component.get("CorePluginManager").get_enabled_plugins(): if 'Label' in component.get("CorePluginManager").get_enabled_plugins():
if watchdir.get('label_toggle', True) and watchdir.get('label'): if watchdir.get('label_toggle', True) and watchdir.get('label'):
@ -240,41 +228,54 @@ class Core(CorePluginBase):
if not watchdir['label'] in label.get_labels(): if not watchdir['label'] in label.get_labels():
label.add(watchdir['label']) label.add(watchdir['label'])
label.set_torrent(torrent_id, watchdir['label']) label.set_torrent(torrent_id, watchdir['label'])
if watchdir.get('queue_to_top_toggle'): if watchdir.get('queue_to_top_toggle', True) and 'queue_to_top' in watchdir:
if watchdir.get('queue_to_top', True): if watchdir['queue_to_top']:
component.get("TorrentManager").queue_top(torrent_id) component.get("TorrentManager").queue_top(torrent_id)
else: else:
component.get("TorrentManager").queue_bottom(torrent_id) component.get("TorrentManager").queue_bottom(torrent_id)
if watchdir.get('append_extension_toggle', False): # Rename or delete the torrent once added to deluge.
if watchdir.get('append_extension_toggle'):
if not watchdir.get('append_extension'): if not watchdir.get('append_extension'):
watchdir['append_extension'] = ".added" watchdir['append_extension'] = ".added"
os.rename(filepath, filepath + watchdir['append_extension']) os.rename(filepath, filepath + watchdir['append_extension'])
else: else:
os.remove(filepath) os.remove(filepath)
def on_update_watchdir_error(self, failure, watchdir_id):
"""Disables any watch folders with unhandled exceptions."""
self.disable_watchdir(watchdir_id)
log.error("Disabling '%s', error during update: %s" % (self.watchdirs[watchdir_id]["path"], failure))
@export @export
def enable_watchdir(self, watchdir_id): def enable_watchdir(self, watchdir_id):
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
self.watchdirs[watchdir_id]['enabled'] = True # Enable the looping call
#Enable the looping call if watchdir_id not in self.update_timers or not self.update_timers[watchdir_id].running:
self.update_timers[watchdir_id] = LoopingCall(self.update_watchdir, watchdir_id) self.update_timers[watchdir_id] = LoopingCall(self.update_watchdir, watchdir_id)
self.update_timers[watchdir_id].start(5) self.update_timers[watchdir_id].start(5).addErrback(self.on_update_watchdir_error, watchdir_id)
self.config.save() # Update the config
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) if not self.watchdirs[watchdir_id]['enabled']:
self.watchdirs[watchdir_id]['enabled'] = True
self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
@export @export
def disable_watchdir(self, watchdir_id): def disable_watchdir(self, watchdir_id):
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
self.watchdirs[watchdir_id]['enabled'] = False # Disable the looping call
#disable the looping call here if watchdir_id in self.update_timers:
self.update_timers[watchdir_id].stop() if self.update_timers[watchdir_id].running:
del self.update_timers[watchdir_id] self.update_timers[watchdir_id].stop()
self.config.save() del self.update_timers[watchdir_id]
component.get("EventManager").emit(AutoaddOptionsChangedEvent()) # Update the config
if self.watchdirs[watchdir_id]['enabled']:
self.watchdirs[watchdir_id]['enabled'] = False
self.config.save()
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
@export @export
def set_config(self, config): def set_config(self, config):
"""sets the config dictionary""" """Sets the config dictionary."""
for key in config.keys(): for key in config.keys():
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
@ -282,7 +283,7 @@ class Core(CorePluginBase):
@export @export
def get_config(self): def get_config(self):
"""returns the config dictionary""" """Returns the config dictionary."""
return self.config.config return self.config.config
@export() @export()
@ -298,19 +299,16 @@ class Core(CorePluginBase):
value = str(value) value = str(value)
opts[key] = value opts[key] = value
return opts return opts
#Labels:
@export() @export()
def add(self, options={}): def add(self, options={}):
"""add a watchdir """Add a watch folder."""
"""
options = self._clean_unicode(options) options = self._clean_unicode(options)
abswatchdir = os.path.abspath(options['path']) abswatchdir = os.path.abspath(options['path'])
CheckInput(os.path.isdir(abswatchdir) , _("Path does not exist.")) CheckInput(os.path.isdir(abswatchdir) , _("Path does not exist."))
CheckInput(os.access(abswatchdir, os.R_OK|os.W_OK), "You must have read and write access to watch folder.") CheckInput(os.access(abswatchdir, os.R_OK|os.W_OK), "You must have read and write access to watch folder.")
for watchdir_id, watchdir in self.watchdirs.iteritems(): if abswatchdir in [wd['abspath'] for wd in self.watchdirs.itervalues()]:
if watchdir['abspath'] == abswatchdir: raise Exception("Path is already being watched.")
raise Exception("Path is already being watched.")
options.setdefault('enabled', False) options.setdefault('enabled', False)
options['abspath'] = abswatchdir options['abspath'] = abswatchdir
watchdir_id = self.config['next_id'] watchdir_id = self.config['next_id']
@ -324,7 +322,7 @@ class Core(CorePluginBase):
@export @export
def remove(self, watchdir_id): def remove(self, watchdir_id):
"""remove a label""" """Remove a watch folder."""
watchdir_id = str(watchdir_id) watchdir_id = str(watchdir_id)
CheckInput(watchdir_id in self.watchdirs, "Unknown Watchdir: %s" % self.watchdirs) CheckInput(watchdir_id in self.watchdirs, "Unknown Watchdir: %s" % self.watchdirs)
if self.watchdirs[watchdir_id]['enabled']: if self.watchdirs[watchdir_id]['enabled']:

View file

@ -42,7 +42,7 @@ from setuptools import setup
__plugin_name__ = "AutoAdd" __plugin_name__ = "AutoAdd"
__author__ = "Chase Sterling" __author__ = "Chase Sterling"
__author_email__ = "chase.sterling@gmail.com" __author_email__ = "chase.sterling@gmail.com"
__version__ = "1.01" __version__ = "1.02"
__url__ = "http://forum.deluge-torrent.org/viewtopic.php?f=9&t=26775" __url__ = "http://forum.deluge-torrent.org/viewtopic.php?f=9&t=26775"
__license__ = "GPLv3" __license__ = "GPLv3"
__description__ = "Monitors folders for .torrent files." __description__ = "Monitors folders for .torrent files."