Plex home user switch finally working

This commit is contained in:
tomkat83 2016-01-14 14:47:34 +01:00
parent 6e8bd3e7da
commit eddfa23a71
5 changed files with 205 additions and 200 deletions

View file

@ -94,7 +94,6 @@ class PlexAPI():
self.server = utils.window('emby_server%s' % self.userId) self.server = utils.window('emby_server%s' % self.userId)
self.plexLogin = utils.settings('plexLogin') self.plexLogin = utils.settings('plexLogin')
self.plexToken = utils.settings('plexToken') self.plexToken = utils.settings('plexToken')
self.machineIdentifier = utils.window('plex_machineIdentifier')
self.doUtils = downloadutils.DownloadUtils() self.doUtils = downloadutils.DownloadUtils()
@ -102,24 +101,18 @@ class PlexAPI():
className = self.__class__.__name__ className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl) 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): def GetPlexLoginFromSettings(self):
""" """
Returns (myplexlogin, plexLogin, plexToken) from the Kodi file Returns empty strings if not found.
settings. Returns empty strings if not found.
myplexlogin is 'true' if user opted to log into plex.tv (the default) 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') plexLogin = utils.settings('plexLogin')
plexToken = utils.settings('plexToken') plexToken = utils.settings('plexToken')
myplexlogin = utils.settings('myplexlogin') myplexlogin = utils.settings('myplexlogin')
return (myplexlogin, plexLogin, plexToken) plexhome = utils.settings('plexhome')
return (myplexlogin, plexhome, plexLogin, plexToken)
def GetPlexLoginAndPassword(self): def GetPlexLoginAndPassword(self):
""" """
@ -157,12 +150,15 @@ class PlexAPI():
plexPassword, plexPassword,
{'X-Plex-Client-Identifier': self.clientId} {'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 == '': if plexLogin == '':
dialog = xbmcgui.Dialog() 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 # Write to Kodi settings file
self.SetPlexLoginToSettings(retrievedPlexLogin, authtoken) utils.settings('plexLogin', value=retrievedPlexLogin)
utils.settings('plexToken', value=authtoken)
return (retrievedPlexLogin, authtoken) return (retrievedPlexLogin, authtoken)
def PlexTvSignInWithPin(self): def PlexTvSignInWithPin(self):
@ -171,7 +167,7 @@ class PlexAPI():
Writes username and token to Kodi settings file. Returns: Writes username and token to Kodi settings file. Returns:
{ {
'home': '1' if Plex Home, '0' otherwise 'plexhome': 'true' if Plex Home, 'false' otherwise
'username': 'username':
'avatar': URL to user avator 'avatar': URL to user avator
'token': 'token':
@ -207,16 +203,22 @@ class PlexAPI():
return False return False
# Parse xml # Parse xml
home = xml.get('home', '0') home = xml.get('home', '0')
if home == '1':
home = 'true'
else:
home = 'false'
username = xml.get('username', '') username = xml.get('username', '')
avatar = xml.get('thumb') avatar = xml.get('thumb')
token = xml.findtext('authentication-token') token = xml.findtext('authentication-token')
result = { result = {
'home': home, 'plexhome': home,
'username': username, 'username': username,
'avatar': avatar, 'avatar': avatar,
'token': token 'token': token
} }
self.SetPlexLoginToSettings(username, token) utils.settings('plexLogin', value=username)
utils.settings('plexToken', value=token)
utils.settings('plexhome', value=home)
return result return result
def CheckPlexTvSignin(self, identifier): def CheckPlexTvSignin(self, identifier):
@ -261,13 +263,17 @@ class PlexAPI():
self.logMsg("plex.tv/pin: Identifier is: %s" % identifier, 2) self.logMsg("plex.tv/pin: Identifier is: %s" % identifier, 2)
return code, identifier 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. 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() header = self.getXArgsDeviceInfo()
if token:
header['X-Plex-Token'] = token
timeout = (3, 10) timeout = (3, 10)
try: try:
if talkType == "GET": if talkType == "GET":
@ -276,6 +282,7 @@ class PlexAPI():
params=header, params=header,
verify=verify, verify=verify,
timeout=timeout) timeout=timeout)
# Only seems to be used for initial plex.tv sign in
if talkType == "GET2": if talkType == "GET2":
answer = requests.get(url, answer = requests.get(url,
headers=header, headers=header,
@ -315,46 +322,52 @@ class PlexAPI():
def CheckConnection(self, url, token): def CheckConnection(self, url, token):
""" """
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.
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 token appropriate token to access server. If None is passed,
the current token is used
Output: Output:
200 if the connection was successfull False if server could not be reached or timeout occured
'' empty string if connection failed for whatever reason e.g. 200 if connection was successfull
401 integer if token has been revoked 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 = 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: 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'
try:
if token: answer = requests.get(url,
self.logMsg("CheckConnection for %s with a token" % url, 0) headers={},
r = self.doUtils.downloadUrl( params=header,
url, verify=sslverify,
authenticate=False, timeout=timeout)
headerOptions={'X-Plex-Token': token, except requests.exceptions.ConnectionError as e:
'Accept': 'application/json'}) self.logMsg("Server is offline or cannot be reached. Url: %s."
else: "Header: %s. Error message: %s"
self.logMsg("CheckConnection for %s without a token" % url, 0) % (url, header, e), -1)
r = self.doUtils.downloadUrl( return False
url, except requests.exceptions.ReadTimeout:
authenticate=False, self.logMsg("Server timeout reached for Url %s with header %s"
headerOptions={'Accept': 'application/json'}) % (url, header), -1)
self.logMsg("Response was: %s" % r, 2) return False
# List of exception returns, when connection failed result = answer.status_code
exceptionlist = [ self.logMsg("Result was: %s" % result, 1)
'', return result
401
]
# To get rid of the stuff that was downloaded :-)
if r not in exceptionlist:
r = 200
return r
def GetgPMSKeylist(self): def GetgPMSKeylist(self):
""" """
@ -593,7 +606,6 @@ class PlexAPI():
result: result:
self.g_PMS dictionary for ATV_udid self.g_PMS dictionary for ATV_udid
""" """
# Plex: changed CSettings to new function getServerFromSettings()
self.g_PMS[ATV_udid] = {} self.g_PMS[ATV_udid] = {}
# install plex.tv "virtual" PMS - for myPlex, PlexHome # install plex.tv "virtual" PMS - for myPlex, PlexHome
@ -612,25 +624,27 @@ class PlexAPI():
# local PMS # local PMS
# PlexGDM # PlexGDM
PMS_list = self.PlexGDM() PMS_list = self.PlexGDM()
for uuid in PMS_list: for uuid_id in PMS_list:
PMS = PMS_list[uuid] PMS = PMS_list[uuid_id]
self.declarePMS(ATV_udid, PMS['uuid'], PMS['serverName'], 'http', PMS['ip'], PMS['port']) # dflt: token='', local, owned self.declarePMS(ATV_udid, PMS['uuid'], PMS['serverName'], 'http', PMS['ip'], PMS['port']) # dflt: token='', local, owned
else: else:
# MyPlex servers # MyPlex servers
self.getPMSListFromMyPlex(ATV_udid, authtoken) self.getPMSListFromMyPlex(ATV_udid, authtoken)
# all servers - update enableGzip # 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 # enable Gzip if not on same host, local&remote PMS depending
# on setting # on setting
enableGzip = (not self.getPMSProperty(ATV_udid, uuid, 'ip') == IP_self) \ enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \
and ( and (
(self.getPMSProperty(ATV_udid, uuid, 'local') == '1' (self.getPMSProperty(ATV_udid, uuid_id, 'local') == '1'
and False) and False)
or or
(self.getPMSProperty(ATV_udid, uuid, 'local') == '0' (self.getPMSProperty(ATV_udid, uuid_id, 'local') == '0'
and True) == 'True' 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): def getPMSListFromMyPlex(self, ATV_udid, authtoken):
""" """
@ -668,11 +682,12 @@ class PlexAPI():
uri = Con.get('uri') uri = Con.get('uri')
# todo: handle unforeseen - like we get multiple suitable connections. how to choose one? # 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')) infoAge = time.time() - int(Dir.get('lastSeenAt'))
oneDayInSec = 60*60*24 oneDayInSec = 60*60*24
if infoAge > 2*oneDayInSec: # two days in seconds -> expiration in setting? if infoAge > 1*oneDayInSec:
dprint(__name__, 1, "Server {0} not updated for {1} days - skipping.", name, infoAge/oneDayInSec) self.logMsg("Server %s not updated for 1 day - "
"skipping." % name, 0)
continue continue
# poke PMS, own thread for each poke # poke PMS, own thread for each poke
@ -1041,13 +1056,14 @@ class PlexAPI():
""" """
plexLogin = self.plexLogin plexLogin = self.plexLogin
plexToken = self.plexToken plexToken = self.plexToken
machineIdentifier = utils.settings('plex_machineIdentifier')
self.logMsg("Getting user list.", 1) self.logMsg("Getting user list.", 1)
# Get list of Plex home users # Get list of Plex home users
users = self.MyPlexListHomeUsers(plexToken) users = self.MyPlexListHomeUsers(plexToken)
# Download users failed. Set username to Plex login # Download users failed. Set username to Plex login
if not users: if not users:
utils.settings('username', value=plexLogin) utils.settings('username', value=plexLogin)
self.logMsg("User download failed. Set username = plexlogin", 1) self.logMsg("User download failed. Set username = plexlogin", 0)
return ('', '', '') return ('', '', '')
userlist = [] userlist = []
@ -1061,10 +1077,12 @@ class PlexAPI():
while trials < 3: while trials < 3:
if usernumber > 1: if usernumber > 1:
dialog = xbmcgui.Dialog() 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: if user_select == -1:
self.logMsg("No user selected.", 1) self.logMsg("No user selected.", 1)
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)'
% self.addonId)
return ('', '', '') return ('', '', '')
# No Plex home in use - only 1 user # No Plex home in use - only 1 user
else: else:
@ -1084,10 +1102,11 @@ class PlexAPI():
else: else:
pin = None pin = None
# Switch to this Plex Home user, if applicable # Switch to this Plex Home user, if applicable
username, usertoken = self.MyPlexSwitchHomeUser( username, usertoken = self.PlexSwitchHomeUser(
user['id'], user['id'],
pin, pin,
plexToken plexToken,
machineIdentifier
) )
# Couldn't get user auth # Couldn't get user auth
if not username: if not username:
@ -1106,67 +1125,70 @@ class PlexAPI():
return ('', '', '', '') return ('', '', '', '')
return (username, user['id'], usertoken) 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. Retrieves Plex home token for a Plex home user.
Input: Input:
id id of the Plex home user userId id of the Plex home user
pin PIN of the Plex home user, if protected pin PIN of the Plex home user, if protected
authtoken token for plex.tv token token for plex.tv
options={} optional additional header options machineId Plex PMS machineIdentifier
Output: Output:
username Plex home username (username, token)
authtoken token for Plex home user
Returns empty strings if unsuccessful Returns 2 empty strings if unsuccessful
""" """
MyPlexHost = 'https://plex.tv' url = 'https://plex.tv/api/home/users/' + userId + '/switch'
MyPlexURL = MyPlexHost + '/api/home/users/' + id + '/switch'
if pin: 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 = {} username = answer.attrib.get('title', '')
xargs = self.getXArgsDeviceInfo(options) token = answer.attrib.get('authenticationToken', '')
xargs['X-Plex-Token'] = authtoken
request = urllib2.Request(MyPlexURL, None, xargs) # Get final token
request.get_method = lambda: 'POST' 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() found = 0
for child in answer:
self.logMsg("====== MyPlexHomeUser XML ======", 1) if child.attrib['machineIdentifier'] == machineId:
self.logMsg(response, 1) token = child.attrib['accessToken']
self.logMsg("====== MyPlexHomeUser XML finished ======", 1) self.logMsg('Found a plex home user token', 1)
found += 1
# analyse response if found == 0:
XMLTree = etree.ElementTree(etree.fromstring(response)) self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
return ('', '')
el_user = XMLTree.getroot() # root=<user>. double check? self.logMsg('Plex.tv switch HomeUser change successfull', 0)
username = el_user.attrib.get('title', '') self.logMsg('username: %s, token: xxxx' % username, 0)
authtoken = el_user.attrib.get('authenticationToken', '') return (username, token)
if username and authtoken:
self.logMsg('MyPlex switch HomeUser change successfull', 0)
else:
self.logMsg('MyPlex switch HomeUser change failed', 0)
return (username, authtoken)
def MyPlexListHomeUsers(self, authtoken): 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: Input:
authtoken for plex.tv authtoken for plex.tv
options, optional
Output: Output:
List of users, where one entry is of the form: List of users, where one entry is of the form:
{ "id": userId,
"id": userId, "admin": '1'/'0', "guest": '1'/'0', "admin": '1'/'0',
"restricted": '1'/'0', "protected": '1'/'0', "guest": '1'/'0',
"email": email, "title": title, "username": username, "restricted": '1'/'0',
"protected": '1'/'0',
"email": email,
"title": title,
"username": username,
"thumb": thumb_url "thumb": thumb_url
} }
If any value is missing, None is returned instead (or "" from plex.tv) If any value is missing, None is returned instead (or "" from plex.tv)
@ -1572,13 +1594,8 @@ class API():
except KeyError: except KeyError:
pass pass
# Include a letter to prohibit saving as an int! # Include a letter to prohibit saving as an int!
checksum = "K%s%s%s%s%s" % ( checksum = "K%s%s" % (self.getKey(),
self.getKey(), item.get('updatedAt', ''))
item['updatedAt'],
item.get('viewCount', ""),
item.get('lastViewedAt', ""),
item.get('viewOffset', "")
)
return checksum return checksum
def getKey(self): def getKey(self):

View file

@ -2,9 +2,6 @@
################################################################################################# #################################################################################################
import json
import socket
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcaddon import xbmcaddon
@ -21,7 +18,6 @@ import PlexAPI
class InitialSetup(): class InitialSetup():
def __init__(self): def __init__(self):
self.addon = xbmcaddon.Addon() self.addon = xbmcaddon.Addon()
@ -40,19 +36,20 @@ class InitialSetup():
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl) utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def setup(self): def setup(self):
# Check server, user, direct paths, music, direct stream if not direct path. """
string = self.__language__ Initial setup. Run once upon startup.
addonId = self.addonId Check server, user, direct paths, music, direct stream if not direct
path.
"""
##### 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() clientId = self.clientInfo.getDeviceId()
serverid = self.userClient.getServerId() 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 # Optionally sign into plex.tv. Will not be called on very first run
# as plexToken will be ''
if plexToken and myplexlogin == 'true': if plexToken and myplexlogin == 'true':
chk = self.plx.CheckConnection('plex.tv', plexToken) chk = self.plx.CheckConnection('plex.tv', plexToken)
# HTTP Error: unauthorized # HTTP Error: unauthorized
@ -67,7 +64,7 @@ class InitialSetup():
if result: if result:
plexLogin = result['username'] plexLogin = result['username']
plexToken = result['token'] plexToken = result['token']
elif chk == "": elif chk is False or chk >= 400:
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
dialog.ok( dialog.ok(
self.addonName, self.addonName,
@ -77,10 +74,8 @@ class InitialSetup():
# If a Plex server IP has already been set, return. # If a Plex server IP has already been set, return.
if server: if server:
self.logMsg("Server is already set.", 0) self.logMsg("Server is already set.", 0)
self.logMsg( self.logMsg("url: %s, Plex machineIdentifier: %s"
"url: %s, Plex machineIdentifier: %s" % (server, serverid), 0)
% (server, serverid),
0)
return return
# If not already retrieved myplex info, optionally let user sign in # If not already retrieved myplex info, optionally let user sign in
@ -98,13 +93,12 @@ class InitialSetup():
else: else:
tokenDict = {} tokenDict = {}
# Populate g_PMS variable with the found Plex servers # Populate g_PMS variable with the found Plex servers
self.plx.discoverPMS( self.plx.discoverPMS(clientId,
clientId, None,
None, xbmc.getIPAddress(),
xbmc.getIPAddress(), tokenDict=tokenDict)
tokenDict=tokenDict self.logMsg("Result of setting g_PMS variable: %s"
) % self.plx.g_PMS, 2)
self.logMsg("Result of setting g_PMS variable: %s" % self.plx.g_PMS, 2)
isconnected = False isconnected = False
serverlist = self.plx.returnServerList(clientId, self.plx.g_PMS) serverlist = self.plx.returnServerList(clientId, self.plx.g_PMS)
# Let user pick server from a list # Let user pick server from a list
@ -122,7 +116,7 @@ class InitialSetup():
dialoglist.append(str(server['name'])) dialoglist.append(str(server['name']))
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
resp = dialog.select( resp = dialog.select(
'Plex server to connect to?', 'Choose your Plex server',
dialoglist) dialoglist)
server = serverlist[resp] server = serverlist[resp]
activeServer = server['machineIdentifier'] activeServer = server['machineIdentifier']
@ -131,18 +125,19 @@ class InitialSetup():
# Deactive SSL verification if the server is local! # Deactive SSL verification if the server is local!
if server['local'] == '1': if server['local'] == '1':
self.addon.setSetting('sslverify', 'false') 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: else:
self.addon.setSetting('sslverify', 'true') 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']) chk = self.plx.CheckConnection(url, server['accesstoken'])
# Unauthorized # Unauthorized
if chk == 401: if chk == 401:
dialog.ok( dialog.ok(self.addonName,
self.addonName, 'Not yet authorized for Plex server %s'
'Not yet authorized for Plex server %s' % str(server['name']), % str(server['name']),
'Please sign in to plex.tv.' 'Please sign in to plex.tv.')
)
result = self.plx.PlexTvSignInWithPin() result = self.plx.PlexTvSignInWithPin()
if result: if result:
plexLogin = result['username'] plexLogin = result['username']
@ -151,13 +146,11 @@ class InitialSetup():
# Exit while loop if user cancels # Exit while loop if user cancels
break break
# Problems connecting # Problems connecting
elif chk == '': elif chk >= 400 or chk is False:
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
resp = dialog.yesno( resp = dialog.yesno(self.addonName,
self.addonName, 'Problems connecting to server.',
'Problems connecting to server.', 'Pick another server?')
'Pick another server?'
)
# Exit while loop if user chooses No # Exit while loop if user chooses No
if not resp: if not resp:
break break
@ -167,16 +160,20 @@ class InitialSetup():
break break
if not isconnected: if not isconnected:
# Enter Kodi settings instead # Enter Kodi settings instead
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
return return
# Write to Kodi settings file # 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('ipaddress', server['ip'])
self.addon.setSetting('port', server['port']) self.addon.setSetting('port', server['port'])
if server['scheme'] == 'https': if server['scheme'] == 'https':
self.addon.setSetting('https', 'true') self.addon.setSetting('https', 'true')
else: else:
self.addon.setSetting('https', 'false') 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 ##### ##### ADDITIONAL PROMPTS #####
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()

View file

@ -302,25 +302,12 @@ class LibrarySync(threading.Thread):
# Save last sync time # Save last sync time
overlap = 2 overlap = 2
url = "{server}/Emby.Kodi.SyncQueue/GetServerDateTime?format=json" self.logMsg("An exception occurred: %s" % e, 1)
result = self.doUtils.downloadUrl(url) time_now = datetime.utcnow()-timedelta(minutes=overlap)
try: # datetime fails when used more than once, TypeError lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ')
server_time = result['ServerDateTime'] self.logMsg("New sync time: client time -%s min: %s"
server_time = datetime.strptime(server_time, "%Y-%m-%dT%H:%M:%SZ") % (overlap, lastSync), 1)
utils.settings('LastIncrementalSync', value=lastSync)
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)
def shouldStop(self): def shouldStop(self):
# Checkpoint during the syncing process # Checkpoint during the syncing process

View file

@ -2,7 +2,6 @@
################################################################################################## ##################################################################################################
import hashlib
import threading import threading
import xbmc import xbmc
@ -10,7 +9,6 @@ import xbmcgui
import xbmcaddon import xbmcaddon
import xbmcvfs import xbmcvfs
import artwork
import utils import utils
import clientinfo import clientinfo
import downloadutils import downloadutils
@ -139,12 +137,7 @@ class UserClient(threading.Thread):
return server return server
def getServerId(self): def getServerId(self):
alternate = utils.settings('altip') == "true" serverId = utils.settings('plex_machineIdentifier')
if alternate:
# Alternate host
serverId = utils.settings('secondserverid')
else:
serverId = utils.settings('serverid')
return serverId return serverId
def getToken(self): def getToken(self):
@ -280,17 +273,17 @@ class UserClient(threading.Thread):
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir) hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
username = self.getUsername() username = self.getUsername()
userId = utils.settings('userId%s' % username)
server = self.getServer() server = self.getServer()
machineIdentifier = self.getServerId()
# If there's no settings.xml # If there's no settings.xml
if not hasSettings: if not hasSettings:
self.logMsg("No settings.xml found.", 1) self.logMsg("No settings.xml found.", 0)
self.auth = False self.auth = False
return return
# If no user information # If no user information
elif not server: elif not server:
self.logMsg("Missing server information.", 1) self.logMsg("Missing server information.", 0)
self.auth = False self.auth = False
return return
# If there's a token, load the user # If there's a token, load the user
@ -302,44 +295,50 @@ class UserClient(threading.Thread):
else: else:
self.logMsg("Current user: %s" % self.currUser, 1) self.logMsg("Current user: %s" % self.currUser, 1)
self.logMsg("Current userId: %s" % self.currUserId, 1) self.logMsg("Current userId: %s" % self.currUserId, 1)
self.logMsg("Current accessToken: %s" % self.currToken, 2) self.logMsg("Current accessToken: xxxx", 1)
return return
##### AUTHENTICATE USER ##### ##### AUTHENTICATE USER #####
# Choose Plex user login # Choose Plex user login
accessToken = "" myplexlogin, plexhome, plexLogin, dont_use_accessToken = \
myplexlogin = utils.settings('myplexlogin') plx.GetPlexLoginFromSettings()
if myplexlogin == "true": self.logMsg("myplexlogin: %s, plexhome: %s, plexLogin: %s"
% (myplexlogin, plexhome, plexLogin), 2)
if myplexlogin == "true" and plexhome == 'true':
username, userId, accessToken = plx.ChoosePlexHomeUser() username, userId, accessToken = plx.ChoosePlexHomeUser()
else: else:
# Try connecting without credentials self.logMsg("Trying to connect to PMS without a token", 0)
pass accessToken = ''
# Check connection # Check connection
if plx.CheckConnection(server, accessToken) == 200: if plx.CheckConnection(server, accessToken) == 200:
self.currUser = username 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('accessToken', value=accessToken)
utils.settings('userId%s' % username, value=userId) utils.settings('userId%s' % username, value=userId)
self.logMsg("User authenticated with an access token", 1) self.logMsg("User authenticated with an access token", 1)
self.loadCurrUser(authenticated=True) self.loadCurrUser(authenticated=True)
utils.window('emby_serverStatus', clear=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 self.retry = 0
else: else:
self.logMsg("User authentication failed.", 1) self.logMsg("Error: user authentication failed.", -1)
utils.settings('accessToken', value="") utils.settings('accessToken', value="")
utils.settings('userId%s' % username, value="") utils.settings('userId%s' % username, value="")
# Give 3 attempts at entering password / selecting user # Give 3 attempts at entering password / selecting user
if self.retry == 3: 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") utils.window('emby_serverStatus', value="Stop")
xbmcgui.Dialog().ok( xbmcgui.Dialog().ok(heading=self.addonName,
heading=self.addonName, line1="Failed to authenticate too many"
line1="Failed to authenticate too many times.", "times.",
line2="You can retry by resetting attempts in the addon " line2="You can retry by resetting attempts"
"settings.") " in the addon settings.")
self.retry += 1 self.retry += 1
self.auth = False self.auth = False

View file

@ -15,16 +15,21 @@
<setting id="secondsslverify" subsetting="true" label="Verify Host SSL Certificate" type="bool" default="true" visible="eq(-1,true)" /> <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)" /> <setting id="secondsslcert" subsetting="true" label="Client SSL certificate" type="file" default="None" visible="eq(-2,true)" />
<!-- User settings --> <!-- 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 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 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 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="accessToken" type="text" visible="false" default="" />
<setting id="pathsub" type="bool" visible="false" default="false" /> <setting id="pathsub" type="bool" visible="false" default="false" />
</category> </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"> <category label="Sync Options">
<setting id="dbSyncIndicator" label="Show sync progress" type="bool" default="false" /> <setting id="dbSyncIndicator" label="Show sync progress" type="bool" default="false" />
<setting id="syncEmptyShows" type="bool" label="Sync empty TV Shows" default="false" /> <setting id="syncEmptyShows" type="bool" label="Sync empty TV Shows" default="false" />