mirror of
https://github.com/SickGear/SickGear.git
synced 2025-01-05 17:43:37 +00:00
Change Kodi notifier to use requests as opposed to urllib
This commit is contained in:
parent
a02f75cc40
commit
b371c83543
2 changed files with 76 additions and 90 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue