diff --git a/data/images/notifiers/pushover.gif b/data/images/notifiers/pushover.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff4de49e067d56707cb7ee810053c94d5679af31 Binary files /dev/null and b/data/images/notifiers/pushover.gif differ diff --git a/data/interfaces/default/config_notifications.tmpl b/data/interfaces/default/config_notifications.tmpl index aa71ebd1f302a5d39ef04f7e1ca988a9148a69b9..5cd55d651af62581b779a2e630e84c9cc3870516 100755 --- a/data/interfaces/default/config_notifications.tmpl +++ b/data/interfaces/default/config_notifications.tmpl @@ -567,6 +567,53 @@ </div><!-- /libnotify component-group //--> + <div class="component-group clearfix"> + <div class="component-group-desc"> + <h3><a href="http://pushover.net/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/pushover.gif" alt="" title="Pushover" width="16" height="16" /> Pushover </a></h3> + <p>Pushover makes it easy to send real-time notifications to your Android and iOS devices.</p> + </div> + <fieldset class="component-group-list"> + <div class="field-pair"> + <input type="checkbox" class="enabler" name="use_pushover" id="use_pushover" #if $sickbeard.USE_PUSHOVER then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="use_pushover"> + <span class="component-title">Enable</span> + <span class="component-desc">Should Sick Beard send notifications through Pushover?</span> + </label> + </div> + + <div id="content_use_pushover"> + <div class="field-pair"> + <input type="checkbox" name="pushover_notify_onsnatch" id="pushover_notify_onsnatch" #if $sickbeard.PUSHOVER_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="pushover_notify_onsnatch"> + <span class="component-title">Notify on Snatch</span> + <span class="component-desc">Send notification when we start a download?</span> + </label> + </div> + <div class="field-pair"> + <input type="checkbox" name="pushover_notify_ondownload" id="pushover_notify_ondownload" #if $sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# /> + <label class="clearfix" for="pushover_notify_ondownload"> + <span class="component-title">Notify on Download</span> + <span class="component-desc">Send notification when we finish a download?</span> + </label> + </div> + <div class="field-pair"> + <label class="nocheck clearfix"> + <span class="component-title"></span> + <input type="text" name="pushover_userkey" id="pushover_userkey" value="$sickbeard.PUSHOVER_USERKEY" size="35" /> + </label> + <label class="nocheck clearfix"> + <span class="component-title"> </span> + <span class="component-desc">User key of your Pushover account</span> + </label> + </div> + <div class="testNotification" id="testPushover-result">Click below to test.</div> + <input type="button" value="Test Pushover" id="testPushover" /> + <input type="submit" class="config_submitter" value="Save Changes" /> + </div><!-- /content_use_pushover //--> + + </fieldset> + </div><!-- /pushover component-group //--> + <div class="component-group clearfix"> <div class="component-group-desc"> <h3><a href="http://boxcar.io/" onclick="window.open(this.href, '_blank'); return false;"><img src="$sbRoot/images/notifiers/boxcar.gif" alt="" title="Boxcar" width="16" height="16" /> Boxcar </a></h3> diff --git a/data/js/configNotifications.js b/data/js/configNotifications.js index 4f02185a1a787dfb07db7b3fbe7cf40796b134ed..a9ed18fe89ab90b22dee734f49f2e014562cd9e4 100644 --- a/data/js/configNotifications.js +++ b/data/js/configNotifications.js @@ -52,6 +52,13 @@ $(document).ready(function(){ function (data){ $('#testBoxcar-result').html(data); }); }); + $('#testPushover').click(function(){ + $('#testPushover-result').html(loading); + var pushover_userkey = $("#pushover_userkey").val(); + $.get(sbRoot+"/home/testPushover", {'userKey': pushover_userkey}, + function (data){ $('#testPushover-result').html(data); }); + }); + $('#testLibnotify').click(function(){ $('#testLibnotify-result').html(loading); $.get(sbRoot+"/home/testLibnotify", diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index cda6094e4d37cf2773bd8be7299b95c966bd744d..1984ac00f93bea96cf9e89234fac1dbaf7b4604b 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -249,6 +249,11 @@ BOXCAR_USERNAME = None BOXCAR_PASSWORD = None BOXCAR_PREFIX = None +USE_PUSHOVER = False +PUSHOVER_NOTIFY_ONSNATCH = False +PUSHOVER_NOTIFY_ONDOWNLOAD = False +PUSHOVER_USERKEY = None + USE_LIBNOTIFY = False LIBNOTIFY_NOTIFY_ONSNATCH = False LIBNOTIFY_NOTIFY_ONDOWNLOAD = False @@ -405,6 +410,7 @@ def initialize(consoleLogging=True): NAMING_DATES, EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \ USE_NOTIFO, NOTIFO_USERNAME, NOTIFO_APISECRET, NOTIFO_NOTIFY_ONDOWNLOAD, NOTIFO_NOTIFY_ONSNATCH, \ USE_BOXCAR, BOXCAR_USERNAME, BOXCAR_PASSWORD, BOXCAR_NOTIFY_ONDOWNLOAD, BOXCAR_NOTIFY_ONSNATCH, \ + USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, \ USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_SYNOINDEX, \ USE_BANNER, USE_LISTVIEW, METADATA_XBMC, METADATA_MEDIABROWSER, METADATA_PS3, METADATA_SYNOLOGY, metadata_provider_dict, \ NEWZBIN, NEWZBIN_USERNAME, NEWZBIN_PASSWORD, GIT_PATH, MOVE_ASSOCIATED_FILES, \ @@ -627,6 +633,11 @@ def initialize(consoleLogging=True): BOXCAR_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Boxcar', 'boxcar_notify_ondownload', 0)) BOXCAR_USERNAME = check_setting_str(CFG, 'Boxcar', 'boxcar_username', '') + USE_PUSHOVER = bool(check_setting_int(CFG, 'Pushover', 'use_pushover', 0)) + PUSHOVER_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Pushover', 'pushover_notify_onsnatch', 0)) + PUSHOVER_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Pushover', 'pushover_notify_ondownload', 0)) + PUSHOVER_USERKEY = check_setting_str(CFG, 'Pushover', 'pushover_userkey', '') + USE_LIBNOTIFY = bool(check_setting_int(CFG, 'Libnotify', 'use_libnotify', 0)) LIBNOTIFY_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Libnotify', 'libnotify_notify_onsnatch', 0)) LIBNOTIFY_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Libnotify', 'libnotify_notify_ondownload', 0)) @@ -1162,6 +1173,12 @@ def save_config(): new_config['Boxcar']['boxcar_notify_ondownload'] = int(BOXCAR_NOTIFY_ONDOWNLOAD) new_config['Boxcar']['boxcar_username'] = BOXCAR_USERNAME + new_config['Pushover'] = {} + new_config['Pushover']['use_pushover'] = int(USE_PUSHOVER) + new_config['Pushover']['pushover_notify_onsnatch'] = int(PUSHOVER_NOTIFY_ONSNATCH) + new_config['Pushover']['pushover_notify_ondownload'] = int(PUSHOVER_NOTIFY_ONDOWNLOAD) + new_config['Pushover']['pushover_userkey'] = PUSHOVER_USERKEY + new_config['Libnotify'] = {} new_config['Libnotify']['use_libnotify'] = int(USE_LIBNOTIFY) new_config['Libnotify']['libnotify_notify_onsnatch'] = int(LIBNOTIFY_NOTIFY_ONSNATCH) diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index 03a4eae9c3f87942ed7af0071cd4bec739bad2d1..6e9228fa432f2e9422da43876694e1263d04f87c 100755 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -26,6 +26,7 @@ import tweet from . import libnotify import notifo import boxcar +import pushover import nmj import synoindex import trakt @@ -41,6 +42,7 @@ prowl_notifier = prowl.ProwlNotifier() twitter_notifier = tweet.TwitterNotifier() notifo_notifier = notifo.NotifoNotifier() boxcar_notifier = boxcar.BoxcarNotifier() +pushover_notifier = pushover.PushoverNotifier() libnotify_notifier = libnotify.LibnotifyNotifier() nmj_notifier = nmj.NMJNotifier() synoindex_notifier = synoindex.synoIndexNotifier() @@ -60,6 +62,7 @@ notifiers = [ nmj_notifier, synoindex_notifier, boxcar_notifier, + pushover_notifier, trakt_notifier, pytivo_notifier, nma_notifier, diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py new file mode 100644 index 0000000000000000000000000000000000000000..5814688f58e7b3883b4dd3160991e03feda8c945 --- /dev/null +++ b/sickbeard/notifiers/pushover.py @@ -0,0 +1,143 @@ +# Author: Marvin Pinto <me@marvinp.ca> +# Author: Dennis Lutter <lad1337@gmail.com> +# Author: Aaron Bieber <deftly@gmail.com> +# URL: http://code.google.com/p/sickbeard/ +# +# This file is part of Sick Beard. +# +# Sick Beard 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 of the License, or +# (at your option) any later version. +# +# Sick Beard 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 Sick Beard. If not, see <http://www.gnu.org/licenses/>. + +import urllib, urllib2 +import time + +import sickbeard + +from sickbeard import logger +from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD +from sickbeard.exceptions import ex + +API_URL = "https://api.pushover.net/1/messages.json" +API_KEY = "OKCXmkvHN1syU2e8xvpefTnyvVWGv5" + +class PushoverNotifier: + + def test_notify(self, userKey=None): + return self._sendPushover("This is a test notification from SickBeard", 'Test', userKey ) + + def _sendPushover(self, msg, title, userKey=None ): + """ + Sends a pushover notification to the address provided + + msg: The message to send (unicode) + title: The title of the message + userKey: The pushover user id to send the message to (or to subscribe with) + + returns: True if the message succeeded, False otherwise + """ + + if not userKey: + userKey = sickbeard.PUSHOVER_USERKEY + + # build up the URL and parameters + msg = msg.strip() + curUrl = API_URL + + data = urllib.urlencode({ + 'token': API_KEY, + 'title': title, + 'user': userKey, + 'message': msg.encode('utf-8'), + 'timestamp': int(time.time()) + }) + + + # send the request to pushover + try: + req = urllib2.Request(curUrl) + handle = urllib2.urlopen(req, data) + handle.close() + + except urllib2.URLError, e: + # if we get an error back that doesn't have an error code then who knows what's really happening + if not hasattr(e, 'code'): + logger.log("Pushover notification failed." + ex(e), logger.ERROR) + return False + else: + logger.log("Pushover notification failed. Error code: " + str(e.code), logger.WARNING) + + # HTTP status 404 if the provided email address isn't a Pushover user. + if e.code == 404: + logger.log("Username is wrong/not a pushover email. Pushover will send an email to it", logger.WARNING) + return False + + # For HTTP status code 401's, it is because you are passing in either an invalid token, or the user has not added your service. + elif e.code == 401: + + # If the user has already added your service, we'll return an HTTP status code of 401. + if subscribe: + logger.log("Already subscribed to service", logger.ERROR) + # i dont know if this is true or false ... its neither but i also dont know how we got here in the first place + return False + + #HTTP status 401 if the user doesn't have the service added + else: + subscribeNote = self._sendPushover(msg, title, userKey ) + if subscribeNote: + logger.log("Subscription send", logger.DEBUG) + return True + else: + logger.log("Subscription could not be send", logger.ERROR) + return False + + # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters + elif e.code == 400: + logger.log("Wrong data sent to pushover", logger.ERROR) + return False + + logger.log("Pushover notification successful.", logger.DEBUG) + return True + + def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): + if sickbeard.PUSHOVER_NOTIFY_ONSNATCH: + self._notifyPushover(title, ep_name) + + + def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): + if sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD: + self._notifyPushover(title, ep_name) + + def _notifyPushover(self, title, message, userKey=None ): + """ + Sends a pushover notification based on the provided info or SB config + + title: The title of the notification to send + message: The message string to send + userKey: The userKey to send the notification to + """ + + if not sickbeard.USE_PUSHOVER and not force: + logger.log("Notification for Pushover not enabled, skipping this notification", logger.DEBUG) + return False + + # if no userKey was given then use the one from the config + if not userKey: + userKey = sickbeard.PUSHOVER_USERKEY + + logger.log("Sending notification for " + message, logger.DEBUG) + + # self._sendPushover(message, title, userKey) + self._sendPushover(message, title) + return True + +notifier = PushoverNotifier diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 7190a4704eba985f053234c7b88032e3d14661a6..cabd4292b9515c2047dfcd758f73c3151e8f745a 100755 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1208,6 +1208,7 @@ class ConfigNotifications: use_twitter=None, twitter_notify_onsnatch=None, twitter_notify_ondownload=None, use_notifo=None, notifo_notify_onsnatch=None, notifo_notify_ondownload=None, notifo_username=None, notifo_apisecret=None, use_boxcar=None, boxcar_notify_onsnatch=None, boxcar_notify_ondownload=None, boxcar_username=None, + use_pushover=None, pushover_notify_onsnatch=None, pushover_notify_ondownload=None, pushover_userkey=None, use_libnotify=None, libnotify_notify_onsnatch=None, libnotify_notify_ondownload=None, use_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, use_synoindex=None, use_trakt=None, trakt_username=None, trakt_password=None, trakt_api=None, @@ -1333,6 +1334,20 @@ class ConfigNotifications: else: use_boxcar = 0 + if pushover_notify_onsnatch == "on": + pushover_notify_onsnatch = 1 + else: + pushover_notify_onsnatch = 0 + + if pushover_notify_ondownload == "on": + pushover_notify_ondownload = 1 + else: + pushover_notify_ondownload = 0 + if use_pushover == "on": + use_pushover = 1 + else: + use_pushover = 0 + if use_nmj == "on": use_nmj = 1 else: @@ -1428,6 +1443,11 @@ class ConfigNotifications: sickbeard.BOXCAR_NOTIFY_ONDOWNLOAD = boxcar_notify_ondownload sickbeard.BOXCAR_USERNAME = boxcar_username + sickbeard.USE_PUSHOVER = use_pushover + sickbeard.PUSHOVER_NOTIFY_ONSNATCH = pushover_notify_onsnatch + sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD = pushover_notify_ondownload + sickbeard.PUSHOVER_USERKEY = pushover_userkey + sickbeard.USE_LIBNOTIFY = use_libnotify == "on" sickbeard.LIBNOTIFY_NOTIFY_ONSNATCH = libnotify_notify_onsnatch == "on" sickbeard.LIBNOTIFY_NOTIFY_ONDOWNLOAD = libnotify_notify_ondownload == "on" @@ -2042,6 +2062,16 @@ class Home: else: return "Error sending Boxcar notification" + @cherrypy.expose + def testPushover(self, userKey=None): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.pushover_notifier.test_notify(userKey) + if result: + return "Pushover notification succeeded. Check your Pushover clients to make sure it worked" + else: + return "Error sending Pushover notification" + @cherrypy.expose def twitterStep1(self): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"