Plex home user switch finally working
This commit is contained in:
parent
6e8bd3e7da
commit
eddfa23a71
5 changed files with 205 additions and 200 deletions
|
@ -94,7 +94,6 @@ class PlexAPI():
|
|||
self.server = utils.window('emby_server%s' % self.userId)
|
||||
self.plexLogin = utils.settings('plexLogin')
|
||||
self.plexToken = utils.settings('plexToken')
|
||||
self.machineIdentifier = utils.window('plex_machineIdentifier')
|
||||
|
||||
self.doUtils = downloadutils.DownloadUtils()
|
||||
|
||||
|
@ -102,24 +101,18 @@ class PlexAPI():
|
|||
className = self.__class__.__name__
|
||||
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
|
||||
|
||||
def SetPlexLoginToSettings(self, plexLogin, plexToken):
|
||||
"""
|
||||
Saves retrieved Plex username and Plex token to Kodi settings file.
|
||||
"""
|
||||
utils.settings('plexLogin', value=plexLogin)
|
||||
utils.settings('plexToken', value=plexToken)
|
||||
|
||||
def GetPlexLoginFromSettings(self):
|
||||
"""
|
||||
Returns (myplexlogin, plexLogin, plexToken) from the Kodi file
|
||||
settings. Returns empty strings if not found.
|
||||
Returns empty strings if not found.
|
||||
|
||||
myplexlogin is 'true' if user opted to log into plex.tv (the default)
|
||||
plexhome is 'true' if plex home is used (the default)
|
||||
"""
|
||||
plexLogin = utils.settings('plexLogin')
|
||||
plexToken = utils.settings('plexToken')
|
||||
myplexlogin = utils.settings('myplexlogin')
|
||||
return (myplexlogin, plexLogin, plexToken)
|
||||
plexhome = utils.settings('plexhome')
|
||||
return (myplexlogin, plexhome, plexLogin, plexToken)
|
||||
|
||||
def GetPlexLoginAndPassword(self):
|
||||
"""
|
||||
|
@ -157,12 +150,15 @@ class PlexAPI():
|
|||
plexPassword,
|
||||
{'X-Plex-Client-Identifier': self.clientId}
|
||||
)
|
||||
self.logMsg("plex.tv username and token: %s, %s" % (plexLogin, authtoken), 1)
|
||||
self.logMsg("plex.tv username and token: %s, %s"
|
||||
% (plexLogin, authtoken), 1)
|
||||
if plexLogin == '':
|
||||
dialog = xbmcgui.Dialog()
|
||||
dialog.ok(self.addonName, 'Could not sign in user %s' % plexLogin)
|
||||
dialog.ok(self.addonName, 'Could not sign in user %s'
|
||||
% plexLogin)
|
||||
# Write to Kodi settings file
|
||||
self.SetPlexLoginToSettings(retrievedPlexLogin, authtoken)
|
||||
utils.settings('plexLogin', value=retrievedPlexLogin)
|
||||
utils.settings('plexToken', value=authtoken)
|
||||
return (retrievedPlexLogin, authtoken)
|
||||
|
||||
def PlexTvSignInWithPin(self):
|
||||
|
@ -171,7 +167,7 @@ class PlexAPI():
|
|||
|
||||
Writes username and token to Kodi settings file. Returns:
|
||||
{
|
||||
'home': '1' if Plex Home, '0' otherwise
|
||||
'plexhome': 'true' if Plex Home, 'false' otherwise
|
||||
'username':
|
||||
'avatar': URL to user avator
|
||||
'token':
|
||||
|
@ -207,16 +203,22 @@ class PlexAPI():
|
|||
return False
|
||||
# Parse xml
|
||||
home = xml.get('home', '0')
|
||||
if home == '1':
|
||||
home = 'true'
|
||||
else:
|
||||
home = 'false'
|
||||
username = xml.get('username', '')
|
||||
avatar = xml.get('thumb')
|
||||
token = xml.findtext('authentication-token')
|
||||
result = {
|
||||
'home': home,
|
||||
'plexhome': home,
|
||||
'username': username,
|
||||
'avatar': avatar,
|
||||
'token': token
|
||||
}
|
||||
self.SetPlexLoginToSettings(username, token)
|
||||
utils.settings('plexLogin', value=username)
|
||||
utils.settings('plexToken', value=token)
|
||||
utils.settings('plexhome', value=home)
|
||||
return result
|
||||
|
||||
def CheckPlexTvSignin(self, identifier):
|
||||
|
@ -261,13 +263,17 @@ class PlexAPI():
|
|||
self.logMsg("plex.tv/pin: Identifier is: %s" % identifier, 2)
|
||||
return code, identifier
|
||||
|
||||
def TalkToPlexServer(self, url, talkType="GET", verify=True):
|
||||
def TalkToPlexServer(self, url, talkType="GET", verify=True, token=None):
|
||||
"""
|
||||
Start request with PMS with url.
|
||||
|
||||
Returns the parsed XML answer as an etree object. Or False.
|
||||
Returns the parsed XML answer as an etree object.
|
||||
False if the server could not be reached/timeout occured.
|
||||
False if HTTP error code of >=400 was returned.
|
||||
"""
|
||||
header = self.getXArgsDeviceInfo()
|
||||
if token:
|
||||
header['X-Plex-Token'] = token
|
||||
timeout = (3, 10)
|
||||
try:
|
||||
if talkType == "GET":
|
||||
|
@ -276,6 +282,7 @@ class PlexAPI():
|
|||
params=header,
|
||||
verify=verify,
|
||||
timeout=timeout)
|
||||
# Only seems to be used for initial plex.tv sign in
|
||||
if talkType == "GET2":
|
||||
answer = requests.get(url,
|
||||
headers=header,
|
||||
|
@ -315,46 +322,52 @@ class PlexAPI():
|
|||
def CheckConnection(self, url, token):
|
||||
"""
|
||||
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.
|
||||
|
||||
Input:
|
||||
url URL to Plex server (e.g. https://192.168.1.1:32400)
|
||||
token appropriate token to access server
|
||||
token appropriate token to access server. If None is passed,
|
||||
the current token is used
|
||||
Output:
|
||||
200 if the connection was successfull
|
||||
'' empty string if connection failed for whatever reason
|
||||
401 integer if token has been revoked
|
||||
False if server could not be reached or timeout occured
|
||||
e.g. 200 if connection was successfull
|
||||
int or other HTML status codes as received from the server
|
||||
"""
|
||||
# Add '/clients' to URL because then an authentication is necessary
|
||||
# If a plex.tv URL was passed, this does not work.
|
||||
header = self.getXArgsDeviceInfo()
|
||||
if token is not None:
|
||||
header['X-Plex-Token'] = token
|
||||
sslverify = utils.settings('sslverify')
|
||||
if sslverify == "true":
|
||||
sslverify = True
|
||||
else:
|
||||
sslverify = False
|
||||
self.logMsg("Checking connection to server %s with header %s and "
|
||||
"sslverify=%s" % (url, header, sslverify), 1)
|
||||
timeout = (3, 10)
|
||||
if 'plex.tv' in url:
|
||||
url = 'https://plex.tv/api/home/users'
|
||||
else:
|
||||
url = url + '/library/onDeck'
|
||||
|
||||
if token:
|
||||
self.logMsg("CheckConnection for %s with a token" % url, 0)
|
||||
r = self.doUtils.downloadUrl(
|
||||
url,
|
||||
authenticate=False,
|
||||
headerOptions={'X-Plex-Token': token,
|
||||
'Accept': 'application/json'})
|
||||
else:
|
||||
self.logMsg("CheckConnection for %s without a token" % url, 0)
|
||||
r = self.doUtils.downloadUrl(
|
||||
url,
|
||||
authenticate=False,
|
||||
headerOptions={'Accept': 'application/json'})
|
||||
self.logMsg("Response was: %s" % r, 2)
|
||||
# List of exception returns, when connection failed
|
||||
exceptionlist = [
|
||||
'',
|
||||
401
|
||||
]
|
||||
# To get rid of the stuff that was downloaded :-)
|
||||
if r not in exceptionlist:
|
||||
r = 200
|
||||
return r
|
||||
try:
|
||||
answer = requests.get(url,
|
||||
headers={},
|
||||
params=header,
|
||||
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), -1)
|
||||
return False
|
||||
except requests.exceptions.ReadTimeout:
|
||||
self.logMsg("Server timeout reached for Url %s with header %s"
|
||||
% (url, header), -1)
|
||||
return False
|
||||
result = answer.status_code
|
||||
self.logMsg("Result was: %s" % result, 1)
|
||||
return result
|
||||
|
||||
def GetgPMSKeylist(self):
|
||||
"""
|
||||
|
@ -593,7 +606,6 @@ class PlexAPI():
|
|||
result:
|
||||
self.g_PMS dictionary for ATV_udid
|
||||
"""
|
||||
# Plex: changed CSettings to new function getServerFromSettings()
|
||||
self.g_PMS[ATV_udid] = {}
|
||||
|
||||
# install plex.tv "virtual" PMS - for myPlex, PlexHome
|
||||
|
@ -612,25 +624,27 @@ class PlexAPI():
|
|||
# local PMS
|
||||
# PlexGDM
|
||||
PMS_list = self.PlexGDM()
|
||||
for uuid in PMS_list:
|
||||
PMS = PMS_list[uuid]
|
||||
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)
|
||||
# all servers - update enableGzip
|
||||
for uuid in self.g_PMS.get(ATV_udid, {}):
|
||||
for uuid_id in self.g_PMS.get(ATV_udid, {}):
|
||||
# enable Gzip if not on same host, local&remote PMS depending
|
||||
# on setting
|
||||
enableGzip = (not self.getPMSProperty(ATV_udid, uuid, 'ip') == IP_self) \
|
||||
enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \
|
||||
and (
|
||||
(self.getPMSProperty(ATV_udid, uuid, 'local') == '1'
|
||||
(self.getPMSProperty(ATV_udid, uuid_id, 'local') == '1'
|
||||
and False)
|
||||
or
|
||||
(self.getPMSProperty(ATV_udid, uuid, 'local') == '0'
|
||||
(self.getPMSProperty(ATV_udid, uuid_id, 'local') == '0'
|
||||
and True) == 'True'
|
||||
)
|
||||
self.updatePMSProperty(ATV_udid, uuid, 'enableGzip', enableGzip)
|
||||
self.updatePMSProperty(ATV_udid, uuid_id, 'enableGzip', enableGzip)
|
||||
# Delete plex.tv again
|
||||
del self.g_PMS[ATV_udid]['plex.tv']
|
||||
|
||||
def getPMSListFromMyPlex(self, ATV_udid, authtoken):
|
||||
"""
|
||||
|
@ -668,13 +682,14 @@ class PlexAPI():
|
|||
uri = Con.get('uri')
|
||||
# todo: handle unforeseen - like we get multiple suitable connections. how to choose one?
|
||||
|
||||
# check MyPlex data age - skip if >2 days
|
||||
# check MyPlex data age - skip if >1 days
|
||||
infoAge = time.time() - int(Dir.get('lastSeenAt'))
|
||||
oneDayInSec = 60*60*24
|
||||
if infoAge > 2*oneDayInSec: # two days in seconds -> expiration in setting?
|
||||
dprint(__name__, 1, "Server {0} not updated for {1} days - skipping.", name, infoAge/oneDayInSec)
|
||||
if infoAge > 1*oneDayInSec:
|
||||
self.logMsg("Server %s not updated for 1 day - "
|
||||
"skipping." % name, 0)
|
||||
continue
|
||||
|
||||
|
||||
# poke PMS, own thread for each poke
|
||||
PMSInfo = { 'uuid': uuid, 'name': name, 'token': token, 'owned': owned, 'local': local, \
|
||||
'protocol': protocol, 'ip': ip, 'port': port, 'uri': uri }
|
||||
|
@ -1041,13 +1056,14 @@ class PlexAPI():
|
|||
"""
|
||||
plexLogin = self.plexLogin
|
||||
plexToken = self.plexToken
|
||||
machineIdentifier = utils.settings('plex_machineIdentifier')
|
||||
self.logMsg("Getting user list.", 1)
|
||||
# Get list of Plex home users
|
||||
users = self.MyPlexListHomeUsers(plexToken)
|
||||
# Download users failed. Set username to Plex login
|
||||
if not users:
|
||||
utils.settings('username', value=plexLogin)
|
||||
self.logMsg("User download failed. Set username = plexlogin", 1)
|
||||
self.logMsg("User download failed. Set username = plexlogin", 0)
|
||||
return ('', '', '')
|
||||
|
||||
userlist = []
|
||||
|
@ -1061,10 +1077,12 @@ class PlexAPI():
|
|||
while trials < 3:
|
||||
if usernumber > 1:
|
||||
dialog = xbmcgui.Dialog()
|
||||
user_select = dialog.select(self.addonName + ": Select User", userlist)
|
||||
user_select = dialog.select(self.addonName + ": Select User",
|
||||
userlist)
|
||||
if user_select == -1:
|
||||
self.logMsg("No user selected.", 1)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)'
|
||||
% self.addonId)
|
||||
return ('', '', '')
|
||||
# No Plex home in use - only 1 user
|
||||
else:
|
||||
|
@ -1084,10 +1102,11 @@ class PlexAPI():
|
|||
else:
|
||||
pin = None
|
||||
# Switch to this Plex Home user, if applicable
|
||||
username, usertoken = self.MyPlexSwitchHomeUser(
|
||||
username, usertoken = self.PlexSwitchHomeUser(
|
||||
user['id'],
|
||||
pin,
|
||||
plexToken
|
||||
plexToken,
|
||||
machineIdentifier
|
||||
)
|
||||
# Couldn't get user auth
|
||||
if not username:
|
||||
|
@ -1106,67 +1125,70 @@ class PlexAPI():
|
|||
return ('', '', '', '')
|
||||
return (username, user['id'], usertoken)
|
||||
|
||||
def MyPlexSwitchHomeUser(self, id, pin, authtoken, options={}):
|
||||
def PlexSwitchHomeUser(self, userId, pin, token, machineId):
|
||||
"""
|
||||
Retrieves Plex home token for a Plex home user.
|
||||
|
||||
Input:
|
||||
id id of the Plex home user
|
||||
userId id of the Plex home user
|
||||
pin PIN of the Plex home user, if protected
|
||||
authtoken token for plex.tv
|
||||
options={} optional additional header options
|
||||
token token for plex.tv
|
||||
machineId Plex PMS machineIdentifier
|
||||
|
||||
Output:
|
||||
username Plex home username
|
||||
authtoken token for Plex home user
|
||||
(username, token)
|
||||
|
||||
Returns empty strings if unsuccessful
|
||||
Returns 2 empty strings if unsuccessful
|
||||
"""
|
||||
MyPlexHost = 'https://plex.tv'
|
||||
MyPlexURL = MyPlexHost + '/api/home/users/' + id + '/switch'
|
||||
|
||||
url = 'https://plex.tv/api/home/users/' + userId + '/switch'
|
||||
if pin:
|
||||
MyPlexURL += '?pin=' + pin
|
||||
url += '?pin=' + pin
|
||||
self.logMsg('Switching to user %s with url %s and machineId %s'
|
||||
% (userId, url, machineId), 0)
|
||||
answer = self.TalkToPlexServer(url, talkType="POST", token=token)
|
||||
if not answer:
|
||||
self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
|
||||
return ('', '')
|
||||
|
||||
xargs = {}
|
||||
xargs = self.getXArgsDeviceInfo(options)
|
||||
xargs['X-Plex-Token'] = authtoken
|
||||
username = answer.attrib.get('title', '')
|
||||
token = answer.attrib.get('authenticationToken', '')
|
||||
|
||||
request = urllib2.Request(MyPlexURL, None, xargs)
|
||||
request.get_method = lambda: 'POST'
|
||||
# Get final token
|
||||
url = 'https://plex.tv/pms/servers.xml'
|
||||
answer = self.TalkToPlexServer(url, talkType="GET", token=token)
|
||||
if not answer:
|
||||
self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
|
||||
return ('', '')
|
||||
|
||||
response = urllib2.urlopen(request).read()
|
||||
|
||||
self.logMsg("====== MyPlexHomeUser XML ======", 1)
|
||||
self.logMsg(response, 1)
|
||||
self.logMsg("====== MyPlexHomeUser XML finished ======", 1)
|
||||
|
||||
# analyse response
|
||||
XMLTree = etree.ElementTree(etree.fromstring(response))
|
||||
|
||||
el_user = XMLTree.getroot() # root=<user>. double check?
|
||||
username = el_user.attrib.get('title', '')
|
||||
authtoken = el_user.attrib.get('authenticationToken', '')
|
||||
|
||||
if username and authtoken:
|
||||
self.logMsg('MyPlex switch HomeUser change successfull', 0)
|
||||
else:
|
||||
self.logMsg('MyPlex switch HomeUser change failed', 0)
|
||||
return (username, authtoken)
|
||||
found = 0
|
||||
for child in answer:
|
||||
if child.attrib['machineIdentifier'] == machineId:
|
||||
token = child.attrib['accessToken']
|
||||
self.logMsg('Found a plex home user token', 1)
|
||||
found += 1
|
||||
if found == 0:
|
||||
self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
|
||||
return ('', '')
|
||||
self.logMsg('Plex.tv switch HomeUser change successfull', 0)
|
||||
self.logMsg('username: %s, token: xxxx' % username, 0)
|
||||
return (username, token)
|
||||
|
||||
def MyPlexListHomeUsers(self, authtoken):
|
||||
"""
|
||||
Returns all myPlex home users for the currently signed in account.
|
||||
Returns a list for myPlex home users for the current plex.tv account.
|
||||
|
||||
Input:
|
||||
authtoken for plex.tv
|
||||
options, optional
|
||||
Output:
|
||||
List of users, where one entry is of the form:
|
||||
{
|
||||
"id": userId, "admin": '1'/'0', "guest": '1'/'0',
|
||||
"restricted": '1'/'0', "protected": '1'/'0',
|
||||
"email": email, "title": title, "username": username,
|
||||
"id": userId,
|
||||
"admin": '1'/'0',
|
||||
"guest": '1'/'0',
|
||||
"restricted": '1'/'0',
|
||||
"protected": '1'/'0',
|
||||
"email": email,
|
||||
"title": title,
|
||||
"username": username,
|
||||
"thumb": thumb_url
|
||||
}
|
||||
If any value is missing, None is returned instead (or "" from plex.tv)
|
||||
|
@ -1572,13 +1594,8 @@ class API():
|
|||
except KeyError:
|
||||
pass
|
||||
# Include a letter to prohibit saving as an int!
|
||||
checksum = "K%s%s%s%s%s" % (
|
||||
self.getKey(),
|
||||
item['updatedAt'],
|
||||
item.get('viewCount', ""),
|
||||
item.get('lastViewedAt', ""),
|
||||
item.get('viewOffset', "")
|
||||
)
|
||||
checksum = "K%s%s" % (self.getKey(),
|
||||
item.get('updatedAt', ''))
|
||||
return checksum
|
||||
|
||||
def getKey(self):
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
#################################################################################################
|
||||
|
||||
import json
|
||||
import socket
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
|
@ -21,7 +18,6 @@ import PlexAPI
|
|||
|
||||
class InitialSetup():
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.addon = xbmcaddon.Addon()
|
||||
|
@ -40,19 +36,20 @@ class InitialSetup():
|
|||
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
|
||||
|
||||
def setup(self):
|
||||
# Check server, user, direct paths, music, direct stream if not direct path.
|
||||
string = self.__language__
|
||||
addonId = self.addonId
|
||||
|
||||
"""
|
||||
Initial setup. Run once upon startup.
|
||||
Check server, user, direct paths, music, direct stream if not direct
|
||||
path.
|
||||
"""
|
||||
##### SERVER INFO #####
|
||||
|
||||
self.logMsg("Initial setup called.", 0)
|
||||
server = self.userClient.getServer()
|
||||
clientId = self.clientInfo.getDeviceId()
|
||||
serverid = self.userClient.getServerId()
|
||||
myplexlogin, plexLogin, plexToken = self.plx.GetPlexLoginFromSettings()
|
||||
myplexlogin, plexhome, plexLogin, plexToken = self.plx.GetPlexLoginFromSettings()
|
||||
|
||||
# Optionally sign into plex.tv. Will not be called on very first run
|
||||
# as plexToken will be ''
|
||||
if plexToken and myplexlogin == 'true':
|
||||
chk = self.plx.CheckConnection('plex.tv', plexToken)
|
||||
# HTTP Error: unauthorized
|
||||
|
@ -67,7 +64,7 @@ class InitialSetup():
|
|||
if result:
|
||||
plexLogin = result['username']
|
||||
plexToken = result['token']
|
||||
elif chk == "":
|
||||
elif chk is False or chk >= 400:
|
||||
dialog = xbmcgui.Dialog()
|
||||
dialog.ok(
|
||||
self.addonName,
|
||||
|
@ -77,10 +74,8 @@ class InitialSetup():
|
|||
# If a Plex server IP has already been set, return.
|
||||
if server:
|
||||
self.logMsg("Server is already set.", 0)
|
||||
self.logMsg(
|
||||
"url: %s, Plex machineIdentifier: %s"
|
||||
% (server, serverid),
|
||||
0)
|
||||
self.logMsg("url: %s, Plex machineIdentifier: %s"
|
||||
% (server, serverid), 0)
|
||||
return
|
||||
|
||||
# If not already retrieved myplex info, optionally let user sign in
|
||||
|
@ -98,13 +93,12 @@ class InitialSetup():
|
|||
else:
|
||||
tokenDict = {}
|
||||
# Populate g_PMS variable with the found Plex servers
|
||||
self.plx.discoverPMS(
|
||||
clientId,
|
||||
None,
|
||||
xbmc.getIPAddress(),
|
||||
tokenDict=tokenDict
|
||||
)
|
||||
self.logMsg("Result of setting g_PMS variable: %s" % self.plx.g_PMS, 2)
|
||||
self.plx.discoverPMS(clientId,
|
||||
None,
|
||||
xbmc.getIPAddress(),
|
||||
tokenDict=tokenDict)
|
||||
self.logMsg("Result of setting g_PMS variable: %s"
|
||||
% self.plx.g_PMS, 2)
|
||||
isconnected = False
|
||||
serverlist = self.plx.returnServerList(clientId, self.plx.g_PMS)
|
||||
# Let user pick server from a list
|
||||
|
@ -122,7 +116,7 @@ class InitialSetup():
|
|||
dialoglist.append(str(server['name']))
|
||||
dialog = xbmcgui.Dialog()
|
||||
resp = dialog.select(
|
||||
'Plex server to connect to?',
|
||||
'Choose your Plex server',
|
||||
dialoglist)
|
||||
server = serverlist[resp]
|
||||
activeServer = server['machineIdentifier']
|
||||
|
@ -131,18 +125,19 @@ class InitialSetup():
|
|||
# Deactive SSL verification if the server is local!
|
||||
if server['local'] == '1':
|
||||
self.addon.setSetting('sslverify', 'false')
|
||||
self.logMsg("Setting SSL verify to false, because server is local", 1)
|
||||
self.logMsg("Setting SSL verify to false, because server is "
|
||||
"local", 1)
|
||||
else:
|
||||
self.addon.setSetting('sslverify', 'true')
|
||||
self.logMsg("Setting SSL verify to true, because server is not local", 1)
|
||||
self.logMsg("Setting SSL verify to true, because server is "
|
||||
"not local", 1)
|
||||
chk = self.plx.CheckConnection(url, server['accesstoken'])
|
||||
# Unauthorized
|
||||
if chk == 401:
|
||||
dialog.ok(
|
||||
self.addonName,
|
||||
'Not yet authorized for Plex server %s' % str(server['name']),
|
||||
'Please sign in to plex.tv.'
|
||||
)
|
||||
dialog.ok(self.addonName,
|
||||
'Not yet authorized for Plex server %s'
|
||||
% str(server['name']),
|
||||
'Please sign in to plex.tv.')
|
||||
result = self.plx.PlexTvSignInWithPin()
|
||||
if result:
|
||||
plexLogin = result['username']
|
||||
|
@ -151,13 +146,11 @@ class InitialSetup():
|
|||
# Exit while loop if user cancels
|
||||
break
|
||||
# Problems connecting
|
||||
elif chk == '':
|
||||
elif chk >= 400 or chk is False:
|
||||
dialog = xbmcgui.Dialog()
|
||||
resp = dialog.yesno(
|
||||
self.addonName,
|
||||
'Problems connecting to server.',
|
||||
'Pick another server?'
|
||||
)
|
||||
resp = dialog.yesno(self.addonName,
|
||||
'Problems connecting to server.',
|
||||
'Pick another server?')
|
||||
# Exit while loop if user chooses No
|
||||
if not resp:
|
||||
break
|
||||
|
@ -167,16 +160,20 @@ class InitialSetup():
|
|||
break
|
||||
if not isconnected:
|
||||
# Enter Kodi settings instead
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
|
||||
return
|
||||
# Write to Kodi settings file
|
||||
self.addon.setSetting('serverid', activeServer)
|
||||
self.addon.setSetting('plex_machineIdentifier', activeServer)
|
||||
self.addon.setSetting('ipaddress', server['ip'])
|
||||
self.addon.setSetting('port', server['port'])
|
||||
if server['scheme'] == 'https':
|
||||
self.addon.setSetting('https', 'true')
|
||||
else:
|
||||
self.addon.setSetting('https', 'false')
|
||||
self.logMsg("Wrote to Kodi user settings file:", 0)
|
||||
self.logMsg("PMS machineIdentifier: %s, ip: %s, port: %s, https: %s "
|
||||
% (activeServer, server['ip'], server['port'],
|
||||
server['scheme']), 0)
|
||||
|
||||
##### ADDITIONAL PROMPTS #####
|
||||
dialog = xbmcgui.Dialog()
|
||||
|
|
|
@ -302,25 +302,12 @@ class LibrarySync(threading.Thread):
|
|||
# Save last sync time
|
||||
overlap = 2
|
||||
|
||||
url = "{server}/Emby.Kodi.SyncQueue/GetServerDateTime?format=json"
|
||||
result = self.doUtils.downloadUrl(url)
|
||||
try: # datetime fails when used more than once, TypeError
|
||||
server_time = result['ServerDateTime']
|
||||
server_time = datetime.strptime(server_time, "%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
except Exception as e:
|
||||
# If the server plugin is not installed or an error happened.
|
||||
self.logMsg("An exception occurred: %s" % e, 1)
|
||||
time_now = datetime.utcnow()-timedelta(minutes=overlap)
|
||||
lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
self.logMsg("New sync time: client time -%s min: %s" % (overlap, lastSync), 1)
|
||||
|
||||
else:
|
||||
lastSync = (server_time - timedelta(minutes=overlap)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
self.logMsg("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
|
||||
|
||||
finally:
|
||||
utils.settings('LastIncrementalSync', value=lastSync)
|
||||
self.logMsg("An exception occurred: %s" % e, 1)
|
||||
time_now = datetime.utcnow()-timedelta(minutes=overlap)
|
||||
lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
self.logMsg("New sync time: client time -%s min: %s"
|
||||
% (overlap, lastSync), 1)
|
||||
utils.settings('LastIncrementalSync', value=lastSync)
|
||||
|
||||
def shouldStop(self):
|
||||
# Checkpoint during the syncing process
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
##################################################################################################
|
||||
|
||||
import hashlib
|
||||
import threading
|
||||
|
||||
import xbmc
|
||||
|
@ -10,7 +9,6 @@ import xbmcgui
|
|||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
|
||||
import artwork
|
||||
import utils
|
||||
import clientinfo
|
||||
import downloadutils
|
||||
|
@ -139,12 +137,7 @@ class UserClient(threading.Thread):
|
|||
return server
|
||||
|
||||
def getServerId(self):
|
||||
alternate = utils.settings('altip') == "true"
|
||||
if alternate:
|
||||
# Alternate host
|
||||
serverId = utils.settings('secondserverid')
|
||||
else:
|
||||
serverId = utils.settings('serverid')
|
||||
serverId = utils.settings('plex_machineIdentifier')
|
||||
return serverId
|
||||
|
||||
def getToken(self):
|
||||
|
@ -280,17 +273,17 @@ class UserClient(threading.Thread):
|
|||
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
|
||||
|
||||
username = self.getUsername()
|
||||
userId = utils.settings('userId%s' % username)
|
||||
server = self.getServer()
|
||||
machineIdentifier = self.getServerId()
|
||||
|
||||
# If there's no settings.xml
|
||||
if not hasSettings:
|
||||
self.logMsg("No settings.xml found.", 1)
|
||||
self.logMsg("No settings.xml found.", 0)
|
||||
self.auth = False
|
||||
return
|
||||
# If no user information
|
||||
elif not server:
|
||||
self.logMsg("Missing server information.", 1)
|
||||
self.logMsg("Missing server information.", 0)
|
||||
self.auth = False
|
||||
return
|
||||
# If there's a token, load the user
|
||||
|
@ -302,44 +295,50 @@ class UserClient(threading.Thread):
|
|||
else:
|
||||
self.logMsg("Current user: %s" % self.currUser, 1)
|
||||
self.logMsg("Current userId: %s" % self.currUserId, 1)
|
||||
self.logMsg("Current accessToken: %s" % self.currToken, 2)
|
||||
self.logMsg("Current accessToken: xxxx", 1)
|
||||
return
|
||||
|
||||
##### AUTHENTICATE USER #####
|
||||
|
||||
##### AUTHENTICATE USER #####
|
||||
# Choose Plex user login
|
||||
accessToken = ""
|
||||
myplexlogin = utils.settings('myplexlogin')
|
||||
if myplexlogin == "true":
|
||||
myplexlogin, plexhome, plexLogin, dont_use_accessToken = \
|
||||
plx.GetPlexLoginFromSettings()
|
||||
self.logMsg("myplexlogin: %s, plexhome: %s, plexLogin: %s"
|
||||
% (myplexlogin, plexhome, plexLogin), 2)
|
||||
if myplexlogin == "true" and plexhome == 'true':
|
||||
username, userId, accessToken = plx.ChoosePlexHomeUser()
|
||||
else:
|
||||
# Try connecting without credentials
|
||||
pass
|
||||
self.logMsg("Trying to connect to PMS without a token", 0)
|
||||
accessToken = ''
|
||||
# Check connection
|
||||
if plx.CheckConnection(server, accessToken) == 200:
|
||||
self.currUser = username
|
||||
xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % username)
|
||||
if username:
|
||||
xbmcgui.Dialog().notification(self.addonName, "Welcome %s"
|
||||
% username)
|
||||
else:
|
||||
xbmcgui.Dialog().notification(self.addonName, "Welcome")
|
||||
utils.settings('accessToken', value=accessToken)
|
||||
utils.settings('userId%s' % username, value=userId)
|
||||
self.logMsg("User authenticated with an access token", 1)
|
||||
self.loadCurrUser(authenticated=True)
|
||||
utils.window('emby_serverStatus', clear=True)
|
||||
# Write plex_machineIdentifier to window
|
||||
plex_machineIdentifier = utils.settings('plex_machineIdentifier')
|
||||
utils.windows('plex_machineIdentifier', plex_machineIdentifier)
|
||||
self.retry = 0
|
||||
else:
|
||||
self.logMsg("User authentication failed.", 1)
|
||||
self.logMsg("Error: user authentication failed.", -1)
|
||||
utils.settings('accessToken', value="")
|
||||
utils.settings('userId%s' % username, value="")
|
||||
|
||||
# Give 3 attempts at entering password / selecting user
|
||||
if self.retry == 3:
|
||||
self.logMsg("""Too many retries. You can retry by resetting
|
||||
attempts in the addon settings.""", 1)
|
||||
utils.window('emby_serverStatus', value="Stop")
|
||||
xbmcgui.Dialog().ok(
|
||||
heading=self.addonName,
|
||||
line1="Failed to authenticate too many times.",
|
||||
line2="You can retry by resetting attempts in the addon "
|
||||
"settings.")
|
||||
xbmcgui.Dialog().ok(heading=self.addonName,
|
||||
line1="Failed to authenticate too many"
|
||||
"times.",
|
||||
line2="You can retry by resetting attempts"
|
||||
" in the addon settings.")
|
||||
self.retry += 1
|
||||
self.auth = False
|
||||
|
||||
|
|
|
@ -15,16 +15,21 @@
|
|||
<setting id="secondsslverify" subsetting="true" label="Verify Host SSL Certificate" type="bool" default="true" visible="eq(-1,true)" />
|
||||
<setting id="secondsslcert" subsetting="true" label="Client SSL certificate" type="file" default="None" visible="eq(-2,true)" />
|
||||
<!-- User settings -->
|
||||
<setting id="myplexlogin" label="Log into plex.tv?" type="bool" default="true" />
|
||||
<setting id="plexLogin" label="30024" type="text" default="" visible="eq(-1,true)" />
|
||||
<setting type="sep" />
|
||||
<setting id="deviceNameOpt" label="Use altername Device Name" type="bool" default="false" />
|
||||
<setting id="deviceNameOpt" label="Change device name (friendly name)" type="bool" default="false" />
|
||||
<setting id="deviceName" label="30016" type="text" visible="eq(-1,true)" default="Kodi" />
|
||||
<setting label="[COLOR yellow]Reset login attempts[/COLOR]" type="action" visible="eq(1,) + !eq(-15,)" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=resetauth)" option="close" />
|
||||
<setting id="accessToken" type="text" visible="false" default="" />
|
||||
<setting id="pathsub" type="bool" visible="false" default="false" />
|
||||
</category>
|
||||
|
||||
<category label="plex.tv"><!-- plex.tv -->
|
||||
<!-- Primary address -->
|
||||
<setting id="myplexlogin" label="Log into plex.tv?" type="bool" default="true" />
|
||||
<setting id="plexLogin" label="plex.tv username" type="text" default="" visible="eq(-1,true)" />
|
||||
<setting id="plexhome" label="Plex home in use (don't change this)" type="bool" default="true" />
|
||||
</category>
|
||||
|
||||
<category label="Sync Options">
|
||||
<setting id="dbSyncIndicator" label="Show sync progress" type="bool" default="false" />
|
||||
<setting id="syncEmptyShows" type="bool" label="Sync empty TV Shows" default="false" />
|
||||
|
|
Loading…
Reference in a new issue