From 3310f6aeb88fcc9a70f9e5d6f673873ff2f1af85 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Thu, 9 Feb 2023 16:58:38 -0500 Subject: [PATCH] Improved audio track language detection by using our video parser instead of values provided by Sonarr/Radarr. We also added "treat as" concept for undefined languages audio and embedded subtitles tracks. #2050 --- bazarr/api/episodes/episodes_subtitles.py | 15 +++-- bazarr/api/movies/movies_subtitles.py | 16 +++-- bazarr/app/config.py | 23 ++++++- bazarr/app/database.py | 23 +++++-- bazarr/radarr/sync/parser.py | 26 ++------ bazarr/sonarr/sync/parser.py | 34 +++------- bazarr/subtitles/indexer/movies.py | 22 +++---- bazarr/subtitles/indexer/series.py | 21 +++---- bazarr/subtitles/refiners/ffprobe.py | 2 +- bazarr/subtitles/upload.py | 11 ++-- .../video_analyzer.py} | 63 +++++++++++++------ frontend/src/apis/hooks/system.ts | 5 ++ frontend/src/pages/Series/index.tsx | 8 --- .../src/pages/Settings/Languages/index.tsx | 46 +++++++++++++- frontend/src/pages/Settings/keys.ts | 3 + 15 files changed, 186 insertions(+), 132 deletions(-) rename bazarr/{subtitles/tools/embedded_subs_reader.py => utilities/video_analyzer.py} (76%) diff --git a/bazarr/api/episodes/episodes_subtitles.py b/bazarr/api/episodes/episodes_subtitles.py index 7943ac01e..5dfaf0eaa 100644 --- a/bazarr/api/episodes/episodes_subtitles.py +++ b/bazarr/api/episodes/episodes_subtitles.py @@ -118,9 +118,7 @@ class EpisodesSubtitles(Resource): args = self.post_request_parser.parse_args() sonarrSeriesId = args.get('seriesid') sonarrEpisodeId = args.get('episodeid') - episodeInfo = TableEpisodes.select(TableEpisodes.title, - TableEpisodes.path, - TableEpisodes.sceneName, + episodeInfo = TableEpisodes.select(TableEpisodes.path, TableEpisodes.audio_language) \ .where(TableEpisodes.sonarrEpisodeId == sonarrEpisodeId) \ .dicts() \ @@ -129,10 +127,13 @@ class EpisodesSubtitles(Resource): if not episodeInfo: return 'Episode not found', 404 - title = episodeInfo['title'] episodePath = path_mappings.path_replace(episodeInfo['path']) - sceneName = episodeInfo['sceneName'] or "None" - audio_language = episodeInfo['audio_language'] + + audio_language = get_audio_profile_languages(episodeInfo['audio_language']) + if len(audio_language) and isinstance(audio_language[0], dict): + audio_language = audio_language[0] + else: + audio_language = {'name': '', 'code2': '', 'code3': ''} language = args.get('language') forced = True if args.get('forced') == 'true' else False @@ -149,8 +150,6 @@ class EpisodesSubtitles(Resource): language=language, forced=forced, hi=hi, - title=title, - sceneName=sceneName, media_type='series', subtitle=subFile, audio_language=audio_language) diff --git a/bazarr/api/movies/movies_subtitles.py b/bazarr/api/movies/movies_subtitles.py index 9abdd3f71..0dbd43b69 100644 --- a/bazarr/api/movies/movies_subtitles.py +++ b/bazarr/api/movies/movies_subtitles.py @@ -113,9 +113,7 @@ class MoviesSubtitles(Resource): # TODO: Support Multiply Upload args = self.post_request_parser.parse_args() radarrId = args.get('radarrid') - movieInfo = TableMovies.select(TableMovies.title, - TableMovies.path, - TableMovies.sceneName, + movieInfo = TableMovies.select(TableMovies.path, TableMovies.audio_language) \ .where(TableMovies.radarrId == radarrId) \ .dicts() \ @@ -125,10 +123,12 @@ class MoviesSubtitles(Resource): return 'Movie not found', 404 moviePath = path_mappings.path_replace_movie(movieInfo['path']) - sceneName = movieInfo['sceneName'] or 'None' - title = movieInfo['title'] - audioLanguage = movieInfo['audio_language'] + audio_language = get_audio_profile_languages(movieInfo['audio_language']) + if len(audio_language) and isinstance(audio_language[0], dict): + audio_language = audio_language[0] + else: + audio_language = {'name': '', 'code2': '', 'code3': ''} language = args.get('language') forced = args.get('forced') == 'true' @@ -145,11 +145,9 @@ class MoviesSubtitles(Resource): language=language, forced=forced, hi=hi, - title=title, - sceneName=sceneName, media_type='movie', subtitle=subFile, - audio_language=audioLanguage) + audio_language=audio_language) if not result: logging.debug(f"BAZARR unable to process subtitles for this movie: {moviePath}") diff --git a/bazarr/app/config.py b/bazarr/app/config.py index 0ea8ad489..ba4bc8a26 100644 --- a/bazarr/app/config.py +++ b/bazarr/app/config.py @@ -79,7 +79,9 @@ defaults = { 'subzero_mods': '[]', 'dont_notify_manual_actions': 'False', 'hi_extension': 'hi', - 'embedded_subtitles_parser': 'ffprobe' + 'embedded_subtitles_parser': 'ffprobe', + 'default_und_audio_lang': '', + 'default_und_embedded_subtitles_lang': '' }, 'auth': { 'type': 'None', @@ -381,6 +383,8 @@ def save_settings(settings_items): sonarr_exclusion_updated = False radarr_exclusion_updated = False use_embedded_subs_changed = False + undefined_audio_track_default_changed = False + undefined_subtitles_track_default_changed = False # Subzero Mods update_subzero = False @@ -416,6 +420,12 @@ def save_settings(settings_items): 'settings-general-ignore_vobsub_subs', 'settings-general-ignore_ass_subs']: use_embedded_subs_changed = True + if key == 'settings-general-default_und_audio_lang': + undefined_audio_track_default_changed = True + + if key == 'settings-general-default_und_embedded_subtitles_lang': + undefined_subtitles_track_default_changed = True + if key in ['settings-general-base_url', 'settings-sonarr-base_url', 'settings-radarr-base_url']: value = base_url_slash_cleaner(value) @@ -537,7 +547,7 @@ def save_settings(settings_items): update_subzero = True - if use_embedded_subs_changed: + if use_embedded_subs_changed or undefined_audio_track_default_changed: from .scheduler import scheduler from subtitles.indexer.series import list_missing_subtitles from subtitles.indexer.movies import list_missing_subtitles_movies @@ -546,6 +556,15 @@ def save_settings(settings_items): if settings.general.getboolean('use_radarr'): scheduler.add_job(list_missing_subtitles_movies, kwargs={'send_event': True}) + if undefined_subtitles_track_default_changed: + from .scheduler import scheduler + from subtitles.indexer.series import series_full_scan_subtitles + from subtitles.indexer.movies import movies_full_scan_subtitles + if settings.general.getboolean('use_sonarr'): + scheduler.add_job(series_full_scan_subtitles, kwargs={'use_cache': True}) + if settings.general.getboolean('use_radarr'): + scheduler.add_job(movies_full_scan_subtitles, kwargs={'use_cache': True}) + if update_subzero: settings.set('general', 'subzero_mods', ','.join(subzero_mods)) diff --git a/bazarr/app/database.py b/bazarr/app/database.py index e96eccf39..85b62387c 100644 --- a/bazarr/app/database.py +++ b/bazarr/app/database.py @@ -650,20 +650,31 @@ def get_profile_cutoff(profile_id): def get_audio_profile_languages(audio_languages_list_str): - from languages.get_languages import alpha2_from_language, alpha3_from_language + from languages.get_languages import alpha2_from_language, alpha3_from_language, language_from_alpha2 audio_languages = [] + und_default_language = language_from_alpha2(settings.general.default_und_audio_lang) + try: audio_languages_list = ast.literal_eval(audio_languages_list_str or '[]') except ValueError: pass else: for language in audio_languages_list: - audio_languages.append( - {"name": language, - "code2": alpha2_from_language(language) or None, - "code3": alpha3_from_language(language) or None} - ) + if language: + audio_languages.append( + {"name": language, + "code2": alpha2_from_language(language) or None, + "code3": alpha3_from_language(language) or None} + ) + else: + if und_default_language: + logging.debug(f"Undefined language audio track treated as {und_default_language}") + audio_languages.append( + {"name": und_default_language, + "code2": alpha2_from_language(und_default_language) or None, + "code3": alpha3_from_language(und_default_language) or None} + ) return audio_languages diff --git a/bazarr/radarr/sync/parser.py b/bazarr/radarr/sync/parser.py index 017d08a47..7537bcec2 100644 --- a/bazarr/radarr/sync/parser.py +++ b/bazarr/radarr/sync/parser.py @@ -3,7 +3,8 @@ import os from radarr.info import get_radarr_info -from languages.get_languages import language_from_alpha2 +from utilities.video_analyzer import embedded_audio_reader +from utilities.path_mappings import path_mappings from .converter import RadarrFormatAudioCodec, RadarrFormatVideoCodec @@ -89,25 +90,10 @@ def movieParser(movie, action, tags_dict, movie_default_profile, audio_profiles) videoCodec = None audioCodec = None - audio_language = [] - if get_radarr_info.is_legacy(): - if 'mediaInfo' in movie['movieFile']: - if 'audioLanguages' in movie['movieFile']['mediaInfo']: - audio_languages_list = movie['movieFile']['mediaInfo']['audioLanguages'].split('/') - if len(audio_languages_list): - for audio_language_list in audio_languages_list: - audio_language.append(audio_language_list.strip()) - if not audio_language: - audio_language = profile_id_to_language(movie['qualityProfileId'], audio_profiles) - else: - if 'languages' in movie['movieFile'] and len(movie['movieFile']['languages']): - for item in movie['movieFile']['languages']: - if isinstance(item, dict): - if 'name' in item: - language = item['name'] - if item['name'] == 'Portuguese (Brazil)': - language = language_from_alpha2('pb') - audio_language.append(language) + audio_language = embedded_audio_reader(path_mappings.path_replace_movie(movie['movieFile']['path']), + file_size=movie['movieFile']['size'], + movie_file_id=movie['movieFile']['id'], + use_cache=True) tags = [d['label'] for d in tags_dict if d['id'] in movie['tags']] diff --git a/bazarr/sonarr/sync/parser.py b/bazarr/sonarr/sync/parser.py index 6566e0630..9fc3c4db2 100644 --- a/bazarr/sonarr/sync/parser.py +++ b/bazarr/sonarr/sync/parser.py @@ -2,9 +2,8 @@ import os -from app.database import TableShows -from sonarr.info import get_sonarr_info from utilities.path_mappings import path_mappings +from utilities.video_analyzer import embedded_audio_reader from .converter import SonarrFormatVideoCodec, SonarrFormatAudioCodec @@ -25,15 +24,6 @@ def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles) if show['alternateTitles'] is not None: alternate_titles = str([item['title'] for item in show['alternateTitles']]) - audio_language = [] - if get_sonarr_info.is_legacy(): - audio_language = profile_id_to_language(show['qualityProfileId'], audio_profiles) - else: - if 'languageProfileId' in show: - audio_language = profile_id_to_language(show['languageProfileId'], audio_profiles) - else: - audio_language = [] - tags = [d['label'] for d in tags_dict if d['id'] in show['tags']] imdbId = show['imdbId'] if 'imdbId' in show else None @@ -46,7 +36,7 @@ def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles) 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': str(audio_language), + 'audio_language': str([]), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternativeTitles': alternate_titles, @@ -62,7 +52,7 @@ def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles) 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': str(audio_language), + 'audio_language': str([]), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternativeTitles': alternate_titles, @@ -95,20 +85,10 @@ def episodeParser(episode): else: sceneName = None - audio_language = [] - if 'language' in episode['episodeFile'] and len(episode['episodeFile']['language']): - item = episode['episodeFile']['language'] - if isinstance(item, dict): - if 'name' in item: - audio_language.append(item['name']) - elif 'languages' in episode['episodeFile'] and len(episode['episodeFile']['languages']): - items = episode['episodeFile']['languages'] - if isinstance(items, list): - for item in items: - if 'name' in item: - audio_language.append(item['name']) - else: - audio_language = TableShows.get(TableShows.sonarrSeriesId == episode['seriesId']).audio_language + audio_language = embedded_audio_reader(path_mappings.path_replace(episode['episodeFile']['path']), + file_size=episode['episodeFile']['size'], + episode_file_id=episode['episodeFile']['id'], + use_cache=True) if 'mediaInfo' in episode['episodeFile']: if 'videoCodec' in episode['episodeFile']['mediaInfo']: diff --git a/bazarr/subtitles/indexer/movies.py b/bazarr/subtitles/indexer/movies.py index 05e41506f..97c247760 100644 --- a/bazarr/subtitles/indexer/movies.py +++ b/bazarr/subtitles/indexer/movies.py @@ -8,12 +8,12 @@ import ast from subliminal_patch import core, search_external_subtitles from languages.custom_lang import CustomLanguage -from app.database import get_profiles_list, get_profile_cutoff, TableMovies -from languages.get_languages import alpha2_from_alpha3, language_from_alpha2, get_language_set +from app.database import get_profiles_list, get_profile_cutoff, TableMovies, get_audio_profile_languages +from languages.get_languages import alpha2_from_alpha3, get_language_set from app.config import settings from utilities.helper import get_subtitle_destination_folder from utilities.path_mappings import path_mappings -from subtitles.tools.embedded_subs_reader import embedded_subs_reader +from utilities.video_analyzer import embedded_subs_reader from app.event_handler import event_stream, show_progress, hide_progress from subtitles.indexer.utils import guess_external_subtitles, get_external_subtitles_path @@ -168,8 +168,8 @@ def list_missing_subtitles_movies(no=None, send_event=True): if desired_subtitles_temp: for language in desired_subtitles_temp['items']: if language['audio_exclude'] == "True": - if language_from_alpha2(language['language']) in ast.literal_eval( - movie_subtitles['audio_language']): + if any(x['code2'] == language['language'] for x in get_audio_profile_languages( + movie_subtitles['audio_language'])): continue desired_subtitles_list.append([language['language'], language['forced'], language['hi']]) @@ -202,8 +202,9 @@ def list_missing_subtitles_movies(no=None, send_event=True): if cutoff_temp_list: for cutoff_temp in cutoff_temp_list: cutoff_language = [cutoff_temp['language'], cutoff_temp['forced'], cutoff_temp['hi']] - if cutoff_temp['audio_exclude'] == 'True' and language_from_alpha2(cutoff_temp['language']) in \ - ast.literal_eval(movie_subtitles['audio_language']): + if cutoff_temp['audio_exclude'] == 'True' and \ + any(x['code2'] == cutoff_temp['language'] for x in + get_audio_profile_languages(movie_subtitles['audio_language'])): cutoff_met = True elif cutoff_language in actual_subtitles_list: cutoff_met = True @@ -251,9 +252,7 @@ def list_missing_subtitles_movies(no=None, send_event=True): event_stream(type='badges') -def movies_full_scan_subtitles(): - use_ffprobe_cache = settings.radarr.getboolean('use_ffprobe_cache') - +def movies_full_scan_subtitles(use_cache=settings.radarr.getboolean('use_ffprobe_cache')): movies = TableMovies.select(TableMovies.path).dicts() count_movies = len(movies) @@ -263,8 +262,7 @@ def movies_full_scan_subtitles(): name='Movies subtitles', value=i, count=count_movies) - store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']), - use_cache=use_ffprobe_cache) + store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']), use_cache=use_cache) hide_progress(id='movies_disk_scan') diff --git a/bazarr/subtitles/indexer/series.py b/bazarr/subtitles/indexer/series.py index c93ad8f4e..e7091bf45 100644 --- a/bazarr/subtitles/indexer/series.py +++ b/bazarr/subtitles/indexer/series.py @@ -8,12 +8,12 @@ import ast from subliminal_patch import core, search_external_subtitles from languages.custom_lang import CustomLanguage -from app.database import get_profiles_list, get_profile_cutoff, TableEpisodes, TableShows -from languages.get_languages import alpha2_from_alpha3, language_from_alpha2, get_language_set +from app.database import get_profiles_list, get_profile_cutoff, TableEpisodes, TableShows, get_audio_profile_languages +from languages.get_languages import alpha2_from_alpha3, get_language_set from app.config import settings from utilities.helper import get_subtitle_destination_folder from utilities.path_mappings import path_mappings -from subtitles.tools.embedded_subs_reader import embedded_subs_reader +from utilities.video_analyzer import embedded_subs_reader from app.event_handler import event_stream, show_progress, hide_progress from subtitles.indexer.utils import guess_external_subtitles, get_external_subtitles_path @@ -176,8 +176,8 @@ def list_missing_subtitles(no=None, epno=None, send_event=True): if desired_subtitles_temp: for language in desired_subtitles_temp['items']: if language['audio_exclude'] == "True": - if language_from_alpha2(language['language']) in ast.literal_eval( - episode_subtitles['audio_language']): + if any(x['code2'] == language['language'] for x in get_audio_profile_languages( + episode_subtitles['audio_language'])): continue desired_subtitles_list.append([language['language'], language['forced'], language['hi']]) @@ -210,8 +210,9 @@ def list_missing_subtitles(no=None, epno=None, send_event=True): if cutoff_temp_list: for cutoff_temp in cutoff_temp_list: cutoff_language = [cutoff_temp['language'], cutoff_temp['forced'], cutoff_temp['hi']] - if cutoff_temp['audio_exclude'] == 'True' and language_from_alpha2(cutoff_temp['language']) in \ - ast.literal_eval(episode_subtitles['audio_language']): + if cutoff_temp['audio_exclude'] == 'True' and \ + any(x['code2'] == cutoff_temp['language'] for x in + get_audio_profile_languages(episode_subtitles['audio_language'])): cutoff_met = True elif cutoff_language in actual_subtitles_list: cutoff_met = True @@ -261,9 +262,7 @@ def list_missing_subtitles(no=None, epno=None, send_event=True): event_stream(type='badges') -def series_full_scan_subtitles(): - use_ffprobe_cache = settings.sonarr.getboolean('use_ffprobe_cache') - +def series_full_scan_subtitles(use_cache=settings.sonarr.getboolean('use_ffprobe_cache')): episodes = TableEpisodes.select(TableEpisodes.path).dicts() count_episodes = len(episodes) @@ -273,7 +272,7 @@ def series_full_scan_subtitles(): name='Episodes subtitles', value=i, count=count_episodes) - store_subtitles(episode['path'], path_mappings.path_replace(episode['path']), use_cache=use_ffprobe_cache) + store_subtitles(episode['path'], path_mappings.path_replace(episode['path']), use_cache=use_cache) hide_progress(id='episodes_disk_scan') diff --git a/bazarr/subtitles/refiners/ffprobe.py b/bazarr/subtitles/refiners/ffprobe.py index c1c69072e..22c21a67c 100644 --- a/bazarr/subtitles/refiners/ffprobe.py +++ b/bazarr/subtitles/refiners/ffprobe.py @@ -7,7 +7,7 @@ from subliminal import Movie from utilities.path_mappings import path_mappings from app.database import TableEpisodes, TableMovies -from subtitles.tools.embedded_subs_reader import parse_video_metadata +from utilities.video_analyzer import parse_video_metadata def refine_from_ffprobe(path, video): diff --git a/bazarr/subtitles/upload.py b/bazarr/subtitles/upload.py index 19e1d965d..6891261f8 100644 --- a/bazarr/subtitles/upload.py +++ b/bazarr/subtitles/upload.py @@ -10,8 +10,7 @@ from subliminal_patch.core import save_subtitles from subliminal_patch.subtitle import Subtitle from pysubs2.formats import get_format_identifier -from languages.get_languages import language_from_alpha3, alpha2_from_alpha3, alpha3_from_alpha2, \ - alpha2_from_language, alpha3_from_language +from languages.get_languages import language_from_alpha3, alpha2_from_alpha3, alpha3_from_alpha2 from app.config import settings, get_array_from from utilities.helper import get_target_folder, force_unicode from utilities.post_processing import pp_replace @@ -26,7 +25,7 @@ from .sync import sync_subtitles from .post_processing import postprocessing -def manual_upload_subtitle(path, language, forced, hi, title, sceneName, media_type, subtitle, audio_language): +def manual_upload_subtitle(path, language, forced, hi, media_type, subtitle, audio_language): logging.debug(f'BAZARR Manually uploading subtitles for this file: {path}') single = settings.general.getboolean('single_language') @@ -131,8 +130,6 @@ def manual_upload_subtitle(path, language, forced, hi, title, sceneName, media_t uploaded_language_code3 = language + modifier_code uploaded_language = language_from_alpha3(language) + modifier_string uploaded_language_code2 = alpha2_from_alpha3(language) + modifier_code - audio_language_code2 = alpha2_from_language(audio_language) - audio_language_code3 = alpha3_from_language(audio_language) if media_type == 'series': if not episode_metadata: @@ -152,8 +149,8 @@ def manual_upload_subtitle(path, language, forced, hi, title, sceneName, media_t if use_postprocessing: command = pp_replace(postprocessing_cmd, path, subtitle_path, uploaded_language, uploaded_language_code2, - uploaded_language_code3, audio_language, audio_language_code2, audio_language_code3, 100, - "1", "manual", series_id, episode_id) + uploaded_language_code3, audio_language['name'], audio_language['code2'], + audio_language['code3'], 100, "1", "manual", series_id, episode_id) postprocessing(command, path) if media_type == 'series': diff --git a/bazarr/subtitles/tools/embedded_subs_reader.py b/bazarr/utilities/video_analyzer.py similarity index 76% rename from bazarr/subtitles/tools/embedded_subs_reader.py rename to bazarr/utilities/video_analyzer.py index 238370d03..72c3a1b5f 100644 --- a/bazarr/subtitles/tools/embedded_subs_reader.py +++ b/bazarr/utilities/video_analyzer.py @@ -6,6 +6,7 @@ import pickle from knowit.api import know, KnowitException from languages.custom_lang import CustomLanguage +from languages.get_languages import language_from_alpha3, alpha3_from_alpha2 from app.database import TableEpisodes, TableMovies from utilities.path_mappings import path_mappings from app.config import settings @@ -24,49 +25,73 @@ def _handle_alpha3(detected_language: dict): def embedded_subs_reader(file, file_size, episode_file_id=None, movie_file_id=None, use_cache=True): data = parse_video_metadata(file, file_size, episode_file_id, movie_file_id, use_cache=use_cache) + und_default_language = alpha3_from_alpha2(settings.general.default_und_embedded_subtitles_lang) subtitles_list = [] if not data: return subtitles_list + cache_provider = None if data["ffprobe"] and "subtitle" in data["ffprobe"]: - for detected_language in data["ffprobe"]["subtitle"]: - if "language" not in detected_language: - continue + cache_provider = 'ffprobe' + elif 'mediainfo' in data and data["mediainfo"] and "subtitle" in data["mediainfo"]: + cache_provider = 'mediainfo' + if cache_provider: + for detected_language in data[cache_provider]["subtitle"]: # Avoid commentary subtitles name = detected_language.get("name", "").lower() if "commentary" in name: - logging.debug("Ignoring commentary subtitle: %s", name) + logging.debug(f"Ignoring commentary subtitle: {name}") continue - language = _handle_alpha3(detected_language) + if "language" not in detected_language: + language = None + else: + language = _handle_alpha3(detected_language) + + if not language and und_default_language: + logging.debug(f"Undefined language embedded subtitles track treated as {language}") + language = und_default_language + + if not language: + continue forced = detected_language.get("forced", False) hearing_impaired = detected_language.get("hearing_impaired", False) codec = detected_language.get("format") # or None subtitles_list.append([language, forced, hearing_impaired, codec]) - elif 'mediainfo' in data and data["mediainfo"] and "subtitle" in data["mediainfo"]: - for detected_language in data["mediainfo"]["subtitle"]: - if "language" not in detected_language: - continue + return subtitles_list - # Avoid commentary subtitles - name = detected_language.get("name", "").lower() - if "commentary" in name: - logging.debug("Ignoring commentary subtitle: %s", name) + +def embedded_audio_reader(file, file_size, episode_file_id=None, movie_file_id=None, use_cache=True): + data = parse_video_metadata(file, file_size, episode_file_id, movie_file_id, use_cache=use_cache) + + audio_list = [] + + if not data: + return audio_list + + cache_provider = None + if data["ffprobe"] and "audio" in data["ffprobe"]: + cache_provider = 'ffprobe' + elif 'mediainfo' in data and data["mediainfo"] and "audio" in data["mediainfo"]: + cache_provider = 'mediainfo' + + if cache_provider: + for detected_language in data[cache_provider]["audio"]: + if "language" not in detected_language: + audio_list.append(None) continue - language = _handle_alpha3(detected_language) + language = language_from_alpha3(detected_language["language"].alpha3) - forced = detected_language.get("forced", False) - hearing_impaired = detected_language.get("hearing_impaired", False) - codec = detected_language.get("format") # or None - subtitles_list.append([language, forced, hearing_impaired, codec]) + if language not in audio_list: + audio_list.append(language) - return subtitles_list + return audio_list def parse_video_metadata(file, file_size, episode_file_id=None, movie_file_id=None, use_cache=True): diff --git a/frontend/src/apis/hooks/system.ts b/frontend/src/apis/hooks/system.ts index 24691c4b6..9be28c4d2 100644 --- a/frontend/src/apis/hooks/system.ts +++ b/frontend/src/apis/hooks/system.ts @@ -49,6 +49,11 @@ export function useSettingsMutation() { { onSuccess: () => { client.invalidateQueries([QueryKeys.System]); + client.invalidateQueries([QueryKeys.Series]); + client.invalidateQueries([QueryKeys.Episodes]); + client.invalidateQueries([QueryKeys.Movies]); + client.invalidateQueries([QueryKeys.Wanted]); + client.invalidateQueries([QueryKeys.Badges]); }, } ); diff --git a/frontend/src/pages/Series/index.tsx b/frontend/src/pages/Series/index.tsx index 6dfe07230..da20c4459 100644 --- a/frontend/src/pages/Series/index.tsx +++ b/frontend/src/pages/Series/index.tsx @@ -1,6 +1,5 @@ import { useSeriesModification, useSeriesPagination } from "@/apis/hooks"; import { Action } from "@/components"; -import { AudioList } from "@/components/bazarr"; import LanguageProfileName from "@/components/bazarr/LanguageProfile"; import { ItemEditModal } from "@/components/forms/ItemEditForm"; import { useModals } from "@/modules/modals"; @@ -44,13 +43,6 @@ const SeriesView: FunctionComponent = () => { ); }, }, - { - Header: "Audio", - accessor: "audio_language", - Cell: ({ value }) => { - return ; - }, - }, { Header: "Languages Profile", accessor: "profileId", diff --git a/frontend/src/pages/Settings/Languages/index.tsx b/frontend/src/pages/Settings/Languages/index.tsx index 726992916..4616ab1ab 100644 --- a/frontend/src/pages/Settings/Languages/index.tsx +++ b/frontend/src/pages/Settings/Languages/index.tsx @@ -1,8 +1,20 @@ import { useLanguageProfiles, useLanguages } from "@/apis/hooks"; import { useEnabledLanguages } from "@/utilities/languages"; import { FunctionComponent } from "react"; -import { Check, CollapseBox, Layout, Message, Section } from "../components"; -import { enabledLanguageKey, languageProfileKey } from "../keys"; +import { + Check, + CollapseBox, + Layout, + Message, + Section, + Selector, +} from "../components"; +import { + defaultUndAudioLang, + defaultUndEmbeddedSubtitlesLang, + enabledLanguageKey, + languageProfileKey, +} from "../keys"; import { useSettingValue } from "../utilities/hooks"; import { LanguageSelector, ProfileSelector } from "./components"; import Table from "./table"; @@ -31,6 +43,8 @@ export function useLatestProfiles() { const SettingsLanguagesView: FunctionComponent = () => { const { data: languages } = useLanguages(); + const { data: und_audio_languages } = useEnabledLanguages(); + const { data: und_embedded_subtitles_languages } = useEnabledLanguages(); return (
@@ -54,6 +68,34 @@ const SettingsLanguagesView: FunctionComponent = () => { options={languages ?? []} >
+ +
+ { + return { label: v.name, value: v.code2 }; + })} + settingOptions={{ + onSubmit: (v) => (v === null ? "" : v), + }} + > + + { + return { label: v.name, value: v.code2 }; + })} + settingOptions={{ + onSubmit: (v) => (v === null ? "" : v), + }} + > +
diff --git a/frontend/src/pages/Settings/keys.ts b/frontend/src/pages/Settings/keys.ts index a8ab17a5b..40b6a252d 100644 --- a/frontend/src/pages/Settings/keys.ts +++ b/frontend/src/pages/Settings/keys.ts @@ -1,4 +1,7 @@ export const enabledLanguageKey = "languages-enabled"; +export const defaultUndAudioLang = "settings-general-default_und_audio_lang"; +export const defaultUndEmbeddedSubtitlesLang = + "settings-general-default_und_embedded_subtitles_lang"; export const languageProfileKey = "languages-profiles"; export const notificationsKey = "notifications-providers";