2021-01-19 04:49:51 +00:00
|
|
|
# coding=utf-8
|
|
|
|
|
2019-04-23 12:35:50 +00:00
|
|
|
import logging
|
2021-05-06 03:07:23 +00:00
|
|
|
import pickle
|
2022-05-01 12:00:20 +00:00
|
|
|
|
2022-06-09 01:34:21 +00:00
|
|
|
from knowit.api import know
|
2021-05-06 03:07:23 +00:00
|
|
|
|
2022-05-01 12:00:20 +00:00
|
|
|
from languages.custom_lang import CustomLanguage
|
|
|
|
from app.database import TableEpisodes, TableMovies
|
|
|
|
from utilities.path_mappings import path_mappings
|
2022-12-21 04:37:52 +00:00
|
|
|
from app.config import settings
|
2021-06-06 13:57:29 +00:00
|
|
|
|
2021-05-15 12:14:46 +00:00
|
|
|
|
|
|
|
def _handle_alpha3(detected_language: dict):
|
|
|
|
alpha3 = detected_language["language"].alpha3
|
2021-06-06 13:57:29 +00:00
|
|
|
custom = CustomLanguage.from_value(alpha3, "official_alpha3")
|
2021-05-15 12:14:46 +00:00
|
|
|
|
2021-06-06 13:57:29 +00:00
|
|
|
if custom and custom.ffprobe_found(detected_language):
|
2022-05-01 12:00:20 +00:00
|
|
|
logging.debug("Custom embedded language found: %s", custom.name)
|
2021-06-06 13:57:29 +00:00
|
|
|
return custom.alpha3
|
2021-05-15 12:14:46 +00:00
|
|
|
|
2021-06-06 13:57:29 +00:00
|
|
|
return alpha3
|
2021-05-15 12:14:46 +00:00
|
|
|
|
2021-05-06 03:07:23 +00:00
|
|
|
|
2021-06-11 21:32:12 +00:00
|
|
|
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)
|
2021-05-02 21:30:35 +00:00
|
|
|
|
2021-05-06 03:07:23 +00:00
|
|
|
subtitles_list = []
|
2021-06-06 13:57:29 +00:00
|
|
|
if data["ffprobe"] and "subtitle" in data["ffprobe"]:
|
|
|
|
for detected_language in data["ffprobe"]["subtitle"]:
|
2022-01-03 03:59:30 +00:00
|
|
|
if "language" not in detected_language:
|
2021-05-15 12:14:46 +00:00
|
|
|
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)
|
2021-06-06 13:57:29 +00:00
|
|
|
codec = detected_language.get("format") # or None
|
2021-05-15 12:14:46 +00:00
|
|
|
subtitles_list.append([language, forced, hearing_impaired, codec])
|
|
|
|
|
2022-12-21 04:37:52 +00:00
|
|
|
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])
|
|
|
|
|
2021-05-06 03:07:23 +00:00
|
|
|
return subtitles_list
|
2021-05-02 21:30:35 +00:00
|
|
|
|
2020-07-19 20:02:38 +00:00
|
|
|
|
2021-06-11 21:32:12 +00:00
|
|
|
def parse_video_metadata(file, file_size, episode_file_id=None, movie_file_id=None, use_cache=True):
|
2021-05-06 03:07:23 +00:00
|
|
|
# Define default data keys value
|
|
|
|
data = {
|
2021-06-06 13:57:29 +00:00
|
|
|
"ffprobe": {},
|
2022-12-21 04:37:52 +00:00
|
|
|
"mediainfo": {},
|
2021-06-06 13:57:29 +00:00
|
|
|
"file_id": episode_file_id or movie_file_id,
|
|
|
|
"file_size": file_size,
|
2021-05-06 03:07:23 +00:00
|
|
|
}
|
2020-03-18 19:33:54 +00:00
|
|
|
|
2022-12-22 00:30:59 +00:00
|
|
|
embedded_subs_parser = settings.general.embedded_subtitles_parser
|
|
|
|
|
2021-06-11 21:32:12 +00:00
|
|
|
if use_cache:
|
|
|
|
# Get the actual cache value form database
|
|
|
|
if episode_file_id:
|
|
|
|
cache_key = TableEpisodes.select(TableEpisodes.ffprobe_cache)\
|
2021-08-17 17:10:27 +00:00
|
|
|
.where(TableEpisodes.path == path_mappings.path_replace_reverse(file))\
|
2021-06-11 21:32:12 +00:00
|
|
|
.dicts()\
|
2022-02-11 15:59:09 +00:00
|
|
|
.get_or_none()
|
2021-06-11 21:32:12 +00:00
|
|
|
elif movie_file_id:
|
|
|
|
cache_key = TableMovies.select(TableMovies.ffprobe_cache)\
|
2021-08-17 17:10:27 +00:00
|
|
|
.where(TableMovies.path == path_mappings.path_replace_reverse_movie(file))\
|
2021-06-11 21:32:12 +00:00
|
|
|
.dicts()\
|
2022-02-11 15:59:09 +00:00
|
|
|
.get_or_none()
|
2021-06-11 21:32:12 +00:00
|
|
|
else:
|
|
|
|
cache_key = None
|
|
|
|
|
|
|
|
# check if we have a value for that cache key
|
|
|
|
try:
|
|
|
|
# Unpickle ffprobe cache
|
|
|
|
cached_value = pickle.loads(cache_key['ffprobe_cache'])
|
2022-01-03 03:59:30 +00:00
|
|
|
except Exception:
|
2021-06-11 21:32:12 +00:00
|
|
|
pass
|
|
|
|
else:
|
2022-12-22 00:30:59 +00:00
|
|
|
# Check if file size and file id matches and if so, we return the cached value if available for the
|
|
|
|
# desired parser
|
2021-06-11 21:32:12 +00:00
|
|
|
if cached_value['file_size'] == file_size and cached_value['file_id'] in [episode_file_id, movie_file_id]:
|
2022-12-22 16:37:37 +00:00
|
|
|
if embedded_subs_parser in cached_value and cached_value[embedded_subs_parser]:
|
2022-12-22 00:30:59 +00:00
|
|
|
return cached_value
|
2022-12-22 16:37:37 +00:00
|
|
|
else:
|
|
|
|
# no valid cache
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
# cache mut be renewed
|
|
|
|
pass
|
2019-04-27 12:13:47 +00:00
|
|
|
|
2021-05-06 03:07:23 +00:00
|
|
|
# if not, we retrieve the metadata from the file
|
2022-05-01 12:00:20 +00:00
|
|
|
from utilities.binaries import get_binary
|
2021-06-06 13:57:29 +00:00
|
|
|
|
2022-12-21 04:37:52 +00:00
|
|
|
ffprobe_path = mediainfo_path = None
|
2022-12-22 00:30:59 +00:00
|
|
|
if embedded_subs_parser == 'ffprobe':
|
2022-12-21 04:37:52 +00:00
|
|
|
ffprobe_path = get_binary("ffprobe")
|
2022-12-22 00:30:59 +00:00
|
|
|
elif embedded_subs_parser == 'mediainfo':
|
2022-12-21 04:37:52 +00:00
|
|
|
mediainfo_path = get_binary("mediainfo")
|
2019-04-27 12:13:47 +00:00
|
|
|
|
2021-05-06 03:07:23 +00:00
|
|
|
# if we have ffprobe available
|
|
|
|
if ffprobe_path:
|
2022-06-09 01:34:21 +00:00
|
|
|
data["ffprobe"] = know(video_path=file, context={"provider": "ffmpeg", "ffmpeg": ffprobe_path})
|
2022-12-21 04:37:52 +00:00
|
|
|
# or if we have mediainfo available
|
|
|
|
elif mediainfo_path:
|
|
|
|
data["mediainfo"] = know(video_path=file, context={"provider": "mediainfo", "mediainfo": mediainfo_path})
|
2022-12-22 16:37:37 +00:00
|
|
|
# else, we warn user of missing binary
|
2021-05-06 03:07:23 +00:00
|
|
|
else:
|
2022-12-22 16:37:37 +00:00
|
|
|
logging.error("BAZARR require ffmpeg/ffprobe or mediainfo, please install it and make sure to choose it in "
|
|
|
|
"Settings-->Subtitles.")
|
|
|
|
return
|
2019-04-23 12:35:50 +00:00
|
|
|
|
2021-05-06 03:07:23 +00:00
|
|
|
# we write to db the result and return the newly cached ffprobe dict
|
|
|
|
if episode_file_id:
|
2021-05-26 20:47:14 +00:00
|
|
|
TableEpisodes.update({TableEpisodes.ffprobe_cache: pickle.dumps(data, pickle.HIGHEST_PROTOCOL)})\
|
2021-08-17 17:10:27 +00:00
|
|
|
.where(TableEpisodes.path == path_mappings.path_replace_reverse(file))\
|
2021-05-26 20:47:14 +00:00
|
|
|
.execute()
|
2021-05-06 03:07:23 +00:00
|
|
|
elif movie_file_id:
|
2021-05-26 20:47:14 +00:00
|
|
|
TableMovies.update({TableEpisodes.ffprobe_cache: pickle.dumps(data, pickle.HIGHEST_PROTOCOL)})\
|
2021-08-17 17:10:27 +00:00
|
|
|
.where(TableMovies.path == path_mappings.path_replace_reverse_movie(file))\
|
2021-05-26 20:47:14 +00:00
|
|
|
.execute()
|
2021-05-06 03:07:23 +00:00
|
|
|
return data
|