From dfd5297cd305c001db922bbed366b2149d9c4e40 Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 28 Jan 2018 17:21:28 +0100 Subject: [PATCH] Revamp playback start, part 7 --- resources/lib/entrypoint.py | 7 +- resources/lib/playback.py | 72 ++++++++++++++++-- resources/lib/playback_starter.py | 120 ++---------------------------- 3 files changed, 75 insertions(+), 124 deletions(-) diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index a4913489..7305a3cd 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -820,7 +820,7 @@ def __build_item(xml_element): params = { 'mode': 'plex_node', 'key': xml_element.attrib.get('key'), - 'view_offset': xml_element.attrib.get('viewOffset', '0'), + 'offset': xml_element.attrib.get('viewOffset', '0'), } url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params)) elif api.getType() == v.PLEX_TYPE_PHOTO: @@ -828,9 +828,8 @@ def __build_item(xml_element): else: params = { 'mode': 'play', - 'filename': api.getKey(), - 'id': api.getRatingKey(), - 'dbid': listitem.getProperty('dbid') + 'plex_id': api.getRatingKey(), + 'plex_type': api.getType(), } url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params)) xbmcplugin.addDirectoryItem(handle=HANDLE, diff --git a/resources/lib/playback.py b/resources/lib/playback.py index ea9371bb..76b06077 100644 --- a/resources/lib/playback.py +++ b/resources/lib/playback.py @@ -9,6 +9,7 @@ from xbmc import Player, sleep from PlexAPI import API from PlexFunctions import GetPlexMetadata, init_plex_playqueue +from downloadutils import DownloadUtils as DU import plexdb_functions as plexdb import playlist_func as PL import playqueue as PQ @@ -28,6 +29,71 @@ LOG = getLogger("PLEX." + __name__) ############################################################################### +def process_indirect(key, offset, resolve=True): + """ + Called e.g. for Plex "Play later" - Plex items where we need to fetch an + additional xml for the actual playurl. In the PMS metadata, indirect="1" is + set. + + Will release default.py with setResolvedUrl + + Set resolve to False if playback should be kicked off directly, not via + setResolvedUrl + """ + LOG.info('process_indirect called with key: %s, offset: %s', key, offset) + result = Playback_Successful() + if key.startswith('http') or key.startswith('{server}'): + xml = DU().downloadUrl(key) + else: + xml = DU().downloadUrl('{server}%s' % key) + try: + xml[0].attrib + except (TypeError, IndexError, AttributeError): + LOG.error('Could not download PMS metadata') + if resolve is True: + # Release default.py + pickle_me(result) + return + if offset != '0': + offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset)) + # Todo: implement offset + api = API(xml[0]) + listitem = PKC_ListItem() + api.CreateListItemFromPlexItem(listitem) + playqueue = PQ.get_playqueue_from_type( + v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()]) + playqueue.clear() + item = PL.Playlist_Item() + item.xml = xml[0] + item.offset = int(offset) + item.plex_type = v.PLEX_TYPE_CLIP + item.playmethod = 'DirectStream' + item.init_done = True + # Need to get yet another xml to get the final playback url + xml = DU().downloadUrl('http://node.plexapp.com:32400%s' + % xml[0][0][0].attrib['key']) + try: + xml[0].attrib + except (TypeError, IndexError, AttributeError): + LOG.error('Could not download last xml for playurl') + if resolve is True: + # Release default.py + pickle_me(result) + return + playurl = xml[0].attrib['key'] + item.file = playurl + listitem.setPath(tryEncode(playurl)) + playqueue.items.append(item) + if resolve is True: + result.listitem = listitem + pickle_me(result) + else: + thread = Thread(target=Player().play, + args={'item': tryEncode(playurl), 'listitem': listitem}) + thread.setDaemon(True) + LOG.info('Done initializing PKC playback, starting Kodi player') + thread.start() + @LOCKER.lockthis def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True): """ @@ -154,12 +220,6 @@ def playback_init(plex_id, plex_type, playqueue): playqueue.clear() PL.get_playlist_details_from_xml(playqueue, xml) stack = _prep_playlist_stack(xml) - # if resume: - # # Need to handle this differently so only 1 dialog is displayed whether - # # user wants to resume to start at the beginning - # LOG.info('Resume detected') - # play_resume(playqueue, xml, stack) - # return # Sleep a bit to let setResolvedUrl do its thing - bit ugly sleep(200) _process_stack(playqueue, stack) diff --git a/resources/lib/playback_starter.py b/resources/lib/playback_starter.py index b1491ee8..dcc7a59f 100644 --- a/resources/lib/playback_starter.py +++ b/resources/lib/playback_starter.py @@ -4,20 +4,8 @@ from logging import getLogger from threading import Thread from urlparse import parse_qsl -from xbmc import Player - -from PKC_listitem import PKC_ListItem from pickler import pickle_me, Playback_Successful -from playbackutils import PlaybackUtils import playback -from utils import window -from PlexFunctions import GetPlexMetadata -from PlexAPI import API -import playqueue as PQ -import variables as v -from downloadutils import DownloadUtils -from PKC_listitem import convert_PKC_to_listitem -import plexdb_functions as plexdb from context_entry import ContextMenu import state @@ -32,118 +20,22 @@ class Playback_Starter(Thread): """ Processes new plays """ - def process_play(self, plex_id, kodi_id=None): - """ - Processes Kodi playback init for ONE item - """ - LOG.info("Process_play called with plex_id %s, kodi_id %s", - plex_id, kodi_id) - if not state.AUTHENTICATED: - LOG.error('Not yet authenticated for PMS, abort starting playback') - # Todo: Warn user with dialog - return - xml = GetPlexMetadata(plex_id) - try: - xml[0].attrib - except (IndexError, TypeError, AttributeError): - LOG.error('Could not get a PMS xml for plex id %s', plex_id) - return - api = API(xml[0]) - if api.getType() == v.PLEX_TYPE_PHOTO: - # Photo - result = Playback_Successful() - listitem = PKC_ListItem() - listitem = api.CreateListItemFromPlexItem(listitem) - result.listitem = listitem - else: - # Video and Music - playqueue = PQ.get_playqueue_from_type( - v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()]) - with PQ.LOCK: - result = PlaybackUtils(xml, playqueue).play( - plex_id, - kodi_id, - xml.attrib.get('librarySectionUUID')) - LOG.info('Done process_play, playqueues: %s', PQ.PLAYQUEUES) - return result - - def process_plex_node(self, url, viewOffset, directplay=False, - node=True): - """ - Called for Plex directories or redirect for playback (e.g. trailers, - clips, watchlater) - """ - LOG.info('process_plex_node called with url: %s, viewOffset: %s', - url, viewOffset) - # Plex redirect, e.g. watch later. Need to get actual URLs - if url.startswith('http') or url.startswith('{server}'): - xml = DownloadUtils().downloadUrl(url) - else: - xml = DownloadUtils().downloadUrl('{server}%s' % url) - try: - xml[0].attrib - except: - LOG.error('Could not download PMS metadata') - return - if viewOffset != '0': - try: - viewOffset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(viewOffset)) - except: - pass - else: - window('plex_customplaylist.seektime', value=str(viewOffset)) - LOG.info('Set resume point to %s', viewOffset) - api = API(xml[0]) - typus = v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()] - if node is True: - plex_id = None - kodi_id = 'plexnode' - else: - plex_id = api.getRatingKey() - kodi_id = None - with plexdb.Get_Plex_DB() as plex_db: - plexdb_item = plex_db.getItem_byId(plex_id) - try: - kodi_id = plexdb_item[0] - except TypeError: - LOG.info('Couldnt find item %s in Kodi db', - api.getRatingKey()) - playqueue = PQ.get_playqueue_from_type(typus) - with PQ.LOCK: - result = PlaybackUtils(xml, playqueue).play( - plex_id, - kodi_id=kodi_id, - plex_lib_UUID=xml.attrib.get('librarySectionUUID')) - if directplay: - if result.listitem: - listitem = convert_PKC_to_listitem(result.listitem) - Player().play(listitem.getfilename(), listitem) - return Playback_Successful() - else: - return result - def triage(self, item): _, params = item.split('?', 1) params = dict(parse_qsl(params)) mode = params.get('mode') LOG.debug('Received mode: %s, params: %s', mode, params) if mode == 'play': - result = playback.playback_triage(plex_id=params.get('plex_id'), - plex_type=params.get('plex_type'), - path=params.get('path')) - elif mode == 'companion': - result = self.process_companion() + playback.playback_triage(plex_id=params.get('plex_id'), + plex_type=params.get('plex_type'), + path=params.get('path')) elif mode == 'plex_node': - result = self.process_plex_node( - params.get('key'), - params.get('view_offset'), - directplay=True if params.get('play_directly') else False, - node=False if params.get('node') == 'false' else True) + playback.process_indirect(params['key'], params['offset']) elif mode == 'context_menu': ContextMenu() result = Playback_Successful() - # Let default.py know! - # pickle_me(result) + # Let default.py know! + pickle_me(result) def run(self): queue = state.COMMAND_PIPELINE_QUEUE