From 7812f7b4e49ef4b63429e4e274bcc0489b308cd9 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Sun, 22 Nov 2009 06:56:50 +0000 Subject: [PATCH] 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. --- deluge/plugins/freespace/freespace/core.py | 2 +- deluge/plugins/freespace/setup.py | 14 +- .../notifications/notifications/common.py | 320 +----------------- .../notifications/notifications/core.py | 151 ++++++++- .../notifications/notifications/gtkui.py | 170 +++++++++- deluge/plugins/notifications/setup.py | 8 +- 6 files changed, 332 insertions(+), 333 deletions(-) diff --git a/deluge/plugins/freespace/freespace/core.py b/deluge/plugins/freespace/freespace/core.py index 4ef054d90..97bc0e6b8 100644 --- a/deluge/plugins/freespace/freespace/core.py +++ b/deluge/plugins/freespace/freespace/core.py @@ -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) diff --git a/deluge/plugins/freespace/setup.py b/deluge/plugins/freespace/setup.py index 2e1843074..3c0dce66f 100755 --- a/deluge/plugins/freespace/setup.py +++ b/deluge/plugins/freespace/setup.py @@ -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) ) diff --git a/deluge/plugins/notifications/notifications/common.py b/deluge/plugins/notifications/notifications/common.py index 243c970f6..674c37cce 100644 --- a/deluge/plugins/notifications/notifications/common.py +++ b/deluge/plugins/notifications/notifications/common.py @@ -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 - - diff --git a/deluge/plugins/notifications/notifications/core.py b/deluge/plugins/notifications/notifications/core.py index 80b356e21..7c148c9e0 100644 --- a/deluge/plugins/notifications/notifications/core.py +++ b/deluge/plugins/notifications/notifications/core.py @@ -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) diff --git a/deluge/plugins/notifications/notifications/gtkui.py b/deluge/plugins/notifications/notifications/gtkui.py index c33618ade..8ae65115c 100644 --- a/deluge/plugins/notifications/notifications/gtkui.py +++ b/deluge/plugins/notifications/notifications/gtkui.py @@ -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): diff --git a/deluge/plugins/notifications/setup.py b/deluge/plugins/notifications/setup.py index b9a080819..b7098e22c 100755 --- a/deluge/plugins/notifications/setup.py +++ b/deluge/plugins/notifications/setup.py @@ -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(