def _show_only_forced_subtitle(self): # Forced stream not found, then fix Kodi bug if user chose to apply the workaround # Kodi bug???: # If the kodi player is set with "forced only" subtitle setting, Kodi use this behavior: # 1) try to select forced subtitle that matches audio language # 2) if missing the forced subtitle in language, then # Kodi try to select: The first "forced" subtitle or the first "regular" subtitle # that can respect the chosen language or not, depends on the available streams # So can cause a wrong subtitle language or in a permanent display of subtitles! # This does not reflect the setting chosen in the Kodi player and is very annoying! # There is no other solution than to disable the subtitles manually. audio_language = common.get_kodi_audio_language() if self.legacy_kodi_version: # --- ONLY FOR KODI VERSION 18 --- # NOTE: With Kodi 18 it is not possible to read the properties of the streams # so the only possible way is to read the data from the manifest file cache_identifier = g.get_esn() + '_' + self.videoid.value manifest_data = g.CACHE.get(CACHE_MANIFESTS, cache_identifier) common.fix_locale_languages(manifest_data['timedtexttracks']) if not any( text_track.get('isForcedNarrative', False) is True and text_track['language'] == audio_language for text_track in manifest_data['timedtexttracks']): self.sc_settings.update({'subtitleenabled': False}) else: # --- ONLY FOR KODI VERSION 19 --- # Check the current stream player_stream = self.player_state.get( STREAMS['subtitle']['current']) if not player_stream[ 'isforced'] or player_stream['language'] != audio_language: self.sc_settings.update({'subtitleenabled': False})
def build_media_tag(player_state, manifest): """Build the playTimes and the mediaId data by parsing manifest and the current player streams used""" common.fix_locale_languages(manifest['audio_tracks']) duration = player_state['elapsed_seconds'] * 1000 audio_downloadable_id, audio_track_id = _find_audio_data( player_state, manifest) video_downloadable_id, video_track_id = _find_video_data( player_state, manifest) # Warning 'currentsubtitle' value in player_state on Kodi 18 # do not have proprieties like isdefault, isforced, isimpaired # if in the future the implementation will be done it should be available only on Kodi 19 # then for now we leave the subtitles as disabled text_track_id = 'T:1:1;1;NONE;0;1;' play_times = { 'total': duration, 'audio': [{ 'downloadableId': audio_downloadable_id, 'duration': duration }], 'video': [{ 'downloadableId': video_downloadable_id, 'duration': duration }], 'text': [] } # Format example: "A:1:1;2;en;1;|V:2:1;2;;default;1;CE3;0;|T:1:1;1;NONE;0;1;" media_id = '|'.join([audio_track_id, video_track_id, text_track_id]) return play_times, media_id
def _ensure_forced_subtitle_only_kodi18(self): """Ensures the display of forced subtitles only with the audio language set [KODI 18]""" # With Kodi 18 it is not possible to read the properties of the player streams, # so the only possible way is to read the data from the manifest file from resources.lib.common.cache_utils import CACHE_MANIFESTS from resources.lib.utils.esn import get_esn # Get the manifest cache_identifier = get_esn() + '_' + self.videoid.value manifest = G.CACHE.get(CACHE_MANIFESTS, cache_identifier) common.fix_locale_languages(manifest['timedtexttracks']) # Get the language audio_language = common.get_kodi_audio_language() if audio_language == 'mediadefault': # Netflix do not have a "Media default" track then we rely on the language of current nf profile, # although due to current Kodi locale problems could be not always accurate. profile_language_code = G.LOCAL_DB.get_profile_config('language') audio_language = profile_language_code[0:2] if audio_language == 'original': # Find the language of the original audio track stream = next((audio_track for audio_track in manifest['audio_tracks'] if audio_track['isNative']), None) if not stream: return audio_language = stream['language'] # Check in the manifest if there is a forced subtitle in the specified language if not any( text_track.get('isForcedNarrative', False) and text_track['language'] == audio_language for text_track in manifest['timedtexttracks']): self.sc_settings.update({'subtitleenabled': False})
def build_media_tag(player_state, manifest): """Build the playTimes and the mediaId data by parsing manifest and the current player streams used""" common.fix_locale_languages(manifest['audio_tracks']) duration = player_state['elapsed_seconds'] * 1000 audio_downloadable_id, audio_track_id = _find_audio_data( player_state, manifest) video_downloadable_id, video_track_id = _find_video_data( player_state, manifest) # Todo: subtitles data set always as disabled, could be added in future text_track_id = 'T:1:1;1;NONE;0;1;' play_times = { 'total': duration, 'audio': [{ 'downloadableId': audio_downloadable_id, 'duration': duration }], 'video': [{ 'downloadableId': video_downloadable_id, 'duration': duration }], 'text': [] } # Format example: "A:1:1;2;en;1;|V:2:1;2;;default;1;CE3;0;|T:1:1;1;NONE;0;1;" media_id = '|'.join([audio_track_id, video_track_id, text_track_id]) return play_times, media_id
def convert_to_dash(manifest): """Convert a Netflix style manifest to MPEGDASH manifest""" seconds = manifest['duration'] / 1000 init_length = seconds / 2 * 12 + 20 * 1000 duration = "PT" + str(seconds) + ".00S" root = _mpd_manifest_root(duration) period = ET.SubElement(root, 'Period', start='PT0S', duration=duration) protection = _protection_info(manifest) if manifest['hasDrmStreams'] else None drm_streams = manifest['hasDrmStreams'] for video_track in manifest['video_tracks']: _convert_video_track( video_track, period, init_length, protection, drm_streams) common.fix_locale_languages(manifest['audio_tracks']) common.fix_locale_languages(manifest['timedtexttracks']) default_audio_language_index = _get_default_audio_language(manifest) for index, audio_track in enumerate(manifest['audio_tracks']): _convert_audio_track(audio_track, period, init_length, (index == default_audio_language_index), drm_streams) default_subtitle_language_index = _get_default_subtitle_language(manifest) for index, text_track in enumerate(manifest['timedtexttracks']): if text_track['isNoneTrack']: continue _convert_text_track(text_track, period, default=(index == default_subtitle_language_index)) xml = ET.tostring(root, encoding='utf-8', method='xml') common.save_file('manifest.mpd', xml) return xml.decode('utf-8').replace('\n', '').replace('\r', '').encode('utf-8')
def convert_to_dash(manifest): """Convert a Netflix style manifest to MPEG-DASH manifest""" from xbmcaddon import Addon isa_version = Addon('inputstream.adaptive').getAddonInfo('version') has_drm_streams = manifest['hasDrmStreams'] protection_info = _get_protection_info(manifest) if has_drm_streams else None seconds = int(manifest['duration'] / 1000) init_length = int(seconds / 2 * 12 + 20 * 1000) duration = "PT" + str(seconds) + ".00S" root = _mpd_manifest_root(duration) period = ET.SubElement(root, 'Period', start='PT0S', duration=duration) for video_track in manifest['video_tracks']: _convert_video_track(video_track, period, init_length, protection_info, has_drm_streams) common.fix_locale_languages(manifest['audio_tracks']) common.fix_locale_languages(manifest['timedtexttracks']) default_audio_language_index = _get_default_audio_language(manifest) for index, audio_track in enumerate(manifest['audio_tracks']): _convert_audio_track(audio_track, period, init_length, (index == default_audio_language_index), has_drm_streams) default_subtitle_language_index = _get_default_subtitle_language(manifest) for index, text_track in enumerate(manifest['timedtexttracks']): if text_track['isNoneTrack']: continue _convert_text_track(text_track, period, (index == default_subtitle_language_index), isa_version) xml = ET.tostring(root, encoding='utf-8', method='xml') if common.is_debug_verbose(): common.save_file('manifest.mpd', xml) return xml.decode('utf-8').replace('\n', '').replace('\r', '').encode('utf-8')
def convert_to_dash(manifest): """Convert a Netflix style manifest to MPEG-DASH manifest""" from xbmcaddon import Addon isa_version = g.remove_ver_suffix( g.py2_decode(Addon('inputstream.adaptive').getAddonInfo('version'))) # If a CDN server has stability problems it may cause errors with streaming, # we allow users to select a different CDN server # (should be managed by ISA but is currently is not implemented) cdn_index = int(g.ADDON.getSettingString('cdn_server')[-1]) - 1 seconds = manifest['duration'] / 1000 init_length = int(seconds / 2 * 12 + 20 * 1000) duration = "PT" + str(int(seconds)) + ".00S" root = _mpd_manifest_root(duration) period = ET.SubElement(root, 'Period', start='PT0S', duration=duration) has_video_drm_streams = manifest['video_tracks'][0].get( 'hasDrmStreams', False) video_protection_info = _get_protection_info( manifest['video_tracks'][0]) if has_video_drm_streams else None for video_track in manifest['video_tracks']: _convert_video_track(video_track, period, init_length, video_protection_info, has_video_drm_streams, cdn_index) common.fix_locale_languages(manifest['audio_tracks']) common.fix_locale_languages(manifest['timedtexttracks']) has_audio_drm_streams = manifest['audio_tracks'][0].get( 'hasDrmStreams', False) default_audio_language_index = _get_default_audio_language(manifest) for index, audio_track in enumerate(manifest['audio_tracks']): _convert_audio_track(audio_track, period, init_length, (index == default_audio_language_index), has_audio_drm_streams, cdn_index) default_subtitle_language_index = _get_default_subtitle_language(manifest) for index, text_track in enumerate(manifest['timedtexttracks']): if text_track['isNoneTrack']: continue _convert_text_track(text_track, period, (index == default_subtitle_language_index), cdn_index, isa_version) xml = ET.tostring(root, encoding='utf-8', method='xml') if common.is_debug_verbose(): common.save_file('manifest.mpd', xml) return xml.decode('utf-8').replace('\n', '').replace('\r', '').encode('utf-8')
def _show_only_forced_subtitle(): # When we have "forced only" subtitle setting in Kodi Player, Kodi use this behavior: # 1) try to select forced subtitle that matches audio language # 2) when missing, try to select the first "regular" subtitle that matches audio language # This Kodi behavior is totally non sense. # If forced is selected you must not view the regular subtitles # There is no other solution than to disable the subtitles manually. manifest_data = json.loads(common.load_file('manifest.json')) common.fix_locale_languages(manifest_data['timedtexttracks']) audio_language = common.get_kodi_audio_language() if not any( text_track.get('isForcedNarrative', False) is True and text_track['language'] == audio_language for text_track in manifest_data['timedtexttracks']): xbmc.Player().showSubtitles(False)
def convert_to_dash(manifest): """Convert a Netflix style manifest to MPEG-DASH manifest""" # If a CDN server has stability problems it may cause errors with streaming, # we allow users to select a different CDN server # (should be managed by ISA but is currently is not implemented) cdn_index = int(G.ADDON.getSettingString('cdn_server')[-1]) - 1 seconds = manifest['duration'] / 1000 init_length = int(seconds / 2 * 12 + 20 * 1000) duration = "PT" + str(int(seconds)) + ".00S" root = _mpd_manifest_root(duration) period = ET.SubElement(root, 'Period', start='PT0S', duration=duration) has_video_drm_streams = manifest['video_tracks'][0].get( 'hasDrmStreams', False) video_protection_info = _get_protection_info( manifest['video_tracks'][0]) if has_video_drm_streams else None for video_track in manifest['video_tracks']: _convert_video_track(video_track, period, init_length, video_protection_info, has_video_drm_streams, cdn_index) common.fix_locale_languages(manifest['audio_tracks']) common.fix_locale_languages(manifest['timedtexttracks']) has_audio_drm_streams = manifest['audio_tracks'][0].get( 'hasDrmStreams', False) id_default_audio_tracks = _get_id_default_audio_tracks(manifest) for audio_track in manifest['audio_tracks']: is_default = audio_track['id'] in id_default_audio_tracks _convert_audio_track(audio_track, period, init_length, is_default, has_audio_drm_streams, cdn_index) for text_track in manifest['timedtexttracks']: if text_track['isNoneTrack']: continue is_default = _is_default_subtitle(manifest, text_track) _convert_text_track(text_track, period, is_default, cdn_index) xml = ET.tostring(root, encoding='utf-8', method='xml') if LOG.level == LOG.LEVEL_VERBOSE: common.save_file_def('manifest.mpd', xml) return xml.decode('utf-8').replace('\n', '').replace('\r', '').encode('utf-8')