Track video streams as well; refactor reporting of playback progress; only switch audio stream if different

This commit is contained in:
croneter 2021-10-20 14:55:39 +02:00
parent 4f7e54591c
commit 49fce5a2cd
5 changed files with 119 additions and 41 deletions

View file

@ -429,6 +429,15 @@ def get_current_audio_stream_index(playerid):
'properties': ['currentaudiostream']})['result']['currentaudiostream']['index'] 'properties': ['currentaudiostream']})['result']['currentaudiostream']['index']
def get_current_video_stream_index(playerid):
"""
Returns the currently active video stream index [int]
"""
return JsonRPC('Player.GetProperties').execute({
'playerid': playerid,
'properties': ['currentvideostream']})['result']['currentvideostream']['index']
def get_current_subtitle_stream_index(playerid): def get_current_subtitle_stream_index(playerid):
""" """
Returns the currently active subtitle stream index [int] or None if there Returns the currently active subtitle stream index [int] or None if there

View file

@ -390,6 +390,8 @@ class KodiMonitor(xbmc.Monitor):
if not self._switched_to_plex_streams: if not self._switched_to_plex_streams:
# We need to switch to the Plex streams ONCE upon playback start # We need to switch to the Plex streams ONCE upon playback start
# after onavchange has been fired # after onavchange has been fired
item.init_kodi_streams()
item.switch_to_plex_stream('video')
if utils.settings('audioStreamPick') == '0': if utils.settings('audioStreamPick') == '0':
item.switch_to_plex_stream('audio') item.switch_to_plex_stream('audio')
if utils.settings('subtitleStreamPick') == '0': if utils.settings('subtitleStreamPick') == '0':

View file

@ -179,9 +179,11 @@ class PlaylistItem(object):
# Get the Plex audio and subtitle streams in the same order as Kodi # Get the Plex audio and subtitle streams in the same order as Kodi
# uses them (Kodi uses indexes to activate them, not ids like Plex) # uses them (Kodi uses indexes to activate them, not ids like Plex)
self._streams_have_been_processed = False self._streams_have_been_processed = False
self._video_streams = None
self._audio_streams = None self._audio_streams = None
self._subtitle_streams = None self._subtitle_streams = None
# Which Kodi streams are active? # Which Kodi streams are active?
self.current_kodi_video_stream = None
self.current_kodi_audio_stream = None self.current_kodi_audio_stream = None
# False means "deactivated", None means "we do not have a Kodi # False means "deactivated", None means "we do not have a Kodi
# equivalent for this Plex subtitle" # equivalent for this Plex subtitle"
@ -201,6 +203,12 @@ class PlaylistItem(object):
def uri(self): def uri(self):
return self._uri return self._uri
@property
def video_streams(self):
if not self._streams_have_been_processed:
self._process_streams()
return self._video_streams
@property @property
def audio_streams(self): def audio_streams(self):
if not self._streams_have_been_processed: if not self._streams_have_been_processed:
@ -213,6 +221,18 @@ class PlaylistItem(object):
self._process_streams() self._process_streams()
return self._subtitle_streams return self._subtitle_streams
@property
def current_plex_video_stream(self):
return self.plex_stream_index(self.current_kodi_video_stream, 'video')
@property
def current_plex_audio_stream(self):
return self.plex_stream_index(self.current_kodi_audio_stream, 'audio')
@property
def current_plex_sub_stream(self):
return self.plex_stream_index(self.current_kodi_sub_stream, 'subtitle')
def __repr__(self): def __repr__(self):
return ("{{" return ("{{"
"'id': {self.id}, " "'id': {self.id}, "
@ -244,6 +264,13 @@ class PlaylistItem(object):
# the same in Kodi and Plex # the same in Kodi and Plex
self._audio_streams = [x for x in self.api.plex_media_streams() self._audio_streams = [x for x in self.api.plex_media_streams()
if x.get('streamType') == '2'] if x.get('streamType') == '2']
# Same for video streams
self._video_streams = [x for x in self.api.plex_media_streams()
if x.get('streamType') == '1']
if len(self._video_streams) == 1:
# Add a selected = "1" attribute to let our logic stand!
# Missing if there is only 1 video stream present
self._video_streams[0].set('selected', '1')
self._streams_have_been_processed = True self._streams_have_been_processed = True
def _get_iterator(self, stream_type): def _get_iterator(self, stream_type):
@ -251,6 +278,17 @@ class PlaylistItem(object):
return self.audio_streams return self.audio_streams
elif stream_type == 'subtitle': elif stream_type == 'subtitle':
return self.subtitle_streams return self.subtitle_streams
elif stream_type == 'video':
return self.video_streams
def init_kodi_streams(self):
"""
Initializes all streams after Kodi has started playing this video
"""
self.current_kodi_video_stream = js.get_current_video_stream_index(v.KODI_VIDEO_PLAYER_ID)
self.current_kodi_audio_stream = js.get_current_audio_stream_index(v.KODI_VIDEO_PLAYER_ID)
self.current_kodi_sub_stream = False if not js.get_subtitle_enabled(v.KODI_VIDEO_PLAYER_ID) \
else js.get_current_subtitle_stream_index(v.KODI_VIDEO_PLAYER_ID)
def plex_stream_index(self, kodi_stream_index, stream_type): def plex_stream_index(self, kodi_stream_index, stream_type):
""" """
@ -261,6 +299,8 @@ class PlaylistItem(object):
""" """
if stream_type == 'audio': if stream_type == 'audio':
return int(self.audio_streams[kodi_stream_index].get('id')) return int(self.audio_streams[kodi_stream_index].get('id'))
elif stream_type == 'video':
return int(self.video_streams[kodi_stream_index].get('id'))
elif stream_type == 'subtitle': elif stream_type == 'subtitle':
try: try:
return int(self.subtitle_streams[kodi_stream_index].get('id')) return int(self.subtitle_streams[kodi_stream_index].get('id'))
@ -324,10 +364,39 @@ class PlaylistItem(object):
PF.change_audio_stream(plex_stream_index, self.api.part_id()) PF.change_audio_stream(plex_stream_index, self.api.part_id())
self.current_kodi_audio_stream = kodi_stream_index self.current_kodi_audio_stream = kodi_stream_index
def on_kodi_video_stream_change(self, kodi_stream_index):
"""
Call this method if Kodi changed its video stream and you want Plex to
know. kodi_stream_index [int]
"""
plex_stream_index = int(self.video_streams[kodi_stream_index].get('id'))
LOG.debug('Changing Plex video stream to %s, Kodi index %s',
plex_stream_index, kodi_stream_index)
PF.change_video_stream(plex_stream_index, self.api.part_id())
self.current_kodi_video_stream = kodi_stream_index
def switch_to_plex_streams(self): def switch_to_plex_streams(self):
self.switch_to_plex_stream('video')
self.switch_to_plex_stream('audio') self.switch_to_plex_stream('audio')
self.switch_to_plex_stream('subtitle') self.switch_to_plex_stream('subtitle')
@staticmethod
def _set_kodi_stream_if_different(kodi_index, typus):
if typus == 'video':
current = js.get_current_video_stream_index(v.KODI_VIDEO_PLAYER_ID)
if current != kodi_index:
LOG.debug('Switching video stream')
app.APP.player.setVideoStream(kodi_index)
else:
LOG.debug('Not switching video stream (no change)')
elif typus == 'audio':
current = js.get_current_audio_stream_index(v.KODI_VIDEO_PLAYER_ID)
if current != kodi_index:
LOG.debug('Switching audio stream')
app.APP.player.setAudioStream(kodi_index)
else:
LOG.debug('Not switching audio stream (no change)')
def switch_to_plex_stream(self, typus): def switch_to_plex_stream(self, typus):
try: try:
plex_index, language_tag = self.active_plex_stream_index(typus) plex_index, language_tag = self.active_plex_stream_index(typus)
@ -351,22 +420,34 @@ class PlaylistItem(object):
# If we're choosing an "illegal" index, this function does # If we're choosing an "illegal" index, this function does
# need seem to fail nor log any errors # need seem to fail nor log any errors
if typus == 'audio': if typus == 'audio':
app.APP.player.setAudioStream(kodi_index) self._set_kodi_stream_if_different(kodi_index, 'audio')
else: elif typus == 'subtitle':
app.APP.player.setSubtitleStream(kodi_index) app.APP.player.setSubtitleStream(kodi_index)
app.APP.player.showSubtitles(True) app.APP.player.showSubtitles(True)
elif typus == 'video':
self._set_kodi_stream_if_different(kodi_index, 'video')
if typus == 'audio': if typus == 'audio':
self.current_kodi_audio_stream = kodi_index self.current_kodi_audio_stream = kodi_index
else: elif typus == 'subtitle':
self.current_kodi_sub_stream = kodi_index self.current_kodi_sub_stream = kodi_index
elif typus == 'video':
self.current_kodi_video_stream = kodi_index
def on_av_change(self, playerid): def on_av_change(self, playerid):
"""
Call this method if Kodi reports an "AV-Change"
(event "Player.OnAVChange")
"""
kodi_video_stream = js.get_current_video_stream_index(playerid)
kodi_audio_stream = js.get_current_audio_stream_index(playerid) kodi_audio_stream = js.get_current_audio_stream_index(playerid)
sub_enabled = js.get_subtitle_enabled(playerid) sub_enabled = js.get_subtitle_enabled(playerid)
kodi_sub_stream = js.get_current_subtitle_stream_index(playerid) kodi_sub_stream = js.get_current_subtitle_stream_index(playerid)
# Audio # Audio
if kodi_audio_stream != self.current_kodi_audio_stream: if kodi_audio_stream != self.current_kodi_audio_stream:
self.on_kodi_audio_stream_change(kodi_audio_stream) self.on_kodi_audio_stream_change(kodi_audio_stream)
# Video
if kodi_video_stream != self.current_kodi_video_stream:
self.on_kodi_video_stream_change(kodi_audio_stream)
# Subtitles - CURRENTLY BROKEN ON THE KODI SIDE! # Subtitles - CURRENTLY BROKEN ON THE KODI SIDE!
# current_kodi_sub_stream may also be zero # current_kodi_sub_stream may also be zero
subs_off = (None, False) subs_off = (None, False)
@ -383,8 +464,13 @@ class PlaylistItem(object):
if 'audioStreamID' in plex_data: if 'audioStreamID' in plex_data:
plex_index = int(plex_data['audioStreamID']) plex_index = int(plex_data['audioStreamID'])
kodi_index = self.kodi_stream_index(plex_index, 'audio') kodi_index = self.kodi_stream_index(plex_index, 'audio')
app.APP.player.setAudioStream(kodi_index) self._set_kodi_stream_if_different(kodi_index, 'audio')
self.current_kodi_audio_stream = kodi_index self.current_kodi_audio_stream = kodi_index
if 'videoStreamID' in plex_data:
plex_index = int(plex_data['videoStreamID'])
kodi_index = self.kodi_stream_index(plex_index, 'video')
self._set_kodi_stream_if_different(kodi_index, 'video')
self.current_kodi_video_stream = kodi_index
if 'subtitleStreamID' in plex_data: if 'subtitleStreamID' in plex_data:
plex_index = int(plex_data['subtitleStreamID']) plex_index = int(plex_data['subtitleStreamID'])
if plex_index == 0: if plex_index == 0:

View file

@ -1148,3 +1148,17 @@ def change_audio_stream(plex_stream_id, part_id):
url = '{server}/library/parts/%s' % part_id url = '{server}/library/parts/%s' % part_id
return DU().downloadUrl(utils.extend_url(url, arguments), return DU().downloadUrl(utils.extend_url(url, arguments),
action_type='PUT') action_type='PUT')
def change_video_stream(plex_stream_id, part_id):
"""
Tell the PMS to display another video stream
- We always do this for ALL parts of a video
"""
arguments = {
'videoStreamID': plex_stream_id,
'allParts': 1
}
url = '{server}/library/parts/%s' % part_id
return DU().downloadUrl(utils.extend_url(url, arguments),
action_type='PUT')

View file

@ -249,27 +249,10 @@ class SubscriptionMgr(object):
answ['token'] = playqueue.plex_transient_token answ['token'] = playqueue.plex_transient_token
# Process audio and subtitle streams # Process audio and subtitle streams
if ptype == v.PLEX_PLAYLIST_TYPE_VIDEO: if ptype == v.PLEX_PLAYLIST_TYPE_VIDEO:
strm_id = self._plex_stream_index(playerid, 'audio') answ['videoStreamID'] = str(item.current_plex_video_stream)
if strm_id: answ['audioStreamID'] = str(item.current_plex_audio_stream)
answ['audioStreamID'] = strm_id # Mind the zero - meaning subs are deactivated
else: answ['subtitleStreamID'] = str(item.current_plex_sub_stream or 0)
LOG.error('We could not select a Plex audiostream')
strm_id = self._plex_stream_index(playerid, 'video')
if strm_id:
answ['videoStreamID'] = strm_id
else:
LOG.error('We could not select a Plex videostream')
if info['subtitleenabled']:
try:
strm_id = self._plex_stream_index(playerid, 'subtitle')
except KeyError:
# subtitleenabled can be True while currentsubtitle can
# still be {}
strm_id = None
if strm_id is not None:
# If None, then the subtitle is only present on Kodi
# side
answ['subtitleStreamID'] = strm_id
return answ return answ
def signal_stop(self): def signal_stop(self):
@ -285,22 +268,6 @@ class SubscriptionMgr(object):
self.last_params, self.last_params,
timeout=0.0001) timeout=0.0001)
def _plex_stream_index(self, playerid, stream_type):
"""
Returns the current Plex stream index [str] for the player playerid
stream_type: 'video', 'audio', 'subtitle'
"""
playqueue = PQ.PLAYQUEUES[playerid]
info = app.PLAYSTATE.player_states[playerid]
position = self._get_correct_position(info, playqueue)
if info[STREAM_DETAILS[stream_type]] == -1:
kodi_stream_index = -1
else:
kodi_stream_index = info[STREAM_DETAILS[stream_type]]['index']
return playqueue.items[position].plex_stream_index(kodi_stream_index,
stream_type)
def update_command_id(self, uuid, command_id): def update_command_id(self, uuid, command_id):
""" """
Updates the Plex Companien client with the machine identifier uuid with Updates the Plex Companien client with the machine identifier uuid with