mirror of https://github.com/morpheus65535/bazarr
Merge branch 'development' into subsync
# Conflicts: # bazarr/get_subtitle.py
This commit is contained in:
commit
d9a9c26d7e
|
@ -55,7 +55,7 @@ def get_video(path, title, sceneName, providers=None, media_type="movie"):
|
|||
path = os.path.join(os.path.dirname(path), sceneName + os.path.splitext(path)[1])
|
||||
used_scene_name = True
|
||||
hash_from = original_path
|
||||
|
||||
|
||||
try:
|
||||
video = parse_video(path, hints=hints, providers=providers, dry_run=used_scene_name,
|
||||
hash_from=hash_from)
|
||||
|
@ -65,10 +65,10 @@ def get_video(path, title, sceneName, providers=None, media_type="movie"):
|
|||
|
||||
refine_from_db(original_path, video)
|
||||
refine_from_ffprobe(original_path, video)
|
||||
|
||||
|
||||
logging.debug('BAZARR is using these video object properties: %s', vars(video))
|
||||
return video
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.exception("BAZARR Error trying to get video information for this file: " + path)
|
||||
|
||||
|
@ -93,30 +93,30 @@ def get_scores(video, media_type, min_score_movie_perc=60 * 100 / 120.0, min_sco
|
|||
scores = list(subliminal_scores.episode_scores.keys())
|
||||
if video.is_special:
|
||||
min_score = max_score * min_score_special_ep / 100.0
|
||||
|
||||
|
||||
return min_score, max_score, set(scores)
|
||||
|
||||
|
||||
def download_subtitle(path, language, audio_language, hi, forced, providers, providers_auth, sceneName, title, media_type,
|
||||
forced_minimum_score=None, is_upgrade=False):
|
||||
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
|
||||
|
||||
|
||||
if settings.general.getboolean('utf8_encode'):
|
||||
os.environ["SZ_KEEP_ENCODING"] = ""
|
||||
else:
|
||||
os.environ["SZ_KEEP_ENCODING"] = "True"
|
||||
|
||||
|
||||
logging.debug('BAZARR Searching subtitles for this file: ' + path)
|
||||
if hi == "True":
|
||||
hi = "force HI"
|
||||
else:
|
||||
hi = "force non-HI"
|
||||
language_set = set()
|
||||
|
||||
|
||||
if not isinstance(language, list):
|
||||
language = [language]
|
||||
|
||||
|
||||
if forced == "True":
|
||||
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()
|
||||
|
@ -125,7 +125,7 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
providers_auth['podnapisi']['only_foreign'] = False
|
||||
providers_auth['subscene']['only_foreign'] = False
|
||||
providers_auth['opensubtitles']['only_foreign'] = False
|
||||
|
||||
|
||||
for l in language:
|
||||
if l == 'pob':
|
||||
lang_obj = Language('por', 'BR')
|
||||
|
@ -136,13 +136,13 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
if forced == "True":
|
||||
lang_obj = Language.rebuild(lang_obj, forced=True)
|
||||
language_set.add(lang_obj)
|
||||
|
||||
|
||||
minimum_score = settings.general.minimum_score
|
||||
minimum_score_movie = settings.general.minimum_score_movie
|
||||
use_postprocessing = settings.general.getboolean('use_postprocessing')
|
||||
postprocessing_cmd = settings.general.postprocessing_cmd
|
||||
single = settings.general.getboolean('single_language')
|
||||
|
||||
|
||||
# todo:
|
||||
"""
|
||||
AsyncProviderPool:
|
||||
|
@ -157,7 +157,7 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
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))
|
||||
|
||||
|
||||
if providers:
|
||||
if forced_minimum_score:
|
||||
min_score = int(forced_minimum_score) + 1
|
||||
|
@ -176,13 +176,13 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
downloaded_subtitles = None
|
||||
logging.info("BAZARR All providers are throttled")
|
||||
return None
|
||||
|
||||
|
||||
saved_any = False
|
||||
if downloaded_subtitles:
|
||||
for video, subtitles in downloaded_subtitles.items():
|
||||
if not subtitles:
|
||||
continue
|
||||
|
||||
|
||||
try:
|
||||
fld = get_target_folder(path)
|
||||
chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
|
||||
|
@ -195,7 +195,8 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
path_decoder=force_unicode
|
||||
)
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path + ': ' + repr(e))
|
||||
logging.exception(
|
||||
'BAZARR Error saving Subtitles file to disk for this file:' + path + ': ' + repr(e))
|
||||
pass
|
||||
else:
|
||||
saved_any = True
|
||||
|
@ -252,12 +253,12 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
pp_threshold = int(settings.general.postprocessing_threshold_movie)
|
||||
|
||||
if not use_pp_threshold or (use_pp_threshold and percent_score < pp_threshold):
|
||||
postprocessing(command, path)
|
||||
logging.debug("BAZARR Using post-processing command: {}".format(command))
|
||||
postprocessing(command, path)
|
||||
else:
|
||||
logging.debug("BAZARR post-processing skipped because subtitles score isn't below this "
|
||||
"threshold value: " + str(pp_threshold) + "%")
|
||||
|
||||
"threshold value: " + str(pp_threshold) + "%")
|
||||
|
||||
# fixme: support multiple languages at once
|
||||
if media_type == 'series':
|
||||
reversed_path = path_mappings.path_replace_reverse(path)
|
||||
|
@ -267,19 +268,19 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
|
|||
track_event(category=downloaded_provider, action=action, label=downloaded_language)
|
||||
|
||||
return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, subtitle.language.forced
|
||||
|
||||
|
||||
if not saved_any:
|
||||
logging.debug('BAZARR No Subtitles were found for this file: ' + path)
|
||||
return None
|
||||
|
||||
|
||||
subliminal.region.backend.sync()
|
||||
|
||||
|
||||
logging.debug('BAZARR Ended searching Subtitles for file: ' + path)
|
||||
|
||||
|
||||
def manual_search(path, language, hi, forced, providers, providers_auth, sceneName, title, media_type):
|
||||
logging.debug('BAZARR Manually searching subtitles for this file: ' + path)
|
||||
|
||||
|
||||
final_subtitles = []
|
||||
|
||||
initial_hi = True if hi == "True" else False
|
||||
|
@ -288,7 +289,7 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
else:
|
||||
hi = "force non-HI"
|
||||
language_set = set()
|
||||
|
||||
|
||||
if forced == "True":
|
||||
providers_auth['podnapisi']['only_foreign'] = True
|
||||
providers_auth['subscene']['only_foreign'] = True
|
||||
|
@ -297,7 +298,7 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
providers_auth['podnapisi']['only_foreign'] = False
|
||||
providers_auth['subscene']['only_foreign'] = False
|
||||
providers_auth['opensubtitles']['only_foreign'] = False
|
||||
|
||||
|
||||
for lang in ast.literal_eval(language):
|
||||
lang = alpha3_from_alpha2(lang)
|
||||
if lang == 'pob':
|
||||
|
@ -309,7 +310,7 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
if forced == "True":
|
||||
lang_obj = Language.rebuild(lang_obj, forced=True)
|
||||
language_set.add(lang_obj)
|
||||
|
||||
|
||||
minimum_score = settings.general.minimum_score
|
||||
minimum_score_movie = settings.general.minimum_score_movie
|
||||
use_postprocessing = settings.general.getboolean('use_postprocessing')
|
||||
|
@ -323,7 +324,7 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
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))
|
||||
|
||||
|
||||
try:
|
||||
if providers:
|
||||
subtitles = list_all_subtitles([video], language_set,
|
||||
|
@ -339,19 +340,19 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
logging.exception("BAZARR Error trying to get Subtitle list from provider for this file: " + path)
|
||||
else:
|
||||
subtitles_list = []
|
||||
|
||||
|
||||
for s in subtitles[video]:
|
||||
try:
|
||||
matches = s.get_matches(video)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
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
|
||||
|
@ -369,7 +370,7 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
for s_item in s.release_info.split(','):
|
||||
if s_item.strip():
|
||||
releases.append(s_item)
|
||||
|
||||
|
||||
if len(releases) == 0:
|
||||
releases = ['n/a']
|
||||
|
||||
|
@ -387,26 +388,26 @@ def manual_search(path, language, hi, forced, providers, providers_auth, sceneNa
|
|||
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))
|
||||
|
||||
|
||||
final_subtitles = sorted(subtitles_list, key=lambda x: (x['orig_score'], x['score_without_hash']),
|
||||
reverse=True)
|
||||
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)
|
||||
|
||||
|
||||
subliminal.region.backend.sync()
|
||||
|
||||
|
||||
return final_subtitles
|
||||
|
||||
|
||||
def manual_download_subtitle(path, language, audio_language, hi, forced, subtitle, provider, providers_auth, sceneName, title,
|
||||
media_type):
|
||||
def manual_download_subtitle(path, language, audio_language, hi, forced, subtitle, provider, providers_auth, sceneName,
|
||||
title, media_type):
|
||||
logging.debug('BAZARR Manually downloading Subtitles for this file: ' + path)
|
||||
|
||||
|
||||
if settings.general.getboolean('utf8_encode'):
|
||||
os.environ["SZ_KEEP_ENCODING"] = ""
|
||||
else:
|
||||
os.environ["SZ_KEEP_ENCODING"] = "True"
|
||||
|
||||
|
||||
subtitle = pickle.loads(codecs.decode(subtitle.encode(), "base64"))
|
||||
use_postprocessing = settings.general.getboolean('use_postprocessing')
|
||||
postprocessing_cmd = settings.general.postprocessing_cmd
|
||||
|
@ -441,7 +442,7 @@ def manual_download_subtitle(path, language, audio_language, hi, forced, subtitl
|
|||
chmod=chmod,
|
||||
# formats=("srt", "vtt")
|
||||
path_decoder=force_unicode)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
|
||||
return
|
||||
|
@ -481,10 +482,12 @@ def manual_download_subtitle(path, language, audio_language, hi, forced, subtitl
|
|||
srt_lang=downloaded_language_code3, media_type=media_type,
|
||||
percent_score=score, radarr_id=movie_metadata['radarrId'])
|
||||
|
||||
if use_postprocessing is True:
|
||||
if use_postprocessing:
|
||||
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,
|
||||
audio_language_code2, audio_language_code3, subtitle.language.forced)
|
||||
audio_language_code2, audio_language_code3, subtitle.language.forced,
|
||||
percent_score)
|
||||
|
||||
if media_type == 'series':
|
||||
use_pp_threshold = settings.general.getboolean('use_postprocessing_threshold')
|
||||
|
@ -494,27 +497,29 @@ def manual_download_subtitle(path, language, audio_language, hi, forced, subtitl
|
|||
pp_threshold = settings.general.postprocessing_threshold_movie
|
||||
|
||||
if not use_pp_threshold or (use_pp_threshold and score < float(pp_threshold)):
|
||||
logging.debug("BAZARR Using post-processing command: {}".format(command))
|
||||
postprocessing(command, path)
|
||||
else:
|
||||
logging.debug("BAZARR post-processing skipped because subtitles score isn't below this "
|
||||
"threshold value: " + pp_threshold + "%")
|
||||
|
||||
"threshold value: " + pp_threshold + "%")
|
||||
|
||||
if media_type == 'series':
|
||||
reversed_path = path_mappings.path_replace_reverse(path)
|
||||
else:
|
||||
reversed_path = path_mappings.path_replace_reverse_movie(path)
|
||||
|
||||
track_event(category=downloaded_provider, action="manually_downloaded", label=downloaded_language)
|
||||
|
||||
track_event(category=downloaded_provider, action="manually_downloaded",
|
||||
label=downloaded_language)
|
||||
|
||||
return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, subtitle.language.forced
|
||||
else:
|
||||
logging.error(
|
||||
"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.")
|
||||
return None
|
||||
|
||||
|
||||
subliminal.region.backend.sync()
|
||||
|
||||
|
||||
logging.debug('BAZARR Ended manually downloading Subtitles for file: ' + path)
|
||||
|
||||
|
||||
|
@ -588,8 +593,8 @@ def manual_upload_subtitle(path, language, forced, title, scene_name, media_type
|
|||
os.chmod(subtitle_path, chmod)
|
||||
|
||||
message = language_from_alpha3(language) + (" forced" if forced else "") + " Subtitles manually uploaded."
|
||||
|
||||
uploaded_language_code3 = language
|
||||
|
||||
uploaded_language_code3 = language
|
||||
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)
|
||||
|
@ -609,13 +614,12 @@ def manual_upload_subtitle(path, language, forced, title, scene_name, media_type
|
|||
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'])
|
||||
|
||||
if use_postprocessing is True:
|
||||
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, forced)
|
||||
audio_language_code2, audio_language_code3, forced, 100)
|
||||
postprocessing(command, path)
|
||||
|
||||
|
||||
if media_type == 'series':
|
||||
reversed_path = path_mappings.path_replace_reverse(path)
|
||||
else:
|
||||
|
@ -629,7 +633,7 @@ def series_download_subtitles(no):
|
|||
episodes_details_clause = " AND monitored='True'"
|
||||
else:
|
||||
episodes_details_clause = ''
|
||||
|
||||
|
||||
episodes_details = database.execute("SELECT path, missing_subtitles, sonarrEpisodeId, scene_name "
|
||||
"FROM table_episodes WHERE sonarrSeriesId=? and missing_subtitles!='[]'" +
|
||||
episodes_details_clause, (no,))
|
||||
|
@ -637,17 +641,18 @@ def series_download_subtitles(no):
|
|||
logging.debug("BAZARR no episode for that sonarrSeriesId can be found in database:", str(no))
|
||||
return
|
||||
|
||||
series_details = database.execute("SELECT hearing_impaired, audio_language, title, forced FROM table_shows WHERE sonarrSeriesId=?",
|
||||
(no,), only_one=True)
|
||||
series_details = database.execute(
|
||||
"SELECT hearing_impaired, audio_language, title, forced FROM table_shows WHERE sonarrSeriesId=?",
|
||||
(no,), only_one=True)
|
||||
if not series_details:
|
||||
logging.debug("BAZARR no series with that sonarrSeriesId can be found in database:", str(no))
|
||||
return
|
||||
|
||||
|
||||
providers_list = get_providers()
|
||||
providers_auth = get_providers_auth()
|
||||
|
||||
|
||||
count_episodes_details = len(episodes_details)
|
||||
|
||||
|
||||
for i, episode in enumerate(episodes_details, 1):
|
||||
if providers_list:
|
||||
for language in ast.literal_eval(episode['missing_subtitles']):
|
||||
|
@ -682,7 +687,7 @@ def episode_download_subtitles(no):
|
|||
episodes_details_clause = " AND monitored='True'"
|
||||
else:
|
||||
episodes_details_clause = ''
|
||||
|
||||
|
||||
episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, "
|
||||
"table_episodes.sonarrEpisodeId, table_episodes.scene_name, "
|
||||
"table_shows.hearing_impaired, table_shows.title, table_shows.sonarrSeriesId, "
|
||||
|
@ -693,10 +698,10 @@ def episode_download_subtitles(no):
|
|||
if not episodes_details:
|
||||
logging.debug("BAZARR no episode with that sonarrEpisodeId can be found in database:", str(no))
|
||||
return
|
||||
|
||||
|
||||
providers_list = get_providers()
|
||||
providers_auth = get_providers_auth()
|
||||
|
||||
|
||||
for episode in episodes_details:
|
||||
if providers_list:
|
||||
for language in ast.literal_eval(episode['missing_subtitles']):
|
||||
|
@ -719,7 +724,8 @@ def episode_download_subtitles(no):
|
|||
provider = result[3]
|
||||
score = result[4]
|
||||
store_subtitles(episode['path'], path_mappings.path_replace(episode['path']))
|
||||
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path, language_code, provider, score)
|
||||
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
|
||||
language_code, provider, score)
|
||||
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
|
||||
else:
|
||||
logging.info("BAZARR All providers are throttled")
|
||||
|
@ -732,13 +738,14 @@ def movies_download_subtitles(no):
|
|||
else:
|
||||
movie_details_clause = ''
|
||||
|
||||
movie = database.execute("SELECT path, missing_subtitles, audio_language, radarrId, sceneName, hearing_impaired, title, forced "
|
||||
"FROM table_movies WHERE radarrId=?" + movie_details_clause, (no,), only_one=True)
|
||||
movie = database.execute(
|
||||
"SELECT path, missing_subtitles, audio_language, radarrId, sceneName, hearing_impaired, title, forced "
|
||||
"FROM table_movies WHERE radarrId=?" + movie_details_clause, (no,), only_one=True)
|
||||
|
||||
if not movie:
|
||||
logging.debug("BAZARR no movie with that radarrId can be found in database:", str(no))
|
||||
return
|
||||
|
||||
|
||||
providers_list = get_providers()
|
||||
providers_auth = get_providers_auth()
|
||||
|
||||
|
@ -746,7 +753,7 @@ def movies_download_subtitles(no):
|
|||
count_movie = len(ast.literal_eval(movie['missing_subtitles']))
|
||||
else:
|
||||
count_movie = 0
|
||||
|
||||
|
||||
for i, language in enumerate(ast.literal_eval(movie['missing_subtitles']), 1):
|
||||
if providers_list:
|
||||
if language is not None:
|
||||
|
@ -784,10 +791,10 @@ def wanted_download_subtitles(path, l, count_episodes):
|
|||
"table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId "
|
||||
"WHERE table_episodes.path=? and table_episodes.missing_subtitles!='[]'",
|
||||
(path_mappings.path_replace_reverse(path),))
|
||||
|
||||
|
||||
providers_list = get_providers()
|
||||
providers_auth = get_providers_auth()
|
||||
|
||||
|
||||
for episode in episodes_details:
|
||||
attempt = episode['failedAttempts']
|
||||
if type(attempt) == str:
|
||||
|
@ -803,7 +810,7 @@ def wanted_download_subtitles(path, l, count_episodes):
|
|||
|
||||
database.execute("UPDATE table_episodes SET failedAttempts=? WHERE sonarrEpisodeId=?",
|
||||
(str(attempt), episode['sonarrEpisodeId']))
|
||||
|
||||
|
||||
for i in range(len(attempt)):
|
||||
if attempt[i][0] == language:
|
||||
if search_active(attempt[i][1]):
|
||||
|
@ -825,21 +832,24 @@ def wanted_download_subtitles(path, l, count_episodes):
|
|||
provider = result[3]
|
||||
score = result[4]
|
||||
store_subtitles(episode['path'], path_mappings.path_replace(episode['path']))
|
||||
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path, language_code, provider, score)
|
||||
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
|
||||
language_code, provider, score)
|
||||
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
|
||||
else:
|
||||
logging.debug(
|
||||
'BAZARR Search is not active for episode ' + episode['path'] + ' Language: ' + attempt[i][0])
|
||||
'BAZARR Search is not active for episode ' + episode['path'] + ' Language: ' + attempt[i][
|
||||
0])
|
||||
|
||||
|
||||
def wanted_download_subtitles_movie(path, l, count_movies):
|
||||
movies_details = database.execute("SELECT path, missing_subtitles, radarrId, hearing_impaired, audio_language, sceneName, "
|
||||
"failedAttempts, title, forced FROM table_movies WHERE path = ? "
|
||||
"AND missing_subtitles != '[]'", (path_mappings.path_replace_reverse_movie(path),))
|
||||
|
||||
movies_details = database.execute(
|
||||
"SELECT path, missing_subtitles, radarrId, hearing_impaired, audio_language, sceneName, "
|
||||
"failedAttempts, title, forced FROM table_movies WHERE path = ? "
|
||||
"AND missing_subtitles != '[]'", (path_mappings.path_replace_reverse_movie(path),))
|
||||
|
||||
providers_list = get_providers()
|
||||
providers_auth = get_providers_auth()
|
||||
|
||||
|
||||
for movie in movies_details:
|
||||
attempt = movie['failedAttempts']
|
||||
if type(attempt) == str:
|
||||
|
@ -852,10 +862,10 @@ def wanted_download_subtitles_movie(path, l, count_movies):
|
|||
att = list(zip(*attempt))[0]
|
||||
if language not in att:
|
||||
attempt.append([language, time.time()])
|
||||
|
||||
|
||||
database.execute("UPDATE table_movies SET failedAttempts=? WHERE radarrId=?",
|
||||
(str(attempt), movie['radarrId']))
|
||||
|
||||
|
||||
for i in range(len(attempt)):
|
||||
if attempt[i][0] == language:
|
||||
if search_active(attempt[i][1]) is True:
|
||||
|
@ -881,7 +891,8 @@ def wanted_download_subtitles_movie(path, l, count_movies):
|
|||
send_notifications_movie(movie['radarrId'], message)
|
||||
else:
|
||||
logging.info(
|
||||
'BAZARR Search is not active for this Movie ' + movie['path'] + ' Language: ' + attempt[i][0])
|
||||
'BAZARR Search is not active for this Movie ' + movie['path'] + ' Language: ' + attempt[i][
|
||||
0])
|
||||
|
||||
|
||||
def wanted_search_missing_subtitles_series():
|
||||
|
@ -903,7 +914,7 @@ def wanted_search_missing_subtitles_series():
|
|||
else:
|
||||
logging.info("BAZARR All providers are throttled")
|
||||
return
|
||||
|
||||
|
||||
logging.info('BAZARR Finished searching for missing Series Subtitles. Check History for more information.')
|
||||
|
||||
|
||||
|
@ -951,13 +962,14 @@ def search_active(timestamp):
|
|||
|
||||
def refine_from_db(path, video):
|
||||
if isinstance(video, Episode):
|
||||
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, "
|
||||
"table_episodes.video_codec, table_episodes.audio_codec, table_episodes.path "
|
||||
"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)
|
||||
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, "
|
||||
"table_episodes.video_codec, table_episodes.audio_codec, table_episodes.path "
|
||||
"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)
|
||||
|
||||
if data:
|
||||
video.series = data['seriesTitle']
|
||||
|
@ -995,7 +1007,7 @@ def refine_from_db(path, video):
|
|||
if data['video_codec']: video.video_codec = data['video_codec']
|
||||
if not video.audio_codec:
|
||||
if data['audio_codec']: video.audio_codec = data['audio_codec']
|
||||
|
||||
|
||||
return video
|
||||
|
||||
|
||||
|
@ -1006,7 +1018,7 @@ def refine_from_ffprobe(path, video):
|
|||
return
|
||||
else:
|
||||
logging.debug('BAZARR FFprobe used is %s', exe)
|
||||
|
||||
|
||||
api.initialize({'provider': 'ffmpeg', 'ffmpeg': exe})
|
||||
data = api.know(path)
|
||||
|
||||
|
@ -1073,7 +1085,7 @@ def upgrade_subtitles():
|
|||
"table_episodes on table_episodes.sonarrEpisodeId = "
|
||||
"table_history.sonarrEpisodeId WHERE action IN "
|
||||
"(" + ','.join(map(str, query_actions)) + ") AND timestamp > ? AND "
|
||||
"score is not null" + series_monitored_only_query_string +
|
||||
"score is not null" + series_monitored_only_query_string +
|
||||
" GROUP BY table_history.video_path, table_history.language",
|
||||
(minimum_timestamp,))
|
||||
|
||||
|
@ -1125,7 +1137,7 @@ def upgrade_subtitles():
|
|||
movies_to_upgrade.append(movie)
|
||||
|
||||
count_movie_to_upgrade = len(movies_to_upgrade)
|
||||
|
||||
|
||||
providers_list = get_providers()
|
||||
providers_auth = get_providers_auth()
|
||||
|
||||
|
@ -1145,7 +1157,7 @@ def upgrade_subtitles():
|
|||
forced_languages = [l + ":forced" for l in desired_languages] + desired_languages
|
||||
else:
|
||||
forced_languages = desired_languages
|
||||
|
||||
|
||||
if episode['language'] in forced_languages:
|
||||
if episode['language'].endswith('forced'):
|
||||
language = episode['language'].split(':')[0]
|
||||
|
@ -1153,7 +1165,7 @@ def upgrade_subtitles():
|
|||
else:
|
||||
language = episode['language']
|
||||
is_forced = "False"
|
||||
|
||||
|
||||
result = download_subtitle(path_mappings.path_replace(episode['video_path']),
|
||||
str(alpha3_from_alpha2(language)),
|
||||
episode['audio_language'],
|
||||
|
@ -1174,9 +1186,10 @@ def upgrade_subtitles():
|
|||
provider = result[3]
|
||||
score = result[4]
|
||||
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)
|
||||
history_log(3, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
|
||||
language_code, provider, score)
|
||||
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
|
||||
|
||||
|
||||
if settings.general.getboolean('use_radarr'):
|
||||
for i, movie in enumerate(movies_to_upgrade, 1):
|
||||
if movie['languages'] in [None, 'None', '[]']:
|
||||
|
@ -1193,7 +1206,7 @@ def upgrade_subtitles():
|
|||
forced_languages = [l + ":forced" for l in desired_languages] + desired_languages
|
||||
else:
|
||||
forced_languages = desired_languages
|
||||
|
||||
|
||||
if movie['language'] in forced_languages:
|
||||
if movie['language'].endswith('forced'):
|
||||
language = movie['language'].split(':')[0]
|
||||
|
@ -1201,7 +1214,7 @@ def upgrade_subtitles():
|
|||
else:
|
||||
language = movie['language']
|
||||
is_forced = "False"
|
||||
|
||||
|
||||
result = download_subtitle(path_mappings.path_replace_movie(movie['video_path']),
|
||||
str(alpha3_from_alpha2(language)),
|
||||
movie['audio_language'],
|
||||
|
@ -1221,7 +1234,8 @@ def upgrade_subtitles():
|
|||
language_code = result[2] + ":forced" if forced else result[2]
|
||||
provider = result[3]
|
||||
score = result[4]
|
||||
store_subtitles_movie(movie['video_path'], path_mappings.path_replace_movie(movie['video_path']))
|
||||
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)
|
||||
send_notifications_movie(movie['radarrId'], message)
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class PathMappings:
|
|||
path_mappings = PathMappings()
|
||||
|
||||
|
||||
def pp_replace(pp_command, episode, subtitles, language, language_code2, language_code3, episode_language, episode_language_code2, episode_language_code3, forced):
|
||||
def pp_replace(pp_command, episode, subtitles, language, language_code2, language_code3, episode_language, episode_language_code2, episode_language_code3, forced, score):
|
||||
is_forced = ":forced" if forced else ""
|
||||
is_forced_string = " forced" if forced else ""
|
||||
pp_command = pp_command.replace('{{directory}}', os.path.dirname(episode))
|
||||
|
@ -108,6 +108,7 @@ def pp_replace(pp_command, episode, subtitles, language, language_code2, languag
|
|||
pp_command = pp_command.replace('{{episode_language}}', episode_language)
|
||||
pp_command = pp_command.replace('{{episode_language_code2}}', episode_language_code2)
|
||||
pp_command = pp_command.replace('{{episode_language_code3}}', episode_language_code3)
|
||||
pp_command = pp_command.replace('{{score}}', str(score))
|
||||
return pp_command
|
||||
|
||||
|
||||
|
|
|
@ -364,8 +364,8 @@ def guess_external_subtitles(dest_folder, subtitles):
|
|||
logging.debug("BAZARR falling back to file content analysis to detect language.")
|
||||
detected_language = None
|
||||
|
||||
# to improve performance, skip detection of files larger that 5M
|
||||
if os.path.getsize(subtitle_path) > 5*1024*1024:
|
||||
# to improve performance, skip detection of files larger that 1M
|
||||
if os.path.getsize(subtitle_path) > 1*1024*1024:
|
||||
logging.debug("BAZARR subtitles file is too large to be text based. Skipping this file: " +
|
||||
subtitle_path)
|
||||
continue
|
||||
|
@ -374,16 +374,11 @@ def guess_external_subtitles(dest_folder, subtitles):
|
|||
text = f.read()
|
||||
|
||||
try:
|
||||
# to improve performance, use only the first 32K to detect encoding
|
||||
guess = chardet.detect(text[:32768])
|
||||
guess = chardet.detect(text)
|
||||
logging.debug('BAZARR detected encoding %r', guess)
|
||||
if guess["confidence"] < 0.6:
|
||||
raise UnicodeError
|
||||
if guess["encoding"] == "ascii":
|
||||
guess["encoding"] = "utf-8"
|
||||
text = text.decode(guess["encoding"])
|
||||
detected_language = guess_language(text)
|
||||
except UnicodeError:
|
||||
except (UnicodeDecodeError, TypeError):
|
||||
logging.exception("BAZARR subtitles file doesn't seems to be text based. Skipping this file: " +
|
||||
subtitle_path)
|
||||
except:
|
||||
|
|
|
@ -605,6 +605,11 @@ def _search_external_subtitles(path, languages=None, only_one=False, scandir_gen
|
|||
if not INCLUDE_EXOTIC_SUBS and p_ext not in (".srt", ".ass", ".ssa", ".vtt"):
|
||||
continue
|
||||
|
||||
if p_root.lower() == fn_no_ext_lower:
|
||||
# skip check for language code if the subtitle file name is the same as the video name
|
||||
subtitles[p] = None
|
||||
continue
|
||||
|
||||
# extract potential forced/normal/default tag
|
||||
# fixme: duplicate from subtitlehelpers
|
||||
split_tag = p_root.rsplit('.', 1)
|
||||
|
|
|
@ -139,7 +139,11 @@ class BetaSeriesProvider(Provider):
|
|||
def download_subtitle(self, subtitle):
|
||||
logger.info('Downloading subtitle %r', subtitle)
|
||||
r = self.session.get(subtitle.download_link, timeout=10)
|
||||
r.raise_for_status()
|
||||
if r.status_code == 404:
|
||||
logger.error('Error 404 downloading %r', subtitle)
|
||||
return
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
archive = _get_archive(r.content)
|
||||
if archive:
|
||||
|
@ -153,7 +157,7 @@ class BetaSeriesProvider(Provider):
|
|||
if subtitle_content:
|
||||
subtitle.content = fix_line_ending(subtitle_content)
|
||||
else:
|
||||
logger.debug('Could not extract subtitle from %r', archive)
|
||||
logger.error('Could not extract subtitle from %r', archive)
|
||||
|
||||
|
||||
def _get_archive(content):
|
||||
|
|
|
@ -66,7 +66,6 @@ class TitulkySubtitle(Subtitle):
|
|||
self.version = version
|
||||
self.year = year
|
||||
self.download_link = download_link
|
||||
self.encoding = 'UTF-8'
|
||||
for t in title:
|
||||
self.title = t
|
||||
if year:
|
||||
|
|
|
@ -105,7 +105,7 @@ class Subtitle(Subtitle_):
|
|||
return self
|
||||
|
||||
def get_encoding(self):
|
||||
return self.encoding if self.encoding else self.guess_encoding()
|
||||
return self.guess_encoding()
|
||||
|
||||
def set_encoding(self, encoding):
|
||||
ge = self.get_encoding()
|
||||
|
@ -116,7 +116,6 @@ class Subtitle(Subtitle_):
|
|||
logger.debug("Changing encoding: to %s, from %s", encoding, ge)
|
||||
self.content = unicontent.encode(encoding)
|
||||
self._guessed_encoding = encoding
|
||||
self.encoding = encoding
|
||||
|
||||
def normalize(self):
|
||||
"""
|
||||
|
@ -141,6 +140,16 @@ class Subtitle(Subtitle_):
|
|||
if self._guessed_encoding:
|
||||
return self._guessed_encoding
|
||||
|
||||
if self.encoding:
|
||||
# check provider encoding and use it only if it is valid
|
||||
try:
|
||||
self.content.decode(self.encoding)
|
||||
self._guessed_encoding = self.encoding
|
||||
return self._guessed_encoding
|
||||
except:
|
||||
# provider specified encoding is invalid, fallback to guessing
|
||||
pass
|
||||
|
||||
logger.info('Guessing encoding for language %s', self.language)
|
||||
|
||||
encodings = ['utf-8']
|
||||
|
@ -206,7 +215,7 @@ class Subtitle(Subtitle_):
|
|||
|
||||
else:
|
||||
# Western European (windows-1252) / Northern European
|
||||
encodings.extend(['latin-1', 'iso-8859-15', 'iso-8859-9', 'iso-8859-4', 'iso-8859-1'])
|
||||
encodings.extend(['windows-1252', 'iso-8859-15', 'iso-8859-9', 'iso-8859-4', 'iso-8859-1'])
|
||||
|
||||
# try to decode
|
||||
logger.debug('Trying encodings %r', encodings)
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -38,6 +38,7 @@
|
|||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ url_for('static',filename='plugins/datatables.net-bs4/css/dataTables.bootstrap4.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-select.css') }}"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/bootstrap-slider.min.css') }}"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/jquery.typeahead.min.css') }}"/>
|
||||
|
||||
{% endblock head_css %}
|
||||
|
@ -130,7 +131,7 @@
|
|||
<!-- ============================================================== -->
|
||||
<!-- Search -->
|
||||
<!-- ============================================================== -->
|
||||
<li class="nav-item hidden-sm-down search-box">
|
||||
<li class="nav-item search-box">
|
||||
<form class="form-material">
|
||||
<div class="typeahead__container">
|
||||
<div class="typeahead__field">
|
||||
|
@ -321,6 +322,7 @@
|
|||
<script src="{{ url_for('static',filename='js/custom.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/socket.io.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/bootstrap-select.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/bootstrap-slider.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='moment/moment.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/jquery.typeahead.min.js') }}"></script>
|
||||
|
||||
|
@ -341,6 +343,11 @@
|
|||
$('[data-toggle="tooltip"]').tooltip({html: true});
|
||||
});
|
||||
|
||||
$(".slider").slider({
|
||||
tooltip: 'always',
|
||||
tooltip_position: 'bottom'
|
||||
});
|
||||
|
||||
events = io.connect({
|
||||
path: '{{ settings.general.base_url.rstrip('/') }}/socket.io',
|
||||
transports: ['polling'],
|
||||
|
|
|
@ -112,8 +112,8 @@
|
|||
<div class="col-sm-3 text-right">
|
||||
<b>Minimum Score</b>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<input type="number" min="0" max="100" step="1" onkeydown="return false" class="form-control" id="settings-general-minimum_score_movie" name="settings-general-minimum_score_movie" value="{{settings.general.minimum_score_movie}}">
|
||||
<div class="col-sm-8">
|
||||
<input class="slider" id="settings-general-minimum_score_movie" name="settings-general-minimum_score_movie" data-slider-id='settings-general-minimum_score_movie' type="text" data-slider-min="1" data-slider-max="100" data-slider-step="1" data-slider-value="{{settings.general.minimum_score_movie}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
@ -112,8 +112,8 @@
|
|||
<div class="col-sm-3 text-right">
|
||||
<b>Minimum Score</b>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<input type="number" min="0" max="100" step="1" onkeydown="return false" class="form-control" id="settings-general-minimum_score" name="settings-general-minimum_score" value="{{settings.general.minimum_score}}">
|
||||
<div class="col-sm-8">
|
||||
<input class="slider" id="settings-general-minimum_score" name="settings-general-minimum_score" data-slider-id='settings-general-minimum_score' type="text" data-slider-min="1" data-slider-max="100" data-slider-step="1" data-slider-value="{{settings.general.minimum_score}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
<button class="btn btn-outline" id="save_button">
|
||||
<div>
|
||||
<span class="fa-stack">
|
||||
<i class="fas fa-save fa-stack-2x align-top text-themecolor text-center font-20" aria-hidden="true"></i>
|
||||
<i class="fas fa-save fa-stack-2x align-top text-themecolor text-center font-20"
|
||||
aria-hidden="true"></i>
|
||||
<i id="save_button_checkmark" class="fas fa-check fa-stack-2x" style="color:green;"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -34,21 +35,24 @@
|
|||
<b>Subtitle Folder</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-4">
|
||||
<select class="form-control selectpicker" id="settings-general-subfolder" name="settings-general-subfolder">
|
||||
<select class="form-control selectpicker" id="settings-general-subfolder"
|
||||
name="settings-general-subfolder">
|
||||
<option value="current">Alongside Media File</option>
|
||||
<option value="relative">Relative Path To Media File</option>
|
||||
<option value="absolute">Absolute Path</option>
|
||||
</select>
|
||||
<label for="settings-general-subfolder">Choose the folder you wish to store/read the Subtitles</label>
|
||||
<label for="settings-general-subfolder">Choose the folder you wish to store/read the
|
||||
Subtitles</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="subfolder_div">
|
||||
<div id="subfolder_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>Custom Subtitle Folder</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-general-subfolder_custom" name="settings-general-subfolder_custom" value="{{settings.general.subfolder_custom}}">
|
||||
<input type="text" class="form-control" id="settings-general-subfolder_custom"
|
||||
name="settings-general-subfolder_custom" value="{{ settings.general.subfolder_custom }}">
|
||||
<label for="settings-general-subfolder_custom">Choose your own folder for Subtitles</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -60,7 +64,8 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-upgrade_subs" name="settings-general-upgrade_subs">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-upgrade_subs"
|
||||
name="settings-general-upgrade_subs">
|
||||
<span class="custom-control-label" for="settings-general-upgrade_subs"></span>
|
||||
</label>
|
||||
<label>Schedule a task to upgrade Subtitles previously downloaded by Bazarr.</label>
|
||||
|
@ -73,7 +78,7 @@
|
|||
<b>Number of days to go back in history to upgrade subtitles (up to 30)</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="number" class="form-control" id="settings-general-days_to_upgrade_subs" name="settings-general-days_to_upgrade_subs" min="1" max="30" value="{{settings.general.days_to_upgrade_subs}}" onkeydown="return false">
|
||||
<input class="slider" id="settings-general-days_to_upgrade_subs" name="settings-general-days_to_upgrade_subs" data-slider-id='settings-general-days_to_upgrade_subs' type="text" data-slider-min="0" data-slider-max="30" data-slider-step="1" data-slider-value="{{settings.general.days_to_upgrade_subs}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -83,7 +88,8 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-upgrade_manual" name="settings-general-upgrade_manual">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-upgrade_manual"
|
||||
name="settings-general-upgrade_manual">
|
||||
<span class="custom-control-label" for="settings-general-upgrade_manual"></span>
|
||||
</label>
|
||||
<label>Enable or disable upgrade of manually searched and downloaded Subtitles.</label>
|
||||
|
@ -99,15 +105,17 @@
|
|||
<b>Provider</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-4">
|
||||
<select class="form-control selectpicker" id="settings-general-anti_captcha_provider" name="settings-general-anti_captcha_provider">
|
||||
<select class="form-control selectpicker" id="settings-general-anti_captcha_provider"
|
||||
name="settings-general-anti_captcha_provider">
|
||||
<option value="None">None</option>
|
||||
<option value="anti-captcha">Anti-Captcha</option>
|
||||
<option value="death-by-captcha">Death by Captcha</option>
|
||||
</select>
|
||||
<label for="settings-general-anti_captcha_provider">Choose the Anti-Captcha provider you want to use.</label>
|
||||
<label for="settings-general-anti_captcha_provider">Choose the Anti-Captcha provider you want to
|
||||
use.</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="anticaptcha_div">
|
||||
<div id="anticaptcha_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Provider Website</b>
|
||||
|
@ -122,12 +130,14 @@
|
|||
<b>Account Key</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-anticaptcha-anti_captcha_key" name="settings-anticaptcha-anti_captcha_key" value="{{settings.anticaptcha.anti_captcha_key}}">
|
||||
<input type="text" class="form-control" id="settings-anticaptcha-anti_captcha_key"
|
||||
name="settings-anticaptcha-anti_captcha_key"
|
||||
value="{{ settings.anticaptcha.anti_captcha_key }}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<div id="deathbycaptcha_div">
|
||||
<div id="deathbycaptcha_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Provider Website</b>
|
||||
|
@ -142,7 +152,8 @@
|
|||
<b>Username</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-deathbycaptcha-username" name="settings-deathbycaptcha-username" value="{{settings.deathbycaptcha.username}}">
|
||||
<input type="text" class="form-control" id="settings-deathbycaptcha-username"
|
||||
name="settings-deathbycaptcha-username" value="{{ settings.deathbycaptcha.username }}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -151,7 +162,8 @@
|
|||
<b>Password</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" class="form-control" id="settings-deathbycaptcha-password" name="settings-deathbycaptcha-password" value="{{settings.deathbycaptcha.password}}">
|
||||
<input type="password" class="form-control" id="settings-deathbycaptcha-password"
|
||||
name="settings-deathbycaptcha-password" value="{{ settings.deathbycaptcha.password }}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -165,10 +177,12 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-adaptive_searching" name="settings-general-adaptive_searching">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-adaptive_searching"
|
||||
name="settings-general-adaptive_searching">
|
||||
<span class="custom-control-label" for="settings-general-adaptive_searching"></span>
|
||||
</label>
|
||||
<label>When searching for Subtitles, Bazarr will search less frequently to limit call to providers.</label>
|
||||
<label>When searching for Subtitles, Bazarr will search less frequently to limit call to
|
||||
providers.</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -177,7 +191,8 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-multithreading" name="settings-general-multithreading">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-multithreading"
|
||||
name="settings-general-multithreading">
|
||||
<span class="custom-control-label" for="settings-general-multithreading"></span>
|
||||
</label>
|
||||
<label>Search multiple providers at once (Don't choose this on low powered devices)</label>
|
||||
|
@ -189,7 +204,8 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_embedded_subs" name="settings-general-use_embedded_subs">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_embedded_subs"
|
||||
name="settings-general-use_embedded_subs">
|
||||
<span class="custom-control-label" for="settings-general-use_embedded_subs"></span>
|
||||
</label>
|
||||
<label>Use embedded Subtitles in media files when determining missing ones.</label>
|
||||
|
@ -202,10 +218,12 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-ignore_pgs_subs" name="settings-general-ignore_pgs_subs">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-ignore_pgs_subs"
|
||||
name="settings-general-ignore_pgs_subs">
|
||||
<span class="custom-control-label" for="settings-general-ignore_pgs_subs"></span>
|
||||
</label>
|
||||
<label>Ignores PGS Subtitles in Embedded Subtitles detection. Only relevant if 'Use embedded Subtitles' is enabled.</label>
|
||||
<label>Ignores PGS Subtitles in Embedded Subtitles detection. Only relevant if 'Use embedded
|
||||
Subtitles' is enabled.</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -214,7 +232,9 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-embedded_subs_show_desired" name="settings-general-embedded_subs_show_desired">
|
||||
<input type="checkbox" class="custom-control-input"
|
||||
id="settings-general-embedded_subs_show_desired"
|
||||
name="settings-general-embedded_subs_show_desired">
|
||||
<span class="custom-control-label" for="settings-general-embedded_subs_show_desired"></span>
|
||||
</label>
|
||||
<label>Hide embedded subtitles for languages that are not currently desired.</label>
|
||||
|
@ -230,36 +250,39 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-utf8_encode" name="settings-general-utf8_encode">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-utf8_encode"
|
||||
name="settings-general-utf8_encode">
|
||||
<span class="custom-control-label" for="settings-general-utf8_encode"></span>
|
||||
</label>
|
||||
<label>Re-encode downloaded Subtitles to UTF8. Should be left enabled in most case.</label>
|
||||
</div>
|
||||
</div>
|
||||
{% if not os.startswith('win') %}
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>Enable CHMOD</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-chmod_enabled" name="settings-general-chmod_enabled">
|
||||
<span class="custom-control-label" for="settings-general-chmod_enabled"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="chmod_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Set Subtitle file permissions to</b>
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>Enable CHMOD</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-general-chmod" name="settings-general-chmod" value="{{settings.general.chmod}}">
|
||||
<label for="settings-general-chmod">Must be 4 digit octal, e.g.: 0775</label>
|
||||
<div class="form-group col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-chmod_enabled"
|
||||
name="settings-general-chmod_enabled">
|
||||
<span class="custom-control-label" for="settings-general-chmod_enabled"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<div id="chmod_div">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 text-right">
|
||||
<b>Set Subtitle file permissions to</b>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="settings-general-chmod"
|
||||
name="settings-general-chmod" value="{{ settings.general.chmod }}">
|
||||
<label for="settings-general-chmod">Must be 4 digit octal, e.g.: 0775</label>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
|
@ -323,7 +346,8 @@
|
|||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_postprocessing" name="settings-general-use_postprocessing">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_postprocessing"
|
||||
name="settings-general-use_postprocessing">
|
||||
<span class="custom-control-label" for="settings-general-use_postprocessing"></span>
|
||||
</label>
|
||||
<label>Enable the post-processing execution after downloading a subtitles.</label>
|
||||
|
@ -336,8 +360,11 @@
|
|||
</div>
|
||||
<div class="col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_postprocessing_threshold" name="settings-general-use_postprocessing_threshold">
|
||||
<span class="custom-control-label" for="settings-general-use_postprocessing_threshold"></span>
|
||||
<input type="checkbox" class="custom-control-input"
|
||||
id="settings-general-use_postprocessing_threshold"
|
||||
name="settings-general-use_postprocessing_threshold">
|
||||
<span class="custom-control-label"
|
||||
for="settings-general-use_postprocessing_threshold"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -346,8 +373,8 @@
|
|||
<div class="col-sm-5 text-right">
|
||||
<b>Only for score below</b>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<input type="number" class="form-control" id="settings-general-postprocessing_threshold" name="settings-general-postprocessing_threshold" min="0" max="100" step="1" onkeydown="return false" value="{{settings.general.postprocessing_threshold}}">
|
||||
<div class="col-sm-4">
|
||||
<input class="slider" id="settings-general-postprocessing_threshold" name="settings-general-postprocessing_threshold" data-slider-id='settings-general-postprocessing_threshold' type="text" data-slider-min="1" data-slider-max="100" data-slider-step="1" data-slider-value="{{settings.general.postprocessing_threshold}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -357,8 +384,11 @@
|
|||
</div>
|
||||
<div class="col-sm-1">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="settings-general-use_postprocessing_threshold_movie" name="settings-general-use_postprocessing_threshold_movie">
|
||||
<span class="custom-control-label" for="settings-general-use_postprocessing_threshold_movie"></span>
|
||||
<input type="checkbox" class="custom-control-input"
|
||||
id="settings-general-use_postprocessing_threshold_movie"
|
||||
name="settings-general-use_postprocessing_threshold_movie">
|
||||
<span class="custom-control-label"
|
||||
for="settings-general-use_postprocessing_threshold_movie"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -367,8 +397,8 @@
|
|||
<div class="col-sm-5 text-right">
|
||||
<b>Only for score below</b>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<input type="number" class="form-control" id="settings-general-postprocessing_threshold_movie" name="settings-general-postprocessing_threshold_movie" min="0" max="100" step="1" onkeydown="return false" value="{{settings.general.postprocessing_threshold_movie}}">
|
||||
<div class="col-sm-4">
|
||||
<input class="slider" id="settings-general-postprocessing_threshold_movie" name="settings-general-postprocessing_threshold_movie" data-slider-id='settings-general-postprocessing_threshold_movie' type="text" data-slider-min="1" data-slider-max="100" data-slider-step="1" data-slider-value="{{settings.general.postprocessing_threshold_movie}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -377,7 +407,9 @@
|
|||
<b>Post-processing command</b>
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control" id="settings-general-postprocessing_cmd" name="settings-general-postprocessing_cmd" value="{{settings.general.postprocessing_cmd}}">
|
||||
<input type="text" class="form-control" id="settings-general-postprocessing_cmd"
|
||||
name="settings-general-postprocessing_cmd"
|
||||
value="{{ settings.general.postprocessing_cmd }}">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -406,6 +438,8 @@
|
|||
<p>The 2-letter ISO-639 language code of the episode audio language.</p>
|
||||
<b>{{episode_language_code3}}</b>
|
||||
<p>The 3-letter ISO-639 language code of the episode audio language.</p>
|
||||
<b>{{score}}</b>
|
||||
<p>The score of the subtitles file.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -418,7 +452,7 @@
|
|||
$(document).ready(function () {
|
||||
// Show warning if there's unsaved changes in the settings_form
|
||||
var form_changed = false;
|
||||
$(window).on('beforeunload', function() {
|
||||
$(window).on('beforeunload', function () {
|
||||
if (form_changed) {
|
||||
return "";
|
||||
}
|
||||
|
@ -429,7 +463,7 @@
|
|||
$('#save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
|
||||
// Hide *_div on Select input changed to None
|
||||
$('#settings-general-subfolder').on('change', function() {
|
||||
$('#settings-general-subfolder').on('change', function () {
|
||||
if ($(this).val() === 'current') {
|
||||
$('#subfolder_div').hide();
|
||||
} else {
|
||||
|
@ -437,7 +471,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$('#settings-general-upgrade_subs').on('change', function() {
|
||||
$('#settings-general-upgrade_subs').on('change', function () {
|
||||
if ($(this).prop('checked')) {
|
||||
$('#upgradesubs_div').show();
|
||||
} else {
|
||||
|
@ -445,7 +479,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$('#settings-general-anti_captcha_provider').on('change', function() {
|
||||
$('#settings-general-anti_captcha_provider').on('change', function () {
|
||||
if ($(this).val() === 'anti-captcha') {
|
||||
$('#anticaptcha_div').show();
|
||||
$('#deathbycaptcha_div').hide();
|
||||
|
@ -458,7 +492,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$('#settings-general-use_embedded_subs').on('change', function() {
|
||||
$('#settings-general-use_embedded_subs').on('change', function () {
|
||||
if ($(this).prop('checked')) {
|
||||
$('#embedded_div').show();
|
||||
} else {
|
||||
|
@ -466,7 +500,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$('#settings-general-chmod_enabled').on('change', function() {
|
||||
$('#settings-general-chmod_enabled').on('change', function () {
|
||||
if ($(this).prop('checked')) {
|
||||
$('#chmod_div').show();
|
||||
} else {
|
||||
|
@ -474,7 +508,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$('#settings-general-use_postprocessing').on('change', function() {
|
||||
$('#settings-general-use_postprocessing').on('change', function () {
|
||||
if ($(this).prop('checked')) {
|
||||
$('#custompp_div').show();
|
||||
} else {
|
||||
|
@ -512,7 +546,7 @@
|
|||
$('#settings-general-use_postprocessing_threshold').prop('checked', {{'true' if settings.general.getboolean('use_postprocessing_threshold') else 'false'}}).trigger('change');
|
||||
$('#settings-general-use_postprocessing_threshold_movie').prop('checked', {{'true' if settings.general.getboolean('use_postprocessing_threshold_movie') else 'false'}}).trigger('change');
|
||||
|
||||
$('#save_button').on('click', function() {
|
||||
$('#save_button').on('click', function () {
|
||||
var formdata = new FormData(document.getElementById("settings_form"));
|
||||
|
||||
// Make sure all checkbox input are sent with true/false value
|
||||
|
@ -531,8 +565,7 @@
|
|||
form_changed = false;
|
||||
$('#save_button').prop('disabled', true).css('cursor', 'not-allowed');
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
function () {
|
||||
$('#save_button_checkmark').hide();
|
||||
}, 2000);
|
||||
}
|
||||
|
@ -540,7 +573,7 @@
|
|||
});
|
||||
|
||||
// monitor changes to the settings_form
|
||||
$('#settings_form').on('change', function() {
|
||||
$('#settings_form').on('change', function () {
|
||||
form_changed = true;
|
||||
$('#save_button').prop('disabled', false).css('cursor', 'auto');
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue