mirror of
https://github.com/morpheus65535/bazarr.git
synced 2025-04-24 06:37:16 -04:00
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
This commit is contained in:
parent
7f05f932ff
commit
3310f6aeb8
15 changed files with 189 additions and 135 deletions
|
@ -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)
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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']]
|
||||
|
||||
|
|
|
@ -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']:
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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,42 +25,38 @@ 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
|
||||
|
||||
# Avoid commentary subtitles
|
||||
name = detected_language.get("name", "").lower()
|
||||
if "commentary" in name:
|
||||
logging.debug("Ignoring commentary subtitle: %s", name)
|
||||
continue
|
||||
|
||||
language = _handle_alpha3(detected_language)
|
||||
|
||||
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])
|
||||
|
||||
cache_provider = 'ffprobe'
|
||||
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
|
||||
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)
|
||||
|
@ -69,6 +66,34 @@ def embedded_subs_reader(file, file_size, episode_file_id=None, movie_file_id=No
|
|||
return subtitles_list
|
||||
|
||||
|
||||
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 = language_from_alpha3(detected_language["language"].alpha3)
|
||||
|
||||
if language not in audio_list:
|
||||
audio_list.append(language)
|
||||
|
||||
return audio_list
|
||||
|
||||
|
||||
def parse_video_metadata(file, file_size, episode_file_id=None, movie_file_id=None, use_cache=True):
|
||||
# Define default data keys value
|
||||
data = {
|
|
@ -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]);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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 <AudioList audios={value}></AudioList>;
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: "Languages Profile",
|
||||
accessor: "profileId",
|
||||
|
|
|
@ -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 (
|
||||
<Layout name="Languages">
|
||||
<Section header="Subtitles Language">
|
||||
|
@ -54,6 +68,34 @@ const SettingsLanguagesView: FunctionComponent = () => {
|
|||
options={languages ?? []}
|
||||
></LanguageSelector>
|
||||
</Section>
|
||||
|
||||
<Section header="Default Unknown Track Language">
|
||||
<Selector
|
||||
clearable
|
||||
settingKey={defaultUndAudioLang}
|
||||
label="Treat unknown language audio track as (changing this will trigger missing subtitles calculation)"
|
||||
placeholder="Select languages"
|
||||
options={und_audio_languages.map((v) => {
|
||||
return { label: v.name, value: v.code2 };
|
||||
})}
|
||||
settingOptions={{
|
||||
onSubmit: (v) => (v === null ? "" : v),
|
||||
}}
|
||||
></Selector>
|
||||
|
||||
<Selector
|
||||
clearable
|
||||
settingKey={defaultUndEmbeddedSubtitlesLang}
|
||||
label="Treat unknown language embedded subtitles track as (changing this will trigger full subtitles indexation using cache)"
|
||||
placeholder="Select languages"
|
||||
options={und_embedded_subtitles_languages.map((v) => {
|
||||
return { label: v.name, value: v.code2 };
|
||||
})}
|
||||
settingOptions={{
|
||||
onSubmit: (v) => (v === null ? "" : v),
|
||||
}}
|
||||
></Selector>
|
||||
</Section>
|
||||
<Section header="Languages Profiles">
|
||||
<Table></Table>
|
||||
</Section>
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue