2021-10-31 20:44:27 +11:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from logging import getLogger
|
|
|
|
import copy
|
|
|
|
|
|
|
|
from ..plex_api import API
|
|
|
|
from .. import variables as v
|
|
|
|
from .. import app
|
|
|
|
from .. import utils
|
|
|
|
from .. import plex_functions as PF
|
|
|
|
from .. import playlist_func as PL
|
|
|
|
from .. import exceptions
|
|
|
|
|
|
|
|
log = getLogger('PLEX.companion.playqueue')
|
|
|
|
|
|
|
|
PLUGIN = 'plugin://%s' % v.ADDON_ID
|
|
|
|
|
|
|
|
|
|
|
|
def init_playqueue_from_plex_children(plex_id, transient_token=None):
|
|
|
|
"""
|
|
|
|
Init a new playqueue e.g. from an album. Alexa does this
|
|
|
|
|
|
|
|
Returns the playqueue
|
|
|
|
"""
|
|
|
|
xml = PF.GetAllPlexChildren(plex_id)
|
|
|
|
try:
|
|
|
|
xml[0].attrib
|
|
|
|
except (TypeError, IndexError, AttributeError):
|
|
|
|
log.error('Could not download the PMS xml for %s', plex_id)
|
|
|
|
return
|
|
|
|
playqueue = app.PLAYQUEUES.from_plex_type(xml[0].attrib['type'])
|
|
|
|
playqueue.clear()
|
|
|
|
for i, child in enumerate(xml):
|
|
|
|
api = API(child)
|
|
|
|
try:
|
|
|
|
PL.add_item_to_playlist(playqueue, i, plex_id=api.plex_id)
|
|
|
|
except exceptions.PlaylistError:
|
|
|
|
log.error('Could not add Plex item to our playlist: %s, %s',
|
|
|
|
child.tag, child.attrib)
|
|
|
|
playqueue.plex_transient_token = transient_token
|
|
|
|
log.debug('Firing up Kodi player')
|
|
|
|
app.APP.player.play(playqueue.kodi_pl, None, False, 0)
|
|
|
|
return playqueue
|
|
|
|
|
|
|
|
|
|
|
|
def compare_playqueues(playqueue, new_kodi_playqueue):
|
|
|
|
"""
|
|
|
|
Used to poll the Kodi playqueue and update the Plex playqueue if needed
|
|
|
|
"""
|
|
|
|
old = list(playqueue.items)
|
|
|
|
# We might append to new_kodi_playqueue but will need the original
|
|
|
|
# still back in the main loop
|
|
|
|
new = copy.deepcopy(new_kodi_playqueue)
|
|
|
|
index = list(range(0, len(old)))
|
|
|
|
log.debug('Comparing new Kodi playqueue %s with our play queue %s',
|
|
|
|
new, old)
|
|
|
|
for i, new_item in enumerate(new):
|
|
|
|
if (new_item['file'].startswith('plugin://') and
|
|
|
|
not new_item['file'].startswith(PLUGIN)):
|
|
|
|
# Ignore new media added by other addons
|
|
|
|
continue
|
|
|
|
for j, old_item in enumerate(old):
|
|
|
|
|
|
|
|
if app.APP.stop_pkc:
|
|
|
|
# Chances are that we got an empty Kodi playlist due to
|
|
|
|
# Kodi exit
|
|
|
|
return
|
|
|
|
try:
|
2021-12-05 23:37:57 +11:00
|
|
|
if (old_item.file.startswith('plugin://') and not old_item.file.startswith(PLUGIN)):
|
2021-10-31 20:44:27 +11:00
|
|
|
# Ignore media by other addons
|
|
|
|
continue
|
|
|
|
except AttributeError:
|
|
|
|
# were not passed a filename; ignore
|
|
|
|
pass
|
|
|
|
if 'id' in new_item:
|
|
|
|
identical = (old_item.kodi_id == new_item['id'] and
|
|
|
|
old_item.kodi_type == new_item['type'])
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
plex_id = int(utils.REGEX_PLEX_ID.findall(new_item['file'])[0])
|
|
|
|
except IndexError:
|
|
|
|
log.debug('Comparing paths directly as a fallback')
|
|
|
|
identical = old_item.file == new_item['file']
|
|
|
|
else:
|
|
|
|
identical = plex_id == old_item.plex_id
|
|
|
|
if j == 0 and identical:
|
2021-12-05 23:37:57 +11:00
|
|
|
del old[0], index[0]
|
2021-10-31 20:44:27 +11:00
|
|
|
break
|
|
|
|
elif identical:
|
|
|
|
log.debug('Playqueue item %s moved to position %s',
|
2021-12-05 23:37:57 +11:00
|
|
|
index[j], i)
|
2021-10-31 20:44:27 +11:00
|
|
|
try:
|
2021-12-05 23:37:57 +11:00
|
|
|
PL.move_playlist_item(playqueue, index[j], i)
|
2021-10-31 20:44:27 +11:00
|
|
|
except exceptions.PlaylistError:
|
|
|
|
log.error('Could not modify playqueue positions')
|
|
|
|
log.error('This is likely caused by mixing audio and '
|
|
|
|
'video tracks in the Kodi playqueue')
|
2021-12-05 23:37:57 +11:00
|
|
|
del old[j], index[i]
|
2021-10-31 20:44:27 +11:00
|
|
|
break
|
|
|
|
else:
|
|
|
|
log.debug('Detected new Kodi element at position %s: %s ',
|
|
|
|
i, new_item)
|
|
|
|
try:
|
|
|
|
if playqueue.id is None:
|
|
|
|
PL.init_plex_playqueue(playqueue, kodi_item=new_item)
|
|
|
|
else:
|
|
|
|
PL.add_item_to_plex_playqueue(playqueue,
|
|
|
|
i,
|
|
|
|
kodi_item=new_item)
|
|
|
|
except exceptions.PlaylistError:
|
|
|
|
# Could not add the element
|
|
|
|
pass
|
|
|
|
except KeyError:
|
|
|
|
# Catches KeyError from PL.verify_kodi_item()
|
|
|
|
# Hack: Kodi already started playback of a new item and we
|
|
|
|
# started playback already using kodimonitors
|
|
|
|
# PlayBackStart(), but the Kodi playlist STILL only shows
|
|
|
|
# the old element. Hence ignore playlist difference here
|
|
|
|
log.debug('Detected an outdated Kodi playlist - ignoring')
|
|
|
|
return
|
|
|
|
except IndexError:
|
|
|
|
# This is really a hack - happens when using Addon Paths
|
|
|
|
# and repeatedly starting the same element. Kodi will then
|
|
|
|
# not pass kodi id nor file path AND will also not
|
|
|
|
# start-up playback. Hence kodimonitor kicks off playback.
|
|
|
|
# Also see kodimonitor.py - _playlist_onadd()
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
for j in range(i, len(index)):
|
|
|
|
index[j] += 1
|
|
|
|
for i in reversed(index):
|
|
|
|
if app.APP.stop_pkc:
|
|
|
|
# Chances are that we got an empty Kodi playlist due to
|
|
|
|
# Kodi exit
|
|
|
|
return
|
|
|
|
log.debug('Detected deletion of playqueue element at pos %s', i)
|
|
|
|
try:
|
|
|
|
PL.delete_playlist_item_from_PMS(playqueue, i)
|
|
|
|
except exceptions.PlaylistError:
|
|
|
|
log.error('Could not delete PMS element from position %s', i)
|
|
|
|
log.error('This is likely caused by mixing audio and '
|
|
|
|
'video tracks in the Kodi playqueue')
|
|
|
|
log.debug('Done comparing playqueues')
|