diff --git a/data/interfaces/default/config_notifications.tmpl b/data/interfaces/default/config_notifications.tmpl index 24222ad182..b8c472058b 100644 --- a/data/interfaces/default/config_notifications.tmpl +++ b/data/interfaces/default/config_notifications.tmpl @@ -17,7 +17,7 @@
-

Home Theater

+

Home Theater / NAS


@@ -366,17 +366,18 @@
- -

Synology Indexer

+ +

Synology

+

The Synology DiskStation NAS.

Synology Indexer is the daemon running on the Synology NAS to build its media database.

+

Synology Notifier is the notification system of Synology DSM.

-
+
+ + +
+
+ + +
+
+ + +
+
Click below to test.
+ -
+
@@ -397,14 +421,14 @@

pyTivo

-

pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.

+

pyTivo is both an HMO and GoBack server. This notifier will load the completed downloads to your Tivo.

@@ -678,14 +702,14 @@

Boxcar

-

Read your messages where and when you want them! A subscription will be sent if needed.

+

Universal push notification for iOS. Read your messages where and when you want them! A subscription will be sent if needed.

@@ -792,7 +816,7 @@

-

Online

+

Social


diff --git a/data/js/configNotifications.js b/data/js/configNotifications.js index a97b339cb1..c23d689c3f 100644 --- a/data/js/configNotifications.js +++ b/data/js/configNotifications.js @@ -257,4 +257,15 @@ $(document).ready(function () { $("#testNMA").attr("disabled", false); }); }); + + $("#testSynoNotify").click(function () { + $(this).attr("disabled", true); + $("#testSynoNotify-result").html(loading); + $.get(sbRoot + "/home/testSynoNotify") + .done(function (data) { + $("#testSynoNotify-result").html(data); + $("#testSynoNotify").attr("disabled", false); + }); + }); + }); diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 2bcd0bd01e..0f9a634cae 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -58,7 +58,7 @@ CONFIG_FILE = None # this is the version of the config we EXPECT to find -CONFIG_VERSION = 5 +CONFIG_VERSION = 6 PROG_DIR = '.' MY_FULLNAME = None @@ -267,6 +267,9 @@ NMJ_MOUNT = None USE_SYNOINDEX = False +SYNOINDEX_NOTIFY_ONSNATCH = False +SYNOINDEX_NOTIFY_ONDOWNLOAD = False +SYNOINDEX_UPDATE_LIBRARY = False USE_NMJv2 = False NMJv2_HOST = None @@ -341,7 +344,8 @@ def initialize(consoleLogging=True): EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \ 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_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, USE_SYNOINDEX, \ + USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, \ + USE_SYNOINDEX, SYNOINDEX_NOTIFY_ONSNATCH, SYNOINDEX_NOTIFY_ONDOWNLOAD, SYNOINDEX_UPDATE_LIBRARY, \ USE_LISTVIEW, METADATA_XBMC, METADATA_XBMC_12PLUS, METADATA_MEDIABROWSER, METADATA_MEDE8ER, METADATA_PS3, metadata_provider_dict, \ GIT_PATH, MOVE_ASSOCIATED_FILES, \ COMING_EPS_LAYOUT, COMING_EPS_SORT, COMING_EPS_DISPLAY_PAUSED, METADATA_WDTV, METADATA_TIVO, IGNORE_WORDS, CREATE_MISSING_SHOW_DIRS, \ @@ -602,6 +606,9 @@ def initialize(consoleLogging=True): CheckSection(CFG, 'Synology') USE_SYNOINDEX = bool(check_setting_int(CFG, 'Synology', 'use_synoindex', 0)) + SYNOINDEX_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Synology', 'synoindex_notify_onsnatch', 0)) + SYNOINDEX_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Synology', 'synoindex_notify_ondownload', 0)) + SYNOINDEX_UPDATE_LIBRARY = bool(check_setting_int(CFG, 'Synology', 'synoindex_update_library', 0)) CheckSection(CFG, 'Trakt') USE_TRAKT = bool(check_setting_int(CFG, 'Trakt', 'use_trakt', 0)) @@ -1125,6 +1132,9 @@ def save_config(): new_config['Synology'] = {} new_config['Synology']['use_synoindex'] = int(USE_SYNOINDEX) + new_config['Synology']['synoindex_notify_onsnatch'] = int(SYNOINDEX_NOTIFY_ONSNATCH) + new_config['Synology']['synoindex_notify_ondownload'] = int(SYNOINDEX_NOTIFY_ONDOWNLOAD) + new_config['Synology']['synoindex_update_library'] = int(SYNOINDEX_UPDATE_LIBRARY) new_config['NMJv2'] = {} new_config['NMJv2']['use_nmjv2'] = int(USE_NMJv2) diff --git a/sickbeard/config.py b/sickbeard/config.py index 89acbac676..ad0035747a 100644 --- a/sickbeard/config.py +++ b/sickbeard/config.py @@ -645,3 +645,10 @@ def _migrate_metadata(metadata, metadata_name, use_banner): sickbeard.METADATA_WDTV = _migrate_metadata(metadata_wdtv, 'WDTV', use_banner) sickbeard.METADATA_TIVO = _migrate_metadata(metadata_tivo, 'TIVO', use_banner) sickbeard.METADATA_MEDE8ER = _migrate_metadata(metadata_mede8er, 'Mede8er', use_banner) + + # Migration v6: Synology notifier update + def _migrate_v6(self): + """ Updates Synology notifier to reflect that their now is an update library option instead misusing the enable option """ + + # clone use_synoindex to update_library since this now has notification options + sickbeard.SYNOINDEX_UPDATE_LIBRARY = bool(check_setting_int(self.config_obj, 'Synology', 'use_synoindex', 0)) diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index cc4e769c21..c65d7c4293 100755 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -36,13 +36,15 @@ import trakt from sickbeard.common import * +from sickbeard import logger +from sickbeard.exceptions import ex -# home theater +# home theater/nas xbmc_notifier = xbmc.XBMCNotifier() plex_notifier = plex.PLEXNotifier() nmj_notifier = nmj.NMJNotifier() -synoindex_notifier = synoindex.synoIndexNotifier() nmjv2_notifier = nmjv2.NMJv2Notifier() +synoindex_notifier = synoindex.synoIndexNotifier() pytivo_notifier = pytivo.pyTivoNotifier() # devices growl_notifier = growl.GrowlNotifier() @@ -51,12 +53,12 @@ pushover_notifier = pushover.PushoverNotifier() boxcar_notifier = boxcar.BoxcarNotifier() nma_notifier = nma.NMA_Notifier() -# online +# social twitter_notifier = tweet.TwitterNotifier() trakt_notifier = trakt.TraktNotifier() notifiers = [ - libnotify_notifier, # Libnotify notifier goes first because it doesn't involve blocking on network activity. + libnotify_notifier, # Libnotify notifier goes first because it doesn't involve blocking on network activity. xbmc_notifier, plex_notifier, nmj_notifier, @@ -75,14 +77,23 @@ def notify_download(ep_name): for n in notifiers: - n.notify_download(ep_name) + try: + n.notify_download(ep_name) + except Exception, e: + logger.log(n.__class__.__name__ + ": " + ex(e), logger.ERROR) def notify_snatch(ep_name): for n in notifiers: - n.notify_snatch(ep_name) + try: + n.notify_snatch(ep_name) + except Exception, e: + logger.log(n.__class__.__name__ + ": " + ex(e), logger.ERROR) def update_library(ep_obj): for n in notifiers: - n.update_library(ep_obj) + try: + n.update_library(ep_obj=ep_obj) + except Exception, e: + logger.log(n.__class__.__name__ + ": " + ex(e), logger.ERROR) diff --git a/sickbeard/notifiers/boxcar.py b/sickbeard/notifiers/boxcar.py index 474bac4d8f..315a4f5916 100644 --- a/sickbeard/notifiers/boxcar.py +++ b/sickbeard/notifiers/boxcar.py @@ -64,7 +64,6 @@ def _sendBoxcar(self, msg, title, email, subscribe=False): # send the request to boxcar try: - # TODO: Use our getURL from helper? req = urllib2.Request(curUrl) handle = urllib2.urlopen(req, data) handle.close() @@ -72,10 +71,10 @@ def _sendBoxcar(self, msg, title, email, subscribe=False): 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(u"BOXCAR: Boxcar notification failed." + ex(e), logger.ERROR) + logger.log(u"BOXCAR: Notification failed." + ex(e), logger.ERROR) return False else: - logger.log(u"BOXCAR: Boxcar notification failed. Error code: " + str(e.code), logger.WARNING) + logger.log(u"BOXCAR: Notification failed. Error code: " + str(e.code), logger.ERROR) # HTTP status 404 if the provided email address isn't a Boxcar user. if e.code == 404: @@ -103,10 +102,10 @@ def _sendBoxcar(self, msg, title, email, subscribe=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(u"BOXCAR: Wrong data send to boxcar.", logger.ERROR) + logger.log(u"BOXCAR: Wrong data sent to boxcar.", logger.ERROR) return False - logger.log(u"BOXCAR: Boxcar notification successful.", logger.DEBUG) + logger.log(u"BOXCAR: Notification successful.", logger.MESSAGE) return True def _notify(self, title, message, username=None, force=False): @@ -129,8 +128,7 @@ def _notify(self, title, message, username=None, force=False): logger.log(u"BOXCAR: Sending notification for " + message, logger.DEBUG) - self._sendBoxcar(message, title, username) - return True + return self._sendBoxcar(message, title, username) ############################################################################## # Public functions @@ -144,10 +142,10 @@ def notify_download(self, ep_name): if sickbeard.BOXCAR_NOTIFY_ONDOWNLOAD: self._notify(notifyStrings[NOTIFY_DOWNLOAD], ep_name) - def test_notify(self, email, title="Test"): - return self._sendBoxcar("This is a test notification from SickBeard", title, email) + def test_notify(self, boxcar_username): + return self._notify("This is a test notification from Sick Beard", "Test", boxcar_username, force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): pass notifier = BoxcarNotifier diff --git a/sickbeard/notifiers/growl.py b/sickbeard/notifiers/growl.py index 9d93bba727..e2b09b73ba 100644 --- a/sickbeard/notifiers/growl.py +++ b/sickbeard/notifiers/growl.py @@ -115,11 +115,11 @@ def _notify(self, title="Sick Beard Notification", message=None, name=None, host print pc opts['host'] = pc[0] opts['port'] = pc[1] - logger.log(u"GROWL: Sending message '" + message + "' to " + opts['host'] + ":" + str(opts['port'])) + logger.log(u"GROWL: Sending message '" + message + "' to " + opts['host'] + ":" + str(opts['port']), logger.DEBUG) try: return self._send_growl(opts, message) except Exception, e: - logger.log(u"GROWL: Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + " - " + ex(e)) + logger.log(u"GROWL: Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + " - " + ex(e), logger.WARNING) return False def _sendRegistration(self, host=None, password=None, name="Sick Beard Notification"): @@ -161,7 +161,7 @@ def _sendRegistration(self, host=None, password=None, name="Sick Beard Notificat try: return self._send(opts['host'], opts['port'], register.encode(), opts['debug']) except Exception, e: - logger.log(u"GROWL: Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + " - " + ex(e)) + logger.log(u"GROWL: Unable to send growl to " + opts['host'] + ":" + str(opts['port']) + " - " + ex(e), logger.WARNING) return False ############################################################################## @@ -183,7 +183,7 @@ def test_notify(self, host, password): else: return result - def update_library(self, showName=None): + def update_library(self, ep_obj=None): pass notifier = GrowlNotifier diff --git a/sickbeard/notifiers/libnotify.py b/sickbeard/notifiers/libnotify.py index d36c8fae0a..2071c07472 100644 --- a/sickbeard/notifiers/libnotify.py +++ b/sickbeard/notifiers/libnotify.py @@ -67,15 +67,15 @@ def init_pynotify(self): try: import pynotify except ImportError: - logger.log(u"LIBNOTIFY: Unable to import pynotify. libnotify notifications won't work.") + logger.log(u"LIBNOTIFY: Unable to import pynotify. libnotify notifications won't work.", logger.ERROR) return False try: import gobject except ImportError: - logger.log(u"LIBNOTIFY: Unable to import gobject. We can't catch a GError in display.") + logger.log(u"LIBNOTIFY: Unable to import gobject. We can't catch a GError in display.", logger.ERROR) return False if not pynotify.init('Sick Beard'): - logger.log(u"LIBNOTIFY: Initialization of pynotify failed. libnotify notifications won't work.") + logger.log(u"LIBNOTIFY: Initialization of pynotify failed. libnotify notifications won't work.", logger.ERROR) return False self.pynotify = pynotify self.gobject = gobject @@ -119,7 +119,7 @@ def notify_download(self, ep_name): def test_notify(self): return self._notify("Test notification", "This is a test notification from Sick Beard", force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): pass notifier = LibnotifyNotifier diff --git a/sickbeard/notifiers/nma.py b/sickbeard/notifiers/nma.py index ab9e4c2d5c..84c6f73875 100644 --- a/sickbeard/notifiers/nma.py +++ b/sickbeard/notifiers/nma.py @@ -1,3 +1,21 @@ +# Author: Adam Landry +# 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 sickbeard from sickbeard import logger, common @@ -8,7 +26,7 @@ class NMA_Notifier: def _sendNMA(self, nma_api=None, nma_priority=None, event=None, message=None, force=False): - title = "Sick-Beard" + title = "Sick Beard" # suppress notifications if the notifier is disabled but the notify options are checked if not sickbeard.USE_NMA and not force: @@ -20,10 +38,6 @@ def _sendNMA(self, nma_api=None, nma_priority=None, event=None, message=None, fo if nma_priority == None: nma_priority = sickbeard.NMA_PRIORITY - logger.log(u"NMA: title: " + title, logger.DEBUG) - logger.log(u"NMA: event: " + event, logger.DEBUG) - logger.log(u"NMA: message: " + message, logger.DEBUG) - batch = False p = pynma.PyNMA() @@ -33,12 +47,14 @@ def _sendNMA(self, nma_api=None, nma_priority=None, event=None, message=None, fo if len(keys) > 1: batch = True + logger.log("NMA: Sending notice with details: event=\"%s\", message=\"%s\", priority=%s, batch=%s" % (event, message, nma_priority, batch), logger.DEBUG) response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[nma_api][u'code'] == u'200': logger.log(u"NMA: Could not send notification to NotifyMyAndroid", logger.ERROR) return False else: + logger.log(u"NMA: Notification sent to NotifyMyAndroid", logger.MESSAGE) return True ############################################################################## @@ -56,7 +72,7 @@ def notify_download(self, ep_name): def test_notify(self, nma_api, nma_priority): return self._sendNMA(nma_api, nma_priority, event="Test", message="Testing NMA settings from Sick Beard", force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): pass notifier = NMA_Notifier diff --git a/sickbeard/notifiers/nmj.py b/sickbeard/notifiers/nmj.py index 2171103310..8c142ada81 100644 --- a/sickbeard/notifiers/nmj.py +++ b/sickbeard/notifiers/nmj.py @@ -23,6 +23,7 @@ import re from sickbeard import logger +from sickbeard.exceptions import ex try: import xml.etree.cElementTree as etree @@ -45,7 +46,7 @@ def notify_settings(self, host): try: terminal = telnetlib.Telnet(host) except Exception: - logger.log(u"NMJ: Warning: unable to get a telnet session to %s" % (host), logger.ERROR) + logger.log(u"NMJ: Unable to get a telnet session to %s" % (host), logger.WARNING) return False # tell the terminal to output the necessary info to the screen so we can search it later @@ -67,7 +68,7 @@ def notify_settings(self, host): logger.log(u"NMJ: Found NMJ database %s on device %s" % (database, device), logger.DEBUG) sickbeard.NMJ_DATABASE = database else: - logger.log(u"NMJ: Could not get current NMJ database on %s, NMJ is probably not running!" % (host), logger.ERROR) + logger.log(u"NMJ: Could not get current NMJ database on %s, NMJ is probably not running!" % (host), logger.WARNING) return False # if the device is a remote host then try to parse the mounting URL and save it to the config @@ -79,7 +80,7 @@ def notify_settings(self, host): logger.log(u"NMJ: Found mounting url on the Popcorn Hour in configuration: %s" % (mount), logger.DEBUG) sickbeard.NMJ_MOUNT = mount else: - logger.log(u"NMJ: Detected a network share on the Popcorn Hour, but could not get the mounting url", logger.DEBUG) + logger.log(u"NMJ: Detected a network share on the Popcorn Hour, but could not get the mounting url", logger.WARNING) return False return True @@ -98,12 +99,17 @@ def _sendNMJ(self, host, database, mount=None): # if a mount URL is provided then attempt to open a handle to that URL if mount: try: - # TODO: Use our getURL from helper? req = urllib2.Request(mount) logger.log(u"NMJ: Try to mount network drive via url: %s" % (mount), logger.DEBUG) handle = urllib2.urlopen(req) except IOError, e: - logger.log(u"NMJ: Warning: Couldn't contact Popcorn Hour on host %s: %s" % (host, e)) + if hasattr(e, 'reason'): + logger.log(u"NMJ: Could not contact Popcorn Hour on host %s: %s" % (host, e.reason), logger.WARNING) + elif hasattr(e, 'code'): + logger.log(u"NMJ: Problem with Popcorn Hour on host %s: %s" % (host, e.code), logger.WARNING) + return False + except Exception, e: + logger.log(u"NMJ: Unknown exception: " + ex(e), logger.ERROR) return False # build up the request URL and parameters @@ -112,19 +118,25 @@ def _sendNMJ(self, host, database, mount=None): "arg0": "scanner_start", "arg1": database, "arg2": "background", - "arg3": ""} + "arg3": "" + } params = urllib.urlencode(params) updateUrl = UPDATE_URL % {"host": host, "params": params} # send the request to the server try: - # TODO: Use our getURL from helper? req = urllib2.Request(updateUrl) logger.log(u"NMJ: Sending NMJ scan update command via url: %s" % (updateUrl), logger.DEBUG) handle = urllib2.urlopen(req) response = handle.read() except IOError, e: - logger.log(u"NMJ: Warning: Couldn't contact Popcorn Hour on host %s: %s" % (host, e)) + if hasattr(e, 'reason'): + logger.log(u"NMJ: Could not contact Popcorn Hour on host %s: %s" % (host, e.reason), logger.WARNING) + elif hasattr(e, 'code'): + logger.log(u"NMJ: Problem with Popcorn Hour on host %s: %s" % (host, e.code), logger.WARNING) + return False + except Exception, e: + logger.log(u"NMJ: Unknown exception: " + ex(e), logger.ERROR) return False # try to parse the resulting XML @@ -137,10 +149,10 @@ def _sendNMJ(self, host, database, mount=None): # if the result was a number then consider that an error if int(result) > 0: - logger.log(u"NMJ: Popcorn Hour returned an errorcode: %s" % (result)) + logger.log(u"NMJ: Popcorn Hour returned an errorcode: %s" % (result), logger.ERROR) return False else: - logger.log(u"NMJ: Started background scan.") + logger.log(u"NMJ: Started background scan.", logger.MESSAGE) return True def _notifyNMJ(self, host=None, database=None, mount=None, force=False): @@ -176,14 +188,12 @@ def notify_snatch(self, ep_name): pass def notify_download(self, ep_name): - # TODO: Drop this and use update_library - if sickbeard.USE_NMJ: - self._notifyNMJ() + pass def test_notify(self, host, database, mount): - return self._sendNMJ(host, database, mount) + return self._notifyNMJ(host, database, mount, force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): if sickbeard.USE_NMJ: self._notifyNMJ() diff --git a/sickbeard/notifiers/nmjv2.py b/sickbeard/notifiers/nmjv2.py index 679381ae39..1128946837 100644 --- a/sickbeard/notifiers/nmjv2.py +++ b/sickbeard/notifiers/nmjv2.py @@ -44,7 +44,6 @@ def notify_settings(self, host, dbloc, instance): """ try: url_loc = "http://" + host + ":8008/file_operation?arg0=list_user_storage_file&arg1=&arg2=" + instance + "&arg3=20&arg4=true&arg5=true&arg6=true&arg7=all&arg8=name_asc&arg9=false&arg10=false" - # TODO: Use our getURL from helper? req = urllib2.Request(url_loc) handle1 = urllib2.urlopen(req) response1 = handle1.read() @@ -71,7 +70,7 @@ def notify_settings(self, host, dbloc, instance): sickbeard.NMJv2_DATABASE = DB_path return True except IOError, e: - logger.log(u"NMJv2: Warning: Couldn't contact Popcorn Hour on host %s: %s" % (host, e)) + logger.log(u"NMJv2: Could not contact Popcorn Hour on host %s: %s" % (host, e), logger.WARNING) return False return False @@ -90,9 +89,9 @@ def _sendNMJ(self, host): #if a host is provided then attempt to open a handle to that URL try: url_scandir = "http://" + host + ":8008/metadata_database?arg0=update_scandir&arg1=" + sickbeard.NMJv2_DATABASE + "&arg2=&arg3=update_all" - logger.log(u"NMJv2 scan update command send to host: %s" % (host)) + logger.log(u"NMJv2: Scan update command send to host: %s" % (host), logger.DEBUG) url_updatedb = "http://" + host + ":8008/metadata_database?arg0=scanner_start&arg1=" + sickbeard.NMJv2_DATABASE + "&arg2=background&arg3=" - logger.log(u"Try to mount network drive via url: %s" % (host), logger.DEBUG) + logger.log(u"NMJv2: Try to mount network drive via url: %s" % (host), logger.DEBUG) prereq = urllib2.Request(url_scandir) req = urllib2.Request(url_updatedb) handle1 = urllib2.urlopen(prereq) @@ -101,7 +100,7 @@ def _sendNMJ(self, host): handle2 = urllib2.urlopen(req) response2 = handle2.read() except IOError, e: - logger.log(u"NMJv2: Warning: Couldn't contact Popcorn Hour on host %s: %s" % (host, e)) + logger.log(u"NMJv2: Could not contact Popcorn Hour on host %s: %s" % (host, e), logger.WARNING) return False try: @@ -130,15 +129,15 @@ def _sendNMJ(self, host): if int(result1) > 0: index = error_codes.index(result1) - logger.log(u"NMJv2: Popcorn Hour returned an error: %s" % (error_messages[index])) + logger.log(u"NMJv2: Popcorn Hour returned an error: %s" % (error_messages[index]), logger.ERROR) return False else: if int(result2) > 0: index = error_codes.index(result2) - logger.log(u"NMJv2: Popcorn Hour returned an error: %s" % (error_messages[index])) + logger.log(u"NMJv2: Popcorn Hour returned an error: %s" % (error_messages[index]), logger.ERROR) return False else: - logger.log(u"NMJv2: Started background scan.") + logger.log(u"NMJv2: Started background scan.", logger.MESSAGE) return True def _notifyNMJ(self, host=None, force=False): @@ -170,14 +169,12 @@ def notify_snatch(self, ep_name): pass def notify_download(self, ep_name): - # TODO: Drop this and use update_library - if sickbeard.USE_NMJv2: - self._notifyNMJ() + pass def test_notify(self, host): - return self._sendNMJ(host) + return self._notifyNMJ(host, force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): if sickbeard.USE_NMJv2: self._notifyNMJ() diff --git a/sickbeard/notifiers/plex.py b/sickbeard/notifiers/plex.py index e870a86102..18d87aa835 100644 --- a/sickbeard/notifiers/plex.py +++ b/sickbeard/notifiers/plex.py @@ -56,7 +56,7 @@ def _send_to_plex(self, command, host, username=None, password=None): password = sickbeard.PLEX_PASSWORD if not host: - logger.log(u"PLEX: No Plex host specified, check your settings", logger.DEBUG) + logger.log(u"PLEX: No host specified, check your settings", logger.ERROR) return False for key in command: @@ -64,7 +64,7 @@ def _send_to_plex(self, command, host, username=None, password=None): command[key] = command[key].encode('utf-8') enc_command = urllib.urlencode(command) - logger.log(u"PLEX: Plex encoded API command: " + enc_command, logger.DEBUG) + logger.log(u"PLEX: Encoded API command: " + enc_command, logger.DEBUG) url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command) try: @@ -74,17 +74,16 @@ def _send_to_plex(self, command, host, username=None, password=None): base64string = base64.encodestring('%s:%s' % (username, password))[:-1] authheader = "Basic %s" % base64string req.add_header("Authorization", authheader) - logger.log(u"PLEX: Contacting Plex (with auth header) via url: " + url, logger.DEBUG) + logger.log(u"PLEX: Contacting (with auth header) via url: " + url, logger.DEBUG) else: - logger.log(u"PLEX: Contacting Plex via url: " + url, logger.DEBUG) + logger.log(u"PLEX: Contacting via url: " + url, logger.DEBUG) - # TODO: Use our getURL from helper? response = urllib2.urlopen(req) result = response.read().decode(sickbeard.SYS_ENCODING) response.close() - logger.log(u"PLEX: Plex HTTP response: " + result.replace('\n', ''), logger.DEBUG) + logger.log(u"PLEX: HTTP response: " + result.replace('\n', ''), logger.DEBUG) # could return result response = re.compile('
  • (.+\w)').findall(result) return 'OK' @@ -101,7 +100,7 @@ def _notify(self, message, title="Sick Beard", host=None, username=None, passwor host: Plex Media Client(s) host:port username: Plex username password: Plex password - force: Used for the Test method to override config saftey checks + force: Used for the Test method to override config safety checks Returns: Returns a list results in the format of host:ip:result @@ -123,7 +122,7 @@ def _notify(self, message, title="Sick Beard", host=None, username=None, passwor result = '' for curHost in [x.strip() for x in host.split(",")]: - logger.log(u"PLEX: Sending Plex notification to '" + curHost + "' - " + message, logger.MESSAGE) + logger.log(u"PLEX: Sending notification to '" + curHost + "' - " + message, logger.MESSAGE) command = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + title.encode("utf-8") + ',' + message.encode("utf-8") + ')'} notifyResult = self._send_to_plex(command, curHost, username, password) @@ -147,7 +146,7 @@ def notify_download(self, ep_name): def test_notify(self, host, username, password): return self._notify("Testing Plex notifications from Sick Beard", "Test Notification", host, username, password, force=True) - def update_library(self): + def update_library(self, ep_obj=None): """Handles updating the Plex Media Server host via HTTP API Plex Media Server currently only supports updating the whole video library and not a specific path. @@ -159,14 +158,13 @@ def update_library(self): if sickbeard.USE_PLEX and sickbeard.PLEX_UPDATE_LIBRARY: if not sickbeard.PLEX_SERVER_HOST: - logger.log(u"PLEX: No Plex Server host specified, check your settings", logger.DEBUG) + logger.log(u"PLEX: No Plex Media Server host specified, check your settings", logger.DEBUG) return False logger.log(u"PLEX: Updating library for the Plex Media Server host: " + sickbeard.PLEX_SERVER_HOST, logger.MESSAGE) url = "http://%s/library/sections" % sickbeard.PLEX_SERVER_HOST try: - # TODO: Use our getURL from helper? xml_tree = etree.parse(urllib.urlopen(url)) media_container = xml_tree.getroot() except IOError, e: diff --git a/sickbeard/notifiers/prowl.py b/sickbeard/notifiers/prowl.py index 74cf9657ae..30d78ade5a 100644 --- a/sickbeard/notifiers/prowl.py +++ b/sickbeard/notifiers/prowl.py @@ -42,12 +42,7 @@ def _notify(self, prowl_api=None, prowl_priority=None, event=None, message=None, title = "Sick Beard" - # TODO: Consolidate this to one logging dict? - logger.log(u"PROWL: title: " + title, logger.DEBUG) - logger.log(u"PROWL: event: " + event, logger.DEBUG) - logger.log(u"PROWL: message: " + message, logger.DEBUG) - logger.log(u"PROWL: api: " + prowl_api, logger.DEBUG) - logger.log(u"PROWL: priority: " + prowl_priority, logger.DEBUG) + logger.log("PROWL: Sending notice with details: event=\"%s\", message=\"%s\", priority=%s, api=%s" % (event, message, prowl_priority, prowl_api), logger.DEBUG) try: @@ -74,7 +69,7 @@ def _notify(self, prowl_api=None, prowl_priority=None, event=None, message=None, return False if request_status == 200: - logger.log(u"PROWL: Notifications sent.", logger.DEBUG) + logger.log(u"PROWL: Notifications sent.", logger.MESSAGE) return True elif request_status == 401: logger.log(u"PROWL: Auth failed: %s" % response.reason, logger.ERROR) @@ -98,7 +93,7 @@ def notify_download(self, ep_name): def test_notify(self, prowl_api, prowl_priority): return self._notify(prowl_api, prowl_priority, event="Test", message="Testing Prowl settings from Sick Beard", force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): pass notifier = ProwlNotifier diff --git a/sickbeard/notifiers/pushover.py b/sickbeard/notifiers/pushover.py index 386a194d7f..7ff796f18b 100644 --- a/sickbeard/notifiers/pushover.py +++ b/sickbeard/notifiers/pushover.py @@ -62,7 +62,6 @@ def _sendPushover(self, msg, title, userKey=None): # send the request to pushover try: - # TODO: Use our getURL from helper? req = urllib2.Request(curUrl) handle = urllib2.urlopen(req, data) handle.close() @@ -73,7 +72,7 @@ def _sendPushover(self, msg, title, userKey=None): logger.log(u"PUSHOVER: Notification failed." + ex(e), logger.ERROR) return False else: - logger.log(u"PUSHOVER: Notification failed. Error code: " + str(e.code), logger.WARNING) + logger.log(u"PUSHOVER: Notification failed. Error code: " + str(e.code), logger.ERROR) # HTTP status 404 if the provided email address isn't a Pushover user. if e.code == 404: @@ -97,10 +96,10 @@ def _sendPushover(self, msg, title, userKey=None): logger.log(u"PUSHOVER: Wrong data sent to Pushover", logger.ERROR) return False - logger.log(u"PUSHOVER: Notification successful.", logger.DEBUG) + logger.log(u"PUSHOVER: Notification successful.", logger.MESSAGE) return True - def _notify(self, title, message, userKey=None ): + def _notify(self, title, message, userKey=None, force=False): """ Sends a pushover notification based on the provided info or SB config @@ -110,7 +109,7 @@ def _notify(self, title, message, userKey=None ): """ # suppress notifications if the notifier is disabled but the notify options are checked - if not sickbeard.USE_PUSHOVER: + if not sickbeard.USE_PUSHOVER and not force: return False # fill in omitted parameters @@ -119,8 +118,7 @@ def _notify(self, title, message, userKey=None ): logger.log(u"PUSHOVER: Sending notification for " + message, logger.DEBUG) - self._sendPushover(message, title) - return True + return self._sendPushover(message, title) ############################################################################## # Public functions @@ -135,9 +133,9 @@ def notify_download(self, ep_name): self._notify(notifyStrings[NOTIFY_DOWNLOAD], ep_name) def test_notify(self, userKey=None): - return self._sendPushover("This is a test notification from SickBeard", 'Test', userKey) + return self._notify("This is a test notification from Sick Beard", "Test", userKey, force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None): pass notifier = PushoverNotifier diff --git a/sickbeard/notifiers/pytivo.py b/sickbeard/notifiers/pytivo.py index 6172fa2f3b..5c3446dd4d 100644 --- a/sickbeard/notifiers/pytivo.py +++ b/sickbeard/notifiers/pytivo.py @@ -20,9 +20,10 @@ import sickbeard from urllib import urlencode -from urllib2 import Request, urlopen, URLError +from urllib2 import Request, urlopen from sickbeard import logger +from sickbeard.exceptions import ex from sickbeard import encodingKludge as ek @@ -38,7 +39,7 @@ def notify_snatch(self, ep_name): def notify_download(self, ep_name): pass - def update_library(self, ep_obj): + def update_library(self, ep_obj=None): if not sickbeard.USE_PYTIVO: return False @@ -74,22 +75,23 @@ def update_library(self, ep_obj): # Finally create the url and make request requestUrl = "http://" + host + "/TiVoConnect?" + urlencode( {'Command': 'Push', 'Container': container, 'File': mediaFile, 'tsn': tsn}) - logger.log(u"PYTIVO: Requesting " + requestUrl) + logger.log(u"PYTIVO: Requesting " + requestUrl, logger.DEBUG) - # TODO: Use our getURL from helper? - request = Request( requestUrl ) + request = Request(requestUrl) try: response = urlopen(request) # @UnusedVariable - except URLError, e: + except IOError, e: if hasattr(e, 'reason'): - logger.log(u"PYTIVO: Error, failed to reach a server - " + str(e.reason)) - return False + logger.log(u"PYTIVO: Failed to reach server '%s' - %s" % (host, e.reason), logger.WARNING) elif hasattr(e, 'code'): - logger.log(u"PYTIVO: Error, the server couldn't fulfill the request - " + str(e.code)) - return False + logger.log(u"PYTIVO: The server could not fulfill the request '%s' - %s" % (host, e.code), logger.WARNING) + return False + except Exception, e: + logger.log(u"PYTIVO: Unknown exception: " + ex(e), logger.ERROR) + return False else: - logger.log(u"PYTIVO: Successfully requested transfer of file") + logger.log(u"PYTIVO: Successfully requested transfer of file", logger.MESSAGE) return True notifier = pyTivoNotifier diff --git a/sickbeard/notifiers/synoindex.py b/sickbeard/notifiers/synoindex.py index 3edcefd2dd..7daaea6769 100755 --- a/sickbeard/notifiers/synoindex.py +++ b/sickbeard/notifiers/synoindex.py @@ -22,6 +22,7 @@ import sickbeard from sickbeard import logger +from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD from sickbeard import encodingKludge as ek from sickbeard.exceptions import ex @@ -37,14 +38,14 @@ def moveFile(self, old_file, new_file): def moveObject(self, old_path, new_path): if sickbeard.USE_SYNOINDEX: synoindex_cmd = ['/usr/syno/bin/synoindex', '-N', ek.ek(os.path.abspath, new_path), ek.ek(os.path.abspath, old_path)] - logger.log(u"SYNOINDEX: Executing command " + str(synoindex_cmd)) + logger.log(u"SYNOINDEX: Executing command " + str(synoindex_cmd), logger.DEBUG) logger.log(u"SYNOINDEX: Absolute path to command: " + ek.ek(os.path.abspath, synoindex_cmd[0]), logger.DEBUG) try: p = subprocess.Popen(synoindex_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=sickbeard.PROG_DIR) out, err = p.communicate() # @UnusedVariable logger.log(u"SYNOINDEX: Script result: " + str(out), logger.DEBUG) except OSError, e: - logger.log(u"SYNOINDEX: Unable to run synoindex: " + ex(e)) + logger.log(u"SYNOINDEX: Unable to run synoindex: " + ex(e), logger.WARNING) def deleteFolder(self, cur_path): self.makeObject('-D', cur_path) @@ -61,23 +62,58 @@ def addFile(self, cur_file): def makeObject(self, cmd_arg, cur_path): if sickbeard.USE_SYNOINDEX: synoindex_cmd = ['/usr/syno/bin/synoindex', cmd_arg, ek.ek(os.path.abspath, cur_path)] - logger.log(u"SYNOINDEX: Executing command " + str(synoindex_cmd)) + logger.log(u"SYNOINDEX: Executing command " + str(synoindex_cmd), logger.DEBUG) logger.log(u"SYNOINDEX: Absolute path to command: " + ek.ek(os.path.abspath, synoindex_cmd[0]), logger.DEBUG) try: p = subprocess.Popen(synoindex_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=sickbeard.PROG_DIR) out, err = p.communicate() # @UnusedVariable logger.log(u"SYNOINDEX: Script result: " + str(out), logger.DEBUG) except OSError, e: - logger.log(u"SYNOINDEX: Unable to run synoindex: " + ex(e)) + logger.log(u"SYNOINDEX: Unable to run synoindex: " + ex(e), logger.WARNING) + + def _notify(self, message, title, force=False): + # suppress notifications if the notifier is disabled but the notify options are checked + if not sickbeard.USE_SYNOINDEX and not force: + return False + + synodsmnotify_cmd = ['/usr/syno/bin/synodsmnotify', '@administrators', title, message] + logger.log(u"SYNOINDEX: Executing command " + str(synodsmnotify_cmd), logger.DEBUG) + + try: + p = subprocess.Popen(synodsmnotify_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + cwd=sickbeard.PROG_DIR) + + output, err = p.communicate() # @UnusedVariable + exit_status = p.returncode + + logger.log(u"SYNOINDEX: Script result: " + str(output), logger.DEBUG) + + if exit_status == 0: + return True + else: + return False + + except OSError, e: + logger.log(u"SYNOINDEX: Unable to run synodsmnotify: " + ex(e), logger.WARNING) + return False ############################################################################## # Public functions ############################################################################## def notify_snatch(self, ep_name): - pass + if sickbeard.SYNOINDEX_NOTIFY_ONSNATCH: + self._notify(notifyStrings[NOTIFY_SNATCH], ep_name) def notify_download(self, ep_name): - pass + if sickbeard.SYNOINDEX_NOTIFY_ONDOWNLOAD: + self._notify(notifyStrings[NOTIFY_DOWNLOAD], ep_name) + + def test_notify(self): + return self._notify("This is a test notification from Sick Beard", "Test", force=True) + + def update_library(self, ep_obj=None): + if sickbeard.USE_SYNOINDEX: + self.addFile(ep_obj.location) notifier = synoIndexNotifier diff --git a/sickbeard/notifiers/trakt.py b/sickbeard/notifiers/trakt.py index 45cbed60f7..1d51366d17 100644 --- a/sickbeard/notifiers/trakt.py +++ b/sickbeard/notifiers/trakt.py @@ -32,7 +32,7 @@ class TraktNotifier: - def _notifyTrakt(self, method, api, username, password, data={}): + def _notifyTrakt(self, method, api, username, password, data={}, force=False): """ A generic method for communicating with trakt. Uses the method and data provided along with the auth info to send the command. @@ -44,6 +44,10 @@ def _notifyTrakt(self, method, api, username, password, data={}): Returns: A boolean representing success """ + # suppress notifications if the notifier is disabled but the notify options are checked + if not sickbeard.USE_TRAKT and not force: + return False + logger.log(u"TRAKT: Calling method " + method, logger.DEBUG) # if the API isn't given then use the config API @@ -71,7 +75,6 @@ def _notifyTrakt(self, method, api, username, password, data={}): # request the URL from trakt and parse the result as json try: logger.log(u"TRAKT: Calling method http://api.trakt.tv/" + method + ", with data" + encoded_data, logger.DEBUG) - # TODO: Use our getURL from helper? stream = urllib2.urlopen("http://api.trakt.tv/" + method, encoded_data) resp = stream.read() @@ -85,7 +88,7 @@ def _notifyTrakt(self, method, api, username, password, data={}): return False if (resp["status"] == "success"): - logger.log(u"TRAKT: Succeeded calling method. Result: " + resp["message"], logger.DEBUG) + logger.log(u"TRAKT: Succeeded calling method. Result: " + resp["message"], logger.MESSAGE) return True logger.log(u"TRAKT: Failed calling method", logger.ERROR) @@ -114,9 +117,9 @@ def test_notify(self, api, username, password): """ method = "account/test/" - return self._notifyTrakt(method, api, username, password, {}) + return self._notifyTrakt(method, api, username, password, {}, force=True) - def update_library(self, ep_obj): + def update_library(self, ep_obj=None): """ Sends a request to trakt indicating that the given episode is part of our library. diff --git a/sickbeard/notifiers/tweet.py b/sickbeard/notifiers/tweet.py index 68f2ea2d4d..b243c09a62 100644 --- a/sickbeard/notifiers/tweet.py +++ b/sickbeard/notifiers/tweet.py @@ -47,12 +47,12 @@ def _get_authorization(self): oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) oauth_client = oauth.Client(oauth_consumer) - logger.log(u'TWITTER: Requesting temp token from Twitter') + logger.log(u'TWITTER: Requesting temp token from Twitter', logger.DEBUG) resp, content = oauth_client.request(self.REQUEST_TOKEN_URL, 'GET') if resp['status'] != '200': - logger.log(u"TWITTER: Invalid respond from Twitter requesting temp token: %s" % resp['status']) + logger.log(u"TWITTER: Invalid respond from Twitter requesting temp token: %s" % resp['status'], logger.ERROR) else: request_token = dict(parse_qsl(content)) @@ -71,26 +71,26 @@ def _get_credentials(self, key): token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret']) token.set_verifier(key) - logger.log(u"TWITTER: Generating and signing request for an access token using key " + key) + logger.log(u"TWITTER: Generating and signing request for an access token using key " + key, logger.DEBUG) signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1() # @UnusedVariable oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) - logger.log(u"TWITTER: oauth_consumer: " + str(oauth_consumer)) + logger.log(u"TWITTER: oauth_consumer: " + str(oauth_consumer), logger.DEBUG) oauth_client = oauth.Client(oauth_consumer, token) - logger.log(u"TWITTER: oauth_client: " + str(oauth_client)) + logger.log(u"TWITTER: oauth_client: " + str(oauth_client), logger.DEBUG) resp, content = oauth_client.request(self.ACCESS_TOKEN_URL, method='POST', body='oauth_verifier=%s' % key) - logger.log(u"TWITTER: resp, content: " + str(resp) + "," + str(content)) + logger.log(u"TWITTER: resp, content: " + str(resp) + "," + str(content), logger.DEBUG) access_token = dict(parse_qsl(content)) - logger.log(u"TWITTER: access_token: " + str(access_token)) + logger.log(u"TWITTER: access_token: " + str(access_token), logger.DEBUG) - logger.log(u"TWITTER: resp[status] = " + str(resp['status'])) + logger.log(u"TWITTER: resp[status] = " + str(resp['status']), logger.DEBUG) if resp['status'] != '200': logger.log(u"TWITTER: The request for a token with did not succeed: " + str(resp['status']), logger.ERROR) return False else: - logger.log(u"TWITTER: Your Twitter Access Token key: %s" % access_token['oauth_token']) - logger.log(u"TWITTER: Access Token secret: %s" % access_token['oauth_token_secret']) + logger.log(u"TWITTER: Your Twitter Access Token key: %s" % access_token['oauth_token'], logger.DEBUG) + logger.log(u"TWITTER: Access Token secret: %s" % access_token['oauth_token_secret'], logger.DEBUG) sickbeard.TWITTER_USERNAME = access_token['oauth_token'] sickbeard.TWITTER_PASSWORD = access_token['oauth_token_secret'] return True @@ -102,7 +102,7 @@ def _send_tweet(self, message=None): access_token_key = sickbeard.TWITTER_USERNAME access_token_secret = sickbeard.TWITTER_PASSWORD - logger.log(u"TWITTER: Sending tweet: " + message) + logger.log(u"TWITTER: Sending tweet: " + message, logger.DEBUG) api = twitter.Api(username, password, access_token_key, access_token_secret) @@ -136,7 +136,7 @@ def notify_download(self, ep_name): def test_notify(self): return self._notify("This is a test notification from Sick Beard", force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj): pass notifier = TwitterNotifier diff --git a/sickbeard/notifiers/xbmc.py b/sickbeard/notifiers/xbmc.py index 3488a35c67..21c713803a 100644 --- a/sickbeard/notifiers/xbmc.py +++ b/sickbeard/notifiers/xbmc.py @@ -67,7 +67,7 @@ def _get_xbmc_version(self, host, username, password): 3 | (pre Eden) 4 | v11 (Eden) 5 | (pre Frodo) - 6 | v12 (Frodo) + 6 | v12 (Frodo) / v13 (Gotham) """ @@ -174,7 +174,7 @@ def _send_to_xbmc(self, command, host=None, username=None, password=None): password = sickbeard.XBMC_PASSWORD if not host: - logger.log(u"XBMC: No XBMC host passed, aborting update", logger.DEBUG) + logger.log(u"XBMC: No host specified, check your settings", logger.DEBUG) return False for key in command: @@ -182,7 +182,7 @@ def _send_to_xbmc(self, command, host=None, username=None, password=None): command[key] = command[key].encode('utf-8') enc_command = urllib.urlencode(command) - logger.log(u"XBMC: XBMC encoded API command: " + enc_command, logger.DEBUG) + logger.log(u"XBMC: Encoded API command: " + enc_command, logger.DEBUG) url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command) try: @@ -197,11 +197,11 @@ def _send_to_xbmc(self, command, host=None, username=None, password=None): result = response.read().decode(sickbeard.SYS_ENCODING) response.close() - logger.log(u"XBMC: XBMC HTTP response: " + result.replace('\n', ''), logger.DEBUG) + logger.log(u"XBMC: HTTP response: " + result.replace('\n', ''), logger.DEBUG) return result except (urllib2.URLError, IOError), e: - logger.log(u"XBMC: Warning: Couldn't contact XBMC HTTP at " + fixStupidEncodings(url) + " " + ex(e), logger.WARNING) + logger.log(u"XBMC: Could not contact XBMC HTTP at " + fixStupidEncodings(url) + " " + ex(e), logger.WARNING) return False def _update_library(self, host=None, showName=None): @@ -220,14 +220,12 @@ def _update_library(self, host=None, showName=None): """ if not host: - logger.log(u"XBMC: No XBMC host passed, aborting update", logger.DEBUG) + logger.log(u"XBMC: No host specified, check your settings", logger.DEBUG) return False - logger.log(u"XBMC: Updating XBMC library via HTTP method for host: " + host, logger.DEBUG) - # if we're doing per-show if showName: - logger.log(u"XBMC: Updating library in XBMC via HTTP method for show " + showName, logger.DEBUG) + logger.log(u"XBMC: Updating library via HTTP method for show " + showName, logger.MESSAGE) pathSql = 'select path.strPath from path, tvshow, tvshowlinkpath where ' \ 'tvshow.c00 = "%s" and tvshowlinkpath.idShow = tvshow.idShow ' \ @@ -268,23 +266,23 @@ def _update_library(self, host=None, showName=None): for path in paths: # we do not need it double-encoded, gawd this is dumb unEncPath = urllib.unquote(path.text).decode(sickbeard.SYS_ENCODING) - logger.log(u"XBMC: XBMC Updating " + showName + " on " + host + " at " + unEncPath, logger.MESSAGE) + logger.log(u"XBMC: Updating " + showName + " on " + host + " at " + unEncPath, logger.MESSAGE) updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video, %s)' % (unEncPath)} request = self._send_to_xbmc(updateCommand, host) if not request: - logger.log(u"XBMC: Update of show directory failed on " + showName + " on " + host + " at " + unEncPath, logger.ERROR) + logger.log(u"XBMC: Update of show directory failed on " + showName + " on " + host + " at " + unEncPath, logger.WARNING) return False # sleep for a few seconds just to be sure xbmc has a chance to finish each directory if len(paths) > 1: time.sleep(5) # do a full update if requested else: - logger.log(u"XBMC: Doing Full Library XBMC update on host: " + host, logger.DEBUG) + logger.log(u"XBMC: Doing Full Library update via HTTP method for host: " + host, logger.MESSAGE) updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'} request = self._send_to_xbmc(updateCommand, host) if not request: - logger.log(u"XBMC: XBMC Full Library update failed on: " + host, logger.ERROR) + logger.log(u"XBMC: Full Library update failed on: " + host, logger.ERROR) return False return True @@ -314,11 +312,11 @@ def _send_to_xbmc_json(self, command, host=None, username=None, password=None): password = sickbeard.XBMC_PASSWORD if not host: - logger.log(u"XBMC: No XBMC host passed, aborting update", logger.DEBUG) + logger.log(u"XBMC: No host specified, check your settings", logger.DEBUG) return False command = command.encode('utf-8') - logger.log(u"XBMC: XBMC JSON command: " + command, logger.DEBUG) + logger.log(u"XBMC: JSON command: " + command, logger.DEBUG) url = 'http://%s/jsonrpc' % (host) try: @@ -340,14 +338,14 @@ def _send_to_xbmc_json(self, command, host=None, username=None, password=None): try: result = json.load(response) response.close() - logger.log(u"XBMC: XBMC JSON response: " + str(result), logger.DEBUG) + logger.log(u"XBMC: JSON response: " + str(result), logger.DEBUG) return result # need to return response for parsing except ValueError, e: logger.log(u"XBMC: Unable to decode JSON: " + response, logger.WARNING) return False except IOError, e: - logger.log(u"XBMC: Warning: Couldn't contact XBMC JSON API at " + fixStupidEncodings(url) + " " + ex(e), logger.WARNING) + logger.log(u"XBMC: Could not contact XBMC JSON API at " + fixStupidEncodings(url) + " " + ex(e), logger.WARNING) return False def _update_library_json(self, host=None, showName=None): @@ -366,15 +364,13 @@ def _update_library_json(self, host=None, showName=None): """ if not host: - logger.log(u"XBMC: No XBMC host passed, aborting update", logger.DEBUG) + logger.log(u"XBMC: No host specified, check your settings", logger.DEBUG) return False - logger.log(u"XBMC: Updating XBMC library via JSON method for host: " + host, logger.MESSAGE) - # if we're doing per-show if showName: tvshowid = -1 - logger.log(u"XBMC: Updating library in XBMC via JSON method for show " + showName, logger.DEBUG) + logger.log(u"XBMC: Updating library via JSON method for show " + showName, logger.MESSAGE) # get tvshowid by showName showsCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShows","id":1}' @@ -410,11 +406,11 @@ def _update_library_json(self, host=None, showName=None): logger.log(u"XBMC: No valid path found for " + showName + " with ID: " + str(tvshowid) + " on " + host, logger.WARNING) return False - logger.log(u"XBMC: XBMC Updating " + showName + " on " + host + " at " + path, logger.MESSAGE) + logger.log(u"XBMC: Updating " + showName + " on " + host + " at " + path, logger.MESSAGE) updateCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.Scan","params":{"directory":%s},"id":1}' % (json.dumps(path)) request = self._send_to_xbmc_json(updateCommand, host) if not request: - logger.log(u"XBMC: Update of show directory failed on " + showName + " on " + host + " at " + path, logger.ERROR) + logger.log(u"XBMC: Update of show directory failed on " + showName + " on " + host + " at " + path, logger.WARNING) return False # catch if there was an error in the returned request @@ -425,12 +421,12 @@ def _update_library_json(self, host=None, showName=None): # do a full update if requested else: - logger.log(u"XBMC: Doing Full Library XBMC update on host: " + host, logger.MESSAGE) + logger.log(u"XBMC: Doing Full Library update via JSON method for host: " + host, logger.MESSAGE) updateCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.Scan","id":1}' request = self._send_to_xbmc_json(updateCommand, host, sickbeard.XBMC_USERNAME, sickbeard.XBMC_PASSWORD) if not request: - logger.log(u"XBMC: XBMC Full Library update failed on: " + host, logger.ERROR) + logger.log(u"XBMC: Full Library update failed on: " + host, logger.ERROR) return False return True @@ -450,7 +446,7 @@ def notify_download(self, ep_name): def test_notify(self, host, username, password): return self._notify("Testing XBMC notifications from Sick Beard", "Test Notification", host, username, password, force=True) - def update_library(self, showName=None): + def update_library(self, ep_obj=None, show_obj=None): """Public wrapper for the update library functions to branch the logic for JSON-RPC or legacy HTTP API Checks the XBMC API version to branch the logic to call either the legacy HTTP API or the newer JSON-RPC over HTTP methods. @@ -466,9 +462,16 @@ def update_library(self, showName=None): """ + if ep_obj: + showName = ep_obj.show.name + elif show_obj: + showName = show_obj.name + else: + showName = None + if sickbeard.USE_XBMC and sickbeard.XBMC_UPDATE_LIBRARY: if not sickbeard.XBMC_HOST: - logger.log(u"XBMC: No XBMC hosts specified, check your settings", logger.DEBUG) + logger.log(u"XBMC: No host specified, check your settings", logger.DEBUG) return False if sickbeard.XBMC_UPDATE_ONLYFIRST: @@ -479,26 +482,20 @@ def update_library(self, showName=None): result = 0 for curHost in [x.strip() for x in host.split(",")]: - logger.log(u"XBMC: Sending request to update library for XBMC host: '" + curHost + "'", logger.MESSAGE) + logger.log(u"XBMC: Sending request to update library for host: '" + curHost + "'", logger.MESSAGE) xbmcapi = self._get_xbmc_version(curHost, sickbeard.XBMC_USERNAME, sickbeard.XBMC_PASSWORD) if xbmcapi: if (xbmcapi <= 4): # try to update for just the show, if it fails, do full update if enabled if not self._update_library(curHost, showName): - if showName: - logger.log(u"XBMC: XBMC single show update failed", logger.WARNING) - if sickbeard.XBMC_UPDATE_FULL: - logger.log(u"XBMC: Falling back to XBMC full update") - self._update_library(curHost) + if showName and sickbeard.XBMC_UPDATE_FULL: + self._update_library(curHost) else: # try to update for just the show, if it fails, do full update if enabled if not self._update_library_json(curHost, showName): - if showName: - logger.log(u"XBMC: XBMC single show update failed", logger.WARNING) - if sickbeard.XBMC_UPDATE_FULL: - logger.log(u"XBMC: Falling back to XBMC full update") - self._update_library_json(curHost) + if showName and sickbeard.XBMC_UPDATE_FULL: + self._update_library_json(curHost) else: if sickbeard.XBMC_ALWAYS_ON: logger.log(u"XBMC: Failed to detect XBMC version for '" + curHost + "', check configuration and try again.", logger.ERROR) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index a2969edabc..8ec0368b7a 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -862,30 +862,15 @@ def process(self): # log it to history history.logDownload(ep_obj, self.file_path, new_ep_quality, self.release_group) - # send notifications + # send notifiers download notification notifiers.notify_download(ep_obj.prettyName()) # generate nfo/tbn ep_obj.createMetaFiles() ep_obj.saveToDB() - # do the library update for XBMC - notifiers.xbmc_notifier.update_library(ep_obj.show.name) - - # do the library update for Plex - notifiers.plex_notifier.update_library() - - # do the library update for NMJ - # nmj_notifier kicks off its library update when the notify_download is issued (inside notifiers) - - # do the library update for Synology Indexer - notifiers.synoindex_notifier.addFile(ep_obj.location) - - # do the library update for pyTivo - notifiers.pytivo_notifier.update_library(ep_obj) - - # do the library update for Trakt - notifiers.trakt_notifier.update_library(ep_obj) + # send notifiers library update + notifiers.update_library(ep_obj) self._run_extra_scripts(ep_obj) diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 37c502ef00..ef640944da 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1084,26 +1084,28 @@ def index(self): return _munge(t) @cherrypy.expose - def saveNotifications(self, use_xbmc=None, xbmc_always_on=None, xbmc_notify_onsnatch=None, xbmc_notify_ondownload=None, xbmc_update_onlyfirst=None, - xbmc_update_library=None, xbmc_update_full=None, xbmc_host=None, xbmc_username=None, xbmc_password=None, + def saveNotifications(self, + use_xbmc=None, xbmc_always_on=None, xbmc_notify_onsnatch=None, xbmc_notify_ondownload=None, xbmc_update_onlyfirst=None, + xbmc_update_library=None, xbmc_update_full=None, xbmc_host=None, xbmc_username=None, xbmc_password=None, use_plex=None, plex_notify_onsnatch=None, plex_notify_ondownload=None, plex_update_library=None, - plex_server_host=None, plex_host=None, plex_username=None, plex_password=None, + plex_server_host=None, plex_host=None, plex_username=None, plex_password=None, use_growl=None, growl_notify_onsnatch=None, growl_notify_ondownload=None, growl_host=None, growl_password=None, use_prowl=None, prowl_notify_onsnatch=None, prowl_notify_ondownload=None, prowl_api=None, prowl_priority=0, use_twitter=None, twitter_notify_onsnatch=None, twitter_notify_ondownload=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_nmj=None, nmj_host=None, nmj_database=None, nmj_mount=None, + use_synoindex=None, synoindex_notify_onsnatch=None, synoindex_notify_ondownload=None, synoindex_update_library=None, use_nmjv2=None, nmjv2_host=None, nmjv2_dbloc=None, nmjv2_database=None, use_trakt=None, trakt_username=None, trakt_password=None, trakt_api=None, use_pytivo=None, pytivo_notify_onsnatch=None, pytivo_notify_ondownload=None, pytivo_update_library=None, - pytivo_host=None, pytivo_share_name=None, pytivo_tivo_name=None, + pytivo_host=None, pytivo_share_name=None, pytivo_tivo_name=None, use_nma=None, nma_notify_onsnatch=None, nma_notify_ondownload=None, nma_api=None, nma_priority=0): results = [] - # Home Theater + # Home Theater / NAS sickbeard.USE_XBMC = config.checkbox_to_value(use_xbmc) sickbeard.XBMC_ALWAYS_ON = config.checkbox_to_value(xbmc_always_on) sickbeard.XBMC_NOTIFY_ONSNATCH = config.checkbox_to_value(xbmc_notify_onsnatch) @@ -1135,6 +1137,9 @@ def saveNotifications(self, use_xbmc=None, xbmc_always_on=None, xbmc_notify_onsn sickbeard.NMJv2_DBLOC = nmjv2_dbloc sickbeard.USE_SYNOINDEX = config.checkbox_to_value(use_synoindex) + sickbeard.SYNOINDEX_NOTIFY_ONSNATCH = config.checkbox_to_value(synoindex_notify_onsnatch) + sickbeard.SYNOINDEX_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(synoindex_notify_ondownload) + sickbeard.SYNOINDEX_UPDATE_LIBRARY = config.checkbox_to_value(synoindex_update_library) sickbeard.USE_PYTIVO = config.checkbox_to_value(use_pytivo) # sickbeard.PYTIVO_NOTIFY_ONSNATCH = config.checkbox_to_value(pytivo_notify_onsnatch) @@ -2024,6 +2029,16 @@ def testNMA(self, nma_api=None, nma_priority=0): else: return "Test NMA notice failed" + @cherrypy.expose + def testSynoNotify(self): + cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" + + result = notifiers.synoindex_notifier.test_notify() + if result: + return "Test Synology notice sent successfully" + else: + return "Test Synology notice failed" + @cherrypy.expose def shutdown(self, pid=None): @@ -2120,7 +2135,7 @@ def displayShow(self, show=None): t.submenu.append({ 'title': 'Delete', 'path': 'home/deleteShow?show=%d' % showObj.tvdbid, 'confirm': True }) t.submenu.append({ 'title': 'Re-scan files', 'path': 'home/refreshShow?show=%d' % showObj.tvdbid }) t.submenu.append({ 'title': 'Force Full Update', 'path': 'home/updateShow?show=%d&force=1' % showObj.tvdbid }) - t.submenu.append({ 'title': 'Update show in XBMC', 'path': 'home/updateXBMC?showName=%s' % urllib.quote_plus(showObj.name.encode('utf-8')), 'requires': haveXBMC }) + t.submenu.append({ 'title': 'Update show in XBMC', 'path': 'home/updateXBMC?show=%d' % showObj.tvdbid, 'requires': haveXBMC }) t.submenu.append({ 'title': 'Preview Rename', 'path': 'home/testRename?show=%d' % showObj.tvdbid }) t.show = showObj @@ -2338,14 +2353,19 @@ def updateShow(self, show=None, force=0): redirect("/home/displayShow?show=" + str(showObj.tvdbid)) @cherrypy.expose - def updateXBMC(self, showName=None): + def updateXBMC(self, show=None): if sickbeard.XBMC_UPDATE_ONLYFIRST: # only send update to first host in the list -- workaround for xbmc sql backend users host = sickbeard.XBMC_HOST.split(",")[0].strip() else: host = sickbeard.XBMC_HOST - if notifiers.xbmc_notifier.update_library(showName=showName): + if show: + show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) + else: + show_obj = None + + if notifiers.xbmc_notifier.update_library(show_obj=show_obj): ui.notifications.message("Library update command sent to XBMC host(s): " + host) else: ui.notifications.error("Unable to contact one or more XBMC host(s): " + host)