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
-~----------~----~----~----~------~----~------~--~---

Reply via email to