Playqueues overhaul continued
This commit is contained in:
parent
0c2d4984ab
commit
9d2902baa5
8 changed files with 216 additions and 139 deletions
|
@ -1646,7 +1646,7 @@ class API():
|
||||||
|
|
||||||
If not found, empty str is returned
|
If not found, empty str is returned
|
||||||
"""
|
"""
|
||||||
return self.item.attrib.get('playQueueItemID', '')
|
return self.item.attrib.get('playQueueItemID')
|
||||||
|
|
||||||
def getDataFromPartOrMedia(self, key):
|
def getDataFromPartOrMedia(self, key):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,8 +9,7 @@ from xbmc import sleep
|
||||||
from utils import settings, ThreadMethodsAdditionalSuspend, ThreadMethods
|
from utils import settings, ThreadMethodsAdditionalSuspend, ThreadMethods
|
||||||
from plexbmchelper import listener, plexgdm, subscribers, functions, \
|
from plexbmchelper import listener, plexgdm, subscribers, functions, \
|
||||||
httppersist, plexsettings
|
httppersist, plexsettings
|
||||||
from PlexFunctions import ParseContainerKey, GetPlayQueue, \
|
from PlexFunctions import ParseContainerKey
|
||||||
ConvertPlexToKodiTime
|
|
||||||
import player
|
import player
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -29,7 +28,6 @@ class PlexCompanion(Thread):
|
||||||
log.info("----===## Starting PlexCompanion ##===----")
|
log.info("----===## Starting PlexCompanion ##===----")
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
self.mgr = callback
|
self.mgr = callback
|
||||||
self.playqueue = self.mgr.playqueue
|
|
||||||
self.settings = plexsettings.getSettings()
|
self.settings = plexsettings.getSettings()
|
||||||
# Start GDM for server/client discovery
|
# Start GDM for server/client discovery
|
||||||
self.client = plexgdm.plexgdm()
|
self.client = plexgdm.plexgdm()
|
||||||
|
@ -60,12 +58,18 @@ class PlexCompanion(Thread):
|
||||||
|
|
||||||
def processTasks(self, task):
|
def processTasks(self, task):
|
||||||
"""
|
"""
|
||||||
Processes tasks picked up e.g. by Companion listener
|
Processes tasks picked up e.g. by Companion listener, e.g.
|
||||||
|
{'action': 'playlist',
|
||||||
task = {
|
'data': {'address': 'xyz.plex.direct',
|
||||||
'action': 'playlist'
|
'commandID': '7',
|
||||||
'data': as received from Plex companion
|
'containerKey': '/playQueues/6669?own=1&repeat=0&window=200',
|
||||||
}
|
'key': '/library/metadata/220493',
|
||||||
|
'machineIdentifier': 'xyz',
|
||||||
|
'offset': '0',
|
||||||
|
'port': '32400',
|
||||||
|
'protocol': 'https',
|
||||||
|
'token': 'transient-cd2527d1-0484-48e0-a5f7-f5caa7d591bd',
|
||||||
|
'type': 'video'}}
|
||||||
"""
|
"""
|
||||||
log.debug('Processing: %s' % task)
|
log.debug('Processing: %s' % task)
|
||||||
data = task['data']
|
data = task['data']
|
||||||
|
@ -79,36 +83,11 @@ class PlexCompanion(Thread):
|
||||||
import traceback
|
import traceback
|
||||||
log.error("Traceback:\n%s" % traceback.format_exc())
|
log.error("Traceback:\n%s" % traceback.format_exc())
|
||||||
return
|
return
|
||||||
self.mgr.playqueue.update_playqueue_with_companion(data)
|
playqueue = self.mgr.playqueue.get_playqueue_from_type(
|
||||||
|
data['type'])
|
||||||
self.playqueue = self.mgr.playqueue.get_playqueue_from_plextype(
|
if ID != playqueue.ID:
|
||||||
data.get('type'))
|
self.mgr.playqueue.update_playqueue_from_PMS(
|
||||||
if queueId != self.playqueue.ID:
|
playqueue, ID, int(query['repeat']))
|
||||||
log.info('New playlist received, updating!')
|
|
||||||
xml = GetPlayQueue(queueId)
|
|
||||||
if xml in (None, 401):
|
|
||||||
log.error('Could not download Plex playlist.')
|
|
||||||
return
|
|
||||||
# Clear existing playlist on the Kodi side
|
|
||||||
self.playqueue.clear()
|
|
||||||
# Set new values
|
|
||||||
self.playqueue.QueueId(queueId)
|
|
||||||
self.playqueue.PlayQueueVersion(int(
|
|
||||||
xml.attrib.get('playQueueVersion')))
|
|
||||||
self.playqueue.Guid(xml.attrib.get('guid'))
|
|
||||||
items = []
|
|
||||||
for item in xml:
|
|
||||||
items.append({
|
|
||||||
'playQueueItemID': item.get('playQueueItemID'),
|
|
||||||
'plexId': item.get('ratingKey'),
|
|
||||||
'kodiId': None})
|
|
||||||
self.playqueue.playAll(
|
|
||||||
items,
|
|
||||||
startitem=self._getStartItem(data.get('key', '')),
|
|
||||||
offset=ConvertPlexToKodiTime(data.get('offset', 0)))
|
|
||||||
log.info('Initiated playlist no %s with version %s'
|
|
||||||
% (self.playqueue.QueueId(),
|
|
||||||
self.playqueue.PlayQueueVersion()))
|
|
||||||
else:
|
else:
|
||||||
log.error('This has never happened before!')
|
log.error('This has never happened before!')
|
||||||
|
|
||||||
|
@ -123,7 +102,7 @@ class PlexCompanion(Thread):
|
||||||
requestMgr = httppersist.RequestMgr()
|
requestMgr = httppersist.RequestMgr()
|
||||||
jsonClass = functions.jsonClass(requestMgr, self.settings)
|
jsonClass = functions.jsonClass(requestMgr, self.settings)
|
||||||
subscriptionManager = subscribers.SubscriptionManager(
|
subscriptionManager = subscribers.SubscriptionManager(
|
||||||
jsonClass, requestMgr, self.player, self.playqueue)
|
jsonClass, requestMgr, self.player, self.mgr)
|
||||||
|
|
||||||
queue = Queue.Queue(maxsize=100)
|
queue = Queue.Queue(maxsize=100)
|
||||||
|
|
||||||
|
|
|
@ -171,22 +171,6 @@ def SelectStreams(url, args):
|
||||||
url + '?' + urlencode(args), action_type='PUT')
|
url + '?' + urlencode(args), action_type='PUT')
|
||||||
|
|
||||||
|
|
||||||
def GetPlayQueue(playQueueID):
|
|
||||||
"""
|
|
||||||
Fetches the PMS playqueue with the playQueueID as an XML
|
|
||||||
|
|
||||||
Returns None if something went wrong
|
|
||||||
"""
|
|
||||||
url = "{server}/playQueues/%s" % playQueueID
|
|
||||||
args = {'Accept': 'application/xml'}
|
|
||||||
xml = downloadutils.DownloadUtils().downloadUrl(url, headerOptions=args)
|
|
||||||
try:
|
|
||||||
xml.attrib['playQueueID']
|
|
||||||
except (AttributeError, KeyError):
|
|
||||||
return None
|
|
||||||
return xml
|
|
||||||
|
|
||||||
|
|
||||||
def GetPlexMetadata(key):
|
def GetPlexMetadata(key):
|
||||||
"""
|
"""
|
||||||
Returns raw API metadata for key as an etree XML.
|
Returns raw API metadata for key as an etree XML.
|
||||||
|
|
|
@ -168,10 +168,10 @@ class KodiMonitor(xbmc.Monitor):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif method == "Playlist.OnAdd":
|
elif method == "Playlist.OnAdd":
|
||||||
# User manipulated Kodi playlist
|
# User (or PKC) manipulated Kodi playlist
|
||||||
# Data : {u'item': {u'type': u'movie', u'id': 3}, u'playlistid': 1,
|
# Data : {u'item': {u'type': u'movie', u'id': 3}, u'playlistid': 1,
|
||||||
# u'position': 0}
|
# u'position': 0}
|
||||||
self.playlist.kodi_onadd(data)
|
self.playqueue.kodi_onadd(data)
|
||||||
|
|
||||||
def PlayBackStart(self, data):
|
def PlayBackStart(self, data):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -37,7 +37,8 @@ class PlaybackUtils():
|
||||||
self.userid = window('currUserId')
|
self.userid = window('currUserId')
|
||||||
self.server = window('pms_server')
|
self.server = window('pms_server')
|
||||||
|
|
||||||
self.pl = Playqueue().get_playqueue_from_plextype(self.API.getType())
|
self.pl = Playqueue().get_playqueue_from_type(
|
||||||
|
PF.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[self.API.getType()])
|
||||||
|
|
||||||
def play(self, itemid, dbid=None):
|
def play(self, itemid, dbid=None):
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from urllib import quote
|
||||||
import embydb_functions as embydb
|
import embydb_functions as embydb
|
||||||
from downloadutils import DownloadUtils as DU
|
from downloadutils import DownloadUtils as DU
|
||||||
from utils import JSONRPC, tryEncode
|
from utils import JSONRPC, tryEncode
|
||||||
|
from PlexAPI import API
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
@ -24,13 +25,35 @@ class Playlist_Object_Baseclase(object):
|
||||||
selectedItemOffset = None
|
selectedItemOffset = None
|
||||||
shuffled = 0 # [int], 0: not shuffled, 1: ??? 2: ???
|
shuffled = 0 # [int], 0: not shuffled, 1: ??? 2: ???
|
||||||
repeat = 0 # [int], 0: not repeated, 1: ??? 2: ???
|
repeat = 0 # [int], 0: not repeated, 1: ??? 2: ???
|
||||||
|
# Hack to later ignore all Kodi playlist adds that PKC did (Kodimonitor)
|
||||||
|
PKC_playlist_edits = []
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
answ = "<%s object: " % (self.__class__.__name__)
|
answ = "<%s: " % (self.__class__.__name__)
|
||||||
for key in self.__dict__:
|
for key in self.__dict__:
|
||||||
answ += '%s: %s, ' % (key, getattr(self, key))
|
answ += '%s: %s, ' % (key, getattr(self, key))
|
||||||
return answ[:-2] + ">"
|
return answ[:-2] + ">"
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""
|
||||||
|
Resets the playlist object to an empty playlist
|
||||||
|
"""
|
||||||
|
# Clear Kodi playlist object
|
||||||
|
self.kodi_pl.clear()
|
||||||
|
self.items = []
|
||||||
|
self.old_kodi_pl = []
|
||||||
|
self.ID = None
|
||||||
|
self.version = None
|
||||||
|
self.selectedItemID = None
|
||||||
|
self.selectedItemOffset = None
|
||||||
|
self.shuffled = 0
|
||||||
|
self.repeat = 0
|
||||||
|
self.PKC_playlist_edits = []
|
||||||
|
log.debug('Playlist cleared: %s' % self)
|
||||||
|
|
||||||
|
def log_Kodi_playlist(self):
|
||||||
|
log.debug('Current Kodi playlist: %s' % get_kodi_playlist_items(self))
|
||||||
|
|
||||||
|
|
||||||
class Playlist_Object(Playlist_Object_Baseclase):
|
class Playlist_Object(Playlist_Object_Baseclase):
|
||||||
kind = 'playList'
|
kind = 'playList'
|
||||||
|
@ -48,6 +71,13 @@ class Playlist_Item(object):
|
||||||
kodi_type = None # Kodi type: 'movie'
|
kodi_type = None # Kodi type: 'movie'
|
||||||
file = None # Path to the item's file
|
file = None # Path to the item's file
|
||||||
uri = None # Weird Plex uri path involving plex_UUID
|
uri = None # Weird Plex uri path involving plex_UUID
|
||||||
|
guid = None # Weird Plex guid
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
answ = "<%s: " % (self.__class__.__name__)
|
||||||
|
for key in self.__dict__:
|
||||||
|
answ += '%s: %s, ' % (key, getattr(self, key))
|
||||||
|
return answ[:-2] + ">"
|
||||||
|
|
||||||
|
|
||||||
def playlist_item_from_kodi_item(kodi_item):
|
def playlist_item_from_kodi_item(kodi_item):
|
||||||
|
@ -127,8 +157,10 @@ def _get_playlist_details_from_xml(playlist, xml):
|
||||||
try:
|
try:
|
||||||
playlist.ID = xml.attrib['%sID' % playlist.kind]
|
playlist.ID = xml.attrib['%sID' % playlist.kind]
|
||||||
playlist.version = xml.attrib['%sVersion' % playlist.kind]
|
playlist.version = xml.attrib['%sVersion' % playlist.kind]
|
||||||
playlist.selectedItemID = xml.attrib['%sSelectedItemID' % playlist.kind]
|
playlist.selectedItemID = xml.attrib['%sSelectedItemID'
|
||||||
playlist.selectedItemOffset = xml.attrib['%sSelectedItemOffset' % playlist.kind]
|
% playlist.kind]
|
||||||
|
playlist.selectedItemOffset = xml.attrib['%sSelectedItemOffset'
|
||||||
|
% playlist.kind]
|
||||||
playlist.shuffled = xml.attrib['%sShuffled' % playlist.kind]
|
playlist.shuffled = xml.attrib['%sShuffled' % playlist.kind]
|
||||||
except:
|
except:
|
||||||
log.error('Could not parse xml answer from PMS for playlist %s'
|
log.error('Could not parse xml answer from PMS for playlist %s'
|
||||||
|
@ -141,9 +173,9 @@ def _get_playlist_details_from_xml(playlist, xml):
|
||||||
|
|
||||||
def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
|
def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
|
||||||
"""
|
"""
|
||||||
Supply either plex_id or the data supplied by Kodi JSON-RPC
|
Supply either with a plex_id OR the data supplied by Kodi JSON-RPC
|
||||||
"""
|
"""
|
||||||
if plex_id is not None:
|
if plex_id:
|
||||||
item = playlist_item_from_plex(plex_id)
|
item = playlist_item_from_plex(plex_id)
|
||||||
else:
|
else:
|
||||||
item = playlist_item_from_kodi_item(kodi_item)
|
item = playlist_item_from_kodi_item(kodi_item)
|
||||||
|
@ -155,7 +187,7 @@ def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
|
||||||
xml = DU().downloadUrl(url="{server}/%ss" % playlist.kind,
|
xml = DU().downloadUrl(url="{server}/%ss" % playlist.kind,
|
||||||
action_type="POST",
|
action_type="POST",
|
||||||
parameters=params)
|
parameters=params)
|
||||||
_get_playlist_details_from_xml(xml)
|
_get_playlist_details_from_xml(playlist, xml)
|
||||||
playlist.items.append(item)
|
playlist.items.append(item)
|
||||||
log.debug('Initialized the playlist: %s' % playlist)
|
log.debug('Initialized the playlist: %s' % playlist)
|
||||||
|
|
||||||
|
@ -176,6 +208,10 @@ def add_playlist_item(playlist, kodi_item, after_pos):
|
||||||
% (kodi_item, playlist))
|
% (kodi_item, playlist))
|
||||||
_log_xml(xml)
|
_log_xml(xml)
|
||||||
return
|
return
|
||||||
|
# Get the guid for this item
|
||||||
|
for plex_item in xml:
|
||||||
|
if plex_item.attrib['%sItemID' % playlist.kind] == item.ID:
|
||||||
|
item.guid = plex_item.attrib['guid']
|
||||||
playlist.items.append(item)
|
playlist.items.append(item)
|
||||||
if after_pos == len(playlist.items) - 1:
|
if after_pos == len(playlist.items) - 1:
|
||||||
# Item was added at the end
|
# Item was added at the end
|
||||||
|
@ -259,6 +295,39 @@ def get_kodi_playqueues():
|
||||||
|
|
||||||
# Functions operating on the Kodi playlist objects ##########
|
# Functions operating on the Kodi playlist objects ##########
|
||||||
|
|
||||||
|
def add_to_Kodi_playlist(playlist, xml_video_element):
|
||||||
|
"""
|
||||||
|
Adds a new item to the Kodi playlist via JSON (at the end of the playlist).
|
||||||
|
Pass in the PMS xml's video element (one level underneath MediaContainer).
|
||||||
|
|
||||||
|
Will return a Playlist_Item
|
||||||
|
"""
|
||||||
|
item = Playlist_Item()
|
||||||
|
api = API(xml_video_element)
|
||||||
|
params = {
|
||||||
|
'playlistid': playlist.playlistid
|
||||||
|
}
|
||||||
|
item.plex_id = api.getRatingKey()
|
||||||
|
item.ID = xml_video_element.attrib['%sItemID' % playlist.kind]
|
||||||
|
item.guid = xml_video_element.attrib.get('guid')
|
||||||
|
if item.plex_id:
|
||||||
|
with embydb.GetEmbyDB() as emby_db:
|
||||||
|
db_element = emby_db.getItem_byId(item.plex_id)
|
||||||
|
try:
|
||||||
|
item.kodi_id, item.kodi_type = int(db_element[0]), db_element[4]
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
if item.kodi_id:
|
||||||
|
params['item'] = {'%sid' % item.kodi_type: item.kodi_id}
|
||||||
|
else:
|
||||||
|
item.file = api.getFilePath()
|
||||||
|
params['item'] = {'file': tryEncode(item.file)}
|
||||||
|
log.debug(JSONRPC('Playlist.Add').execute(params))
|
||||||
|
playlist.PKC_playlist_edits.append(
|
||||||
|
item.kodi_id if item.kodi_id else item.file)
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
def insertintoPlaylist(self,
|
def insertintoPlaylist(self,
|
||||||
position,
|
position,
|
||||||
dbid=None,
|
dbid=None,
|
||||||
|
@ -275,57 +344,51 @@ def insertintoPlaylist(self,
|
||||||
JSONRPC('Playlist.Insert').execute(params)
|
JSONRPC('Playlist.Insert').execute(params)
|
||||||
|
|
||||||
|
|
||||||
def addtoPlaylist(self, dbid=None, mediatype=None, url=None):
|
|
||||||
params = {
|
|
||||||
'playlistid': self.playlistId
|
|
||||||
}
|
|
||||||
if dbid is not None:
|
|
||||||
params['item'] = {'%sid' % tryEncode(mediatype): int(dbid)}
|
|
||||||
else:
|
|
||||||
params['item'] = {'file': url}
|
|
||||||
JSONRPC('Playlist.Add').execute(params)
|
|
||||||
|
|
||||||
|
|
||||||
def removefromPlaylist(self, position):
|
def removefromPlaylist(self, position):
|
||||||
params = {
|
params = {
|
||||||
'playlistid': self.playlistId,
|
'playlistid': self.playlistId,
|
||||||
'position': position
|
'position': position
|
||||||
}
|
}
|
||||||
JSONRPC('Playlist.Remove').execute(params)
|
log.debug(JSONRPC('Playlist.Remove').execute(params))
|
||||||
|
|
||||||
|
|
||||||
def playAll(self, items, startitem, offset):
|
def get_PMS_playlist(playlist, playlist_id=None):
|
||||||
"""
|
"""
|
||||||
items: list of dicts of the form
|
Fetches the PMS playlist/playqueue as an XML. Pass in playlist_id if we
|
||||||
{
|
need to fetch a new playlist
|
||||||
'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
|
Returns None if something went wrong
|
||||||
'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)
|
|
||||||
"""
|
"""
|
||||||
log.info("---*** PLAY ALL ***---")
|
playlist_id = playlist_id if playlist_id else playlist.ID
|
||||||
log.debug('Startitem: %s, offset: %s, items: %s'
|
xml = DU().downloadUrl(
|
||||||
% (startitem, offset, items))
|
"{server}/%ss/%s" % (playlist.kind, playlist_id),
|
||||||
self.items = items
|
headerOptions={'Accept': 'application/xml'})
|
||||||
if self.playlist is None:
|
try:
|
||||||
self._initiatePlaylist()
|
xml.attrib['%sID' % playlist.kind]
|
||||||
if self.playlist is None:
|
except (AttributeError, KeyError):
|
||||||
log.error('Could not create playlist, abort')
|
xml = None
|
||||||
|
return xml
|
||||||
|
|
||||||
|
|
||||||
|
def update_playlist_from_PMS(playlist, playlist_id=None, repeat=None):
|
||||||
|
"""
|
||||||
|
Updates Kodi playlist using a new PMS playlist. Pass in playlist_id if we
|
||||||
|
need to fetch a new playqueue
|
||||||
|
"""
|
||||||
|
xml = get_PMS_playlist(playlist, playlist_id)
|
||||||
|
try:
|
||||||
|
xml.attrib['%sVersion' % playlist.kind]
|
||||||
|
except:
|
||||||
|
log.error('Could not download Plex playlist.')
|
||||||
return
|
return
|
||||||
|
# Clear our existing playlist and the associated Kodi playlist
|
||||||
window('plex_customplaylist', value="true")
|
playlist.clear()
|
||||||
if offset != 0:
|
# Set new values
|
||||||
# Seek to the starting position
|
_get_playlist_details_from_xml(playlist, xml)
|
||||||
window('plex_customplaylist.seektime', str(offset))
|
if repeat:
|
||||||
self._processItems(startitem, startPlayer=True)
|
playlist.repeat = repeat
|
||||||
# Log playlist
|
for plex_item in xml:
|
||||||
self._verifyPlaylist()
|
playlist.items.append(add_to_Kodi_playlist(playlist, plex_item))
|
||||||
log.debug('Internal playlist: %s' % self.items)
|
|
||||||
|
|
||||||
|
|
||||||
def _processItems(self, startitem, startPlayer=False):
|
def _processItems(self, startitem, startPlayer=False):
|
||||||
|
@ -380,15 +443,3 @@ def _addtoPlaylist_xbmc(self, item):
|
||||||
playbackutils.PlaybackUtils(item).setArtwork(listitem)
|
playbackutils.PlaybackUtils(item).setArtwork(listitem)
|
||||||
|
|
||||||
self.playlist.add(playurl, listitem)
|
self.playlist.add(playurl, listitem)
|
||||||
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
"""
|
|
||||||
Empties current Kodi playlist and associated variables
|
|
||||||
"""
|
|
||||||
self.playlist.clear()
|
|
||||||
self.items = []
|
|
||||||
self.queueId = None
|
|
||||||
self.playQueueVersion = None
|
|
||||||
self.guid = None
|
|
||||||
log.info('Playlist cleared')
|
|
|
@ -5,10 +5,10 @@ from threading import Lock, Thread
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
|
|
||||||
from utils import ThreadMethods, ThreadMethodsAdditionalSuspend, Lock_Function
|
from utils import window, ThreadMethods, ThreadMethodsAdditionalSuspend, \
|
||||||
|
Lock_Function
|
||||||
import playlist_func as PL
|
import playlist_func as PL
|
||||||
from PlexFunctions import KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE, GetPlayQueue, \
|
from PlexFunctions import ConvertPlexToKodiTime
|
||||||
ParseContainerKey
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
log = logging.getLogger("PLEX."+__name__)
|
log = logging.getLogger("PLEX."+__name__)
|
||||||
|
@ -36,6 +36,7 @@ class Playqueue(Thread):
|
||||||
if self.playqueues is not None:
|
if self.playqueues is not None:
|
||||||
return
|
return
|
||||||
self.mgr = callback
|
self.mgr = callback
|
||||||
|
self.player = xbmc.Player()
|
||||||
|
|
||||||
# Initialize Kodi playqueues
|
# Initialize Kodi playqueues
|
||||||
self.playqueues = []
|
self.playqueues = []
|
||||||
|
@ -52,8 +53,64 @@ class Playqueue(Thread):
|
||||||
# Currently, only video or audio playqueues available
|
# Currently, only video or audio playqueues available
|
||||||
playqueue.kodi_pl = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
playqueue.kodi_pl = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||||
self.playqueues.append(playqueue)
|
self.playqueues.append(playqueue)
|
||||||
|
# sort the list by their playlistid, just in case
|
||||||
|
self.playqueues = sorted(
|
||||||
|
self.playqueues, key=lambda i: i.playlistid)
|
||||||
log.debug('Initialized the Kodi play queues: %s' % self.playqueues)
|
log.debug('Initialized the Kodi play queues: %s' % self.playqueues)
|
||||||
|
|
||||||
|
def get_playqueue_from_type(self, typus):
|
||||||
|
"""
|
||||||
|
Returns the playqueue according to the typus ('video', 'audio',
|
||||||
|
'picture') passed in
|
||||||
|
"""
|
||||||
|
for playqueue in self.playqueues:
|
||||||
|
if playqueue.type == typus:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError('Wrong type was passed in: %s' % typus)
|
||||||
|
return playqueue
|
||||||
|
|
||||||
|
def get_playqueue_from_playerid(self, kodi_player_id):
|
||||||
|
for playqueue in self.playqueues:
|
||||||
|
if playqueue.playlistid == kodi_player_id:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError('Wrong kodi_player_id passed was passed in: %s'
|
||||||
|
% kodi_player_id)
|
||||||
|
return playqueue
|
||||||
|
|
||||||
|
@lockmethod.lockthis
|
||||||
|
def update_playqueue_from_PMS(self,
|
||||||
|
playqueue,
|
||||||
|
playqueue_id=None,
|
||||||
|
repeat=None):
|
||||||
|
"""
|
||||||
|
Completely updates the Kodi playqueue with the new Plex playqueue. Pass
|
||||||
|
in playqueue_id if we need to fetch a new playqueue
|
||||||
|
|
||||||
|
repeat = 0, 1, 2
|
||||||
|
"""
|
||||||
|
log.info('New playqueue received, updating!')
|
||||||
|
PL.update_playlist_from_PMS(playqueue, playqueue_id, repeat)
|
||||||
|
log.debug('Updated playqueue: %s' % playqueue)
|
||||||
|
|
||||||
|
window('plex_customplaylist', value="true")
|
||||||
|
if playqueue.selectedItemOffset not in (None, "0"):
|
||||||
|
window('plex_customplaylist.seektime',
|
||||||
|
str(ConvertPlexToKodiTime(playqueue.selectedItemOffset)))
|
||||||
|
for startpos, item in enumerate(playqueue.items):
|
||||||
|
if item.ID == playqueue.selectedItemID:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
startpos = None
|
||||||
|
# Start playback
|
||||||
|
if startpos:
|
||||||
|
self.player.play(playqueue.kodi_pl, startpos=startpos)
|
||||||
|
else:
|
||||||
|
self.player.play(playqueue.kodi_pl)
|
||||||
|
log.debug('Playqueue at the end: %s' % playqueue)
|
||||||
|
playqueue.log_Kodi_playlist()
|
||||||
|
|
||||||
@lockmethod.lockthis
|
@lockmethod.lockthis
|
||||||
def update_playqueue_with_companion(self, data):
|
def update_playqueue_with_companion(self, data):
|
||||||
"""
|
"""
|
||||||
|
@ -61,10 +118,6 @@ class Playqueue(Thread):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get the correct queue
|
# Get the correct queue
|
||||||
for playqueue in self.playqueues:
|
|
||||||
if playqueue.type == KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[
|
|
||||||
data['type']]:
|
|
||||||
break
|
|
||||||
|
|
||||||
@lockmethod.lockthis
|
@lockmethod.lockthis
|
||||||
def kodi_onadd(self, data):
|
def kodi_onadd(self, data):
|
||||||
|
@ -80,11 +133,20 @@ class Playqueue(Thread):
|
||||||
for playqueue in self.playqueues:
|
for playqueue in self.playqueues:
|
||||||
if playqueue.playlistid == data['playlistid']:
|
if playqueue.playlistid == data['playlistid']:
|
||||||
break
|
break
|
||||||
|
if playqueue.PKC_playlist_edits:
|
||||||
|
old = (data['item'].get('id') if data['item'].get('id')
|
||||||
|
else data['item'].get('file'))
|
||||||
|
for i, item in enumerate(playqueue.PKC_playlist_edits):
|
||||||
|
if old == item:
|
||||||
|
log.debug('kodimonitor told us of a PKC edit - ignore.')
|
||||||
|
del playqueue.PKC_playlist_edits[i]
|
||||||
|
return
|
||||||
if playqueue.ID is None:
|
if playqueue.ID is None:
|
||||||
# Need to initialize the queue for the first time
|
# Need to initialize the queue for the first time
|
||||||
PL.init_Plex_playlist(playqueue, kodi_item=data['item'])
|
PL.init_Plex_playlist(playqueue, kodi_item=data['item'])
|
||||||
else:
|
else:
|
||||||
PL.add_playlist_item(playqueue, data['item'], data['position'])
|
PL.add_playlist_item(playqueue, data['item'], data['position'])
|
||||||
|
log.debug('Added a new item to the playqueue: %s' % playqueue)
|
||||||
|
|
||||||
@lockmethod.lockthis
|
@lockmethod.lockthis
|
||||||
def _compare_playqueues(self, playqueue, new):
|
def _compare_playqueues(self, playqueue, new):
|
||||||
|
|
|
@ -15,7 +15,7 @@ log = logging.getLogger("PLEX."+__name__)
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionManager:
|
class SubscriptionManager:
|
||||||
def __init__(self, jsonClass, RequestMgr, player, playlist):
|
def __init__(self, jsonClass, RequestMgr, player, mgr):
|
||||||
self.serverlist = []
|
self.serverlist = []
|
||||||
self.subscribers = {}
|
self.subscribers = {}
|
||||||
self.info = {}
|
self.info = {}
|
||||||
|
@ -36,7 +36,7 @@ class SubscriptionManager:
|
||||||
self.playerprops = {}
|
self.playerprops = {}
|
||||||
self.doUtils = downloadutils.DownloadUtils().downloadUrl
|
self.doUtils = downloadutils.DownloadUtils().downloadUrl
|
||||||
self.xbmcplayer = player
|
self.xbmcplayer = player
|
||||||
self.playlist = playlist
|
self.playqueue = mgr.playqueue
|
||||||
|
|
||||||
self.js = jsonClass
|
self.js = jsonClass
|
||||||
self.RequestMgr = RequestMgr
|
self.RequestMgr = RequestMgr
|
||||||
|
@ -231,6 +231,8 @@ class SubscriptionManager:
|
||||||
|
|
||||||
def getPlayerProperties(self, playerid):
|
def getPlayerProperties(self, playerid):
|
||||||
try:
|
try:
|
||||||
|
# Get the playqueue
|
||||||
|
playqueue = self.playqueue.playqueues[playerid]
|
||||||
# get info from the player
|
# get info from the player
|
||||||
props = self.js.jsonrpc(
|
props = self.js.jsonrpc(
|
||||||
"Player.GetProperties",
|
"Player.GetProperties",
|
||||||
|
@ -248,18 +250,16 @@ class SubscriptionManager:
|
||||||
'shuffle': ("0", "1")[props.get('shuffled', False)],
|
'shuffle': ("0", "1")[props.get('shuffled', False)],
|
||||||
'repeat': pf.getPlexRepeat(props.get('repeat')),
|
'repeat': pf.getPlexRepeat(props.get('repeat')),
|
||||||
}
|
}
|
||||||
if self.playlist is not None:
|
if playqueue.ID is not None:
|
||||||
if self.playlist.QueueId() is not None:
|
info['playQueueID'] = playqueue.ID
|
||||||
info['playQueueID'] = self.playlist.QueueId()
|
info['playQueueVersion'] = playqueue.version
|
||||||
info['playQueueVersion'] = self.playlist.PlayQueueVersion()
|
|
||||||
info['guid'] = self.playlist.Guid()
|
|
||||||
# Get the playlist position
|
# Get the playlist position
|
||||||
pos = self.js.jsonrpc(
|
pos = self.js.jsonrpc(
|
||||||
"Player.GetProperties",
|
"Player.GetProperties",
|
||||||
{"playerid": playerid,
|
{"playerid": playerid,
|
||||||
"properties": ["position"]})
|
"properties": ["position"]})['position']
|
||||||
info['playQueueItemID'] = \
|
info['playQueueItemID'] = playqueue.items[pos].ID
|
||||||
self.playlist.getQueueIdFromPosition(pos['position'])
|
info['guid'] = playqueue.items[pos].guid
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
log.error("Traceback:\n%s" % traceback.format_exc())
|
log.error("Traceback:\n%s" % traceback.format_exc())
|
||||||
|
|
Loading…
Reference in a new issue