bazarr/bazarr/get_subtitle.py

1440 lines
73 KiB
Python
Raw Normal View History

# coding=utf-8
2017-09-17 00:11:47 +00:00
import os
import sys
2017-10-16 23:27:19 +00:00
import ast
2017-12-06 04:07:37 +00:00
import logging
2018-03-24 00:00:50 +00:00
import subprocess
import time
2020-02-13 04:16:22 +00:00
import pickle
import codecs
import re
2018-10-31 16:33:19 +00:00
import subliminal
from datetime import datetime, timedelta
from subzero.language import Language
from subzero.video import parse_video
from subliminal import region, score as subliminal_scores, \
list_subtitles, Episode, Movie
from subliminal_patch.core import SZAsyncProviderPool, download_best_subtitles, save_subtitles, download_subtitles, \
list_all_subtitles, get_subtitle_path
from subliminal_patch.score import compute_score
from subliminal_patch.subtitle import Subtitle
from get_languages import language_from_alpha3, alpha2_from_alpha3, alpha3_from_alpha2, language_from_alpha2, \
alpha2_from_language, alpha3_from_language
2018-12-15 00:36:28 +00:00
from config import settings
2020-05-19 13:27:13 +00:00
from helper import path_mappings, pp_replace, get_target_folder, force_unicode
2018-08-15 20:51:46 +00:00
from list_subtitles import store_subtitles, list_missing_subtitles, store_subtitles_movie, list_missing_subtitles_movies
from utils import history_log, history_log_movie, get_binary, get_blacklist, notify_sonarr, notify_radarr
2018-04-24 14:48:52 +00:00
from notifier import send_notifications, send_notifications_movie
from get_providers import get_providers, get_providers_auth, provider_throttle, provider_pool
2020-03-18 19:33:54 +00:00
from knowit import api
from subsyncer import subsync
from guessit import guessit
from database import database, dict_mapper, get_exclusion_clause, get_profiles_list, get_audio_profile_languages, \
get_desired_languages
2017-09-17 00:11:47 +00:00
from analytics import track_event
2020-01-06 22:11:01 +00:00
from locale import getpreferredencoding
2020-02-25 21:14:15 +00:00
def get_video(path, title, sceneName, providers=None, media_type="movie"):
"""
Construct `Video` instance
:param path: path to video
:param title: series/movie title
:param sceneName: sceneName
:param providers: provider list for selective hashing
:param media_type: movie/series
:return: `Video` instance
"""
hints = {"title": title, "type": "movie" if media_type == "movie" else "episode"}
used_scene_name = False
original_path = path
original_name = os.path.basename(path)
hash_from = None
2020-02-25 21:14:15 +00:00
if sceneName != "None":
# use the sceneName but keep the folder structure for better guessing
path = os.path.join(os.path.dirname(path), sceneName + os.path.splitext(path)[1])
used_scene_name = True
hash_from = original_path
2020-06-08 06:35:08 +00:00
2019-07-28 19:49:19 +00:00
try:
video = parse_video(path, hints=hints, providers=providers, dry_run=used_scene_name,
hash_from=hash_from)
video.used_scene_name = used_scene_name
video.original_name = original_name
video.original_path = original_path
2019-07-28 19:49:19 +00:00
refine_from_db(original_path, video)
refine_from_ffprobe(original_path, video)
2020-06-08 06:35:08 +00:00
2019-09-17 13:51:40 +00:00
logging.debug('BAZARR is using these video object properties: %s', vars(video))
2019-07-28 19:49:19 +00:00
return video
2020-06-08 06:35:08 +00:00
except Exception as e:
2021-01-25 04:10:00 +00:00
logging.exception("BAZARR Error trying to get video information for this file: " + original_path)
def get_scores(video, media_type, min_score_movie_perc=60 * 100 / 120.0, min_score_series_perc=240 * 100 / 360.0,
min_score_special_ep=180 * 100 / 360.0):
"""
Get score range for a video.
:param video: `Video` instance
:param media_type: movie/series
:param min_score_movie_perc: Percentage of max score for min score of movies
:param min_score_series_perc: Percentage of max score for min score of series
:param min_score_special_ep: Percentage of max score for min score of series special episode
:return: tuple(min_score, max_score, set(scores))
"""
max_score = 120.0
min_score = max_score * min_score_movie_perc / 100.0
2019-09-13 19:12:26 +00:00
scores = list(subliminal_scores.movie_scores.keys())
if media_type == "series":
max_score = 360.0
min_score = max_score * min_score_series_perc / 100.0
2019-09-13 19:12:26 +00:00
scores = list(subliminal_scores.episode_scores.keys())
if video.is_special:
min_score = max_score * min_score_special_ep / 100.0
2020-06-08 06:35:08 +00:00
return min_score, max_score, set(scores)
2020-06-08 06:35:08 +00:00
def download_subtitle(path, language, audio_language, hi, forced, providers, providers_auth, sceneName, title,
media_type, forced_minimum_score=None, is_upgrade=False):
# fixme: supply all missing languages, not only one, to hit providers only once who support multiple languages in
# one query
2020-06-08 06:35:08 +00:00
if settings.general.getboolean('utf8_encode'):
os.environ["SZ_KEEP_ENCODING"] = ""
else:
2019-08-16 01:29:21 +00:00
os.environ["SZ_KEEP_ENCODING"] = "True"
2020-06-08 06:35:08 +00:00
logging.debug('BAZARR Searching subtitles for this file: ' + path)
if hi == "True":
2019-05-03 17:37:29 +00:00
hi = "force HI"
else:
2019-05-03 17:37:29 +00:00
hi = "force non-HI"
2018-10-09 20:33:18 +00:00
language_set = set()
2020-06-08 06:35:08 +00:00
2019-09-13 19:12:26 +00:00
if not isinstance(language, list):
language = [language]
2020-06-08 06:35:08 +00:00
if forced == "True":
2019-07-28 19:49:19 +00:00
providers_auth['podnapisi']['only_foreign'] = True ## fixme: This is also in get_providers_auth()
providers_auth['subscene']['only_foreign'] = True ## fixme: This is also in get_providers_auth()
providers_auth['opensubtitles']['only_foreign'] = True ## fixme: This is also in get_providers_auth()
else:
providers_auth['podnapisi']['only_foreign'] = False
providers_auth['subscene']['only_foreign'] = False
providers_auth['opensubtitles']['only_foreign'] = False
2020-06-08 06:35:08 +00:00
for l in language:
if l == 'pob':
lang_obj = Language('por', 'BR')
2019-08-16 01:55:21 +00:00
if forced == "True":
lang_obj = Language.rebuild(lang_obj, forced=True)
2020-09-10 18:26:37 +00:00
if hi == "force HI":
lang_obj = Language.rebuild(lang_obj, hi=True)
elif l == 'zht':
lang_obj = Language('zho', 'TW')
if forced == "True":
lang_obj = Language.rebuild(lang_obj, forced=True)
if hi == "force HI":
lang_obj = Language.rebuild(lang_obj, hi=True)
else:
lang_obj = Language(l)
2019-08-16 01:55:21 +00:00
if forced == "True":
lang_obj = Language.rebuild(lang_obj, forced=True)
2020-09-10 18:26:37 +00:00
if hi == "force HI":
lang_obj = Language.rebuild(lang_obj, hi=True)
language_set.add(lang_obj)
2020-06-08 06:35:08 +00:00
2018-12-15 00:36:28 +00:00
minimum_score = settings.general.minimum_score
minimum_score_movie = settings.general.minimum_score_movie
use_postprocessing = settings.general.getboolean('use_postprocessing')
2018-12-15 00:36:28 +00:00
postprocessing_cmd = settings.general.postprocessing_cmd
single = settings.general.getboolean('single_language')
2020-06-08 06:35:08 +00:00
# todo:
"""
AsyncProviderPool:
implement:
blacklist=None,
pre_download_hook=None,
post_download_hook=None,
language_hook=None
"""
2020-02-25 21:14:15 +00:00
video = get_video(force_unicode(path), title, sceneName, providers=providers,
2019-07-28 19:49:19 +00:00
media_type=media_type)
if video:
min_score, max_score, scores = get_scores(video, media_type, min_score_movie_perc=int(minimum_score_movie),
min_score_series_perc=int(minimum_score))
2020-06-08 06:35:08 +00:00
if providers:
2019-03-16 19:30:06 +00:00
if forced_minimum_score:
min_score = int(forced_minimum_score) + 1
downloaded_subtitles = download_best_subtitles({video}, language_set, int(min_score), hi,
providers=providers,
provider_configs=providers_auth,
pool_class=provider_pool(),
compute_score=compute_score,
throttle_time=None, # fixme
2020-07-19 20:02:38 +00:00
blacklist=get_blacklist(media_type=media_type),
throttle_callback=provider_throttle,
pre_download_hook=None, # fixme
post_download_hook=None, # fixme
language_hook=None) # fixme
else:
downloaded_subtitles = None
logging.info("BAZARR All providers are throttled")
2019-07-28 19:49:19 +00:00
return None
2020-06-08 06:35:08 +00:00
2020-07-29 13:11:45 +00:00
subz_mods = settings.general.subzero_mods.strip().split(',') if settings.general.subzero_mods.strip() else None
saved_any = False
if downloaded_subtitles:
2020-02-13 04:16:22 +00:00
for video, subtitles in downloaded_subtitles.items():
if not subtitles:
continue
2020-06-08 06:35:08 +00:00
2020-07-29 13:11:45 +00:00
for s in subtitles:
s.mods = subz_mods
try:
fld = get_target_folder(path)
2019-06-11 18:45:48 +00:00
chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
'win') and settings.general.getboolean('chmod_enabled') else None
saved_subtitles = save_subtitles(video.original_path, subtitles, single=single,
tags=None, # fixme
directory=fld,
2019-02-27 20:55:06 +00:00
chmod=chmod,
# formats=("srt", "vtt")
2019-09-28 18:05:34 +00:00
path_decoder=force_unicode
)
except Exception as e:
2020-06-08 06:35:08 +00:00
logging.exception(
'BAZARR Error saving Subtitles file to disk for this file:' + path + ': ' + repr(e))
pass
else:
saved_any = True
for subtitle in saved_subtitles:
downloaded_provider = subtitle.provider_name
2019-03-20 00:16:19 +00:00
if subtitle.language == 'pt-BR':
downloaded_language_code3 = 'pob'
elif subtitle.language == 'zh-TW':
downloaded_language_code3 = 'zht'
2019-03-20 00:16:19 +00:00
else:
2019-03-20 03:44:50 +00:00
downloaded_language_code3 = subtitle.language.alpha3
2019-03-20 00:16:19 +00:00
downloaded_language = language_from_alpha3(downloaded_language_code3)
downloaded_language_code2 = alpha2_from_alpha3(downloaded_language_code3)
audio_language_code2 = alpha2_from_language(audio_language)
audio_language_code3 = alpha3_from_language(audio_language)
downloaded_path = subtitle.storage_path
subtitle_id = subtitle.id
2020-09-10 18:26:37 +00:00
if subtitle.language.hi:
modifier_string = " HI"
elif subtitle.language.forced:
modifier_string = " forced"
else:
modifier_string = ""
logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
2019-03-20 10:33:11 +00:00
if is_upgrade:
action = "upgraded"
else:
action = "downloaded"
percent_score = round(subtitle.score * 100 / max_score, 2)
2020-09-10 18:26:37 +00:00
message = downloaded_language + modifier_string + " subtitles " + action + " from " + \
downloaded_provider + " with a score of " + str(percent_score) + "%."
if media_type == 'series':
episode_metadata = database.execute("SELECT sonarrSeriesId, sonarrEpisodeId FROM "
"table_episodes WHERE path = ?",
(path_mappings.path_replace_reverse(path),),
only_one=True)
series_id = episode_metadata['sonarrSeriesId']
episode_id = episode_metadata['sonarrEpisodeId']
sync_subtitles(video_path=path, srt_path=downloaded_path,
srt_lang=downloaded_language_code3, media_type=media_type,
percent_score=percent_score,
sonarr_series_id=episode_metadata['sonarrSeriesId'],
sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
else:
movie_metadata = database.execute("SELECT radarrId FROM table_movies WHERE path = ?",
(path_mappings.path_replace_reverse_movie(path),),
only_one=True)
series_id = ""
episode_id = movie_metadata['radarrId']
sync_subtitles(video_path=path, srt_path=downloaded_path,
srt_lang=downloaded_language_code3, media_type=media_type,
percent_score=percent_score,
radarr_id=movie_metadata['radarrId'])
if use_postprocessing is True:
command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language,
downloaded_language_code2, downloaded_language_code3, audio_language,
2020-06-17 13:50:14 +00:00
audio_language_code2, audio_language_code3, subtitle.language.forced,
percent_score, subtitle_id, downloaded_provider, series_id, episode_id)
2020-05-15 18:12:31 +00:00
if media_type == 'series':
use_pp_threshold = settings.general.getboolean('use_postprocessing_threshold')
2020-05-23 10:10:32 +00:00
pp_threshold = int(settings.general.postprocessing_threshold)
2020-05-15 18:12:31 +00:00
else:
use_pp_threshold = settings.general.getboolean('use_postprocessing_threshold_movie')
2020-05-23 10:10:32 +00:00
pp_threshold = int(settings.general.postprocessing_threshold_movie)
2020-05-15 18:12:31 +00:00
if not use_pp_threshold or (use_pp_threshold and percent_score < pp_threshold):
logging.debug("BAZARR Using post-processing command: {}".format(command))
2020-06-08 06:35:08 +00:00
postprocessing(command, path)
2020-05-15 18:12:31 +00:00
else:
logging.debug("BAZARR post-processing skipped because subtitles score isn't below this "
2020-06-08 06:35:08 +00:00
"threshold value: " + str(pp_threshold) + "%")
# fixme: support multiple languages at once
if media_type == 'series':
2020-05-19 13:27:13 +00:00
reversed_path = path_mappings.path_replace_reverse(path)
2020-07-19 20:02:38 +00:00
reversed_subtitles_path = path_mappings.path_replace_reverse(downloaded_path)
notify_sonarr(episode_metadata['sonarrSeriesId'])
2020-07-19 20:02:38 +00:00
else:
2020-05-19 13:27:13 +00:00
reversed_path = path_mappings.path_replace_reverse_movie(path)
2020-07-19 20:02:38 +00:00
reversed_subtitles_path = path_mappings.path_replace_reverse_movie(downloaded_path)
notify_radarr(movie_metadata['radarrId'])
track_event(category=downloaded_provider, action=action, label=downloaded_language)
return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, \
2020-09-10 18:26:37 +00:00
subtitle.language.forced, subtitle.id, reversed_subtitles_path, subtitle.language.hi
2020-06-08 06:35:08 +00:00
if not saved_any:
2019-09-17 13:51:40 +00:00
logging.debug('BAZARR No Subtitles were found for this file: ' + path)
return None
2020-06-08 06:35:08 +00:00
subliminal.region.backend.sync()
2020-06-08 06:35:08 +00:00
2019-09-17 13:51:40 +00:00
logging.debug('BAZARR Ended searching Subtitles for file: ' + path)
2017-10-16 23:27:19 +00:00
def manual_search(path, profileId, providers, providers_auth, sceneName, title, media_type):
logging.debug('BAZARR Manually searching subtitles for this file: ' + path)
2020-06-08 06:35:08 +00:00
final_subtitles = []
initial_language_set = set()
language_set = set()
2020-06-08 06:35:08 +00:00
# where [3] is items list of dict(id, lang, forced, hi)
language_items = ast.literal_eval(get_profiles_list(profile_id=int(profileId))['items'])
for language in language_items:
lang_id, lang, forced, hi, audio_exclude = language.values()
2020-06-08 06:35:08 +00:00
2018-10-12 03:44:34 +00:00
lang = alpha3_from_alpha2(lang)
2020-09-10 18:26:37 +00:00
2018-10-12 03:44:34 +00:00
if lang == 'pob':
lang_obj = Language('por', 'BR')
elif lang == 'zht':
lang_obj = Language('zho', 'TW')
else:
lang_obj = Language(lang)
2020-09-10 18:26:37 +00:00
if forced == "True":
lang_obj = Language.rebuild(lang_obj, forced=True)
2020-06-08 06:35:08 +00:00
providers_auth['podnapisi']['also_foreign'] = True
providers_auth['opensubtitles']['also_foreign'] = True
if hi == "True":
lang_obj = Language.rebuild(lang_obj, hi=True)
initial_language_set.add(lang_obj)
language_set = initial_language_set.copy()
for language in language_set.copy():
lang_obj_for_hi = language
if not language.forced and not language.hi:
lang_obj_hi = Language.rebuild(lang_obj_for_hi, hi=True)
elif not language.forced and language.hi:
lang_obj_hi = Language.rebuild(lang_obj_for_hi, hi=False)
else:
continue
language_set.add(lang_obj_hi)
2020-09-10 18:26:37 +00:00
minimum_score = settings.general.minimum_score
minimum_score_movie = settings.general.minimum_score_movie
use_postprocessing = settings.general.getboolean('use_postprocessing')
2018-12-15 00:36:28 +00:00
postprocessing_cmd = settings.general.postprocessing_cmd
2019-07-28 19:49:19 +00:00
if providers:
2020-02-25 21:14:15 +00:00
video = get_video(force_unicode(path), title, sceneName, providers=providers,
2019-07-28 19:49:19 +00:00
media_type=media_type)
else:
logging.info("BAZARR All providers are throttled")
return None
if video:
min_score, max_score, scores = get_scores(video, media_type, min_score_movie_perc=int(minimum_score_movie),
min_score_series_perc=int(minimum_score))
2020-06-08 06:35:08 +00:00
try:
if providers:
subtitles = list_all_subtitles([video], language_set,
providers=providers,
provider_configs=providers_auth,
2020-07-19 20:02:38 +00:00
blacklist=get_blacklist(media_type=media_type),
throttle_callback=provider_throttle,
language_hook=None) # fixme
if 'subscene' in providers:
subscene_language_set = set()
for language in language_set:
if language.forced:
subscene_language_set.add(language)
if len(subscene_language_set):
providers_auth['subscene']['only_foreign'] = True
subtitles_subscene = list_all_subtitles([video], subscene_language_set,
providers=['subscene'],
provider_configs=providers_auth,
blacklist=get_blacklist(media_type=media_type),
throttle_callback=provider_throttle,
language_hook=None) # fixme
providers_auth['subscene']['only_foreign'] = False
subtitles[video] += subtitles_subscene[video]
else:
subtitles = []
logging.info("BAZARR All providers are throttled")
2019-07-28 19:49:19 +00:00
return None
except Exception as e:
2019-09-17 13:51:40 +00:00
logging.exception("BAZARR Error trying to get Subtitle list from provider for this file: " + path)
else:
subtitles_list = []
2020-06-08 06:35:08 +00:00
for s in subtitles[video]:
try:
matches = s.get_matches(video)
except AttributeError:
continue
2020-06-08 06:35:08 +00:00
# skip wrong season/episodes
if media_type == "series":
can_verify_series = True
if not s.hash_verifiable and "hash" in matches:
can_verify_series = False
2020-06-08 06:35:08 +00:00
if can_verify_series and not {"series", "season", "episode"}.issubset(matches):
logging.debug(u"BAZARR Skipping %s, because it doesn't match our series/episode", s)
continue
initial_hi_match = False
for language in initial_language_set:
if s.language.basename == language.basename and \
s.language.forced == language.forced and \
s.language.hi == language.hi:
initial_hi = language.hi
initial_hi_match = True
break
if not initial_hi_match:
initial_hi = None
if initial_hi_match:
matches.add('hearing_impaired')
score, score_without_hash = compute_score(matches, s, video, hearing_impaired=initial_hi)
if 'hash' not in matches:
not_matched = scores - matches
else:
not_matched = set()
s.score = score
if s.hearing_impaired == initial_hi:
matches.add('hearing_impaired')
else:
not_matched.add('hearing_impaired')
releases = []
if hasattr(s, 'release_info'):
if s.release_info is not None:
for s_item in s.release_info.split(','):
if s_item.strip():
releases.append(s_item)
2020-06-08 06:35:08 +00:00
if len(releases) == 0:
releases = ['n/a']
if s.uploader and s.uploader.strip():
s_uploader = s.uploader.strip()
else:
s_uploader = 'n/a'
subtitles_list.append(
dict(score=round((score / max_score * 100), 2),
orig_score=score,
2020-09-10 18:26:37 +00:00
score_without_hash=score_without_hash, forced=str(s.language.forced),
language=str(s.language.basename), hearing_impaired=str(s.hearing_impaired),
provider=s.provider_name,
subtitle=codecs.encode(pickle.dumps(s.make_picklable()), "base64").decode(),
url=s.page_link, matches=list(matches), dont_matches=list(not_matched),
release_info=releases, uploader=s_uploader))
2020-06-08 06:35:08 +00:00
final_subtitles = sorted(subtitles_list, key=lambda x: (x['orig_score'], x['score_without_hash']),
reverse=True)
2019-09-17 13:51:40 +00:00
logging.debug('BAZARR ' + str(len(final_subtitles)) + " Subtitles have been found for this file: " + path)
logging.debug('BAZARR Ended searching Subtitles for this file: ' + path)
2020-06-08 06:35:08 +00:00
subliminal.region.backend.sync()
2020-06-08 06:35:08 +00:00
return final_subtitles
2020-06-08 06:35:08 +00:00
def manual_download_subtitle(path, language, audio_language, hi, forced, subtitle, provider, providers_auth, sceneName,
title, media_type):
2019-09-17 13:51:40 +00:00
logging.debug('BAZARR Manually downloading Subtitles for this file: ' + path)
2020-06-08 06:35:08 +00:00
if settings.general.getboolean('utf8_encode'):
os.environ["SZ_KEEP_ENCODING"] = ""
else:
2019-08-16 02:01:42 +00:00
os.environ["SZ_KEEP_ENCODING"] = "True"
2020-06-08 06:35:08 +00:00
subtitle = pickle.loads(codecs.decode(subtitle.encode(), "base64"))
2020-07-29 13:11:45 +00:00
subtitle.mods = settings.general.subzero_mods.strip().split(',') if settings.general.subzero_mods.strip() else None
use_postprocessing = settings.general.getboolean('use_postprocessing')
2018-12-15 00:36:28 +00:00
postprocessing_cmd = settings.general.postprocessing_cmd
single = settings.general.getboolean('single_language')
2020-02-25 21:14:15 +00:00
video = get_video(force_unicode(path), title, sceneName, providers={provider},
2019-07-28 19:49:19 +00:00
media_type=media_type)
if video:
min_score, max_score, scores = get_scores(video, media_type)
try:
if provider:
2020-07-19 20:02:38 +00:00
download_subtitles([subtitle],
providers={provider},
provider_configs=providers_auth,
pool_class=provider_pool(),
blacklist=get_blacklist(media_type=media_type),
throttle_callback=provider_throttle)
logging.debug('BAZARR Subtitles file downloaded for this file:' + path)
else:
logging.info("BAZARR All providers are throttled")
return None
except Exception as e:
2019-09-17 13:51:40 +00:00
logging.exception('BAZARR Error downloading Subtitles for this file ' + path)
return None
else:
if not subtitle.is_valid():
2019-09-17 13:51:40 +00:00
logging.exception('BAZARR No valid Subtitles file found for this file: ' + path)
return
try:
score = round(subtitle.score / max_score * 100, 2)
fld = get_target_folder(path)
2019-06-11 18:45:48 +00:00
chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
'win') and settings.general.getboolean('chmod_enabled') else None
saved_subtitles = save_subtitles(video.original_path, [subtitle], single=single,
tags=None, # fixme
directory=fld,
chmod=chmod,
# formats=("srt", "vtt")
2019-09-28 18:05:34 +00:00
path_decoder=force_unicode)
2020-06-08 06:35:08 +00:00
except Exception as e:
2019-09-17 13:51:40 +00:00
logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
return
else:
if saved_subtitles:
for saved_subtitle in saved_subtitles:
downloaded_provider = saved_subtitle.provider_name
2019-03-20 00:16:19 +00:00
if saved_subtitle.language == 'pt-BR':
downloaded_language_code3 = 'pob'
elif saved_subtitle.language == 'zh-TW':
downloaded_language_code3 = 'zht'
2019-03-20 00:16:19 +00:00
else:
2019-03-20 03:44:50 +00:00
downloaded_language_code3 = subtitle.language.alpha3
2019-03-20 00:16:19 +00:00
downloaded_language = language_from_alpha3(downloaded_language_code3)
downloaded_language_code2 = alpha2_from_alpha3(downloaded_language_code3)
audio_language_code2 = alpha2_from_language(audio_language)
audio_language_code3 = alpha3_from_language(audio_language)
downloaded_path = saved_subtitle.storage_path
subtitle_id = subtitle.id
logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
2020-09-10 18:26:37 +00:00
if subtitle.language.hi:
modifier_string = " HI"
elif subtitle.language.forced:
modifier_string = " forced"
else:
modifier_string = ""
message = downloaded_language + modifier_string + " subtitles downloaded from " + \
downloaded_provider + " with a score of " + str(score) + "% using manual search."
if media_type == 'series':
episode_metadata = database.execute("SELECT sonarrSeriesId, sonarrEpisodeId FROM "
"table_episodes WHERE path = ?",
(path_mappings.path_replace_reverse(path),),
only_one=True)
series_id = episode_metadata['sonarrSeriesId']
episode_id = episode_metadata['sonarrEpisodeId']
sync_subtitles(video_path=path, srt_path=downloaded_path,
srt_lang=downloaded_language_code3, media_type=media_type,
percent_score=score,
sonarr_series_id=episode_metadata['sonarrSeriesId'],
sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
else:
movie_metadata = database.execute("SELECT radarrId FROM table_movies WHERE path = ?",
(path_mappings.path_replace_reverse_movie(path),),
only_one=True)
series_id = ""
episode_id = movie_metadata['radarrId']
sync_subtitles(video_path=path, srt_path=downloaded_path,
srt_lang=downloaded_language_code3, media_type=media_type,
percent_score=score, radarr_id=movie_metadata['radarrId'])
2020-06-08 06:35:08 +00:00
if use_postprocessing:
2020-06-07 12:00:42 +00:00
percent_score = round(subtitle.score * 100 / max_score, 2)
command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language,
downloaded_language_code2, downloaded_language_code3, audio_language,
2020-06-08 06:35:08 +00:00
audio_language_code2, audio_language_code3, subtitle.language.forced,
percent_score, subtitle_id, downloaded_provider, series_id, episode_id)
2020-05-15 18:12:31 +00:00
if media_type == 'series':
use_pp_threshold = settings.general.getboolean('use_postprocessing_threshold')
pp_threshold = settings.general.postprocessing_threshold
else:
use_pp_threshold = settings.general.getboolean('use_postprocessing_threshold_movie')
pp_threshold = settings.general.postprocessing_threshold_movie
if not use_pp_threshold or (use_pp_threshold and score < float(pp_threshold)):
2020-06-08 06:35:08 +00:00
logging.debug("BAZARR Using post-processing command: {}".format(command))
2020-05-15 18:12:31 +00:00
postprocessing(command, path)
else:
logging.debug("BAZARR post-processing skipped because subtitles score isn't below this "
2020-06-08 06:35:08 +00:00
"threshold value: " + pp_threshold + "%")
if media_type == 'series':
2020-05-19 13:27:13 +00:00
reversed_path = path_mappings.path_replace_reverse(path)
2020-07-19 20:02:38 +00:00
reversed_subtitles_path = path_mappings.path_replace_reverse(downloaded_path)
notify_sonarr(episode_metadata['sonarrSeriesId'])
else:
2020-05-19 13:27:13 +00:00
reversed_path = path_mappings.path_replace_reverse_movie(path)
2020-07-19 20:02:38 +00:00
reversed_subtitles_path = path_mappings.path_replace_reverse_movie(downloaded_path)
notify_radarr(movie_metadata['radarrId'])
2020-06-08 06:35:08 +00:00
track_event(category=downloaded_provider, action="manually_downloaded",
label=downloaded_language)
return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, \
2020-09-10 18:26:37 +00:00
subtitle.language.forced, subtitle.id, reversed_subtitles_path, subtitle.language.hi
2018-10-12 02:24:27 +00:00
else:
logging.error(
2019-09-17 13:51:40 +00:00
"BAZARR Tried to manually download a Subtitles for file: " + path + " but we weren't able to do (probably throttled by " + str(
subtitle.provider_name) + ". Please retry later or select a Subtitles from another provider.")
2018-10-12 02:24:27 +00:00
return None
2020-06-08 06:35:08 +00:00
subliminal.region.backend.sync()
2020-06-08 06:35:08 +00:00
2019-09-17 13:51:40 +00:00
logging.debug('BAZARR Ended manually downloading Subtitles for file: ' + path)
2020-04-23 18:12:13 +00:00
def manual_upload_subtitle(path, language, forced, title, scene_name, media_type, subtitle, audio_language):
logging.debug('BAZARR Manually uploading subtitles for this file: ' + path)
single = settings.general.getboolean('single_language')
2020-04-23 18:12:13 +00:00
use_postprocessing = settings.general.getboolean('use_postprocessing')
postprocessing_cmd = settings.general.postprocessing_cmd
chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
'win') and settings.general.getboolean('chmod_enabled') else None
language = alpha3_from_alpha2(language)
if language == 'pob':
lang_obj = Language('por', 'BR')
elif language == 'zht':
lang_obj = Language('zho', 'TW')
else:
lang_obj = Language(language)
if forced:
lang_obj = Language.rebuild(lang_obj, forced=True)
sub = Subtitle(
lang_obj,
mods=settings.general.subzero_mods.strip().split(',') if settings.general.subzero_mods.strip() else None
)
sub.content = subtitle.read()
if not sub.is_valid():
logging.exception('BAZARR Invalid subtitle file: ' + subtitle.filename)
sub.mods = None
2020-03-25 20:25:37 +00:00
if settings.general.getboolean('utf8_encode'):
sub.set_encoding("utf-8")
saved_subtitles = []
try:
saved_subtitles = save_subtitles(path,
[sub],
single=single,
tags=None, # fixme
directory=get_target_folder(path),
chmod=chmod,
# formats=("srt", "vtt")
path_decoder=force_unicode)
except:
pass
if len(saved_subtitles) < 1:
logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
return
subtitle_path = saved_subtitles[0].storage_path
2019-09-17 13:51:40 +00:00
message = language_from_alpha3(language) + (" forced" if forced else "") + " Subtitles manually uploaded."
2020-06-08 06:35:08 +00:00
uploaded_language_code3 = language
2020-04-23 18:12:13 +00:00
uploaded_language = language_from_alpha3(uploaded_language_code3)
uploaded_language_code2 = alpha2_from_alpha3(uploaded_language_code3)
audio_language_code2 = alpha2_from_language(audio_language)
audio_language_code3 = alpha3_from_language(audio_language)
if media_type == 'series':
episode_metadata = database.execute("SELECT sonarrSeriesId, sonarrEpisodeId FROM table_episodes WHERE path = ?",
(path_mappings.path_replace_reverse(path),),
only_one=True)
series_id = episode_metadata['sonarrSeriesId']
episode_id = episode_metadata['sonarrEpisodeId']
sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code3, media_type=media_type,
percent_score=100, sonarr_series_id=episode_metadata['sonarrSeriesId'],
sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
else:
movie_metadata = database.execute("SELECT radarrId FROM table_movies WHERE path = ?",
(path_mappings.path_replace_reverse_movie(path),),
only_one=True)
series_id = ""
episode_id = movie_metadata['radarrId']
sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code3, media_type=media_type,
percent_score=100, radarr_id=movie_metadata['radarrId'])
2020-04-23 18:12:13 +00:00
if use_postprocessing :
2020-04-23 18:12:13 +00:00
command = pp_replace(postprocessing_cmd, path, subtitle_path, uploaded_language,
2020-05-15 18:12:31 +00:00
uploaded_language_code2, uploaded_language_code3, audio_language,
audio_language_code2, audio_language_code3, forced, 100, "1", "manual", series_id, episode_id)
2020-04-23 18:12:13 +00:00
postprocessing(command, path)
if media_type == 'series':
2020-05-19 13:27:13 +00:00
reversed_path = path_mappings.path_replace_reverse(path)
2020-07-19 20:02:38 +00:00
reversed_subtitles_path = path_mappings.path_replace_reverse(subtitle_path)
notify_sonarr(episode_metadata['sonarrSeriesId'])
else:
2020-05-19 13:27:13 +00:00
reversed_path = path_mappings.path_replace_reverse_movie(path)
2020-07-19 20:02:38 +00:00
reversed_subtitles_path = path_mappings.path_replace_reverse_movie(subtitle_path)
notify_radarr(movie_metadata['radarrId'])
2020-07-19 20:02:38 +00:00
return message, reversed_path, reversed_subtitles_path
2017-10-16 23:27:19 +00:00
def series_download_subtitles(no):
episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, monitored, "
"table_episodes.sonarrEpisodeId, table_episodes.scene_name, table_shows.tags, "
"table_shows.seriesType, table_episodes.audio_language, table_shows.title "
"FROM table_episodes INNER JOIN table_shows on table_shows.sonarrSeriesId = "
"table_episodes.sonarrSeriesId WHERE table_episodes.sonarrSeriesId=? and "
"missing_subtitles!='[]'" + get_exclusion_clause('series'), (no,))
2019-10-31 10:40:45 +00:00
if not episodes_details:
logging.debug("BAZARR no episode for that sonarrSeriesId can be found in database:", str(no))
return
2019-10-25 02:35:04 +00:00
2018-09-22 22:07:46 +00:00
providers_list = get_providers()
providers_auth = get_providers_auth()
2020-06-08 06:35:08 +00:00
2019-10-25 02:35:04 +00:00
count_episodes_details = len(episodes_details)
2020-06-08 06:35:08 +00:00
2019-04-04 22:33:49 +00:00
for i, episode in enumerate(episodes_details, 1):
2019-07-28 19:49:19 +00:00
if providers_list:
2019-10-25 02:35:04 +00:00
for language in ast.literal_eval(episode['missing_subtitles']):
2019-07-28 19:49:19 +00:00
if language is not None:
audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
2020-05-19 13:27:13 +00:00
result = download_subtitle(path_mappings.path_replace(episode['path']),
2019-10-28 00:45:15 +00:00
str(alpha3_from_alpha2(language.split(':')[0])),
audio_language,
"True" if language.endswith(':hi') else "False",
2020-09-10 18:26:37 +00:00
"True" if language.endswith(':forced') else "False",
2019-08-16 01:07:40 +00:00
providers_list,
providers_auth,
2019-10-25 02:35:04 +00:00
str(episode['scene_name']),
episode['title'],
2019-07-28 19:49:19 +00:00
'series')
if result is not None:
message = result[0]
path = result[1]
forced = result[5]
2020-09-10 18:26:37 +00:00
if result[8]:
language_code = result[2] + ":hi"
elif forced:
language_code = result[2] + ":forced"
else:
language_code = result[2]
2019-07-28 19:49:19 +00:00
provider = result[3]
score = result[4]
subs_id = result[6]
2020-07-19 20:02:38 +00:00
subs_path = result[7]
2020-05-19 13:27:13 +00:00
store_subtitles(episode['path'], path_mappings.path_replace(episode['path']))
history_log(1, no, episode['sonarrEpisodeId'], message, path, language_code, provider, score,
2020-07-19 20:02:38 +00:00
subs_id, subs_path)
2019-10-25 02:35:04 +00:00
send_notifications(no, episode['sonarrEpisodeId'], message)
2019-07-28 19:49:19 +00:00
else:
logging.info("BAZARR All providers are throttled")
break
2018-04-24 14:48:52 +00:00
def episode_download_subtitles(no):
episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, monitored, "
"table_episodes.sonarrEpisodeId, table_episodes.scene_name, table_shows.tags, "
"table_shows.title, table_shows.sonarrSeriesId, table_episodes.audio_language, "
"table_shows.seriesType FROM table_episodes LEFT JOIN table_shows on "
"table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId WHERE sonarrEpisodeId=?" +
get_exclusion_clause('series'), (no,))
2019-10-31 10:40:45 +00:00
if not episodes_details:
logging.debug("BAZARR no episode with that sonarrEpisodeId can be found in database:", str(no))
return
2020-06-08 06:35:08 +00:00
providers_list = get_providers()
providers_auth = get_providers_auth()
2020-06-08 06:35:08 +00:00
for episode in episodes_details:
2019-07-28 19:49:19 +00:00
if providers_list:
2019-10-25 02:35:04 +00:00
for language in ast.literal_eval(episode['missing_subtitles']):
2019-07-28 19:49:19 +00:00
if language is not None:
audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
2020-05-19 13:27:13 +00:00
result = download_subtitle(path_mappings.path_replace(episode['path']),
2019-08-15 20:36:53 +00:00
str(alpha3_from_alpha2(language.split(':')[0])),
audio_language,
"True" if language.endswith(':hi') else "False",
2020-09-10 18:26:37 +00:00
"True" if language.endswith(':forced') else "False",
2019-08-15 20:36:53 +00:00
providers_list,
providers_auth,
2019-10-25 02:35:04 +00:00
str(episode['scene_name']),
episode['title'],
2019-08-15 20:36:53 +00:00
'series')
2019-07-28 19:49:19 +00:00
if result is not None:
message = result[0]
path = result[1]
forced = result[5]
2020-09-10 18:26:37 +00:00
if result[8]:
language_code = result[2] + ":hi"
elif forced:
language_code = result[2] + ":forced"
else:
language_code = result[2]
2019-07-28 19:49:19 +00:00
provider = result[3]
score = result[4]
subs_id = result[6]
2020-07-19 20:02:38 +00:00
subs_path = result[7]
2020-05-19 13:27:13 +00:00
store_subtitles(episode['path'], path_mappings.path_replace(episode['path']))
2020-06-08 06:35:08 +00:00
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
2020-07-19 20:02:38 +00:00
language_code, provider, score, subs_id, subs_path)
2019-10-25 02:35:04 +00:00
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
2019-07-28 19:49:19 +00:00
else:
logging.info("BAZARR All providers are throttled")
break
2018-04-24 14:48:52 +00:00
def movies_download_subtitles(no):
movies = database.execute(
"SELECT path, missing_subtitles, audio_language, radarrId, sceneName, title, tags, "
"monitored FROM table_movies WHERE radarrId=?" + get_exclusion_clause('movie'), (no,))
if not len(movies):
2019-10-31 10:40:45 +00:00
logging.debug("BAZARR no movie with that radarrId can be found in database:", str(no))
return
else:
movie = movies[0]
2020-06-08 06:35:08 +00:00
2018-09-22 22:07:46 +00:00
providers_list = get_providers()
providers_auth = get_providers_auth()
2019-10-28 00:45:15 +00:00
if ast.literal_eval(movie['missing_subtitles']):
count_movie = len(ast.literal_eval(movie['missing_subtitles']))
else:
count_movie = 0
2020-06-08 06:35:08 +00:00
2019-10-25 02:35:04 +00:00
for i, language in enumerate(ast.literal_eval(movie['missing_subtitles']), 1):
2019-07-28 19:49:19 +00:00
if providers_list:
if language is not None:
audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
2020-05-19 13:27:13 +00:00
result = download_subtitle(path_mappings.path_replace_movie(movie['path']),
2019-08-15 20:36:53 +00:00
str(alpha3_from_alpha2(language.split(':')[0])),
audio_language,
"True" if language.endswith(':hi') else "False",
2020-09-10 18:26:37 +00:00
"True" if language.endswith(':forced') else "False",
2019-08-15 20:36:53 +00:00
providers_list,
providers_auth,
2019-10-25 02:35:04 +00:00
str(movie['sceneName']),
movie['title'],
2019-08-15 20:36:53 +00:00
'movie')
2019-07-28 19:49:19 +00:00
if result is not None:
message = result[0]
path = result[1]
forced = result[5]
2020-09-10 18:26:37 +00:00
if result[8]:
language_code = result[2] + ":hi"
elif forced:
language_code = result[2] + ":forced"
else:
language_code = result[2]
2019-07-28 19:49:19 +00:00
provider = result[3]
score = result[4]
subs_id = result[6]
2020-07-19 20:02:38 +00:00
subs_path = result[7]
2020-05-19 13:27:13 +00:00
store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']))
2020-07-19 20:02:38 +00:00
history_log_movie(1, no, message, path, language_code, provider, score, subs_id, subs_path)
2019-07-28 19:49:19 +00:00
send_notifications_movie(no, message)
else:
logging.info("BAZARR All providers are throttled")
break
2018-04-24 14:48:52 +00:00
2019-04-04 22:33:49 +00:00
def wanted_download_subtitles(path, l, count_episodes):
2019-10-25 02:35:04 +00:00
episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, "
"table_episodes.sonarrEpisodeId, table_episodes.sonarrSeriesId, "
"table_episodes.audio_language, table_episodes.scene_name,"
"table_episodes.failedAttempts, table_shows.title "
2019-10-25 02:35:04 +00:00
"FROM table_episodes LEFT JOIN table_shows on "
"table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId "
"WHERE table_episodes.path=? and table_episodes.missing_subtitles!='[]'",
2020-05-19 13:27:13 +00:00
(path_mappings.path_replace_reverse(path),))
2020-06-08 06:35:08 +00:00
2018-09-22 22:07:46 +00:00
providers_list = get_providers()
providers_auth = get_providers_auth()
2020-06-08 06:35:08 +00:00
2017-11-16 19:09:40 +00:00
for episode in episodes_details:
2019-10-28 00:45:15 +00:00
attempt = episode['failedAttempts']
2020-02-13 04:16:22 +00:00
if type(attempt) == str:
attempt = ast.literal_eval(attempt)
2019-10-25 02:35:04 +00:00
for language in ast.literal_eval(episode['missing_subtitles']):
if attempt is None:
attempt = []
attempt.append([language, time.time()])
else:
2019-09-28 04:22:17 +00:00
att = list(zip(*attempt))[0]
if language not in att:
attempt.append([language, time.time()])
2019-08-17 14:24:55 +00:00
2019-10-25 02:35:04 +00:00
database.execute("UPDATE table_episodes SET failedAttempts=? WHERE sonarrEpisodeId=?",
2020-02-13 04:16:22 +00:00
(str(attempt), episode['sonarrEpisodeId']))
2020-06-08 06:35:08 +00:00
for i in range(len(attempt)):
if attempt[i][0] == language:
if search_active(attempt[i][1]):
audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
2020-05-19 13:27:13 +00:00
result = download_subtitle(path_mappings.path_replace(episode['path']),
2019-08-15 20:36:53 +00:00
str(alpha3_from_alpha2(language.split(':')[0])),
audio_language,
"True" if language.endswith(':hi') else "False",
2020-09-10 18:26:37 +00:00
"True" if language.endswith(':forced') else "False",
2019-08-15 20:36:53 +00:00
providers_list,
providers_auth,
2019-10-25 02:35:04 +00:00
str(episode['scene_name']),
episode['title'],
2019-08-15 20:36:53 +00:00
'series')
if result is not None:
message = result[0]
path = result[1]
2019-05-02 00:26:48 +00:00
forced = result[5]
2020-09-10 18:26:37 +00:00
if result[8]:
language_code = result[2] + ":hi"
elif forced:
language_code = result[2] + ":forced"
else:
language_code = result[2]
provider = result[3]
score = result[4]
2020-07-19 20:02:38 +00:00
subs_id = result[6]
subs_path = result[7]
2020-05-19 13:27:13 +00:00
store_subtitles(episode['path'], path_mappings.path_replace(episode['path']))
2020-06-08 06:35:08 +00:00
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
2020-07-19 20:02:38 +00:00
language_code, provider, score, subs_id, subs_path)
2019-10-28 00:45:15 +00:00
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
else:
logging.debug(
2020-06-08 06:35:08 +00:00
'BAZARR Search is not active for episode ' + episode['path'] + ' Language: ' + attempt[i][
0])
2017-11-16 17:04:20 +00:00
2019-04-04 22:33:49 +00:00
def wanted_download_subtitles_movie(path, l, count_movies):
2020-06-08 06:35:08 +00:00
movies_details = database.execute(
"SELECT path, missing_subtitles, radarrId, audio_language, sceneName, "
"failedAttempts, title FROM table_movies WHERE path = ? "
2020-06-08 06:35:08 +00:00
"AND missing_subtitles != '[]'", (path_mappings.path_replace_reverse_movie(path),))
2018-09-22 22:07:46 +00:00
providers_list = get_providers()
providers_auth = get_providers_auth()
2020-06-08 06:35:08 +00:00
for movie in movies_details:
2019-10-28 00:45:15 +00:00
attempt = movie['failedAttempts']
2020-02-13 04:16:22 +00:00
if type(attempt) == str:
attempt = ast.literal_eval(attempt)
2019-10-25 02:35:04 +00:00
for language in ast.literal_eval(movie['missing_subtitles']):
if attempt is None:
attempt = []
attempt.append([language, time.time()])
else:
2019-09-28 04:22:17 +00:00
att = list(zip(*attempt))[0]
if language not in att:
attempt.append([language, time.time()])
2020-06-08 06:35:08 +00:00
2019-10-25 02:35:04 +00:00
database.execute("UPDATE table_movies SET failedAttempts=? WHERE radarrId=?",
2020-02-13 04:16:22 +00:00
(str(attempt), movie['radarrId']))
2020-06-08 06:35:08 +00:00
for i in range(len(attempt)):
if attempt[i][0] == language:
if search_active(attempt[i][1]) is True:
audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
2020-05-19 13:27:13 +00:00
result = download_subtitle(path_mappings.path_replace_movie(movie['path']),
2019-08-15 20:36:53 +00:00
str(alpha3_from_alpha2(language.split(':')[0])),
audio_language,
"True" if language.endswith(':hi') else "False",
2020-09-10 18:26:37 +00:00
"True" if language.endswith(':forced') else "False",
2019-08-15 20:36:53 +00:00
providers_list,
providers_auth,
2019-10-25 02:35:04 +00:00
str(movie['sceneName']),
movie['title'],
2019-08-15 20:36:53 +00:00
'movie')
if result is not None:
message = result[0]
path = result[1]
2019-05-02 00:26:48 +00:00
forced = result[5]
2020-09-10 18:26:37 +00:00
if result[8]:
language_code = result[2] + ":hi"
elif forced:
language_code = result[2] + ":forced"
else:
language_code = result[2]
provider = result[3]
score = result[4]
subs_id = result[6]
2020-07-19 20:02:38 +00:00
subs_path = result[7]
2020-05-19 13:27:13 +00:00
store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']))
history_log_movie(1, movie['radarrId'], message, path, language_code, provider, score,
2020-07-19 20:02:38 +00:00
subs_id, subs_path)
2019-10-25 02:35:04 +00:00
send_notifications_movie(movie['radarrId'], message)
else:
logging.info(
2020-06-08 06:35:08 +00:00
'BAZARR Search is not active for this Movie ' + movie['path'] + ' Language: ' + attempt[i][
0])
2020-02-13 04:16:22 +00:00
def wanted_search_missing_subtitles_series():
episodes = database.execute("SELECT table_episodes.path, table_shows.tags, table_episodes.monitored, "
"table_shows.seriesType FROM table_episodes INNER JOIN table_shows on "
"table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId WHERE missing_subtitles != "
"'[]'" + get_exclusion_clause('series'))
2020-05-19 15:39:57 +00:00
# path_replace
dict_mapper.path_replace(episodes)
2019-08-17 14:24:55 +00:00
2020-02-13 04:16:22 +00:00
count_episodes = len(episodes)
for i, episode in enumerate(episodes, 1):
providers = get_providers()
if providers:
wanted_download_subtitles(episode['path'], i, count_episodes)
2019-10-25 02:35:04 +00:00
else:
2020-02-13 04:16:22 +00:00
logging.info("BAZARR All providers are throttled")
return
2020-06-08 06:35:08 +00:00
2020-02-13 04:16:22 +00:00
logging.info('BAZARR Finished searching for missing Series Subtitles. Check History for more information.')
2019-10-25 02:35:04 +00:00
2020-02-13 04:16:22 +00:00
def wanted_search_missing_subtitles_movies():
movies = database.execute("SELECT path, tags, monitored FROM table_movies WHERE missing_subtitles != '[]'" +
get_exclusion_clause('movie'))
2020-05-19 15:39:57 +00:00
# path_replace
dict_mapper.path_replace_movie(movies)
2020-02-13 04:16:22 +00:00
count_movies = len(movies)
for i, movie in enumerate(movies, 1):
providers = get_providers()
if providers:
wanted_download_subtitles_movie(movie['path'], i, count_movies)
else:
logging.info("BAZARR All providers are throttled")
return
logging.info('BAZARR Finished searching for missing Movies Subtitles. Check History for more information.')
def search_active(timestamp):
2019-01-06 17:15:43 +00:00
if settings.general.getboolean('adaptive_searching'):
search_deadline = timedelta(weeks=3)
search_delta = timedelta(weeks=1)
aa = datetime.fromtimestamp(float(timestamp))
attempt_datetime = datetime.strptime(str(aa).split(".")[0], '%Y-%m-%d %H:%M:%S')
attempt_search_deadline = attempt_datetime + search_deadline
today = datetime.today()
attempt_age_in_days = (today.date() - attempt_search_deadline.date()).days
if today.date() <= attempt_search_deadline.date():
return True
elif attempt_age_in_days % search_delta.days == 0:
return True
else:
return False
else:
return True
def convert_to_guessit(guessit_key, attr_from_db):
try:
return guessit(attr_from_db)[guessit_key]
except KeyError:
return attr_from_db
def refine_from_db(path, video):
if isinstance(video, Episode):
2020-06-08 06:35:08 +00:00
data = database.execute(
"SELECT table_shows.title as seriesTitle, table_episodes.season, table_episodes.episode, "
"table_episodes.title as episodeTitle, table_shows.year, table_shows.tvdbId, "
"table_shows.alternateTitles, table_episodes.format, table_episodes.resolution, "
2020-09-28 12:22:00 +00:00
"table_episodes.video_codec, table_episodes.audio_codec, table_episodes.path, table_shows.imdbId "
2020-06-08 06:35:08 +00:00
"FROM table_episodes INNER JOIN table_shows on "
"table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId "
"WHERE table_episodes.path = ?", (path_mappings.path_replace_reverse(path),), only_one=True)
2019-08-17 14:24:55 +00:00
2019-02-08 03:34:54 +00:00
if data:
video.series = re.sub(r'\s(\(\d\d\d\d\))', '', data['seriesTitle'])
2019-10-25 02:35:04 +00:00
video.season = int(data['season'])
video.episode = int(data['episode'])
video.title = data['episodeTitle']
2020-09-15 13:06:07 +00:00
# Commented out because Sonarr provided so much bad year
# if data['year']:
# if int(data['year']) > 0: video.year = int(data['year'])
2019-10-26 18:52:22 +00:00
video.series_tvdb_id = int(data['tvdbId'])
video.alternative_series = ast.literal_eval(data['alternateTitles'])
2020-09-28 12:22:00 +00:00
if data['imdbId'] and not video.series_imdb_id:
video.series_imdb_id = data['imdbId']
2020-05-20 15:29:39 +00:00
if not video.source:
video.source = convert_to_guessit('source', str(data['format']))
2019-02-06 03:49:58 +00:00
if not video.resolution:
2019-10-25 02:35:04 +00:00
video.resolution = str(data['resolution'])
2019-02-06 03:49:58 +00:00
if not video.video_codec:
if data['video_codec']: video.video_codec = convert_to_guessit('video_codec', data['video_codec'])
2019-02-06 03:49:58 +00:00
if not video.audio_codec:
if data['audio_codec']: video.audio_codec = convert_to_guessit('audio_codec', data['audio_codec'])
elif isinstance(video, Movie):
2019-10-25 02:35:04 +00:00
data = database.execute("SELECT title, year, alternativeTitles, format, resolution, video_codec, audio_codec, "
2019-10-27 01:16:59 +00:00
"imdbId FROM table_movies WHERE path = ?",
2020-05-19 13:27:13 +00:00
(path_mappings.path_replace_reverse_movie(path),), only_one=True)
2019-08-17 14:24:55 +00:00
2019-02-08 03:34:54 +00:00
if data:
video.title = re.sub(r'\s(\(\d\d\d\d\))', '', data['title'])
2020-09-15 13:06:07 +00:00
# Commented out because Radarr provided so much bad year
# if data['year']:
# if int(data['year']) > 0: video.year = int(data['year'])
2020-09-29 14:35:00 +00:00
if data['imdbId'] and not video.imdb_id:
video.imdb_id = data['imdbId']
2019-10-27 03:17:14 +00:00
video.alternative_titles = ast.literal_eval(data['alternativeTitles'])
2020-05-20 15:29:39 +00:00
if not video.source:
if data['format']: video.source = convert_to_guessit('source', data['format'])
2019-02-06 03:49:58 +00:00
if not video.resolution:
2019-10-25 02:35:04 +00:00
if data['resolution']: video.resolution = data['resolution']
2019-02-06 03:49:58 +00:00
if not video.video_codec:
if data['video_codec']: video.video_codec = convert_to_guessit('video_codec', data['video_codec'])
2019-02-06 03:49:58 +00:00
if not video.audio_codec:
if data['audio_codec']: video.audio_codec = convert_to_guessit('audio_codec', data['audio_codec'])
2020-06-08 06:35:08 +00:00
return video
def refine_from_ffprobe(path, video):
exe = get_binary('ffprobe')
if not exe:
logging.debug('BAZARR FFprobe not found!')
return
else:
logging.debug('BAZARR FFprobe used is %s', exe)
2020-06-08 06:35:08 +00:00
2020-03-18 19:33:54 +00:00
api.initialize({'provider': 'ffmpeg', 'ffmpeg': exe})
data = api.know(path)
logging.debug('FFprobe found: %s', data)
2020-03-18 19:33:54 +00:00
if 'video' not in data:
logging.debug('BAZARR FFprobe was unable to find video tracks in the file!')
else:
2020-03-18 19:33:54 +00:00
if 'resolution' in data['video'][0]:
if not video.resolution:
2020-03-18 19:33:54 +00:00
video.resolution = data['video'][0]['resolution']
if 'codec' in data['video'][0]:
if not video.video_codec:
2020-03-18 19:33:54 +00:00
video.video_codec = data['video'][0]['codec']
if 'frame_rate' in data['video'][0]:
2019-08-26 12:21:36 +00:00
if not video.fps:
if isinstance(data['video'][0]['frame_rate'], float):
video.fps = data['video'][0]['frame_rate']
else:
video.fps = data['video'][0]['frame_rate'].magnitude
2020-03-18 19:33:54 +00:00
if 'audio' not in data:
logging.debug('BAZARR FFprobe was unable to find audio tracks in the file!')
else:
2020-03-18 19:33:54 +00:00
if 'codec' in data['audio'][0]:
if not video.audio_codec:
2020-03-18 19:33:54 +00:00
video.audio_codec = data['audio'][0]['codec']
for track in data['audio']:
if 'language' in track:
video.audio_languages.add(track['language'].alpha3)
return video
def upgrade_subtitles():
days_to_upgrade_subs = settings.general.days_to_upgrade_subs
2019-03-17 14:29:38 +00:00
minimum_timestamp = ((datetime.now() - timedelta(days=int(days_to_upgrade_subs))) -
datetime(1970, 1, 1)).total_seconds()
2019-08-30 00:16:11 +00:00
2019-10-25 02:35:04 +00:00
if settings.general.getboolean('upgrade_manual'):
query_actions = [1, 2, 3, 6]
2019-10-25 02:35:04 +00:00
else:
query_actions = [1, 3]
2019-08-30 00:16:11 +00:00
if settings.general.getboolean('use_sonarr'):
2019-10-25 02:35:04 +00:00
upgradable_episodes = database.execute("SELECT table_history.video_path, table_history.language, "
"table_history.score, table_shows.tags, table_shows.profileId, "
"table_episodes.audio_language, table_episodes.scene_name, "
"table_episodes.title, table_episodes.sonarrSeriesId, "
"table_history.subtitles_path, table_episodes.sonarrEpisodeId, "
"MAX(table_history.timestamp) as timestamp, table_episodes.monitored, "
"table_shows.seriesType FROM table_history INNER JOIN table_shows on "
"table_shows.sonarrSeriesId = table_history.sonarrSeriesId INNER JOIN "
"table_episodes on table_episodes.sonarrEpisodeId = "
"table_history.sonarrEpisodeId WHERE action IN "
"(" + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND "
"score is not null" + get_exclusion_clause('series') + " GROUP BY "
"table_history.video_path, table_history.language",
2019-10-25 02:35:04 +00:00
(minimum_timestamp,))
2019-08-19 22:13:29 +00:00
upgradable_episodes_not_perfect = []
2019-10-25 02:35:04 +00:00
for upgradable_episode in upgradable_episodes:
2019-08-19 22:13:29 +00:00
if upgradable_episode['timestamp'] > minimum_timestamp:
try:
int(upgradable_episode['score'])
except ValueError:
pass
else:
if int(upgradable_episode['score']) < 360:
upgradable_episodes_not_perfect.append(upgradable_episode)
episodes_to_upgrade = []
for episode in upgradable_episodes_not_perfect:
if os.path.exists(path_mappings.path_replace(episode['subtitles_path'])) and int(episode['score']) < 357:
episodes_to_upgrade.append(episode)
2019-10-07 23:36:20 +00:00
count_episode_to_upgrade = len(episodes_to_upgrade)
if settings.general.getboolean('use_radarr'):
2019-10-25 02:35:04 +00:00
upgradable_movies = database.execute("SELECT table_history_movie.video_path, table_history_movie.language, "
"table_history_movie.score, table_movies.profileId, "
"table_history_movie.subtitles_path, table_movies.audio_language, "
"table_movies.sceneName, table_movies.title, table_movies.radarrId, "
"MAX(table_history_movie.timestamp) as timestamp, table_movies.tags, "
"table_movies.monitored FROM table_history_movie INNER JOIN table_movies "
"on table_movies.radarrId = table_history_movie.radarrId WHERE action IN "
"(" + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND score "
"is not null" + get_exclusion_clause('movie') + " GROUP BY "
"table_history_movie.video_path, table_history_movie.language",
(minimum_timestamp,))
2019-08-19 22:13:29 +00:00
upgradable_movies_not_perfect = []
2019-10-25 02:35:04 +00:00
for upgradable_movie in upgradable_movies:
2019-08-19 22:13:29 +00:00
if upgradable_movie['timestamp'] > minimum_timestamp:
try:
int(upgradable_movie['score'])
except ValueError:
pass
else:
2020-02-01 00:18:51 +00:00
if int(upgradable_movie['score']) < 120:
2019-08-19 22:13:29 +00:00
upgradable_movies_not_perfect.append(upgradable_movie)
movies_to_upgrade = []
for movie in upgradable_movies_not_perfect:
if os.path.exists(path_mappings.path_replace_movie(movie['subtitles_path'])) and int(movie['score']) < 117:
movies_to_upgrade.append(movie)
2019-10-07 23:36:20 +00:00
count_movie_to_upgrade = len(movies_to_upgrade)
2020-06-08 06:35:08 +00:00
2019-03-16 19:30:06 +00:00
providers_list = get_providers()
providers_auth = get_providers_auth()
2019-10-07 23:36:20 +00:00
if settings.general.getboolean('use_sonarr'):
for i, episode in enumerate(episodes_to_upgrade, 1):
2019-07-28 19:49:19 +00:00
providers = get_providers()
if not providers:
logging.info("BAZARR All providers are throttled")
return
if episode['language'].endswith('forced'):
language = episode['language'].split(':')[0]
is_forced = True
is_hi = False
elif episode['language'].endswith('hi'):
language = episode['language'].split(':')[0]
is_forced = False
is_hi = True
else:
language = episode['language'].split(':')[0]
is_forced = False
is_hi = False
2020-06-08 06:35:08 +00:00
audio_language_list = get_audio_profile_languages(episode_id=episode['sonarrEpisodeId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
result = download_subtitle(path_mappings.path_replace(episode['video_path']),
str(alpha3_from_alpha2(language)),
audio_language,
is_hi,
is_forced,
providers_list,
providers_auth,
str(episode['scene_name']),
episode['title'],
'series',
forced_minimum_score=int(episode['score']),
is_upgrade=True)
if result is not None:
message = result[0]
path = result[1]
forced = result[5]
if result[8]:
language_code = result[2] + ":hi"
elif forced:
language_code = result[2] + ":forced"
else:
language_code = result[2]
provider = result[3]
score = result[4]
subs_id = result[6]
subs_path = result[7]
store_subtitles(episode['video_path'], path_mappings.path_replace(episode['video_path']))
history_log(3, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
language_code, provider, score, subs_id, subs_path)
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
2020-06-08 06:35:08 +00:00
if settings.general.getboolean('use_radarr'):
for i, movie in enumerate(movies_to_upgrade, 1):
2019-07-28 19:49:19 +00:00
providers = get_providers()
if not providers:
logging.info("BAZARR All providers are throttled")
return
if not providers:
logging.info("BAZARR All providers are throttled")
return
2021-01-31 03:34:40 +00:00
if movie['language'].endswith('forced'):
language = movie['language'].split(':')[0]
is_forced = True
is_hi = False
2021-01-31 03:34:40 +00:00
elif movie['language'].endswith('hi'):
language = movie['language'].split(':')[0]
is_forced = False
is_hi = True
else:
2021-01-31 03:34:40 +00:00
language = movie['language'].split(':')[0]
is_forced = False
is_hi = False
2020-06-08 06:35:08 +00:00
audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId'])
if len(audio_language_list) > 0:
audio_language = audio_language_list[0]['name']
else:
audio_language = 'None'
result = download_subtitle(path_mappings.path_replace_movie(movie['video_path']),
str(alpha3_from_alpha2(language)),
audio_language,
is_hi,
is_forced,
providers_list,
providers_auth,
str(movie['sceneName']),
movie['title'],
'movie',
forced_minimum_score=int(movie['score']),
is_upgrade=True)
if result is not None:
message = result[0]
path = result[1]
forced = result[5]
language_code = result[2] + ":forced" if forced else result[2]
provider = result[3]
score = result[4]
subs_id = result[6]
subs_path = result[7]
store_subtitles_movie(movie['video_path'],
path_mappings.path_replace_movie(movie['video_path']))
history_log_movie(3, movie['radarrId'], message, path, language_code, provider, score, subs_id, subs_path)
send_notifications_movie(movie['radarrId'], message)
2020-01-06 22:11:01 +00:00
2021-02-01 11:39:47 +00:00
logging.info('BAZARR Finished searching for Subtitles to upgrade. Check History for more information.')
2020-01-06 22:11:01 +00:00
def postprocessing(command, path):
try:
encoding = getpreferredencoding()
if os.name == 'nt':
2020-01-29 11:53:29 +00:00
codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding=getpreferredencoding())
2020-01-06 22:11:01 +00:00
# wait for the process to terminate
out_codepage, err_codepage = codepage.communicate()
encoding = out_codepage.split(':')[-1].strip()
2020-01-29 11:53:29 +00:00
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding=encoding)
2020-01-06 22:11:01 +00:00
# wait for the process to terminate
out, err = process.communicate()
out = out.replace('\n', ' ').replace('\r', ' ')
except Exception as e:
logging.error('BAZARR Post-processing failed for file ' + path + ' : ' + repr(e))
else:
if out == "":
logging.info(
'BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
else:
logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)
def sync_subtitles(video_path, srt_path, srt_lang, media_type, percent_score, sonarr_series_id=None,
sonarr_episode_id=None, radarr_id=None):
if settings.subsync.getboolean('use_subsync'):
if media_type == 'series':
use_subsync_threshold = settings.subsync.getboolean('use_subsync_threshold')
subsync_threshold = settings.subsync.subsync_threshold
else:
use_subsync_threshold = settings.subsync.getboolean('use_subsync_movie_threshold')
subsync_threshold = settings.subsync.subsync_movie_threshold
if not use_subsync_threshold or (use_subsync_threshold and percent_score < float(subsync_threshold)):
subsync.sync(video_path=video_path, srt_path=srt_path, srt_lang=srt_lang, media_type=media_type,
sonarr_series_id=sonarr_series_id, sonarr_episode_id=sonarr_episode_id, radarr_id=radarr_id)
return True
else:
logging.debug("BAZARR subsync skipped because subtitles score isn't below this "
"threshold value: " + subsync_threshold + "%")
return False