Author: feffe
Revision: 5708
Log:
importing the feeder-plugin for porting to 1.2
Diff:
Added: trunk/deluge/plugins/feeder/feeder/__init__.py
===================================================================
--- trunk/deluge/plugins/feeder/feeder/__init__.py
(rev 0)
+++ trunk/deluge/plugins/feeder/feeder/__init__.py 2009-08-31 18:55:51 UTC
(rev 5708)
@@ -0,0 +1,65 @@
+#
+# __init__.py
+#
+# Copyright (C) 2008 Fredrik Eriksson <[email protected]>
+#
+# Basic plugin template created by:
+# Copyright (C) 2008 Martijn Voncken <[email protected]>
+# Copyright (C) 2007, 2008 Andrew Resch <[email protected]>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# 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.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# 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
+
+from deluge.log import LOG as log
+
+from deluge.plugins.init import PluginBase
+
+class CorePlugin(PluginBase):
+ def __init__(self, plugin_api, plugin_name):
+ # Load the Core portion of the plugin
+ try:
+ from core import Core
+ self.plugin = Core(plugin_api, plugin_name)
+ except Exception, e:
+ log.debug("Did not load a Core plugin: %s", e)
+
+class WebUIPlugin(PluginBase):
+ def __init__(self, plugin_api, plugin_name):
+ try:
+ from webui import WebUI
+ self.plugin = WebUI(plugin_api, plugin_name)
+ except Exception, e:
+ log.debug("Did not load a WebUI plugin: %s", e)
+
+class GtkUIPlugin(PluginBase):
+ def __init__(self, plugin_api, plugin_name):
+ # Load the GtkUI portion of the plugin
+ try:
+ from gtkui import GtkUI
+ self.plugin = GtkUI(plugin_api, plugin_name)
+ except Exception, e:
+ log.debug("Did not load a GtkUI plugin: %s", e)
Added: trunk/deluge/plugins/feeder/feeder/core.py
===================================================================
--- trunk/deluge/plugins/feeder/feeder/core.py (rev 0)
+++ trunk/deluge/plugins/feeder/feeder/core.py 2009-08-31 18:55:51 UTC (rev
5708)
@@ -0,0 +1,419 @@
+#
+# core.py
+#
+# Copyright (C) 2008 Fredrik Eriksson <[email protected]>
+#
+# Basic plugin template created by:
+# Copyright (C) 2008 Martijn Voncken <[email protected]>
+# Copyright (C) 2007, 2008 Andrew Resch <[email protected]>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# 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.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# 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
+
+
+import feedparser # for parsing rss feeds
+import gobject # for the update timer
+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
+
+"""Help classes"""
+class Feed:
+ "Class for the Feed object (containging feed configurations)"
+ def __init__(self):
+ self.url = ""
+ self.updatetime = 15
+
+ def get_config(self):
+ return {'url': self.url, 'updatetime': self.updatetime}
+
+ def set_config(self, config):
+ self.url = config['url']
+ self.updatetime = config['updatetime']
+
+class Filter:
+ "Class for the Filter object (containing filter configurations)"
+
+ def __init__(self):
+ self.regex = ""
+ self.feeds = [] #TODO activate filter per feed
+ self.all_feeds = True
+ self.active = True
+
+ # by default, set the configuration to match
+ # the per-torrent settings in deluge
+ def_conf = client.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']
+ self.max_upload_slots = def_conf['max_upload_slots_per_torrent']
+ self.prioritize_first_last_pieces =
def_conf['prioritize_first_last_pieces']
+ self.auto_managed = def_conf['auto_managed']
+ self.download_location = def_conf['download_location']
+
+ 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()
+
+ try:
+ tmp = self.active
+ except Exception, e:
+ log.debug("Old filter detected (pre 0.3), updating...")
+ self.active = True
+
+ try:
+ tmp = self.stop_at_ratio
+ tmp = self.stop_ratio
+ tmp = self.remove_at_ratio
+ except:
+ log.debug("Old filter detected (pre 0.4), updating...")
+ 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_upload_speed': self.max_upload_speed,
+ 'max_connections': self.max_connections,
+ 'max_upload_slots': self.max_upload_slots,
+ 'prioritize_first_last_pieces': self.prioritize_first_last_pieces,
+ 'auto_managed': self.auto_managed,
+ 'download_location':self.download_location,
+ 'remove_at_ratio':self.remove_at_ratio,
+ 'stop_ratio': self.stop_ratio,
+ 'stop_at_ratio': self.stop_at_ratio }
+
+ return conf
+
+ def set_config(self, conf):
+ self.regex = conf['regex']
+ self.feeds = conf['feeds']
+ self.all_feeds = conf['all_feeds']
+ self.active = conf['active']
+ self.max_download_speed = int(conf['max_download_speed'])
+ self.max_upload_speed = int(conf['max_upload_speed'])
+ self.max_connections = int(conf['max_connections'])
+ self.max_upload_slots = int(conf['max_upload_slots'])
+ self.prioritize_first_last_pieces =
conf['prioritize_first_last_pieces']
+ self.auto_managed = conf['auto_managed']
+ self.download_location = conf['download_location']
+ self.remove_at_ratio = conf['remove_at_ratio']
+ self.stop_ratio = float(conf['stop_ratio'])
+ self.stop_at_ratio = conf['stop_at_ratio']
+
+
+DEFAULT_PREFS = {
+ "feeds": {},
+ "filters": {},
+ "updatetime": 15,
+ "history": []
+}
+
+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']
+
+ # 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.update_feed, feed )
+
+ # update all feeds on startup
+ self.update_feeds()
+
+ def disable(self):
+ self.config['history'] = self.history
+ self.config.save()
+
+
+
+ """=============Internal functions============="""
+
+ def update_feeds(self):
+ "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"
+ threading.Thread(
+ target=self.update_feed_thread,
+ args=(self.on_feed_updated, feedname)).start()
+
+ # Need to return true to not destoy timer...
+ return True
+
+ def update_feed_thread(self, callback, feedname):
+ "updates a feed"
+ feed = self.config['feeds'][feedname]
+ try:
+ self.feeds[feedname] = feedparser.parse(feed.url)
+ except Exception, e:
+ log.warning("Error parsing feed %s: %s", feedname, e)
+ else:
+ callback(feedname)
+
+ def on_feed_updated(self, feedname):
+ "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
+ try:
+ if not self.feeds[feedname].ttl ==
self.config['feeds'][feedname].updatetime:
+ 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.update_feed, feedname )
+ except Exception, e:
+ log.debug("feed '%s' has no ttl set, will use default timer",
feedname)
+
+ # Run filters on the feed
+ self.run_filters(feedname)
+
+ def run_filters(self, feedname, filters={}, test=False):
+ "Test all available filters on the given feed"
+ if not filters:
+ filters = self.config['filters']
+ log.debug("will test filters %s", filters)
+ hits = {}
+ # Test every entry...
+ for entry in self.feeds[feedname]['entries']:
+ # ...and every filter
+ for filter in filters:
+ # We need to be able to run feeds saved before implementation
of actiave/deactivate filter (pre 0.3) TODO
+ try:
+ if not filters[filter].active:
+ continue
+ except:
+ log.debug("old filter, will assume filter is activated")
+
+ 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):
+ if test:
+ hits[entry.title] = entry.link
+ else:
+ opts = filters[filter].get_config()
+ #remove filter options that should not be passed on to
the torrent.
+ del opts['regex']
+ del opts['feeds']
+ del opts['all_feeds']
+
+ # history patch from Darrell Enns, slightly modified :)
+ # check history to prevent multiple adds of the same
torrent
+ log.debug("testing %s", entry.link)
+ if not entry.link in self.history:
+ self.add_torrent(entry.link, opts)
+ self.history.append(entry.link)
+
+ #limit history to 50 entries
+ if len(self.history)>50:
+ self.history=self.history[-50:]
+ log.debug("wrapping history")
+ else:
+ log.debug("'%s' is in history, will not download",
entry.link)
+ return hits
+
+
+ def test_filter(self, entry, filter):
+ "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
+ else:
+ return False
+
+ 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
Added: trunk/deluge/plugins/feeder/feeder/template/feeds.html
===================================================================
--- trunk/deluge/plugins/feeder/feeder/template/feeds.html
(rev 0)
+++ trunk/deluge/plugins/feeder/feeder/template/feeds.html 2009-08-31
18:55:51 UTC (rev 5708)
@@ -0,0 +1,13 @@
+$def with (entries, feedname)
+$:render.header("things", '')
+<div class="panel" >
+<div>
+<h3>Feed items for feed $feedname</h3>
+<ul>
+$entries
+</ul>
+</div>
+<a href="/config/feeder">back to config</a>
+</div>
+
+$:render.footer()
Added: trunk/deluge/plugins/feeder/feeder/template/filter_settings.html
===================================================================
--- trunk/deluge/plugins/feeder/feeder/template/filter_settings.html
(rev 0)
+++ trunk/deluge/plugins/feeder/feeder/template/filter_settings.html
2009-08-31 18:55:51 UTC (rev 5708)
@@ -0,0 +1,50 @@
+$def with (filter_settings_form, filter)
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+<head>
+ <title>Deluge:things</title>
+ <link rel="icon" href="/static/images/deluge-icon.png" type="image/png" />
+ <link rel="shortcut icon" href="/static/images/deluge-icon.png"
type="image/png" />
+ <link rel="stylesheet" type="text/css" href="/template_style.css" />
+ <script language="javascript" src="/static/deluge.js"></script>
+ <script language="javascript" src="/static/mootools-1.2-core.js"></script>
+
+ <script language="javascript" src="/static/mootools-1.2-more.js"></script>
+ <script language="javascript" src="/static/mooui.js"></script>
+ <script language="javascript" src="/static/deluge-moo.js"></script>
+ <script language="javascript" src="/gettext.js"></script>
+ <script language="javascript" src="/label/data/label.js"></script>
+</head>
+<body>
+
+<form method="post" action='$base/feeder/filter_settings/$filter'>
+<div class="info">
+<h3>Filter</h3>
+<table>
+$:(filter_settings_form.as_table(["regex", "active"]))
+</table>
+
+<h3>Speed</h3>
+<table>
+$:(filter_settings_form.as_table(["max_download_speed", "max_upload_speed",
"max_upload_slots", "max_connections"]))
+</table>
+
+<h3>Seed options</h3>
+<table>
+$:(filter_settings_form.as_table(["stop_ratio", "stop_at_ratio",
"remove_at_ratio"]))
+</table>
+
+<h3>Other options</h3>
+<table>
+$:(filter_settings_form.as_table(["prioritize_first_last_pieces",
"auto_managed", "download_location"]))
+</table>
+<input type="submit" name="submit" value="$_('Save')" />
+
+</form>
+<h3>Matches</h3>
+$:filter_settings_form.post_html()
+</div>
+
+</body>
+</html>
Added: trunk/deluge/plugins/feeder/feeder/template/filters.html
===================================================================
--- trunk/deluge/plugins/feeder/feeder/template/filters.html
(rev 0)
+++ trunk/deluge/plugins/feeder/feeder/template/filters.html 2009-08-31
18:55:51 UTC (rev 5708)
@@ -0,0 +1,39 @@
+$def with (filters, new_filter_form)
+$:render.header("things", '')
+<table><tr>
+<td>
+ <table><tr></td>
+ <div class="info">
+ <h3>Filters</h3>
+ </div></td></tr>
+ <tr><td>
+ <div class="info">
+ <ul>
+ $filters
+ </ul>
+ <form method="post" action='$base/feeder/filters'>
+ $:(new_filter_form.as_p(["name"]))
+ <input type="submit" name="submit" class="form_input" value="$_('Add
filter')" />
+ </form>
+ <p><a href="/config/feeder">back to config</a>
+ </div></td></tr></table>
+</td>
+<td>
+ <div class="panel">
+ <iframe style="border-style:hidden;" id="filter_settings" width=100%
height=600>
+ </iframe>
+ </div>
+</td>
+</tr></table>
+
+<script language="javascript">
+function load_options(filter){
+ \$('filter_settings').src = state.base_url + '/feeder/filter_settings/' +
filter;
+}
+</script>
+<script language="javascript">
+new InputSensitivitySetter({prefix:"id_",groups:[
+ ["name"]
+]});
+</script>
+$:render.footer()
Added: trunk/deluge/plugins/feeder/feeder/webui.py
===================================================================
--- trunk/deluge/plugins/feeder/feeder/webui.py (rev 0)
+++ trunk/deluge/plugins/feeder/feeder/webui.py 2009-08-31 18:55:51 UTC (rev
5708)
@@ -0,0 +1,277 @@
+#
+# webui.py
+#
+# Copyright (C) 2008 Fredrik Eriksson <[email protected]>
+#
+# Basic plugin template created by:
+# Copyright (C) 2008 Martijn Voncken <[email protected]>
+# Copyright (C) 2007, 2008 Andrew Resch <[email protected]>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# 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.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# 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
+
+import feedparser # for proccessing feed entries
+import os
+from deluge.log import LOG as log
+from deluge.ui.client import sclient, aclient
+from deluge.plugins.webuipluginbase import WebUIPluginBase
+from deluge import component
+
+api = component.get("WebPluginApi")
+forms = api.forms
+
+class feed_page:
+ "Class for showing feed items"
+ @api.deco.deluge_page
+ def GET(self, feedname):
+ entries = sclient.feeder_get_items(feedname)
+ items = ""
+ for item in entries:
+ items = """%(old)s
+ <a href="%(link)s">
+ <li>%(entry)s</li>
+ </a>""" % { "old":items, "entry":item, "link":entries[item]}
+ return api.render.feeder.feeds(items, feedname)
+
+class filter_page:
+ "Class for showing filters / filter settings"
+ @api.deco.deluge_page
+ def GET(self, args):
+ new_filter = new_filter_form()
+ filters = sclient.feeder_get_filters()
+
+ # List filters
+ txt = ""
+ for filter in filters:
+ txt = """%(old)s
+ <li onclick=\"load_options('%(new)s')\">
+ %(new)s
+ </li>""" % {'old':txt, 'new':filter}
+
+ return api.render.feeder.filters(txt, new_filter)
+
+ def POST(self):
+ "Saves the new filter"
+ name = api.utils.get_newforms_data(new_filter_form)['name']
+ sclient.feeder_add_filter(name)
+ return self.GET(name)
+
+class new_filter_form(forms.Form):
+ "basic form for a new label"
+ name = forms.CharField(label="")
+
+class filter_settings_page:
+ "Class for showing filter settings"
+ @api.deco.deluge_page
+ def GET(self, filter):
+ form = filter_settings_form(filter)
+ return api.render.feeder.filter_settings(form, filter)
+
+ def POST(self, filter):
+ opts = api.utils.get_newforms_data(filter_settings_form)
+
+ # apparently the "Unlimited" options still have to be changed
+ # to -1 (wtf?)
+ # FIXME there is probably a very much better way to ensure that
+ # all values have the right types... not to mention to convert
"Unlimited"
+ # to -1...
+ try:
+ opts['max_upload_speed'] = int(opts['max_upload_speed'])
+ except:
+ opts['max_upload_speed'] = int(-1)
+ try:
+ opts['max_download_speed'] = int(opts['max_download_speed'])
+ except:
+ opts['max_download_speed'] = int(-1)
+ try:
+ opts['max_connections'] = int(opts['max_connections'])
+ except:
+ opts['max_connections'] = int(-1)
+ try:
+ opts['max_upload_slots'] = int(opts['max_upload_slots'])
+ except:
+ opts['max_upload_slots'] = int(-1)
+ """opts['max_upload_slots'] = long(opts['max_upload_slots'])
+ opts['max_connections'] = long(opts['max_connections'])"""
+
+ # TODO filter settings per feed not implemented.
+ opts['feeds'] = []
+
+ sclient.feeder_set_filter_config(filter, opts)
+ return self.GET(filter)
+
+class filter_settings_form(forms.Form):
+ "form for filter settings"
+
+ def __init__(self, filter, test=False):
+ self.filtername = filter # We want to save our filtername
+ forms.Form.__init__(self)
+
+ def initial_data(self):
+ self.conf = sclient.feeder_get_filter_config(self.filtername)
+ return self.conf
+
+ def post_html(self):
+ regex = self.conf["regex"]
+ hits = sclient.feeder_test_filter(regex)
+ if not hits:
+ return "No hits"
+ list = ""
+ for hit in hits:
+ list = """%(old)s
+ <li><a href="%(link)s" >%(name)s</a></li>
+ """ % { "old":list, "link":hits[hit], "name":hit }
+ return """
+ <ul>
+ %s
+ </ul>
+ """ % list
+
+ regex = forms.CharField(_("regular_expression"))
+ all_feeds = forms.CheckBox(_("all_feeds"))
+ active = forms.CheckBox(_("active"))
+
+ #maximum:
+ max_download_speed = forms.DelugeFloat(_("max_download_speed"))
+ max_upload_speed = forms.DelugeFloat(_("max_upload_speed"))
+ max_upload_slots = forms.DelugeInt(_("max_upload_slots"))
+ max_connections = forms.DelugeInt(_("max_connections"))
+
+ stop_ratio = forms.DelugeFloat(_("stop_ratio"))
+ stop_at_ratio = forms.CheckBox(_("stop_at_ratio"))
+ remove_at_ratio = forms.CheckBox(_("remove_at_ratio"))
+
+ #queue:
+ auto_managed = forms.CheckBox(_("is_auto_managed"))
+ prioritize_first_last_pieces =
forms.CheckBox(_("prioritize_first_last_pieces"))
+
+ download_location = forms.ServerFolder(_("download_location"))
+
+class remove_feed_page:
+ "Class for deleting feeds, redirects to setting page"
+ @api.deco.deluge_page
+ def GET(self, feedname):
+ sclient.feeder_remove_feed(feedname)
+ return """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
+ <html>
+ <head>
+ <title>Redirecting back to settings</title>
+ <meta http-equiv="refresh" content="0; URL=/config/feeder">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ </head>
+ <body>
+ </body>
+
+ </html>"""
+
+class remove_filter_page:
+ "Class for deleting filters, redirects to setting page"
+ @api.deco.deluge_page
+ def GET(self, name):
+ sclient.feeder_remove_filter(name)
+ return """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
+ <html>
+ <head>
+ <title>Redirecting back to settings</title>
+ <meta http-equiv="refresh" content="0; URL=/config/feeder">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ </head>
+ <body>
+ </body>
+
+ </html>"""
+
+
+class WebUI(WebUIPluginBase):
+ #map url's to classes: [(url,class), ..]
+ urls = [('/feeder/filters', filter_page),
+ ('/feeder/filter_settings/(.*)', filter_settings_page),
+ ('/feeder/feed_remove/(.*)', remove_feed_page),
+ ('/feeder/filter_remove/(.*)', remove_filter_page),
+ ('/feeder/feed/(.*)', feed_page)]
+
+ def enable(self):
+ api.config_page_manager.register('plugins', 'feeder' ,ConfigForm)
+
+ def disable(self):
+ api.config_page_manager.deregister('feeder')
+
+class ConfigForm(forms.Form):
+ #meta:
+ title = _("feeder")
+
+ #load/save:
+ def initial_data(self):
+ return sclient.feeder_get_config()
+
+ def save(self, data):
+ cfg = dict(data)
+ sclient.feeder_add_feed(cfg)
+
+ def pre_html(self):
+ feeds = sclient.feeder_get_feeds()
+ filters = sclient.feeder_get_filters()
+ filterlist = ""
+ for filter in filters:
+ filterlist = """ %(old)s <li>%(new)s
+ <a href="/feeder/filter_remove/%(new)s">
+ <img src="/static/images/16/list-remove.png" alt="Remove" />
+ </a></li>""" % {'old':filterlist, 'new':filter}
+ feedlist = ""
+ for feed in feeds:
+ feedlist = """%(old)s
+ <li> <a href="/feeder/feed/%(new)s"> %(new)s (%(entrys)s
torrents)</a>
+ <a href="/feeder/feed_remove/%(new)s">
+ <img src="/static/images/16/list-remove.png" alt="Remove" />
+ </a></li>""" % {'old':feedlist, 'new':feed,
'entrys':len(sclient.feeder_get_items(feed))}
+
+ return """
+ <table width=100%%><tr><td>
+ <h3>Feeds</h3>
+ </td>
+ <td>
+ <h3>Filters</h3>
+ </td></tr>
+ <tr><td>
+ <div class="info">
+ <ul>
+ %(feeds)s
+ </ul></div>
+ </td><td>
+ <div class="info">
+ <ul>
+ %(filters)s
+ </ul></div>
+ <a href="/feeder/filters">Add/modify filters</a>
+ </td></tr>
+ </table>
+ <h3>Add/change feed settings</h3>""" % {'feeds':feedlist,
'filters':filterlist}
+
+ name = forms.CharField(label=_("Name of feed"))
+ url = forms.URLField(label=_("URL of feed"))
+ updatetime = forms.IntegerField(label=_("Defualt refresh time"))
+
Added: trunk/deluge/plugins/feeder/setup.py
===================================================================
--- trunk/deluge/plugins/feeder/setup.py (rev 0)
+++ trunk/deluge/plugins/feeder/setup.py 2009-08-31 18:55:51 UTC (rev
5708)
@@ -0,0 +1,70 @@
+#
+# setup.py
+#
+# Copyright (C) 2008 Fredrik Eriksson <[email protected]>
+#
+# Basic plugin template created by:
+# Copyright (C) 2008 Martijn Voncken <[email protected]>
+# Copyright (C) 2007, 2008 Andrew Resch <[email protected]>
+#
+# Deluge is free software.
+#
+# You may redistribute it and/or modify it under the terms of the
+# GNU General Public License, as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option)
+# any later version.
+#
+# deluge is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU General Public License for more details.
+#
+# 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.
+#
+# In addition, as a special exception, the copyright holders give
+# permission to link the code of portions of this program with the OpenSSL
+# library.
+# You must obey the GNU General Public License in all respects for all of
+# the code used other than OpenSSL. If you modify file(s) with this
+# 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
+
+from setuptools import setup
+
+__plugin_name__ = "feeder"
+__author__ = "Fredrik Eriksson"
+__author_email__ = "[email protected]"
+__version__ = "0.4"
+__url__ = ""
+__license__ = "GPLv3"
+__description__ = "A plugin for automatically downloadning torrents from a
RSS-feed"
+__long_description__ = """"""
+__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]}
+
+setup(
+ name=__plugin_name__,
+ version=__version__,
+ description=__description__,
+ author=__author__,
+ author_email=__author_email__,
+ url=__url__,
+ license=__license__,
+ long_description=__long_description__,
+
+ packages=[__plugin_name__.lower()],
+ package_data = __pkg_data__,
+
+ entry_points="""
+ [deluge.plugin.core]
+ %s = %s:CorePlugin
+ [deluge.plugin.gtkui]
+ %s = %s:GtkUIPlugin
+ [deluge.plugin.webui]
+ %s = %s:WebUIPlugin
+ """ % ((__plugin_name__, __plugin_name__.lower())*3)
+)
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"deluge-commit" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/deluge-commit?hl=en
-~----------~----~----~----~------~----~------~--~---