From 4e3f4128fa5bdb62000fe63e6acd6296d4f4141d Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Wed, 2 Sep 2009 22:36:34 +0000 Subject: [PATCH] Apply patch from David Mohr to make core.py more 1.2 compatible --- deluge/plugins/feeder/feeder/core.py | 404 +++++++++++++++------------ 1 file changed, 219 insertions(+), 185 deletions(-) diff --git a/deluge/plugins/feeder/feeder/core.py b/deluge/plugins/feeder/feeder/core.py index 2f7134ee2..fb6fc65b4 100644 --- a/deluge/plugins/feeder/feeder/core.py +++ b/deluge/plugins/feeder/feeder/core.py @@ -1,11 +1,12 @@ # # core.py # +# Copyright (C) 2009 David Mohr # Copyright (C) 2008 Fredrik Eriksson # # Basic plugin template created by: # Copyright (C) 2008 Martijn Voncken -# Copyright (C) 2007, 2008 Andrew Resch +# Copyright (C) 2007-2009 Andrew Resch # # Deluge is free software. # @@ -21,9 +22,9 @@ # # You should have received a copy of the GNU General Public License # along with deluge. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -33,25 +34,32 @@ # exception, you may extend this exception to your version of the file(s), # but you are not obligated to do so. If you do not wish to do so, delete # this exception statement from your version. If you delete this exception - +# statement from all source files in the program, then also delete it here. +# import feedparser # for parsing rss feeds -import gobject # for the update timer -import threading # for threaded updates -import re # for regular expressions +import threading # for threaded updates +import re # for regular expressions - -import deluge -import string from deluge.log import LOG as log -from deluge.plugins.corepluginbase import CorePluginBase -from deluge import component -from deluge.plugins.coreclient import client #1.1 and later only -#client: see http://dev.deluge-torrent.org/wiki/Development/UiClient#Remoteapi +from deluge.plugins.pluginbase import CorePluginBase +import deluge.component as component +import deluge.configmanager +from deluge.core.rpcserver import export + +DEFAULT_PREFS = { + "feeds": {}, + "filters": {}, + "updatetime": 15, + "history": [] +} + +# Helper classes -"""Help classes""" class Feed: - "Class for the Feed object (containging feed configurations)" + """ + Class for the Feed object (containging feed configurations) + """ def __init__(self): self.url = "" self.updatetime = 15 @@ -63,8 +71,11 @@ class Feed: self.url = config['url'] self.updatetime = config['updatetime'] + class Filter: - "Class for the Filter object (containing filter configurations)" + """ + Class for the Filter object (containing filter configurations) + """ def __init__(self): self.regex = "" @@ -74,7 +85,7 @@ class Filter: # by default, set the configuration to match # the per-torrent settings in deluge - def_conf = client.get_config() + def_conf = component.get("Core").get_config() self.max_download_speed = def_conf['max_download_speed_per_torrent'] self.max_upload_speed = def_conf['max_upload_speed_per_torrent'] self.max_connections = def_conf['max_connections_per_torrent'] @@ -86,9 +97,9 @@ class Filter: self.stop_at_ratio = def_conf['stop_seed_at_ratio'] self.stop_ratio = def_conf['stop_seed_ratio'] self.remove_at_ratio = def_conf['remove_seed_at_ratio'] - + def get_config(self): - def_conf = client.get_config() + def_conf = component.get("Core").get_config() try: tmp = self.active @@ -105,13 +116,13 @@ class Filter: self.stop_at_ratio = def_conf['stop_seed_at_ratio'] self.stop_ratio = def_conf['stop_seed_ratio'] self.remove_at_ratio = def_conf['remove_seed_at_ratio'] - + conf = { 'regex': self.regex, 'feeds': self.feeds, 'all_feeds': self.all_feeds, 'active' : self.active, - 'max_download_speed': self.max_download_speed, + 'max_download_speed': self.max_download_speed, 'max_upload_speed': self.max_upload_speed, 'max_connections': self.max_connections, 'max_upload_slots': self.max_upload_slots, @@ -141,50 +152,208 @@ class Filter: self.stop_at_ratio = conf['stop_at_ratio'] -DEFAULT_PREFS = { - "feeds": {}, - "filters": {}, - "updatetime": 15, - "history": [] -} +class Timer: + def Timer(self, curr_time, timeout, callback, data): + self.timeout = curr_time + timeout + """Timeout is specified in seconds, since it is used by the update() method""" + self.callback = callback + self.data = data + + def check_timeout(self, curr_time): + return curr_time == self.timeout + + def execute(self): + self.callback(data) + class Core(CorePluginBase): - - - - """=============enable/disable functions=============""" - def enable(self): - #initiate variables self.config = deluge.configmanager.ConfigManager("feeder.conf", DEFAULT_PREFS) self.feeds = {} self.timers = {} self.history = self.config['history'] + self.time = 0 # Setting default timer to configured update time for feed in self.config['feeds']: - self.timers[feed] = gobject.timeout_add( - self.config['feeds'][feed].updatetime * 60 * 1000, + self.timers[feed] = Timer( self,time, + self.config['feeds'][feed].updatetime * 60, self.update_feed, feed ) # update all feeds on startup self.update_feeds() + def disable(self): self.config['history'] = self.history self.config.save() + def update(self): + self.time += 1 + for timer in self.timers: + if timer.check_timeout(time): + timer.execute() - """=============Internal functions=============""" + + +#=================Exported functions================== + + @export + def set_config(self, config): + """sets the config dictionary""" + for key in config.keys(): + self.config[key] = config[key] + self.config.save() + +####################Configuration Getters################## + + @export + def get_config(self): + """returns the config dictionary""" + return self.config.config + + @export + def get_feed_config(self, feedname): + """Returns configuration for a feed""" + return self.config['feeds'][feedname].get_config() + + @export + def get_filter_config(self, filtername): + """Returns a configuration for a filter""" + return self.config['filters'][filtername].get_config() + +####################Information Getters#################### + + @export + def get_feeds(self): + """Returns a list of the configured feeds""" + feeds = [] + for feedname in self.config['feeds']: + feeds.append(feedname) + feeds.sort(key=string.lower) + return feeds + + @export + def get_filters(self): + """Returns a list of all available filters""" + filters = [] + for filter in self.config['filters']: + filters.append(filter) + filters.sort(key=string.lower) + return filters + + @export + def get_items(self, feedname): + """Returns a dictionary with feedname:link""" + try: + items = {} + feed = self.feeds[feedname] + for entry in feed['entries']: + items[entry.title] = entry.link + except Exception, e: + items = {} + log.warning("Feed '%s' not loaded", feedname) + return items + + @export + def test_filter(self, regex): + filters = { "to_test":Filter() } + conf = filters["to_test"].get_config() + conf["regex"] = regex + filters["to_test"].set_config(conf) + hits = {} + for feed in self.feeds: + hits.update(self.run_filters(feed, filters, test=True)) + return hits + + @export + def add_feed(self, config): + """adds/updates a feed and, for whatever reason, sets the default timeout""" + + # save the feedname and remove it from the config + feedname = config['name'] + del config['name'] + + # check if the feed already exists and save config + try: + conf = self.config['feeds'][feedname].get_config() + del self.config['feeds'][feedname] + except Exception, e: + conf = {} + + # update configuration + for var in config: + conf[var] = config[var] + + # save as default update time + try: + self.config['updatetime'] = config['updatetime'] + except Exception, e: + log.warning("updatetime not set when adding feed %s", feedname) + + # Create the new feed + newfeed = Feed() + newfeed.set_config(conf) + + # Add a timer (with default timer for now, since we can't get ttl just yet)... + self.timers[feedname] = Timer( self.time, + newfeed.updatetime * 60, + self.update_feed, feedname ) + + # Save the new feed + self.config['feeds'].update({feedname: newfeed }) + self.config.save() + + # And update the new feed + self.update_feed(feedname) + + @export + def remove_feed(self, feedname): + """Remove a feed""" + if self.feeds.has_key(feedname): # Check if we have the feed saved and remove it + del self.feeds[feedname] + if self.timers.has_key(feedname): # Check if we have a timer for this feed and remove it + del self.timers[feedname] + if self.config['feeds'].has_key(feedname): # Check if we have the feed in the configuration and remove it + del self.config['feeds'][feedname] + self.config.save() + + @export + def add_filter(self, name): + """Adds a new filter to the configuration""" + if not self.config['filters'].has_key(name): # we don't want to add a filter that already exists + self.config['filters'][name] = Filter() + self.config.save() + + @export + def set_filter_config(self, filtername, conf): + """Changes the options for a filter""" + oldconf = self.config['filters'][filtername].get_config() + for item in conf: + oldconf[item] = conf[item] + + self.config['filters'][filtername].set_config(oldconf) + self.config.save() + for feed in self.config['feeds']: # we would like to check if the filter now matches something new + self.run_filters(feed) + + @export + def remove_filter(self, name): + """Removes a filter""" + if self.config['filters'].has_key(name): # Can't remove a filter that doesn't exists + del self.config['filters'][name] + self.config.save() + +#=================Internal functions================ def update_feeds(self): - "Start threads to update all feeds" + """Start threads to update all feeds""" for feedname in self.config['feeds']: self.update_feed(feedname) - + def update_feed(self, feedname): - "Start a thread to update a single feed" + """Start a thread to update a single feed""" threading.Thread( target=self.update_feed_thread, args=(self.on_feed_updated, feedname)).start() @@ -193,7 +362,7 @@ class Core(CorePluginBase): return True def update_feed_thread(self, callback, feedname): - "updates a feed" + """updates a feed""" feed = self.config['feeds'][feedname] try: self.feeds[feedname] = feedparser.parse(feed.url) @@ -203,7 +372,7 @@ class Core(CorePluginBase): callback(feedname) def on_feed_updated(self, feedname): - "Run stuff when a feed has been updated" + """Run stuff when a feed has been updated""" # Not all feeds contain a ttl value, but if it does # we would like to obey it @@ -212,8 +381,8 @@ class Core(CorePluginBase): log.debug("feed '%s' request a ttl of %s, updating timer", feedname, self.feeds[feedname].ttl) self.config['feeds'][feedname].updatetime = self.feeds[feedname].ttl del self.timers[feedname] - self.timers[feedname] = gobject.timeout_add( - self.config['feeds'][feedname].updatetime * 60 * 1000, + self.timers[feedname] = Timer( self.time, + self.config['feeds'][feedname].updatetime * 60 * 1000, self.update_feed, feedname ) except Exception, e: log.debug("feed '%s' has no ttl set, will use default timer", feedname) @@ -222,7 +391,7 @@ class Core(CorePluginBase): self.run_filters(feedname) def run_filters(self, feedname, filters={}, test=False): - "Test all available filters on the given feed" + """Test all available filters on the given feed""" if not filters: filters = self.config['filters'] log.debug("will test filters %s", filters) @@ -241,7 +410,7 @@ class Core(CorePluginBase): if filters[filter].regex == "": # we don't want a empty regex... log.warning("Filter '%s' has not been configured, ignoring!", filter) continue - + # if the filter isn't supposed to be run on this feed we don't want to run it... # if filter.all_feeds or self.config['filters'][filter].feeds.has_element(feedname) : # ...apparently has_element doesn't work on arrays... TODO if self.test_filter(entry, filters[filter].regex): @@ -271,8 +440,8 @@ class Core(CorePluginBase): def test_filter(self, entry, filter): - "Tests a filter to a given rss entry" - f = re.compile(filter, re.IGNORECASE) + """Tests a filter to a given rss entry""" + f = re.compile(filter, re.IGNORECASE) if f.search(entry.title) or f.search(entry.link): log.debug("RSS item '%s' matches filter '%s'", entry.title, filter) return True @@ -281,139 +450,4 @@ class Core(CorePluginBase): def add_torrent(self, url, torrent_options): log.debug("Attempting to add torrent %s", url) - client.add_torrent_url(url, torrent_options) - - """=============Export functions=============""" - - """#############Configuration Setters#############""" - - def export_add_feed(self, config): - "adds/updates a feed and, for whatever reason, sets the default timeout" - - # save the feedname and remove it from the config - feedname = config['name'] - del config['name'] - - # check if the feed already exists and save config - try: - conf = self.config['feeds'][feedname].get_config() - del self.config['feeds'][feedname] - except Exception, e: - conf = {} - - # update configuration - for var in config: - conf[var] = config[var] - - # save as default update time - try: - self.config['updatetime'] = config['updatetime'] - except Exception, e: - log.warning("updatetime not set when adding feed %s", feedname) - - # Create the new feed - newfeed = Feed() - newfeed.set_config(conf) - - # Add a timer (with default timer for now, since we can't get ttl just yet)... - self.timers[feedname] = gobject.timeout_add( - newfeed.updatetime * 60 * 1000, - self.update_feed, feedname ) - - # Save the new feed - self.config['feeds'].update({feedname: newfeed }) - self.config.save() - - # And update the new feed - self.update_feed(feedname) - - def export_remove_feed(self, feedname): - "Remove a feed" - if self.feeds.has_key(feedname): # Check if we have the feed saved and remove it - del self.feeds[feedname] - if self.timers.has_key(feedname): # Check if we have a timer for this feed and remove it - del self.timers[feedname] - if self.config['feeds'].has_key(feedname): # Check if we have the feed in the configuration and remove it - del self.config['feeds'][feedname] - self.config.save() - - def export_add_filter(self, name): - "Adds a new filter to the configuration" - if not self.config['filters'].has_key(name): # we don't want to add a filter that already exists - self.config['filters'][name] = Filter() - self.config.save() - - def export_set_filter_config(self, filtername, conf): - "Changes the options for a filter" - oldconf = self.config['filters'][filtername].get_config() - for item in conf: - oldconf[item] = conf[item] - - self.config['filters'][filtername].set_config(oldconf) - self.config.save() - for feed in self.config['feeds']: # we would like to check if the filter now matches something new - self.run_filters(feed) - - def export_remove_filter(self, name): - "Removes a filter" - if self.config['filters'].has_key(name): # Can't remove a filter that doesn't exists - del self.config['filters'][name] - self.config.save() - - - - """#############Configuration Getters#############""" - - def export_get_config(self): - "returns the config dictionary" - return self.config.config - - - def export_get_feed_config(self, feedname): - "Returns configuration for a feed" - return self.config['feeds'][feedname].get_config() - - def export_get_filter_config(self, filtername): - "Returns a configuration for a filter" - return self.config['filters'][filtername].get_config() - - - """#############Information Getters#############""" - - def export_get_feeds(self): - "Returns a list of the configured feeds" - feeds = [] - for feedname in self.config['feeds']: - feeds.append(feedname) - feeds.sort(key=string.lower) - return feeds - - def export_get_filters(self): - "Returns a list of all available filters" - filters = [] - for filter in self.config['filters']: - filters.append(filter) - filters.sort(key=string.lower) - return filters - - def export_get_items(self, feedname): - "Returns a dictionary with feedname:link" - try: - items = {} - feed = self.feeds[feedname] - for entry in feed['entries']: - items[entry.title] = entry.link - except Exception, e: - items = {} - log.warning("Feed '%s' not loaded", feedname) - return items - - def export_test_filter(self, regex): - filters = { "to_test":Filter() } - conf = filters["to_test"].get_config() - conf["regex"] = regex - filters["to_test"].set_config(conf) - hits = {} - for feed in self.feeds: - hits.update(self.run_filters(feed, filters, test=True)) - return hits + component.get("Core").add_torrent_url(url, torrent_options)