From 5378884bf8f73bab83cbc38d492c6ba6246309c7 Mon Sep 17 00:00:00 2001 From: daktak Date: Mon, 14 Apr 2014 17:43:01 +1000 Subject: [PATCH] boxcar notification --- data/interfaces/default/config.html | 36 +++++++++ headphones/__init__.py | 14 ++++ headphones/notifiers.py | 115 ++++++++++++++++++++++++++++ headphones/postprocessor.py | 6 ++ headphones/sab.py | 4 + headphones/webserve.py | 8 +- 6 files changed, 182 insertions(+), 1 deletion(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 820e729d..103864d3 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -737,6 +737,22 @@ +
+

Boxcar.IO

+
+ +
+
+
+
+ +
+ + +
+
+
+

Pushbullet

@@ -1427,6 +1443,26 @@ $("#pushbulletoptions").hide(); } + if ($("#boxcar").is(":checked")) + { + $("#boxcaroptions").show(); + } + else + { + $("#boxcaroptions").hide(); + } + + $("#boxcar").click(function(){ + if ($("#boxcar").is(":checked")) + { + $("#boxcaroptions").slideDown(); + } + else + { + $("#boxcaroptions").slideUp(); + } + }); + $("#pushbullet").click(function(){ if ($("#pushbullet").is(":checked")) { diff --git a/headphones/__init__.py b/headphones/__init__.py index 47588ec4..4e05eb4f 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -261,6 +261,10 @@ PUSHOVER_PRIORITY = 1 PUSHOVER_KEYS = None PUSHOVER_ONSNATCH = True PUSHOVER_APITOKEN = None +BOXCAR_ENABLED = False +BOXCAR_USERNAME = None +BOXCAR_ONSNATCH = False + PUSHBULLET_ENABLED = True PUSHBULLET_APIKEY = None PUSHBULLET_DEVICEID = None @@ -350,6 +354,7 @@ def initialize(): MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, ENCODER_MULTICORE, ENCODER_MULTICORE_COUNT, DELETE_LOSSLESS_FILES, \ GROWL_ENABLED, GROWL_HOST, GROWL_PASSWORD, GROWL_ONSNATCH, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_KEYS, PUSHOVER_ONSNATCH, PUSHOVER_APITOKEN, MIRRORLIST, \ TWITTER_ENABLED, TWITTER_ONSNATCH, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \ + BOXCAR_ENABLED, BOXCAR_USERNAME, BOXCAR_ONSNATCH, \ PUSHBULLET_ENABLED, PUSHBULLET_APIKEY, PUSHBULLET_DEVICEID, PUSHBULLET_ONSNATCH, \ MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \ XBMC_NOTIFY, LMS_ENABLED, LMS_HOST, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \ @@ -599,6 +604,10 @@ def initialize(): PUSHOVER_PRIORITY = check_setting_int(CFG, 'Pushover', 'pushover_priority', 0) PUSHOVER_APITOKEN = check_setting_str(CFG, 'Pushover', 'pushover_apitoken', '') + BOXCAR_ENABLED = bool(check_setting_int(CFG, 'BOXCAR', 'boxcar_enabled', 0)) + BOXCAR_USERNAME = check_setting_str(CFG, 'BOXCAR', 'boxcar_username', '') + BOXCAR_ONSNATCH = bool(check_setting_int(CFG, 'BOXCAR', 'boxcar_onsnatch', 0)) + PUSHBULLET_ENABLED = bool(check_setting_int(CFG, 'PushBullet', 'pushbullet_enabled', 0)) PUSHBULLET_APIKEY = check_setting_str(CFG, 'PushBullet', 'pushbullet_apikey', '') PUSHBULLET_DEVICEID = check_setting_str(CFG, 'PushBullet', 'pushbullet_deviceid', '') @@ -1012,6 +1021,11 @@ def config_write(): new_config['Pushover']['pushover_priority'] = int(PUSHOVER_PRIORITY) new_config['Pushover']['pushover_apitoken'] = PUSHOVER_APITOKEN + new_config['BOXCAR'] = {} + new_config['BOXCAR']['boxcar_enabled'] = int(BOXCAR_ENABLED) + new_config['BOXCAR']['boxcar_username'] = BOXCAR_USERNAME + new_config['BOXCAR']['boxcar_onsnatch'] = int(BOXCAR_ONSNATCH) + new_config['PushBullet'] = {} new_config['PushBullet']['pushbullet_enabled'] = int(PUSHBULLET_ENABLED) new_config['PushBullet']['pushbullet_apikey'] = PUSHBULLET_APIKEY diff --git a/headphones/notifiers.py b/headphones/notifiers.py index ff27077f..e7f4f5fe 100644 --- a/headphones/notifiers.py +++ b/headphones/notifiers.py @@ -22,6 +22,7 @@ import simplejson import os.path import subprocess import gntp.notifier +import time from xml.dom import minidom from httplib import HTTPSConnection @@ -694,3 +695,117 @@ class TwitterNotifier: return self._send_tweet(prefix+": "+message) notifier = TwitterNotifier + +API_URL = "https://boxcar.io/devices/providers/WqbewHpV8ZATnawpCsr4/notifications" + +class BOXCAR: + + def test_notify(self, email, title="Test"): + return self._sendBoxcar("This is a test notification from Headphones", title, email) + + def _sendBoxcar(self, msg, title, email, subscribe=False): + """ + Sends a boxcar notification to the address provided + + msg: The message to send (unicode) + title: The title of the message + email: The email address to send the message to (or to subscribe with) + subscribe: If true then instead of sending a message this function will send a subscription notificat$ + + returns: True if the message succeeded, False otherwise + """ + + # build up the URL and parameters + msg = msg.strip() + curUrl = API_URL + # if this is a subscription notification then act accordingly + if subscribe: + data = urllib.urlencode({'email': email}) + curUrl = curUrl + "/subscribe" + # for normal requests we need all these parameters + else: + data = urllib.urlencode({ + 'email': email, + 'notification[from_screen_name]': title, + 'notification[message]': msg.encode('utf-8'), + 'notification[from_remote_service_id]': int(time.time()) + }) + + logger.info(data) + # send the request to boxcar + 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.error("Boxcar notification failed." + ex(e)) + return False + else: + logger.error("Boxcar notification failed. Error code: " + str(e.code)) + + # HTTP status 404 if the provided email address isn't a Boxcar user. + if e.code == 404: + logger.error("Username is wrong/not a boxcar email. Boxcar will send an email to it") + 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$ + elif e.code == 401: + + # If the user has already added your service, we'll return an HTTP status code of 401. + if subscribe: + logger.error("Already subscribed to service") + # i dont know if this is true or false ... its neither but i also dont know how we got here in the first $ + return False + + #HTTP status 401 if the user doesn't have the service added + else: + subscribeNote = self._sendBoxcar(msg, title, email, True) + if subscribeNote: + logger.info("Subscription send") + return True + else: + logger.info("Subscription could not be send") + 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.info("Wrong data sent to boxcar") + logger.info('data:' + data) + return False + + logger.fdebug("Boxcar notification successful.") + return True + + def notify(self, artist=None, album=None, snatched_nzb=None, username=None, force=False): + """ + Sends a boxcar notification based on the provided info or SB config + + title: The title of the notification to send + message: The message string to send + username: The username to send the notification to (optional, defaults to the username in the config) + force: If True then the notification will be sent even if Boxcar is disabled in the config + """ + if not headphones.BOXCAR_ENABLED and not force: + logger.fdebug("Notification for Boxcar not enabled, skipping this notification") + return False + + # if no username was given then use the one from the config + if not username: + username = headphones.BOXCAR_USERNAME + + if snatched_nzb: + title = "Headphones. Sucessfully Snatched!" + message = u"Headphones has snatched: " + snatched_nzb + " and has sent it to SABnzbd+" + else: + title = "Headphones. Successfully Downloaded & Post-Processed!" + message = u"Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']' + + logger.info("Sending notification to Boxcar") + + self._sendBoxcar(message, title, username) + return True + + diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 8e7dccb4..6ef7dd9e 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -462,6 +462,12 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, pushover = notifiers.PUSHOVER() pushover.notify(pushmessage,"Headphones") + if headphones.BOXCAR_ENABLED: + pushmessage = release['ArtistName'] + ' - ' + release['AlbumTitle'] + logger.info(u"Boxcar request") + boxcar = notifiers.BOXCAR() + boxcar.notify(artist=release['ArtistName'], album=release['AlbumTitle']) + if headphones.PUSHBULLET_ENABLED: pushmessage = release['ArtistName'] + ' - ' + release['AlbumTitle'] logger.info(u"PushBullet request") diff --git a/headphones/sab.py b/headphones/sab.py index 2bcbe2d2..0bdb584a 100644 --- a/headphones/sab.py +++ b/headphones/sab.py @@ -131,6 +131,10 @@ def sendNZB(nzb): logger.info(u"Sending Pushover notification") prowl = notifiers.PUSHOVER() prowl.notify(nzb.name,"Download started") + if headphones.BOXCAR_ENABLED and headphones.BOXCAR_ONSNATCH: + logger.info(u"Sending Boxcar notification") + boxcar = notifiers.BOXCAR() + boxcar.notify(snatched_nzb=nzb.name) if headphones.PUSHBULLET_ENABLED and headphones.PUSHBULLET_ONSNATCH: logger.info(u"Sending PushBullet notification") pushbullet = notifiers.PUSHBULLET() diff --git a/headphones/webserve.py b/headphones/webserve.py index 497ecd7b..b626b6c1 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -1053,6 +1053,9 @@ class WebInterface(object): "pushover_keys": headphones.PUSHOVER_KEYS, "pushover_apitoken": headphones.PUSHOVER_APITOKEN, "pushover_priority": headphones.PUSHOVER_PRIORITY, + "boxcar_enabled": helpers.checked(headphones.BOXCAR_ENABLED), + "boxcar_username": headphones.BOXCAR_USERNAME, + "boxcar_onsnatch": helpers.checked(headphones.BOXCAR_ONSNATCH), "pushbullet_enabled": checked(headphones.PUSHBULLET_ENABLED), "pushbullet_onsnatch": checked(headphones.PUSHBULLET_ONSNATCH), "pushbullet_apikey": headphones.PUSHBULLET_APIKEY, @@ -1105,7 +1108,7 @@ class WebInterface(object): bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0, delete_lossless_files=0, growl_enabled=0, growl_onsnatch=0, growl_host=None, growl_password=None, prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=0, xbmc_enabled=0, xbmc_host=None, xbmc_username=None, xbmc_password=None, xbmc_update=0, xbmc_notify=0, nma_enabled=False, nma_apikey=None, nma_priority=0, nma_onsnatch=0, pushalot_enabled=False, pushalot_apikey=None, pushalot_onsnatch=0, synoindex_enabled=False, lms_enabled=0, lms_host=None, - pushover_enabled=0, pushover_onsnatch=0, pushover_keys=None, pushover_priority=0, pushover_apitoken=None, pushbullet_enabled=0, pushbullet_onsnatch=0, pushbullet_apikey=None, pushbullet_deviceid=None, twitter_enabled=0, twitter_onsnatch=0, mirror=None, customhost=None, customport=None, + pushover_enabled=0, pushover_onsnatch=0, pushover_keys=None, pushover_priority=0, pushover_apitoken=None, boxcar_enabled=0, boxcar_username=None, boxcar_onsnatch=0, pushbullet_enabled=0, pushbullet_onsnatch=0, pushbullet_apikey=None, pushbullet_deviceid=None, twitter_enabled=0, twitter_onsnatch=0, mirror=None, customhost=None, customport=None, customsleep=None, hpuser=None, hppass=None, preferred_bitrate_high_buffer=None, preferred_bitrate_low_buffer=None, preferred_bitrate_allow_lossless=0, cache_sizemb=None, enable_https=0, https_cert=None, https_key=None, file_permissions=None, folder_permissions=None, plex_enabled=0, plex_server_host=None, plex_client_host=None, plex_username=None, plex_password=None, plex_update=0, plex_notify=0, songkick_enabled=0, songkick_apikey=None, songkick_location=None, songkick_filter_enabled=0, encoder_multicore=False, encoder_multicore_count=0, **kwargs): @@ -1258,6 +1261,9 @@ class WebInterface(object): headphones.PUSHOVER_KEYS = pushover_keys headphones.PUSHOVER_PRIORITY = pushover_priority headphones.PUSHOVER_APITOKEN = pushover_apitoken + headphones.BOXCAR_ENABLED = boxcar_enabled + headphones.BOXCAR_USERNAME = boxcar_username + headphones.BOXCAR_ONSNATCH = boxcar_onsnatch headphones.PUSHBULLET_ENABLED = pushbullet_enabled headphones.PUSHBULLET_ONSNATCH = pushbullet_onsnatch headphones.PUSHBULLET_APIKEY = pushbullet_apikey