From e635f43845a4a0eff0ebfb4441188833577605ca Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 17:41:07 +0100 Subject: [PATCH] Improve sync resiliance and GDM discovery Improve sync resiliance to bad connections (e.g. behind a firewall) --- resources/lib/PlexAPI.py | 8 +++++++- resources/lib/PlexFunctions.py | 21 +++++++++++++++++++ resources/lib/librarysync.py | 28 +++++++++++++++++--------- resources/lib/plexbmchelper/plexgdm.py | 27 +++++++++++++++++++------ 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index a68c6014..ba72c46b 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -55,7 +55,7 @@ import re import json from urllib import urlencode, quote_plus -from PlexFunctions import PlexToKodiTimefactor +from PlexFunctions import PlexToKodiTimefactor, PMSHttpsEnabled try: import xml.etree.cElementTree as etree @@ -630,6 +630,12 @@ class PlexAPI(): self.getPMSListFromMyPlex(ATV_udid, authtoken) # all servers - update enableGzip for uuid_id in self.g_PMS.get(ATV_udid, {}): + # Ping to check whether we need HTTPs or HTTP + url = (self.getPMSProperty(ATV_udid, uuid_id, 'ip') + ':' + + self.getPMSProperty(ATV_udid, uuid_id, 'port')) + if PMSHttpsEnabled(url): + self.logMsg('PMS %s talks HTTPS' % uuid_id, 1) + self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'https') # enable Gzip if not on same host, local&remote PMS depending # on setting enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \ diff --git a/resources/lib/PlexFunctions.py b/resources/lib/PlexFunctions.py index c371ac2c..6fc744f4 100644 --- a/resources/lib/PlexFunctions.py +++ b/resources/lib/PlexFunctions.py @@ -347,3 +347,24 @@ def getPlexRepeat(kodiRepeat): 'all': '2' # does this work?!? } return plexRepeat.get(kodiRepeat) + + +def PMSHttpsEnabled(url): + """ + Returns True if the PMS wants to talk https, False otherwise + + With with e.g. url=192.168.0.1:32400 (NO http/https) + + This is done by GET /identity (returns an error if https is enabled and we + are trying to use http) + """ + xml = downloadutils.DownloadUtils().downloadUrl('http://%s/identity' % url) + try: + # received a valid XML - http connection is possible + xml.attrib + logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTP' % url, 1) + return False + except: + # couldn't get an xml - switch to https traffic + logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTPS' % url, 1) + return True diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index f7a56908..828f0ac5 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -40,10 +40,11 @@ class ThreadedGetMetadata(Thread): the downloaded metadata XMLs as etree objects lock Lock(), used for counting where we are """ - def __init__(self, queue, out_queue, lock): + def __init__(self, queue, out_queue, lock, processlock): self.queue = queue self.out_queue = out_queue self.lock = lock + self.processlock = processlock Thread.__init__(self) def run(self): @@ -51,8 +52,10 @@ class ThreadedGetMetadata(Thread): queue = self.queue out_queue = self.out_queue lock = self.lock + processlock = self.processlock threadStopped = self.threadStopped global getMetadataCount + global processMetadataCount while threadStopped() is False: # grabs Plex item from queue try: @@ -66,9 +69,13 @@ class ThreadedGetMetadata(Thread): if plexXML is None: # Did not receive a valid XML - skip that item for now self.logMsg("Could not get metadata for %s. " - "Skipping that item for now", -1) + "Skipping that item for now" + % updateItem['itemId'], -1) + # Increase BOTH counters - since metadata won't be processed with lock: getMetadataCount += 1 + with processlock: + processMetadataCount += 1 queue.task_done() continue @@ -119,20 +126,20 @@ class ThreadedProcessMetadata(Thread): except Queue.Empty: xbmc.sleep(100) continue - # Do the work; lock to be sure we've only got 1 Thread + # Do the work plexitem = updateItem['XML'] method = updateItem['method'] viewName = updateItem['viewName'] viewId = updateItem['viewId'] title = updateItem['title'] itemSubFkt = getattr(item, method) + # Get the one child entry in the xml and process + for child in plexitem: + itemSubFkt(child, + viewtag=viewName, + viewid=viewId) + # Keep track of where we are at with lock: - # Get the one child entry in the xml and process - for child in plexitem: - itemSubFkt(child, - viewtag=viewName, - viewid=viewId) - # Keep track of where we are at processMetadataCount += 1 processingViewName = title # signals to queue job is done @@ -728,7 +735,8 @@ class LibrarySync(Thread): for i in range(min(self.syncThreadNumber, itemNumber)): thread = ThreadedGetMetadata(getMetadataQueue, processMetadataQueue, - getMetadataLock) + getMetadataLock, + processMetadataLock) thread.setDaemon(True) thread.start() threads.append(thread) diff --git a/resources/lib/plexbmchelper/plexgdm.py b/resources/lib/plexbmchelper/plexgdm.py index 06544f94..597eedc3 100644 --- a/resources/lib/plexbmchelper/plexgdm.py +++ b/resources/lib/plexbmchelper/plexgdm.py @@ -31,7 +31,10 @@ import re import threading import time import urllib2 + import downloadutils +from PlexFunctions import PMSHttpsEnabled + class plexgdm: @@ -56,6 +59,7 @@ class plexgdm: self.discovery_complete = False self.client_registered = False self.debug = debug + self.download = downloadutils.DownloadUtils().downloadUrl def __printDebug(self, message, level=1): if self.debug: @@ -139,13 +143,19 @@ class plexgdm: try: media_server=self.server_list[0]['server'] media_port=self.server_list[0]['port'] + scheme = self.server_list[0]['protocol'] self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2) - client_result = downloadutils.DownloadUtils().downloadUrl( - 'http://%s:%s/clients' % (media_server, media_port)) + client_result = self.download( + '%s://%s:%s/clients' % (scheme, media_server, media_port)) # f = urllib2.urlopen('http://%s:%s/clients' % (media_server, media_port)) # client_result = f.read() - if self.client_id in str(client_result): + registered = False + for client in client_result: + if (client.attrib.get('machineIdentifier') == + self.client_id): + registered = True + if registered: self.__printDebug("Client registration successful",1) self.__printDebug("Client data is: %s" % client_result, 3) return True @@ -208,7 +218,6 @@ class plexgdm: if "200 OK" in response.get('data'): for each in response.get('data').split('\r\n'): - update['discovery'] = "auto" update['owned']='1' update['master']= 1 @@ -230,7 +239,13 @@ class plexgdm: elif "Server-Class:" in each: update['class'] = each.split(':')[1].strip() - discovered_servers.append(update) + # Quickly test if we need https + if PMSHttpsEnabled( + '%s:%s' % (update['server'], update['port'])): + update['protocol'] = 'https' + else: + update['protocol'] = 'http' + discovered_servers.append(update) self.server_list = discovered_servers @@ -239,7 +254,7 @@ class plexgdm: else: self.__printDebug("Number of servers Discovered: %s" % len(self.server_list),1) for items in self.server_list: - self.__printDebug("Server Discovered: %s" % items['serverName'] ,2) + self.__printDebug("Server Discovered: %s" % items, 2) def setInterval(self, interval):