Remove old plugins

This commit is contained in:
Calum Lind 2013-05-15 16:56:31 +01:00
parent 6bed403412
commit 391513d378
30 changed files with 0 additions and 2141 deletions

View File

@ -1,3 +0,0 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -1,3 +0,0 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -1,54 +0,0 @@
#
# __init__.py
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
from deluge.plugins.init import PluginInitBase
class CorePlugin(PluginInitBase):
def __init__(self, plugin_name):
from core import Core as _plugin_cls
self._plugin_cls = _plugin_cls
super(CorePlugin, self).__init__(plugin_name)
class GtkUIPlugin(PluginInitBase):
def __init__(self, plugin_name):
from gtkui import GtkUI as _plugin_cls
self._plugin_cls = _plugin_cls
super(GtkUIPlugin, self).__init__(plugin_name)
class WebUIPlugin(PluginInitBase):
def __init__(self, plugin_name):
from webui import WebUI as _plugin_cls
self._plugin_cls = _plugin_cls
super(WebUIPlugin, self).__init__(plugin_name)

View File

@ -1,41 +0,0 @@
#
# common.py
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
import pkg_resources
import os.path
def get_resource(filename):
return pkg_resources.resource_filename("deluge.plugins.example",
os.path.join("data", filename))

View File

@ -1,57 +0,0 @@
#
# core.py
#
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
import logging
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component
import deluge.configmanager
from deluge.core.rpcserver import export
log = logging.getLogger(__name__)
class Core(CorePluginBase):
def enable(self):
log.debug("Example core plugin enabled!")
def disable(self):
log.debug("Example core plugin disabled!")
def update(self):
pass
### Exported RPC methods ###
@export()
def example_method(self):
pass

View File

@ -1,51 +0,0 @@
/*
Script: example.js
The client-side javascript code for the Example plugin.
Copyright:
(C) Damien Churchill 2009 <damoxc@gmail.com>
This program is free software; you can 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, or (at your option)
any later version.
This program 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 this program. 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
statement from all source files in the program, then also delete it here.
*/
ExamplePlugin = Ext.extend(Deluge.Plugin, {
constructor: function(config) {
config = Ext.apply({
name: "Example"
}, config);
ExamplePlugin.superclass.constructor.call(this, config);
},
onDisable: function() {
Deluge.Preferences.removePage(this.prefsPage);
},
onEnable: function() {
this.prefsPage = new ExamplePreferencesPanel();
this.prefsPage = Deluge.Preferences.addPage(this.prefsPage);
}
});
new ExamplePlugin();

View File

@ -1,50 +0,0 @@
#
# gtkui.py
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
import gtk
import logging
from deluge.ui.client import client
from deluge.plugins.pluginbase import GtkPluginBase
import deluge.component as component
import deluge.common
log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase):
def enable(self):
pass
def disable(self):
pass

View File

@ -1,56 +0,0 @@
#
# webui.py
#
# Copyright (C) 2009 Martijn Voncken <mvoncken@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
import logging
from deluge.ui.client import client
from deluge import component
from deluge.plugins.pluginbase import WebPluginBase
from common import get_resource
log = logging.getLogger(__name__)
class WebUI(WebPluginBase):
scripts = [get_resource("example.js")]
# The enable and disable methods are not scrictly required on the WebUI
# plugins. They are only here if you need to register images/stylesheets
# with the webserver.
def enable(self):
log.debug("Example Web plugin enabled!")
def disable(self):
log.debug("Example Web plugin disabled!")

View File

@ -1,68 +0,0 @@
#
# setup.py
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
# This program is free software; you can 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, or (at your option)
# any later version.
#
# This program 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 this program. 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
# statement from all source files in the program, then also delete it here.
#
#
from setuptools import setup, find_packages
__plugin_name__ = "Example"
__author__ = "Andrew Resch"
__author_email__ = "andrewresch@gmail.com"
__version__ = "1.2"
__url__ = "http://deluge-torrent.org"
__license__ = "GPLv3"
__description__ = "Example plugin"
__long_description__ = __description__
__pkg_data__ = {"deluge.plugins."+__plugin_name__.lower(): []}
setup(
name=__plugin_name__,
version=__version__,
description=__description__,
author=__author__,
author_email=__author_email__,
url=__url__,
license=__license__,
long_description=__long_description__,
packages=find_packages(),
namespace_packages = ["deluge", "deluge.plugins"],
package_data = __pkg_data__,
entry_points="""
[deluge.plugin.core]
%s = deluge.plugins.%s:CorePlugin
[deluge.plugin.gtkui]
%s = deluge.plugins.%s:GtkUIPlugin
[deluge.plugin.web]
%s = deluge.plugins.%s:WebUIPlugin
""" % ((__plugin_name__, __plugin_name__.lower())*3)
)

View File

@ -1,3 +0,0 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -1,3 +0,0 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -1,55 +0,0 @@
#
# feeder/__init__.py
#
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
from deluge.plugins.init import PluginInitBase
class CorePlugin(PluginInitBase):
def __init__(self, plugin_name):
from core import Core as _plugin_cls
self._plugin_cls = _plugin_cls
super(CorePlugin, self).__init__(plugin_name)
class GtkUIPlugin(PluginInitBase):
def __init__(self, plugin_name):
from gtkui import GtkUI as _plugin_cls
self._plugin_cls = _plugin_cls
super(GtkUIPlugin, self).__init__(plugin_name)
class WebUIPlugin(PluginInitBase):
def __init__(self, plugin_name):
from webui import WebUI as _plugin_cls
self._plugin_cls = _plugin_cls
super(WebUIPlugin, self).__init__(plugin_name)

View File

@ -1,434 +0,0 @@
#
# core.py
#
# Copyright (C) 2008-2009 Fredrik Eriksson <feeder@winterbird.org>
# Copyright (C) 2009 David Mohr <david@mcbf.net>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
import logging
import feedparser # for parsing rss feeds
import threading # for threaded updates
import re # for regular expressions
from twisted.internet.task import LoopingCall
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component
import deluge.configmanager
from deluge.core.rpcserver import export
log = logging.getLogger(__name__)
DEFAULT_PREFS = {
"feeds": {},
"filters": {},
"updatetime": 15,
"history": []
}
# Helper classes
class Feed:
"""
Class for the Feed object (containging feed configurations)
"""
def __init__(self):
self.url = ""
self.cookies = {}
self.updatetime = 15
def get_config(self):
try:
tmp = self.cookies
except Exception, e:
log.debug("Old feed without cookies... updating")
self.cookies = {}
return {'url': self.url, 'updatetime': self.updatetime, 'cookies': self.cookies}
def set_config(self, config):
self.url = config['url']
self.updatetime = config['updatetime']
self.cookies = config['cookies']
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 = 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']
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 = component.get("Core").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']
class Core(CorePluginBase):
def enable(self):
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] = LoopingCall(self.update_feed, feed)
self.timers[feed].start( self.config['feeds'][feed].updatetime * 60)
def disable(self):
self.config['history'] = self.history
self.config.save()
def update(self):
pass
#=================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] = LoopingCall(self.update_feed, feedname)
# Save the new feed
self.config['feeds'].update({feedname: newfeed })
self.config.save()
# Start the timeout, which will also update the new feed
self.timers[feedname].start(newfeed.updatetime * 60)
@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
self.timers[feedname].stop()
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_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
self.timers[feedname].stop()
self.timers[feedname].start(self.config['feeds'][feedname].updatetime * 60)
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.feeds[feedname].cookies)
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, headers):
log.debug("Attempting to add torrent %s", url)
component.get("Core").add_torrent_url(url, torrent_options, headers)

View File

@ -1,50 +0,0 @@
#
# gtkui.py
#
# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
#
import gtk
import logging
from deluge.ui.client import client
from deluge.plugins.pluginbase import GtkPluginBase
import deluge.component as component
import deluge.common
log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase):
def enable(self):
pass
def disable(self):
pass

View File

@ -1,13 +0,0 @@
$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()

View File

@ -1,50 +0,0 @@
$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>

View File

@ -1,39 +0,0 @@
$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()

View File

@ -1,279 +0,0 @@
#
# webui.py
#
# Copyright (C) 2008 Fredrik Eriksson <feeder@winterbird.org>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
# 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 logging
import feedparser # for proccessing feed entries
import os
from deluge.ui.client import sclient, aclient
from deluge.plugins.webuipluginbase import WebUIPluginBase
from deluge import component
log = logging.getLogger(__name__)
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"))

View File

@ -1,71 +0,0 @@
#
# setup.py
#
# Copyright (C) 2008 Fredrik Eriksson <feeder@winterbird.org>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
#
# 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, find_packages
__plugin_name__ = "Feeder"
__author__ = "Fredrik Eriksson"
__author_email__ = "feeder@winterbird.org"
__version__ = "0.4"
__url__ = ""
__license__ = "GPLv3"
__description__ = "A plugin for automatically downloadning torrents from a RSS-feed"
__long_description__ = """"""
__pkg_data__ = {"deluge.plugins."+__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=find_packages(),
namespace_packages = ["deluge", "deluge.plugins"],
package_data = __pkg_data__,
entry_points="""
[deluge.plugin.core]
%s = deluge.plugins.%s:CorePlugin
[deluge.plugin.gtkui]
%s = deluge.plugins.%s:GtkUIPlugin
[deluge.plugin.web]
%s = deluge.plugins.%s:WebUIPlugin
""" % ((__plugin_name__, __plugin_name__.lower())*3)
)

View File

@ -1,11 +0,0 @@
#!/bin/bash
BASEDIR=$(cd `dirname $0` && pwd)
CONFIG_DIR=$( test -z $1 && echo "" || echo "$1")
[ -d "$CONFIG_DIR/plugins" ] || echo "Config dir "$CONFIG_DIR" is either not a directory or is not a proper deluge config directory. Exiting"
[ -d "$CONFIG_DIR/plugins" ] || exit 1
cd $BASEDIR
test -d $BASEDIR/temp || mkdir $BASEDIR/temp
export PYTHONPATH=$BASEDIR/temp
python setup.py build develop --install-dir $BASEDIR/temp
cp $BASEDIR/temp/*.egg-link $CONFIG_DIR/plugins
rm -fr $BASEDIR/temp

View File

@ -1,3 +0,0 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -1,3 +0,0 @@
# this is a namespace package
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -1,58 +0,0 @@
#
# __init__.py
#
# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
from deluge.plugins.init import PluginInitBase
class CorePlugin(PluginInitBase):
def __init__(self, plugin_name):
from core import Core as _plugin_cls
self._plugin_cls = _plugin_cls
super(CorePlugin, self).__init__(plugin_name)
class GtkUIPlugin(PluginInitBase):
def __init__(self, plugin_name):
from gtkui import GtkUI as _plugin_cls
self._plugin_cls = _plugin_cls
super(GtkUIPlugin, self).__init__(plugin_name)
class WebUIPlugin(PluginInitBase):
def __init__(self, plugin_name):
from webui import WebUI as _plugin_cls
self._plugin_cls = _plugin_cls
super(WebUIPlugin, self).__init__(plugin_name)

View File

@ -1,43 +0,0 @@
#
# common.py
#
# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
def get_resource(filename):
import pkg_resources, os
return pkg_resources.resource_filename("deluge.plugins.freespace",
os.path.join("data", filename))

View File

@ -1,202 +0,0 @@
#
# core.py
#
# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
import logging
import os, statvfs
from datetime import datetime, timedelta
from twisted.internet import task
from deluge.plugins.pluginbase import CorePluginBase
from deluge.event import DelugeEvent
import deluge.component as component
import deluge.configmanager
from deluge.core.rpcserver import export
log = logging.getLogger(__name__)
class LowDiskSpaceEvent(DelugeEvent):
"""Triggered when the available space for a specific path is getting
too low.
"""
def __init__(self, percents_dict):
"""
:param percents: dictionary of path keys with their respecive
occupation percentages.
"""
self._args = [percents_dict]
DEFAULT_PREFS = {
"enabled": False,
"percent": 90
}
class Core(CorePluginBase):
CLEANUP_TIMEOUT_SECS = 3600 # One hour
def enable(self):
self.config = deluge.configmanager.ConfigManager("freespace.conf",
DEFAULT_PREFS)
self.notifications_sent = {}
self._timer = task.LoopingCall(self.update)
self._interval = 60 * 5 # every 5 minutes
if self.config['enabled']:
self._timer.start(self._interval, False)
self._cleanup = task.LoopingCall(self.__cleanup_notifications)
self._cleanup.start(self._interval, False)
try:
component.get("CorePlugin.Notifications"). \
register_custom_email_notification(
"LowDiskSpaceEvent", self.__custom_email_notification
)
except KeyError:
pass
component.get("EventManager").register_event_handler(
"PluginEnabledEvent", self.__on_plugin_enabled
)
component.get("EventManager").register_event_handler(
"PluginDisabledEvent", self.__on_plugin_disabled
)
def disable(self):
try:
component.get("CorePlugin.Notifications"). \
deregister_custom_email_notification("LowDiskSpaceEvent")
except KeyError:
pass
component.get("EventManager").deregister_event_handler(
"PluginEnabledEvent", self.__on_plugin_enabled
)
component.get("EventManager").deregister_event_handler(
"PluginDisabledEvent", self.__on_plugin_disabled
)
self._cleanup.stop()
if self._timer.running:
self._timer.stop()
def update(self):
log.debug('Updating %s FreeSpace', self.__class__.__name__)
nots = {}
for path in self.__gather_paths_to_check():
log.debug("Checking path %s", path)
if os.path.exists(path):
free_percent = self.__get_free_space(path)
if (100 - free_percent) > self.config['percent']:
if path not in self.notifications_sent:
self.notifications_sent[path] = datetime.utcnow()
nots[path] = (100 - free_percent)
else:
log.warning("Running low on disk space on %s but "
"notifications were already triggered.",
path)
if nots:
component.get("EventManager").emit(LowDiskSpaceEvent(nots))
@export
def set_config(self, config):
"sets the config dictionary"
if not self.config['enabled'] and config['enabled']:
self._timer.start(self._interval, False)
elif self.config['enabled'] and not config['enabled']:
self._timer.stop()
for key in config.keys():
self.config[key] = config[key]
self.config.save()
@export
def get_config(self):
"returns the config dictionary"
return self.config.config
def __gather_paths_to_check(self):
self.over_percentage = {}
torrent_manager = component.get('TorrentManager')
paths = set()
for torrent_id in torrent_manager.get_torrent_list():
status = torrent_manager[torrent_id].get_status([
'is_finished',
'move_on_completed_path',
'save_path'
])
if not status['is_finished']:
paths.add(status['move_on_completed_path'])
paths.add(status['save_path'])
return paths
def __get_free_space(self, path):
log.debug("Calculating free space on %s", path)
stat = os.statvfs(path)
free_blocks = stat[statvfs.F_BAVAIL]
total_blocks = stat[statvfs.F_BLOCKS]
free_percent = free_blocks * 100 / total_blocks
return free_percent
def __custom_email_notification(self, ocupied_percents):
subject = _("Low Disk Space Warning")
message = _("You're running low on disk space:\n")
for path, ocupied_percent in ocupied_percents.iteritems():
message += ' %s%% %s %s\n' % (ocupied_percent, _("ocupation in"), path)
# "\"%s\"%% space occupation on %s") % (ocupied_percent, path)
return subject, message
def __on_plugin_enabled(self, plugin_name):
if plugin_name == 'Notifications':
component.get("CorePlugin.Notifications"). \
register_custom_email_notification(
"LowDiskSpaceEvent", self.__custom_email_notification
)
def __on_plugin_disabled(self, plugin_name):
if plugin_name == 'Notifications':
component.get("CorePlugin.Notifications"). \
deregister_custom_email_notification("LowDiskSpaceEvent")
def __cleanup_notifications(self):
now = datetime.now()
for path, when in self.notifications_sent.copy().iteritems():
if when <= (now -timedelta(seconds=self.CLEANUP_TIMEOUT_SECS)):
log.debug("Removing old(%s) path from notified paths: %s",
when, path)
self.notifications_sent.pop(path)

View File

@ -1,100 +0,0 @@
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.6 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkHBox" id="prefs_box">
<property name="visible">True</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<child>
<widget class="GtkCheckButton" id="enabled">
<property name="label" translatable="yes">Consider low when</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="percent">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">2</property>
<property name="invisible_char">&#x25CF;</property>
<property name="adjustment">90 0 99 1 10 0</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="label">%</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="label" translatable="yes">of the disk is occupied.</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">5</property>
<property name="position">3</property>
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Free Space Checking&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -1,50 +0,0 @@
/*
Script: freespace.js
The client-side javascript code for the FreeSpace plugin.
Copyright:
(C) Pedro Algarvio 2009 <damoxc@gmail.com>
This program is free software; you can 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, or (at your option)
any later version.
This program 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 this program. 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
statement from all source files in the program, then also delete it here.
*/
FreeSpacePlugin = Ext.extend(Deluge.Plugin, {
constructor: function(config) {
config = Ext.apply({
name: "FreeSpace"
}, config);
FreeSpacePlugin.superclass.constructor.call(this, config);
},
onDisable: function() {
},
onEnable: function() {
}
});
new FreeSpacePlugin();

View File

@ -1,162 +0,0 @@
#
# gtkui.py
#
# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
import gtk
import gtk.glade
import logging
from deluge.ui.client import client
from deluge.plugins.pluginbase import GtkPluginBase
import deluge.component as component
import deluge.common
from common import get_resource
log = logging.getLogger(__name__)
class GtkUI(GtkPluginBase):
def enable(self):
log.debug('Enabling %s FreeSpace', self.__class__.__name__)
self.glade = gtk.glade.XML(get_resource("config.glade"))
self.prefs = self.glade.get_widget('prefs_box')
parent = self.prefs.get_parent()
if parent:
parent.remove(self.prefs)
self.downloads_vbox = component.get("Preferences").builder.get_object('downloads_vbox')
self.downloads_vbox.pack_start(self.prefs, False, True, 0)
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
try:
notifications = component.get("GtkPlugin.Notifications")
notifications.register_custom_popup_notification(
"LowDiskSpaceEvent", self.__custom_popup_notification
)
notifications.register_custom_blink_notification(
"LowDiskSpaceEvent", self.__custom_blink_notification
)
notifications.register_custom_sound_notification(
"LowDiskSpaceEvent", self.__custom_sound_notification
)
except KeyError:
pass
client.register_event_handler("PluginEnabledEvent", self.__on_plugin_enabled)
client.register_event_handler("PluginDisabledEvent", self.__on_plugin_disabled)
def disable(self):
self.downloads_vbox.remove(self.prefs)
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
try:
notifications = component.get("GtkPlugin.Notifications")
notifications.deregister_custom_popup_notification(
"LowDiskSpaceEvent"
)
notifications.deregister_custom_blink_notification(
"LowDiskSpaceEvent"
)
notifications.deregister_custom_sound_notification(
"LowDiskSpaceEvent"
)
except KeyError:
pass
client.deregister_event_handler("PluginEnabledEvent", self.__on_plugin_enabled)
client.deregister_event_handler("PluginDisabledEvent", self.__on_plugin_disabled)
def on_apply_prefs(self):
log.debug("applying prefs for FreeSpace")
config = {
"enabled": self.glade.get_widget('enabled').get_active(),
"percent": self.glade.get_widget('percent').get_value()
}
client.freespace.set_config(config)
def on_show_prefs(self):
client.freespace.get_config().addCallback(self.cb_get_config)
def cb_get_config(self, config):
"callback for on show_prefs"
self.glade.get_widget('enabled').set_active(config['enabled'])
self.glade.get_widget('percent').set_value(config['percent'])
def __custom_popup_notification(self, ocupied_percents):
title = _("Low Free Space")
message = ''
for path, percent in ocupied_percents.iteritems():
message += '%s%% %s\n' % (percent, path)
message += '\n'
return title, message
def __custom_blink_notification(self, ocupied_percents):
return True # Yes, do blink
def __custom_sound_notification(self, ocupied_percents):
return '' # Use default sound
def __on_plugin_enabled(self, plugin_name):
if plugin_name == 'Notifications':
notifications = component.get("GtkPlugin.Notifications")
notifications.register_custom_popup_notification(
"LowDiskSpaceEvent", self.__custom_popup_notification
)
notifications.register_custom_blink_notification(
"LowDiskSpaceEvent", self.__custom_blink_notification
)
notifications.register_custom_sound_notification(
"LowDiskSpaceEvent", self.__custom_sound_notification
)
def __on_plugin_disabled(self, plugin_name):
pass
# if plugin_name == 'Notifications':
# notifications = component.get("GtkPlugin.Notifications")
# notifications.deregister_custom_popup_notification(
# "LowDiskSpaceEvent"
# )
# notifications.deregister_custom_blink_notification(
# "LowDiskSpaceEvent"
# )
# notifications.deregister_custom_sound_notification(
# "LowDiskSpaceEvent"
# )

View File

@ -1,57 +0,0 @@
#
# webui.py
#
# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
import logging
from deluge.ui.client import client
from deluge import component
from deluge.plugins.pluginbase import WebPluginBase
from common import get_resource
log = logging.getLogger(__name__)
class WebUI(WebPluginBase):
scripts = [get_resource("freespace.js")]
def enable(self):
pass
def disable(self):
pass

View File

@ -1,72 +0,0 @@
#
# setup.py
#
# Copyright (C) 2009-2010 Pedro Algarvio <pedro@algarvio.me>
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
#
# 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
# statement from all source files in the program, then also delete it here.
#
from setuptools import setup, find_packages
__plugin_name__ = "FreeSpace"
__author__ = "Pedro Algarvio"
__author_email__ = "pedro@algarvio.me"
__version__ = "0.1"
__url__ = "http://deluge.ufsoft.org/hg/Notification/"
__license__ = "GPLv3"
__description__ = "Plugin which continuously checks for available free space."
__long_description__ = __description__
__pkg_data__ = {"deluge.plugins."+__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__ if __long_description__ else __description__,
packages=find_packages(),
namespace_packages = ["deluge", "deluge.plugins"],
package_data = __pkg_data__,
entry_points="""
[deluge.plugin.core]
%s = deluge.plugins.%s:CorePlugin
[deluge.plugin.gtkui]
%s = deluge.plugins.%s:GtkUIPlugin
""" % ((__plugin_name__, __plugin_name__.lower())*2)
)