2017-01-03 00:07:24 +11:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
###############################################################################
|
2017-12-10 00:35:08 +11:00
|
|
|
from logging import getLogger
|
2017-01-03 00:07:24 +11:00
|
|
|
from threading import Thread
|
|
|
|
from urlparse import parse_qsl
|
|
|
|
|
2017-03-14 07:39:07 +11:00
|
|
|
from xbmc import Player
|
|
|
|
|
2017-01-03 00:07:24 +11:00
|
|
|
from PKC_listitem import PKC_ListItem
|
|
|
|
from pickler import pickle_me, Playback_Successful
|
|
|
|
from playbackutils import PlaybackUtils
|
|
|
|
from utils import window
|
2017-01-25 02:04:42 +11:00
|
|
|
from PlexFunctions import GetPlexMetadata
|
2017-01-03 00:07:24 +11:00
|
|
|
from PlexAPI import API
|
2018-01-07 01:19:12 +11:00
|
|
|
import playqueue as PQ
|
2017-01-25 02:04:42 +11:00
|
|
|
import variables as v
|
2017-03-14 07:39:07 +11:00
|
|
|
from downloadutils import DownloadUtils
|
|
|
|
from PKC_listitem import convert_PKC_to_listitem
|
|
|
|
import plexdb_functions as plexdb
|
2017-09-10 23:09:32 +10:00
|
|
|
from context_entry import ContextMenu
|
2017-05-17 18:10:14 +10:00
|
|
|
import state
|
2017-01-03 00:07:24 +11:00
|
|
|
|
|
|
|
###############################################################################
|
2018-01-07 01:19:12 +11:00
|
|
|
|
|
|
|
LOG = getLogger("PLEX." + __name__)
|
2017-01-03 00:07:24 +11:00
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
class Playback_Starter(Thread):
|
|
|
|
"""
|
|
|
|
Processes new plays
|
|
|
|
"""
|
|
|
|
def process_play(self, plex_id, kodi_id=None):
|
|
|
|
"""
|
|
|
|
Processes Kodi playback init for ONE item
|
|
|
|
"""
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.info("Process_play called with plex_id %s, kodi_id %s",
|
|
|
|
plex_id, kodi_id)
|
2017-05-17 18:10:14 +10:00
|
|
|
if not state.AUTHENTICATED:
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.error('Not yet authenticated for PMS, abort starting playback')
|
2017-01-03 00:07:24 +11:00
|
|
|
# Todo: Warn user with dialog
|
|
|
|
return
|
|
|
|
xml = GetPlexMetadata(plex_id)
|
2017-01-09 01:40:47 +11:00
|
|
|
try:
|
|
|
|
xml[0].attrib
|
2017-03-14 06:25:52 +11:00
|
|
|
except (IndexError, TypeError, AttributeError):
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.error('Could not get a PMS xml for plex id %s', plex_id)
|
2017-01-09 01:40:47 +11:00
|
|
|
return
|
2017-01-09 01:43:30 +11:00
|
|
|
api = API(xml[0])
|
2017-01-25 02:04:42 +11:00
|
|
|
if api.getType() == v.PLEX_TYPE_PHOTO:
|
2017-01-03 00:07:24 +11:00
|
|
|
# Photo
|
|
|
|
result = Playback_Successful()
|
|
|
|
listitem = PKC_ListItem()
|
|
|
|
listitem = api.CreateListItemFromPlexItem(listitem)
|
|
|
|
result.listitem = listitem
|
|
|
|
else:
|
|
|
|
# Video and Music
|
2018-01-07 01:19:12 +11:00
|
|
|
playqueue = PQ.get_playqueue_from_type(
|
2017-01-25 02:04:42 +11:00
|
|
|
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()])
|
2018-01-07 01:19:12 +11:00
|
|
|
with PQ.LOCK:
|
2017-01-10 05:56:57 +11:00
|
|
|
result = PlaybackUtils(xml, playqueue).play(
|
2017-01-03 00:07:24 +11:00
|
|
|
plex_id,
|
|
|
|
kodi_id,
|
|
|
|
xml.attrib.get('librarySectionUUID'))
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.info('Done process_play, playqueues: %s', PQ.PLAYQUEUES)
|
2017-01-03 00:07:24 +11:00
|
|
|
return result
|
|
|
|
|
2017-03-14 07:39:07 +11:00
|
|
|
def process_plex_node(self, url, viewOffset, directplay=False,
|
|
|
|
node=True):
|
|
|
|
"""
|
|
|
|
Called for Plex directories or redirect for playback (e.g. trailers,
|
|
|
|
clips, watchlater)
|
|
|
|
"""
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.info('process_plex_node called with url: %s, viewOffset: %s',
|
|
|
|
url, viewOffset)
|
2017-03-14 07:39:07 +11:00
|
|
|
# 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:
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.error('Could not download PMS metadata')
|
2017-03-14 07:39:07 +11:00
|
|
|
return
|
|
|
|
if viewOffset != '0':
|
|
|
|
try:
|
|
|
|
viewOffset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(viewOffset))
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
window('plex_customplaylist.seektime', value=str(viewOffset))
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.info('Set resume point to %s', viewOffset)
|
2017-03-14 07:39:07 +11:00
|
|
|
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:
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.info('Couldnt find item %s in Kodi db',
|
|
|
|
api.getRatingKey())
|
|
|
|
playqueue = PQ.get_playqueue_from_type(typus)
|
|
|
|
with PQ.LOCK:
|
2017-03-14 07:39:07 +11:00
|
|
|
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)
|
2017-03-19 23:54:59 +11:00
|
|
|
return Playback_Successful()
|
2017-03-14 07:39:07 +11:00
|
|
|
else:
|
|
|
|
return result
|
|
|
|
|
2017-01-03 00:07:24 +11:00
|
|
|
def triage(self, item):
|
2017-03-14 07:39:07 +11:00
|
|
|
_, params = item.split('?', 1)
|
2017-01-03 00:07:24 +11:00
|
|
|
params = dict(parse_qsl(params))
|
2017-03-14 07:39:07 +11:00
|
|
|
mode = params.get('mode')
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.debug('Received mode: %s, params: %s', mode, params)
|
2017-01-03 00:07:24 +11:00
|
|
|
try:
|
|
|
|
if mode == 'play':
|
|
|
|
result = self.process_play(params.get('id'),
|
|
|
|
params.get('dbid'))
|
|
|
|
elif mode == 'companion':
|
|
|
|
result = self.process_companion()
|
2017-03-14 07:39:07 +11:00
|
|
|
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)
|
2017-09-10 23:09:32 +10:00
|
|
|
elif mode == 'context_menu':
|
|
|
|
ContextMenu()
|
|
|
|
result = Playback_Successful()
|
2017-01-03 00:07:24 +11:00
|
|
|
except:
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.error('Error encountered for mode %s, params %s',
|
|
|
|
mode, params)
|
2017-01-03 00:07:24 +11:00
|
|
|
import traceback
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.error(traceback.format_exc())
|
2017-01-03 00:07:24 +11:00
|
|
|
# Let default.py know!
|
|
|
|
pickle_me(None)
|
|
|
|
else:
|
|
|
|
pickle_me(result)
|
|
|
|
|
|
|
|
def run(self):
|
2018-01-07 01:19:12 +11:00
|
|
|
queue = state.COMMAND_PIPELINE_QUEUE
|
|
|
|
LOG.info("----===## Starting Playback_Starter ##===----")
|
2017-01-03 00:07:24 +11:00
|
|
|
while True:
|
|
|
|
item = queue.get()
|
|
|
|
if item is None:
|
2017-05-17 18:09:50 +10:00
|
|
|
# Need to shutdown - initiated by command_pipeline
|
2017-01-03 00:07:24 +11:00
|
|
|
break
|
|
|
|
else:
|
|
|
|
self.triage(item)
|
|
|
|
queue.task_done()
|
2018-01-07 01:19:12 +11:00
|
|
|
LOG.info("----===## Playback_Starter stopped ##===----")
|