Overhaul userclient

This commit is contained in:
tomkat83 2016-03-04 13:34:30 +01:00
parent a9a271840e
commit e784dab578
13 changed files with 209 additions and 134 deletions

View file

@ -14,9 +14,16 @@
7. Once you're succesfully authenticated to your Plex server, the initial sync will start. 7. Once you're succesfully authenticated to your Plex server, the initial sync will start.
8. The first sync of the Plex server to local Kodi database may take a LONG time. With my setup (~400 movies, ~600 episodes, couple of Test music albums and a very powerful NAS), sync take approximately 5 minutes. 8. The first sync of the Plex server to local Kodi database may take a LONG time. With my setup (~400 movies, ~600 episodes, couple of Test music albums and a very powerful NAS), sync take approximately 5 minutes.
9. Once the full sync is done, you can browse your media in Kodi, syncs will be automatically done in the background. 9. Once the full sync is done, you can browse your media in Kodi, syncs will be automatically done in the background.
10. Restart!
Again, this is beta. You have been warned. It's a given that you will need to fully resync and reset your setup on a regular basis. Again, this is beta. You have been warned. It's a given that you will need to fully resync and reset your setup on a regular basis.
**Having Problems? Then thanks for your log files**
1. Activate a more detailed logging for KodiPlexConnect: Settings -> Advanced -> "Debug"
2. Follow the instructions here: http://kodi.wiki/view/Log_file/Easy
3. Post the link to your log (that you posted e.g. here: http://xbmclogs.com/) on https://forums.plex.tv/discussion/210023/plexkodiconnect-supercharge-your-plex-kodi-connection
### Welcome to PlexKodiConnect ### Welcome to PlexKodiConnect
**Connect your Plex Media Server to a Kodi Front End** **Connect your Plex Media Server to a Kodi Front End**
@ -44,6 +51,7 @@ Guess what, this is BETA. Currently these features are working:
**Known Issues:** **Known Issues:**
- Windows users: Kodi Helix 14.2 RC1 required - other versions will result in errors with recently added items etc. - Windows users: Kodi Helix 14.2 RC1 required - other versions will result in errors with recently added items etc.
- You must have a static IP address for your Plex media server if you plan to use Plex Music features. This is due to the way Kodi works and cannot be helped. - You must have a static IP address for your Plex media server if you plan to use Plex Music features. This is due to the way Kodi works and cannot be helped.
- PlexKodiConnect continuously polls the Plex Media Server for changes. If something on the PMS changed, this change is synced to Kodi. Hence if you rescan your entire library, a long PlexKodiConnect re-sync is triggered.
- This is a BETA version and could potentially set fire to your Raspi - This is a BETA version and could potentially set fire to your Raspi

View file

@ -8,7 +8,6 @@ import urlparse
import xbmc import xbmc
import xbmcaddon import xbmcaddon
import xbmcgui
################################################################################################# #################################################################################################
@ -67,7 +66,8 @@ class Main:
'refreshplaylist': entrypoint.refreshPlaylist, 'refreshplaylist': entrypoint.refreshPlaylist,
'companion': entrypoint.plexCompanion, 'companion': entrypoint.plexCompanion,
'switchuser': entrypoint.switchPlexUser, 'switchuser': entrypoint.switchPlexUser,
'deviceid': entrypoint.resetDeviceId 'deviceid': entrypoint.resetDeviceId,
'doPlexTvLogin': entrypoint.doPlexTvLogin
} }
if "extrafanart" in sys.argv[0]: if "extrafanart" in sys.argv[0]:

View file

@ -310,7 +310,7 @@
<string id="33007">Access is enabled</string> <string id="33007">Access is enabled</string>
<string id="33008">Enter password for user:</string> <string id="33008">Enter password for user:</string>
<string id="33009">Invalid username or password</string> <string id="33009">Invalid username or password</string>
<string id="33010">Failed to authenticate too many times</string> <string id="33010">Failed to authenticate too many times. Reset in the settings.</string>
<string id="33011">Unable to direct play</string> <string id="33011">Unable to direct play</string>
<string id="33012">Direct play failed 3 times. Enabled play from HTTP.</string> <string id="33012">Direct play failed 3 times. Enabled play from HTTP.</string>
<string id="33013">Choose the audio stream</string> <string id="33013">Choose the audio stream</string>
@ -360,6 +360,11 @@
<string id="39019">[COLOR yellow]Perform local database reset (full resync)[/COLOR]</string> <string id="39019">[COLOR yellow]Perform local database reset (full resync)[/COLOR]</string>
<string id="39020">[COLOR yellow]Cache all images to Kodi texture cache[/COLOR]</string> <string id="39020">[COLOR yellow]Cache all images to Kodi texture cache[/COLOR]</string>
<string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string> <string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string>
<string id="39022"> (local)</string>
<string id="39023">Failed to authenticate. Did you login to plex.tv?</string>
<string id="39024">[COLOR yellow]Log into plex.tv[/COLOR]</string>
<string id="39025">Automatically log into plex.tv on startup</string>
<!-- Plex Entrypoint.py --> <!-- Plex Entrypoint.py -->
<string id="39200">Switch Plex Home User</string> <string id="39200">Switch Plex Home User</string>

View file

@ -250,6 +250,8 @@
<string id="30249">Unterdrücke Server-Verbindungsmeldungen beim Starten</string> <string id="30249">Unterdrücke Server-Verbindungsmeldungen beim Starten</string>
<string id="30250">Benutze lokale Pfade anstelle von Addon-Umleitungen beim Abspielen</string> <string id="30250">Benutze lokale Pfade anstelle von Addon-Umleitungen beim Abspielen</string>
<string id="33010">Plex Media Server Authorisierung ist zu häufig fehlgeschlagen. In den Einstellungen können die Anzahl erfolgloser Versuche zurückgesetzt werden.</string>
<!-- Default views --> <!-- Default views -->
<string id="30300">Aktiviert</string> <string id="30300">Aktiviert</string>
<string id="30301">Zurücksetzen</string> <string id="30301">Zurücksetzen</string>
@ -289,6 +291,10 @@
<string id="39019">[COLOR yellow]Lokale Datenbank zurücksetzen (kompletter Resync nötig)[/COLOR]</string> <string id="39019">[COLOR yellow]Lokale Datenbank zurücksetzen (kompletter Resync nötig)[/COLOR]</string>
<string id="39020">[COLOR yellow]Alle Plex Bilder in Kodi zwischenspeichern[/COLOR]</string> <string id="39020">[COLOR yellow]Alle Plex Bilder in Kodi zwischenspeichern[/COLOR]</string>
<string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string> <string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string>
<string id="39022"> (lokal)</string>
<string id="39023">Plex Media Server Authentifizierung fehlgeschlagen. Haben Sie sich bei plex.tv eingeloggt?</string>
<string id="39024">[COLOR yellow]Bei plex.tv einloggen[/COLOR]</string>
<string id="39025">Automatisch beim Starten bei plex.tv einloggen</string>
<!-- Plex Entrypoint.py --> <!-- Plex Entrypoint.py -->
<string id="39200">Plex Home Benutzer wechseln</string> <string id="39200">Plex Home Benutzer wechseln</string>

View file

@ -88,16 +88,25 @@ class PlexAPI():
def GetPlexLoginFromSettings(self): def GetPlexLoginFromSettings(self):
""" """
Returns empty strings if not found. Returns a dict:
'plexLogin': utils.settings('plexLogin'),
'plexToken': utils.settings('plexToken'),
'plexhome': utils.settings('plexhome'),
'plexid': utils.settings('plexid'),
'myplexlogin': utils.settings('myplexlogin')
Returns empty strings '' for a setting 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) plexhome is 'true' if plex home is used (the default)
""" """
plexLogin = utils.settings('plexLogin') return {
plexToken = utils.settings('plexToken') 'plexLogin': utils.settings('plexLogin'),
myplexlogin = utils.settings('myplexlogin') 'plexToken': utils.settings('plexToken'),
plexhome = utils.settings('plexhome') 'plexhome': utils.settings('plexhome'),
return (myplexlogin, plexhome, plexLogin, plexToken) 'plexid': utils.settings('plexid'),
'myplexlogin': utils.settings('myplexlogin')
}
def GetPlexLoginAndPassword(self): def GetPlexLoginAndPassword(self):
""" """
@ -178,18 +187,19 @@ class PlexAPI():
return False return False
count = 0 count = 0
# Wait for approx 30 seconds (since the PIN is not visible anymore :-)) # Wait for approx 30 seconds (since the PIN is not visible anymore :-))
while count < 6: while count < 30:
xml = self.CheckPlexTvSignin(identifier) xml = self.CheckPlexTvSignin(identifier)
if xml: if xml:
break break
# Wait for 5 seconds # Wait for 1 seconds
xbmc.sleep(5000) xbmc.sleep(1000)
count += 1 count += 1
if not xml: if not xml:
# Could not sign in to plex.tv Try again later # Could not sign in to plex.tv Try again later
dialog.ok(self.addonName, string(39305)) dialog.ok(self.addonName, string(39305))
return False return False
# Parse xml # Parse xml
userid = xml.attrib.get('id')
home = xml.get('home', '0') home = xml.get('home', '0')
if home == '1': if home == '1':
home = 'true' home = 'true'
@ -202,11 +212,15 @@ class PlexAPI():
'plexhome': home, 'plexhome': home,
'username': username, 'username': username,
'avatar': avatar, 'avatar': avatar,
'token': token 'token': token,
'plexid': userid
} }
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)
# Let Kodi log into plex.tv on startup from now on
utils.settings('myplexlogin', 'true')
return result return result
def CheckPlexTvSignin(self, identifier): def CheckPlexTvSignin(self, identifier):
@ -307,7 +321,7 @@ class PlexAPI():
return False return False
return xml return xml
def CheckConnection(self, url, token): def CheckConnection(self, url, token=None):
""" """
Checks connection to a Plex server, available at url. Can also be used Checks connection to a Plex server, available at url. Can also be used
to check for connection with plex.tv. to check for connection with plex.tv.
@ -735,7 +749,6 @@ class PlexAPI():
xargs['X-Plex-Token'] = authtoken xargs['X-Plex-Token'] = authtoken
self.logMsg("URL for XML download: %s%s" % (baseURL, path), 1) self.logMsg("URL for XML download: %s%s" % (baseURL, path), 1)
self.logMsg("xargs: %s" % xargs, 1)
request = urllib2.Request(baseURL+path, None, xargs) request = urllib2.Request(baseURL+path, None, xargs)
request.add_header('User-agent', 'PlexDB') request.add_header('User-agent', 'PlexDB')
@ -1090,11 +1103,14 @@ class PlexAPI():
if user['protected'] == '1': if user['protected'] == '1':
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
# Please enter pin for user # Please enter pin for user
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
if pin is None:
break
else: else:
pin = None pin = None
# Switch to this Plex Home user, if applicable # Switch to this Plex Home user, if applicable
@ -1108,18 +1124,20 @@ class PlexAPI():
if not username: if not username:
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
# Could not login user, please try again # Could not login user, please try again
dialog.ok( if not dialog.yesno(
self.addonName, self.addonName,
string(39308) + selected_user, string(39308) + selected_user,
string(39309) string(39309)
) ):
# User chose to cancel
break
# Successfully retrieved: break out of while loop # Successfully retrieved: break out of while loop
else: else:
break break
trials += trials trials += trials
if not username: if not username:
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
return ('', '', '', '') return ('', '', '')
return (username, user['id'], usertoken) return (username, user['id'], usertoken)
def PlexSwitchHomeUser(self, userId, pin, token, machineId): def PlexSwitchHomeUser(self, userId, pin, token, machineId):

View file

@ -73,6 +73,20 @@ def plexCompanion(fullurl, params):
title, "Not knowing what to do for now - no playQueue sent", -1) title, "Not knowing what to do for now - no playQueue sent", -1)
def doPlexTvLogin():
"""
Triggers login to plex.tv
"""
# Suspend the user client during procedure
utils.window('suspend_Userclient', value='true')
import initialsetup
initialsetup.InitialSetup().setup(forcePlexTV=True)
utils.logMsg("PLEX", "Reset login attempts.", 1)
utils.window('emby_serverStatus', value="Auth")
# Restart user client
utils.window('suspend_Userclient', clear=True)
def PassPlaylist(xml, resume=None): def PassPlaylist(xml, resume=None):
""" """
resume in KodiTime - seconds. resume in KodiTime - seconds.

View file

@ -30,7 +30,7 @@ class InitialSetup():
self.userClient = userclient.UserClient() self.userClient = userclient.UserClient()
self.plx = PlexAPI.PlexAPI() self.plx = PlexAPI.PlexAPI()
def setup(self): def setup(self, forcePlexTV=False):
""" """
Initial setup. Run once upon startup. Initial setup. Run once upon startup.
Check server, user, direct paths, music, direct stream if not direct Check server, user, direct paths, music, direct stream if not direct
@ -42,16 +42,24 @@ class InitialSetup():
server = self.userClient.getServer() server = self.userClient.getServer()
clientId = self.clientInfo.getDeviceId() clientId = self.clientInfo.getDeviceId()
serverid = utils.settings('plex_machineIdentifier') serverid = utils.settings('plex_machineIdentifier')
myplexlogin, plexhome, plexLogin, plexToken = \ # Get Plex credentials from settings file, if they exist
self.plx.GetPlexLoginFromSettings() plexdict = self.plx.GetPlexLoginFromSettings()
myplexlogin = plexdict['myplexlogin']
plexLogin = plexdict['plexLogin']
plexToken = plexdict['plexToken']
plexid = plexdict['plexid']
self.logMsg('Plex info retrieved from settings: %s' % plexdict, 1)
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
# 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 '' # as plexToken will be ''
if plexToken and myplexlogin == 'true': if (plexToken and myplexlogin == 'true' and forcePlexTV is False):
chk = self.plx.CheckConnection('plex.tv', plexToken) chk = self.plx.CheckConnection('plex.tv', plexToken)
# HTTP Error: unauthorized # HTTP Error: unauthorized. Token is no longer valid
if chk == 401: if chk == 401:
# Delete token in the settings
utils.settings('plexToken', value='')
# Could not login, please try again # Could not login, please try again
dialog.ok( dialog.ok(
self.addonName, self.addonName,
@ -61,25 +69,28 @@ class InitialSetup():
if result: if result:
plexLogin = result['username'] plexLogin = result['username']
plexToken = result['token'] plexToken = result['token']
plexid = result['plexid']
elif chk is False or chk >= 400: elif chk is False or chk >= 400:
# Problems connecting to plex.tv. Network or internet issue?
dialog.ok( dialog.ok(
self.addonName, self.addonName,
string(39010) string(39010)
) )
# If a Plex server IP has already been set, return. # If a Plex server IP has already been set, return.
if server: if server and forcePlexTV is False:
self.logMsg("Server is already set.", 0) self.logMsg("Server is already set.", 0)
self.logMsg("url: %s, Plex machineIdentifier: %s" self.logMsg("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
# to plex.tv. # to plex.tv. This DOES get called on very first install run
if not plexToken and myplexlogin == 'true': if ((not plexToken and myplexlogin == 'true') or forcePlexTV):
result = self.plx.PlexTvSignInWithPin() result = self.plx.PlexTvSignInWithPin()
if result: if result:
plexLogin = result['username'] plexLogin = result['username']
plexToken = result['token'] plexToken = result['token']
plexid = result['plexid']
# Get g_PMS list of servers (saved to plx.g_PMS) # Get g_PMS list of servers (saved to plx.g_PMS)
while True: while True:
tokenDict = {'MyPlexToken': plexToken} if plexToken else {} tokenDict = {'MyPlexToken': plexToken} if plexToken else {}
@ -104,8 +115,8 @@ class InitialSetup():
break break
for server in serverlist: for server in serverlist:
if server['local'] == '1': if server['local'] == '1':
# server is in the same network as client # server is in the same network as client. Add "local"
dialoglist.append(str(server['name']) + ' (nearby)') dialoglist.append(str(server['name']) + string(39022))
else: else:
dialoglist.append(str(server['name'])) dialoglist.append(str(server['name']))
resp = dialog.select( resp = dialog.select(
@ -127,6 +138,8 @@ class InitialSetup():
chk = self.plx.CheckConnection(url, server['accesstoken']) chk = self.plx.CheckConnection(url, server['accesstoken'])
# Unauthorized # Unauthorized
if chk == 401: if chk == 401:
# Not yet authorized for Plex server
# Please sign in to plex.tv
dialog.ok(self.addonName, dialog.ok(self.addonName,
string(39013) + str(server['name']), string(39013) + str(server['name']),
string(39014)) string(39014))
@ -134,13 +147,14 @@ class InitialSetup():
if result: if result:
plexLogin = result['username'] plexLogin = result['username']
plexToken = result['token'] plexToken = result['token']
plexid = result['plexid']
else: else:
# Exit while loop if user cancels # Exit while loop if user cancels
break break
# Problems connecting # Problems connecting
elif chk >= 400 or chk is False: elif chk >= 400 or chk is False:
resp = dialog.yesno(self.addonName, # Problems connecting to server. Pick another server?
string(39015)) resp = dialog.yesno(self.addonName, string(39015))
# Exit while loop if user chooses No # Exit while loop if user chooses No
if not resp: if not resp:
break break
@ -150,6 +164,11 @@ class InitialSetup():
break break
if not isconnected: if not isconnected:
# Enter Kodi settings instead # Enter Kodi settings instead
if dialog.yesno(
heading=self.addonName,
line1=string(39016)):
self.logMsg("User opted to disable Plex music library.", 1)
utils.settings('enableMusic', value="false")
xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
return return
# Write to Kodi settings file # Write to Kodi settings file
@ -160,7 +179,7 @@ class InitialSetup():
utils.settings('https', 'true') utils.settings('https', 'true')
else: else:
utils.settings('https', 'false') utils.settings('https', 'false')
self.logMsg("Wrote to Kodi user settings file:", 0) self.logMsg("Writing to Kodi user settings file", 0)
self.logMsg("PMS machineIdentifier: %s, ip: %s, port: %s, https: %s " self.logMsg("PMS machineIdentifier: %s, ip: %s, port: %s, https: %s "
% (activeServer, server['ip'], server['port'], % (activeServer, server['ip'], server['port'],
server['scheme']), 0) server['scheme']), 0)
@ -178,6 +197,9 @@ class InitialSetup():
# self.logMsg("User opted to use direct paths.", 1) # self.logMsg("User opted to use direct paths.", 1)
# utils.settings('useDirectPaths', value="1") # utils.settings('useDirectPaths', value="1")
if forcePlexTV:
return
if dialog.yesno( if dialog.yesno(
heading=self.addonName, heading=self.addonName,
line1=string(39016)): line1=string(39016)):

View file

@ -369,7 +369,6 @@ class Movies(Items):
if extra['extraType'] == '1': if extra['extraType'] == '1':
trailer = ("plugin://plugin.video.plexkodiconnect/trailer/?" trailer = ("plugin://plugin.video.plexkodiconnect/trailer/?"
"id=%s&mode=play") % extra['key'] "id=%s&mode=play") % extra['key']
self.logMsg("Trailer for %s: %s" % (itemid, trailer), 2)
break break
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
@ -403,9 +402,7 @@ class Movies(Items):
# Set plugin path and media flags using real filename # Set plugin path and media flags using real filename
path = "plugin://plugin.video.plexkodiconnect.movies/" path = "plugin://plugin.video.plexkodiconnect.movies/"
params = { params = {
'filename': filename.encode('utf-8'),
#'filename': filename.encode('utf-8'),
'filename': filename,
'id': itemid, 'id': itemid,
'dbid': movieid, 'dbid': movieid,
'mode': "play" 'mode': "play"
@ -1257,7 +1254,7 @@ class TVShows(Items):
params = { params = {
#'filename': filename.encode('utf-8'), #'filename': filename.encode('utf-8'),
'filename': filename, 'filename': filename.encode('utf-8'),
'id': itemid, 'id': itemid,
'dbid': episodeid, 'dbid': episodeid,
'mode': "play" 'mode': "play"

View file

@ -165,7 +165,9 @@ class ThreadedShowSyncInfo(Thread):
downloadLock = self.locks[0] downloadLock = self.locks[0]
processLock = self.locks[1] processLock = self.locks[1]
dialog.create("%s: Sync %s: %s items" dialog.create("%s: Sync %s: %s items"
% (self.addonName, self.itemType, str(total)), % (self.addonName.encode('utf-8'),
self.itemType.encode('utf-8'),
str(total)),
"Starting") "Starting")
global getMetadataCount global getMetadataCount
global processMetadataCount global processMetadataCount
@ -188,7 +190,7 @@ class ThreadedShowSyncInfo(Thread):
percentage, percentage,
message="Downloaded: %s. Processed: %s: %s" message="Downloaded: %s. Processed: %s: %s"
% (getMetadataProgress, processMetadataProgress, % (getMetadataProgress, processMetadataProgress,
viewName)) viewName.decode('utf-8')))
except: except:
# Wierd formating of the string viewName?!? # Wierd formating of the string viewName?!?
pass pass
@ -819,7 +821,7 @@ class LibrarySync(Thread):
viewName, viewName,
viewId) viewId)
self.GetAndProcessXMLs(itemType) self.GetAndProcessXMLs(itemType)
self.logMsg("Processed view %s with ID %s" % (viewName, viewId), 1) self.logMsg("Processed view", 1)
# Update viewstate # Update viewstate
for view in views: for view in views:
if self.threadStopped(): if self.threadStopped():

View file

@ -18,6 +18,7 @@ import PlexAPI
@utils.logging @utils.logging
@utils.ThreadMethodsAdditionalSuspend('suspend_Userclient')
@utils.ThreadMethods @utils.ThreadMethods
class UserClient(threading.Thread): class UserClient(threading.Thread):
@ -57,7 +58,10 @@ class UserClient(threading.Thread):
username = utils.settings('username') username = utils.settings('username')
if not username: if not username:
self.logMsg("No username saved.", 2) self.logMsg("No username saved, trying to get Plex username", 0)
username = utils.settings('plexLogin')
if not username:
self.logMsg("Also no Plex username found", 0)
return "" return ""
return username return username
@ -71,12 +75,13 @@ class UserClient(threading.Thread):
return logLevel return logLevel
def getUserId(self): def getUserId(self, username=None):
log = self.logMsg log = self.logMsg
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
if username is None:
username = self.getUsername() username = self.getUsername()
w_userId = window('emby_currUser') w_userId = window('emby_currUser')
s_userId = settings('userId%s' % username) s_userId = settings('userId%s' % username)
@ -87,28 +92,30 @@ class UserClient(threading.Thread):
# Save access token if it's missing from settings # Save access token if it's missing from settings
settings('userId%s' % username, value=w_userId) settings('userId%s' % username, value=w_userId)
log("Returning userId from WINDOW for username: %s UserId: %s" log("Returning userId from WINDOW for username: %s UserId: %s"
% (username, w_userId), 2) % (username, w_userId), 1)
return w_userId return w_userId
# Verify the settings # Verify the settings
elif s_userId: elif s_userId:
log("Returning userId from SETTINGS for username: %s userId: %s" log("Returning userId from SETTINGS for username: %s userId: %s"
% (username, s_userId), 2) % (username, s_userId), 1)
return s_userId return s_userId
# No userId found # No userId found
else: else:
log("No userId saved for username: %s." % username, 1) log("No userId saved for username: %s. Trying to get Plex ID"
% username, 0)
plexId = settings('plexid')
if not plexId:
log('Also no Plex ID found in settings', 0)
return ''
log('Using Plex ID %s as userid for username: %s'
% (plexId, username))
settings('userId%s' % username, value=plexId)
return plexId
def getServer(self, prefix=True): def getServer(self, prefix=True):
settings = utils.settings settings = utils.settings
alternate = settings('altip') == "true"
if alternate:
# Alternate host
HTTPS = settings('secondhttps') == "true"
host = settings('secondipaddress')
port = settings('secondport')
else:
# Original host # Original host
HTTPS = settings('https') == "true" HTTPS = settings('https') == "true"
host = settings('ipaddress') host = settings('ipaddress')
@ -132,13 +139,15 @@ class UserClient(threading.Thread):
elif not prefix: elif not prefix:
return server return server
def getToken(self): def getToken(self, username=None, userId=None):
log = self.logMsg log = self.logMsg
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
if username is None:
username = self.getUsername() username = self.getUsername()
if userId is None:
userId = self.getUserId() userId = self.getUserId()
w_token = window('emby_accessToken%s' % userId) w_token = window('emby_accessToken%s' % userId)
s_token = settings('accessToken') s_token = settings('accessToken')
@ -188,7 +197,7 @@ class UserClient(threading.Thread):
return s_cert return s_cert
def setUserPref(self): def setUserPref(self):
self.logMsg('Setting user preferences', 0)
url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser) url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser)
if url: if url:
utils.window('EmbyUserImage', value=url) utils.window('EmbyUserImage', value=url)
@ -235,17 +244,16 @@ class UserClient(threading.Thread):
log("Access is granted.", 1) log("Access is granted.", 1)
self.HasAccess = True self.HasAccess = True
window('emby_serverStatus', clear=True) window('emby_serverStatus', clear=True)
xbmcgui.Dialog().notification("Emby for Kodi", utils.language(33007)) xbmcgui.Dialog().notification(self.addonName, utils.language(33007))
def loadCurrUser(self, authenticated=False): def loadCurrUser(self, authenticated=False):
self.logMsg('Loading current user', 0)
window = utils.window window = utils.window
doUtils = self.doUtils doUtils = self.doUtils
username = self.getUsername() username = self.getUsername()
userId = self.getUserId() userId = self.getUserId()
# Only to be used if token exists
self.currUserId = userId self.currUserId = userId
self.currServer = self.getServer() self.currServer = self.getServer()
self.currToken = self.getToken() self.currToken = self.getToken()
@ -253,18 +261,23 @@ class UserClient(threading.Thread):
self.ssl = self.getSSLverify() self.ssl = self.getSSLverify()
self.sslcert = self.getSSL() self.sslcert = self.getSSL()
# Test the validity of current token
if authenticated is False: if authenticated is False:
url = "%s/clients" % (self.currServer) self.logMsg('Testing validity of current token', 0)
window('emby_currUser', value=userId) window('emby_currUser', value=userId)
window('plex_username', value=username) window('plex_username', value=username)
window('emby_accessToken%s' % userId, value=self.currToken) window('emby_accessToken%s' % userId, value=self.currToken)
result = doUtils.downloadUrl(url) res = PlexAPI.PlexAPI().CheckConnection(
self.currServer, self.currToken)
if result == 401: if res is False:
# Token is no longer valid self.logMsg('Answer from PMS is not as expected. Retrying', -1)
return False
elif res == 401:
self.logMsg('Token is no longer valid', -1)
self.resetClient() self.resetClient()
return False return False
elif res >= 400:
self.logMsg('Answer from PMS is not as expected. Retrying', -1)
return False
# Set to windows property # Set to windows property
window('emby_currUser', value=userId) window('emby_currUser', value=userId)
@ -274,6 +287,9 @@ class UserClient(threading.Thread):
window('emby_server_%s' % userId, value=self.getServer(prefix=False)) window('emby_server_%s' % userId, value=self.getServer(prefix=False))
window('plex_machineIdentifier', value=self.machineIdentifier) window('plex_machineIdentifier', value=self.machineIdentifier)
window('emby_serverStatus', clear=True)
window('suspend_LibraryThread', clear=True)
# Set DownloadUtils values # Set DownloadUtils values
doUtils.setUsername(username) doUtils.setUsername(username)
doUtils.setUserId(self.currUserId) doUtils.setUserId(self.currUserId)
@ -292,52 +308,49 @@ class UserClient(threading.Thread):
return True return True
def authenticate(self): def authenticate(self):
log = self.logMsg log = self.logMsg
log('Authenticating user', 1)
lang = utils.language lang = utils.language
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
# Get /profile/addon_data # Get /profile/addon_data
plx = PlexAPI.PlexAPI()
addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8') addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8')
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir) hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
username = self.getUsername()
userId = settings('userId%s' % username)
server = self.getServer()
# If there's no settings.xml # If there's no settings.xml
if not hasSettings: if not hasSettings:
log("No settings.xml found.", 1) log("Error, no settings.xml found.", -1)
self.auth = False self.auth = False
return return
server = self.getServer()
# If no user information # If no user information
elif not server: if not server:
log("Missing server information.", 0) log("Missing server information.", 0)
self.auth = False self.auth = False
return return
# If there's a token, load the user
elif self.getToken():
result = self.loadCurrUser()
if result is False: username = self.getUsername()
userId = self.getUserId(username)
# If there's a token, load the user
if self.getToken(username=username, userId=userId):
if self.loadCurrUser() is False:
pass pass
else: else:
# We successfully loaded a user
log("Current user: %s" % self.currUser, 1) log("Current user: %s" % self.currUser, 1)
log("Current userId: %s" % self.currUserId, 1) log("Current userId: %s" % self.currUserId, 1)
log("Current accessToken: xxxx", 1) log("Current accessToken: xxxx", 1)
window('suspend_LibraryThread', clear=True)
return return
# AUTHENTICATE USER ##### # AUTHENTICATE USER #####
plx = PlexAPI.PlexAPI()
# Choose Plex user login # Choose Plex user login
myplexlogin, plexhome, plexLogin, dont_use_accessToken = \ plexdict = plx.GetPlexLoginFromSettings()
plx.GetPlexLoginFromSettings() myplexlogin = plexdict['myplexlogin']
log("myplexlogin: %s, plexhome: %s, plexLogin: %s" plexhome = plexdict['plexhome']
% (myplexlogin, plexhome, plexLogin), 2)
if myplexlogin == "true" and plexhome == 'true': if myplexlogin == "true" and plexhome == 'true':
username, userId, accessToken = plx.ChoosePlexHomeUser() username, userId, accessToken = plx.ChoosePlexHomeUser()
else: else:
@ -347,6 +360,15 @@ class UserClient(threading.Thread):
if plx.CheckConnection(server, accessToken) == 200: if plx.CheckConnection(server, accessToken) == 200:
self.currUser = username self.currUser = username
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
settings('accessToken', value=accessToken)
settings('userId%s' % username, 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.currUser = None
return
# Success!
if username: if username:
dialog.notification( dialog.notification(
heading=self.addonName, heading=self.addonName,
@ -357,28 +379,20 @@ class UserClient(threading.Thread):
heading=self.addonName, heading=self.addonName,
message="Welcome", message="Welcome",
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png") icon="special://home/addons/plugin.video.plexkodiconnect/icon.png")
settings('accessToken', value=accessToken)
settings('userId%s' % username, value=userId)
log("User authenticated with an access token", 1)
self.loadCurrUser(authenticated=True)
window('emby_serverStatus', clear=True)
# Write plex_machineIdentifier to window
plex_machineIdentifier = settings('plex_machineIdentifier')
window('plex_machineIdentifier', plex_machineIdentifier)
self.retry = 0 self.retry = 0
# Make sure that lib sync thread is not paused # Make sure that lib sync thread is not paused
utils.window('suspend_LibraryThread', clear=True)
else: else:
self.logMsg("Error: user authentication failed.", -1) self.logMsg("Error: user authentication failed.", -1)
settings('accessToken', value="") settings('accessToken', value="")
settings('userId%s' % username, value="") settings('userId%s' % username, value="")
# Give 3 attempts at entering password / selecting user # Give attempts at entering password / selecting user
if self.retry == 3: if self.retry >= 5:
log("Too many retries. You can retry by resetting attempts in " log("Too many retries.", 1)
"the addon settings.", 1)
window('emby_serverStatus', value="Stop") window('emby_serverStatus', value="Stop")
dialog.ok(lang(33001), lang(33010)) dialog.ok(lang(33001), lang(39023))
xbmc.executebuiltin(
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
self.retry += 1 self.retry += 1
self.auth = False self.auth = False
@ -430,15 +444,13 @@ class UserClient(threading.Thread):
self.authenticate() self.authenticate()
if not self.auth and (self.currUser is None): if not self.auth and (self.currUser is None):
# If authenticate failed. # Loop if no server found
server = self.getServer() server = self.getServer()
username = self.getUsername()
# The status Stop is for when user cancelled password dialog. # The status Stop is for when user cancelled password dialog.
if server and username and status != "Stop": if server and status != "Stop":
# Only if there's information found to login # Only if there's information found to login
log("Server found: %s" % server, 2) log("Server found: %s" % server, 2)
log("Username found: %s" % username, 2)
self.auth = True self.auth = True
self.doUtils.stopSession() self.doUtils.stopSession()

View file

@ -304,7 +304,7 @@ def setScreensaver(value):
} }
} }
result = xbmc.executeJSONRPC(json.dumps(query)) result = xbmc.executeJSONRPC(json.dumps(query))
logMsg("EMBY", "Toggling screensaver: %s %s" % (value, result), 1) logMsg("PLEX", "Toggling screensaver: %s %s" % (value, result), 1)
def reset(): def reset():
@ -318,7 +318,7 @@ def reset():
window('emby_shouldStop', value="true") window('emby_shouldStop', value="true")
count = 10 count = 10
while window('emby_dbScan') == "true": while window('emby_dbScan') == "true":
logMsg("EMBY", "Sync is running, will retry: %s..." % count) logMsg("PLEX", "Sync is running, will retry: %s..." % count)
count -= 1 count -= 1
if count == 0: if count == 0:
dialog.ok("Warning", "Could not stop the database from running. Try again.") dialog.ok("Warning", "Could not stop the database from running. Try again.")

View file

@ -25,10 +25,11 @@
<category label="plex.tv"><!-- plex.tv --> <category label="plex.tv"><!-- plex.tv -->
<!-- Primary address --> <!-- Primary address -->
<setting id="myplexlogin" label="Log into plex.tv?" type="bool" default="true" /> <setting id="myplexlogin" label="39025" type="bool" default="true" /> <!-- Log into plex.tv on startup -->
<setting id="plexLogin" label="plex.tv username" type="text" default="" visible="eq(-1,true)" /> <setting id="doPlexTvLogin" label="39024" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=doPlexTvLogin)" option="close" />
<setting id="plexhome" label="Plex home in use" type="bool" default="true" 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="plexToken" label="plexToken" type="text" default="" visible="false" /> <setting id="plexToken" label="plexToken" type="text" default="" visible="false" />
</category> </category>
<category label="Plex Companion"> <category label="Plex Companion">

View file

@ -169,21 +169,14 @@ class Service():
if self.welcome_msg: if self.welcome_msg:
# Reset authentication warnings # Reset authentication warnings
self.welcome_msg = False self.welcome_msg = False
# Get additional users
additionalUsers = user.AdditionalUser
if additionalUsers:
add = ", %s" % ", ".join(additionalUsers)
else:
add = ""
xbmcgui.Dialog().notification( xbmcgui.Dialog().notification(
heading=self.addonName, heading=self.addonName,
message=("%s %s%s!" message=("%s %s"
% (lang(33000), user.currUser.decode('utf-8'), % (lang(33000),
add.decode('utf-8'))), user.currUser.decode('utf-8'))),
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
time=2000, time=2000,
sound=False) sound=False)
# Start monitoring kodi events # Start monitoring kodi events
if not self.kodimonitor_running: if not self.kodimonitor_running:
self.kodimonitor_running = kodimonitor.KodiMonitor() self.kodimonitor_running = kodimonitor.KodiMonitor()
@ -221,15 +214,12 @@ class Service():
# Wait until Emby server is online # Wait until Emby server is online
# or Kodi is shut down. # or Kodi is shut down.
while not monitor.abortRequested(): while not monitor.abortRequested():
server = user.getServer() server = user.getServer()
plexToken = utils.settings('plexToken') if server is False:
if server == False:
# No server info set in add-on settings # No server info set in add-on settings
pass pass
elif plx.CheckConnection(server) is False:
elif plx.CheckConnection(server, plexToken) != 200: # Server is offline or cannot be reached
# Server is offline.
# Alert the user and suppress future warning # Alert the user and suppress future warning
if self.server_online: if self.server_online:
log("Server is offline.", 1) log("Server is offline.", 1)