diff --git a/gui/slick/images/notifiers/boxcar2.png b/gui/slick/images/notifiers/boxcar2.png new file mode 100644 index 00000000..e25888f6 Binary files /dev/null and b/gui/slick/images/notifiers/boxcar2.png differ diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl index 7354b420..d8befbef 100644 --- a/gui/slick/interfaces/default/config_notifications.tmpl +++ b/gui/slick/interfaces/default/config_notifications.tmpl @@ -799,6 +799,59 @@ +
+
+

Boxcar2

+

Read your messages where and when you want them!

+
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
Click below to test.
+ + +
+ +
+
diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js index e828bd76..8a390d3c 100644 --- a/gui/slick/js/configNotifications.js +++ b/gui/slick/js/configNotifications.js @@ -46,6 +46,13 @@ $(document).ready(function(){ $.get(sbRoot + "/home/testBoxcar", {'username': boxcar_username}, function (data) { $('#testBoxcar-result').html(data); }); }); + + $('#testBoxcar2').click(function() { + $('#testBoxcar2-result').html(loading); + var boxcar2_accesstoken = $("#boxcar2_accesstoken").val(); + $.get(sbRoot + "/home/testBoxcar2", {'accesstoken': boxcar2_accesstoken}, + function (data) { $('#testBoxcar2-result').html(data); }); + }); $('#testPushover').click(function() { $('#testPushover-result').html(loading); diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 97413d67..540264c3 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -342,6 +342,12 @@ BOXCAR_USERNAME = None BOXCAR_PASSWORD = None BOXCAR_PREFIX = None +USE_BOXCAR2 = False +BOXCAR2_NOTIFY_ONSNATCH = False +BOXCAR2_NOTIFY_ONDOWNLOAD = False +BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD = False +BOXCAR2_ACCESSTOKEN = None + USE_PUSHOVER = False PUSHOVER_NOTIFY_ONSNATCH = False PUSHOVER_NOTIFY_ONDOWNLOAD = False @@ -495,6 +501,7 @@ def initialize(consoleLogging=True): WOMBLE, OMGWTFNZBS, OMGWTFNZBS_USERNAME, OMGWTFNZBS_APIKEY, providerList, newznabProviderList, torrentRssProviderList, \ EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \ USE_BOXCAR, BOXCAR_USERNAME, BOXCAR_PASSWORD, BOXCAR_NOTIFY_ONDOWNLOAD, BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR_NOTIFY_ONSNATCH, \ + USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, \ USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, \ 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, \ @@ -519,6 +526,8 @@ def initialize(consoleLogging=True): CheckSection(CFG, 'Growl') CheckSection(CFG, 'Prowl') CheckSection(CFG, 'Twitter') + # CheckSection(CFG, 'Boxcar') + # CheckSection(CFG, 'Boxcar2') CheckSection(CFG, 'NMJ') CheckSection(CFG, 'NMJv2') CheckSection(CFG, 'Synology') @@ -821,6 +830,12 @@ def initialize(consoleLogging=True): BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Boxcar', 'boxcar_notify_onsubtitledownload', 0)) BOXCAR_USERNAME = check_setting_str(CFG, 'Boxcar', 'boxcar_username', '') + USE_BOXCAR2 = bool(check_setting_int(CFG, 'Boxcar2', 'use_boxcar2', 0)) + BOXCAR_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Boxcar2', 'boxcar2_notify_onsnatch', 0)) + BOXCAR_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Boxcar2', 'boxcar2_notify_ondownload', 0)) + BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Boxcar2', 'boxcar2_notify_onsubtitledownload', 0)) + BOXCAR2_ACCESSTOKEN = check_setting_str(CFG, 'Boxcar2', 'boxcar2_accesstoken', '') + 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)) @@ -1563,6 +1578,13 @@ def save_config(): new_config['Boxcar']['boxcar_notify_onsubtitledownload'] = int(BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD) new_config['Boxcar']['boxcar_username'] = BOXCAR_USERNAME + new_config['Boxcar2'] = {} + new_config['Boxcar2']['use_boxcar2'] = int(USE_BOXCAR2) + new_config['Boxcar2']['boxcar2_notify_onsnatch'] = int(BOXCAR2_NOTIFY_ONSNATCH) + new_config['Boxcar2']['boxcar2_notify_ondownload'] = int(BOXCAR2_NOTIFY_ONDOWNLOAD) + new_config['Boxcar2']['boxcar2_notify_onsubtitledownload'] = int(BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD) + new_config['Boxcar2']['boxcar2_accesstoken'] = BOXCAR2_ACCESSTOKEN + new_config['Pushover'] = {} new_config['Pushover']['use_pushover'] = int(USE_PUSHOVER) new_config['Pushover']['pushover_notify_onsnatch'] = int(PUSHOVER_NOTIFY_ONSNATCH) diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index 6d6eeb77..8c9cf6a0 100644 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -31,6 +31,7 @@ import prowl from . import libnotify import pushover import boxcar +import boxcar2 import nma import pushalot import pushbullet @@ -55,6 +56,7 @@ prowl_notifier = prowl.ProwlNotifier() libnotify_notifier = libnotify.LibnotifyNotifier() pushover_notifier = pushover.PushoverNotifier() boxcar_notifier = boxcar.BoxcarNotifier() +boxcar2_notifier = boxcar2.Boxcar2Notifier() nma_notifier = nma.NMA_Notifier() pushalot_notifier = pushalot.PushalotNotifier() pushbullet_notifier = pushbullet.PushbulletNotifier() @@ -76,6 +78,7 @@ notifiers = [ prowl_notifier, pushover_notifier, boxcar_notifier, + boxcar2_notifier, nma_notifier, pushalot_notifier, pushbullet_notifier, diff --git a/sickbeard/notifiers/boxcar2.py b/sickbeard/notifiers/boxcar2.py new file mode 100755 index 00000000..5be0220e --- /dev/null +++ b/sickbeard/notifiers/boxcar2.py @@ -0,0 +1,122 @@ +# Author: Rafael Silva +# Author: Marvin Pinto +# Author: Dennis Lutter +# 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 . + +import urllib, urllib2 +import time + +import sickbeard + +from sickbeard import logger +from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD, NOTIFY_SUBTITLE_DOWNLOAD +from sickbeard.exceptions import ex + +API_URL = "https://new.boxcar.io/api/notifications" + + +class Boxcar2Notifier: + def test_notify(self, accesstoken, title="Test"): + return self._sendBoxcar2("This is a test notification from SickBeard", title, accesstoken) + + def _sendBoxcar2(self, msg, title, accesstoken): + """ + Sends a boxcar2 notification to the address provided + + msg: The message to send + title: The title of the message + accesstoken: to send to this device + + returns: True if the message succeeded, False otherwise + """ + + # build up the URL and parameters + msg = msg.strip() + curUrl = API_URL + + data = urllib.urlencode({ + 'user_credentials': accesstoken, + 'notification[title]': title, + 'notification[long_message]': msg, + 'notification[sound]': "bird-1" + }) + + # send the request to boxcar2 + 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("Boxcar2 notification failed." + ex(e), logger.ERROR) + return False + else: + logger.log("Boxcar2 notification failed. Error code: " + str(e.code), logger.WARNING) + + # HTTP status 404 + if e.code == 404: + logger.log("Access token is invalid. Check it.", logger.WARNING) + 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 send to boxcar2", logger.ERROR) + return False + + logger.log("Boxcar2 notification successful.", logger.DEBUG) + return True + + def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]): + if sickbeard.BOXCAR2_NOTIFY_ONSNATCH: + self._notifyBoxcar2(title, ep_name) + + + def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]): + if sickbeard.BOXCAR2_NOTIFY_ONDOWNLOAD: + self._notifyBoxcar2(title, ep_name) + + def notify_subtitle_download(self, ep_name, lang, title=notifyStrings[NOTIFY_SUBTITLE_DOWNLOAD]): + if sickbeard.BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD: + self._notifyBoxcar2(title, ep_name + ": " + lang) + + def _notifyBoxcar2(self, title, message, accesstoken=None): + """ + Sends a boxcar2 notification based on the provided info or SB config + + title: The title of the notification to send + message: The message string to send + accesstoken: to send to this device + """ + + if not sickbeard.USE_BOXCAR2: + logger.log("Notification for Boxcar2 not enabled, skipping this notification", logger.DEBUG) + return False + + # if no username was given then use the one from the config + if not accesstoken: + accesstoken = sickbeard.BOXCAR2_ACCESSTOKEN + + logger.log("Sending notification for " + message, logger.DEBUG) + + self._sendBoxcar2(message, title, accesstoken) + return True + + +notifier = Boxcar2Notifier diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 2f1001d8..21f014cd 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1665,6 +1665,8 @@ class ConfigNotifications: twitter_notify_onsubtitledownload=None, use_boxcar=None, boxcar_notify_onsnatch=None, boxcar_notify_ondownload=None, boxcar_notify_onsubtitledownload=None, boxcar_username=None, + use_boxcar2=None, boxcar2_notify_onsnatch=None, boxcar2_notify_ondownload=None, + boxcar2_notify_onsubtitledownload=None, boxcar2_accesstoken=None, use_pushover=None, pushover_notify_onsnatch=None, pushover_notify_ondownload=None, pushover_notify_onsubtitledownload=None, pushover_userkey=None, use_libnotify=None, libnotify_notify_onsnatch=None, libnotify_notify_ondownload=None, @@ -1739,6 +1741,12 @@ class ConfigNotifications: sickbeard.BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD = config.checkbox_to_value(boxcar_notify_onsubtitledownload) sickbeard.BOXCAR_USERNAME = boxcar_username + sickbeard.USE_BOXCAR2 = config.checkbox_to_value(use_boxcar2) + sickbeard.BOXCAR2_NOTIFY_ONSNATCH = config.checkbox_to_value(boxcar2_notify_onsnatch) + sickbeard.BOXCAR2_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(boxcar2_notify_ondownload) + sickbeard.BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD = config.checkbox_to_value(boxcar2_notify_onsubtitledownload) + sickbeard.BOXCAR2_ACCESSTOKEN = boxcar2_accesstoken + sickbeard.USE_PUSHOVER = config.checkbox_to_value(use_pushover) sickbeard.PUSHOVER_NOTIFY_ONSNATCH = config.checkbox_to_value(pushover_notify_onsnatch) sickbeard.PUSHOVER_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(pushover_notify_ondownload) @@ -2501,6 +2509,16 @@ class Home: else: return "Error sending Boxcar notification" + @cherrypy.expose + def testBoxcar2(self, accesstoken=None): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.boxcar2_notifier.test_notify(accesstoken) + if result: + return "Boxcar2 notification succeeded. Check your Boxcar2 clients to make sure it worked" + else: + return "Error sending Boxcar2 notification" + @cherrypy.expose def testPushover(self, userKey=None): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"