Revamp monitor

This commit is contained in:
croneter 2019-04-13 13:29:35 +02:00
parent ad6c160524
commit 643e6171c4

View file

@ -25,6 +25,13 @@ STRINGS = (utils.lang(12021).encode('utf-8'),
utils.lang(12023).encode('utf-8')) utils.lang(12023).encode('utf-8'))
class MonitorError(Exception):
"""
Exception we raise for all errors associated with xbmc.Monitor
"""
pass
class KodiMonitor(xbmc.Monitor): class KodiMonitor(xbmc.Monitor):
""" """
PKC implementation of the Kodi Monitor class. Invoke only once. PKC implementation of the Kodi Monitor class. Invoke only once.
@ -32,11 +39,14 @@ class KodiMonitor(xbmc.Monitor):
def __init__(self): def __init__(self):
self._already_slept = False self._already_slept = False
self.hack_replay = None self.hack_replay = None
# Info to the currently playing item
self.playerid = None
self.playlistid = None self.playlistid = None
xbmc.Monitor.__init__(self) self.playqueue = None
for playerid in app.PLAYSTATE.player_states: for playerid in app.PLAYSTATE.player_states:
app.PLAYSTATE.player_states[playerid] = copy.deepcopy(app.PLAYSTATE.template) app.PLAYSTATE.player_states[playerid] = copy.deepcopy(app.PLAYSTATE.template)
app.PLAYSTATE.old_player_states[playerid] = copy.deepcopy(app.PLAYSTATE.template) app.PLAYSTATE.old_player_states[playerid] = copy.deepcopy(app.PLAYSTATE.template)
xbmc.Monitor.__init__(self)
LOG.info("Kodi monitor started.") LOG.info("Kodi monitor started.")
def onScanStarted(self, library): def onScanStarted(self, library):
@ -74,7 +84,7 @@ class KodiMonitor(xbmc.Monitor):
if method == "Player.OnPlay": if method == "Player.OnPlay":
with app.APP.lock_playqueues: with app.APP.lock_playqueues:
self.PlayBackStart(data) self.on_play(data)
elif method == "Player.OnStop": elif method == "Player.OnStop":
# Should refresh our video nodes, e.g. on deck # Should refresh our video nodes, e.g. on deck
# xbmc.executebuiltin('ReloadSkin()') # xbmc.executebuiltin('ReloadSkin()')
@ -279,7 +289,88 @@ class KodiMonitor(xbmc.Monitor):
json_item.get('type'), json_item.get('type'),
json_item.get('file')) json_item.get('file'))
def PlayBackStart(self, data): def _get_playerid(self, data):
"""
Sets self.playerid with an int 0, 1 [or 2] or raises MonitorError
0: usually video
1: usually audio
"""
try:
self.playerid = data['player']['playerid']
except (TypeError, KeyError):
LOG.info('Aborting playback report - data invalid for updates: %s',
data)
raise MonitorError()
if self.playerid == -1:
# Kodi might return -1 for "last player"
try:
self.playerid = js.get_player_ids()[0]
except IndexError:
LOG.error('Coud not get playerid for data: %s', data)
raise MonitorError()
def _check_playing_item(self, data):
"""
Returns a PF.Playlist_Item() for the currently playing item
Raises MonitorError or IndexError if we need to init the PKC playqueue
"""
info = js.get_player_props(self.playerid)
LOG.debug('Current info for player %s: %s', self.playerid, info)
position = info['position'] if info['position'] != -1 else 0
kodi_playlist = js.playlist_get_items(self.playerid)
LOG.debug('Current Kodi playlist: %s', kodi_playlist)
kodi_item = PL.playlist_item_from_kodi(kodi_playlist[position])
if (position == 1 and
len(kodi_playlist) == len(self.playqueue.items) + 1 and
kodi_playlist[0].get('type') == 'unknown' and
kodi_playlist[0].get('file') and
kodi_playlist[0].get('file').startswith('http://127.0.0.1')):
if kodi_item == self.playqueue.items[0]:
# Delete the very first item that we used to start playback:
# {
# u'title': u'',
# u'type': u'unknown',
# u'file': u'http://127.0.0.1:57578/plex/kodi/....',
# u'label': u''
# }
LOG.debug('Deleting the very first playqueue item')
js.playlist_remove(self.playqueue.playlistid, 0)
position = 0
else:
LOG.debug('Different item in PKC playlist: %s vs. %s',
self.playqueue.items[0], kodi_item)
raise MonitorError()
elif kodi_item != self.playqueue.items[position]:
LOG.debug('Different playqueue items: %s vs. %s ',
kodi_item, self.playqueue.items[position])
raise MonitorError()
# Return the PKC playqueue item - contains more info
return self.playqueue.items[position]
def _load_playerstate(self, item):
"""
Pass in a PF.Playlist_Item(). Will then set the currently playing
state with app.PLAYSTATE.player_states[self.playerid]
"""
if self.playqueue.id:
container_key = '/playQueues/%s' % self.playqueue.id
else:
container_key = '/library/metadata/%s' % item.plex_id
status = app.PLAYSTATE.player_states[self.playerid]
# Remember that this player has been active
app.PLAYSTATE.active_players.add(self.playerid)
status.update(js.get_player_props(self.playerid))
status['container_key'] = container_key
status['file'] = item.file
status['kodi_id'] = item.kodi_id
status['kodi_type'] = item.kodi_type
status['plex_id'] = item.plex_id
status['plex_type'] = item.plex_type
status['playmethod'] = item.playmethod
status['playcount'] = item.playcount
LOG.debug('Set the player state: %s', status)
def on_play(self, data):
""" """
Called whenever playback is started. Example data: Called whenever playback is started. Example data:
{ {
@ -288,87 +379,26 @@ class KodiMonitor(xbmc.Monitor):
} }
Unfortunately when using Widgets, Kodi doesn't tell us shit Unfortunately when using Widgets, Kodi doesn't tell us shit
""" """
# Some init
self._already_slept = False self._already_slept = False
self.playlistid = None
self.playerid = None
# Get the type of media we're playing # Get the type of media we're playing
try: try:
playerid = data['player']['playerid'] self._get_playerid(data)
except (TypeError, KeyError): except MonitorError:
LOG.info('Aborting playback report - item invalid for updates %s',
data)
return return
kodi_id = data['item'].get('id') if 'item' in data else None self.playqueue = PQ.PLAYQUEUES[self.playerid]
kodi_type = data['item'].get('type') if 'item' in data else None LOG.debug('Current PKC playqueue: %s', self.playqueue)
path = data['item'].get('file') if 'item' in data else None item = None
if playerid == -1:
# Kodi might return -1 for "last player"
# Getting the playerid is really a PITA
try:
playerid = js.get_player_ids()[0]
except IndexError:
# E.g. Kodi 18 doesn't tell us anything useful
if kodi_type in v.KODI_VIDEOTYPES:
playlist_type = v.KODI_TYPE_VIDEO_PLAYLIST
elif kodi_type in v.KODI_AUDIOTYPES:
playlist_type = v.KODI_TYPE_AUDIO_PLAYLIST
else:
LOG.error('Unexpected type %s, data %s', kodi_type, data)
return
playerid = js.get_playlist_id(playlist_type)
if not playerid:
LOG.error('Coud not get playerid for data %s', data)
return
playqueue = PQ.PLAYQUEUES[playerid]
info = js.get_player_props(playerid)
if playqueue.kodi_playlist_playback:
# Kodi will tell us the wrong position - of the playlist, not the
# playqueue, when user starts playing from a playlist :-(
pos = 0
LOG.debug('Detected playback from a Kodi playlist')
else:
pos = info['position'] if info['position'] != -1 else 0
LOG.debug('Detected position %s for %s', pos, playqueue)
status = app.PLAYSTATE.player_states[playerid]
try: try:
item = playqueue.items[pos] item = self._check_playing_item(data)
LOG.debug('PKC playqueue item is: %s', item) except (MonitorError, IndexError):
except IndexError: LOG.debug('Detected that we need to initialize the PKC playqueue')
# PKC playqueue not yet initialized
LOG.debug('Position %s not in PKC playqueue yet', pos) if not item:
initialize = True # Initialize the PKC playqueue
else: # Yet TODO
if not kodi_id:
kodi_id, kodi_type, path = self._json_item(playerid)
if kodi_id and item.kodi_id:
if item.kodi_id != kodi_id or item.kodi_type != kodi_type:
LOG.debug('Detected different Kodi id')
initialize = True
else:
initialize = False
else:
# E.g. clips set-up previously with no Kodi DB entry
if not path:
kodi_id, kodi_type, path = self._json_item(playerid)
if path == '':
LOG.debug('Detected empty path: aborting playback report')
return
if item.file != path:
# Clips will get a new path
LOG.debug('Detected different path')
try:
tmp_plex_id = int(utils.REGEX_PLEX_ID.findall(path)[0])
except IndexError:
LOG.debug('No Plex id in path, need to init playqueue')
initialize = True
else:
if tmp_plex_id == item.plex_id:
LOG.debug('Detected different path for the same id')
initialize = False
else:
LOG.debug('Different Plex id, need to init playqueue')
initialize = True
else:
initialize = False
if initialize:
LOG.debug('Need to initialize Plex and PKC playqueue') LOG.debug('Need to initialize Plex and PKC playqueue')
if not kodi_id or not kodi_type: if not kodi_id or not kodi_type:
kodi_id, kodi_type, path = self._json_item(playerid) kodi_id, kodi_type, path = self._json_item(playerid)
@ -388,29 +418,7 @@ class KodiMonitor(xbmc.Monitor):
container_key = '/playQueues/%s' % container_key container_key = '/playQueues/%s' % container_key
elif plex_id is not None: elif plex_id is not None:
container_key = '/library/metadata/%s' % plex_id container_key = '/library/metadata/%s' % plex_id
else: self._load_playerstate(item)
LOG.debug('No need to initialize playqueues')
kodi_id = item.kodi_id
kodi_type = item.kodi_type
plex_id = item.plex_id
plex_type = item.plex_type
if playqueue.id:
container_key = '/playQueues/%s' % playqueue.id
else:
container_key = '/library/metadata/%s' % plex_id
# Remember that this player has been active
app.PLAYSTATE.active_players.add(playerid)
status.update(info)
LOG.debug('Set the Plex container_key to: %s', container_key)
status['container_key'] = container_key
status['file'] = path
status['kodi_id'] = kodi_id
status['kodi_type'] = kodi_type
status['plex_id'] = plex_id
status['plex_type'] = plex_type
status['playmethod'] = item.playmethod
status['playcount'] = item.playcount
LOG.debug('Set the player state: %s', status)
def _playback_cleanup(ended=False): def _playback_cleanup(ended=False):