mirror of https://github.com/morpheus65535/bazarr
Added mediainfo as potential embedded subtitles parser. #2007
This commit is contained in:
parent
1233026adc
commit
c4b8345e65
|
@ -78,7 +78,8 @@ defaults = {
|
||||||
'wanted_search_frequency_movie': '3',
|
'wanted_search_frequency_movie': '3',
|
||||||
'subzero_mods': '[]',
|
'subzero_mods': '[]',
|
||||||
'dont_notify_manual_actions': 'False',
|
'dont_notify_manual_actions': 'False',
|
||||||
'hi_extension': 'hi'
|
'hi_extension': 'hi',
|
||||||
|
'embedded_subtitles_parser': 'ffprobe'
|
||||||
},
|
},
|
||||||
'auth': {
|
'auth': {
|
||||||
'type': 'None',
|
'type': 'None',
|
||||||
|
|
|
@ -32,38 +32,45 @@ def refine_from_ffprobe(path, video):
|
||||||
data = parse_video_metadata(file=path, file_size=file_id['file_size'],
|
data = parse_video_metadata(file=path, file_size=file_id['file_size'],
|
||||||
episode_file_id=file_id['episode_file_id'])
|
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))
|
logging.debug("No FFprobe available in cache for this file: {}".format(path))
|
||||||
return video
|
return video
|
||||||
|
|
||||||
logging.debug('FFprobe found: %s', data['ffprobe'])
|
if data['ffprobe']:
|
||||||
|
logging.debug('FFprobe found: %s', data['ffprobe'])
|
||||||
if 'video' not in data['ffprobe']:
|
parser_data = data['ffprobe']
|
||||||
logging.debug('BAZARR FFprobe was unable to find video tracks in the file!')
|
elif data['mediainfo']:
|
||||||
|
logging.debug('Mediainfo found: %s', data['mediainfo'])
|
||||||
|
parser_data = data['mediainfo']
|
||||||
else:
|
else:
|
||||||
if 'resolution' in data['ffprobe']['video'][0]:
|
parser_data = {}
|
||||||
|
|
||||||
|
if 'video' not in parser_data:
|
||||||
|
logging.debug('BAZARR parser was unable to find video tracks in the file!')
|
||||||
|
else:
|
||||||
|
if 'resolution' in parser_data['video'][0]:
|
||||||
if not video.resolution:
|
if not video.resolution:
|
||||||
video.resolution = data['ffprobe']['video'][0]['resolution']
|
video.resolution = parser_data['video'][0]['resolution']
|
||||||
if 'codec' in data['ffprobe']['video'][0]:
|
if 'codec' in parser_data['video'][0]:
|
||||||
if not video.video_codec:
|
if not video.video_codec:
|
||||||
video.video_codec = data['ffprobe']['video'][0]['codec']
|
video.video_codec = parser_data['video'][0]['codec']
|
||||||
if 'frame_rate' in data['ffprobe']['video'][0]:
|
if 'frame_rate' in parser_data['video'][0]:
|
||||||
if not video.fps:
|
if not video.fps:
|
||||||
if isinstance(data['ffprobe']['video'][0]['frame_rate'], float):
|
if isinstance(parser_data['video'][0]['frame_rate'], float):
|
||||||
video.fps = data['ffprobe']['video'][0]['frame_rate']
|
video.fps = parser_data['video'][0]['frame_rate']
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
video.fps = data['ffprobe']['video'][0]['frame_rate'].magnitude
|
video.fps = parser_data['video'][0]['frame_rate'].magnitude
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
video.fps = data['ffprobe']['video'][0]['frame_rate']
|
video.fps = parser_data['video'][0]['frame_rate']
|
||||||
|
|
||||||
if 'audio' not in data['ffprobe']:
|
if 'audio' not in parser_data:
|
||||||
logging.debug('BAZARR FFprobe was unable to find audio tracks in the file!')
|
logging.debug('BAZARR parser was unable to find audio tracks in the file!')
|
||||||
else:
|
else:
|
||||||
if 'codec' in data['ffprobe']['audio'][0]:
|
if 'codec' in parser_data['audio'][0]:
|
||||||
if not video.audio_codec:
|
if not video.audio_codec:
|
||||||
video.audio_codec = data['ffprobe']['audio'][0]['codec']
|
video.audio_codec = parser_data['audio'][0]['codec']
|
||||||
for track in data['ffprobe']['audio']:
|
for track in parser_data['audio']:
|
||||||
if 'language' in track:
|
if 'language' in track:
|
||||||
video.audio_languages.add(track['language'].alpha3)
|
video.audio_languages.add(track['language'].alpha3)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from enzyme.exceptions import MalformedMKVError
|
||||||
from languages.custom_lang import CustomLanguage
|
from languages.custom_lang import CustomLanguage
|
||||||
from app.database import TableEpisodes, TableMovies
|
from app.database import TableEpisodes, TableMovies
|
||||||
from utilities.path_mappings import path_mappings
|
from utilities.path_mappings import path_mappings
|
||||||
|
from app.config import settings
|
||||||
|
|
||||||
|
|
||||||
def _handle_alpha3(detected_language: dict):
|
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
|
codec = detected_language.get("format") # or None
|
||||||
subtitles_list.append([language, forced, hearing_impaired, codec])
|
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"]:
|
elif data["enzyme"]:
|
||||||
for subtitle_track in data["enzyme"].subtitle_tracks:
|
for subtitle_track in data["enzyme"].subtitle_tracks:
|
||||||
hearing_impaired = (
|
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
|
# Define default data keys value
|
||||||
data = {
|
data = {
|
||||||
"ffprobe": {},
|
"ffprobe": {},
|
||||||
|
"mediainfo": {},
|
||||||
"enzyme": {},
|
"enzyme": {},
|
||||||
"file_id": episode_file_id or movie_file_id,
|
"file_id": episode_file_id or movie_file_id,
|
||||||
"file_size": file_size,
|
"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
|
# if not, we retrieve the metadata from the file
|
||||||
from utilities.binaries import get_binary
|
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 we have ffprobe available
|
||||||
if ffprobe_path:
|
if ffprobe_path:
|
||||||
data["ffprobe"] = know(video_path=file, context={"provider": "ffmpeg", "ffmpeg": 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:
|
else:
|
||||||
if os.path.splitext(file)[1] == ".mkv":
|
if os.path.splitext(file)[1] == ".mkv":
|
||||||
with open(file, "rb") as f:
|
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:
|
except MalformedMKVError:
|
||||||
logging.error(
|
logging.error(
|
||||||
"BAZARR cannot analyze this MKV with our built-in MKV parser, you should install "
|
"BAZARR cannot analyze this MKV with our built-in MKV parser, you should install "
|
||||||
"ffmpeg/ffprobe: " + file
|
"ffmpeg/ffprobe or mediainfo: " + file
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
data["enzyme"] = mkv
|
data["enzyme"] = mkv
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
adaptiveSearchingDeltaOption,
|
adaptiveSearchingDeltaOption,
|
||||||
antiCaptchaOption,
|
antiCaptchaOption,
|
||||||
colorOptions,
|
colorOptions,
|
||||||
|
embeddedSubtitlesParserOption,
|
||||||
folderOptions,
|
folderOptions,
|
||||||
hiExtensionOptions,
|
hiExtensionOptions,
|
||||||
} from "./options";
|
} from "./options";
|
||||||
|
@ -278,6 +279,14 @@ const SettingsSubtitlesView: FunctionComponent = () => {
|
||||||
Hide embedded subtitles for languages that are not currently
|
Hide embedded subtitles for languages that are not currently
|
||||||
desired.
|
desired.
|
||||||
</Message>
|
</Message>
|
||||||
|
<Selector
|
||||||
|
settingKey="settings-general-embedded_subtitles_parser"
|
||||||
|
settingOptions={{
|
||||||
|
onSaved: (v) => (v === undefined ? "ffprobe" : v),
|
||||||
|
}}
|
||||||
|
options={embeddedSubtitlesParserOption}
|
||||||
|
></Selector>
|
||||||
|
<Message>Embedded subtitles video parser</Message>
|
||||||
</CollapseBox>
|
</CollapseBox>
|
||||||
</Section>
|
</Section>
|
||||||
<Section header="Post-Processing">
|
<Section header="Post-Processing">
|
||||||
|
|
|
@ -41,6 +41,18 @@ export const antiCaptchaOption: SelectorOption<string>[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const embeddedSubtitlesParserOption: SelectorOption<string>[] = [
|
||||||
|
{
|
||||||
|
label: "ffprobe (faster)",
|
||||||
|
value: "ffprobe",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label:
|
||||||
|
"mediainfo (slower but may give better results. Must be already installed)",
|
||||||
|
value: "mediainfo",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const adaptiveSearchingDelayOption: SelectorOption<string>[] = [
|
export const adaptiveSearchingDelayOption: SelectorOption<string>[] = [
|
||||||
{
|
{
|
||||||
label: "1 week",
|
label: "1 week",
|
||||||
|
|
Loading…
Reference in New Issue