From ff1c7f9db1e9ba87fc0606b4d2867e448ec70803 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Thu, 11 Aug 2016 22:11:00 +0200 Subject: [PATCH] Complete redesign of playlist handling --- resources/lib/PlexCompanion.py | 28 ++++++---- resources/lib/playbackutils.py | 5 -- resources/lib/player.py | 10 +--- resources/lib/playlist.py | 65 ++++++++++++++++++---- resources/lib/plexbmchelper/subscribers.py | 63 ++++++++++++++------- 5 files changed, 115 insertions(+), 56 deletions(-) diff --git a/resources/lib/PlexCompanion.py b/resources/lib/PlexCompanion.py index 75910792..c6e92edb 100644 --- a/resources/lib/PlexCompanion.py +++ b/resources/lib/PlexCompanion.py @@ -3,7 +3,6 @@ import threading import traceback import socket import Queue -import threading import xbmc @@ -34,8 +33,7 @@ class PlexCompanion(threading.Thread): % self.client.getClientDetails(), 2) # Initialize playlist/queue stuff - self.queueId = None - self.playlist = None + self.playlist = playlist.Playlist('video') # kodi player instance self.player = player.Player() @@ -80,11 +78,10 @@ class PlexCompanion(threading.Thread): self.logMsg("Traceback:\n%s" % traceback.format_exc(), -1) return if self.playlist is not None: - if self.playlist.typus != data.get('type'): + if self.playlist.Typus() != data.get('type'): self.logMsg('Switching to Kodi playlist of type %s' % data.get('type'), 1) self.playlist = None - self.queueId = None if self.playlist is None: if data.get('type') == 'music': self.playlist = playlist.Playlist('music') @@ -92,26 +89,35 @@ class PlexCompanion(threading.Thread): self.playlist = playlist.Playlist('video') else: self.playlist = playlist.Playlist() - if queueId != self.queueId: + if self.playlist is None: + self.logMsg('Could not initialize playlist', -1) + return + if queueId != self.playlist.QueueId(): self.logMsg('New playlist received, updating!', 1) - self.queueId = queueId xml = GetPlayQueue(queueId) if xml in (None, 401): self.logMsg('Could not download Plex playlist.', -1) return # Clear existing playlist on the Kodi side self.playlist.clear() + # Set new values + self.playlist.QueueId(queueId) + self.playlist.PlayQueueVersion(int( + xml.attrib.get('playQueueVersion'))) + self.playlist.Guid(xml.attrib.get('guid')) items = [] for item in xml: items.append({ - 'queueId': item.get('playQueueItemID'), + 'playQueueItemID': item.get('playQueueItemID'), 'plexId': item.get('ratingKey'), - 'kodiId': None - }) + 'kodiId': None}) self.playlist.playAll( items, startitem=self._getStartItem(data.get('key', '')), offset=ConvertPlexToKodiTime(data.get('offset', 0))) + self.logMsg('Initiated playlist no %s with version %s' + % (self.playlist.QueueId(), + self.playlist.PlayQueueVersion())) else: self.logMsg('This has never happened before!', -1) @@ -127,7 +133,7 @@ class PlexCompanion(threading.Thread): requestMgr = httppersist.RequestMgr() jsonClass = functions.jsonClass(requestMgr, self.settings) subscriptionManager = subscribers.SubscriptionManager( - jsonClass, requestMgr, self.player) + jsonClass, requestMgr, self.player, self.playlist) queue = Queue.Queue(maxsize=100) diff --git a/resources/lib/playbackutils.py b/resources/lib/playbackutils.py index 040d495a..8dba60d3 100644 --- a/resources/lib/playbackutils.py +++ b/resources/lib/playbackutils.py @@ -278,11 +278,6 @@ class PlaybackUtils(): window('%s.itemid' % embyitem, value=itemid) window('%s.playcount' % embyitem, value=str(userdata['PlayCount'])) - # We need to keep track of playQueueItemIDs for Plex Companion - window('plex_%s.playQueueItemID' - % playurl, self.API.GetPlayQueueItemID()) - window('plex_%s.guid' % playurl, self.API.getGuid()) - if itemtype == "episode": window('%s.refreshid' % embyitem, value=self.API.getParentRatingKey()) diff --git a/resources/lib/player.py b/resources/lib/player.py index 740db38b..81479e22 100644 --- a/resources/lib/player.py +++ b/resources/lib/player.py @@ -232,9 +232,6 @@ class Player(xbmc.Player): self.logMsg('Could not get kodi runtime, setting to zero', -1) runtime = 0 - playQueueVersion = window('playQueueVersion') - playQueueID = window('playQueueID') - playQueueItemID = window('plex_%s.playQueueItemID' % currentFile) with embydb.GetEmbyDB() as emby_db: emby_dbitem = emby_db.getItem_byId(itemId) try: @@ -244,9 +241,6 @@ class Player(xbmc.Player): fileid = None # Save data map for updates and position calls data = { - 'playQueueVersion': playQueueVersion, - 'playQueueID': playQueueID, - 'playQueueItemID': playQueueItemID, 'runtime': runtime, 'item_id': itemId, 'refresh_id': refresh_id, @@ -415,9 +409,7 @@ class Player(xbmc.Player): 'emby_%s.type' % filename, 'emby_%s.runtime' % filename, 'emby_%s.playcount' % filename, - 'plex_%s.playQueueItemID' % filename, - 'plex_%s.playlistPosition' % filename, - 'plex_%s.guid' % filename + 'plex_%s.playlistPosition' % filename ) for item in cleanup: utils.window(item, clear=True) diff --git a/resources/lib/playlist.py b/resources/lib/playlist.py index 6c86caba..f3195935 100644 --- a/resources/lib/playlist.py +++ b/resources/lib/playlist.py @@ -45,6 +45,15 @@ class Playlist(): # Borg - multiple instances, shared state _shared_state = {} + typus = None + queueId = None + playQueueVersion = None + guid = None + playlistId = None + player = xbmc.Player() + # "interal" PKC playlist + items = [] + @lockMethod.decorate def __init__(self, typus=None): # Borg @@ -53,6 +62,8 @@ class Playlist(): self.userid = utils.window('currUserId') self.server = utils.window('pms_server') # Construct the Kodi playlist instance + if self.typus == typus: + return if typus == 'video': self.playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) self.typus = 'video' @@ -64,20 +75,53 @@ class Playlist(): else: self.playlist = None self.typus = None + self.logMsg('Empty playlist initiated', 1) if self.playlist is not None: self.playlistId = self.playlist.getPlayListId() - self.player = xbmc.Player() - # "interal" PKC playlist - self.items = [] + + @lockMethod.decorate + def getQueueIdFromPosition(self, playlistPosition): + return self.items[playlistPosition]['playQueueItemID'] + + @lockMethod.decorate + def Typus(self, value=None): + if value: + self.typus = value + else: + return self.typus + + @lockMethod.decorate + def PlayQueueVersion(self, value=None): + if value: + self.playQueueVersion = value + else: + return self.playQueueVersion + + @lockMethod.decorate + def QueueId(self, value=None): + if value: + self.queueId = value + else: + return self.queueId + + @lockMethod.decorate + def Guid(self, value=None): + if value: + self.guid = value + else: + return self.guid @lockMethod.decorate def clear(self): """ - Empties current Kodi playlist and internal self.items list + Empties current Kodi playlist and associated variables """ self.logMsg('Clearing playlist', 1) self.playlist.clear() self.items = [] + self.queueId = None + self.playQueueVersion = None + self.guid = None def _initiatePlaylist(self): self.logMsg('Initiating playlist', 1) @@ -161,13 +205,14 @@ class Playlist(): """ items: list of dicts of the form { - 'queueId': Plex playQueueItemID, e.g. '29175' + 'playQueueItemID': Plex playQueueItemID, e.g. '29175' 'plexId': Plex ratingKey, e.g. '125' 'kodiId': Kodi's db id of the same item } - startitem: tuple (typus, id), where typus is either 'queueId' or - 'plexId' and id is the corresponding id as a string + startitem: tuple (typus, id), where typus is either + 'playQueueItemID' or 'plexId' and id is the corresponding + id as a string offset: First item's time offset to play in Kodi time (an int) """ self.logMsg("---*** PLAY ALL ***---", 1) @@ -201,13 +246,13 @@ class Playlist(): @lockMethod.decorate def addtoPlaylist(self, dbid=None, mediatype=None, url=None): - self._addtoPlaylist(dbid=None, mediatype=None, url=None) - - def _addtoPlaylist(self, dbid=None, mediatype=None, url=None): """ mediatype: Kodi type: 'movie', 'episode', 'musicvideo', 'artist', 'album', 'song', 'genre' """ + self._addtoPlaylist(dbid=None, mediatype=None, url=None) + + def _addtoPlaylist(self, dbid=None, mediatype=None, url=None): pl = { 'jsonrpc': "2.0", 'id': 1, diff --git a/resources/lib/plexbmchelper/subscribers.py b/resources/lib/plexbmchelper/subscribers.py index d9108911..93f4c3ff 100644 --- a/resources/lib/plexbmchelper/subscribers.py +++ b/resources/lib/plexbmchelper/subscribers.py @@ -9,7 +9,7 @@ from functions import * @logging class SubscriptionManager: - def __init__(self, jsonClass, RequestMgr, player): + def __init__(self, jsonClass, RequestMgr, player, playlist): self.serverlist = [] self.subscribers = {} self.info = {} @@ -30,6 +30,7 @@ class SubscriptionManager: self.playerprops = {} self.doUtils = downloadutils.DownloadUtils().downloadUrl self.xbmcplayer = player + self.playlist = playlist self.js = jsonClass self.RequestMgr = RequestMgr @@ -111,6 +112,7 @@ class SubscriptionManager: ret += ' playQueueVersion="%s"' % info.get('playQueueVersion') ret += ' playQueueItemID="%s"' % info.get('playQueueItemID') ret += ' containerKey="%s"' % self.containerKey + ret += ' guid="%s"' % info['guid'] elif keyid: self.containerKey = self.lastkey ret += ' containerKey="%s"' % self.containerKey @@ -122,7 +124,6 @@ class SubscriptionManager: ret += ' protocol="%s"' % serv.get('protocol', "http") ret += ' address="%s"' % serv.get('server', self.server) ret += ' port="%s"' % serv.get('port', self.port) - ret += ' guid="%s"' % info['guid'] ret += ' volume="%s"' % info['volume'] ret += ' shuffle="%s"' % info['shuffle'] ret += ' mute="%s"' % self.mute @@ -221,30 +222,50 @@ class SubscriptionManager: if sub.age > 30: sub.cleanup() del self.subscribers[sub.uuid] - + def getPlayerProperties(self, playerid): - info = {} try: # get info from the player - props = self.js.jsonrpc("Player.GetProperties", {"playerid": playerid, "properties": ["time", "totaltime", "speed", "shuffled", "repeat"]}) - self.logMsg(self.js.jsonrpc("Player.GetItem", {"playerid": playerid, "properties": ["file", "showlink", "episode", "season"]}), 2) - info['time'] = timeToMillis(props['time']) - info['duration'] = timeToMillis(props['totaltime']) - info['state'] = ("paused", "playing")[int(props['speed'])] - info['shuffle'] = ("0","1")[props.get('shuffled', False)] - info['repeat'] = pf.getPlexRepeat(props.get('repeat')) - # New PMS playQueue attributes - cf = self.xbmcplayer.getPlayingFile() - info['playQueueID'] = window('playQueueID') - info['playQueueVersion'] = window('playQueueVersion') - info['playQueueItemID'] = window('plex_%s.playQueueItemID' % cf) - info['guid'] = window('plex_%s.guid' % cf) + props = self.js.jsonrpc( + "Player.GetProperties", + {"playerid": playerid, + "properties": ["time", + "totaltime", + "speed", + "shuffled", + "repeat"]}) + info = { + 'time': timeToMillis(props['time']), + 'duration': timeToMillis(props['totaltime']), + 'state': ("paused", "playing")[int(props['speed'])], + 'shuffle': ("0", "1")[props.get('shuffled', False)], + 'repeat': pf.getPlexRepeat(props.get('repeat')), + } + if self.playlist is not None: + if self.playlist.QueueId() is not None: + info['playQueueID'] = self.playlist.QueueId() + info['playQueueVersion'] = self.playlist.PlayQueueVersion() + info['guid'] = self.playlist.Guid() + # Get the playlist position + pos = self.js.jsonrpc( + "Player.GetProperties", + {"playerid": playerid, + "properties": ["position"]}) + info['playQueueItemID'] = \ + self.playlist.getQueueIdFromPosition(pos['position']) except: - info['time'] = 0 - info['duration'] = 0 - info['state'] = "stopped" - info['shuffle'] = False + import traceback + self.logMsg("Traceback:\n%s" + % traceback.format_exc(), -1) + info = { + 'time': 0, + 'duration': 0, + 'state': 'stopped', + 'shuffle': False, + 'repeat': 0 + } + # get the volume from the application info['volume'] = self.volume info['mute'] = self.mute