Big update

This commit is contained in:
croneter 2019-05-12 14:38:31 +02:00
parent a1f4960bca
commit ea4a062aac
5 changed files with 272 additions and 154 deletions

View file

@ -63,3 +63,6 @@ class PlayState(object):
self.context_menu_play = False
# Which Kodi player is/has been active? (either int 1, 2 or 3)
self.active_players = set()
# Have we initiated playback via Plex Companion or Alexa - so from the
# Plex side of things?
self.initiated_by_plex = False

View file

@ -322,12 +322,10 @@ class KodiMonitor(xbmc.Monitor):
LOG.debug('Current Kodi playlist: %s', kodi_playlist)
kodi_item = PL.playlist_item_from_kodi(kodi_playlist[position])
if isinstance(self.playqueue.items[0], PL.PlaylistItemDummy):
# Get rid of the very first element in the queue that Kodi marked
# as unplayed (the one to init the queue)
LOG.debug('Deleting the very first playqueue item')
js.playlist_remove(self.playqueue.playlistid, 0)
del self.playqueue.items[0]
position = 0
# This dummy item will be deleted by webservice soon - it won't
# play
LOG.debug('Dummy item detected')
position = 1
elif kodi_item != self.playqueue.items[position]:
LOG.debug('Different playqueue items: %s vs. %s ',
kodi_item, self.playqueue.items[position])
@ -487,9 +485,6 @@ def _record_playstate(status, ended):
playcount += 1
time = 0
with kodi_db.KodiVideoDB() as kodidb:
LOG.error('Setting file_id %s, time %s, totaltime %s, playcount %s, '
'last_played %s',
db_item['kodi_fileid'], time, totaltime, playcount, last_played)
kodidb.set_resume(db_item['kodi_fileid'],
time,
totaltime,

View file

@ -5,8 +5,7 @@ Collection of functions associated with Kodi and Plex playlists and playqueues
"""
from __future__ import absolute_import, division, unicode_literals
from logging import getLogger
import xbmc
import threading
from .plex_api import API
from .plex_db import PlexDB
@ -139,20 +138,59 @@ class PlayQueue(object):
self.force_transcode = None
LOG.debug('Playlist cleared: %s', self)
def init(self, plex_id, plex_type=None, position=None, synched=True,
force_transcode=None):
def play(self, plex_id, plex_type=None, startpos=None, position=None,
synched=True, force_transcode=None):
"""
Initializes the playQueue with e.g. trailers and additional file parts
Pass synched=False if you're sure that this item has not been synched
to Kodi
Or resolves webservice paths to actual paths
"""
LOG.debug('Play called with plex_id %s, plex_type %s, position %s, '
'synched %s, force_transcode %s, startpos %s', plex_id,
plex_type, position, synched, force_transcode, startpos)
resolve = False
try:
if plex_id == self.items[startpos].plex_id:
resolve = True
except IndexError:
pass
if resolve:
LOG.info('Resolving playback')
self._resolve(plex_id, startpos)
else:
LOG.info('Initializing playback')
self.init(plex_id,
plex_type,
startpos,
position,
synched,
force_transcode)
def _resolve(self, plex_id, startpos):
"""
The Plex playqueue has already been initialized. We resolve the path
from original webservice http://127.0.0.1 to the "correct" Plex one
"""
self.index = startpos + 1
xml = PF.GetPlexMetadata(plex_id)
if xml in (None, 401):
raise PlaylistError('Could not get Plex metadata %s for %s',
plex_id, self.items[startpos])
api = API(xml[0])
resume = self._resume_playback(None, xml[0])
self._kodi_add_xml(xml[0], api, resume)
# Add additional file parts, if any exist
self._add_additional_parts(xml)
def init(self, plex_id, plex_type=None, startpos=None, position=None,
synched=True, force_transcode=None):
"""
Initializes the Plex and PKC playqueue for playback
"""
LOG.error('Current Kodi playlist: %s',
js.playlist_get_items(self.playlistid))
LOG.debug('Initializing with plex_id %s, plex_type %s, position %s, '
'synched %s, force_transcode %s, index %s', plex_id,
plex_type, position, synched, force_transcode, self.index)
self.index = position
if self.kodi_pl.size() != len(self.items):
while len(self.items) < self.kodi_pl.size():
# The original item that Kodi put into the playlist, e.g.
# {
# u'title': u'',
@ -161,13 +199,10 @@ class PlayQueue(object):
# u'label': u''
# }
# We CANNOT delete that item right now - so let's add a dummy
# on the PKC side
LOG.debug('Detected Kodi playlist size %s to be off for PKC: %s',
self.kodi_pl.size(), len(self.items))
while len(self.items) < self.kodi_pl.size():
LOG.debug('Adding a dummy item to our playqueue')
playlistitem = PlaylistItemDummy()
self.items.insert(0, playlistitem)
# on the PKC side to keep all indicees lined up.
# The failing item will be deleted in webservice.py
LOG.debug('Adding a dummy item to our playqueue')
self.items.insert(0, PlaylistItemDummy())
self.force_transcode = force_transcode
if synched:
with PlexDB(lock=False) as plexdb:
@ -316,7 +351,11 @@ class PlayQueue(object):
raise PlaylistError('Position %s too large for playlist length %s'
% (pos, len(self.items)))
LOG.debug('Adding item to Kodi playlist at position %s: %s', pos, item)
if item.kodi_id is not None and item.kodi_type is not None:
if listitem:
self.kodi_pl.add(url=listitem.getPath(),
listitem=listitem,
index=pos)
elif item.kodi_id is not None and item.kodi_type is not None:
# This method ensures we have full Kodi metadata, potentially
# with more artwork, for example, than Plex provides
if pos == len(self.items):
@ -330,24 +369,24 @@ class PlayQueue(object):
raise PlaylistError('Kodi did not add item to playlist: %s',
answ)
else:
if not listitem:
if item.xml is None:
LOG.debug('Need to get metadata for item %s', item)
item.xml = PF.GetPlexMetadata(item.plex_id)
if item.xml in (None, 401):
raise PlaylistError('Could not get metadata for %s', item)
listitem = widgets.get_listitem(item.xml, resume=True)
url = 'http://127.0.0.1:%s/plex/play/file.strm' % v.WEBSERVICE_PORT
args = {
'plex_id': self.plex_id,
'plex_type': self.plex_type
}
if item.force_transcode:
args['transcode'] = 'true'
url = utils.extend_url(url, args)
item.file = url
listitem.setPath(url.encode('utf-8'))
self.kodi_pl.add(url=listitem.getPath(),
if item.xml is None:
LOG.debug('Need to get metadata for item %s', item)
item.xml = PF.GetPlexMetadata(item.plex_id)
if item.xml in (None, 401):
raise PlaylistError('Could not get metadata for %s', item)
api = API(item.xml[0])
listitem = widgets.get_listitem(item.xml, resume=True)
url = 'http://127.0.0.1:%s/plex/play/file.strm' % v.WEBSERVICE_PORT
args = {
'plex_id': item.plex_id,
'plex_type': api.plex_type()
}
if item.force_transcode:
args['transcode'] = 'true'
url = utils.extend_url(url, args)
item.file = url
listitem.setPath(url.encode('utf-8'))
self.kodi_pl.add(url=url.encode('utf-8'),
listitem=listitem,
index=pos)
@ -372,9 +411,6 @@ class PlayQueue(object):
except (TypeError, AttributeError, KeyError, IndexError):
raise PlaylistError('Could not add item %s to playlist %s'
% (item, self))
if len(xml) != len(self.items) + 1:
raise PlaylistError('Could not add item %s to playlist %s - wrong'
' length received' % (item, self))
for actual_pos, xml_video_element in enumerate(xml):
api = API(xml_video_element)
if api.plex_id() == item.plex_id:
@ -395,7 +431,7 @@ class PlayQueue(object):
LOG.debug('Removing position %s on the Kodi side for %s', pos, self)
answ = js.playlist_remove(self.playlistid, pos)
if 'error' in answ:
raise PlaylistError('Could not remove item: %s' % answ)
raise PlaylistError('Could not remove item: %s' % answ['error'])
def plex_move_item(self, before, after):
"""
@ -436,9 +472,71 @@ class PlayQueue(object):
self.items.insert(after, self.items.pop(before))
LOG.debug('Done moving items for %s', self)
def start_playback(self, pos=0):
LOG.info('Starting playback at %s for %s', pos, self)
xbmc.Player().play(self.kodi_pl, startpos=pos, windowed=False)
def init_from_xml(self, xml, offset=None, start_plex_id=None, repeat=None,
transient_token=None):
"""
Play all items contained in the xml passed in. Called by Plex Companion.
Either supply the ratingKey of the starting Plex element. Or set
playqueue.selectedItemID
offset [float]: will seek to position offset after playback start
start_plex_id [int]: the plex_id of the element that should be
played
repeat [int]: 0: don't repear
1: repeat item
2: repeat everything
transient_token [unicode]: temporary token received from the PMS
Will stop current playback and start playback at the end
"""
LOG.debug("init_from_xml called with offset %s, start_plex_id %s",
offset, start_plex_id)
app.APP.player.stop()
self.clear()
self.update_details_from_xml(xml)
self.repeat = 0 if not repeat else repeat
self.plex_transient_token = transient_token
for pos, xml_video_element in enumerate(xml):
playlistitem = PlaylistItem(xml_video_element=xml_video_element)
self.kodi_add_item(playlistitem, pos)
self.items.append(playlistitem)
# Where do we start playback?
if start_plex_id is not None:
for startpos, item in enumerate(self.items):
if item.plex_id == start_plex_id:
break
else:
startpos = 0
else:
for startpos, item in enumerate(self.items):
if item.id == self.selectedItemID:
break
else:
startpos = 0
self.start_playback(pos=startpos, offset=offset)
def start_playback(self, pos=0, offset=0):
"""
Seek immediately after kicking off playback is not reliable.
Threaded, since we need to return BEFORE seeking
"""
LOG.info('Starting playback at %s offset %s for %s', pos, offset, self)
thread = threading.Thread(target=self._threaded_playback,
args=(self.kodi_pl, pos, offset))
thread.start()
@staticmethod
def _threaded_playback(kodi_playlist, pos, offset):
app.APP.player.play(kodi_playlist, startpos=pos, windowed=False)
if offset:
i = 0
while not app.APP.is_playing:
app.APP.monitor.waitForAbort(0.1)
i += 1
if i > 50:
LOG.warn('Could not seek to %s', offset)
return
js.seek_to(offset)
class PlaylistItem(object):
@ -1069,7 +1167,7 @@ def move_playlist_item(playlist, before_pos, after_pos):
LOG.debug('Done moving for %s', playlist)
def get_PMS_playlist(playlist, playlist_id=None):
def get_PMS_playlist(playlist=None, playlist_id=None):
"""
Fetches the PMS playlist/playqueue as an XML. Pass in playlist_id if we
need to fetch a new playlist
@ -1077,7 +1175,7 @@ def get_PMS_playlist(playlist, playlist_id=None):
Returns None if something went wrong
"""
playlist_id = playlist_id if playlist_id else playlist.id
if playlist.kind == 'playList':
if playlist and playlist.kind == 'playList':
xml = DU().downloadUrl("{server}/playlists/%s/items" % playlist_id)
else:
xml = DU().downloadUrl("{server}/playQueues/%s" % playlist_id)

View file

@ -15,7 +15,6 @@ from .plex_api import API
from . import utils
from . import plex_functions as PF
from . import playlist_func as PL
from . import playback
from . import json_rpc as js
from . import playqueue as PQ
from . import variables as v
@ -40,6 +39,8 @@ def update_playqueue_from_PMS(playqueue,
repeat = 0, 1, 2
offset = time offset in Plextime (milliseconds)
Will (re)start playback
"""
LOG.info('New playqueue %s received from Plex companion with offset '
'%s, repeat %s', playqueue_id, offset, repeat)
@ -47,21 +48,15 @@ def update_playqueue_from_PMS(playqueue,
if transient_token is None:
transient_token = playqueue.plex_transient_token
with app.APP.lock_playqueues:
xml = PL.get_PMS_playlist(playqueue, playqueue_id)
try:
xml.attrib
except AttributeError:
xml = PL.get_PMS_playlist(playlist_id=playqueue_id)
if xml is None:
LOG.error('Could now download playqueue %s', playqueue_id)
return
playqueue.clear()
try:
PL.get_playlist_details_from_xml(playqueue, xml)
except PL.PlaylistError:
LOG.error('Could not get playqueue ID %s', playqueue_id)
return
playqueue.repeat = 0 if not repeat else int(repeat)
playqueue.plex_transient_token = transient_token
playback.play_xml(playqueue, xml, offset)
raise PL.PlaylistError()
app.PLAYSTATE.initiated_by_plex = True
playqueue.init_from_xml(xml,
offset=offset,
repeat=0 if not repeat else int(repeat),
transient_token=transient_token)
class PlexCompanion(backgroundthread.KillableThread):
@ -81,45 +76,48 @@ class PlexCompanion(backgroundthread.KillableThread):
@staticmethod
def _process_alexa(data):
app.PLAYSTATE.initiated_by_plex = True
xml = PF.GetPlexMetadata(data['key'])
try:
xml[0].attrib
except (AttributeError, IndexError, TypeError):
LOG.error('Could not download Plex metadata for: %s', data)
return
raise PL.PlaylistError()
api = API(xml[0])
if api.plex_type() == v.PLEX_TYPE_ALBUM:
LOG.debug('Plex music album detected')
PQ.init_playqueue_from_plex_children(
api.plex_id(),
transient_token=data.get('token'))
xml = PF.GetAllPlexChildren(api.plex_id())
try:
xml[0].attrib
except (TypeError, IndexError, AttributeError):
LOG.error('Could not download the album xml for %s', data)
raise PL.PlaylistError()
playqueue = PQ.get_playqueue_from_type('audio')
playqueue.init_from_xml(xml,
transient_token=data.get('token'))
elif data['containerKey'].startswith('/playQueues/'):
_, container_key, _ = PF.ParseContainerKey(data['containerKey'])
xml = PF.DownloadChunks('{server}/playQueues/%s' % container_key)
if xml is None:
# "Play error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
return
LOG.error('Could not get playqueue for %s', data)
raise PL.PlaylistError()
playqueue = PQ.get_playqueue_from_type(
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
playqueue.clear()
PL.get_playlist_details_from_xml(playqueue, xml)
playqueue.plex_transient_token = data.get('token')
if data.get('offset') != '0':
if data.get('offset') not in ('0', None):
offset = float(data['offset']) / 1000.0
else:
offset = None
playback.play_xml(playqueue, xml, offset)
playqueue.init_from_xml(xml,
offset=offset,
transient_token=data.get('token'))
else:
app.CONN.plex_transient_token = data.get('token')
if data.get('offset') != '0':
if data.get('offset') not in (None, '0'):
app.PLAYSTATE.resume_playback = True
playback.playback_triage(api.plex_id(),
api.plex_type(),
resolve=False)
path = ('http://127.0.0.1:%s/plex/play/file.strm?plex_id=%s'
% (v.WEBSERVICE_PORT, api.plex_id()))
path += '&plex_type=%s' % api.plex_type()
executebuiltin(('PlayMedia(%s)' % path).encode('utf-8'))
@staticmethod
def _process_node(data):
@ -150,7 +148,7 @@ class PlexCompanion(backgroundthread.KillableThread):
xml[0].attrib
except (AttributeError, IndexError, TypeError):
LOG.error('Could not download Plex metadata')
return
raise PL.PlaylistError()
api = API(xml[0])
playqueue = PQ.get_playqueue_from_type(
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
@ -167,20 +165,23 @@ class PlexCompanion(backgroundthread.KillableThread):
"""
playqueue = PQ.get_playqueue_from_type(
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']])
pos = js.get_position(playqueue.playlistid)
if 'audioStreamID' in data:
index = playqueue.items[pos].kodi_stream_index(
data['audioStreamID'], 'audio')
app.APP.player.setAudioStream(index)
elif 'subtitleStreamID' in data:
if data['subtitleStreamID'] == '0':
app.APP.player.showSubtitles(False)
else:
try:
pos = js.get_position(playqueue.playlistid)
if 'audioStreamID' in data:
index = playqueue.items[pos].kodi_stream_index(
data['subtitleStreamID'], 'subtitle')
app.APP.player.setSubtitleStream(index)
else:
LOG.error('Unknown setStreams command: %s', data)
data['audioStreamID'], 'audio')
app.APP.player.setAudioStream(index)
elif 'subtitleStreamID' in data:
if data['subtitleStreamID'] == '0':
app.APP.player.showSubtitles(False)
else:
index = playqueue.items[pos].kodi_stream_index(
data['subtitleStreamID'], 'subtitle')
app.APP.player.setSubtitleStream(index)
else:
LOG.error('Unknown setStreams command: %s', data)
except KeyError:
LOG.warn('Could not process stream data: %s', data)
@staticmethod
def _process_refresh(data):
@ -220,23 +221,29 @@ class PlexCompanion(backgroundthread.KillableThread):
"""
LOG.debug('Processing: %s', task)
data = task['data']
if task['action'] == 'alexa':
with app.APP.lock_playqueues:
self._process_alexa(data)
elif (task['action'] == 'playlist' and
data.get('address') == 'node.plexapp.com'):
self._process_node(data)
elif task['action'] == 'playlist':
with app.APP.lock_playqueues:
self._process_playlist(data)
elif task['action'] == 'refreshPlayQueue':
with app.APP.lock_playqueues:
self._process_refresh(data)
elif task['action'] == 'setStreams':
try:
try:
if task['action'] == 'alexa':
with app.APP.lock_playqueues:
self._process_alexa(data)
elif (task['action'] == 'playlist' and
data.get('address') == 'node.plexapp.com'):
self._process_node(data)
elif task['action'] == 'playlist':
with app.APP.lock_playqueues:
self._process_playlist(data)
elif task['action'] == 'refreshPlayQueue':
with app.APP.lock_playqueues:
self._process_refresh(data)
elif task['action'] == 'setStreams':
self._process_streams(data)
except KeyError:
pass
except PL.PlaylistError:
LOG.error('Could not process companion data: %s', data)
# "Play Error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
app.PLAYSTATE.initiated_by_plex = False
def run(self):
"""

View file

@ -13,16 +13,16 @@ import Queue
import xbmc
import xbmcvfs
from .plex_api import API
from .plex_db import PlexDB
from . import backgroundthread, utils, variables as v, app, playqueue as PQ
from . import playlist_func as PL, json_rpc as js
from . import playlist_func as PL, json_rpc as js, plex_functions as PF
LOG = getLogger('PLEX.webservice')
class WebService(backgroundthread.KillableThread):
''' Run a webservice to trigger playback.
'''
def is_alive(self):
@ -48,7 +48,7 @@ class WebService(backgroundthread.KillableThread):
conn.request('QUIT', '/')
conn.getresponse()
except Exception as error:
xbmc.log('Plex.WebService abort error: %s' % error, xbmc.LOGWARNING)
xbmc.log('PLEX.webservice abort error: %s' % error, xbmc.LOGWARNING)
def suspend(self):
"""
@ -124,7 +124,7 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
# Silence "[Errno 10054] An existing connection was forcibly
# closed by the remote host"
return
xbmc.log('Plex.WebService handle error: %s' % error, xbmc.LOGWARNING)
xbmc.log('PLEX.webservice handle error: %s' % error, xbmc.LOGWARNING)
def do_QUIT(self):
''' send 200 OK response, and set server.stop to True
@ -144,7 +144,12 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
if '?' in path:
path = path.split('?', 1)[1]
params = dict(utils.parse_qsl(path))
if 'plex_id' not in params:
LOG.error('No plex_id received for path %s', path)
return
if 'plex_type' in params and params['plex_type'].lower() == 'none':
del params['plex_type']
if 'plex_type' not in params:
LOG.debug('Need to look-up plex_type')
with PlexDB(lock=False) as plexdb:
@ -154,9 +159,20 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
else:
LOG.debug('No plex_type found, using Kodi player id')
players = js.get_players()
params['plex_type'] = v.PLEX_TYPE_CLIP if 'video' in players \
else v.PLEX_TYPE_SONG
if players:
params['plex_type'] = v.PLEX_TYPE_CLIP if 'video' in players \
else v.PLEX_TYPE_SONG
LOG.debug('Using the following plex_type: %s',
params['plex_type'])
else:
xml = PF.GetPlexMetadata(params['plex_id'])
if xml in (None, 401):
LOG.error('Could not get metadata for %s', params)
return
api = API(xml[0])
params['plex_type'] = api.plex_type()
LOG.debug('Got metadata, using plex_type %s',
params['plex_type'])
return params
def do_HEAD(self):
@ -172,7 +188,7 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def handle_request(self, headers_only=False):
'''Send headers and reponse
'''
xbmc.log('Plex.WebService handle_request called. headers %s, path: %s'
xbmc.log('PLEX.webservice handle_request called. headers %s, path: %s'
% (headers_only, self.path), xbmc.LOGDEBUG)
try:
if b'extrafanart' in self.path or b'extrathumbs' in self.path:
@ -311,11 +327,13 @@ class QueuePlay(backgroundthread.KillableThread):
self.synched = not params['synched'].lower() == 'false'
def _get_playqueue(self):
if (self.plex_type in v.PLEX_VIDEOTYPES and
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):
playqueue = PQ.get_playqueue_from_type(v.KODI_TYPE_VIDEO)
if ((self.plex_type in v.PLEX_VIDEOTYPES and
not app.PLAYSTATE.initiated_by_plex and
xbmc.getCondVisibility('Window.IsVisible(Home.xml)'))):
# Video launched from a widget - which starts a Kodi AUDIO playlist
# We will empty everything and start with a fresh VIDEO playlist
LOG.debug('Widget video playback detected; relaunching')
LOG.debug('Widget video playback detected')
video_widget_playback = True
# Release default.py
utils.window('plex.playlist.ready', value='true')
@ -335,14 +353,9 @@ class QueuePlay(backgroundthread.KillableThread):
else:
LOG.debug('Audio playback detected')
playqueue = PQ.get_playqueue_from_type(v.KODI_TYPE_AUDIO)
playqueue.clear(kodi=False)
return playqueue, video_widget_playback
def run(self):
"""
We cannot use js.get_players() to reliably get the active player
Use Kodimonitor's OnNotification and OnAdd
"""
LOG.debug('##===---- Starting QueuePlay ----===##')
abort = False
play_folder = False
@ -358,6 +371,8 @@ class QueuePlay(backgroundthread.KillableThread):
# Position to add next element to queue - we're doing this at the end
# of our current playqueue
position = playqueue.kodi_pl.size()
# Set to start_position + 1 because first item will fail
utils.window('plex.playlist.start', str(start_position + 1))
LOG.debug('start_position %s, position %s for current playqueue: %s',
start_position, position, playqueue)
while True:
@ -370,7 +385,7 @@ class QueuePlay(backgroundthread.KillableThread):
LOG.debug('Wrapping up')
if xbmc.getCondVisibility('VideoPlayer.Content(livetv)'):
# avoid issues with ongoing Live TV playback
xbmc.Player().stop()
app.APP.player.stop()
count = 50
while not utils.window('plex.playlist.ready'):
xbmc.sleep(50)
@ -392,48 +407,47 @@ class QueuePlay(backgroundthread.KillableThread):
LOG.info('Start normal playback')
# Release default.py
utils.window('plex.playlist.play', value='true')
# Remove the playlist element we just added with the
# right path
xbmc.sleep(1000)
playqueue.kodi_remove_item(start_position)
del playqueue.items[start_position]
LOG.debug('Done wrapping up')
break
self.load_params(params)
if play_folder:
# position = play.play_folder(position)
item = PL.PlaylistItem(plex_id=self.plex_id,
plex_type=self.plex_type,
kodi_id=self.kodi_id,
kodi_type=self.kodi_type)
item.force_transcode = self.force_transcode
playqueue.add_item(item, position)
playlistitem = PL.PlaylistItem(plex_id=self.plex_id,
plex_type=self.plex_type,
kodi_id=self.kodi_id,
kodi_type=self.kodi_type)
playlistitem.force_transcode = self.force_transcode
playqueue.add_item(playlistitem, position)
position += 1
else:
if self.server.pending.count(params['plex_id']) != len(self.server.pending):
# E.g. when selecting "play" for an entire video genre
LOG.debug('Folder playback detected')
play_folder = True
# Set to start_position + 1 because first item will fail
utils.window('plex.playlist.start', str(start_position + 1))
playqueue.init(self.plex_id,
xbmc.executebuiltin('Activateutils.window(busydialognocancel)')
playqueue.play(self.plex_id,
plex_type=self.plex_type,
startpos=start_position,
position=position,
synched=self.synched,
force_transcode=self.force_transcode)
# Do NOT start playback here - because Kodi already started
# it!
# playqueue.start_playback(position)
position = playqueue.index
if play_folder:
xbmc.executebuiltin('Activateutils.window(busydialognocancel)')
except PL.PlaylistError as error:
abort = True
LOG.warn('Not playing due to the following: %s', error)
except Exception:
abort = True
utils.ERROR()
utils.ERROR(notify=True)
try:
self.server.queue.task_done()
except ValueError:
# "task_done() called too many times"
# "task_done() called too many times" when aborting
pass
if abort:
xbmc.Player().stop()
app.APP.player.stop()
playqueue.clear()
self.server.queue.queue.clear()
if play_folder:
@ -444,6 +458,7 @@ class QueuePlay(backgroundthread.KillableThread):
utils.window('plex.playlist.ready', clear=True)
utils.window('plex.playlist.start', clear=True)
app.PLAYSTATE.initiated_by_plex = False
self.server.threads.remove(self)
self.server.pending = []
LOG.debug('##===---- QueuePlay Stopped ----===##')