PlexKodiConnect/resources/lib/playback_starter.py

138 lines
4.9 KiB
Python
Raw Normal View History

#!/usr/bin/env python
2017-01-03 00:07:24 +11:00
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals
2017-12-10 00:35:08 +11:00
from logging import getLogger
2017-01-03 00:07:24 +11:00
2019-05-25 21:35:14 +10:00
from .plex_api import API
from . import utils, context_entry, transfer, backgroundthread, variables as v
from . import app, plex_functions as PF, playqueue as PQ, playlist_func as PL
2017-01-03 00:07:24 +11:00
###############################################################################
2018-06-22 03:24:37 +10:00
LOG = getLogger('PLEX.playback_starter')
2017-01-03 00:07:24 +11:00
###############################################################################
class PlaybackTask(backgroundthread.Task):
2017-01-03 00:07:24 +11:00
"""
Processes new plays
"""
def __init__(self, command):
self.command = command
super(PlaybackTask, self).__init__()
def run(self):
LOG.debug('Starting PlaybackTask with %s', self.command)
item = self.command
try:
_, params = item.split('?', 1)
except ValueError:
# E.g. other add-ons scanning for Extras folder
LOG.debug('Detected 3rd party add-on call - ignoring')
transfer.send(True)
return
2019-03-30 20:32:56 +11:00
params = dict(utils.parse_qsl(params))
mode = params.get('mode')
2018-04-16 02:13:48 +10:00
resolve = False if params.get('handle') == '-1' else True
LOG.debug('Received mode: %s, params: %s', mode, params)
2019-05-25 21:35:14 +10:00
if mode == 'plex_node':
process_indirect(params['key'],
params['offset'],
resolve=resolve)
2018-01-11 06:14:05 +11:00
elif mode == 'context_menu':
2018-06-22 03:24:37 +10:00
context_entry.ContextMenu(kodi_id=params.get('kodi_id'),
kodi_type=params.get('kodi_type'))
LOG.debug('Finished PlaybackTask')
2019-05-25 21:35:14 +10:00
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, resolve: %s',
key, offset, resolve)
global RESOLVE
RESOLVE = resolve
offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset)) if offset != '0' else None
if key.startswith('http') or key.startswith('{server}'):
xml = PF.get_playback_xml(key, app.CONN.server_name)
elif key.startswith('/system/services'):
xml = PF.get_playback_xml('http://node.plexapp.com:32400%s' % key,
'plexapp.com',
authenticate=False,
token=app.ACCOUNT.plex_token)
else:
xml = PF.get_playback_xml('{server}%s' % key, app.CONN.server_name)
if xml is None:
_ensure_resolve(abort=True)
return
api = API(xml[0])
listitem = transfer.PKCListItem()
api.create_listitem(listitem)
playqueue = PQ.get_playqueue_from_type(
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
playqueue.clear()
item = PL.PlaylistItem(xml_video_element=xml[0])
item.offset = offset
item.playmethod = 'DirectStream'
# Need to get yet another xml to get the final playback url
try:
xml = PF.get_playback_xml('http://node.plexapp.com:32400%s'
% xml[0][0][0].attrib['key'],
'plexapp.com',
authenticate=False,
token=app.ACCOUNT.plex_token)
except (TypeError, IndexError, AttributeError):
LOG.error('XML malformed: %s', xml.attrib)
xml = None
if xml is None:
_ensure_resolve(abort=True)
return
try:
playurl = xml[0].attrib['key']
except (TypeError, IndexError, AttributeError):
LOG.error('Last xml malformed: %s\n%s', xml.tag, xml.attrib)
_ensure_resolve(abort=True)
return
item.file = playurl
listitem.setPath(playurl.encode('utf-8'))
playqueue.items.append(item)
if resolve is True:
transfer.send(listitem)
else:
LOG.info('Done initializing PKC playback, starting Kodi player')
app.APP.player.play(item=playurl.encode('utf-8'),
listitem=listitem)
def _ensure_resolve(abort=False):
"""
Will check whether RESOLVE=True and if so, fail Kodi playback startup
with the path 'PKC_Dummy_Path_Which_Fails' using setResolvedUrl (and some
pickling)
This way we're making sure that other Python instances (calling default.py)
will be destroyed.
"""
if RESOLVE:
# Releases the other Python thread without a ListItem
transfer.send(True)
# Shows PKC error message
# transfer.send(None)
if abort:
# Reset some playback variables
app.PLAYSTATE.context_menu_play = False
app.PLAYSTATE.force_transcode = False
app.PLAYSTATE.resume_playback = False