Merge pull request #396 from adam111316/feature/ChangeKodiNotifier

Change Kodi notifier to use requests as opposed to urllib
This commit is contained in:
adam111316 2015-06-11 19:01:23 +08:00
commit 0e7c9656b9
2 changed files with 76 additions and 90 deletions

View file

@ -34,6 +34,7 @@
* Add py2/3 regression testing for exception clauses
* Change py2 exception clauses to py2/3 compatible clauses
* Change py2 print statements to py2/3 compatible functions
* Change Kodi notifier to use requests as opposed to urllib
[develop changelog]
* Update Requests library 2.7.0 (ab1f493) to 2.7.0 (8b5e457)

View file

@ -16,24 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import urllib
import urllib2
import socket
import base64
import time
import requests
import sickbeard
from sickbeard import logger
from sickbeard import common
from sickbeard import logger, common
from sickbeard.exceptions import ex
from sickbeard.encodingKludge import fixStupidEncodings
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
try:
import json
except ImportError:
@ -41,7 +30,8 @@ except ImportError:
class KODINotifier:
sg_logo_url = 'https://raw.githubusercontent.com/SickGear/SickGear/master/gui/slick/images/ico/apple-touch-icon-precomposed.png'
sg_logo_url = 'https://raw.githubusercontent.com/SickGear/SickGear/master/gui/slick/images/ico/apple-touch-icon' \
'-precomposed.png'
def _notify_kodi(self, message, title='SickGear', host=None, username=None, password=None, force=False):
@ -55,21 +45,19 @@ class KODINotifier:
# suppress notifications if the notifier is disabled but the notify options are checked
if not sickbeard.USE_KODI and not force:
logger.log(u'KODI: Notifications are not enabled, skipping this notification', logger.DEBUG)
return False
result = ''
for curHost in [x.strip() for x in host.split(',')]:
logger.log(u'KODI: Sending Kodi notification to \'%s\' - %s' % (curHost, message), logger.MESSAGE)
command = '{"jsonrpc":"2.0","method":"GUI.ShowNotification","params":{"title":"%s","message":"%s", "image": "%s"},"id":1}' % (title.encode('utf-8'), message.encode('utf-8'), self.sg_logo_url)
logger.log(u'KODI: Sending Kodi notification to "%s" - %s' % (curHost, message), logger.MESSAGE)
command = {'jsonrpc': '2.0', 'method': 'GUI.ShowNotification',
'params': {'title': title, 'message': message, 'image': self.sg_logo_url}, 'id': 1}
notifyResult = self._send_to_kodi(command, curHost, username, password)
if notifyResult:
result += curHost + ':' + notifyResult['result'].decode(sickbeard.SYS_ENCODING)
result += '%s:%s' % (curHost, notifyResult['result'])
else:
if sickbeard.KODI_ALWAYS_ON or force:
result += curHost + ':False'
result += '%s:False' % curHost
return result
def _send_to_kodi(self, command, host=None, username=None, password=None):
@ -84,40 +72,38 @@ class KODINotifier:
logger.log(u'KODI: No host specified, check your settings', logger.ERROR)
return False
command = command.encode('utf-8')
logger.log(u'KODI: JSON command: ' + command, logger.DEBUG)
data = json.dumps(command)
logger.log(u'KODI: JSON command: %s' % data, logger.DEBUG)
url = 'http://%s/jsonrpc' % host
headers = {'Content-type': 'application/json'}
# if we have a password, use authentication
if password:
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = 'Basic %s' % base64string
headers['Authorization'] = authheader
logger.log(u'KODI: Contacting (with auth header) via url: %s' % fixStupidEncodings(url), logger.DEBUG)
else:
logger.log(u'KODI: Contacting via url: %s' % fixStupidEncodings(url), logger.DEBUG)
url = 'http://%s/jsonrpc' % (host)
try:
req = urllib2.Request(url, command)
req.add_header('Content-type', 'application/json')
# if we have a password, use authentication
if password:
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = 'Basic %s' % base64string
req.add_header('Authorization', authheader)
logger.log(u'KODI: Contacting (with auth header) via url: ' + fixStupidEncodings(url), logger.DEBUG)
else:
logger.log(u'KODI: Contacting via url: ' + fixStupidEncodings(url), logger.DEBUG)
response = requests.post(url, data=data, headers=headers)
except Exception as e:
logger.log(u'KODI: Warning: Couldn\'t contact Kodi at %s - %s' % (host, ex(e)), logger.WARNING)
return False
try:
response = urllib2.urlopen(req)
except urllib2.URLError as e:
logger.log(u'KODI: Warning: Couldn\'t contact Kodi at ' + host + '- ' + ex(e), logger.WARNING)
return False
if response.status_code == 401:
logger.log(u'KODI: Invalid login credentials', logger.ERROR)
return False
# parse the json result
try:
result = json.load(response)
response.close()
logger.log(u'KODI: JSON response: ' + str(result), logger.DEBUG)
return result # need to return response for parsing
except ValueError as e:
logger.log(u'KODI: Unable to decode JSON response: ' + response, logger.WARNING)
return False
except IOError as e:
logger.log(u'KODI: Warning: Couldn\'t contact Kodi at ' + host + ' - ' + ex(e), logger.WARNING)
# parse the json result
try:
result = response.json()
logger.log(u'KODI: JSON response: %s' % result, logger.DEBUG)
return result # need to return response for parsing
except ValueError as e:
logger.log(u'KODI: Unable to decode JSON response: %s' % response.text, logger.WARNING)
return False
def _update_library(self, host=None, showName=None):
@ -126,70 +112,66 @@ class KODINotifier:
logger.log(u'KODI: No host specified, check your settings', logger.DEBUG)
return False
logger.log(u'KODI: Updating library on host: ' + host, logger.MESSAGE)
logger.log(u'KODI: Updating library on host: %s' % host, logger.MESSAGE)
# if we're doing per-show
if showName:
tvshowid = -1
logger.log(u'KODI: Updating library for show ' + showName, logger.DEBUG)
logger.log(u'KODI: Updating library for show %s' % showName, logger.DEBUG)
# get tvshowid by showName
showsCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShows","id":1}'
showsCommand = {'jsonrpc': '2.0', 'method': 'VideoLibrary.GetTVShows', 'id': 1}
showsResponse = self._send_to_kodi(showsCommand, host)
if showsResponse and 'result' in showsResponse and 'tvshows' in showsResponse['result']:
try:
shows = showsResponse['result']['tvshows']
else:
except:
logger.log(u'KODI: No TV shows in Kodi TV show list', logger.DEBUG)
return False
for show in shows:
if (show['label'] == showName):
tvshowid = show['tvshowid']
break # exit out of loop otherwise the label and showname will not match up
# this can be big, so free some memory
del shows
# we didn't find the show (exact match), thus revert to just doing a full update if enabled
if (tvshowid == -1):
logger.log(u'KODI: Exact show name not matched in KODI TV show list', logger.DEBUG)
try:
tvshowid = next((show['tvshowid'] for show in shows if show['label'] == showName))
except StopIteration:
logger.log(u'XBMC: Exact show name not matched in XBMC TV show list', logger.DEBUG)
return False
# lookup tv-show path
pathCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShowDetails","params":{"tvshowid":%d, "properties": ["file"]},"id":1}' % (tvshowid)
pathCommand = {'jsonrpc': '2.0', 'method': 'VideoLibrary.GetTVShowDetails',
'params': {'tvshowid': tvshowid, 'properties': ['file']}, 'id': 1}
pathResponse = self._send_to_kodi(pathCommand, host)
path = pathResponse['result']['tvshowdetails']['file']
logger.log(u'KODI: Received Show: ' + showName + ' with ID: ' + str(tvshowid) + ' Path: ' + path, logger.DEBUG)
logger.log(u'KODI: Received Show: %s with ID: %s Path: %s' % (showName, tvshowid, path), logger.DEBUG)
if (len(path) < 1):
logger.log(u'KODI: No valid path found for ' + showName + ' with ID: ' + str(tvshowid) + ' on ' + host, logger.WARNING)
if len(path) < 1:
logger.log(u'KODI: No valid path found for %s with ID: %s on %s' % (showName, tvshowid, host),
logger.WARNING)
return False
logger.log(u'KODI: Updating ' + showName + ' on ' + host + ' at ' + path, logger.DEBUG)
updateCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.Scan","params":{"directory":%s},"id":1}' % (json.dumps(path))
logger.log(u'KODI: Updating %s on %s at %s' % (showName, host, path), logger.DEBUG)
updateCommand = {'jsonrpc': '2.0', 'method': 'VideoLibrary.Scan',
'params': {'directory': json.dumps(path)}, 'id': 1}
request = self._send_to_kodi(updateCommand, host)
if not request:
logger.log(u'KODI: Update of show directory failed on ' + showName + ' on ' + host + ' at ' + path, logger.ERROR)
logger.log(u'KODI: Update of show directory failed on %s on %s at %s' % (showName, host, path),
logger.ERROR)
return False
# catch if there was an error in the returned request
for r in request:
if 'error' in r:
logger.log(u'KODI: Error while attempting to update show directory for ' + showName + ' on ' + host + ' at ' + path, logger.ERROR)
logger.log(u'KODI: Error while attempting to update show directory for %s on %s at %s'
% (showName, host, path), logger.ERROR)
return False
# do a full update if requested
else:
logger.log(u'KODI: Performing full library update on host: ' + host, logger.DEBUG)
updateCommand = '{"jsonrpc":"2.0","method":"VideoLibrary.Scan","id":1}'
logger.log(u'KODI: Performing full library update on host: %s' % host, logger.DEBUG)
updateCommand = {'jsonrpc': '2.0', 'method': 'VideoLibrary.Scan', 'id': 1}
request = self._send_to_kodi(updateCommand, host, sickbeard.KODI_USERNAME, sickbeard.KODI_PASSWORD)
if not request:
logger.log(u'KODI: Full library update failed on host: ' + host, logger.ERROR)
logger.log(u'KODI: Full library update failed on host: %s' % host, logger.ERROR)
return False
return True
def notify_snatch(self, ep_name):
@ -202,16 +184,17 @@ class KODINotifier:
def notify_subtitle_download(self, ep_name, lang):
if sickbeard.KODI_NOTIFY_ONSUBTITLEDOWNLOAD:
self._notify_kodi(ep_name + ': ' + lang, common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD])
def notify_git_update(self, new_version = '??'):
self._notify_kodi('%s: %s' % (ep_name, lang), common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD])
def notify_git_update(self, new_version='??'):
if sickbeard.USE_KODI:
update_text=common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT]
title=common.notifyStrings[common.NOTIFY_GIT_UPDATE]
self._notify_kodi(update_text + new_version, title)
update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT]
title = common.notifyStrings[common.NOTIFY_GIT_UPDATE]
self._notify_kodi('%s %s' % (update_text, new_version), title)
def test_notify(self, host, username, password):
return self._notify_kodi('Testing Kodi notifications from SickGear', 'Test', host, username, password, force=True)
return self._notify_kodi(
'Testing Kodi notifications from SickGear', 'Test', host, username, password, force=True)
def update_library(self, showName=None):
@ -225,17 +208,19 @@ class KODINotifier:
for host in [x.strip() for x in sickbeard.KODI_HOST.split(',')]:
if self._update_library(host, showName):
if sickbeard.KODI_UPDATE_ONLYFIRST:
logger.log(u'KODI: Update first host successful on host ' + host + ', stopped sending library update commands', logger.DEBUG)
logger.log(
u'KODI: Update first host successful on host %s , stopped sending library update commands'
% host, logger.DEBUG)
return True
else:
if sickbeard.KODI_ALWAYS_ON:
result = result + 1
# needed for the 'update kodi' submenu command
# as it only cares of the final result vs the individual ones
# needed for the 'update kodi' submenu command as it only cares of the final result vs the individual ones
if result == 0:
return True
else:
return False
notifier = KODINotifier