Revamp monitor
This commit is contained in:
parent
ad6c160524
commit
643e6171c4
1 changed files with 110 additions and 102 deletions
|
@ -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:
|
try:
|
||||||
playerid = js.get_player_ids()[0]
|
item = self._check_playing_item(data)
|
||||||
except IndexError:
|
except (MonitorError, IndexError):
|
||||||
# E.g. Kodi 18 doesn't tell us anything useful
|
LOG.debug('Detected that we need to initialize the PKC playqueue')
|
||||||
if kodi_type in v.KODI_VIDEOTYPES:
|
|
||||||
playlist_type = v.KODI_TYPE_VIDEO_PLAYLIST
|
if not item:
|
||||||
elif kodi_type in v.KODI_AUDIOTYPES:
|
# Initialize the PKC playqueue
|
||||||
playlist_type = v.KODI_TYPE_AUDIO_PLAYLIST
|
# Yet TODO
|
||||||
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:
|
|
||||||
item = playqueue.items[pos]
|
|
||||||
LOG.debug('PKC playqueue item is: %s', item)
|
|
||||||
except IndexError:
|
|
||||||
# PKC playqueue not yet initialized
|
|
||||||
LOG.debug('Position %s not in PKC playqueue yet', pos)
|
|
||||||
initialize = True
|
|
||||||
else:
|
|
||||||
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):
|
||||||
|
|
Loading…
Reference in a new issue