From c4b8345e659e38992456e31a4c21bbf0a7d38545 Mon Sep 17 00:00:00 2001 From: morpheus65535 Date: Tue, 20 Dec 2022 23:37:52 -0500 Subject: [PATCH] Added mediainfo as potential embedded subtitles parser. #2007 --- bazarr/app/config.py | 3 +- bazarr/subtitles/refiners/ffprobe.py | 43 +++++++++++-------- .../subtitles/tools/embedded_subs_reader.py | 33 ++++++++++++-- .../src/pages/Settings/Subtitles/index.tsx | 9 ++++ .../src/pages/Settings/Subtitles/options.ts | 12 ++++++ 5 files changed, 78 insertions(+), 22 deletions(-) diff --git a/bazarr/app/config.py b/bazarr/app/config.py index faee369e1..0ce861856 100644 --- a/bazarr/app/config.py +++ b/bazarr/app/config.py @@ -78,7 +78,8 @@ defaults = { 'wanted_search_frequency_movie': '3', 'subzero_mods': '[]', 'dont_notify_manual_actions': 'False', - 'hi_extension': 'hi' + 'hi_extension': 'hi', + 'embedded_subtitles_parser': 'ffprobe' }, 'auth': { 'type': 'None', diff --git a/bazarr/subtitles/refiners/ffprobe.py b/bazarr/subtitles/refiners/ffprobe.py index 2ffcac1c6..f0e1ce0bd 100644 --- a/bazarr/subtitles/refiners/ffprobe.py +++ b/bazarr/subtitles/refiners/ffprobe.py @@ -32,38 +32,45 @@ def refine_from_ffprobe(path, video): data = parse_video_metadata(file=path, file_size=file_id['file_size'], episode_file_id=file_id['episode_file_id']) - if not data['ffprobe']: + if not data['ffprobe'] or data['mediainfo']: logging.debug("No FFprobe available in cache for this file: {}".format(path)) return video - logging.debug('FFprobe found: %s', data['ffprobe']) + if data['ffprobe']: + logging.debug('FFprobe found: %s', data['ffprobe']) + parser_data = data['ffprobe'] + elif data['mediainfo']: + logging.debug('Mediainfo found: %s', data['mediainfo']) + parser_data = data['mediainfo'] + else: + parser_data = {} - if 'video' not in data['ffprobe']: - logging.debug('BAZARR FFprobe was unable to find video tracks in the file!') + if 'video' not in parser_data: + logging.debug('BAZARR parser was unable to find video tracks in the file!') else: - if 'resolution' in data['ffprobe']['video'][0]: + if 'resolution' in parser_data['video'][0]: if not video.resolution: - video.resolution = data['ffprobe']['video'][0]['resolution'] - if 'codec' in data['ffprobe']['video'][0]: + video.resolution = parser_data['video'][0]['resolution'] + if 'codec' in parser_data['video'][0]: if not video.video_codec: - video.video_codec = data['ffprobe']['video'][0]['codec'] - if 'frame_rate' in data['ffprobe']['video'][0]: + video.video_codec = parser_data['video'][0]['codec'] + if 'frame_rate' in parser_data['video'][0]: if not video.fps: - if isinstance(data['ffprobe']['video'][0]['frame_rate'], float): - video.fps = data['ffprobe']['video'][0]['frame_rate'] + if isinstance(parser_data['video'][0]['frame_rate'], float): + video.fps = parser_data['video'][0]['frame_rate'] else: try: - video.fps = data['ffprobe']['video'][0]['frame_rate'].magnitude + video.fps = parser_data['video'][0]['frame_rate'].magnitude except AttributeError: - video.fps = data['ffprobe']['video'][0]['frame_rate'] + video.fps = parser_data['video'][0]['frame_rate'] - if 'audio' not in data['ffprobe']: - logging.debug('BAZARR FFprobe was unable to find audio tracks in the file!') + if 'audio' not in parser_data: + logging.debug('BAZARR parser was unable to find audio tracks in the file!') else: - if 'codec' in data['ffprobe']['audio'][0]: + if 'codec' in parser_data['audio'][0]: if not video.audio_codec: - video.audio_codec = data['ffprobe']['audio'][0]['codec'] - for track in data['ffprobe']['audio']: + video.audio_codec = parser_data['audio'][0]['codec'] + for track in parser_data['audio']: if 'language' in track: video.audio_languages.add(track['language'].alpha3) diff --git a/bazarr/subtitles/tools/embedded_subs_reader.py b/bazarr/subtitles/tools/embedded_subs_reader.py index 3a6ff50c5..99c8490f6 100644 --- a/bazarr/subtitles/tools/embedded_subs_reader.py +++ b/bazarr/subtitles/tools/embedded_subs_reader.py @@ -11,6 +11,7 @@ from enzyme.exceptions import MalformedMKVError from languages.custom_lang import CustomLanguage from app.database import TableEpisodes, TableMovies from utilities.path_mappings import path_mappings +from app.config import settings def _handle_alpha3(detected_language: dict): @@ -46,6 +47,24 @@ def embedded_subs_reader(file, file_size, episode_file_id=None, movie_file_id=No 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 + + # 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]) + elif data["enzyme"]: for subtitle_track in data["enzyme"].subtitle_tracks: hearing_impaired = ( @@ -68,6 +87,7 @@ def parse_video_metadata(file, file_size, episode_file_id=None, movie_file_id=No # Define default data keys value data = { "ffprobe": {}, + "mediainfo": {}, "enzyme": {}, "file_id": episode_file_id or movie_file_id, "file_size": file_size, @@ -102,12 +122,19 @@ def parse_video_metadata(file, file_size, episode_file_id=None, movie_file_id=No # if not, we retrieve the metadata from the file from utilities.binaries import get_binary - ffprobe_path = get_binary("ffprobe") + ffprobe_path = mediainfo_path = None + if settings.general.embedded_subtitles_parser == 'ffprobe': + ffprobe_path = get_binary("ffprobe") + elif settings.general.embedded_subtitles_parser == 'mediainfo': + mediainfo_path = get_binary("mediainfo") # if we have ffprobe available if ffprobe_path: data["ffprobe"] = know(video_path=file, context={"provider": "ffmpeg", "ffmpeg": ffprobe_path}) - # if not, we use enzyme for mkv files + # or if we have mediainfo available + elif mediainfo_path: + data["mediainfo"] = know(video_path=file, context={"provider": "mediainfo", "mediainfo": mediainfo_path}) + # else, we use enzyme for mkv files else: if os.path.splitext(file)[1] == ".mkv": with open(file, "rb") as f: @@ -116,7 +143,7 @@ def parse_video_metadata(file, file_size, episode_file_id=None, movie_file_id=No except MalformedMKVError: logging.error( "BAZARR cannot analyze this MKV with our built-in MKV parser, you should install " - "ffmpeg/ffprobe: " + file + "ffmpeg/ffprobe or mediainfo: " + file ) else: data["enzyme"] = mkv diff --git a/frontend/src/pages/Settings/Subtitles/index.tsx b/frontend/src/pages/Settings/Subtitles/index.tsx index 2c71b3cdc..a1927682f 100644 --- a/frontend/src/pages/Settings/Subtitles/index.tsx +++ b/frontend/src/pages/Settings/Subtitles/index.tsx @@ -20,6 +20,7 @@ import { adaptiveSearchingDeltaOption, antiCaptchaOption, colorOptions, + embeddedSubtitlesParserOption, folderOptions, hiExtensionOptions, } from "./options"; @@ -278,6 +279,14 @@ const SettingsSubtitlesView: FunctionComponent = () => { Hide embedded subtitles for languages that are not currently desired. + (v === undefined ? "ffprobe" : v), + }} + options={embeddedSubtitlesParserOption} + > + Embedded subtitles video parser
diff --git a/frontend/src/pages/Settings/Subtitles/options.ts b/frontend/src/pages/Settings/Subtitles/options.ts index 5549a4128..62c4f60b2 100644 --- a/frontend/src/pages/Settings/Subtitles/options.ts +++ b/frontend/src/pages/Settings/Subtitles/options.ts @@ -41,6 +41,18 @@ export const antiCaptchaOption: SelectorOption[] = [ }, ]; +export const embeddedSubtitlesParserOption: SelectorOption[] = [ + { + label: "ffprobe (faster)", + value: "ffprobe", + }, + { + label: + "mediainfo (slower but may give better results. Must be already installed)", + value: "mediainfo", + }, +]; + export const adaptiveSearchingDelayOption: SelectorOption[] = [ { label: "1 week",