mirror of https://github.com/morpheus65535/bazarr
176 lines
4.5 KiB
TypeScript
176 lines
4.5 KiB
TypeScript
import { useEpisodeSubtitleModification } from "@/apis/hooks";
|
|
import api from "@/apis/raw";
|
|
import { usePayload, withModal } from "@/modules/modals";
|
|
import { createTask, dispatchTask } from "@/modules/task/utilities";
|
|
import {
|
|
useLanguageProfileBy,
|
|
useProfileItemsToLanguages,
|
|
} from "@/utilities/languages";
|
|
import { FunctionComponent, useCallback, useMemo } from "react";
|
|
import { Column } from "react-table";
|
|
import { Selector, SelectorOption } from "../inputs";
|
|
import SubtitleUploader, {
|
|
PendingSubtitle,
|
|
useRowMutation,
|
|
Validator,
|
|
} from "./SubtitleUploadModal";
|
|
|
|
interface Payload {
|
|
instance: Item.Episode | null;
|
|
}
|
|
|
|
interface SeriesProps {
|
|
episodes: readonly Item.Episode[];
|
|
}
|
|
|
|
const SeriesUploadModal: FunctionComponent<SeriesProps> = ({ episodes }) => {
|
|
const payload = usePayload<Item.Series>();
|
|
|
|
const profile = useLanguageProfileBy(payload?.profileId);
|
|
|
|
const availableLanguages = useProfileItemsToLanguages(profile);
|
|
|
|
const {
|
|
upload: { mutateAsync },
|
|
} = useEpisodeSubtitleModification();
|
|
|
|
const update = useCallback(
|
|
async (list: PendingSubtitle<Payload>[]) => {
|
|
const newList = [...list];
|
|
const names = list.map((v) => v.file.name);
|
|
|
|
if (names.length > 0) {
|
|
const results = await api.subtitles.info(names);
|
|
|
|
// TODO: Optimization
|
|
newList.forEach((v) => {
|
|
const info = results.find((f) => f.filename === v.file.name);
|
|
if (info) {
|
|
v.payload.instance =
|
|
episodes.find(
|
|
(e) => e.season === info.season && e.episode === info.episode
|
|
) ?? null;
|
|
}
|
|
});
|
|
}
|
|
|
|
return newList;
|
|
},
|
|
[episodes]
|
|
);
|
|
|
|
const validate = useCallback<Validator<Payload>>((item) => {
|
|
const { language } = item;
|
|
const { instance } = item.payload;
|
|
if (language === null || instance === null) {
|
|
return {
|
|
state: "error",
|
|
messages: ["Language or Episode is not selected"],
|
|
};
|
|
} else if (
|
|
instance.subtitles.find((v) => v.code2 === language.code2) !== undefined
|
|
) {
|
|
return {
|
|
state: "warning",
|
|
messages: ["Override existing subtitle"],
|
|
};
|
|
}
|
|
return {
|
|
state: "valid",
|
|
messages: [],
|
|
};
|
|
}, []);
|
|
|
|
const upload = useCallback(
|
|
(items: PendingSubtitle<Payload>[]) => {
|
|
if (payload === null) {
|
|
return;
|
|
}
|
|
|
|
const { sonarrSeriesId: seriesId } = payload;
|
|
|
|
const tasks = items
|
|
.filter((v) => v.payload.instance !== undefined)
|
|
.map((v) => {
|
|
const {
|
|
hi,
|
|
forced,
|
|
payload: { instance },
|
|
language,
|
|
} = v;
|
|
|
|
if (language === null || instance === null) {
|
|
throw new Error("Invalid state");
|
|
}
|
|
|
|
const { code2 } = language;
|
|
const { sonarrEpisodeId: episodeId } = instance;
|
|
|
|
const form: FormType.UploadSubtitle = {
|
|
file: v.file,
|
|
language: code2,
|
|
hi: hi,
|
|
forced: forced,
|
|
};
|
|
|
|
return createTask(v.file.name, mutateAsync, {
|
|
seriesId,
|
|
episodeId,
|
|
form,
|
|
});
|
|
});
|
|
|
|
dispatchTask(tasks, "upload-subtitles");
|
|
},
|
|
[mutateAsync, payload]
|
|
);
|
|
|
|
const columns = useMemo<Column<PendingSubtitle<Payload>>[]>(
|
|
() => [
|
|
{
|
|
id: "instance",
|
|
Header: "Episode",
|
|
accessor: "payload",
|
|
className: "vw-1",
|
|
Cell: ({ value, row }) => {
|
|
const options = episodes.map<SelectorOption<Item.Episode>>((ep) => ({
|
|
label: `(${ep.season}x${ep.episode}) ${ep.title}`,
|
|
value: ep,
|
|
}));
|
|
|
|
const mutate = useRowMutation();
|
|
|
|
return (
|
|
<Selector
|
|
disabled={row.original.state === "fetching"}
|
|
options={options}
|
|
value={value.instance}
|
|
onChange={(ep: Nullable<Item.Episode>) => {
|
|
if (ep) {
|
|
const newInfo = { ...row.original };
|
|
newInfo.payload.instance = ep;
|
|
mutate(row.index, newInfo);
|
|
}
|
|
}}
|
|
></Selector>
|
|
);
|
|
},
|
|
},
|
|
],
|
|
[episodes]
|
|
);
|
|
|
|
return (
|
|
<SubtitleUploader
|
|
columns={columns}
|
|
initial={{ instance: null }}
|
|
availableLanguages={availableLanguages}
|
|
upload={upload}
|
|
update={update}
|
|
validate={validate}
|
|
></SubtitleUploader>
|
|
);
|
|
};
|
|
|
|
export default withModal(SeriesUploadModal, "series-upload");
|