Complete redesign of playlist handling
This commit is contained in:
parent
8ef66884df
commit
ff1c7f9db1
5 changed files with 115 additions and 56 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
@ -223,28 +224,48 @@ class SubscriptionManager:
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue