From 5dc4e782ae31ed36aaf4d27d9a46af3e494c7491 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Thu, 23 Feb 2023 18:31:29 -0500 Subject: [PATCH] Added option to deeply analyze audio tracks from media files or not to determine languages. Default is to use Sonarr/Radarr provided languages instead. Should prevent API limit ban for cloud user. --- bazarr/app/config.py | 18 +++++++- bazarr/radarr/sync/parser.py | 33 +++++++++++--- bazarr/sonarr/sync/parser.py | 43 ++++++++++++++++--- frontend/src/pages/Series/index.tsx | 8 ++++ .../src/pages/Settings/Languages/index.tsx | 35 +++++++++------ 5 files changed, 112 insertions(+), 25 deletions(-) diff --git a/bazarr/app/config.py b/bazarr/app/config.py index ba4bc8a26..37da0f744 100644 --- a/bazarr/app/config.py +++ b/bazarr/app/config.py @@ -81,7 +81,8 @@ defaults = { 'hi_extension': 'hi', 'embedded_subtitles_parser': 'ffprobe', 'default_und_audio_lang': '', - 'default_und_embedded_subtitles_lang': '' + 'default_und_embedded_subtitles_lang': '', + 'parse_embedded_audio_track': 'False' }, 'auth': { 'type': 'None', @@ -385,6 +386,7 @@ def save_settings(settings_items): use_embedded_subs_changed = False undefined_audio_track_default_changed = False undefined_subtitles_track_default_changed = False + audio_tracks_parsing_changed = False # Subzero Mods update_subzero = False @@ -423,6 +425,9 @@ def save_settings(settings_items): if key == 'settings-general-default_und_audio_lang': undefined_audio_track_default_changed = True + if key == 'settings-general-parse_embedded_audio_track': + audio_tracks_parsing_changed = True + if key == 'settings-general-default_und_embedded_subtitles_lang': undefined_subtitles_track_default_changed = True @@ -565,6 +570,17 @@ def save_settings(settings_items): if settings.general.getboolean('use_radarr'): scheduler.add_job(movies_full_scan_subtitles, kwargs={'use_cache': True}) + if audio_tracks_parsing_changed: + from .scheduler import scheduler + if settings.general.getboolean('use_sonarr'): + from sonarr.sync.episodes import sync_episodes + from sonarr.sync.series import update_series + scheduler.add_job(update_series, kwargs={'send_event': True}, max_instances=1) + scheduler.add_job(sync_episodes, kwargs={'send_event': True}, max_instances=1) + if settings.general.getboolean('use_radarr'): + from radarr.sync.movies import update_movies + scheduler.add_job(update_movies, kwargs={'send_event': True}, max_instances=1) + if update_subzero: settings.set('general', 'subzero_mods', ','.join(subzero_mods)) diff --git a/bazarr/radarr/sync/parser.py b/bazarr/radarr/sync/parser.py index 7537bcec2..60b4c7024 100644 --- a/bazarr/radarr/sync/parser.py +++ b/bazarr/radarr/sync/parser.py @@ -2,6 +2,8 @@ import os +from app.config import settings +from languages.get_languages import language_from_alpha2 from radarr.info import get_radarr_info from utilities.video_analyzer import embedded_audio_reader from utilities.path_mappings import path_mappings @@ -90,10 +92,31 @@ def movieParser(movie, action, tags_dict, movie_default_profile, audio_profiles) videoCodec = None audioCodec = None - 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) + if settings.general.getboolean('parse_embedded_audio_track'): + 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) + else: + 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) tags = [d['label'] for d in tags_dict if d['id'] in movie['tags']] @@ -146,8 +169,8 @@ def movieParser(movie, action, tags_dict, movie_default_profile, audio_profiles) def profile_id_to_language(id, profiles): + profiles_to_return = [] for profile in profiles: - profiles_to_return = [] if id == profile[0]: profiles_to_return.append(profile[1]) return profiles_to_return diff --git a/bazarr/sonarr/sync/parser.py b/bazarr/sonarr/sync/parser.py index 9fc3c4db2..341229d48 100644 --- a/bazarr/sonarr/sync/parser.py +++ b/bazarr/sonarr/sync/parser.py @@ -2,8 +2,11 @@ import os +from app.config import settings +from app.database import TableShows from utilities.path_mappings import path_mappings from utilities.video_analyzer import embedded_audio_reader +from sonarr.info import get_sonarr_info from .converter import SonarrFormatVideoCodec, SonarrFormatAudioCodec @@ -28,6 +31,16 @@ def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles) imdbId = show['imdbId'] if 'imdbId' in show else None + audio_language = [] + if not settings.general.getboolean('parse_embedded_audio_track'): + 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 = [] + if action == 'update': return {'title': show["title"], 'path': show["path"], @@ -36,7 +49,7 @@ def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles) 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': str([]), + 'audio_language': str(audio_language), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternativeTitles': alternate_titles, @@ -52,7 +65,7 @@ def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles) 'overview': overview, 'poster': poster, 'fanart': fanart, - 'audio_language': str([]), + 'audio_language': str(audio_language), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternativeTitles': alternate_titles, @@ -85,10 +98,28 @@ def episodeParser(episode): else: sceneName = None - 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 settings.general.getboolean('parse_embedded_audio_track'): + 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) + else: + 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 if 'mediaInfo' in episode['episodeFile']: if 'videoCodec' in episode['episodeFile']['mediaInfo']: diff --git a/frontend/src/pages/Series/index.tsx b/frontend/src/pages/Series/index.tsx index da20c4459..6dfe07230 100644 --- a/frontend/src/pages/Series/index.tsx +++ b/frontend/src/pages/Series/index.tsx @@ -1,5 +1,6 @@ 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"; @@ -43,6 +44,13 @@ 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 4616ab1ab..64c3e58b2 100644 --- a/frontend/src/pages/Settings/Languages/index.tsx +++ b/frontend/src/pages/Settings/Languages/index.tsx @@ -69,19 +69,28 @@ const SettingsLanguagesView: FunctionComponent = () => { > -
- { - 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), + }} + > +