PlexKodiConnect/resources/lib/playqueue.py

189 lines
7.9 KiB
Python
Raw Normal View History

2016-12-28 03:33:52 +11:00
# -*- coding: utf-8 -*-
###############################################################################
import logging
2017-01-03 00:07:24 +11:00
from threading import RLock, Thread
2016-12-28 03:33:52 +11:00
2017-01-03 00:07:24 +11:00
from xbmc import sleep, Player, PlayList, PLAYLIST_MUSIC, PLAYLIST_VIDEO
2016-12-28 03:33:52 +11:00
2017-01-03 00:07:24 +11:00
from utils import window, ThreadMethods, ThreadMethodsAdditionalSuspend
2016-12-28 03:33:52 +11:00
import playlist_func as PL
2016-12-28 23:14:21 +11:00
from PlexFunctions import ConvertPlexToKodiTime
2017-01-10 05:56:57 +11:00
from playbackutils import PlaybackUtils
2016-12-28 03:33:52 +11:00
###############################################################################
log = logging.getLogger("PLEX."+__name__)
2017-01-03 00:07:24 +11:00
# Lock used for playqueue manipulations
lock = RLock()
2016-12-28 03:33:52 +11:00
###############################################################################
@ThreadMethodsAdditionalSuspend('plex_serverStatus')
@ThreadMethods
class Playqueue(Thread):
"""
Monitors Kodi's playqueues for changes on the Kodi side
"""
# Borg - multiple instances, shared state
__shared_state = {}
playqueues = None
def __init__(self, callback=None):
self.__dict__ = self.__shared_state
if self.playqueues is not None:
return
self.mgr = callback
# Initialize Kodi playqueues
2017-01-03 00:07:24 +11:00
with lock:
self.playqueues = []
for queue in PL.get_kodi_playqueues():
playqueue = PL.Playqueue_Object()
playqueue.playlistid = queue['playlistid']
playqueue.type = queue['type']
# Initialize each Kodi playlist
if playqueue.type == 'audio':
playqueue.kodi_pl = PlayList(PLAYLIST_MUSIC)
elif playqueue.type == 'video':
playqueue.kodi_pl = PlayList(PLAYLIST_VIDEO)
else:
# Currently, only video or audio playqueues available
playqueue.kodi_pl = PlayList(PLAYLIST_VIDEO)
self.playqueues.append(playqueue)
# sort the list by their playlistid, just in case
self.playqueues = sorted(
self.playqueues, key=lambda i: i.playlistid)
2016-12-28 03:33:52 +11:00
log.debug('Initialized the Kodi play queues: %s' % self.playqueues)
2017-01-03 01:41:38 +11:00
Thread.__init__(self)
2016-12-28 03:33:52 +11:00
2016-12-28 23:14:21 +11:00
def get_playqueue_from_type(self, typus):
"""
Returns the playqueue according to the typus ('video', 'audio',
'picture') passed in
"""
2017-01-03 00:07:24 +11:00
with lock:
for playqueue in self.playqueues:
if playqueue.type == typus:
break
else:
raise ValueError('Wrong playlist type passed in: %s' % typus)
return playqueue
2016-12-30 01:41:14 +11:00
2016-12-28 23:14:21 +11:00
def update_playqueue_from_PMS(self,
playqueue,
playqueue_id=None,
2016-12-29 00:57:10 +11:00
repeat=None,
offset=None):
2016-12-28 23:14:21 +11:00
"""
Completely updates the Kodi playqueue with the new Plex playqueue. Pass
in playqueue_id if we need to fetch a new playqueue
repeat = 0, 1, 2
2017-01-03 00:07:24 +11:00
offset = time offset in Plextime (milliseconds)
2016-12-29 00:48:23 +11:00
"""
2017-01-03 00:07:24 +11:00
log.info('New playqueue %s received from Plex companion with offset '
'%s, repeat %s' % (playqueue_id, offset, repeat))
with lock:
if playqueue_id != playqueue.ID:
log.debug('Need to fetch new playQueue from the PMS')
2017-01-09 01:03:41 +11:00
xml = PL.get_PMS_playlist(playqueue, playqueue_id)
2017-01-10 05:56:57 +11:00
if xml is None:
log.error('Could not get playqueue ID %s' % playqueue_id)
return
playqueue.clear()
PL.get_playlist_details_from_xml(playqueue, xml)
PlaybackUtils(xml, playqueue).play_all()
2017-01-03 00:07:24 +11:00
else:
log.debug('Restarting existing playQueue')
PL.refresh_playlist_from_PMS(playqueue)
playqueue.repeat = 0 if not repeat else int(repeat)
window('plex_customplaylist', value="true")
if offset not in (None, "0"):
window('plex_customplaylist.seektime',
str(ConvertPlexToKodiTime(offset)))
for startpos, item in enumerate(playqueue.items):
if item.ID == playqueue.selectedItemID:
break
else:
2017-01-10 05:56:57 +11:00
startpos = 0
2017-01-03 00:07:24 +11:00
# Start playback. Player does not return in time
2017-01-10 05:56:57 +11:00
log.debug('Playqueues after Plex Companion update are now: %s'
% self.playqueues)
log.debug('Start position Plex Companion playback: %s'
% startpos)
thread = Thread(target=Player().play,
args=(playqueue.kodi_pl,
None,
False,
startpos))
2017-01-03 00:07:24 +11:00
thread.setDaemon(True)
thread.start()
2016-12-29 00:48:23 +11:00
2016-12-28 03:33:52 +11:00
def _compare_playqueues(self, playqueue, new):
"""
Used to poll the Kodi playqueue and update the Plex playqueue if needed
"""
2017-01-03 00:07:24 +11:00
old = list(playqueue.items)
2016-12-29 00:48:23 +11:00
index = list(range(0, len(old)))
2016-12-28 03:33:52 +11:00
log.debug('Comparing new Kodi playqueue %s with our play queue %s'
2017-01-03 00:07:24 +11:00
% (new, old))
2016-12-28 03:33:52 +11:00
for i, new_item in enumerate(new):
for j, old_item in enumerate(old):
2017-01-03 00:07:24 +11:00
if self.threadStopped():
# Chances are that we got an empty Kodi playlist due to
# Kodi exit
return
if new_item.get('id') is None:
identical = old_item.file == new_item['file']
2016-12-28 03:33:52 +11:00
else:
2017-01-03 00:07:24 +11:00
identical = (old_item.kodi_id == new_item['id'] and
old_item.kodi_type == new_item['type'])
2016-12-28 03:33:52 +11:00
if j == 0 and identical:
del old[j], index[j]
break
elif identical:
2017-01-03 00:07:24 +11:00
log.debug('Detected playqueue item %s moved to position %s'
% (i+j, i))
2016-12-28 03:33:52 +11:00
PL.move_playlist_item(playqueue, i + j, i)
2016-12-29 00:48:23 +11:00
del old[j], index[j]
2016-12-28 03:33:52 +11:00
break
2017-01-03 00:07:24 +11:00
else:
log.debug('Detected new Kodi element: %s' % new_item)
if playqueue.ID is None:
PL.init_Plex_playlist(playqueue,
kodi_item=new_item)
2016-12-28 03:33:52 +11:00
else:
2017-01-03 00:07:24 +11:00
PL.add_item_to_PMS_playlist(playqueue,
i,
kodi_item=new_item)
for i in reversed(index):
log.debug('Detected deletion of playqueue element at pos %s' % i)
PL.delete_playlist_item_from_PMS(playqueue, i)
log.debug('Done comparing playqueues')
2016-12-29 05:38:43 +11:00
def run(self):
threadStopped = self.threadStopped
threadSuspended = self.threadSuspended
log.info("----===## Starting PlayQueue client ##===----")
# Initialize the playqueues, if Kodi already got items in them
2017-01-03 00:07:24 +11:00
for playqueue in self.playqueues:
for i, item in enumerate(PL.get_kodi_playlist_items(playqueue)):
if i == 0:
PL.init_Plex_playlist(playqueue, kodi_item=item)
else:
PL.add_item_to_PMS_playlist(playqueue, i, kodi_item=item)
2016-12-28 03:33:52 +11:00
while not threadStopped():
while threadSuspended():
if threadStopped():
break
2017-01-03 00:07:24 +11:00
sleep(1000)
with lock:
for playqueue in self.playqueues:
kodi_playqueue = PL.get_kodi_playlist_items(playqueue)
if playqueue.old_kodi_pl != kodi_playqueue:
# compare old and new playqueue
self._compare_playqueues(playqueue, kodi_playqueue)
playqueue.old_kodi_pl = list(kodi_playqueue)
sleep(50)
2016-12-28 03:33:52 +11:00
log.info("----===## PlayQueue client stopped ##===----")