diff --git a/CHANGES.md b/CHANGES.md
index f062d368..6ee3b63b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@
* Change authentication credentials to display more securely on config pages
* Add a "Use as default home page" selector to General Config/Interface/User Interface
* Add Kodi notifier and metadata
+* Add priority, device, and sound support to Pushover notifier (port from midgetspy/sickbeard)
[develop changelog]
diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl
index 4833b9d7..c1d8d8f8 100644
--- a/gui/slick/interfaces/default/config_notifications.tmpl
+++ b/gui/slick/interfaces/default/config_notifications.tmpl
@@ -977,11 +977,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Click below to test.
-
+
diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js
index e3c70c2f..e6469a3e 100644
--- a/gui/slick/js/configNotifications.js
+++ b/gui/slick/js/configNotifications.js
@@ -132,8 +132,11 @@ $(document).ready(function(){
});
$('#testPushover').click(function () {
- var pushover_userkey = $('#pushover_userkey').val();
- var pushover_apikey = $('#pushover_apikey').val();
+ var pushover_userkey = $.trim($('#pushover_userkey').val());
+ var pushover_apikey = $.trim($('#pushover_apikey').val());
+ var pushover_priority = $("#pushover_priority").val();
+ var pushover_device = $("#pushover_device").val();
+ var pushover_sound = $("#pushover_sound").val();
if (!pushover_userkey || !pushover_apikey) {
$('#testPushover-result').html('Please fill out the necessary fields above.');
if (!pushover_userkey) {
@@ -151,13 +154,71 @@ $(document).ready(function(){
$('#pushover_userkey,#pushover_apikey').removeClass('warning');
$(this).prop('disabled', true);
$('#testPushover-result').html(loading);
- $.get(sbRoot + '/home/testPushover', {'userKey': pushover_userkey, 'apiKey': pushover_apikey})
+ $.get(sbRoot + '/home/testPushover', {'userKey': pushover_userkey, 'apiKey': pushover_apikey, 'priority': pushover_priority, 'device': pushover_device, 'sound': pushover_sound})
.done(function (data) {
$('#testPushover-result').html(data);
$('#testPushover').prop('disabled', false);
});
});
+ function get_pushover_devices (msg) {
+ var pushover_userkey = $.trim($('#pushover_userkey').val());
+ var pushover_apikey = $.trim($('#pushover_apikey').val());
+ if (!pushover_userkey || !pushover_apikey) {
+ $('#testPushover-result').html('Please fill out the necessary fields above.');
+ if (!pushover_userkey) {
+ $('#pushover_userkey').addClass('warning');
+ } else {
+ $('#pushover_userkey').removeClass('warning');
+ }
+ if (!pushover_apikey) {
+ $('#pushover_apikey').addClass('warning');
+ } else {
+ $('#pushover_apikey').removeClass('warning');
+ }
+ return;
+ }
+ $(this).prop('disabled', true);
+ if (msg) {
+ $('#testPushover-result').html(loading);
+ }
+ var current_pushover_device = $('#pushover_device').val();
+ $.get(sbRoot + "/home/getPushoverDevices", {'userKey': pushover_userkey, 'apiKey': pushover_apikey})
+ .done(function (data) {
+ var devices = jQuery.parseJSON(data || '{}').devices;
+ $('#pushover_device_list').html('');
+ // add default option to send to all devices
+ $('#pushover_device_list').append('');
+ if (devices) {
+ for (var i = 0; i < devices.length; i++) {
+ // if a device in the list matches our current iden, select it
+ if (current_pushover_device == devices[i]) {
+ $('#pushover_device_list').append('');
+ } else {
+ $('#pushover_device_list').append('');
+ }
+ }
+ }
+ $('#getPushoverDevices').prop('disabled', false);
+ if (msg) {
+ $('#testPushover-result').html(msg);
+ }
+ });
+
+ $('#pushover_device_list').change(function () {
+ $('#pushover_device').val($('#pushover_device_list').val());
+ $('#testPushover-result').html('Don\'t forget to save your new Pushover settings.');
+ });
+ }
+
+ $('#getPushoverDevices').click(function () {
+ get_pushover_devices('Device list updated. Select specific device to use.');
+ });
+
+ if ($('#use_pushover').prop('checked')) {
+ get_pushover_devices();
+ }
+
$('#testLibnotify').click(function() {
$('#testLibnotify-result').html(loading);
$.get(sbRoot + '/home/testLibnotify',
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index f350f77e..8bc8344f 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -338,6 +338,9 @@ PUSHOVER_NOTIFY_ONDOWNLOAD = False
PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD = False
PUSHOVER_USERKEY = None
PUSHOVER_APIKEY = None
+PUSHOVER_PRIORITY = 0
+PUSHOVER_DEVICE = None
+PUSHOVER_SOUND = None
USE_LIBNOTIFY = False
LIBNOTIFY_NOTIFY_ONSNATCH = False
@@ -505,7 +508,7 @@ def initialize(consoleLogging=True):
WOMBLE, OMGWTFNZBS, OMGWTFNZBS_USERNAME, OMGWTFNZBS_APIKEY, providerList, newznabProviderList, torrentRssProviderList, \
EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, RECENTSEARCH_FREQUENCY, \
USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_SOUND, \
- USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, \
+ USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \
USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, USE_SYNOINDEX, \
USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_EMAIL, EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_FROM, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_LIST, \
@@ -836,6 +839,10 @@ def initialize(consoleLogging=True):
check_setting_int(CFG, 'Pushover', 'pushover_notify_onsubtitledownload', 0))
PUSHOVER_USERKEY = check_setting_str(CFG, 'Pushover', 'pushover_userkey', '')
PUSHOVER_APIKEY = check_setting_str(CFG, 'Pushover', 'pushover_apikey', '')
+ PUSHOVER_PRIORITY = check_setting_int(CFG, 'Pushover', 'pushover_priority', 0)
+ PUSHOVER_DEVICE = check_setting_str(CFG, 'Pushover', 'pushover_device', 'all')
+ PUSHOVER_SOUND = check_setting_str(CFG, 'Pushover', 'pushover_sound', 'pushover')
+
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))
@@ -1696,6 +1703,9 @@ def save_config():
new_config['Pushover']['pushover_notify_onsubtitledownload'] = int(PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD)
new_config['Pushover']['pushover_userkey'] = PUSHOVER_USERKEY
new_config['Pushover']['pushover_apikey'] = PUSHOVER_APIKEY
+ new_config['Pushover']['pushover_priority'] = int(PUSHOVER_PRIORITY)
+ new_config['Pushover']['pushover_device'] = PUSHOVER_DEVICE
+ new_config['Pushover']['pushover_sound'] = PUSHOVER_SOUND
new_config['Libnotify'] = {}
new_config['Libnotify']['use_libnotify'] = int(USE_LIBNOTIFY)
diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py
index 15bc1d33..f48a763d 100644
--- a/sickbeard/notifiers/pushover.py
+++ b/sickbeard/notifiers/pushover.py
@@ -17,23 +17,50 @@
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see .
-import httplib
-import urllib, urllib2
+
+import urllib
+import urllib2
import time
+import socket
+import base64
import sickbeard
from sickbeard import logger
from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD, NOTIFY_SUBTITLE_DOWNLOAD, NOTIFY_GIT_UPDATE, NOTIFY_GIT_UPDATE_TEXT
from sickbeard.exceptions import ex
-API_URL = "https://api.pushover.net/1/messages.json"
+API_URL = 'https://api.pushover.net/1/messages.json'
+DEVICE_URL = 'https://api.pushover.net/1/users/validate.json'
class PushoverNotifier:
- def test_notify(self, userKey=None, apiKey=None):
- return self._notifyPushover("This is a test notification from SickGear", 'Test', userKey, apiKey, force=True)
- def _sendPushover(self, msg, title, userKey=None, apiKey=None):
+ def get_devices(self, userKey=None, apiKey=None):
+ # fill in omitted parameters
+ if not userKey:
+ userKey = sickbeard.PUSHOVER_USERKEY
+ if not apiKey:
+ apiKey = sickbeard.PUSHOVER_APIKEY
+
+ data = urllib.urlencode({
+ 'token': apiKey,
+ 'user': userKey
+ })
+
+ # get devices from pushover
+ try:
+ req = urllib2.Request(DEVICE_URL)
+ handle = urllib2.urlopen(req, data)
+ if handle:
+ result = handle.read()
+ handle.close()
+ return result
+ except urllib2.URLError:
+ return None
+ except socket.timeout:
+ return None
+
+ def _sendPushover(self, title, msg, userKey, apiKey, priority, device, sound):
"""
Sends a pushover notification to the address provided
@@ -44,91 +71,71 @@ class PushoverNotifier:
returns: True if the message succeeded, False otherwise
"""
- if userKey == None:
+ # fill in omitted parameters
+ if not userKey:
userKey = sickbeard.PUSHOVER_USERKEY
-
- if apiKey == None:
+ if not apiKey:
apiKey = sickbeard.PUSHOVER_APIKEY
- logger.log("Pushover API KEY in use: " + apiKey, logger.DEBUG)
-
# build up the URL and parameters
msg = msg.strip()
+ data = urllib.urlencode({
+ 'token': apiKey,
+ 'title': title,
+ 'user': userKey,
+ 'message': msg.encode('utf-8'),
+ 'priority': priority,
+ 'device': device,
+ 'sound': sound,
+ 'timestamp': int(time.time())
+ })
+
# send the request to pushover
try:
- conn = httplib.HTTPSConnection("api.pushover.net:443")
- conn.request("POST", "/1/messages.json",
- urllib.urlencode({
- "token": apiKey,
- "user": userKey,
- "title": title.encode('utf-8'),
- "message": msg.encode('utf-8'),
- 'timestamp': int(time.time()),
- "retry": 60,
- "expire": 3600,
- }), {"Content-type": "application/x-www-form-urlencoded"})
-
- except urllib2.HTTPError, 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.ERROR)
+ req = urllib2.Request(API_URL)
+ handle = urllib2.urlopen(req, data)
+ handle.close()
+ except urllib2.URLError, e:
# 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)
+ logger.log(u'PUSHOVER: 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:
- #HTTP status 401 if the user doesn't have the service added
- subscribeNote = self._sendPushover(msg, title, userKey, apiKey)
+ # HTTP status 401 if the user doesn't have the service added
+ subscribeNote = self._sendPushover(title, msg, userKey)
if subscribeNote:
- logger.log("Subscription send", logger.DEBUG)
+ logger.log(u'PUSHOVER: Subscription sent', logger.DEBUG)
return True
else:
- logger.log("Subscription could not be send", logger.ERROR)
+ logger.log(u'PUSHOVER: Subscription could not be sent', 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)
+ logger.log(u'PUSHOVER: Wrong data sent to Pushover', logger.ERROR)
return False
# If you receive a HTTP status code of 429, it is because the message limit has been reached (free limit is 7,500)
elif e.code == 429:
- logger.log("Pushover API message limit reached - try a different API key", logger.ERROR)
+ logger.log(u'PUSHOVER: API message limit reached - try a different API key', logger.ERROR)
return False
- logger.log("Pushover notification successful.", logger.MESSAGE)
+ # If you receive a HTTP status code of 500, service is unavailable
+ elif e.code == 500:
+ logger.log(u'PUSHOVER: Unable to connect to API, service unavailable', logger.ERROR)
+ return False
+
+ logger.log(u'PUSHOVER: Notification successful.', logger.MESSAGE)
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 notify_subtitle_download(self, ep_name, lang, title=notifyStrings[NOTIFY_SUBTITLE_DOWNLOAD]):
- if sickbeard.PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD:
- self._notifyPushover(title, ep_name + ": " + lang)
-
- def notify_git_update(self, new_version = "??"):
- if sickbeard.USE_PUSHOVER:
- update_text=notifyStrings[NOTIFY_GIT_UPDATE_TEXT]
- title=notifyStrings[NOTIFY_GIT_UPDATE]
- self._notifyPushover(title, update_text + new_version)
-
- def _notifyPushover(self, title, message, userKey=None, apiKey=None, force=False):
+ def _notifyPushover(self, title, message, userKey=None, apiKey=None, priority=None, device=None, sound=None, force=False):
"""
- Sends a pushover notification based on the provided info or SB config
+ Sends a pushover notification based on the provided info or SG config
title: The title of the notification to send
message: The message string to send
@@ -136,14 +143,46 @@ class PushoverNotifier:
force: Enforce sending, for instance for testing
"""
+ # suppress notifications if the notifier is disabled but the notify options are checked
if not sickbeard.USE_PUSHOVER and not force:
- logger.log("Notification for Pushover not enabled, skipping this notification", logger.DEBUG)
+ logger.log(u'PUSHOVER: Notifications not enabled, skipping this notification', logger.DEBUG)
return False
- logger.log("Sending notification for " + message, logger.DEBUG)
+ # fill in omitted parameters
+ if not userKey:
+ userKey = sickbeard.PUSHOVER_USERKEY
+ if not apiKey:
+ apiKey = sickbeard.PUSHOVER_APIKEY
+ if not priority:
+ priority = sickbeard.PUSHOVER_PRIORITY
+ if not device:
+ device = sickbeard.PUSHOVER_DEVICE
+ if not sound:
+ sound = sickbeard.PUSHOVER_SOUND
- # self._sendPushover(message, title, userKey, apiKey)
- return self._sendPushover(message, title, userKey, apiKey)
+ logger.log(u'PUSHOVER: Sending notice with details: %s - %s, priority: %s, device: %s, sound: %s' % (title, message, priority, device, sound), logger.DEBUG)
+ return self._sendPushover(title, message, userKey, apiKey, priority, device, sound)
+
+ def test_notify(self, userKey, apiKey, priority, device, sound):
+ return self._notifyPushover('Test', 'This is a test notification from SickGear', userKey, apiKey, priority, device, sound, force=True)
+
+ def notify_snatch(self, ep_name):
+ if sickbeard.PUSHOVER_NOTIFY_ONSNATCH:
+ self._notifyPushover(notifyStrings[NOTIFY_SNATCH], ep_name)
+
+ def notify_download(self, ep_name):
+ if sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD:
+ self._notifyPushover(notifyStrings[NOTIFY_DOWNLOAD], ep_name)
+
+ def notify_subtitle_download(self, ep_name, lang):
+ if sickbeard.PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD:
+ self._notifyPushover(notifyStrings[NOTIFY_SUBTITLE_DOWNLOAD], ep_name + ': ' + lang)
+
+ def notify_git_update(self, new_version = '??'):
+ if sickbeard.USE_PUSHOVER:
+ update_text=notifyStrings[NOTIFY_GIT_UPDATE_TEXT]
+ title=notifyStrings[NOTIFY_GIT_UPDATE]
+ self._notifyPushover(title, update_text + new_version)
notifier = PushoverNotifier
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 7264285d..6b7b05c7 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -662,7 +662,7 @@ class Home(MainHandler):
else:
return 'Error sending Boxcar2 notification'
- def testPushover(self, userKey=None, apiKey=None):
+ def testPushover(self, userKey=None, apiKey=None, priority=None, device=None, sound=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
if None is not userKey and starify(userKey, True):
@@ -671,12 +671,27 @@ class Home(MainHandler):
if None is not apiKey and starify(apiKey, True):
apiKey = sickbeard.PUSHOVER_APIKEY
- result = notifiers.pushover_notifier.test_notify(userKey, apiKey)
+ result = notifiers.pushover_notifier.test_notify(userKey, apiKey, priority, device, sound)
if result:
return 'Pushover notification succeeded. Check your Pushover clients to make sure it worked'
else:
return 'Error sending Pushover notification'
+ def getPushoverDevices(self, userKey=None, apiKey=None):
+ self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
+
+ if None is not userKey and starify(userKey, True):
+ userKey = sickbeard.PUSHOVER_USERKEY
+
+ if None is not apiKey and starify(apiKey, True):
+ apiKey = sickbeard.PUSHOVER_APIKEY
+
+ result = notifiers.pushover_notifier.get_devices(userKey, apiKey)
+ if result:
+ return result
+ else:
+ return "{}"
+
def twitterStep1(self, *args, **kwargs):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@@ -4176,6 +4191,7 @@ class ConfigNotifications(Config):
boxcar2_notify_onsubtitledownload=None, boxcar2_accesstoken=None, boxcar2_sound=None,
use_pushover=None, pushover_notify_onsnatch=None, pushover_notify_ondownload=None,
pushover_notify_onsubtitledownload=None, pushover_userkey=None, pushover_apikey=None,
+ pushover_priority=None, pushover_device=None, pushover_sound=None, pushover_device_list=None,
use_libnotify=None, libnotify_notify_onsnatch=None, libnotify_notify_ondownload=None,
libnotify_notify_onsubtitledownload=None,
use_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, use_synoindex=None,
@@ -4281,6 +4297,9 @@ class ConfigNotifications(Config):
key = pushover_apikey.strip()
if not starify(key, True):
sickbeard.PUSHOVER_APIKEY = key
+ sickbeard.PUSHOVER_PRIORITY = pushover_priority
+ sickbeard.PUSHOVER_DEVICE = pushover_device
+ sickbeard.PUSHOVER_SOUND = pushover_sound
sickbeard.USE_LIBNOTIFY = config.checkbox_to_value(use_libnotify)
sickbeard.LIBNOTIFY_NOTIFY_ONSNATCH = config.checkbox_to_value(libnotify_notify_onsnatch)