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 @@
+
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"