aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/src/pages/Settings/Languages
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/pages/Settings/Languages')
-rw-r--r--frontend/src/pages/Settings/Languages/index.tsx46
-rw-r--r--frontend/src/pages/Settings/Languages/table.tsx49
2 files changed, 91 insertions, 4 deletions
diff --git a/frontend/src/pages/Settings/Languages/index.tsx b/frontend/src/pages/Settings/Languages/index.tsx
index 9fe562920..1bd9d72a8 100644
--- a/frontend/src/pages/Settings/Languages/index.tsx
+++ b/frontend/src/pages/Settings/Languages/index.tsx
@@ -1,7 +1,9 @@
import { FunctionComponent } from "react";
+import { Text as MantineText } from "@mantine/core";
import { useLanguageProfiles, useLanguages } from "@/apis/hooks";
import {
Check,
+ Chips,
CollapseBox,
Layout,
Message,
@@ -115,6 +117,50 @@ const SettingsLanguagesView: FunctionComponent = () => {
<Section header="Languages Profile">
<Table></Table>
</Section>
+ <Section header="Tag-Based Automatic Language Profile Selection Settings">
+ <Message>
+ If enabled, Bazarr will look at the names of all tags of a Series from
+ Sonarr (or a Movie from Radarr) to find a matching Bazarr language
+ profile tag. It will use as the language profile the FIRST tag from
+ Sonarr/Radarr that matches the tag of a Bazarr language profile
+ EXACTLY. If multiple tags match, there is no guarantee as to which one
+ will be used, so choose your tag names carefully. Also, if you update
+ the tag names in Sonarr/Radarr, Bazarr will detect this and repeat the
+ matching process for the affected shows. However, if a show's only
+ matching tag is removed from Sonarr/Radarr, Bazarr will NOT remove the
+ show's existing language profile for that reason. But if you wish to
+ have language profiles removed automatically by tag value, simply
+ enter a list of one or more tags in the{" "}
+ <MantineText fw={700} span>
+ Remove Profile Tags
+ </MantineText>{" "}
+ entry list below. If your video tag matches one of the tags in that
+ list, then Bazarr will remove the language profile for that video. If
+ there is a conflict between profile selection and profile removal,
+ then profile removal wins out and is performed.
+ </Message>
+ <Check
+ label="Series"
+ settingKey="settings-general-serie_tag_enabled"
+ ></Check>
+ <Check
+ label="Movies"
+ settingKey="settings-general-movie_tag_enabled"
+ ></Check>
+ <Chips
+ label="Remove Profile Tags"
+ settingKey="settings-general-remove_profile_tags"
+ sanitizeFn={(values: string[] | null) =>
+ values?.map((item) =>
+ item.replace(/[^a-z0-9_-]/gi, "").toLowerCase(),
+ )
+ }
+ ></Chips>
+ <Message>
+ Enter tag values that will trigger a language profile removal. Leave
+ empty if you don't want Bazarr to remove language profiles.
+ </Message>
+ </Section>
<Section header="Default Settings">
<Check
label="Series"
diff --git a/frontend/src/pages/Settings/Languages/table.tsx b/frontend/src/pages/Settings/Languages/table.tsx
index c32300628..5cfefdfa9 100644
--- a/frontend/src/pages/Settings/Languages/table.tsx
+++ b/frontend/src/pages/Settings/Languages/table.tsx
@@ -2,7 +2,7 @@ import { FunctionComponent, useCallback, useMemo } from "react";
import { Badge, Button, Group } from "@mantine/core";
import { faTrash, faWrench } from "@fortawesome/free-solid-svg-icons";
import { ColumnDef } from "@tanstack/react-table";
-import { cloneDeep } from "lodash";
+import { cloneDeep, includes, maxBy } from "lodash";
import { Action } from "@/components";
import {
anyCutoff,
@@ -66,6 +66,10 @@ const Table: FunctionComponent = () => {
accessorKey: "name",
},
{
+ header: "Tag",
+ accessorKey: "tag",
+ },
+ {
header: "Languages",
accessorKey: "items",
cell: ({
@@ -75,10 +79,10 @@ const Table: FunctionComponent = () => {
}) => {
return (
<Group gap="xs" wrap="nowrap">
- {items.map((v) => {
+ {items.map((v, i) => {
const isCutoff = v.id === cutoff || cutoff === anyCutoff;
return (
- <ItemBadge key={v.id} cutoff={isCutoff} item={v}></ItemBadge>
+ <ItemBadge key={i} cutoff={isCutoff} item={v}></ItemBadge>
);
})}
</Group>
@@ -144,9 +148,45 @@ const Table: FunctionComponent = () => {
icon={faWrench}
c="gray"
onClick={() => {
+ const lastId = maxBy(profile.items, "id")?.id || 0;
+
+ // We once had an issue on the past where there were duplicated
+ // item ids that needs to become unique upon editing.
+ const sanitizedProfile = {
+ ...cloneDeep(profile),
+ items: profile.items.reduce(
+ (acc, value) => {
+ const { ids, duplicatedIds, items } = acc;
+
+ // We once had an issue on the past where there were duplicated
+ // item ids that needs to become unique upon editing.
+ if (includes(ids, value.id)) {
+ duplicatedIds.push(value.id);
+ items.push({
+ ...value,
+ id: lastId + duplicatedIds.length,
+ });
+
+ return acc;
+ }
+
+ ids.push(value.id);
+ items.push(value);
+
+ return acc;
+ },
+ {
+ ids: [] as number[],
+ duplicatedIds: [] as number[],
+ items: [] as typeof profile.items,
+ },
+ ).items,
+ tag: profile.tag || undefined,
+ };
+
modals.openContextModal(ProfileEditModal, {
languages,
- profile: cloneDeep(profile),
+ profile: sanitizedProfile,
onComplete: updateProfile,
});
}}
@@ -178,6 +218,7 @@ const Table: FunctionComponent = () => {
const profile = {
profileId: nextProfileId,
name: "",
+ tag: undefined,
items: [],
cutoff: null,
mustContain: [],