Plex home user switch working

This commit is contained in:
tomkat83 2016-01-27 12:18:54 +01:00
parent 0d4c8ae53e
commit 42bd570187
7 changed files with 66 additions and 39 deletions

View file

@ -39,9 +39,9 @@ def plexCompanion(fullurl, resume=None):
except IndexError: except IndexError:
# No matches found, url not like: # No matches found, url not like:
# http://192.168.0.2:32400/library/metadata/243480 # http://192.168.0.2:32400/library/metadata/243480
utils.logMsg("plexCompanion", "Could not parse url: %s" % fullurl, -1) utils.logMsg("entrypoint - plexCompanion",
"Could not parse url: %s" % fullurl, -1)
return False return False
# TODO: direct play an URL
# Initialize embydb # Initialize embydb
embyconn = utils.kodiSQL('emby') embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
@ -272,14 +272,16 @@ def switchPlexUser():
# Delete any userimages. Since there's always only 1 user: position = 0 # Delete any userimages. Since there's always only 1 user: position = 0
# position = 0 # position = 0
# utils.window('EmbyAdditionalUserImage.%s' % position, clear=True) # utils.window('EmbyAdditionalUserImage.%s' % position, clear=True)
utils.logMsg("PLEX", "Plex home user switch requested", 0) utils.logMsg("entrypoint switchPlexUser",
"Plex home user switch requested", 0)
# Pause library sync thread - user needs to be auth in order to sync # Pause library sync thread - user needs to be auth in order to sync
utils.window('suspend_LibraryThread', value='true') utils.window('suspend_LibraryThread', value='true')
# Wait 1 second to ensure that library thread is indeed suspended
xbmc.sleep(1000)
# Log out currently signed in user: # Log out currently signed in user:
utils.window('emby_serverStatus', value="401") utils.window('emby_serverStatus', value="401")
# 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='true') utils.window('plex_runLibScan', value='true')
# Reset Plex userdata: resume points, watched/unwatched status
##### THEME MUSIC/VIDEOS ##### ##### THEME MUSIC/VIDEOS #####

View file

@ -178,6 +178,7 @@ class ThreadedShowSyncInfo(threading.Thread):
@utils.logging @utils.logging
@utils.ThreadMethodsAdditionalSuspend('suspend_LibraryThread')
@utils.ThreadMethodsStopsync @utils.ThreadMethodsStopsync
@utils.ThreadMethods @utils.ThreadMethods
class LibrarySync(threading.Thread): class LibrarySync(threading.Thread):
@ -225,7 +226,7 @@ class LibrarySync(threading.Thread):
self.maintainViews() self.maintainViews()
completed = False completed = False
completed = self.fastSync() # completed = self.fastSync()
if not completed: if not completed:
# Fast sync failed or server plugin is not found # Fast sync failed or server plugin is not found
@ -1158,8 +1159,13 @@ class LibrarySync(threading.Thread):
# This will prevent an infinite loop in case something goes wrong. # This will prevent an infinite loop in case something goes wrong.
startupComplete = True startupComplete = True
# Process updates
if utils.window('emby_dbScan') != "true": if utils.window('emby_dbScan') != "true":
# Currently no db scan, so we can start a new scan
if utils.window('plex_runLibScan') == "true":
self.logMsg('Full library scan requested, starting', 1)
utils.window('plex_runLibScan', value='false')
self.fullSync(manualrun=True)
else:
self.incrementalSync() self.incrementalSync()
if (utils.window('emby_onWake') == "true" and if (utils.window('emby_onWake') == "true" and
@ -1172,10 +1178,7 @@ class LibrarySync(threading.Thread):
librarySync = self.startSync() librarySync = self.startSync()
self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0) self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0)
if self.threadStopped(): xbmc.sleep(1000)
# Set in service.py
self.logMsg("Service terminated thread.", 2)
break
self.logMsg("###===--- LibrarySync Stopped ---===###", 0) self.logMsg("###===--- LibrarySync Stopped ---===###", 0)

View file

@ -42,7 +42,8 @@ class PlaybackUtils():
def play(self, itemid, dbid=None, seektime=None): def play(self, itemid, dbid=None, seektime=None):
self.logMsg("Play called.", 1) self.logMsg("Play called with itemid: %s, dbid: %s, seektime: %s."
% (itemid, dbid, seektime), 1)
doUtils = self.doUtils doUtils = self.doUtils
item = self.item item = self.item

View file

@ -82,6 +82,7 @@ class Player(xbmc.Player):
else: tryCount += 1 else: tryCount += 1
else: else:
utils.window('Plex_currently_playing_itemid', value=itemId)
self.logMsg("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0) self.logMsg("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
# Only proceed if an itemId was found. # Only proceed if an itemId was found.
@ -113,7 +114,7 @@ class Player(xbmc.Player):
muted = result.get('muted') muted = result.get('muted')
# Postdata structure to send to Emby server # Postdata structure to send to Emby server
url = "{server}/emby/Sessions/Playing" url = "{server}/:/timeline?"
postdata = { postdata = {
'QueueableMediaTypes': "Video", 'QueueableMediaTypes': "Video",
@ -194,8 +195,8 @@ class Player(xbmc.Player):
# Post playback to server # Post playback to server
self.logMsg("Sending POST play started: %s." % postdata, 2) # self.logMsg("Sending POST play started: %s." % postdata, 2)
self.doUtils.downloadUrl(url, postBody=postdata, type="POST") # self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
# Ensure we do have a runtime # Ensure we do have a runtime
try: try:
@ -370,10 +371,9 @@ class Player(xbmc.Player):
# Report progress via websocketclient # Report progress via websocketclient
# postdata = json.dumps(postdata) # postdata = json.dumps(postdata)
self.logMsg("Report: %s" % postdata, 2)
# self.ws.sendProgressUpdate(postdata) # self.ws.sendProgressUpdate(postdata)
url = "{server}/:/timeline?" + urlencode(postdata) self.doUtils.downloadUrl(
self.doUtils.downloadUrl(url, type="GET") "{server}/:/timeline?" + urlencode(postdata), type="GET")
def onPlayBackPaused( self ): def onPlayBackPaused( self ):

View file

@ -19,7 +19,6 @@ class SubscriptionManager:
self.protocol = "http" self.protocol = "http"
self.port = "" self.port = ""
self.playerprops = {} self.playerprops = {}
self.sentstopped = True
self.download = downloadutils.DownloadUtils() self.download = downloadutils.DownloadUtils()
def getVolume(self): def getVolume(self):
@ -60,11 +59,25 @@ class SubscriptionManager:
ret = "\r\n"+'<Timeline location="%s" state="%s" time="%s" type="%s"' % (self.mainlocation, state, time, ptype) ret = "\r\n"+'<Timeline location="%s" state="%s" time="%s" type="%s"' % (self.mainlocation, state, time, ptype)
if playerid is not None: if playerid is not None:
WINDOW = xbmcgui.Window(10000) WINDOW = xbmcgui.Window(10000)
pbmc_server = str(WINDOW.getProperty('plexbmc.nowplaying.server'))
keyid = str(WINDOW.getProperty('plexbmc.nowplaying.id')) # pbmc_server = str(WINDOW.getProperty('plexbmc.nowplaying.server'))
# userId = str(WINDOW.getProperty('emby_currUser'))
# pbmc_server = str(WINDOW.getProperty('emby_server%s' % userId))
pbmc_server = None
keyid = None
count = 0
while not keyid:
if count > 10:
break
keyid = str(WINDOW.getProperty('Plex_currently_playing_itemid'))
xbmc.sleep(1000)
count += 1
if keyid: if keyid:
self.lastkey = "/library/metadata/%s"%keyid self.lastkey = "/library/metadata/%s"%keyid
self.lastratingkey = keyid self.lastratingkey = keyid
ret += ' containerKey="%s"' % (self.lastkey)
ret += ' key="%s"' % (self.lastkey)
ret += ' ratingKey="%s"' % (self.lastratingkey)
if pbmc_server: if pbmc_server:
(self.server, self.port) = pbmc_server.split(':') (self.server, self.port) = pbmc_server.split(':')
serv = getServerByHost(self.server) serv = getServerByHost(self.server)
@ -76,9 +89,6 @@ class SubscriptionManager:
ret += ' address="%s"' % serv.get('server', self.server) ret += ' address="%s"' % serv.get('server', self.server)
ret += ' port="%s"' % serv.get('port', self.port) ret += ' port="%s"' % serv.get('port', self.port)
ret += ' guid="%s"' % info['guid'] ret += ' guid="%s"' % info['guid']
ret += ' containerKey="%s"' % (self.lastkey or "/library/metadata/900000")
ret += ' key="%s"' % (self.lastkey or "/library/metadata/900000")
ret += ' ratingKey="%s"' % (self.lastratingkey or "900000")
ret += ' volume="%s"' % info['volume'] ret += ' volume="%s"' % info['volume']
ret += ' shuffle="%s"' % info['shuffle'] ret += ' shuffle="%s"' % info['shuffle']
@ -103,7 +113,8 @@ class SubscriptionManager:
return True return True
def notifyServer(self, players): def notifyServer(self, players):
if not players and self.sentstopped: return True if not players:
return True
params = {'state': 'stopped'} params = {'state': 'stopped'}
for p in players.values(): for p in players.values():
info = self.playerprops[p.get('playerid')] info = self.playerprops[p.get('playerid')]
@ -120,13 +131,11 @@ class SubscriptionManager:
+ serv.get('port', 32400) + "/:/timeline" + serv.get('port', 32400) + "/:/timeline"
self.download.downloadUrl(url, type="GET", parameters=params) self.download.downloadUrl(url, type="GET", parameters=params)
# requests.getwithparams(serv.get('server', 'localhost'), serv.get('port', 32400), "/:/timeline", params, getPlexHeaders(), serv.get('protocol', 'http')) # requests.getwithparams(serv.get('server', 'localhost'), serv.get('port', 32400), "/:/timeline", params, getPlexHeaders(), serv.get('protocol', 'http'))
printDebug("params: %s" % params)
printDebug("players: %s" % players)
printDebug("sent server notification with state = %s" % params['state']) printDebug("sent server notification with state = %s" % params['state'])
WINDOW = xbmcgui.Window(10000) WINDOW = xbmcgui.Window(10000)
WINDOW.setProperty('plexbmc.nowplaying.sent', '1') WINDOW.setProperty('plexbmc.nowplaying.sent', '1')
if players:
self.sentstopped = False
else:
self.sentstopped = True
def controllable(self): def controllable(self):
return "playPause,play,stop,skipPrevious,skipNext,volume,stepBack,stepForward,seekTo" return "playPause,play,stop,skipPrevious,skipNext,volume,stepBack,stepForward,seekTo"

View file

@ -260,7 +260,6 @@ class UserClient(threading.Thread):
def authenticate(self): def authenticate(self):
# Get /profile/addon_data # Get /profile/addon_data
plx = PlexAPI.PlexAPI() plx = PlexAPI.PlexAPI()
lib = librarysync.LibrarySync()
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)
@ -288,7 +287,8 @@ class UserClient(threading.Thread):
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: xxxx", 1) self.logMsg("Current accessToken: xxxx", 1)
lib.resumeThread()
utils.window('suspend_LibraryThread', value='false')
return return
##### AUTHENTICATE USER ##### ##### AUTHENTICATE USER #####
@ -326,7 +326,7 @@ class UserClient(threading.Thread):
utils.window('plex_machineIdentifier', plex_machineIdentifier) utils.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
lib.resumeThread() utils.window('suspend_LibraryThread', value='false')
else: else:
self.logMsg("Error: user authentication failed.", -1) self.logMsg("Error: user authentication failed.", -1)
utils.settings('accessToken', value="") utils.settings('accessToken', value="")

View file

@ -37,6 +37,22 @@ def ThreadMethodsStopsync(cls):
return cls return cls
def ThreadMethodsAdditionalSuspend(windowAttribute):
"""
Decorator to replace threadSuspended(): thread now also suspends if a
Kodi windowAttribute is set to 'true', e.g. 'suspend_LibraryThread'
Use with any library sync threads. @ThreadMethods still required FIRST
"""
def wrapper(cls):
def threadSuspended(self):
return (self._threadSuspended or True if
window(windowAttribute) == 'true' else False)
cls.threadSuspended = threadSuspended
return cls
return wrapper
def ThreadMethods(cls): def ThreadMethods(cls):
""" """
Decorator to add the following methods to a threading class: Decorator to add the following methods to a threading class:
@ -86,8 +102,8 @@ def ThreadMethods(cls):
def logging(cls): def logging(cls):
""" """
A decorator adding logging capabilities to classes. Also adds A decorator adding logging capabilities to classes.
self.addonName to the class Also adds self.addonName to the class
Syntax: self.logMsg(message, loglevel) Syntax: self.logMsg(message, loglevel)
@ -102,9 +118,6 @@ def logging(cls):
logMsg(title, msg, lvl) logMsg(title, msg, lvl)
cls.logMsg = newFunction cls.logMsg = newFunction
# Override the name, we don't want the decorators name showing up
__name__ = cls.__name__
# Return class to render this a decorator # Return class to render this a decorator
return cls return cls
@ -143,7 +156,6 @@ def window(property, value=None, clear=False, windowid=10000):
property = property.encode("utf-8") property = property.encode("utf-8")
if isinstance(value, unicode): if isinstance(value, unicode):
value = value.encode("utf-8")''' value = value.encode("utf-8")'''
if clear: if clear:
WINDOW.clearProperty(property) WINDOW.clearProperty(property)
elif value is not None: elif value is not None: