Rewired download and PMS connection
- Look for PMS in the LAN, even if plex.tv is available
This commit is contained in:
parent
8bad79413c
commit
260fc7adf8
9 changed files with 468 additions and 664 deletions
|
@ -363,7 +363,7 @@
|
||||||
<string id="39019">[COLOR red]Partial or full reset of Database and PKC[/COLOR]</string>
|
<string id="39019">[COLOR red]Partial or full reset of Database and PKC[/COLOR]</string>
|
||||||
<string id="39020">[COLOR yellow]Cache all images to Kodi texture cache[/COLOR]</string>
|
<string id="39020">[COLOR yellow]Cache all images to Kodi texture cache[/COLOR]</string>
|
||||||
<string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string>
|
<string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string>
|
||||||
<string id="39022"> (local)</string>
|
<string id="39022">local</string>
|
||||||
<string id="39023">Failed to authenticate. Did you login to plex.tv?</string>
|
<string id="39023">Failed to authenticate. Did you login to plex.tv?</string>
|
||||||
<string id="39024">[COLOR yellow]Reset PMS and plex.tv connections to re-login[/COLOR]</string>
|
<string id="39024">[COLOR yellow]Reset PMS and plex.tv connections to re-login[/COLOR]</string>
|
||||||
<string id="39025">Automatically log into plex.tv on startup</string>
|
<string id="39025">Automatically log into plex.tv on startup</string>
|
||||||
|
@ -396,6 +396,8 @@
|
||||||
<string id="39051">Wait before sync new/changed PMS item [s]</string>
|
<string id="39051">Wait before sync new/changed PMS item [s]</string>
|
||||||
<string id="39052">Background Sync</string>
|
<string id="39052">Background Sync</string>
|
||||||
<string id="39053">Do a full library sync every x minutes</string>
|
<string id="39053">Do a full library sync every x minutes</string>
|
||||||
|
<string id="39054">remote</string>
|
||||||
|
<string id="39055">Searching for Plex Server</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,7 @@
|
||||||
<string id="39019">[COLOR red]Datenbank und auf Wunsch PKC zurücksetzen[/COLOR]</string>
|
<string id="39019">[COLOR red]Datenbank und auf Wunsch PKC zurücksetzen[/COLOR]</string>
|
||||||
<string id="39020">[COLOR yellow]Alle Plex Bilder in Kodi zwischenspeichern[/COLOR]</string>
|
<string id="39020">[COLOR yellow]Alle Plex Bilder in Kodi zwischenspeichern[/COLOR]</string>
|
||||||
<string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string>
|
<string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string>
|
||||||
<string id="39022"> (lokal)</string>
|
<string id="39022">lokal</string>
|
||||||
<string id="39023">Plex Media Server Authentifizierung fehlgeschlagen. Haben Sie sich bei plex.tv eingeloggt?</string>
|
<string id="39023">Plex Media Server Authentifizierung fehlgeschlagen. Haben Sie sich bei plex.tv eingeloggt?</string>
|
||||||
<string id="39024">[COLOR yellow]PMS und plex.tv Verbindungen zurücksetzen für erneuten Login[/COLOR]</string>
|
<string id="39024">[COLOR yellow]PMS und plex.tv Verbindungen zurücksetzen für erneuten Login[/COLOR]</string>
|
||||||
<string id="39025">Automatisch beim Starten bei plex.tv einloggen</string>
|
<string id="39025">Automatisch beim Starten bei plex.tv einloggen</string>
|
||||||
|
@ -334,6 +334,8 @@
|
||||||
<string id="39051">Warten bevor neue/geänderte PMS Einträge gesynct werden [s]</string>
|
<string id="39051">Warten bevor neue/geänderte PMS Einträge gesynct werden [s]</string>
|
||||||
<string id="39052">Hintergrund-Synchronisation</string>
|
<string id="39052">Hintergrund-Synchronisation</string>
|
||||||
<string id="39053">Kompletten Scan aller Bibliotheken alle x Minuten durchführen</string>
|
<string id="39053">Kompletten Scan aller Bibliotheken alle x Minuten durchführen</string>
|
||||||
|
<string id="39054">remote</string>
|
||||||
|
<string id="39055">Suche Plex Server</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Plex Entrypoint.py -->
|
<!-- Plex Entrypoint.py -->
|
||||||
|
|
|
@ -29,18 +29,12 @@ http://stackoverflow.com/questions/2407126/python-urllib2-basic-auth-problem
|
||||||
http://stackoverflow.com/questions/111945/is-there-any-way-to-do-http-put-in-python
|
http://stackoverflow.com/questions/111945/is-there-any-way-to-do-http-put-in-python
|
||||||
(and others...)
|
(and others...)
|
||||||
"""
|
"""
|
||||||
import struct
|
|
||||||
import time
|
import time
|
||||||
import urllib2
|
import urllib2
|
||||||
import httplib
|
|
||||||
import socket
|
import socket
|
||||||
import StringIO
|
|
||||||
import gzip
|
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import traceback
|
|
||||||
import requests
|
import requests
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
from uuid import uuid4
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
@ -232,15 +226,15 @@ class PlexAPI():
|
||||||
try:
|
try:
|
||||||
temp_token = xml.find('auth_token').text
|
temp_token = xml.find('auth_token').text
|
||||||
except:
|
except:
|
||||||
self.logMsg("Error: Could not find token in plex.tv answer.", -1)
|
self.logMsg("Could not find token in plex.tv answer.", -1)
|
||||||
return False
|
return False
|
||||||
self.logMsg("temp token from plex.tv is: %s" % temp_token, 2)
|
self.logMsg("temp token from plex.tv is: %s" % temp_token, 2)
|
||||||
if not temp_token:
|
if not temp_token:
|
||||||
return False
|
return False
|
||||||
# Use temp token to get the final plex credentials
|
# Use temp token to get the final plex credentials
|
||||||
xml = self.doUtils('https://plex.tv/users/account?X-Plex-Token=%s'
|
xml = self.doUtils('https://plex.tv/users/account',
|
||||||
% temp_token,
|
|
||||||
authenticate=False,
|
authenticate=False,
|
||||||
|
parameters={'X-Plex-Token': temp_token},
|
||||||
type="GET")
|
type="GET")
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
|
@ -320,66 +314,63 @@ class PlexAPI():
|
||||||
return False
|
return False
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
def CheckConnection(self, url, token=None):
|
def CheckConnection(self, url, token=None, verifySSL=None):
|
||||||
"""
|
"""
|
||||||
Checks connection to a Plex server, available at url. Can also be used
|
Checks connection to a Plex server, available at url. Can also be used
|
||||||
to check for connection with plex.tv.
|
to check for connection with plex.tv.
|
||||||
Will check up to 3x until reply with False
|
Will check up to 3x until reply with False
|
||||||
|
|
||||||
|
Override SSL to skip the check by setting verifySSL=False
|
||||||
|
if 'None', SSL will be checked (standard requests setting)
|
||||||
|
if 'True', SSL settings from file settings are used (False/True)
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
url URL to Plex server (e.g. https://192.168.1.1:32400)
|
url URL to Plex server (e.g. https://192.168.1.1:32400)
|
||||||
token appropriate token to access server. If None is passed,
|
token appropriate token to access server. If None is passed,
|
||||||
the current token is used
|
the current token is used
|
||||||
Output:
|
Output:
|
||||||
False if server could not be reached or timeout occured
|
False if server could not be reached or timeout occured
|
||||||
e.g. 200 if connection was successfull
|
200 if connection was successfull
|
||||||
int or other HTML status codes as received from the server
|
int or other HTML status codes as received from the server
|
||||||
"""
|
"""
|
||||||
# Add '/clients' to URL because then an authentication is necessary
|
# Add '/clients' to URL because then an authentication is necessary
|
||||||
# If a plex.tv URL was passed, this does not work.
|
# If a plex.tv URL was passed, this does not work.
|
||||||
header = clientinfo.ClientInfo().getXArgsDeviceInfo()
|
headerOptions = None
|
||||||
if token:
|
if token is not None:
|
||||||
header['X-Plex-Token'] = token
|
headerOptions = {'X-Plex-Token': token}
|
||||||
sslverify = utils.settings('sslverify')
|
if verifySSL is True:
|
||||||
if sslverify == "true":
|
verifySSL = None if utils.settings('sslverify') == 'true' \
|
||||||
sslverify = True
|
else False
|
||||||
else:
|
|
||||||
sslverify = False
|
|
||||||
self.logMsg("Checking connection to server %s with sslverify=%s"
|
|
||||||
% (url, sslverify), 1)
|
|
||||||
timeout = (3, 10)
|
|
||||||
if 'plex.tv' in url:
|
if 'plex.tv' in url:
|
||||||
url = 'https://plex.tv/api/home/users'
|
url = 'https://plex.tv/api/home/users'
|
||||||
else:
|
else:
|
||||||
url = url + '/library/onDeck'
|
url = url + '/library/onDeck'
|
||||||
# Check up to 3 times before giving up - this sometimes happens when
|
self.logMsg("Checking connection to server %s with verifySSL=%s"
|
||||||
# PKC was just started
|
% (url, verifySSL), 1)
|
||||||
|
# Check up to 3 times before giving up
|
||||||
count = 0
|
count = 0
|
||||||
while count < 3:
|
while count < 3:
|
||||||
|
answer = self.doUtils(url,
|
||||||
|
authenticate=False,
|
||||||
|
headerOptions=headerOptions,
|
||||||
|
verifySSL=verifySSL)
|
||||||
|
if answer is False:
|
||||||
|
self.logMsg("Could not connect to %s" % url, 0)
|
||||||
|
count += 1
|
||||||
|
xbmc.sleep(500)
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
answer = requests.get(url,
|
answer.attrib
|
||||||
headers={},
|
except:
|
||||||
params=header,
|
pass
|
||||||
verify=sslverify,
|
|
||||||
timeout=timeout)
|
|
||||||
except requests.exceptions.ConnectionError as e:
|
|
||||||
self.logMsg("Server is offline or cannot be reached. Url: %s "
|
|
||||||
"Header: %s Error message: %s"
|
|
||||||
% (url, header, e), 0)
|
|
||||||
count += 1
|
|
||||||
xbmc.sleep(1000)
|
|
||||||
continue
|
|
||||||
except requests.exceptions.ReadTimeout:
|
|
||||||
self.logMsg("Server timeout reached for Url %s with header %s"
|
|
||||||
% (url, header), 0)
|
|
||||||
count += 1
|
|
||||||
xbmc.sleep(1000)
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
result = answer.status_code
|
# Success - we downloaded an xml!
|
||||||
self.logMsg("Result was: %s" % result, 1)
|
answer = 200
|
||||||
return result
|
self.logMsg("Checking connection successfull. Answer: %s"
|
||||||
self.logMsg('Failed to connect to %s too many times.' % url, -1)
|
% answer, 1)
|
||||||
|
return answer
|
||||||
|
self.logMsg('Failed to connect to %s too many times. PMS is dead'
|
||||||
|
% url, 0)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def GetgPMSKeylist(self):
|
def GetgPMSKeylist(self):
|
||||||
|
@ -455,23 +446,21 @@ class PlexAPI():
|
||||||
addon.setSetting('serverlist', serverlist)
|
addon.setSetting('serverlist', serverlist)
|
||||||
return
|
return
|
||||||
|
|
||||||
def declarePMS(self, ATV_udid, uuid, name, scheme, ip, port):
|
def declarePMS(self, uuid, name, scheme, ip, port):
|
||||||
"""
|
"""
|
||||||
Plex Media Server handling
|
Plex Media Server handling
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
ATV_udid
|
|
||||||
uuid - PMS ID
|
uuid - PMS ID
|
||||||
name, scheme, ip, port, type, owned, token
|
name, scheme, ip, port, type, owned, token
|
||||||
"""
|
"""
|
||||||
# store PMS information in g_PMS database
|
|
||||||
if ATV_udid not in self.g_PMS:
|
|
||||||
self.g_PMS[ATV_udid] = {}
|
|
||||||
|
|
||||||
address = ip + ':' + port
|
address = ip + ':' + port
|
||||||
baseURL = scheme+'://'+ip+':'+port
|
baseURL = scheme+'://'+ip+':'+port
|
||||||
self.g_PMS[ATV_udid][uuid] = { 'name': name,
|
self.g_PMS[uuid] = {
|
||||||
'scheme':scheme, 'ip': ip , 'port': port,
|
'name': name,
|
||||||
|
'scheme': scheme,
|
||||||
|
'ip': ip,
|
||||||
|
'port': port,
|
||||||
'address': address,
|
'address': address,
|
||||||
'baseURL': baseURL,
|
'baseURL': baseURL,
|
||||||
'local': '1',
|
'local': '1',
|
||||||
|
@ -480,48 +469,22 @@ class PlexAPI():
|
||||||
'enableGzip': False
|
'enableGzip': False
|
||||||
}
|
}
|
||||||
|
|
||||||
def updatePMSProperty(self, ATV_udid, uuid, tag, value):
|
def updatePMSProperty(self, uuid, tag, value):
|
||||||
# set property element of PMS by UUID
|
# set property element of PMS by UUID
|
||||||
if not ATV_udid in self.g_PMS:
|
try:
|
||||||
return '' # no server known for this aTV
|
self.g_PMS[uuid][tag] = value
|
||||||
if not uuid in self.g_PMS[ATV_udid]:
|
except:
|
||||||
return '' # requested PMS not available
|
self.logMsg('%s has not yet been declared ' % uuid, -1)
|
||||||
|
return False
|
||||||
|
|
||||||
self.g_PMS[ATV_udid][uuid][tag] = value
|
def getPMSProperty(self, uuid, tag):
|
||||||
|
|
||||||
def getPMSProperty(self, ATV_udid, uuid, tag):
|
|
||||||
# get name of PMS by UUID
|
# get name of PMS by UUID
|
||||||
if not ATV_udid in self.g_PMS:
|
try:
|
||||||
return '' # no server known for this aTV
|
answ = self.g_PMS[uuid].get(tag, '')
|
||||||
if not uuid in self.g_PMS[ATV_udid]:
|
except:
|
||||||
return '' # requested PMS not available
|
self.logMsg('%s not found in PMS catalogue' % uuid, -1)
|
||||||
|
answ = False
|
||||||
return self.g_PMS[ATV_udid][uuid].get(tag, '')
|
return answ
|
||||||
|
|
||||||
def getPMSFromAddress(self, ATV_udid, address):
|
|
||||||
# find PMS by IP, return UUID
|
|
||||||
if not ATV_udid in self.g_PMS:
|
|
||||||
return '' # no server known for this aTV
|
|
||||||
|
|
||||||
for uuid in self.g_PMS[ATV_udid]:
|
|
||||||
if address in self.g_PMS[ATV_udid][uuid].get('address', None):
|
|
||||||
return uuid
|
|
||||||
return '' # IP not found
|
|
||||||
|
|
||||||
def getPMSAddress(self, ATV_udid, uuid, data):
|
|
||||||
# get address of PMS by UUID
|
|
||||||
if not ATV_udid in data:
|
|
||||||
return '' # no server known for this aTV
|
|
||||||
if not uuid in data[ATV_udid]:
|
|
||||||
return '' # requested PMS not available
|
|
||||||
return data[ATV_udid][uuid]['ip'] + ':' + data[ATV_udid][uuid]['port']
|
|
||||||
|
|
||||||
def getPMSCount(self, ATV_udid):
|
|
||||||
# get count of discovered PMS by UUID
|
|
||||||
if not ATV_udid in self.g_PMS:
|
|
||||||
return 0 # no server known for this aTV
|
|
||||||
|
|
||||||
return len(self.g_PMS[ATV_udid])
|
|
||||||
|
|
||||||
def PlexGDM(self):
|
def PlexGDM(self):
|
||||||
"""
|
"""
|
||||||
|
@ -532,25 +495,23 @@ class PlexAPI():
|
||||||
result:
|
result:
|
||||||
PMS_list - dict() of PMSs found
|
PMS_list - dict() of PMSs found
|
||||||
"""
|
"""
|
||||||
|
import struct
|
||||||
|
|
||||||
IP_PlexGDM = '239.0.0.250' # multicast to PMS
|
IP_PlexGDM = '239.0.0.250' # multicast to PMS
|
||||||
Port_PlexGDM = 32414
|
Port_PlexGDM = 32414
|
||||||
Msg_PlexGDM = 'M-SEARCH * HTTP/1.0'
|
Msg_PlexGDM = 'M-SEARCH * HTTP/1.0'
|
||||||
# dprint(__name__, 0, "***")
|
|
||||||
# dprint(__name__, 0, "PlexGDM - looking up Plex Media Server")
|
|
||||||
# dprint(__name__, 0, "***")
|
|
||||||
|
|
||||||
# setup socket for discovery -> multicast message
|
# setup socket for discovery -> multicast message
|
||||||
GDM = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
GDM = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
GDM.settimeout(1.0)
|
GDM.settimeout(2.0)
|
||||||
|
|
||||||
# Set the time-to-live for messages to 1 for local network
|
# Set the time-to-live for messages to 2 for local network
|
||||||
ttl = struct.pack('b', 1)
|
ttl = struct.pack('b', 2)
|
||||||
GDM.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
|
GDM.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
|
||||||
|
|
||||||
returnData = []
|
returnData = []
|
||||||
try:
|
try:
|
||||||
# Send data to the multicast group
|
# Send data to the multicast group
|
||||||
# dprint(__name__, 1, "Sending discovery message: {0}", Msg_PlexGDM)
|
|
||||||
GDM.sendto(Msg_PlexGDM, (IP_PlexGDM, Port_PlexGDM))
|
GDM.sendto(Msg_PlexGDM, (IP_PlexGDM, Port_PlexGDM))
|
||||||
|
|
||||||
# Look for responses from all recipients
|
# Look for responses from all recipients
|
||||||
|
@ -559,126 +520,109 @@ class PlexAPI():
|
||||||
data, server = GDM.recvfrom(1024)
|
data, server = GDM.recvfrom(1024)
|
||||||
# dprint(__name__, 1, "Received data from {0}", server)
|
# dprint(__name__, 1, "Received data from {0}", server)
|
||||||
# dprint(__name__, 1, "Data received:\n {0}", data)
|
# dprint(__name__, 1, "Data received:\n {0}", data)
|
||||||
returnData.append( { 'from' : server,
|
returnData.append({'from': server,
|
||||||
'data' : data } )
|
'data': data})
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
break
|
break
|
||||||
finally:
|
finally:
|
||||||
GDM.close()
|
GDM.close()
|
||||||
|
|
||||||
discovery_complete = True
|
pmsList = {}
|
||||||
|
|
||||||
PMS_list = {}
|
self.logMsg('returndata is: %s' % returnData)
|
||||||
if returnData:
|
|
||||||
for response in returnData:
|
for response in returnData:
|
||||||
update = { 'ip' : response.get('from')[0] }
|
update = {'ip': response.get('from')[0]}
|
||||||
|
|
||||||
# Check if we had a positive HTTP response
|
# Check if we had a positive HTTP response
|
||||||
if "200 OK" in response.get('data'):
|
if "200 OK" in response.get('data'):
|
||||||
for each in response.get('data').split('\n'):
|
for each in response.get('data').split('\n'):
|
||||||
# decode response data
|
# decode response data
|
||||||
update['discovery'] = "auto"
|
update['discovery'] = "auto"
|
||||||
#update['owned']='1'
|
# update['owned']='1'
|
||||||
#update['master']= 1
|
# update['master']= 1
|
||||||
#update['role']='master'
|
# update['role']='master'
|
||||||
|
|
||||||
if "Content-Type:" in each:
|
if "Content-Type:" in each:
|
||||||
update['content-type'] = each.split(':')[1].strip()
|
update['content-type'] = each.split(':')[1].strip()
|
||||||
elif "Resource-Identifier:" in each:
|
elif "Resource-Identifier:" in each:
|
||||||
update['uuid'] = each.split(':')[1].strip()
|
update['uuid'] = each.split(':')[1].strip()
|
||||||
elif "Name:" in each:
|
elif "Name:" in each:
|
||||||
update['serverName'] = each.split(':')[1].strip().decode('utf-8', 'replace') # store in utf-8
|
update['serverName'] = each.split(':')[1].strip().decode('utf-8', 'replace')
|
||||||
elif "Port:" in each:
|
elif "Port:" in each:
|
||||||
update['port'] = each.split(':')[1].strip()
|
update['port'] = each.split(':')[1].strip()
|
||||||
elif "Updated-At:" in each:
|
elif "Updated-At:" in each:
|
||||||
update['updated'] = each.split(':')[1].strip()
|
update['updated'] = each.split(':')[1].strip()
|
||||||
elif "Version:" in each:
|
elif "Version:" in each:
|
||||||
update['version'] = each.split(':')[1].strip()
|
update['version'] = each.split(':')[1].strip()
|
||||||
|
pmsList[update['uuid']] = update
|
||||||
|
|
||||||
PMS_list[update['uuid']] = update
|
return pmsList
|
||||||
|
|
||||||
# if PMS_list=={}:
|
def discoverPMS(self, IP_self, plexToken=None):
|
||||||
# dprint(__name__, 0, "GDM: No servers discovered")
|
|
||||||
# else:
|
|
||||||
# dprint(__name__, 0, "GDM: Servers discovered: {0}", len(PMS_list))
|
|
||||||
# for uuid in PMS_list:
|
|
||||||
# dprint(__name__, 1, "{0} {1}:{2}", PMS_list[uuid]['serverName'], PMS_list[uuid]['ip'], PMS_list[uuid]['port'])
|
|
||||||
|
|
||||||
return PMS_list
|
|
||||||
|
|
||||||
def discoverPMS(self, ATV_udid, CSettings, IP_self, tokenDict={}):
|
|
||||||
"""
|
"""
|
||||||
discoverPMS
|
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
ATV_udid
|
IP_self Own IP
|
||||||
CSettings - for manual PMS configuration. this one looks strange.
|
|
||||||
IP_self
|
|
||||||
optional:
|
optional:
|
||||||
tokenDict - dictionary of tokens for MyPlex, PlexHome
|
plexToken token for plex.tv
|
||||||
result:
|
result:
|
||||||
self.g_PMS dictionary for ATV_udid
|
self.g_PMS dict set
|
||||||
"""
|
"""
|
||||||
self.g_PMS[ATV_udid] = {}
|
self.g_PMS = {}
|
||||||
|
xbmcgui.Dialog().notification(
|
||||||
|
heading=self.addonName,
|
||||||
|
message=self.__language__(39055),
|
||||||
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
|
time=3000,
|
||||||
|
sound=False)
|
||||||
|
|
||||||
# install plex.tv "virtual" PMS - for myPlex, PlexHome
|
# Look first for local PMS in the LAN
|
||||||
self.declarePMS(ATV_udid, 'plex.tv', 'plex.tv', 'https', 'plex.tv', '443')
|
pmsList = self.PlexGDM()
|
||||||
self.updatePMSProperty(ATV_udid, 'plex.tv', 'local', '-')
|
self.logMsg('pmslist: %s' % pmsList, 1)
|
||||||
self.updatePMSProperty(ATV_udid, 'plex.tv', 'owned', '-')
|
for uuid in pmsList:
|
||||||
self.updatePMSProperty(ATV_udid, 'plex.tv', 'accesstoken', tokenDict.get('MyPlexToken', ''))
|
PMS = pmsList[uuid]
|
||||||
|
self.declarePMS(PMS['uuid'], PMS['serverName'], 'http',
|
||||||
if 'PlexHomeToken' in tokenDict:
|
PMS['ip'], PMS['port'])
|
||||||
authtoken = tokenDict.get('PlexHomeToken')
|
self.updatePMSProperty(PMS['uuid'], 'owned', '-')
|
||||||
else:
|
|
||||||
authtoken = tokenDict.get('MyPlexToken', '')
|
|
||||||
|
|
||||||
if authtoken == '':
|
|
||||||
# not logged into myPlex
|
|
||||||
# local PMS
|
|
||||||
# PlexGDM
|
|
||||||
PMS_list = self.PlexGDM()
|
|
||||||
for uuid_id in PMS_list:
|
|
||||||
PMS = PMS_list[uuid_id]
|
|
||||||
self.declarePMS(ATV_udid, PMS['uuid'], PMS['serverName'], 'http', PMS['ip'], PMS['port']) # dflt: token='', local, owned
|
|
||||||
else:
|
|
||||||
# MyPlex servers
|
|
||||||
self.getPMSListFromMyPlex(ATV_udid, authtoken)
|
|
||||||
# Delete plex.tv again
|
|
||||||
del self.g_PMS[ATV_udid]['plex.tv']
|
|
||||||
# all servers - update enableGzip
|
|
||||||
for uuid_id in self.g_PMS.get(ATV_udid, {}):
|
|
||||||
# Ping to check whether we need HTTPs or HTTP
|
# Ping to check whether we need HTTPs or HTTP
|
||||||
url = (self.getPMSProperty(ATV_udid, uuid_id, 'ip') + ':'
|
url = '%s:%s' % (PMS['ip'], PMS['port'])
|
||||||
+ self.getPMSProperty(ATV_udid, uuid_id, 'port'))
|
|
||||||
https = PMSHttpsEnabled(url)
|
https = PMSHttpsEnabled(url)
|
||||||
if https is None:
|
if https is None:
|
||||||
# Error contacting url
|
# Error contacting url. Skip for now
|
||||||
continue
|
continue
|
||||||
elif https:
|
elif https is True:
|
||||||
self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'https')
|
self.updatePMSProperty(PMS['uuid'], 'scheme', 'https')
|
||||||
|
self.updatePMSProperty(
|
||||||
|
PMS['uuid'],
|
||||||
|
'baseURL',
|
||||||
|
'https://%s:%s' % (PMS['ip'], PMS['port']))
|
||||||
else:
|
else:
|
||||||
self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'http')
|
# Already declared with http
|
||||||
# enable Gzip if not on same host, local&remote PMS depending
|
pass
|
||||||
# on setting
|
|
||||||
enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \
|
|
||||||
and (
|
|
||||||
(self.getPMSProperty(ATV_udid, uuid_id, 'local') == '1'
|
|
||||||
and False)
|
|
||||||
or
|
|
||||||
(self.getPMSProperty(ATV_udid, uuid_id, 'local') == '0'
|
|
||||||
and True) == 'True'
|
|
||||||
)
|
|
||||||
self.updatePMSProperty(ATV_udid, uuid_id, 'enableGzip', enableGzip)
|
|
||||||
|
|
||||||
def getPMSListFromMyPlex(self, ATV_udid, authtoken):
|
if not plexToken:
|
||||||
|
self.logMsg('No plex.tv token supplied, checked LAN for PMS', 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
# install plex.tv "virtual" PMS - for myPlex, PlexHome
|
||||||
|
# self.declarePMS('plex.tv', 'plex.tv', 'https', 'plex.tv', '443')
|
||||||
|
# self.updatePMSProperty('plex.tv', 'local', '-')
|
||||||
|
# self.updatePMSProperty('plex.tv', 'owned', '-')
|
||||||
|
# self.updatePMSProperty(
|
||||||
|
# 'plex.tv', 'accesstoken', plexToken)
|
||||||
|
# (remote and local) servers from plex.tv
|
||||||
|
|
||||||
|
# Get PMS from plex.tv. This will overwrite any PMS we already found
|
||||||
|
self.getPMSListFromMyPlex(plexToken)
|
||||||
|
|
||||||
|
def getPMSListFromMyPlex(self, token):
|
||||||
"""
|
"""
|
||||||
getPMSListFromMyPlex
|
getPMSListFromMyPlex
|
||||||
|
|
||||||
get Plex media Server List from plex.tv/pms/resources
|
get Plex media Server List from plex.tv/pms/resources
|
||||||
"""
|
"""
|
||||||
xml = self.doUtils('https://plex.tv/api/resources?includeHttps=1',
|
xml = self.doUtils('https://plex.tv/api/resources',
|
||||||
authenticate=False,
|
authenticate=False,
|
||||||
headerOptions={'X-Plex-Token': authtoken})
|
parameters={'includeHttps': 1},
|
||||||
|
headerOptions={'X-Plex-Token': token})
|
||||||
try:
|
try:
|
||||||
xml.attrib
|
xml.attrib
|
||||||
except:
|
except:
|
||||||
|
@ -699,36 +643,43 @@ class PlexAPI():
|
||||||
PMS = {}
|
PMS = {}
|
||||||
PMS['name'] = Dir.get('name')
|
PMS['name'] = Dir.get('name')
|
||||||
infoAge = time.time() - int(Dir.get('lastSeenAt'))
|
infoAge = time.time() - int(Dir.get('lastSeenAt'))
|
||||||
oneDayInSec = 2*60*60*24
|
oneDayInSec = 60*60*24
|
||||||
if infoAge > 1*oneDayInSec:
|
if infoAge > 2*oneDayInSec:
|
||||||
self.logMsg("Server %s not seen for 1 day - "
|
self.logMsg("Server %s not seen for 2 days - "
|
||||||
"skipping." % PMS['name'], 0)
|
"skipping." % PMS['name'], 0)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
PMS['uuid'] = Dir.get('clientIdentifier')
|
PMS['uuid'] = Dir.get('clientIdentifier')
|
||||||
PMS['token'] = Dir.get('accessToken', authtoken)
|
PMS['token'] = Dir.get('accessToken', token)
|
||||||
PMS['owned'] = Dir.get('owned', '0')
|
PMS['owned'] = Dir.get('owned', '0')
|
||||||
PMS['local'] = Dir.get('publicAddressMatches')
|
PMS['local'] = Dir.get('publicAddressMatches')
|
||||||
PMS['ownername'] = Dir.get('sourceTitle', '')
|
PMS['ownername'] = Dir.get('sourceTitle', '')
|
||||||
PMS['path'] = '/'
|
PMS['path'] = '/'
|
||||||
PMS['options'] = None
|
PMS['options'] = None
|
||||||
|
|
||||||
# flag to set first connection, possibly overwrite later with
|
# If PMS seems (!!) local, try a local connection first
|
||||||
# more suitable
|
# Backup to remote connection, if that failes
|
||||||
PMS['baseURL'] = ""
|
PMS['baseURL'] = ''
|
||||||
for Con in Dir.iter(tag='Connection'):
|
for Con in Dir.iter(tag='Connection'):
|
||||||
if (PMS['baseURL'] == "" or
|
localConn = Con.get('local')
|
||||||
Con.get('local') == PMS['local']):
|
if ((PMS['local'] == '1' and localConn == '1') or
|
||||||
|
(PMS['local'] == '0' and localConn == '0')):
|
||||||
|
# Either both local or both remote
|
||||||
PMS['protocol'] = Con.get('protocol')
|
PMS['protocol'] = Con.get('protocol')
|
||||||
PMS['ip'] = Con.get('address')
|
PMS['ip'] = Con.get('address')
|
||||||
PMS['port'] = Con.get('port')
|
PMS['port'] = Con.get('port')
|
||||||
PMS['baseURL'] = Con.get('baseURL')
|
PMS['baseURL'] = Con.get('uri')
|
||||||
# todo: handle unforeseen - like we get multiple suitable
|
elif PMS['local'] == '1' and localConn == '0':
|
||||||
# connections. how to choose one?
|
# Backup connection if local one did not work
|
||||||
|
PMS['backup'] = {}
|
||||||
|
PMS['backup']['protocol'] = Con.get('protocol')
|
||||||
|
PMS['backup']['ip'] = Con.get('address')
|
||||||
|
PMS['backup']['port'] = Con.get('port')
|
||||||
|
PMS['backup']['baseURL'] = Con.get('uri')
|
||||||
|
|
||||||
# poke PMS, own thread for each poke
|
# poke PMS, own thread for each poke
|
||||||
t = Thread(target=self.pokePMS,
|
t = Thread(target=self.pokePMS,
|
||||||
args=(PMS['baseURL'], PMS['token'], PMS, queue))
|
args=(PMS, queue))
|
||||||
t.start()
|
t.start()
|
||||||
threads.append(t)
|
threads.append(t)
|
||||||
|
|
||||||
|
@ -739,45 +690,49 @@ class PlexAPI():
|
||||||
# declare new PMSs
|
# declare new PMSs
|
||||||
while not queue.empty():
|
while not queue.empty():
|
||||||
PMS = queue.get()
|
PMS = queue.get()
|
||||||
self.declarePMS(ATV_udid, PMS['uuid'], PMS['name'],
|
self.declarePMS(PMS['uuid'], PMS['name'],
|
||||||
PMS['protocol'], PMS['ip'], PMS['port'])
|
PMS['protocol'], PMS['ip'], PMS['port'])
|
||||||
# dflt: token='', local, owned - updated later
|
# dflt: token='', local, owned - updated later
|
||||||
self.updatePMSProperty(
|
self.updatePMSProperty(
|
||||||
ATV_udid, PMS['uuid'], 'accesstoken', PMS['token'])
|
PMS['uuid'], 'accesstoken', PMS['token'])
|
||||||
self.updatePMSProperty(
|
self.updatePMSProperty(
|
||||||
ATV_udid, PMS['uuid'], 'owned', PMS['owned'])
|
PMS['uuid'], 'owned', PMS['owned'])
|
||||||
self.updatePMSProperty(
|
self.updatePMSProperty(
|
||||||
ATV_udid, PMS['uuid'], 'local', PMS['local'])
|
PMS['uuid'], 'local', PMS['local'])
|
||||||
# set in declarePMS, overwrite for https encryption
|
# set in declarePMS, overwrite for https encryption
|
||||||
self.updatePMSProperty(
|
self.updatePMSProperty(
|
||||||
ATV_udid, PMS['uuid'], 'baseURL', PMS['baseURL'])
|
PMS['uuid'], 'baseURL', PMS['baseURL'])
|
||||||
self.updatePMSProperty(
|
self.updatePMSProperty(
|
||||||
ATV_udid, PMS['uuid'], 'ownername', PMS['ownername'])
|
PMS['uuid'], 'ownername', PMS['ownername'])
|
||||||
queue.task_done()
|
queue.task_done()
|
||||||
|
|
||||||
def pokePMS(self, url, token, PMS, queue):
|
def pokePMS(self, PMS, queue):
|
||||||
xml = self.doUtils(url,
|
# Ignore SSL certificates for now
|
||||||
|
xml = self.doUtils(PMS['baseURL'],
|
||||||
authenticate=False,
|
authenticate=False,
|
||||||
headerOptions={'X-Plex-Token': token})
|
headerOptions={'X-Plex-Token': PMS['token']},
|
||||||
|
verifySSL=False)
|
||||||
try:
|
try:
|
||||||
xml.attrib
|
xml.attrib
|
||||||
except:
|
except:
|
||||||
|
# Connection failed
|
||||||
|
# retry with remote connection if we just tested local one.
|
||||||
|
if PMS['local'] == '1' and PMS.get('backup'):
|
||||||
|
self.logMsg('Couldnt talk to local PMS locally.'
|
||||||
|
'Trying again remotely.', 0)
|
||||||
|
PMS['protocol'] = PMS['backup']['protocol']
|
||||||
|
PMS['ip'] = PMS['backup']['ip']
|
||||||
|
PMS['port'] = PMS['backup']['port']
|
||||||
|
PMS['baseURL'] = PMS['backup']['baseURL']
|
||||||
|
PMS['local'] = '0'
|
||||||
|
# Try again
|
||||||
|
self.pokePMS(PMS, queue)
|
||||||
|
else:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
# Connection successful, process later
|
||||||
queue.put(PMS)
|
queue.put(PMS)
|
||||||
|
|
||||||
def getURL(self, baseURL, path, key):
|
|
||||||
if key.startswith('http://') or key.startswith('https://'): # external server
|
|
||||||
URL = key
|
|
||||||
elif key.startswith('/'): # internal full path.
|
|
||||||
URL = baseURL + key
|
|
||||||
elif key == '': # internal path
|
|
||||||
URL = baseURL + path
|
|
||||||
else: # internal path, add-on
|
|
||||||
URL = baseURL + path + '/' + key
|
|
||||||
|
|
||||||
return URL
|
|
||||||
|
|
||||||
def MyPlexSignIn(self, username, password, options):
|
def MyPlexSignIn(self, username, password, options):
|
||||||
"""
|
"""
|
||||||
MyPlex Sign In, Sign Out
|
MyPlex Sign In, Sign Out
|
||||||
|
@ -1226,13 +1181,12 @@ class PlexAPI():
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def returnServerList(self, ATV_udid, data):
|
def returnServerList(self, data):
|
||||||
"""
|
"""
|
||||||
Returns a nicer list of all servers found in data, where data is in
|
Returns a nicer list of all servers found in data, where data is in
|
||||||
g_PMS format, for the client device with unique ID ATV_udid
|
g_PMS format, for the client device with unique ID ATV_udid
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
ATV_udid Unique client ID
|
|
||||||
data e.g. self.g_PMS
|
data e.g. self.g_PMS
|
||||||
|
|
||||||
Output: List of all servers, with an entry of the form:
|
Output: List of all servers, with an entry of the form:
|
||||||
|
@ -1247,21 +1201,23 @@ class PlexAPI():
|
||||||
'machineIdentifier': id, Plex server machine identifier
|
'machineIdentifier': id, Plex server machine identifier
|
||||||
'accesstoken': token Access token to this server
|
'accesstoken': token Access token to this server
|
||||||
'baseURL': baseURL scheme://ip:port
|
'baseURL': baseURL scheme://ip:port
|
||||||
|
'ownername' Plex username of PMS owner
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
serverlist = []
|
serverlist = []
|
||||||
for key, value in data[ATV_udid].items():
|
for key, value in data.items():
|
||||||
serverlist.append({
|
serverlist.append({
|
||||||
'name': value['name'],
|
'name': value.get('name'),
|
||||||
'address': value['address'],
|
'address': value.get('address'),
|
||||||
'ip': value['ip'],
|
'ip': value.get('ip'),
|
||||||
'port': value['port'],
|
'port': value.get('port'),
|
||||||
'scheme': value['scheme'],
|
'scheme': value.get('scheme'),
|
||||||
'local': value['local'],
|
'local': value.get('local'),
|
||||||
'owned': value['owned'],
|
'owned': value.get('owned'),
|
||||||
'machineIdentifier': key,
|
'machineIdentifier': key,
|
||||||
'accesstoken': value['accesstoken'],
|
'accesstoken': value.get('accesstoken'),
|
||||||
'baseURL': value['baseURL']
|
'baseURL': value.get('baseURL'),
|
||||||
|
'ownername': value.get('ownername')
|
||||||
})
|
})
|
||||||
return serverlist
|
return serverlist
|
||||||
|
|
||||||
|
@ -2001,6 +1957,7 @@ class API():
|
||||||
return url
|
return url
|
||||||
|
|
||||||
# For Direct Streaming or Transcoding
|
# For Direct Streaming or Transcoding
|
||||||
|
from uuid import uuid4
|
||||||
# Path/key to VIDEO item of xml PMS response is needed, not part
|
# Path/key to VIDEO item of xml PMS response is needed, not part
|
||||||
path = self.item.attrib['key']
|
path = self.item.attrib['key']
|
||||||
transcodePath = self.server + \
|
transcodePath = self.server + \
|
||||||
|
|
|
@ -410,47 +410,38 @@ def getPlexRepeat(kodiRepeat):
|
||||||
|
|
||||||
def PMSHttpsEnabled(url):
|
def PMSHttpsEnabled(url):
|
||||||
"""
|
"""
|
||||||
Returns True if the PMS wants to talk https, False otherwise. None if error
|
Returns True if the PMS can talk https, False otherwise.
|
||||||
occured, e.g. the connection timed out
|
None if error occured, e.g. the connection timed out
|
||||||
|
|
||||||
With with e.g. url=192.168.0.1:32400 (NO http/https)
|
Call 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
|
This is done by GET /identity (returns an error if https is enabled and we
|
||||||
are trying to use http)
|
are trying to use http)
|
||||||
|
|
||||||
Prefers HTTPS over HTTP
|
Prefers HTTPS over HTTP
|
||||||
"""
|
"""
|
||||||
# True if https, False if http
|
doUtils = downloadutils.DownloadUtils().downloadUrl
|
||||||
answer = True
|
res = doUtils('https://%s/identity' % url,
|
||||||
|
authenticate=False,
|
||||||
|
verifySSL=False)
|
||||||
try:
|
try:
|
||||||
# Don't use downloadutils here, otherwise we may get un-authorized!
|
res.attrib
|
||||||
res = requests.get('https://%s/identity' % url,
|
except:
|
||||||
headers={},
|
|
||||||
verify=False,
|
|
||||||
timeout=(3, 10))
|
|
||||||
# Don't verify SSL since we can connect for sure then!
|
|
||||||
except requests.exceptions.ConnectionError as e:
|
|
||||||
# Might have SSL deactivated. Try with http
|
# Might have SSL deactivated. Try with http
|
||||||
|
res = doUtils('http://%s/identity' % url,
|
||||||
|
authenticate=False,
|
||||||
|
verifySSL=False)
|
||||||
try:
|
try:
|
||||||
res = requests.get('http://%s/identity' % url,
|
res.attrib
|
||||||
headers={},
|
except:
|
||||||
timeout=(3, 10))
|
logMsg(title, "Could not contact PMS %s" % url, -1)
|
||||||
except requests.exceptions.ConnectionError as e:
|
|
||||||
logMsg(title, "Server is offline or cannot be reached. Url: %s"
|
|
||||||
", Error message: %s" % (url, e), -1)
|
|
||||||
return None
|
|
||||||
except requests.exceptions.ReadTimeout:
|
|
||||||
logMsg(title, "Server timeout reached for Url %s" % url, -1)
|
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
answer = False
|
# Received a valid XML. Server wants to talk HTTP
|
||||||
except requests.exceptions.ReadTimeout:
|
return False
|
||||||
logMsg(title, "Server timeout reached for Url %s" % url, -1)
|
|
||||||
return None
|
|
||||||
if res.status_code == requests.codes.ok:
|
|
||||||
return answer
|
|
||||||
else:
|
else:
|
||||||
return None
|
# Received a valid XML. Server wants to talk HTTPS
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def GetMachineIdentifier(url):
|
def GetMachineIdentifier(url):
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
import requests
|
import requests
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
|
|
||||||
import xbmcgui
|
from utils import logging, settings, window
|
||||||
|
|
||||||
import utils
|
|
||||||
import clientinfo
|
import clientinfo
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -20,382 +18,258 @@ requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
@utils.logging
|
@logging
|
||||||
class DownloadUtils():
|
class DownloadUtils():
|
||||||
|
"""
|
||||||
|
Manages any up/downloads with PKC. Careful to initiate correctly
|
||||||
|
Use startSession() to initiate.
|
||||||
|
If not initiated, e.g. SSL check will fallback to False
|
||||||
|
"""
|
||||||
|
|
||||||
# Borg - multiple instances, shared state
|
# Borg - multiple instances, shared state
|
||||||
_shared_state = {}
|
_shared_state = {}
|
||||||
|
|
||||||
# Requests session
|
# Requests session
|
||||||
s = None
|
|
||||||
timeout = 30
|
timeout = 30
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__dict__ = self._shared_state
|
self.__dict__ = self._shared_state
|
||||||
|
|
||||||
def setUsername(self, username):
|
def setUsername(self, username):
|
||||||
# Reserved for userclient only
|
"""
|
||||||
|
Reserved for userclient only
|
||||||
|
"""
|
||||||
self.username = username
|
self.username = username
|
||||||
self.logMsg("Set username: %s" % username, 2)
|
self.logMsg("Set username: %s" % username, 0)
|
||||||
|
|
||||||
def setUserId(self, userId):
|
def setUserId(self, userId):
|
||||||
# Reserved for userclient only
|
"""
|
||||||
|
Reserved for userclient only
|
||||||
|
"""
|
||||||
self.userId = userId
|
self.userId = userId
|
||||||
self.logMsg("Set userId: %s" % userId, 2)
|
self.logMsg("Set userId: %s" % userId, 0)
|
||||||
|
|
||||||
def setServer(self, server):
|
def setServer(self, server):
|
||||||
# Reserved for userclient only
|
"""
|
||||||
|
Reserved for userclient only
|
||||||
|
"""
|
||||||
self.server = server
|
self.server = server
|
||||||
self.logMsg("Set server: %s" % server, 2)
|
self.logMsg("Set server: %s" % server, 0)
|
||||||
|
|
||||||
def setToken(self, token):
|
def setToken(self, token):
|
||||||
# Reserved for userclient only
|
"""
|
||||||
|
Reserved for userclient only
|
||||||
|
"""
|
||||||
self.token = token
|
self.token = token
|
||||||
self.logMsg("Set token: xxxxxxx", 2)
|
if token == '':
|
||||||
|
self.logMsg('Set token: empty token!', 0)
|
||||||
def setSSL(self, ssl, sslclient):
|
|
||||||
# Reserved for userclient only
|
|
||||||
self.sslverify = ssl
|
|
||||||
self.sslclient = sslclient
|
|
||||||
self.logMsg("Verify SSL host certificate: %s" % ssl, 2)
|
|
||||||
self.logMsg("SSL client side certificate: %s" % sslclient, 2)
|
|
||||||
|
|
||||||
def postCapabilities(self, deviceId):
|
|
||||||
|
|
||||||
# Post settings to session
|
|
||||||
url = "{server}/emby/Sessions/Capabilities/Full?format=json"
|
|
||||||
data = {
|
|
||||||
|
|
||||||
'PlayableMediaTypes': "Audio,Video",
|
|
||||||
'SupportsMediaControl': True,
|
|
||||||
'SupportedCommands': (
|
|
||||||
|
|
||||||
"MoveUp,MoveDown,MoveLeft,MoveRight,Select,"
|
|
||||||
"Back,ToggleContextMenu,ToggleFullscreen,ToggleOsdMenu,"
|
|
||||||
"GoHome,PageUp,NextLetter,GoToSearch,"
|
|
||||||
"GoToSettings,PageDown,PreviousLetter,TakeScreenshot,"
|
|
||||||
"VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage,"
|
|
||||||
"SetAudioStreamIndex,SetSubtitleStreamIndex,"
|
|
||||||
|
|
||||||
"Mute,Unmute,SetVolume,"
|
|
||||||
"Play,Playstate,PlayNext"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.logMsg("Capabilities URL: %s" % url, 2)
|
|
||||||
self.logMsg("Postdata: %s" % data, 2)
|
|
||||||
|
|
||||||
self.downloadUrl(url, postBody=data, type="POST")
|
|
||||||
self.logMsg("Posted capabilities to %s" % self.server, 2)
|
|
||||||
|
|
||||||
# Attempt at getting sessionId
|
|
||||||
url = "{server}/emby/Sessions?DeviceId=%s&format=json" % deviceId
|
|
||||||
result = self.downloadUrl(url)
|
|
||||||
try:
|
|
||||||
sessionId = result[0]['Id']
|
|
||||||
|
|
||||||
except (KeyError, TypeError):
|
|
||||||
self.logMsg("Failed to retrieve sessionId.", 1)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logMsg("Session: %s" % result, 2)
|
self.logMsg("Set token: xxxxxxx", 0)
|
||||||
self.logMsg("SessionId: %s" % sessionId, 1)
|
|
||||||
utils.window('emby_sessionId', value=sessionId)
|
|
||||||
|
|
||||||
# Post any permanent additional users
|
def setSSL(self, verifySSL=None, certificate=None):
|
||||||
# additionalUsers = utils.settings('additionalUsers')
|
"""
|
||||||
# if additionalUsers:
|
Reserved for userclient only
|
||||||
|
|
||||||
# additionalUsers = additionalUsers.split(',')
|
verifySSL must be 'true' to enable certificate validation
|
||||||
# self.logMsg(
|
|
||||||
# "List of permanent users added to the session: %s"
|
|
||||||
# % additionalUsers, 1)
|
|
||||||
|
|
||||||
# # Get the user list from server to get the userId
|
certificate must be path to certificate or 'None'
|
||||||
# url = "{server}/emby/Users?format=json"
|
"""
|
||||||
# result = self.downloadUrl(url)
|
if verifySSL is None:
|
||||||
|
verifySSL = settings('sslverify')
|
||||||
# for additional in additionalUsers:
|
if certificate is None:
|
||||||
# addUser = additional.decode('utf-8').lower()
|
certificate = settings('sslcert')
|
||||||
|
self.logMsg("Verify SSL certificates set to: %s" % verifySSL, 0)
|
||||||
# # Compare to server users to list of permanent additional users
|
self.logMsg("SSL client side certificate set to: %s" % certificate, 0)
|
||||||
# for user in result:
|
if verifySSL != 'true':
|
||||||
# username = user['Name'].lower()
|
self.s.verify = False
|
||||||
|
if certificate != 'None':
|
||||||
# if username in addUser:
|
self.s.cert = certificate
|
||||||
# userId = user['Id']
|
|
||||||
# url = (
|
|
||||||
# "{server}/emby/Sessions/%s/Users/%s?format=json"
|
|
||||||
# % (sessionId, userId)
|
|
||||||
# )
|
|
||||||
# self.downloadUrl(url, postBody={}, type="POST")
|
|
||||||
|
|
||||||
def startSession(self):
|
def startSession(self):
|
||||||
# User should be authenticated when this method is called
|
"""
|
||||||
client = clientinfo.ClientInfo()
|
User should be authenticated when this method is called (via
|
||||||
|
userclient)
|
||||||
self.deviceId = client.getDeviceId()
|
"""
|
||||||
verify = False
|
|
||||||
|
|
||||||
# If user enabled host certificate verification
|
|
||||||
try:
|
|
||||||
verify = self.sslverify
|
|
||||||
if self.sslclient is not None:
|
|
||||||
verify = self.sslclient
|
|
||||||
except:
|
|
||||||
self.logMsg("Could not load SSL settings.", -1)
|
|
||||||
# Start session
|
# Start session
|
||||||
self.s = requests.Session()
|
self.s = requests.Session()
|
||||||
|
|
||||||
|
client = clientinfo.ClientInfo()
|
||||||
|
self.deviceId = client.getDeviceId()
|
||||||
# Attach authenticated header to the session
|
# Attach authenticated header to the session
|
||||||
self.s.headers = client.getXArgsDeviceInfo()
|
self.s.headers = client.getXArgsDeviceInfo()
|
||||||
self.s.verify = verify
|
self.s.encoding = 'utf-8'
|
||||||
|
# Set SSL settings
|
||||||
|
self.setSSL()
|
||||||
|
|
||||||
|
# Set other stuff
|
||||||
|
self.setServer(window('pms_server'))
|
||||||
|
self.setToken(window('pms_token'))
|
||||||
|
self.setUserId(window('currUserId'))
|
||||||
|
self.setUsername(window('plex_username'))
|
||||||
|
|
||||||
# Retry connections to the server
|
# Retry connections to the server
|
||||||
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||||
self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
|
self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||||
|
|
||||||
self.logMsg("Requests session started on: %s" % self.server, 1)
|
self.logMsg("Requests session started on: %s" % self.server, 0)
|
||||||
|
|
||||||
def stopSession(self):
|
def stopSession(self):
|
||||||
try:
|
try:
|
||||||
self.s.close()
|
self.s.close()
|
||||||
except:
|
except:
|
||||||
self.logMsg("Requests session could not be terminated.", 1)
|
self.logMsg("Requests session could not be terminated.", 0)
|
||||||
|
try:
|
||||||
|
del self.s
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.logMsg('Request session stopped', 0)
|
||||||
|
|
||||||
def getHeader(self, options=None):
|
def getHeader(self, options=None):
|
||||||
try:
|
|
||||||
header = self.s.headers.copy()
|
|
||||||
except:
|
|
||||||
header = clientinfo.ClientInfo().getXArgsDeviceInfo()
|
header = clientinfo.ClientInfo().getXArgsDeviceInfo()
|
||||||
if options is not None:
|
if options is not None:
|
||||||
header.update(options)
|
header.update(options)
|
||||||
return header
|
return header
|
||||||
|
|
||||||
def downloadUrl(self, url, postBody=None, type="GET", parameters=None,
|
def __doDownload(self, s, type, **kwargs):
|
||||||
authenticate=True, headerOptions=None):
|
if type == "GET":
|
||||||
timeout = self.timeout
|
r = s.get(**kwargs)
|
||||||
default_link = ""
|
elif type == "POST":
|
||||||
|
r = s.post(**kwargs)
|
||||||
|
elif type == "DELETE":
|
||||||
|
r = s.delete(**kwargs)
|
||||||
|
elif type == "OPTIONS":
|
||||||
|
r = s.options(**kwargs)
|
||||||
|
elif type == "PUT":
|
||||||
|
r = s.put(**kwargs)
|
||||||
|
return r
|
||||||
|
|
||||||
try:
|
def downloadUrl(self, url, type="GET", postBody=None, parameters=None,
|
||||||
# If user is authenticated
|
authenticate=True, headerOptions=None, verifySSL=True):
|
||||||
if (authenticate):
|
"""
|
||||||
|
Override SSL check with verifySSL=False
|
||||||
|
|
||||||
|
If authenticate=True, existing request session will be used/started
|
||||||
|
Otherwise, 'empty' request will be made
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
False If an error occured
|
||||||
|
True If connection worked but no body was received
|
||||||
|
401, ... integer if PMS answered with HTTP error 401
|
||||||
|
(unauthorized) or other http error codes
|
||||||
|
xml xml etree root object, if applicable
|
||||||
|
JSON json() object, if applicable
|
||||||
|
"""
|
||||||
|
kwargs = {}
|
||||||
|
if authenticate:
|
||||||
# Get requests session
|
# Get requests session
|
||||||
try:
|
try:
|
||||||
s = self.s
|
s = self.s
|
||||||
|
except AttributeError:
|
||||||
|
self.logMsg("Request session does not exist: start one", 0)
|
||||||
|
self.startSession()
|
||||||
|
s = self.s
|
||||||
# Replace for the real values
|
# Replace for the real values
|
||||||
url = url.replace("{server}", self.server)
|
url = url.replace("{server}", self.server)
|
||||||
url = url.replace("{UserId}", self.userId)
|
|
||||||
header = self.getHeader(options=headerOptions)
|
|
||||||
# Prepare request
|
|
||||||
if type == "GET":
|
|
||||||
r = s.get(url, json=postBody, params=parameters, timeout=timeout, headers=header)
|
|
||||||
elif type == "POST":
|
|
||||||
r = s.post(url, json=postBody, timeout=timeout, headers=header)
|
|
||||||
elif type == "DELETE":
|
|
||||||
r = s.delete(url, json=postBody, timeout=timeout, headers=header)
|
|
||||||
elif type == "OPTIONS":
|
|
||||||
r = s.options(url, json=postBody, timeout=timeout, headers=header)
|
|
||||||
# For Plex Companion
|
|
||||||
elif type == "POSTXML":
|
|
||||||
r = s.post(url, postBody, timeout=timeout, headers=header)
|
|
||||||
elif type == "PUT":
|
|
||||||
r = s.put(url, timeout=timeout, headers=header)
|
|
||||||
|
|
||||||
except AttributeError:
|
|
||||||
# request session does not exists
|
|
||||||
self.logMsg("Request session does not exist: start one", 1)
|
|
||||||
# Get user information
|
|
||||||
self.userId = utils.window('currUserId')
|
|
||||||
self.server = utils.window('pms_server')
|
|
||||||
self.token = utils.window('pms_token')
|
|
||||||
header = self.getHeader(options=headerOptions)
|
|
||||||
verifyssl = False
|
|
||||||
cert = None
|
|
||||||
|
|
||||||
# IF user enables ssl verification
|
|
||||||
if utils.settings('sslverify') == "true":
|
|
||||||
verifyssl = True
|
|
||||||
if utils.settings('sslcert') != "None":
|
|
||||||
verifyssl = utils.settings('sslcert')
|
|
||||||
|
|
||||||
# Replace for the real values
|
|
||||||
url = url.replace("{server}", self.server)
|
|
||||||
url = url.replace("{UserId}", self.userId)
|
|
||||||
|
|
||||||
# Prepare request
|
|
||||||
if type == "GET":
|
|
||||||
r = requests.get(url,
|
|
||||||
json=postBody,
|
|
||||||
params=parameters,
|
|
||||||
headers=header,
|
|
||||||
timeout=timeout,
|
|
||||||
verify=verifyssl)
|
|
||||||
|
|
||||||
elif type == "POST":
|
|
||||||
r = requests.post(url,
|
|
||||||
json=postBody,
|
|
||||||
headers=header,
|
|
||||||
timeout=timeout,
|
|
||||||
verify=verifyssl)
|
|
||||||
|
|
||||||
elif type == "DELETE":
|
|
||||||
r = requests.delete(url,
|
|
||||||
json=postBody,
|
|
||||||
headers=header,
|
|
||||||
timeout=timeout,
|
|
||||||
verify=verifyssl)
|
|
||||||
|
|
||||||
elif type == "OPTIONS":
|
|
||||||
r = requests.options(url,
|
|
||||||
json=postBody,
|
|
||||||
headers=header,
|
|
||||||
timeout=timeout,
|
|
||||||
cert=cert,
|
|
||||||
verify=verifyssl)
|
|
||||||
|
|
||||||
elif type == "PUT":
|
|
||||||
r = requests.put(url,
|
|
||||||
json=postBody,
|
|
||||||
headers=header,
|
|
||||||
timeout=timeout,
|
|
||||||
cert=cert,
|
|
||||||
verify=verifyssl)
|
|
||||||
# If user is not authenticated
|
|
||||||
elif not authenticate:
|
|
||||||
|
|
||||||
header = self.getHeader(options=headerOptions)
|
|
||||||
|
|
||||||
# If user enables ssl verification
|
|
||||||
try:
|
|
||||||
verifyssl = self.sslverify
|
|
||||||
if self.sslclient is not None:
|
|
||||||
verifyssl = self.sslclient
|
|
||||||
except AttributeError:
|
|
||||||
if utils.settings('sslverify') == "true":
|
|
||||||
verifyssl = True
|
|
||||||
else:
|
else:
|
||||||
verifyssl = False
|
# User is not (yet) authenticated. Used to communicate with
|
||||||
self.logMsg("Set SSL verification to: %s" % verifyssl, 2)
|
# plex.tv and to check for PMS servers
|
||||||
# Prepare request
|
s = requests
|
||||||
if type == "GET":
|
headerOptions = self.getHeader(options=headerOptions)
|
||||||
r = requests.get(url,
|
kwargs['timeout'] = self.timeout
|
||||||
json=postBody,
|
if settings('sslcert') != 'None':
|
||||||
params=parameters,
|
kwargs['cert'] = settings('sslcert')
|
||||||
headers=header,
|
|
||||||
timeout=timeout,
|
|
||||||
verify=verifyssl)
|
|
||||||
|
|
||||||
elif type == "POST":
|
# Set the variables we were passed (fallback to request session
|
||||||
r = requests.post(url,
|
# otherwise - faster)
|
||||||
json=postBody,
|
kwargs['url'] = url
|
||||||
headers=header,
|
if verifySSL is False:
|
||||||
timeout=timeout,
|
kwargs['verify'] = False
|
||||||
verify=verifyssl)
|
if headerOptions is not None:
|
||||||
|
kwargs['headers'] = headerOptions
|
||||||
elif type == "PUT":
|
if postBody is not None:
|
||||||
r = requests.put(url,
|
kwargs['data'] = postBody
|
||||||
json=postBody,
|
if parameters is not None:
|
||||||
headers=header,
|
kwargs['params'] = parameters
|
||||||
timeout=timeout,
|
|
||||||
verify=verifyssl)
|
|
||||||
##### THE RESPONSE #####
|
|
||||||
# self.logMsg(r.url, 2)
|
|
||||||
if r.status_code == 204:
|
|
||||||
# No body in the response
|
|
||||||
# self.logMsg("====== 204 Success ======", 2)
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif r.status_code == requests.codes.ok:
|
|
||||||
|
|
||||||
|
# ACTUAL DOWNLOAD HAPPENING HERE
|
||||||
try:
|
try:
|
||||||
# Allow for xml responses
|
r = self.__doDownload(s, type, **kwargs)
|
||||||
r = etree.fromstring(r.content)
|
|
||||||
# self.logMsg("====== 200 Success ======", 2)
|
|
||||||
# self.logMsg("Received an XML response for: %s" % url, 2)
|
|
||||||
|
|
||||||
|
# THE EXCEPTIONS
|
||||||
|
except requests.exceptions.ConnectionError as e:
|
||||||
|
# Connection error
|
||||||
|
self.logMsg("Server unreachable at: %s" % url, -1)
|
||||||
|
self.logMsg(e, 2)
|
||||||
|
# Make the addon aware of status
|
||||||
|
window('emby_online', value="false")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except requests.exceptions.ConnectTimeout as e:
|
||||||
|
self.logMsg("Server timeout at: %s" % url, -1)
|
||||||
|
self.logMsg(e, 2)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
r = r.status_code
|
||||||
|
if r == 401:
|
||||||
|
# Unauthorized
|
||||||
|
self.logMsg('Error 401 contacting %s' % url, -1)
|
||||||
|
elif r in (301, 302):
|
||||||
|
# Redirects
|
||||||
|
self.logMsg('HTTP redirect error %s at %s' % (r, url), -1)
|
||||||
|
elif r == 400:
|
||||||
|
# Bad requests
|
||||||
|
self.logMsg('Bad request at %s' % url, -1)
|
||||||
|
else:
|
||||||
|
self.logMsg('HTTP Error %s at %s' % (r, url), -1)
|
||||||
|
self.logMsg(e, 2)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
except requests.exceptions.SSLError as e:
|
||||||
|
self.logMsg("Invalid SSL certificate for: %s" % url, -1)
|
||||||
|
self.logMsg(e, 2)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
self.logMsg("Unknown error connecting to: %s" % url, -1)
|
||||||
|
self.logMsg("Error message: %s" % e, 2)
|
||||||
|
return False
|
||||||
|
|
||||||
except:
|
except:
|
||||||
|
self.logMsg('Unknown requests error', -1)
|
||||||
|
import traceback
|
||||||
|
self.logMsg(traceback.format_exc(), 0)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# THE RESPONSE #####
|
||||||
|
if r.status_code == 204:
|
||||||
|
# No body in the response
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif r.status_code in (200, 201):
|
||||||
|
# 200: OK
|
||||||
|
# 201: Created
|
||||||
|
try:
|
||||||
|
# xml response
|
||||||
|
r = etree.fromstring(r.content)
|
||||||
|
return r
|
||||||
|
except:
|
||||||
|
r.encoding = 'utf-8'
|
||||||
|
if r.text == '':
|
||||||
|
# Answer does not contain a body (even though it should)
|
||||||
|
return True
|
||||||
try:
|
try:
|
||||||
# UNICODE - JSON object
|
# UNICODE - JSON object
|
||||||
r = r.json()
|
r = r.json()
|
||||||
# self.logMsg("====== 200 Success ======", 2)
|
|
||||||
# self.logMsg("Response: %s" % r, 2)
|
|
||||||
return r
|
return r
|
||||||
except:
|
except:
|
||||||
try:
|
self.logMsg("Unable to convert the response for: %s"
|
||||||
if r.text == '' and r.status_code == 200:
|
% url, -1)
|
||||||
# self.logMsg("====== 200 Success ======", 2)
|
self.logMsg("Received headers were: %s" % r.headers, -1)
|
||||||
# self.logMsg("Answer from PMS does not contain a body", 2)
|
|
||||||
pass
|
|
||||||
# self.logMsg("Unable to convert the response for: %s" % url, 2)
|
|
||||||
# self.logMsg("Content-type was: %s" % r.headers['content-type'], 2)
|
|
||||||
except:
|
|
||||||
self.logMsg("Unable to convert the response for: %s" % url, 2)
|
|
||||||
self.logMsg("Content-type was: %s" % r.headers['content-type'], 2)
|
|
||||||
else:
|
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
##### EXCEPTIONS #####
|
|
||||||
|
|
||||||
except requests.exceptions.ConnectionError as e:
|
|
||||||
# Make the addon aware of status
|
|
||||||
if utils.window('emby_online') != "false":
|
|
||||||
self.logMsg("Server unreachable at: %s" % url, -1)
|
|
||||||
self.logMsg(e, 2)
|
|
||||||
utils.window('emby_online', value="false")
|
|
||||||
|
|
||||||
except requests.exceptions.ConnectTimeout as e:
|
|
||||||
self.logMsg("Server timeout at: %s" % url, 0)
|
|
||||||
self.logMsg(e, 1)
|
|
||||||
|
|
||||||
except requests.exceptions.HTTPError as e:
|
|
||||||
|
|
||||||
if r.status_code == 401:
|
|
||||||
# Unauthorized
|
|
||||||
status = utils.window('emby_serverStatus')
|
|
||||||
|
|
||||||
if 'X-Application-Error-Code' in r.headers:
|
|
||||||
# Emby server errors
|
|
||||||
if r.headers['X-Application-Error-Code'] == "ParentalControl":
|
|
||||||
# Parental control - access restricted
|
|
||||||
self.logMsg('Setting emby_serverStatus to restricted')
|
|
||||||
utils.window('emby_serverStatus', value="restricted")
|
|
||||||
xbmcgui.Dialog().notification(
|
|
||||||
heading=self.addonName,
|
|
||||||
message="Access restricted.",
|
|
||||||
icon=xbmcgui.NOTIFICATION_ERROR,
|
|
||||||
time=5000)
|
|
||||||
return False
|
return False
|
||||||
|
else:
|
||||||
elif r.headers['X-Application-Error-Code'] == "UnauthorizedAccessException":
|
self.logMsg('Unknown answer from PMS %s with status code %s. '
|
||||||
# User tried to do something his emby account doesn't allow
|
'Message:' % (url, r.status_code), -1)
|
||||||
pass
|
r.encoding = 'utf-8'
|
||||||
|
self.logMsg(r.text, -1)
|
||||||
elif status not in ("401", "Auth"):
|
return True
|
||||||
# Tell userclient token has been revoked.
|
|
||||||
self.logMsg('Error 401 contacting %s' % url, 0)
|
|
||||||
self.logMsg('Setting emby_serverStatus to 401', 0)
|
|
||||||
utils.window('emby_serverStatus', value="401")
|
|
||||||
self.logMsg("HTTP Error: %s" % e, 0)
|
|
||||||
xbmcgui.Dialog().notification(
|
|
||||||
heading=self.addonName,
|
|
||||||
message="Error connecting: Unauthorized.",
|
|
||||||
icon=xbmcgui.NOTIFICATION_ERROR)
|
|
||||||
return 401
|
|
||||||
|
|
||||||
elif r.status_code in (301, 302):
|
|
||||||
# Redirects
|
|
||||||
pass
|
|
||||||
elif r.status_code == 400:
|
|
||||||
# Bad requests
|
|
||||||
pass
|
|
||||||
|
|
||||||
except requests.exceptions.SSLError as e:
|
|
||||||
self.logMsg("Invalid SSL certificate for: %s" % url, 0)
|
|
||||||
self.logMsg(e, 1)
|
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
self.logMsg("Unknown error connecting to: %s" % url, 0)
|
|
||||||
self.logMsg(e, 1)
|
|
||||||
|
|
||||||
return default_link
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ class InitialSetup():
|
||||||
# SERVER INFO #####
|
# SERVER INFO #####
|
||||||
self.logMsg("Initial setup called.", 0)
|
self.logMsg("Initial setup called.", 0)
|
||||||
server = self.userClient.getServer()
|
server = self.userClient.getServer()
|
||||||
clientId = self.clientInfo.getDeviceId()
|
|
||||||
serverid = utils.settings('plex_machineIdentifier')
|
serverid = utils.settings('plex_machineIdentifier')
|
||||||
# Get Plex credentials from settings file, if they exist
|
# Get Plex credentials from settings file, if they exist
|
||||||
plexdict = self.plx.GetPlexLoginFromSettings()
|
plexdict = self.plx.GetPlexLoginFromSettings()
|
||||||
|
@ -54,8 +53,15 @@ class InitialSetup():
|
||||||
if (plexToken and myplexlogin == 'true' and forcePlexTV is False
|
if (plexToken and myplexlogin == 'true' and forcePlexTV is False
|
||||||
and chooseServer is False):
|
and chooseServer is False):
|
||||||
chk = self.plx.CheckConnection('plex.tv', plexToken)
|
chk = self.plx.CheckConnection('plex.tv', plexToken)
|
||||||
|
try:
|
||||||
|
chk.attrib
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Success - we downloaded an xml!
|
||||||
|
chk = 200
|
||||||
# HTTP Error: unauthorized. Token is no longer valid
|
# HTTP Error: unauthorized. Token is no longer valid
|
||||||
if chk == 401 or chk == 403:
|
if chk in (401, 403):
|
||||||
self.logMsg('plex.tv connection returned HTTP %s' % chk, 0)
|
self.logMsg('plex.tv connection returned HTTP %s' % chk, 0)
|
||||||
# Delete token in the settings
|
# Delete token in the settings
|
||||||
utils.settings('plexToken', value='')
|
utils.settings('plexToken', value='')
|
||||||
|
@ -113,18 +119,13 @@ class InitialSetup():
|
||||||
httpsUpdated = False
|
httpsUpdated = False
|
||||||
while True:
|
while True:
|
||||||
if httpsUpdated is False:
|
if httpsUpdated is False:
|
||||||
tokenDict = {'MyPlexToken': plexToken} if plexToken else {}
|
|
||||||
# Populate g_PMS variable with the found Plex servers
|
# Populate g_PMS variable with the found Plex servers
|
||||||
self.plx.discoverPMS(clientId,
|
self.plx.discoverPMS(xbmc.getIPAddress(),
|
||||||
None,
|
plexToken=plexToken)
|
||||||
xbmc.getIPAddress(),
|
|
||||||
tokenDict=tokenDict)
|
|
||||||
self.logMsg("Result of setting g_PMS variable: %s"
|
|
||||||
% self.plx.g_PMS, 1)
|
|
||||||
isconnected = False
|
isconnected = False
|
||||||
serverlist = self.plx.returnServerList(clientId,
|
self.logMsg('g_PMS: %s' % self.plx.g_PMS, 1)
|
||||||
self.plx.g_PMS)
|
serverlist = self.plx.returnServerList(self.plx.g_PMS)
|
||||||
self.logMsg('PMS serverlist: %s' % serverlist)
|
self.logMsg('PMS serverlist: %s' % serverlist, 2)
|
||||||
# Let user pick server from a list
|
# Let user pick server from a list
|
||||||
# Get a nicer list
|
# Get a nicer list
|
||||||
dialoglist = []
|
dialoglist = []
|
||||||
|
@ -138,11 +139,20 @@ class InitialSetup():
|
||||||
for server in serverlist:
|
for server in serverlist:
|
||||||
if server['local'] == '1':
|
if server['local'] == '1':
|
||||||
# server is in the same network as client. Add "local"
|
# server is in the same network as client. Add "local"
|
||||||
dialoglist.append(
|
msg = string(39022)
|
||||||
server['name']
|
|
||||||
+ string(39022))
|
|
||||||
else:
|
else:
|
||||||
dialoglist.append(server['name'])
|
# Add 'remote'
|
||||||
|
msg = string(39054)
|
||||||
|
if server.get('ownername'):
|
||||||
|
# Display username if its not our PMS
|
||||||
|
dialoglist.append('%s (%s, %s)'
|
||||||
|
% (server['name'],
|
||||||
|
server['ownername'],
|
||||||
|
msg))
|
||||||
|
else:
|
||||||
|
dialoglist.append('%s (%s)'
|
||||||
|
% (server['name'],
|
||||||
|
msg))
|
||||||
resp = dialog.select(string(39012), dialoglist)
|
resp = dialog.select(string(39012), dialoglist)
|
||||||
server = serverlist[resp]
|
server = serverlist[resp]
|
||||||
activeServer = server['machineIdentifier']
|
activeServer = server['machineIdentifier']
|
||||||
|
@ -154,15 +164,20 @@ class InitialSetup():
|
||||||
else:
|
else:
|
||||||
url = server['baseURL']
|
url = server['baseURL']
|
||||||
# Deactive SSL verification if the server is local!
|
# Deactive SSL verification if the server is local!
|
||||||
|
# Watch out - settings is cached by Kodi - use dedicated var!
|
||||||
if server['local'] == '1':
|
if server['local'] == '1':
|
||||||
utils.settings('sslverify', 'false')
|
utils.settings('sslverify', 'false')
|
||||||
self.logMsg("Setting SSL verify to false, because server is "
|
self.logMsg("Setting SSL verify to false, because server is "
|
||||||
"local", 1)
|
"local", 1)
|
||||||
|
verifySSL = False
|
||||||
else:
|
else:
|
||||||
utils.settings('sslverify', 'true')
|
utils.settings('sslverify', 'true')
|
||||||
self.logMsg("Setting SSL verify to true, because server is "
|
self.logMsg("Setting SSL verify to true, because server is "
|
||||||
"not local", 1)
|
"not local", 1)
|
||||||
chk = self.plx.CheckConnection(url, server['accesstoken'])
|
verifySSL = None
|
||||||
|
chk = self.plx.CheckConnection(url,
|
||||||
|
server['accesstoken'],
|
||||||
|
verifySSL=verifySSL)
|
||||||
if chk == 504 and httpsUpdated is False:
|
if chk == 504 and httpsUpdated is False:
|
||||||
# Not able to use HTTP, try HTTPs for now
|
# Not able to use HTTP, try HTTPs for now
|
||||||
serverlist[resp]['scheme'] = 'https'
|
serverlist[resp]['scheme'] = 'https'
|
||||||
|
@ -221,19 +236,6 @@ class InitialSetup():
|
||||||
% (activeServer, server['ip'], server['port'],
|
% (activeServer, server['ip'], server['port'],
|
||||||
server['scheme']), 0)
|
server['scheme']), 0)
|
||||||
|
|
||||||
# ADDITIONAL PROMPTS #####
|
|
||||||
# directPaths = dialog.yesno(
|
|
||||||
# heading="%s: Playback Mode" % self.addonName,
|
|
||||||
# line1=(
|
|
||||||
# "Caution! If you choose Native mode, you "
|
|
||||||
# "will probably lose access to certain Plex "
|
|
||||||
# "features."),
|
|
||||||
# nolabel="Addon (Default)",
|
|
||||||
# yeslabel="Native (Direct Paths)")
|
|
||||||
# if directPaths:
|
|
||||||
# self.logMsg("User opted to use direct paths.", 1)
|
|
||||||
# utils.settings('useDirectPaths', value="1")
|
|
||||||
|
|
||||||
if forcePlexTV is True or chooseServer is True:
|
if forcePlexTV is True or chooseServer is True:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -278,9 +278,8 @@ class Subscriber:
|
||||||
Threaded POST request, because they stall due to PMS response missing
|
Threaded POST request, because they stall due to PMS response missing
|
||||||
the Content-Length header :-(
|
the Content-Length header :-(
|
||||||
"""
|
"""
|
||||||
response = self.download.downloadUrl(
|
response = self.download.downloadUrl(url,
|
||||||
url,
|
|
||||||
postBody=msg,
|
postBody=msg,
|
||||||
type="POSTXML")
|
type="POST")
|
||||||
if response in [False, None, 401]:
|
if response in [False, None, 401]:
|
||||||
self.subMgr.removeSubscriber(self.uuid)
|
self.subMgr.removeSubscriber(self.uuid)
|
||||||
|
|
|
@ -106,29 +106,12 @@ class UserClient(threading.Thread):
|
||||||
|
|
||||||
def getSSLverify(self):
|
def getSSLverify(self):
|
||||||
# Verify host certificate
|
# Verify host certificate
|
||||||
settings = utils.settings
|
return None if utils.settings('sslverify') == 'true' else False
|
||||||
|
|
||||||
s_sslverify = settings('sslverify')
|
|
||||||
if settings('altip') == "true":
|
|
||||||
s_sslverify = settings('secondsslverify')
|
|
||||||
|
|
||||||
if s_sslverify == "true":
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def getSSL(self):
|
def getSSL(self):
|
||||||
# Client side certificate
|
# Client side certificate
|
||||||
settings = utils.settings
|
return None if utils.settings('sslcert') == 'None' \
|
||||||
|
else utils.settings('sslcert')
|
||||||
s_cert = settings('sslcert')
|
|
||||||
if settings('altip') == "true":
|
|
||||||
s_cert = settings('secondsslcert')
|
|
||||||
|
|
||||||
if s_cert == "None":
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return s_cert
|
|
||||||
|
|
||||||
def setUserPref(self):
|
def setUserPref(self):
|
||||||
self.logMsg('Setting user preferences', 0)
|
self.logMsg('Setting user preferences', 0)
|
||||||
|
@ -183,8 +166,9 @@ class UserClient(threading.Thread):
|
||||||
|
|
||||||
if authenticated is False:
|
if authenticated is False:
|
||||||
self.logMsg('Testing validity of current token', 0)
|
self.logMsg('Testing validity of current token', 0)
|
||||||
res = PlexAPI.PlexAPI().CheckConnection(
|
res = PlexAPI.PlexAPI().CheckConnection(self.currServer,
|
||||||
self.currServer, self.currToken)
|
token=self.currToken,
|
||||||
|
verifySSL=self.ssl)
|
||||||
if res is False:
|
if res is False:
|
||||||
self.logMsg('Answer from PMS is not as expected. Retrying', -1)
|
self.logMsg('Answer from PMS is not as expected. Retrying', -1)
|
||||||
return False
|
return False
|
||||||
|
@ -227,13 +211,6 @@ class UserClient(threading.Thread):
|
||||||
window('remapSMB%sOrg' % item, value=org)
|
window('remapSMB%sOrg' % item, value=org)
|
||||||
window('remapSMB%sNew' % item, value=new)
|
window('remapSMB%sNew' % item, value=new)
|
||||||
|
|
||||||
# Set DownloadUtils values
|
|
||||||
doUtils.setUsername(username)
|
|
||||||
doUtils.setUserId(self.currUserId)
|
|
||||||
doUtils.setServer(self.currServer)
|
|
||||||
doUtils.setToken(self.currToken)
|
|
||||||
doUtils.setSSL(self.ssl, self.sslcert)
|
|
||||||
|
|
||||||
# Start DownloadUtils session
|
# Start DownloadUtils session
|
||||||
doUtils.startSession()
|
doUtils.startSession()
|
||||||
# self.getAdditionalUsers()
|
# self.getAdditionalUsers()
|
||||||
|
|
|
@ -233,7 +233,7 @@ class Service():
|
||||||
if server is False:
|
if server is False:
|
||||||
# No server info set in add-on settings
|
# No server info set in add-on settings
|
||||||
pass
|
pass
|
||||||
elif plx.CheckConnection(server) is False:
|
elif plx.CheckConnection(server, verifySSL=True) is False:
|
||||||
# Server is offline or cannot be reached
|
# Server is offline or cannot be reached
|
||||||
# Alert the user and suppress future warning
|
# Alert the user and suppress future warning
|
||||||
if self.server_online:
|
if self.server_online:
|
||||||
|
|
Loading…
Reference in a new issue