mirror of
https://github.com/morpheus65535/bazarr.git
synced 2025-04-24 06:37:16 -04:00
Added normal only (non-hi) option to languages profile
This commit is contained in:
parent
36730a17d0
commit
eee8659ce1
10 changed files with 139 additions and 100 deletions
|
@ -497,3 +497,28 @@ def convert_list_to_clause(arr: list):
|
|||
return f"({','.join(str(x) for x in arr)})"
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
def upgrade_languages_profile_hi_values():
|
||||
for languages_profile in (database.execute(
|
||||
select(
|
||||
TableLanguagesProfiles.profileId,
|
||||
TableLanguagesProfiles.name,
|
||||
TableLanguagesProfiles.cutoff,
|
||||
TableLanguagesProfiles.items,
|
||||
TableLanguagesProfiles.mustContain,
|
||||
TableLanguagesProfiles.mustNotContain,
|
||||
TableLanguagesProfiles.originalFormat)
|
||||
))\
|
||||
.all():
|
||||
items = json.loads(languages_profile.items)
|
||||
for language in items:
|
||||
if language['hi'] == "True":
|
||||
language['hi'] = "only"
|
||||
elif language['hi'] == "False":
|
||||
language['hi'] = "also"
|
||||
database.execute(
|
||||
update(TableLanguagesProfiles)
|
||||
.values({"items": json.dumps(items)})
|
||||
.where(TableLanguagesProfiles.profileId == languages_profile.profileId)
|
||||
)
|
||||
|
|
|
@ -35,7 +35,7 @@ else:
|
|||
# there's missing embedded packages after a commit
|
||||
check_if_new_update()
|
||||
|
||||
from app.database import System, database, update, migrate_db, create_db_revision # noqa E402
|
||||
from app.database import System, database, update, migrate_db, create_db_revision, upgrade_languages_profile_hi_values # noqa E402
|
||||
from app.notifier import update_notifier # noqa E402
|
||||
from languages.get_languages import load_language_in_db # noqa E402
|
||||
from app.signalr_client import sonarr_signalr_client, radarr_signalr_client # noqa E402
|
||||
|
@ -49,6 +49,7 @@ if args.create_db_revision:
|
|||
stop_bazarr(EXIT_NORMAL)
|
||||
else:
|
||||
migrate_db(app)
|
||||
upgrade_languages_profile_hi_values()
|
||||
|
||||
configure_proxy_func()
|
||||
|
||||
|
|
|
@ -41,10 +41,6 @@ def generate_subtitles(path, languages, audio_language, sceneName, title, media_
|
|||
providers = pool.providers
|
||||
|
||||
language_set = _get_language_obj(languages=languages)
|
||||
hi_required = "force HI" if any([x.hi for x in language_set]) else False
|
||||
also_forced = any([x.forced for x in language_set])
|
||||
forced_required = all([x.forced for x in language_set])
|
||||
_set_forced_providers(pool=pool, also_forced=also_forced, forced_required=forced_required)
|
||||
|
||||
video = get_video(force_unicode(path), title, sceneName, providers=providers, media_type=media_type)
|
||||
|
||||
|
@ -60,6 +56,9 @@ def generate_subtitles(path, languages, audio_language, sceneName, title, media_
|
|||
if forced_minimum_score:
|
||||
min_score = int(forced_minimum_score) + 1
|
||||
for language in language_set:
|
||||
# check if language appears more than one time which means that the languages profile requires normal
|
||||
# and hi subtitles (also)
|
||||
also_hi = len(set([x.hi for x in language_set if x.alpha3 == language.alpha3 and not x.forced])) > 1
|
||||
# confirm if language is still missing or if cutoff has been reached
|
||||
if check_if_still_required and language not in check_missing_languages(path, media_type):
|
||||
# cutoff has been reached
|
||||
|
@ -67,11 +66,13 @@ def generate_subtitles(path, languages, audio_language, sceneName, title, media_
|
|||
f"has been reached during this search.")
|
||||
continue
|
||||
else:
|
||||
hi_required = "force HI" if language.hi else "force non-HI"
|
||||
_set_forced_providers(pool=pool, also_forced=language.forced, forced_required=language.forced)
|
||||
downloaded_subtitles = download_best_subtitles(videos={video},
|
||||
languages={language},
|
||||
pool_instance=pool,
|
||||
min_score=int(min_score),
|
||||
hearing_impaired=hi_required,
|
||||
hearing_impaired=False if also_hi else hi_required,
|
||||
compute_score=ComputeScore(get_scores()))
|
||||
|
||||
if downloaded_subtitles:
|
||||
|
|
|
@ -182,7 +182,9 @@ def list_missing_subtitles_movies(no=None, send_event=True):
|
|||
if any(x['code2'] == language['language'] for x in get_audio_profile_languages(
|
||||
movie_subtitles.audio_language)):
|
||||
continue
|
||||
desired_subtitles_list.append([language['language'], language['forced'], language['hi']])
|
||||
desired_subtitles_list.append({'language': language['language'],
|
||||
'forced': language['forced'],
|
||||
'hi': language['hi']})
|
||||
|
||||
# get existing subtitles
|
||||
actual_subtitles_list = []
|
||||
|
@ -204,7 +206,9 @@ def list_missing_subtitles_movies(no=None, send_event=True):
|
|||
elif subtitles[1] == 'hi':
|
||||
forced = False
|
||||
hi = True
|
||||
actual_subtitles_list.append([lang, str(forced), str(hi)])
|
||||
actual_subtitles_list.append({'language': lang,
|
||||
'forced': str(forced),
|
||||
'hi': str(hi)})
|
||||
|
||||
# check if cutoff is reached and skip any further check
|
||||
cutoff_met = False
|
||||
|
@ -229,24 +233,34 @@ def list_missing_subtitles_movies(no=None, send_event=True):
|
|||
# get difference between desired and existing subtitles
|
||||
missing_subtitles_list = []
|
||||
for item in desired_subtitles_list:
|
||||
if item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(item)
|
||||
|
||||
# remove missing that have forced or hi subtitles for this language in existing
|
||||
for item in actual_subtitles_list:
|
||||
if item[2] == 'True':
|
||||
try:
|
||||
missing_subtitles_list.remove([item[0], 'False', 'False'])
|
||||
except ValueError:
|
||||
pass
|
||||
if item['forced'] == 'True':
|
||||
desired_item = {'language': item['language'], 'forced': item['forced'], 'hi': 'False'}
|
||||
if desired_item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
elif item['hi'] == 'never':
|
||||
desired_item = {'language': item['language'], 'forced': item['forced'], 'hi': 'False'}
|
||||
if desired_item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
elif item['hi'] == 'only':
|
||||
desired_item = {'language': item['language'], 'forced': item['forced'], 'hi': 'True'}
|
||||
if desired_item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
elif item['hi'] == 'also':
|
||||
desired_items = [{'language': item['language'], 'forced': item['forced'], 'hi': 'True'},
|
||||
{'language': item['language'], 'forced': item['forced'], 'hi': 'False'}]
|
||||
if [x for x in desired_items if x in actual_subtitles_list]:
|
||||
continue
|
||||
else:
|
||||
for desired_item in desired_items:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
|
||||
# make the missing languages list looks like expected
|
||||
missing_subtitles_output_list = []
|
||||
for item in missing_subtitles_list:
|
||||
lang = item[0]
|
||||
if item[1] == 'True':
|
||||
lang = item['language']
|
||||
if item['forced'] == 'True':
|
||||
lang += ':forced'
|
||||
elif item[2] == 'True':
|
||||
elif item['hi'] == 'True':
|
||||
lang += ':hi'
|
||||
missing_subtitles_output_list.append(lang)
|
||||
|
||||
|
|
|
@ -182,7 +182,9 @@ def list_missing_subtitles(no=None, epno=None, send_event=True):
|
|||
if any(x['code2'] == language['language'] for x in get_audio_profile_languages(
|
||||
episode_subtitles.audio_language)):
|
||||
continue
|
||||
desired_subtitles_list.append([language['language'], language['forced'], language['hi']])
|
||||
desired_subtitles_list.append({'language': language['language'],
|
||||
'forced': language['forced'],
|
||||
'hi': language['hi']})
|
||||
|
||||
# get existing subtitles
|
||||
actual_subtitles_list = []
|
||||
|
@ -204,7 +206,9 @@ def list_missing_subtitles(no=None, epno=None, send_event=True):
|
|||
elif subtitles[1] == 'hi':
|
||||
forced = False
|
||||
hi = True
|
||||
actual_subtitles_list.append([lang, str(forced), str(hi)])
|
||||
actual_subtitles_list.append({'language': lang,
|
||||
'forced': str(forced),
|
||||
'hi': str(hi)})
|
||||
|
||||
# check if cutoff is reached and skip any further check
|
||||
cutoff_met = False
|
||||
|
@ -231,24 +235,34 @@ def list_missing_subtitles(no=None, epno=None, send_event=True):
|
|||
# get difference between desired and existing subtitles
|
||||
missing_subtitles_list = []
|
||||
for item in desired_subtitles_list:
|
||||
if item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(item)
|
||||
|
||||
# remove missing that have hi subtitles for this language in existing
|
||||
for item in actual_subtitles_list:
|
||||
if item[2] == 'True':
|
||||
try:
|
||||
missing_subtitles_list.remove([item[0], 'False', 'False'])
|
||||
except ValueError:
|
||||
pass
|
||||
if item['forced'] == 'True':
|
||||
desired_item = {'language': item['language'], 'forced': item['forced'], 'hi': 'False'}
|
||||
if desired_item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
elif item['hi'] == 'never':
|
||||
desired_item = {'language': item['language'], 'forced': item['forced'], 'hi': 'False'}
|
||||
if desired_item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
elif item['hi'] == 'only':
|
||||
desired_item = {'language': item['language'], 'forced': item['forced'], 'hi': 'True'}
|
||||
if desired_item not in actual_subtitles_list:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
elif item['hi'] == 'also':
|
||||
desired_items = [{'language': item['language'], 'forced': item['forced'], 'hi': 'True'},
|
||||
{'language': item['language'], 'forced': item['forced'], 'hi': 'False'}]
|
||||
if [x for x in desired_items if x in actual_subtitles_list]:
|
||||
continue
|
||||
else:
|
||||
for desired_item in desired_items:
|
||||
missing_subtitles_list.append(desired_item)
|
||||
|
||||
# make the missing languages list looks like expected
|
||||
missing_subtitles_output_list = []
|
||||
for item in missing_subtitles_list:
|
||||
lang = item[0]
|
||||
if item[1] == 'True':
|
||||
lang = item['language']
|
||||
if item['forced'] == 'True':
|
||||
lang += ':forced'
|
||||
elif item[2] == 'True':
|
||||
elif item['hi'] == 'True':
|
||||
lang += ':hi'
|
||||
missing_subtitles_output_list.append(lang)
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ def manual_search(path, profile_id, providers, sceneName, title, media_type):
|
|||
|
||||
pool = _get_pool(media_type, profile_id)
|
||||
|
||||
language_set, initial_language_set, original_format = _get_language_obj(profile_id=profile_id)
|
||||
also_forced = any([x.forced for x in initial_language_set])
|
||||
forced_required = all([x.forced for x in initial_language_set])
|
||||
language_set, original_format = _get_language_obj(profile_id=profile_id)
|
||||
also_forced = any([x.forced for x in language_set])
|
||||
forced_required = all([x.forced for x in language_set])
|
||||
compute_score = ComputeScore(get_scores())
|
||||
_set_forced_providers(pool=pool, also_forced=also_forced, forced_required=forced_required)
|
||||
|
||||
|
@ -57,6 +57,10 @@ def manual_search(path, profile_id, providers, sceneName, title, media_type):
|
|||
minimum_score_movie = settings.general.minimum_score_movie
|
||||
|
||||
for s in subtitles[video]:
|
||||
if s.language not in language_set:
|
||||
# HI may not be matching what was requested
|
||||
continue
|
||||
|
||||
try:
|
||||
matches = s.get_matches(video)
|
||||
except AttributeError:
|
||||
|
@ -75,20 +79,8 @@ def manual_search(path, profile_id, providers, sceneName, title, media_type):
|
|||
logging.debug("BAZARR Ignoring invalid subtitles")
|
||||
continue
|
||||
|
||||
initial_hi = None
|
||||
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
|
||||
|
||||
_, max_score, scores = _get_scores(media_type, minimum_score_movie, minimum_score)
|
||||
score, score_without_hash = compute_score(matches, s, video, hearing_impaired=initial_hi)
|
||||
score, score_without_hash = compute_score(matches, s, video, hearing_impaired=s.language.hi)
|
||||
if 'hash' not in matches:
|
||||
not_matched = scores - matches
|
||||
s.score = score_without_hash
|
||||
|
@ -96,11 +88,6 @@ def manual_search(path, profile_id, providers, sceneName, title, media_type):
|
|||
s.score = score
|
||||
not_matched = set()
|
||||
|
||||
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:
|
||||
|
@ -215,7 +202,6 @@ def manual_download_subtitle(path, audio_language, hi, forced, subtitle, provide
|
|||
|
||||
|
||||
def _get_language_obj(profile_id):
|
||||
initial_language_set = set()
|
||||
language_set = set()
|
||||
|
||||
profile = get_profiles_list(profile_id=int(profile_id))
|
||||
|
@ -232,22 +218,13 @@ def _get_language_obj(profile_id):
|
|||
lang_obj = _get_lang_obj(lang)
|
||||
|
||||
if forced == "True":
|
||||
lang_obj = Language.rebuild(lang_obj, forced=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)
|
||||
language_set.add(Language.rebuild(lang_obj, forced=True))
|
||||
elif hi == "only":
|
||||
language_set.add(Language.rebuild(lang_obj, hi=True))
|
||||
elif hi == "also":
|
||||
language_set.add(lang_obj)
|
||||
language_set.add(Language.rebuild(lang_obj, hi=True))
|
||||
else:
|
||||
continue
|
||||
language_set.add(lang_obj_hi)
|
||||
language_set.add(lang_obj)
|
||||
|
||||
return language_set, initial_language_set, original_format
|
||||
return language_set, original_format
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { cond } from "lodash";
|
||||
import { Action, Selector, SelectorOption, SimpleTable } from "@/components";
|
||||
import ChipInput from "@/components/inputs/ChipInput";
|
||||
import { useModals, withModal } from "@/modules/modals";
|
||||
|
@ -30,7 +31,7 @@ const defaultCutoffOptions: SelectorOption<Language.ProfileItem>[] = [
|
|||
// eslint-disable-next-line camelcase
|
||||
audio_exclude: "False",
|
||||
forced: "False",
|
||||
hi: "False",
|
||||
hi: "also",
|
||||
language: "any",
|
||||
},
|
||||
},
|
||||
|
@ -38,12 +39,16 @@ const defaultCutoffOptions: SelectorOption<Language.ProfileItem>[] = [
|
|||
|
||||
const subtitlesTypeOptions: SelectorOption<string>[] = [
|
||||
{
|
||||
label: "Normal or hearing-impaired",
|
||||
value: "normal",
|
||||
label: "Normal only",
|
||||
value: "never",
|
||||
},
|
||||
{
|
||||
label: "Hearing-impaired required",
|
||||
value: "hi",
|
||||
label: "Hearing-impaired only",
|
||||
value: "only",
|
||||
},
|
||||
{
|
||||
label: "Normal or hearing-impaired",
|
||||
value: "also",
|
||||
},
|
||||
{
|
||||
label: "Forced (foreign part only)",
|
||||
|
@ -83,10 +88,14 @@ const ProfileEditForm: FunctionComponent<Props> = ({
|
|||
const itemCutoffOptions = useSelectorOptions(
|
||||
form.values.items,
|
||||
(v) => {
|
||||
const suffix =
|
||||
v.hi === "True" ? ":hi" : v.forced === "True" ? ":forced" : "";
|
||||
const suffix = cond([
|
||||
[(v: { forced: string; hi: string }) => v.hi === "only", () => ":hi"],
|
||||
[(v) => v.hi === "never", () => ":normal"],
|
||||
[(v) => v.forced === "True", () => ":forced"],
|
||||
[() => true, () => ""],
|
||||
]);
|
||||
|
||||
return v.language + suffix;
|
||||
return v.language + suffix(v);
|
||||
},
|
||||
(v) => String(v.id),
|
||||
);
|
||||
|
@ -136,7 +145,7 @@ const ProfileEditForm: FunctionComponent<Props> = ({
|
|||
language,
|
||||
// eslint-disable-next-line camelcase
|
||||
audio_exclude: "False",
|
||||
hi: "False",
|
||||
hi: "also",
|
||||
forced: "False",
|
||||
};
|
||||
|
||||
|
@ -184,10 +193,8 @@ const ProfileEditForm: FunctionComponent<Props> = ({
|
|||
const selectValue = useMemo(() => {
|
||||
if (item.forced === "True") {
|
||||
return "forced";
|
||||
} else if (item.hi === "True") {
|
||||
return "hi";
|
||||
} else {
|
||||
return "normal";
|
||||
return item.hi;
|
||||
}
|
||||
}, [item.forced, item.hi]);
|
||||
|
||||
|
@ -199,9 +206,9 @@ const ProfileEditForm: FunctionComponent<Props> = ({
|
|||
if (value) {
|
||||
action.mutate(index, {
|
||||
...item,
|
||||
hi: value === "hi" ? "True" : "False",
|
||||
hi: value,
|
||||
forced: value === "forced" ? "True" : "False",
|
||||
});
|
||||
} as Language.ProfileItem);
|
||||
}
|
||||
}}
|
||||
></Select>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { FunctionComponent, useCallback, useMemo } from "react";
|
|||
import { Column } from "react-table";
|
||||
import { Badge, Button, Group } from "@mantine/core";
|
||||
import { faTrash, faWrench } from "@fortawesome/free-solid-svg-icons";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { cloneDeep, cond } from "lodash";
|
||||
import { Action, SimpleTable } from "@/components";
|
||||
import {
|
||||
anyCutoff,
|
||||
|
@ -193,14 +193,14 @@ interface ItemProps {
|
|||
|
||||
const ItemBadge: FunctionComponent<ItemProps> = ({ cutoff, item }) => {
|
||||
const text = useMemo(() => {
|
||||
let result = item.language;
|
||||
if (item.hi === "True") {
|
||||
result += ":HI";
|
||||
} else if (item.forced === "True") {
|
||||
result += ":Forced";
|
||||
}
|
||||
return result;
|
||||
}, [item.hi, item.forced, item.language]);
|
||||
const suffix = cond([
|
||||
[(v: { forced: string; hi: string }) => v.hi === "only", () => ":HI"],
|
||||
[(v) => v.hi === "never", () => ":Normal"],
|
||||
[(v) => v.forced === "True", () => ":Forced"],
|
||||
[() => true, () => ""],
|
||||
]);
|
||||
return item.language + suffix(item);
|
||||
}, [item]);
|
||||
return (
|
||||
<Badge
|
||||
title={cutoff ? "Ignore others if this one is available" : undefined}
|
||||
|
|
2
frontend/src/types/api.d.ts
vendored
2
frontend/src/types/api.d.ts
vendored
|
@ -28,7 +28,7 @@ declare namespace Language {
|
|||
id: number;
|
||||
audio_exclude: PythonBoolean;
|
||||
forced: PythonBoolean;
|
||||
hi: PythonBoolean;
|
||||
hi: "never" | "also" | "only";
|
||||
language: CodeType;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ export function useProfileItemsToLanguages(profile?: Language.Profile) {
|
|||
profile?.items.map<Language.Info>(({ language: code, hi, forced }) => {
|
||||
const name = data?.find((v) => v.code2 === code)?.name ?? "";
|
||||
return {
|
||||
hi: hi === "True",
|
||||
hi: hi === "only",
|
||||
forced: forced === "True",
|
||||
code2: code,
|
||||
name,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue