From cc44c72cd62c722687f0495a147c0fc9c538248e Mon Sep 17 00:00:00 2001 From: croneter Date: Tue, 25 Feb 2020 12:04:00 +0100 Subject: [PATCH 1/3] Increase logging --- resources/lib/downloadutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py index 21384bf2..678876c4 100644 --- a/resources/lib/downloadutils.py +++ b/resources/lib/downloadutils.py @@ -291,8 +291,8 @@ class DownloadUtils(): return else: r.encoding = 'utf-8' - LOG.warn('Unknown answer from PMS %s with status code %s. ', - url, r.status_code) + LOG.warn('Unknown answer from PMS %s with status code %s: %s', + url, r.status_code, r.text) return True finally: From f524674b683958e04d2a00e7f6c4a0d8b21e2185 Mon Sep 17 00:00:00 2001 From: croneter Date: Tue, 25 Feb 2020 17:21:15 +0100 Subject: [PATCH 2/3] Increase logging --- resources/lib/playback_decision.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/lib/playback_decision.py b/resources/lib/playback_decision.py index 4035ad6f..50b822cf 100644 --- a/resources/lib/playback_decision.py +++ b/resources/lib/playback_decision.py @@ -34,9 +34,12 @@ def set_playurl(api, item): LOG.info('Lets ask the PMS next') try: _pms_playback_decision(api, item) - except (exceptions.RequestException, AttributeError, IndexError, SystemExit) as err: + except (exceptions.RequestException, + AttributeError, + IndexError, + SystemExit): LOG.warn('Could not find suitable settings for playback, aborting') - LOG.warn('Error received: %s', err) + utils.ERROR(notify=True) item.playmethod = None item.file = None else: From 6a7ca3c4d1947b7e5c468d0619913b5c9509cf54 Mon Sep 17 00:00:00 2001 From: croneter Date: Tue, 25 Feb 2020 17:27:35 +0100 Subject: [PATCH 3/3] Rewire the set-up of audio and subtitle streams, esp. before starting a transcoding session --- resources/lib/playback.py | 33 +++--- resources/lib/playback_decision.py | 156 +++++++++++++++-------------- resources/lib/plex_functions.py | 12 ++- 3 files changed, 102 insertions(+), 99 deletions(-) diff --git a/resources/lib/playback.py b/resources/lib/playback.py index bb46b21d..2b30e741 100644 --- a/resources/lib/playback.py +++ b/resources/lib/playback.py @@ -12,16 +12,10 @@ import xbmc from .plex_api import API from .plex_db import PlexDB -from . import plex_functions as PF -from . import utils from .kodi_db import KodiVideoDB -from . import playlist_func as PL -from . import playqueue as PQ -from . import json_rpc as js -from . import transfer -from .playback_decision import set_playurl, audio_subtitle_prefs -from . import variables as v -from . import app +from . import plex_functions as PF, playlist_func as PL, playqueue as PQ +from . import json_rpc as js, variables as v, utils, transfer +from . import playback_decision, app ############################################################################### LOG = getLogger('PLEX.playback') @@ -457,21 +451,20 @@ def _conclude_playback(playqueue, pos): _ensure_resolve() return api.part = item.part or 0 - listitem = api.listitem(listitem=transfer.PKCListItem, resume=False) - set_playurl(api, item) - if not item.file: - LOG.debug('Did not get a playurl, aborting playback silently') + playback_decision.set_pkc_playmethod(api, item) + if not playback_decision.audio_subtitle_prefs(api, item): + LOG.info('Did not set audio subtitle prefs, aborting silently') _ensure_resolve() return + playback_decision.set_playurl(api, item) + if not item.file: + LOG.info('Did not get a playurl, aborting playback silently') + _ensure_resolve() + return + listitem = api.listitem(listitem=transfer.PKCListItem, resume=False) listitem.setPath(item.file.encode('utf-8')) - if item.playmethod == v.PLAYBACK_METHOD_DIRECT_PLAY: + if item.playmethod != v.PLAYBACK_METHOD_DIRECT_PATH: listitem.setSubtitles(api.cache_external_subs()) - elif item.playmethod in (v.PLAYBACK_METHOD_DIRECT_STREAM, - v.PLAYBACK_METHOD_TRANSCODE): - audio_subtitle_prefs(api, listitem) - # Need to hit the PMS api again in order to get the selected - # burn-in subtitles set-up correctly - set_playurl(api, item) transfer.send(listitem) LOG.debug('Done concluding playback') diff --git a/resources/lib/playback_decision.py b/resources/lib/playback_decision.py index 50b822cf..9fe5ed8e 100644 --- a/resources/lib/playback_decision.py +++ b/resources/lib/playback_decision.py @@ -18,33 +18,36 @@ DIRECT_PLAY_OK = 1000 CONVERSION_OK = 1001 # PMS can either direct stream or transcode -def set_playurl(api, item): +def set_pkc_playmethod(api, item): item.playmethod = int(utils.settings('playType')) LOG.info('User chose playback method %s in PKC settings', v.EXPLICIT_PLAYBACK_METHOD[item.playmethod]) _initial_best_playback_method(api, item) LOG.info('PKC decided on playback method %s', v.EXPLICIT_PLAYBACK_METHOD[item.playmethod]) - if item.playmethod == v.PLAYBACK_METHOD_DIRECT_PATH: - # No need to ask the PMS whether we can play - we circumvent - # the PMS entirely - LOG.info('The playurl for %s is: %s', - v.EXPLICIT_PLAYBACK_METHOD[item.playmethod], item.file) - return - LOG.info('Lets ask the PMS next') + + +def set_playurl(api, item): try: - _pms_playback_decision(api, item) - except (exceptions.RequestException, - AttributeError, - IndexError, - SystemExit): - LOG.warn('Could not find suitable settings for playback, aborting') - utils.ERROR(notify=True) - item.playmethod = None - item.file = None - else: - item.file = api.transcode_video_path(item.playmethod, - quality=item.quality) + if item.playmethod == v.PLAYBACK_METHOD_DIRECT_PATH: + # No need to ask the PMS whether we can play - we circumvent + # the PMS entirely + return + LOG.info('Lets ask the PMS next') + try: + _pms_playback_decision(api, item) + except (exceptions.RequestException, + AttributeError, + IndexError, + SystemExit): + LOG.warn('Could not find suitable settings for playback, aborting') + utils.ERROR(notify=True) + item.playmethod = None + item.file = None + else: + item.file = api.transcode_video_path(item.playmethod, + quality=item.quality) + finally: LOG.info('The playurl for %s is: %s', v.EXPLICIT_PLAYBACK_METHOD[item.playmethod], item.file) @@ -316,12 +319,16 @@ def _getH265(): return H265[utils.settings('transcodeH265')] -def audio_subtitle_prefs(api, listitem): +def audio_subtitle_prefs(api, item): """ - For transcoding only + Sets the stage for transcoding, letting the user potentially choose both + audio and subtitle streams; subtitle streams to burn-into the video file. - Called at the very beginning of play; used to change audio and subtitle - stream by a PUT request to the PMS + Uses a PUT request to the PMS, simulating e.g. the user using Plex Web, + choosing a different stream in the video's metadata and THEN initiating + playback. + + Returns None if user cancelled or we need to abort, True otherwise """ # Set media and part where we're at if (api.mediastream is None and @@ -334,13 +341,21 @@ def audio_subtitle_prefs(api, listitem): api.mediastream, api.part) return part_id = mediastreams.attrib['id'] + if item.playmethod != v.PLAYBACK_METHOD_TRANSCODE: + LOG.debug('Telling PMS we are not burning in any subtitles') + args = { + 'subtitleStreamID': 0, + 'allParts': 1 + } + DU().downloadUrl('{server}/library/parts/%s' % part_id, + action_type='PUT', + parameters=args) + return True audio_streams_list = [] audio_streams = [] subtitle_streams_list = [] # "Don't burn-in any subtitle" subtitle_streams = ['1 %s' % utils.lang(39706)] - downloadable_streams = [] - download_subs = [] # selectAudioIndex = "" select_subs_index = "" audio_numb = 0 @@ -372,66 +387,58 @@ def audio_subtitle_prefs(api, listitem): # Subtitles elif typus == "3": - downloadable = stream.get('key') - if downloadable: - # Download the subtitle to Kodi - the user will need to - # manually select the subtitle on the Kodi side - # Hence do NOT show dialog for this sub - path = api.download_external_subtitles( - '{{server}}{}'.format(stream.get('key')), - stream.get('displayTitle'), - stream.get('codec')) - if path: - downloadable_streams.append(index) - download_subs.append(path.encode('utf-8')) - else: - # Burn in the subtitle, if user chooses to do so - default = stream.get('default') - forced = stream.get('forced') - try: - track = '{} {}'.format(sub_num + 1, - stream.attrib['displayTitle']) - except KeyError: - track = '{} {} ({})'.format(sub_num + 1, - utils.lang(39707), # unknown - stream.get('codec')) - if default: - track = "%s - %s" % (track, utils.lang(39708)) # Default - if forced: - track = "%s - %s" % (track, utils.lang(39709)) # Forced - track = "%s (%s)" % (track, utils.lang(39710)) # burn-in - subtitle_streams_list.append(index) - subtitle_streams.append(track.encode('utf-8')) - sub_num += 1 + if stream.get('key'): + # Subtitle can and will be downloaded - don't let user choose + # this subtitle to burn-in + continue + # Subtitle is available within the video file + # Burn in the subtitle, if user chooses to do so + default = stream.get('default') + forced = stream.get('forced') + try: + track = '{} {}'.format(sub_num + 1, + stream.attrib['displayTitle']) + except KeyError: + track = '{} {} ({})'.format(sub_num + 1, + utils.lang(39707), # unknown + stream.get('codec')) + if default: + track = "%s - %s" % (track, utils.lang(39708)) # Default + if forced: + track = "%s - %s" % (track, utils.lang(39709)) # Forced + track = "%s (%s)" % (track, utils.lang(39710)) # burn-in + subtitle_streams_list.append(index) + subtitle_streams.append(track.encode('utf-8')) + sub_num += 1 if audio_numb > 1: resp = utils.dialog('select', utils.lang(33013), audio_streams) - if resp > -1: - # User selected some audio track - args = { - 'audioStreamID': audio_streams_list[resp], - 'allParts': 1 - } - DU().downloadUrl('{server}/library/parts/%s' % part_id, - action_type='PUT', - parameters=args) + if resp == -1: + LOG.info('User aborted dialog to select audio stream') + return + args = { + 'audioStreamID': audio_streams_list[resp], + 'allParts': 1 + } + DU().downloadUrl('{server}/library/parts/%s' % part_id, + action_type='PUT', + parameters=args) - LOG.debug('Adding downloadable subtitles: %s', download_subs) - # Enable Kodi to switch autonomously to downloadable subtitles - if download_subs: - listitem.setSubtitles(download_subs) select_subs_index = '' if sub_num == 1: # Note: we DO need to tell the PMS that we DONT want any sub # Otherwise, the PMS might pick-up the last one - LOG.debug('No subtitles to burn-in') + LOG.info('No subtitles to burn-in') else: resp = utils.dialog('select', utils.lang(33014), subtitle_streams) - if resp < 1: + if resp == -1: + LOG.info('User aborted dialog to select subtitle stream') + return + elif resp == 0: # User did not select a subtitle or backed out of the dialog - LOG.debug('User chose to not burn-in any subtitles') + LOG.info('User chose to not burn-in any subtitles') else: - LOG.debug('User chose to burn-in subtitle %s: %s', + LOG.info('User chose to burn-in subtitle %s: %s', select_subs_index, subtitle_streams[resp].decode('utf-8')) select_subs_index = subtitle_streams_list[resp - 1] @@ -443,3 +450,4 @@ def audio_subtitle_prefs(api, listitem): DU().downloadUrl('{server}/library/parts/%s' % part_id, action_type='PUT', parameters=args) + return True diff --git a/resources/lib/plex_functions.py b/resources/lib/plex_functions.py index 43dd5885..dac7e2b0 100644 --- a/resources/lib/plex_functions.py +++ b/resources/lib/plex_functions.py @@ -1085,13 +1085,15 @@ def transcoding_arguments(path, media, part, playmethod, args=None): 'protocol': 'hls', # seen in the wild: 'http', 'dash', 'http', 'hls' 'session': v.PKC_MACHINE_IDENTIFIER, # TODO: create new unique id 'fastSeek': 1, - # none, embedded, sidecar - # Essentially indicating what you want to do with subtitles and state - # you aren’t want it to burn them into the video (requires transcoding) - # 'subtitles': 'none', - 'subtitleSize': utils.settings('subtitleSize'), 'copyts': 1 } + if playmethod != v.PLAYBACK_METHOD_TRANSCODE: + # Essentially indicating what you want to do with subtitles and state + # you aren’t want it to burn them into the video (requires transcoding) + # none, embedded, sidecar + args['subtitles'] = 'none' + else: + args['subtitleSize'] = utils.settings('subtitleSize') if args: arguments.update(args) return arguments