Overhaul userclient

Again...
This commit is contained in:
tomkat83 2016-03-09 15:37:27 +01:00
parent 63df69dee9
commit 55b3d44899
9 changed files with 254 additions and 180 deletions

View file

@ -298,6 +298,7 @@
<string id="30533">Duration of the music library pop up (in seconds)</string> <string id="30533">Duration of the music library pop up (in seconds)</string>
<string id="30534">Server messages</string> <string id="30534">Server messages</string>
<string id="30535">Generate a new device Id</string> <string id="30535">Generate a new device Id</string>
<string id="30536">Users must log in every time when Kodi restarts</string>
<!-- service add-on --> <!-- service add-on -->
<string id="33000">Welcome</string> <string id="33000">Welcome</string>

View file

@ -24,6 +24,8 @@
<string id="30521">Bei Wiederaufnahme zurückspulen (in Sekunden)</string> <string id="30521">Bei Wiederaufnahme zurückspulen (in Sekunden)</string>
<string id="30505">[COLOR yellow]Anzahl Login-Versuche zurücksetzen[/COLOR]</string> <string id="30505">[COLOR yellow]Anzahl Login-Versuche zurücksetzen[/COLOR]</string>
<string id="30536">Benutzer müssen sich bei jedem Neustart von Kodi neu anmelden</string>
<string id="30014">Verbindung</string> <string id="30014">Verbindung</string>
<string id="30015">Netzwerk</string> <string id="30015">Netzwerk</string>

View file

@ -92,9 +92,11 @@ class PlexAPI():
'plexToken': utils.settings('plexToken'), 'plexToken': utils.settings('plexToken'),
'plexhome': utils.settings('plexhome'), 'plexhome': utils.settings('plexhome'),
'plexid': utils.settings('plexid'), 'plexid': utils.settings('plexid'),
'myplexlogin': utils.settings('myplexlogin') 'myplexlogin': utils.settings('myplexlogin'),
'plexAvatar': utils.settings('plexAvatar'),
'plexHomeSize': utils.settings('plexHomeSize')
plexLogin is unicode or empty unicode string u'' Returns strings or unicode
Returns empty strings '' for a setting if not found. Returns empty strings '' for a setting if not found.
@ -102,11 +104,13 @@ class PlexAPI():
plexhome is 'true' if plex home is used (the default) plexhome is 'true' if plex home is used (the default)
""" """
return { return {
'plexLogin': utils.settings('plexLogin').decode('utf-8'), 'plexLogin': utils.settings('plexLogin'),
'plexToken': utils.settings('plexToken'), 'plexToken': utils.settings('plexToken'),
'plexhome': utils.settings('plexhome'), 'plexhome': utils.settings('plexhome'),
'plexid': utils.settings('plexid'), 'plexid': utils.settings('plexid'),
'myplexlogin': utils.settings('myplexlogin') 'myplexlogin': utils.settings('myplexlogin'),
'plexAvatar': utils.settings('plexAvatar'),
'plexHomeSize': utils.settings('plexHomeSize')
} }
def GetPlexLoginAndPassword(self): def GetPlexLoginAndPassword(self):
@ -158,12 +162,14 @@ class PlexAPI():
""" """
Prompts user to sign in by visiting https://plex.tv/pin Prompts user to sign in by visiting https://plex.tv/pin
Writes plexhome, username and token to Kodi settings file. Returns: Writes to Kodi settings file. Also returns:
{ {
'plexhome': 'true' if Plex Home, 'false' otherwise 'plexhome': 'true' if Plex Home, 'false' otherwise
'username': 'username':
'avatar': URL to user avator 'avatar': URL to user avator
'token': 'token':
'plexid': Plex user ID
'homesize': Number of Plex home users (defaults to '1')
} }
Returns False if authentication did not work. Returns False if authentication did not work.
""" """
@ -202,19 +208,23 @@ class PlexAPI():
else: else:
home = 'false' 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')
homeSize = xml.get('homeSize', '1')
result = { result = {
'plexhome': home, 'plexhome': home,
'username': username, 'username': username,
'avatar': avatar, 'avatar': avatar,
'token': token, 'token': token,
'plexid': userid 'plexid': userid,
'homesize': homeSize
} }
utils.settings('plexLogin', username) utils.settings('plexLogin', username)
utils.settings('plexToken', token) utils.settings('plexToken', token)
utils.settings('plexhome', home) utils.settings('plexhome', home)
utils.settings('plexid', userid) utils.settings('plexid', userid)
utils.settings('plexAvatar', avatar)
utils.settings('plexHomeSize', homeSize)
# Let Kodi log into plex.tv on startup from now on # Let Kodi log into plex.tv on startup from now on
utils.settings('myplexlogin', 'true') utils.settings('myplexlogin', 'true')
return result return result
@ -334,7 +344,7 @@ class PlexAPI():
# 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() header = self.getXArgsDeviceInfo()
if token is not None: if token:
header['X-Plex-Token'] = token header['X-Plex-Token'] = token
sslverify = utils.settings('sslverify') sslverify = utils.settings('sslverify')
if sslverify == "true": if sslverify == "true":
@ -780,7 +790,7 @@ class PlexAPI():
XML = etree.parse(response) XML = etree.parse(response)
# Log received XML if debugging enabled. # Log received XML if debugging enabled.
self.logMsg("====== received PMS-XML ======", 1) self.logMsg("====== received PMS-XML ======", 1)
self.logMsg(XML.getroot(), 1) self.logMsg(XML, 1)
self.logMsg("====== PMS-XML finished ======", 1) self.logMsg("====== PMS-XML finished ======", 1)
return XML return XML
@ -1050,42 +1060,41 @@ class PlexAPI():
self.logMsg("Avatar url for user %s is: %s" % (username, url), 1) self.logMsg("Avatar url for user %s is: %s" % (username, url), 1)
return url return url
def ChoosePlexHomeUser(self): def ChoosePlexHomeUser(self, plexToken):
""" """
Let's user choose from a list of Plex home users. Will switch to that Let's user choose from a list of Plex home users. Will switch to that
user accordingly. user accordingly.
Output: Returns a dict:
username {
userid 'username': Unicode
authtoken 'userid': '' Plex ID of the user
'token': '' User's token
'protected': True if PIN is needed, else False
}
Will return empty strings if failed. Will return False if something went wrong (wrong PIN, no connection)
""" """
string = self.__language__ string = self.__language__
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
plexLogin = utils.settings('plexLogin')
plexToken = utils.settings('plexToken')
machineIdentifier = utils.settings('plex_machineIdentifier')
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
if not users: if not users:
utils.settings('username', value=plexLogin) self.logMsg("User download failed.", -1)
self.logMsg("User download failed. Set username = plexlogin", 0) return False
return ('', '', '')
userlist = [] userlist = []
userlistCoded = [] userlistCoded = []
for user in users: for user in users:
username = user['title'] username = user['title']
userlist.append(username) userlist.append(username)
# To take care of non-ASCII usernames
userlistCoded.append(username.encode('utf-8')) userlistCoded.append(username.encode('utf-8'))
usernumber = len(userlist) usernumber = len(userlist)
username = ''
usertoken = '' usertoken = ''
# Plex home not in use: only 1 user returned
trials = 0 trials = 0
while trials < 3: while trials < 3:
if usernumber > 1: if usernumber > 1:
@ -1094,58 +1103,62 @@ class PlexAPI():
self.addonName + string(39306), self.addonName + string(39306),
userlistCoded) userlistCoded)
if user_select == -1: if user_select == -1:
self.logMsg("No user selected.", 1) self.logMsg("No user selected.", 0)
utils.settings('username', value='')
xbmc.executebuiltin('Addon.OpenSettings(%s)' xbmc.executebuiltin('Addon.OpenSettings(%s)'
% self.addonId) % self.addonId)
return ('', '', '') return False
# No Plex home in use - only 1 user # Only 1 user received, choose that one
else: else:
user_select = 0 user_select = 0
selected_user = userlist[user_select] selected_user = userlist[user_select]
self.logMsg("Selected user: %s" % selected_user, 1) self.logMsg("Selected user: %s" % selected_user, 0)
utils.settings('username', value=selected_user)
user = users[user_select] user = users[user_select]
# Ask for PIN, if protected: # Ask for PIN, if protected:
pin = None
if user['protected'] == '1': if user['protected'] == '1':
# Please enter pin for user
self.logMsg('Asking for users PIN', 1) self.logMsg('Asking for users PIN', 1)
pin = dialog.input( pin = dialog.input(
string(39307) + selected_user, string(39307) + selected_user,
type=xbmcgui.INPUT_NUMERIC, type=xbmcgui.INPUT_NUMERIC,
option=xbmcgui.ALPHANUM_HIDE_INPUT) option=xbmcgui.ALPHANUM_HIDE_INPUT)
# User chose to cancel # User chose to cancel
if pin is None: # Plex bug: don't call url for protected user with empty PIN
break if not pin:
else: trials += 1
pin = None continue
# Switch to this Plex Home user, if applicable # Switch to this Plex Home user, if applicable
# Plex bug: don't call url for protected user with empty PIN
if user['protected'] == '1' and not pin:
break
username, usertoken = self.PlexSwitchHomeUser( username, usertoken = self.PlexSwitchHomeUser(
user['id'], user['id'],
pin, pin,
plexToken, plexToken,
machineIdentifier utils.settings('plex_machineIdentifier'))
)
# Couldn't get user auth # Couldn't get user auth
if not username: if not username:
trials += 1
# Could not login user, please try again # Could not login user, please try again
if not dialog.yesno(self.addonName, if not dialog.yesno(self.addonName,
string(39308) + selected_user, string(39308) + selected_user,
string(39309)): string(39309)):
# User chose to cancel # User chose to cancel
break break
# Successfully retrieved: break out of while loop
else: else:
# Successfully retrieved username: break out of while loop
break break
trials += trials
if not username:
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
return ('', '', '')
return (username, user['id'], usertoken)
def PlexSwitchHomeUser(self, userId, pin, token, machineId): if not username:
self.logMsg('Failed signing in a user to plex.tv', -1)
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
return False
return {
'username': username,
'userid': user['id'],
'protected': True if user['protected'] == '1' else False,
'token': usertoken
}
def PlexSwitchHomeUser(self, userId, pin, token, machineIdentifier):
""" """
Retrieves Plex home token for a Plex home user. Retrieves Plex home token for a Plex home user.
@ -1153,7 +1166,6 @@ class PlexAPI():
userId 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
token token for plex.tv token token for plex.tv
machineId Plex PMS machineIdentifier
Output: Output:
(username, token) (username, token)
@ -1165,7 +1177,9 @@ class PlexAPI():
url += '?pin=' + pin url += '?pin=' + pin
self.logMsg('Switching to user %s' % userId, 0) self.logMsg('Switching to user %s' % userId, 0)
answer = self.TalkToPlexServer(url, talkType="POST", token=token) answer = self.TalkToPlexServer(url, talkType="POST", token=token)
if not answer: try:
answer.attrib
except:
self.logMsg('Error: plex.tv switch HomeUser change failed', -1) self.logMsg('Error: plex.tv switch HomeUser change failed', -1)
return ('', '') return ('', '')
@ -1173,28 +1187,25 @@ class PlexAPI():
token = answer.attrib.get('authenticationToken', '') token = answer.attrib.get('authenticationToken', '')
# Get final token # Get final token
url = 'https://plex.tv/pms/servers.xml' url = 'https://plex.tv/api/resources?includeHttps=1'
answer = self.TalkToPlexServer(url, talkType="GET", token=token) xml = self.TalkToPlexServer(url, talkType="GET", token=token)
if not answer: try:
self.logMsg('Error: plex.tv switch HomeUser change failed', -1) xml.attrib
except:
self.logMsg('switch HomeUser failed - plex.tv answer wrong', -1)
return ('', '') return ('', '')
found = 0 found = 0
for child in answer: for device in xml:
if child.attrib['machineIdentifier'] == machineId: if device.attrib.get('clientIdentifier') == machineIdentifier:
token = child.attrib['accessToken']
self.logMsg('Found a plex home user token', 1)
found += 1 found += 1
token = device.attrib.get('accessToken')
if found == 0: if found == 0:
self.logMsg('Error: plex.tv switch HomeUser change failed', -1) self.logMsg('No tokens found for your server!', -1)
return ('', '') return ('', '')
self.logMsg('Plex.tv switch HomeUser change successfull', 0) self.logMsg('Plex.tv switch HomeUser change successfull', 0)
self.logMsg("username: %s, token: xxxx. " self.logMsg("username: %s, token: xxxx. " % username, 0)
"Saving to window and file settings" % username, 0)
utils.window('emby_currUser', value=userId)
utils.settings('userId', value=userId)
utils.settings('username', value=username)
utils.window('emby_accessToken%s' % userId, value=token)
return (username, token) return (username, token)
def MyPlexListHomeUsers(self, authtoken): def MyPlexListHomeUsers(self, authtoken):
@ -1218,9 +1229,11 @@ class PlexAPI():
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)
If an error is encountered, False is returned If an error is encountered, False is returned
""" """
XML = self.getXMLFromPMS('https://plex.tv', '/api/home/users/', {}, authtoken) XML = self.getXMLFromPMS(
'https://plex.tv', '/api/home/users/', {}, authtoken)
if not XML: if not XML:
# Download failed; quitting with False self.logMsg('Download of Plex home users failed.', -1)
self.logMsg('plex.tv xml received was: %s' % XML, -1)
return False return False
# analyse response # analyse response
root = XML.getroot() root = XML.getroot()

View file

@ -224,7 +224,8 @@ class DownloadUtils():
# Get user information # Get user information
self.userId = utils.window('emby_currUser') self.userId = utils.window('emby_currUser')
self.server = utils.window('emby_server%s' % self.userId) self.server = utils.window('emby_server%s' % self.userId)
self.token = utils.window('emby_accessToken%s' % self.userId) self.token = utils.window(
'emby_accessToken%s' % self.userId)
header = self.getHeader(options=headerOptions) header = self.getHeader(options=headerOptions)
verifyssl = False verifyssl = False
cert = None cert = None

View file

@ -79,41 +79,61 @@ def reConnect():
string = xbmcaddon.Addon().getLocalizedString string = xbmcaddon.Addon().getLocalizedString
utils.logMsg("entrypoint reConnect", utils.logMsg("entrypoint reConnect",
"Connection resets requested", 0) "Connection resets requested", 0)
# Pause library sync thread - user needs to be auth in order to sync
utils.window('suspend_LibraryThread', value='true')
# Suspend the user client during procedure
utils.window('suspend_Userclient', value='true')
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
dialog.notification( dialog.notification(
heading=addonName, heading=addonName,
message=string(39207), message=string(39207),
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
sound=False) sound=False)
# Pause library sync thread - user needs to be auth in order to sync
utils.window('suspend_LibraryThread', value='true')
# Wait max for 20 seconds for all lib scans to finish # Delete plex credentials in settings
utils.settings('myplexlogin', value="true")
utils.settings('plexLogin', value="")
utils.settings('plexToken', value=""),
utils.settings('plexid', value="")
utils.settings('plexHomeSize', value="")
utils.settings('plexAvatar', value="")
# Wait max for 5 seconds for all lib scans to finish
counter = 0 counter = 0
while utils.window('emby_dbScan') == 'true': while utils.window('emby_dbScan') == 'true':
xbmc.sleep(1000) if counter > 100:
counter += 1
if counter > 20:
dialog.ok( dialog.ok(
heading=addonName, heading=addonName,
message=string(39208), message=string(39208),
) )
# Resuming threads, just in case # Resuming threads, just in case
utils.window('suspend_LibraryThread', clear=True) utils.window('suspend_LibraryThread', clear=True)
utils.window('suspend_Userclient', clear=True)
# Abort reConnection # Abort reConnection
return return
counter += 1
xbmc.sleep(50)
# Log out currently signed in user:
utils.window('emby_serverStatus', value="401")
# Above method needs to have run its course! Hence wait
counter = 0
while utils.window('emby_serverStatus') == "401":
if counter > 100:
dialog.ok(
heading=addonName,
message=string(39208),
)
# Abort reConnection
return
counter += 1
xbmc.sleep(50)
# Suspend the user client during procedure
utils.window('suspend_Userclient', value='true')
import initialsetup import initialsetup
initialsetup.InitialSetup().setup(forcePlexTV=True) initialsetup.InitialSetup().setup(forcePlexTV=True)
# Log out currently signed in user:
utils.window('emby_serverStatus', value="401")
# Restart user client
utils.window('suspend_Userclient', clear=True)
# Request lib sync to get user view data (e.g. watched/unwatched) # Request lib sync to get user view data (e.g. watched/unwatched)
utils.window('plex_runLibScan', value='full') utils.window('plex_runLibScan', value='full')
# Restart user client
utils.window('suspend_Userclient', clear=True)
def PassPlaylist(xml, resume=None): def PassPlaylist(xml, resume=None):
@ -222,7 +242,7 @@ def doMainListing():
addDirectoryItem(label, path) addDirectoryItem(label, path)
# Plex user switch, if Plex home is in use # Plex user switch, if Plex home is in use
if utils.settings('plexhome') == 'true': if int(utils.settings('plexHomeSize')) > 1:
addDirectoryItem(string(39200), addDirectoryItem(string(39200),
"plugin://plugin.video.plexkodiconnect/" "plugin://plugin.video.plexkodiconnect/"
"?mode=switchuser") "?mode=switchuser")

View file

@ -68,6 +68,24 @@ class InitialSetup():
# Problems connecting to plex.tv. Network or internet issue? # Problems connecting to plex.tv. Network or internet issue?
dialog.ok(self.addonName, dialog.ok(self.addonName,
string(39010)) string(39010))
else:
# Successful connected to plex.tv
# Refresh the info from Plex.tv
url = 'https://plex.tv/'
path = 'users/account'
xml = self.plx.getXMLFromPMS(url, path, authtoken=plexToken)
if xml:
xml = xml.getroot()
plexLogin = xml.attrib.get('title')
utils.settings('plexLogin', value=plexLogin)
home = 'true' if xml.attrib.get('home') == '1' else 'false'
utils.settings('plexhome', value=home)
utils.settings('plexAvatar', value=xml.attrib.get('thumb'))
utils.settings(
'plexHomeSize', value=xml.attrib.get('homeSize', '1'))
self.logMsg('Updated Plex info from plex.tv', 0)
else:
self.logMsg('Failed to update Plex info from plex.tv', -1)
# If a Plex server IP has already been set, return. # If a Plex server IP has already been set, return.
if server and forcePlexTV is False: if server and forcePlexTV is False:
self.logMsg("Server is already set.", 0) self.logMsg("Server is already set.", 0)
@ -175,6 +193,7 @@ class InitialSetup():
return return
# Write to Kodi settings file # Write to Kodi settings file
utils.settings('plex_machineIdentifier', activeServer) utils.settings('plex_machineIdentifier', activeServer)
utils.settings('plex_servername', server['name'])
if server['local'] == '1': if server['local'] == '1':
scheme = server['scheme'] scheme = server['scheme']
utils.settings('ipaddress', server['ip']) utils.settings('ipaddress', server['ip'])

View file

@ -111,6 +111,8 @@ class UserClient(threading.Thread):
settings = utils.settings settings = utils.settings
# Original host # Original host
self.machineIdentifier = utils.settings('plex_machineIdentifier')
self.servername = utils.settings('plex_servername')
HTTPS = settings('https') == "true" HTTPS = settings('https') == "true"
host = settings('ipaddress') host = settings('ipaddress')
port = settings('port') port = settings('port')
@ -192,29 +194,17 @@ class UserClient(threading.Thread):
def setUserPref(self): def setUserPref(self):
self.logMsg('Setting user preferences', 0) self.logMsg('Setting user preferences', 0)
url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser) # Only try to get user avatar if there is a token
if url: if self.currToken:
utils.window('EmbyUserImage', value=url) url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser)
if url:
utils.window('EmbyUserImage', value=url)
# Set resume point max # Set resume point max
# url = "{server}/emby/System/Configuration?format=json" # url = "{server}/emby/System/Configuration?format=json"
# result = doUtils.downloadUrl(url) # result = doUtils.downloadUrl(url)
# utils.settings('markPlayed', value=str(result['MaxResumePct'])) # utils.settings('markPlayed', value=str(result['MaxResumePct']))
def getPublicUsers(self):
server = self.getServer()
# Get public Users
url = "%s/emby/Users/Public?format=json" % server
result = self.doUtils.downloadUrl(url, authenticate=False)
if result != "":
return result
else:
# Server connection failed
return False
def hasAccess(self): def hasAccess(self):
# Plex: always return True for now # Plex: always return True for now
return True return True
@ -241,18 +231,15 @@ class UserClient(threading.Thread):
xbmcgui.Dialog().notification(self.addonName, xbmcgui.Dialog().notification(self.addonName,
utils.language(33007)) utils.language(33007))
def loadCurrUser(self, authenticated=False): def loadCurrUser(self, username, userId, usertoken, authenticated=False):
self.logMsg('Loading current user', 0) self.logMsg('Loading current user', 0)
window = utils.window window = utils.window
settings = utils.settings
doUtils = self.doUtils doUtils = self.doUtils
username = self.getUsername()
userId = self.getUserId()
self.currUserId = userId self.currUserId = userId
self.currToken = usertoken
self.currServer = self.getServer() self.currServer = self.getServer()
self.currToken = self.getToken()
self.machineIdentifier = utils.settings('plex_machineIdentifier')
self.ssl = self.getSSLverify() self.ssl = self.getSSLverify()
self.sslcert = self.getSSL() self.sslcert = self.getSSL()
@ -268,7 +255,6 @@ class UserClient(threading.Thread):
return False return False
elif res == 401: elif res == 401:
self.logMsg('Token is no longer valid', -1) self.logMsg('Token is no longer valid', -1)
self.resetClient()
return False return False
elif res >= 400: elif res >= 400:
self.logMsg('Answer from PMS is not as expected. Retrying', -1) self.logMsg('Answer from PMS is not as expected. Retrying', -1)
@ -280,9 +266,7 @@ class UserClient(threading.Thread):
window('emby_accessToken%s' % userId, value=self.currToken) window('emby_accessToken%s' % userId, value=self.currToken)
window('emby_server%s' % userId, value=self.currServer) window('emby_server%s' % userId, value=self.currServer)
window('plex_machineIdentifier', value=self.machineIdentifier) window('plex_machineIdentifier', value=self.machineIdentifier)
window('plex_servername', value=self.servername)
window('emby_serverStatus', clear=True)
window('suspend_LibraryThread', clear=True)
# Set DownloadUtils values # Set DownloadUtils values
doUtils.setUsername(username) doUtils.setUsername(username)
@ -290,8 +274,6 @@ class UserClient(threading.Thread):
doUtils.setServer(self.currServer) doUtils.setServer(self.currServer)
doUtils.setToken(self.currToken) doUtils.setToken(self.currToken)
doUtils.setSSL(self.ssl, self.sslcert) doUtils.setSSL(self.ssl, self.sslcert)
# parental control - let's verify if access is restricted
# self.hasAccess()
# Start DownloadUtils session # Start DownloadUtils session
doUtils.startSession() doUtils.startSession()
@ -299,6 +281,23 @@ class UserClient(threading.Thread):
# Set user preferences in settings # Set user preferences in settings
self.currUser = username self.currUser = username
self.setUserPref() self.setUserPref()
# Writing values to settings file
settings('username', value=username)
settings('userid', value=userId)
settings('accessToken', value=usertoken)
dialog = xbmcgui.Dialog()
if username:
dialog.notification(
heading=self.addonName,
message="Welcome " + username,
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
else:
dialog.notification(
heading=self.addonName,
message="Welcome",
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
return True return True
def authenticate(self): def authenticate(self):
@ -309,6 +308,15 @@ class UserClient(threading.Thread):
settings = utils.settings settings = utils.settings
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
# Give attempts at entering password / selecting user
if self.retry >= 2:
log("Too many retries to login.", -1)
window('emby_serverStatus', value="Stop")
dialog.ok(lang(33001),
lang(39023))
xbmc.executebuiltin(
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
# Get /profile/addon_data # Get /profile/addon_data
addondir = xbmc.translatePath( addondir = xbmc.translatePath(
self.addon.getAddonInfo('profile')).decode('utf-8') self.addon.getAddonInfo('profile')).decode('utf-8')
@ -318,98 +326,94 @@ class UserClient(threading.Thread):
if not hasSettings: if not hasSettings:
log("Error, no settings.xml found.", -1) log("Error, no settings.xml found.", -1)
self.auth = False self.auth = False
return return False
server = self.getServer() server = self.getServer()
# If no user information # If there is no server we can connect to
if not server: if not server:
log("Missing server information.", 0) log("Missing server information.", 0)
self.auth = False self.auth = False
return return False
username = self.getUsername() # If there is a username in the settings, try authenticating
userId = self.getUserId(username) username = settings('username')
# If there's a token, load the user userId = settings('userid')
if self.getToken(username=username, userId=userId): usertoken = settings('accessToken')
if self.loadCurrUser() is False: enforceLogin = settings('enforceUserLogin')
pass # Found a user in the settings, try to authenticate
if username and enforceLogin == 'false':
log('Trying to authenticate with old settings', 0)
if self.loadCurrUser(username,
userId,
usertoken,
authenticated=False):
# SUCCESS: loaded a user from the settings
return True
else: else:
# We successfully loaded a user # Failed to use the settings - delete them!
log("Current user: %s" % self.currUser, 1) log("Failed to use the settings credentials. Deleting them", 1)
log("Current userId: %s" % self.currUserId, 1) settings('username', value='')
log("Current accessToken: xxxx", 1) settings('userid', value='')
return settings('accessToken', value='')
# AUTHENTICATE USER #####
plx = PlexAPI.PlexAPI() plx = PlexAPI.PlexAPI()
# Choose Plex user login
plexdict = plx.GetPlexLoginFromSettings()
myplexlogin = plexdict['myplexlogin']
plexhome = plexdict['plexhome']
if myplexlogin == "true" and plexhome == 'true': # Could not use settings - try to get Plex user list from plex.tv
username, userId, accessToken = plx.ChoosePlexHomeUser() plextoken = settings('plexToken')
else: if plextoken:
log("Trying to connect to PMS without a token", 0) log("Trying to connect to plex.tv to get a user list", 0)
accessToken = '' userInfo = plx.ChoosePlexHomeUser(plextoken)
# Check connection if userInfo is False:
if plx.CheckConnection(server, accessToken) == 200: # FAILURE: Something went wrong, try again
self.currUser = username
settings('accessToken', value=accessToken)
settings('userId', value=userId)
log("User authenticated with an access token", 1)
if self.loadCurrUser(authenticated=True) is False:
# Something went really wrong, return and try again
self.auth = True self.auth = True
self.currUser = None self.retry += 1
return return False
# Success! username = userInfo['username']
if username: userId = userInfo['userid']
dialog.notification( usertoken = userInfo['token']
heading=self.addonName,
message="Welcome " + username,
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
else:
dialog.notification(
heading=self.addonName,
message="Welcome",
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
self.retry = 0
# Make sure that lib sync thread is not paused
else: else:
self.logMsg("Error: user authentication failed.", -1) log("Trying to authenticate without a token", 0)
settings('accessToken', value="") username = ''
settings('userId', value="") userId = ''
usertoken = ''
# Give attempts at entering password / selecting user
if self.retry >= 2:
log("Too many retries to login.", -1)
window('emby_serverStatus', value="Stop")
dialog.ok(lang(33001),
lang(39023))
xbmc.executebuiltin(
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
if self.loadCurrUser(username, userId, usertoken, authenticated=False):
# SUCCESS: loaded a user from the settings
return True
else:
# FAILUR: Something went wrong, try again
self.auth = True
self.retry += 1 self.retry += 1
self.auth = False return False
def resetClient(self): def resetClient(self):
self.logMsg("Reset UserClient authentication.", 1) self.logMsg("Reset UserClient authentication.", 1)
settings = utils.settings
window = utils.window
window('emby_accessToken%s' % self.currUserId, clear=True)
window('emby_server%s' % self.currUserId, clear=True)
window('emby_currUser', clear=True)
window('plex_username', clear=True)
settings('username', value='')
settings('userid', value='')
settings('accessToken', value='')
# Reset token in downloads
self.doUtils.setToken('')
self.doUtils.setUserId('')
self.doUtils.setUsername('')
utils.settings('accessToken', value="")
utils.window('emby_accessToken%s' % self.currUserId, clear=True)
self.currToken = None self.currToken = None
self.logMsg("User token has been removed. Pausing Lib sync thread", 1)
utils.window('suspend_LibraryThread', value="true")
self.auth = True self.auth = True
self.currUser = None self.currUser = None
self.currUserId = None self.currUserId = None
self.retry = 0
def run(self): def run(self):
log = self.logMsg log = self.logMsg
window = utils.window window = utils.window
# Start library sync thread in a suspended mode, until signed in
utils.window('suspend_LibraryThread', value="true")
log("----===## Starting UserClient ##===----", 0) log("----===## Starting UserClient ##===----", 0)
while not self.threadStopped(): while not self.threadStopped():
@ -429,6 +433,7 @@ class UserClient(threading.Thread):
# Unauthorized access, revoke token # Unauthorized access, revoke token
window('emby_serverStatus', value="Auth") window('emby_serverStatus', value="Auth")
self.resetClient() self.resetClient()
xbmc.sleep(2000)
if self.auth and (self.currUser is None): if self.auth and (self.currUser is None):
# Try to authenticate user # Try to authenticate user
@ -436,7 +441,13 @@ class UserClient(threading.Thread):
# Set auth flag because we no longer need # Set auth flag because we no longer need
# to authenticate the user # to authenticate the user
self.auth = False self.auth = False
self.authenticate() if self.authenticate():
log("Current user: %s" % self.currUser, 1)
log("Current userId: %s" % self.currUserId, 1)
log("Current accessToken: xxxx", 1)
self.retry = 0
window('suspend_LibraryThread', clear=True)
window('emby_serverStatus', clear=True)
if not self.auth and (self.currUser is None): if not self.auth and (self.currUser is None):
# Loop if no server found # Loop if no server found

View file

@ -16,7 +16,9 @@
<setting id="secondsslcert" subsetting="true" label="30501" type="file" default="None" visible="eq(-2,true)" /> <setting id="secondsslcert" subsetting="true" label="30501" type="file" default="None" visible="eq(-2,true)" />
<!-- User settings --> <!-- User settings -->
<setting type="sep" /> <setting type="sep" />
<setting id="deviceName" label="30016" type="text" visible="eq(-1,true)" default="Kodi" />
<setting id="enforceUserLogin" label="30536" type="bool" default="false" />
<setting label="30505" type="action" visible="eq(1,) + !eq(-15,)" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=resetauth)" option="close" /> <setting label="30505" type="action" visible="eq(1,) + !eq(-15,)" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=resetauth)" option="close" />
<setting label="30517" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=passwords)" option="close" /><!-- Network credentials --> <setting label="30517" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=passwords)" option="close" /><!-- Network credentials -->
<setting id="accessToken" type="text" visible="false" default="" /> <setting id="accessToken" type="text" visible="false" default="" />
@ -32,11 +34,13 @@
<setting id="plexLogin" label="plex.tv username" type="text" default="" visible="false" /> <setting id="plexLogin" label="plex.tv username" type="text" default="" visible="false" />
<setting id="plexhome" label="Plex home in use" type="bool" default="" visible="false" /> <setting id="plexhome" label="Plex home in use" type="bool" default="" visible="false" />
<setting id="plexToken" label="plexToken" type="text" default="" visible="false" /> <setting id="plexToken" label="plexToken" type="text" default="" visible="false" />
<setting id="plexHomeSize" type="number" default="1" visible="false" />
</category> </category>
<category label="Plex Companion"> <category label="Plex Companion">
<setting type="lsep" label="39008" /> <setting type="lsep" label="39008" />
<setting id="plexCompanion" label="39004" type="bool" default="true" /> <setting id="plexCompanion" label="39004" type="bool" default="true" />
<setting id="deviceNameOpt" label="30504" type="bool" default="false" /> <setting id="deviceNameOpt" label="30504" type="bool" default="false" />
<setting id="deviceName" label="30016" type="text" visible="eq(-1,true)" default="Kodi" />
<setting id="companionPort" label="39005" type="number" default="3005" option="int" visible="eq(-1,true)"/> <setting id="companionPort" label="39005" type="number" default="3005" option="int" visible="eq(-1,true)"/>
<setting id="companionDebugging" label="39006" type="bool" default="false" visible="eq(-3,true)"/> <setting id="companionDebugging" label="39006" type="bool" default="false" visible="eq(-3,true)"/>
<setting id="companionGDMDebugging" label="39007" type="bool" default="false" visible="eq(-4,true)"/> <setting id="companionGDMDebugging" label="39007" type="bool" default="false" visible="eq(-4,true)"/>

View file

@ -254,6 +254,9 @@ class Service():
log("Server is online and ready.", 1) log("Server is online and ready.", 1)
window('emby_online', value="true") window('emby_online', value="true")
# Start library sync thread in a suspended mode
# until signed in
utils.window('suspend_LibraryThread', value="true")
# Start the userclient thread # Start the userclient thread
if not self.userclient_running: if not self.userclient_running:
self.userclient_running = True self.userclient_running = True