Revamp playback start, part 7
This commit is contained in:
parent
0e3a7a1673
commit
dfd5297cd3
3 changed files with 75 additions and 124 deletions
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue