begin an execute command upon event plugin

This commit is contained in:
Damien Churchill 2009-03-22 23:37:21 +00:00
parent 3f0a1eb896
commit a0e9fafb8f
7 changed files with 524 additions and 0 deletions

View File

@ -0,0 +1,34 @@
#
# __init__.py
#
# 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.
#
from deluge.plugins.init import PluginInitBase
class CorePlugin(PluginInitBase):
from core import Core as _plugin_cls
class GtkUIPlugin(PluginInitBase):
from gtkui import GtkUI as _plugin_cls
class WebUIPlugin(PluginInitBase):
from webui import WebUI as _plugin_cls

View File

@ -0,0 +1,29 @@
#
# 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.
#
import pkg_resources
import os.path
def get_resource(filename):
return pkg_resources.resource_filename("example", os.path.join("data", filename))

View File

@ -0,0 +1,103 @@
#
# 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.
#
import os
import time
import hashlib
from subprocess import Popen, PIPE
from deluge.log import LOG as log
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component
from deluge.configmanager import ConfigManager
from deluge.core.rpcserver import export
DEFAULT_CONFIG = {
"commands": []
}
EXECUTE_ID = 0
EXECUTE_EVENT = 1
EXECUTE_COMMAND = 2
class Core(CorePluginBase):
def enable(self):
self.config = ConfigManager("execute.conf", DEFAULT_CONFIG)
event_manager = component.get("EventManager")
event_manager.register_event_handler("TorrentFinishedEvent",
self.on_torrent_finished)
log.debug("Example core plugin enabled!")
def execute_commands(self, torrent_id, event):
torrent = component.get("TorrentManager").torrents[torrent_id]
info = torrent.get_status(["name", "save_path"])
torrent_name = info["name"]
path = info["save_path"]
for command in self.config["commands"]:
if command[EXECUTE_EVENT] == event:
command = os.path.expandvars(command[EXECUTE_COMMAND])
command = os.path.expanduser(command)
p = Popen([command, torrent_id, torrent_name, path],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
if p.wait() != 0:
log.warn("Execute command failed with exit code %d",
p.returncode)
def disable(self):
self.config.save()
event_manager = component.get("EventManager")
event_manager.deregister_event_handler("TorrentFinishedEvent",
self.on_torrent_finished)
log.debug("Example core plugin disabled!")
def on_torrent_finished(self, torrent_id):
self.execute_commands(torrent_id, "complete")
### Exported RPC methods ###
@export
def add_command(self, event, command):
command_id = hashlib.sha1(str(time.time())).hexdigest()
self.config["commands"].append((command_id, event, command))
self.config.save()
@export
def get_commands(self):
return self.config["commands"]
@export
def remove_command(self, command_id):
for command in self.config["commands"]:
if command[EXECUTE_ID] == command_id:
self.config["commands"].remove(command)
break
self.config.save()
@export
def save_command(self, command_id, event, command):
for command in self.config["commands"]:
if command[EXECUTE_ID] == command_id:
command[EXECUTE_EVENT] = event
command[EXECUTE_COMMAND] = event
break
self.config.save()

View File

@ -0,0 +1,157 @@
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy project-wide -->
<widget class="GtkWindow" id="execute_window">
<child>
<widget class="GtkVBox" id="execute_box">
<property name="visible">True</property>
<child>
<widget class="GtkFrame" id="commands_frame">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="commands_alignment">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkVBox" id="commands_vbox">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="commands_label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Commands&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>
<child>
<widget class="GtkFrame" id="add_frame">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<widget class="GtkAlignment" id="add_alignment">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<widget class="GtkTable" id="add_table">
<property name="visible">True</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<child>
<widget class="GtkLabel" id="event_label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Event</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="x_padding">5</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="command_label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Command</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="x_padding">5</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="command_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="event_combobox">
<property name="visible">True</property>
<property name="items" translatable="yes"></property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<widget class="GtkButton" id="add_button">
<property name="label" translatable="yes">Add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_add_button_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">5</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="add_label">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Add Command&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,109 @@
#
# gtkui.py
#
# 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.
#
import os
import gtk
import pkg_resources
from deluge.log import LOG as log
from deluge.ui.client import client
from deluge.plugins.pluginbase import GtkPluginBase
import deluge.component as component
import deluge.common
EXECUTE_ID = 0
EXECUTE_EVENT = 1
EXECUTE_COMMAND = 2
EVENT_MAP = {
"complete": _("Torrent Complete")
}
class ExecutePreferences(object):
def __init__(self, plugin):
self.plugin = plugin
def load(self):
log.debug("Adding Execute Preferences page")
self.glade = gtk.glade.XML(self.get_resource("execute_prefs.glade"))
self.glade.signal_autoconnect({
"on_add_button_clicked": self.on_add_button_clicked
})
events = self.glade.get_widget("event_combobox")
store = gtk.ListStore(str, str)
store.append((_("Torrent Complete"), "complete"))
events.set_model(store)
self.plugin.add_preferences_page(_("Execute"),
self.glade.get_widget("execute_box"))
self.plugin.register_hook("on_show_prefs", self.load_commands)
self.plugin.register_hook("on_apply_prefs", self.on_apply_prefs)
def unload(self):
self.plugin.remove_preferences_page(_("Execute"))
self.plugin.deregister_hook("on_apply_prefs", self.on_apply_prefs)
self.plugin.deregister_hook("on_show_prefs", self.load_commands)
def get_resource(self, filename):
return pkg_resources.resource_filename("execute", os.path.join("data",
filename))
def load_commands(self):
def on_get_commands(commands):
vbox = self.glade.get_widget("commands_vbox")
for command in commands:
command_id, event, command = command
log.debug("Adding command `%s`", command_id)
hbox = gtk.HBox(False, 0)
label = gtk.Label(EVENT_MAP[event])
entry = gtk.Entry()
entry.set_text(command)
hbox.pack_start(label, padding = 5)
hbox.pack_start(entry)
vbox.pack_start(hbox)
hbox.show_all()
client.execute.get_commands().addCallback(on_get_commands)
def on_add_button_clicked(self, *args):
command = self.glade.get_widget("command_entry").get_text()
events = self.glade.get_widget("event_combobox")
event = events.get_model()[events.get_active()][1]
client.execute.add_command(event, command)
def on_apply_prefs(self):
options = {}
#update options dict here.
client.label.set_config(options)
class GtkUI(GtkPluginBase):
def enable(self):
self.plugin = component.get("PluginManager")
self.prefences = ExecutePreferences(self.plugin)
self.prefences.load()
def disable(self):
pass

View File

@ -0,0 +1,36 @@
#
# webui.py
#
# 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.
#
from deluge.log import LOG as log
from deluge.ui.client import client
from deluge import component
from deluge.plugins.pluginbase import WebPluginBase
class WebUI(WebPluginBase):
def enable(self):
log.debug("Example Web plugin enabled!")
def disable(self):
log.debug("Example Web plugin disabled!")

View File

@ -0,0 +1,56 @@
#
# setup.py
#
# Copyright (C) 2009 Damien Churchill <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.
#
from setuptools import setup
__plugin_name__ = "Execute"
__author__ = "Damien Churchill"
__author_email__ = "damoxc@gmail.com"
__version__ = "1.2"
__url__ = "http://deluge-torrent.org"
__license__ = "GPLv3"
__description__ = "Plugin to execute a command upon an event"
__long_description__ = __description__
__pkg_data__ = {__plugin_name__.lower(): ["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)
)