Revamp playback start, part 7

This commit is contained in:
croneter 2018-01-28 17:21:28 +01:00
parent 0e3a7a1673
commit dfd5297cd3
3 changed files with 75 additions and 124 deletions

View file

@ -820,7 +820,7 @@ def __build_item(xml_element):
params = { params = {
'mode': 'plex_node', 'mode': 'plex_node',
'key': xml_element.attrib.get('key'), '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)) url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
elif api.getType() == v.PLEX_TYPE_PHOTO: elif api.getType() == v.PLEX_TYPE_PHOTO:
@ -828,9 +828,8 @@ def __build_item(xml_element):
else: else:
params = { params = {
'mode': 'play', 'mode': 'play',
'filename': api.getKey(), 'plex_id': api.getRatingKey(),
'id': api.getRatingKey(), 'plex_type': api.getType(),
'dbid': listitem.getProperty('dbid')
} }
url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params)) url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,

View file

@ -9,6 +9,7 @@ from xbmc import Player, sleep
from PlexAPI import API from PlexAPI import API
from PlexFunctions import GetPlexMetadata, init_plex_playqueue from PlexFunctions import GetPlexMetadata, init_plex_playqueue
from downloadutils import DownloadUtils as DU
import plexdb_functions as plexdb import plexdb_functions as plexdb
import playlist_func as PL import playlist_func as PL
import playqueue as PQ 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 @LOCKER.lockthis
def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True): 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() playqueue.clear()
PL.get_playlist_details_from_xml(playqueue, xml) PL.get_playlist_details_from_xml(playqueue, xml)
stack = _prep_playlist_stack(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 a bit to let setResolvedUrl do its thing - bit ugly
sleep(200) sleep(200)
_process_stack(playqueue, stack) _process_stack(playqueue, stack)

View file

@ -4,20 +4,8 @@ from logging import getLogger
from threading import Thread from threading import Thread
from urlparse import parse_qsl from urlparse import parse_qsl
from xbmc import Player
from PKC_listitem import PKC_ListItem
from pickler import pickle_me, Playback_Successful from pickler import pickle_me, Playback_Successful
from playbackutils import PlaybackUtils
import playback 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 from context_entry import ContextMenu
import state import state
@ -32,118 +20,22 @@ class Playback_Starter(Thread):
""" """
Processes new plays 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): def triage(self, item):
_, params = item.split('?', 1) _, params = item.split('?', 1)
params = dict(parse_qsl(params)) params = dict(parse_qsl(params))
mode = params.get('mode') mode = params.get('mode')
LOG.debug('Received mode: %s, params: %s', mode, params) LOG.debug('Received mode: %s, params: %s', mode, params)
if mode == 'play': if mode == 'play':
result = playback.playback_triage(plex_id=params.get('plex_id'), playback.playback_triage(plex_id=params.get('plex_id'),
plex_type=params.get('plex_type'), plex_type=params.get('plex_type'),
path=params.get('path')) path=params.get('path'))
elif mode == 'companion':
result = self.process_companion()
elif mode == 'plex_node': elif mode == 'plex_node':
result = self.process_plex_node( playback.process_indirect(params['key'], params['offset'])
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)
elif mode == 'context_menu': elif mode == 'context_menu':
ContextMenu() ContextMenu()
result = Playback_Successful() result = Playback_Successful()
# Let default.py know! # Let default.py know!
# pickle_me(result) pickle_me(result)
def run(self): def run(self):
queue = state.COMMAND_PIPELINE_QUEUE queue = state.COMMAND_PIPELINE_QUEUE