Update the Notifications and FreeSpace plugins descriptions.

On the Notifications plugin, moved the Core and GtkUi notification implementations to `core.py` and `gtkui.py` respectively.
This commit is contained in:
Pedro Algarvio 2009-11-22 06:56:50 +00:00
parent 127b577440
commit 7812f7b4e4
6 changed files with 332 additions and 333 deletions

View File

@ -77,7 +77,7 @@ class Core(CorePluginBase):
self._timer = task.LoopingCall(self.update)
else:
self._timer.stop()
self._interval = 15 #60
self._interval = 60 * 5 # every 5 minutes
if self.config['enabled']:
self._timer.start(self._interval, False)

View File

@ -22,9 +22,9 @@
#
# You should have received a copy of the GNU General Public License
# along with deluge. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
@ -45,8 +45,8 @@ __author_email__ = "ufs@ufsoft.org"
__version__ = "0.1"
__url__ = "http://deluge.ufsoft.org/hg/Notification/"
__license__ = "GPLv3"
__description__ = ""
__long_description__ = """"""
__description__ = "Plugin which continuously checks for available free space."
__long_description__ = __description__
__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]}
setup(
@ -67,7 +67,5 @@ setup(
%s = %s:CorePlugin
[deluge.plugin.gtkui]
%s = %s:GtkUIPlugin
[deluge.plugin.webui]
%s = %s:WebUIPlugin
""" % ((__plugin_name__, __plugin_name__.lower())*3)
""" % ((__plugin_name__, __plugin_name__.lower())*2)
)

View File

@ -37,12 +37,9 @@
# statement from all source files in the program, then also delete it here.
#
import smtplib
from twisted.internet import defer, threads
from twisted.internet import defer
from deluge import component
from deluge.log import LOG as log
from deluge.ui.client import client
import deluge.common
try:
from deluge.event import known_events
@ -50,20 +47,6 @@ except ImportError:
# Old deluge version
known_events = {}
try:
import pygame
SOUND_AVAILABLE = True
except ImportError:
SOUND_AVAILABLE = False
try:
import pynotify
POPUP_AVAILABLE = True
if deluge.common.windows_check():
POPUP_AVAILABLE = False
except ImportError:
POPUP_AVAILABLE = False
def get_resource(filename):
import pkg_resources, os
@ -154,304 +137,3 @@ class CustomNotifications(object):
log.debug("Notification failure using %s: %s", kind, failure)
return failure
class CoreNotifications(CustomNotifications):
def enable(self):
CustomNotifications.enable(self)
self.register_custom_email_notification('TorrentFinishedEvent',
self._on_torrent_finished_event)
def disable(self):
self.deregister_custom_email_notification('TorrentFinishedEvent')
CustomNotifications.disable(self)
def register_custom_email_notification(self, eventtype, handler):
"""This is used to register email notifications for custom event types.
:param event: str, the event name
:param handler: function, to be called when `:param:event` is emitted
Your handler should return a tuple of (email_subject, email_contents).
"""
self._register_custom_provider('email', eventtype, handler)
def deregister_custom_email_notification(self, eventtype):
self._deregister_custom_provider('email', eventtype)
def handle_custom_email_notification(self, result, eventtype):
if not self.config['smtp_enabled']:
return defer.succeed("SMTP notification not enabled.")
subject, message = result
log.debug("Spawning new thread to send email with subject: %s: %s",
subject, message)
# Spawn thread because we don't want Deluge to lock up while we send the
# email.
return threads.deferToThread(self._notify_email, subject, message)
def get_handled_events(self):
handled_events = []
for evt in sorted(known_events.keys()):
if known_events[evt].__module__.startswith('deluge.event'):
if evt not in ('TorrentFinishedEvent',):
# Skip all un-handled built-in events
continue
classdoc = known_events[evt].__doc__.strip()
handled_events.append((evt, classdoc))
log.debug("Handled Notification Events: %s", handled_events)
return handled_events
def _notify_email(self, subject='', message=''):
log.debug("Email prepared")
to_addrs = '; '.join(self.config['smtp_recipients'])
headers = """\
From: %(smtp_from)s
To: %(smtp_recipients)s
Subject: %(subject)s
""" % {'smtp_from': self.config['smtp_from'],
'subject': subject,
'smtp_recipients': to_addrs}
message = '\r\n'.join((headers + message).splitlines())
try:
try:
# Python 2.6
server = smtplib.SMTP(self.config["smtp_host"],
self.config["smtp_port"],
timeout=60)
except:
# Python 2.5
server = smtplib.SMTP(self.config["smtp_host"],
self.config["smtp_port"])
except Exception, err:
err_msg = _("There was an error sending the notification email:"
" %s") % err
log.error(err_msg)
return err
security_enabled = self.config['smtp_tls']
if security_enabled:
server.ehlo()
if not server.esmtp_features.has_key('starttls'):
log.warning("TLS/SSL enabled but server does not support it")
else:
server.starttls()
server.ehlo()
if self.config['smtp_user'] and self.config['smtp_pass']:
try:
server.login(self.config['smtp_user'], self.config['smtp_pass'])
except smtplib.SMTPHeloError, err:
err_msg = _("The server didn't reply properly to the helo "
"greeting: %s") % err
log.error(err_msg)
return err
except smtplib.SMTPAuthenticationError, err:
err_msg = _("The server didn't accept the username/password "
"combination: %s") % err
log.error(err_msg)
return err
try:
try:
server.sendmail(self.config['smtp_from'], to_addrs, message)
except smtplib.SMTPException, err:
err_msg = _("There was an error sending the notification email:"
" %s") % err
log.error(err_msg)
return err
finally:
if security_enabled:
# avoid false failure detection when the server closes
# the SMTP connection with TLS enabled
import socket
try:
server.quit()
except socket.sslerror:
pass
else:
server.quit()
return _("Notification email sent.")
def _on_torrent_finished_event(self, torrent_id):
log.debug("Handler for TorrentFinishedEvent called for CORE")
torrent = component.get("TorrentManager")[torrent_id]
torrent_status = torrent.get_status({})
# Email
subject = _("Finished Torrent \"%(name)s\"") % torrent_status
message = _(
"This email is to inform you that Deluge has finished "
"downloading \"%(name)s\", which includes %(num_files)i files."
"\nTo stop receiving these alerts, simply turn off email "
"notification in Deluge's preferences.\n\n"
"Thank you,\nDeluge."
) % torrent_status
return subject, message
d = defer.maybeDeferred(self.handle_custom_email_notification,
[subject, message],
"TorrentFinishedEvent")
d.addCallback(self._on_notify_sucess, 'email')
d.addErrback(self._on_notify_failure, 'email')
return d
class GtkUiNotifications(CustomNotifications):
def enable(self):
CustomNotifications.enable(self)
self.register_custom_blink_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_blink
)
self.register_custom_sound_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_sound
)
self.register_custom_popup_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_popup
)
def disable(self):
self.deregister_custom_blink_notification("TorrentFinishedEvent")
self.deregister_custom_sound_notification("TorrentFinishedEvent")
self.deregister_custom_popup_notification("TorrentFinishedEvent")
CustomNotifications.disable(self)
def register_custom_popup_notification(self, eventtype, handler):
"""This is used to register popup notifications for custom event types.
:param event: the event name
:param type: string
:param handler: function, to be called when `:param:event` is emitted
Your handler should return a tuple of (popup_title, popup_contents).
"""
self._register_custom_provider('popup', eventtype, handler)
def deregister_custom_popup_notification(self, eventtype):
self._deregister_custom_provider('popup', eventtype)
def register_custom_blink_notification(self, eventtype, handler):
"""This is used to register blink notifications for custom event types.
:param event: str, the event name
:param handler: function, to be called when `:param:event` is emitted
Your handler should return `True` or `False` to blink or not the
trayicon.
"""
self._register_custom_provider('blink', eventtype, handler)
def deregister_custom_blink_notification(self, eventtype):
self._deregister_custom_provider('blink', eventtype)
def register_custom_sound_notification(self, eventtype, handler):
"""This is used to register sound notifications for custom event types.
:param event: the event name
:type event: string
:param handler: function to be called when `:param:event` is emitted
Your handler should return either '' to use the sound defined on the
notification preferences, the path to a sound file, which will then be
played or None, where no sound will be played at all.
"""
self._register_custom_provider('sound', eventtype, handler)
def deregister_custom_sound_notification(self, eventtype):
self._deregister_custom_provider('sound', eventtype)
def handle_custom_popup_notification(self, result, eventtype):
title, message = result
return defer.maybeDeferred(self.__popup, title, message)
def handle_custom_blink_notification(self, result, eventtype):
if result:
return defer.maybeDeferred(self.__blink)
return defer.succeed("Won't blink. The returned value from the custom "
"handler was: %s", result)
def handle_custom_sound_notification(self, result, eventtype):
if isinstance(result, basestring):
if not result and eventtype in self.config['custom_sounds']:
return defer.maybeDeferred(
self.__play_sound, self.config['custom_sounds'][eventtype])
return defer.maybeDeferred(self.__play_sound, result)
return defer.succeed("Won't play sound. The returned value from the "
"custom handler was: %s", result)
def __blink(self):
self.systray.blink(True)
return defer.succeed(_("Notification Blink shown"))
def __popup(self, title='', message=''):
import gtk
if not self.config['popup_enabled']:
return defer.succeed(_("Popup notification is not enabled."))
if not POPUP_AVAILABLE:
return defer.fail(_("pynotify is not installed"))
if pynotify.init("Deluge"):
icon = gtk.gdk.pixbuf_new_from_file_at_size(
deluge.common.get_pixmap("deluge.svg"), 48, 48)
self.note = pynotify.Notification(title, message)
self.note.set_icon_from_pixbuf(icon)
if not self.note.show():
err_msg = _("pynotify failed to show notification")
log.warning(err_msg)
return defer.fail(err_msg)
return defer.succeed(_("Notification popup shown"))
def __play_sound(self, sound_path=''):
if not self.config['sound_enabled']:
return defer.succeed(_("Sound notification not enabled"))
if not SOUND_AVAILABLE:
err_msg = _("pygame is not installed")
log.warning(err_msg)
return defer.fail(err_msg)
pygame.init()
try:
if not sound_path:
sound_path = self.config['sound_path']
alert_sound = pygame.mixer.music
alert_sound.load(sound_path)
alert_sound.play()
except pygame.error, message:
err_msg = _("Sound notification failed %s") % (message)
log.warning(err_msg)
return defer.fail(err_msg)
else:
msg = _("Sound notification Success")
log.info(msg)
return defer.succeed(msg)
def _on_torrent_finished_event_blink(self, torrent_id):
return True # Yes, Blink
def _on_torrent_finished_event_sound(self, torrent_id):
# Since there's no custom sound hardcoded, just return ''
return ''
def _on_torrent_finished_event_popup(self, torrent_id):
d = client.core.get_torrent_status(torrent_id, ["name", "num_files"])
d.addCallback(self._on_torrent_finished_event_got_torrent_status)
d.addErrback(self._on_torrent_finished_event_torrent_status_failure)
return d
def _on_torrent_finished_event_torrent_status_failure(self, failure):
log.debug("Failed to get torrent status to be able to show the popup")
def _on_torrent_finished_event_got_torrent_status(self, torrent_status):
log.debug("Handler for TorrentFinishedEvent GTKUI called. "
"Got Torrent Status")
title = _("Finished Torrent")
message = _("The torrent \"%(name)s\" including %(num_files)i "
"has finished downloading.") % torrent_status
return title, message

View File

@ -37,12 +37,15 @@
# statement from all source files in the program, then also delete it here.
#
import smtplib
from twisted.internet import defer, threads
from deluge.event import known_events
from deluge.log import LOG as log
from deluge.plugins.pluginbase import CorePluginBase
import deluge.configmanager
from deluge.core.rpcserver import export
from notifications.common import CoreNotifications
from notifications.common import CustomNotifications
DEFAULT_PREFS = {
"smtp_enabled": False,
@ -59,6 +62,152 @@ DEFAULT_PREFS = {
}
}
class CoreNotifications(CustomNotifications):
def enable(self):
CustomNotifications.enable(self)
self.register_custom_email_notification('TorrentFinishedEvent',
self._on_torrent_finished_event)
def disable(self):
self.deregister_custom_email_notification('TorrentFinishedEvent')
CustomNotifications.disable(self)
def register_custom_email_notification(self, eventtype, handler):
"""This is used to register email notifications for custom event types.
:param event: str, the event name
:param handler: function, to be called when `:param:event` is emitted
Your handler should return a tuple of (email_subject, email_contents).
"""
self._register_custom_provider('email', eventtype, handler)
def deregister_custom_email_notification(self, eventtype):
self._deregister_custom_provider('email', eventtype)
def handle_custom_email_notification(self, result, eventtype):
if not self.config['smtp_enabled']:
return defer.succeed("SMTP notification not enabled.")
subject, message = result
log.debug("Spawning new thread to send email with subject: %s: %s",
subject, message)
# Spawn thread because we don't want Deluge to lock up while we send the
# email.
return threads.deferToThread(self._notify_email, subject, message)
def get_handled_events(self):
handled_events = []
for evt in sorted(known_events.keys()):
if known_events[evt].__module__.startswith('deluge.event'):
if evt not in ('TorrentFinishedEvent',):
# Skip all un-handled built-in events
continue
classdoc = known_events[evt].__doc__.strip()
handled_events.append((evt, classdoc))
log.debug("Handled Notification Events: %s", handled_events)
return handled_events
def _notify_email(self, subject='', message=''):
log.debug("Email prepared")
to_addrs = '; '.join(self.config['smtp_recipients'])
headers = """\
From: %(smtp_from)s
To: %(smtp_recipients)s
Subject: %(subject)s
""" % {'smtp_from': self.config['smtp_from'],
'subject': subject,
'smtp_recipients': to_addrs}
message = '\r\n'.join((headers + message).splitlines())
try:
try:
# Python 2.6
server = smtplib.SMTP(self.config["smtp_host"],
self.config["smtp_port"],
timeout=60)
except:
# Python 2.5
server = smtplib.SMTP(self.config["smtp_host"],
self.config["smtp_port"])
except Exception, err:
err_msg = _("There was an error sending the notification email:"
" %s") % err
log.error(err_msg)
return err
security_enabled = self.config['smtp_tls']
if security_enabled:
server.ehlo()
if not server.esmtp_features.has_key('starttls'):
log.warning("TLS/SSL enabled but server does not support it")
else:
server.starttls()
server.ehlo()
if self.config['smtp_user'] and self.config['smtp_pass']:
try:
server.login(self.config['smtp_user'], self.config['smtp_pass'])
except smtplib.SMTPHeloError, err:
err_msg = _("The server didn't reply properly to the helo "
"greeting: %s") % err
log.error(err_msg)
return err
except smtplib.SMTPAuthenticationError, err:
err_msg = _("The server didn't accept the username/password "
"combination: %s") % err
log.error(err_msg)
return err
try:
try:
server.sendmail(self.config['smtp_from'], to_addrs, message)
except smtplib.SMTPException, err:
err_msg = _("There was an error sending the notification email:"
" %s") % err
log.error(err_msg)
return err
finally:
if security_enabled:
# avoid false failure detection when the server closes
# the SMTP connection with TLS enabled
import socket
try:
server.quit()
except socket.sslerror:
pass
else:
server.quit()
return _("Notification email sent.")
def _on_torrent_finished_event(self, torrent_id):
log.debug("Handler for TorrentFinishedEvent called for CORE")
torrent = component.get("TorrentManager")[torrent_id]
torrent_status = torrent.get_status({})
# Email
subject = _("Finished Torrent \"%(name)s\"") % torrent_status
message = _(
"This email is to inform you that Deluge has finished "
"downloading \"%(name)s\", which includes %(num_files)i files."
"\nTo stop receiving these alerts, simply turn off email "
"notification in Deluge's preferences.\n\n"
"Thank you,\nDeluge."
) % torrent_status
return subject, message
d = defer.maybeDeferred(self.handle_custom_email_notification,
[subject, message],
"TorrentFinishedEvent")
d.addCallback(self._on_notify_sucess, 'email')
d.addErrback(self._on_notify_failure, 'email')
return d
class Core(CorePluginBase, CoreNotifications):
def __init__(self, plugin_name):
CorePluginBase.__init__(self, plugin_name)

View File

@ -49,8 +49,22 @@ import deluge.common
import deluge.configmanager
# Relative imports
from notifications.common import (get_resource, GtkUiNotifications,
SOUND_AVAILABLE, POPUP_AVAILABLE)
from common import get_resource, CustomNotifications
try:
import pygame
SOUND_AVAILABLE = True
except ImportError:
SOUND_AVAILABLE = False
try:
import pynotify
POPUP_AVAILABLE = True
if deluge.common.windows_check():
POPUP_AVAILABLE = False
except ImportError:
POPUP_AVAILABLE = False
DEFAULT_PREFS = {
# BLINK
@ -76,6 +90,158 @@ RECIPIENT_FIELD, RECIPIENT_EDIT = range(2)
SUB_NOT_SOUND) = range(6)
SND_EVENT, SND_EVENT_DOC, SND_NAME, SND_PATH = range(4)
class GtkUiNotifications(CustomNotifications):
def enable(self):
CustomNotifications.enable(self)
self.register_custom_blink_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_blink
)
self.register_custom_sound_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_sound
)
self.register_custom_popup_notification(
"TorrentFinishedEvent", self._on_torrent_finished_event_popup
)
def disable(self):
self.deregister_custom_blink_notification("TorrentFinishedEvent")
self.deregister_custom_sound_notification("TorrentFinishedEvent")
self.deregister_custom_popup_notification("TorrentFinishedEvent")
CustomNotifications.disable(self)
def register_custom_popup_notification(self, eventtype, handler):
"""This is used to register popup notifications for custom event types.
:param event: the event name
:param type: string
:param handler: function, to be called when `:param:event` is emitted
Your handler should return a tuple of (popup_title, popup_contents).
"""
self._register_custom_provider('popup', eventtype, handler)
def deregister_custom_popup_notification(self, eventtype):
self._deregister_custom_provider('popup', eventtype)
def register_custom_blink_notification(self, eventtype, handler):
"""This is used to register blink notifications for custom event types.
:param event: str, the event name
:param handler: function, to be called when `:param:event` is emitted
Your handler should return `True` or `False` to blink or not the
trayicon.
"""
self._register_custom_provider('blink', eventtype, handler)
def deregister_custom_blink_notification(self, eventtype):
self._deregister_custom_provider('blink', eventtype)
def register_custom_sound_notification(self, eventtype, handler):
"""This is used to register sound notifications for custom event types.
:param event: the event name
:type event: string
:param handler: function to be called when `:param:event` is emitted
Your handler should return either '' to use the sound defined on the
notification preferences, the path to a sound file, which will then be
played or None, where no sound will be played at all.
"""
self._register_custom_provider('sound', eventtype, handler)
def deregister_custom_sound_notification(self, eventtype):
self._deregister_custom_provider('sound', eventtype)
def handle_custom_popup_notification(self, result, eventtype):
title, message = result
return defer.maybeDeferred(self.__popup, title, message)
def handle_custom_blink_notification(self, result, eventtype):
if result:
return defer.maybeDeferred(self.__blink)
return defer.succeed("Won't blink. The returned value from the custom "
"handler was: %s", result)
def handle_custom_sound_notification(self, result, eventtype):
if isinstance(result, basestring):
if not result and eventtype in self.config['custom_sounds']:
return defer.maybeDeferred(
self.__play_sound, self.config['custom_sounds'][eventtype])
return defer.maybeDeferred(self.__play_sound, result)
return defer.succeed("Won't play sound. The returned value from the "
"custom handler was: %s", result)
def __blink(self):
self.systray.blink(True)
return defer.succeed(_("Notification Blink shown"))
def __popup(self, title='', message=''):
import gtk
if not self.config['popup_enabled']:
return defer.succeed(_("Popup notification is not enabled."))
if not POPUP_AVAILABLE:
return defer.fail(_("pynotify is not installed"))
if pynotify.init("Deluge"):
icon = gtk.gdk.pixbuf_new_from_file_at_size(
deluge.common.get_pixmap("deluge.svg"), 48, 48)
self.note = pynotify.Notification(title, message)
self.note.set_icon_from_pixbuf(icon)
if not self.note.show():
err_msg = _("pynotify failed to show notification")
log.warning(err_msg)
return defer.fail(err_msg)
return defer.succeed(_("Notification popup shown"))
def __play_sound(self, sound_path=''):
if not self.config['sound_enabled']:
return defer.succeed(_("Sound notification not enabled"))
if not SOUND_AVAILABLE:
err_msg = _("pygame is not installed")
log.warning(err_msg)
return defer.fail(err_msg)
pygame.init()
try:
if not sound_path:
sound_path = self.config['sound_path']
alert_sound = pygame.mixer.music
alert_sound.load(sound_path)
alert_sound.play()
except pygame.error, message:
err_msg = _("Sound notification failed %s") % (message)
log.warning(err_msg)
return defer.fail(err_msg)
else:
msg = _("Sound notification Success")
log.info(msg)
return defer.succeed(msg)
def _on_torrent_finished_event_blink(self, torrent_id):
return True # Yes, Blink
def _on_torrent_finished_event_sound(self, torrent_id):
# Since there's no custom sound hardcoded, just return ''
return ''
def _on_torrent_finished_event_popup(self, torrent_id):
d = client.core.get_torrent_status(torrent_id, ["name", "num_files"])
d.addCallback(self._on_torrent_finished_event_got_torrent_status)
d.addErrback(self._on_torrent_finished_event_torrent_status_failure)
return d
def _on_torrent_finished_event_torrent_status_failure(self, failure):
log.debug("Failed to get torrent status to be able to show the popup")
def _on_torrent_finished_event_got_torrent_status(self, torrent_status):
log.debug("Handler for TorrentFinishedEvent GTKUI called. "
"Got Torrent Status")
title = _("Finished Torrent")
message = _("The torrent \"%(name)s\" including %(num_files)i "
"has finished downloading.") % torrent_status
return title, message
class GtkUI(GtkPluginBase, GtkUiNotifications):
def __init__(self, plugin_name):

View File

@ -45,8 +45,12 @@ __author_email__ = "ufs@ufsoft.org"
__version__ = "0.1"
__url__ = "http://dev.deluge-torrent.org/"
__license__ = "GPLv3"
__description__ = ""
__long_description__ = """"""
__description__ = "Plugin which provides notifications to Deluge."
__long_description__ = __description__ + """\
Email, Popup, Blink and Sound notifications are supported.
The plugin also allows other plugins to make use of itself for their own custom
notifications.
"""
__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]}
setup(