|
|
|
@ -1,105 +1,199 @@
|
|
|
|
|
import React, { FunctionComponent, useEffect, useMemo, useState } from "react";
|
|
|
|
|
import { faTrash } from "@fortawesome/free-solid-svg-icons";
|
|
|
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
|
|
import React, {
|
|
|
|
|
FunctionComponent,
|
|
|
|
|
useCallback,
|
|
|
|
|
useMemo,
|
|
|
|
|
useState,
|
|
|
|
|
} from "react";
|
|
|
|
|
import { Button, Container, Form } from "react-bootstrap";
|
|
|
|
|
import { FileForm, LanguageSelector } from "..";
|
|
|
|
|
import { Column, Row } from "react-table";
|
|
|
|
|
import { dispatchTask } from "../../@modules/task";
|
|
|
|
|
import { createTask } from "../../@modules/task/utilites";
|
|
|
|
|
import {
|
|
|
|
|
useEnabledLanguages,
|
|
|
|
|
useLanguageBy,
|
|
|
|
|
useProfileBy,
|
|
|
|
|
} from "../../@redux/hooks";
|
|
|
|
|
import { useProfileBy, useProfileItemsToLanguages } from "../../@redux/hooks";
|
|
|
|
|
import { MoviesApi } from "../../apis";
|
|
|
|
|
import { BuildKey } from "../../utilites";
|
|
|
|
|
import { FileForm } from "../inputs";
|
|
|
|
|
import { LanguageSelector } from "../LanguageSelector";
|
|
|
|
|
import { SimpleTable } from "../tables";
|
|
|
|
|
import BaseModal, { BaseModalProps } from "./BaseModal";
|
|
|
|
|
import { useModalInformation } from "./hooks";
|
|
|
|
|
|
|
|
|
|
interface PendingSubtitle {
|
|
|
|
|
file: File;
|
|
|
|
|
language: Language.Info;
|
|
|
|
|
forced: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const TaskGroupName = "Uploading Subtitles...";
|
|
|
|
|
|
|
|
|
|
const MovieUploadModal: FunctionComponent<BaseModalProps> = (props) => {
|
|
|
|
|
const modal = props;
|
|
|
|
|
|
|
|
|
|
const availableLanguages = useEnabledLanguages();
|
|
|
|
|
|
|
|
|
|
const { payload, closeModal } = useModalInformation<Item.Movie>(
|
|
|
|
|
modal.modalKey
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const [language, setLanguage] = useState<Nullable<Language.Info>>(null);
|
|
|
|
|
|
|
|
|
|
const profile = useProfileBy(payload?.profileId);
|
|
|
|
|
|
|
|
|
|
const defaultLanguage = useLanguageBy(profile?.items[0]?.language);
|
|
|
|
|
const availableLanguages = useProfileItemsToLanguages(profile);
|
|
|
|
|
|
|
|
|
|
useEffect(() => setLanguage(defaultLanguage ?? null), [defaultLanguage]);
|
|
|
|
|
const [pending, setPending] = useState<PendingSubtitle[]>([]);
|
|
|
|
|
|
|
|
|
|
const [file, setFile] = useState<Nullable<File>>(null);
|
|
|
|
|
const [forced, setForced] = useState(false);
|
|
|
|
|
const filelist = useMemo(() => pending.map((v) => v.file), [pending]);
|
|
|
|
|
|
|
|
|
|
const canUpload = useMemo(() => {
|
|
|
|
|
return file !== null && language?.code2;
|
|
|
|
|
}, [language, file]);
|
|
|
|
|
const setFiles = useCallback(
|
|
|
|
|
(files: File[]) => {
|
|
|
|
|
const list: PendingSubtitle[] = files.map((v) => ({
|
|
|
|
|
file: v,
|
|
|
|
|
forced: availableLanguages[0].forced ?? false,
|
|
|
|
|
language: availableLanguages[0],
|
|
|
|
|
}));
|
|
|
|
|
setPending(list);
|
|
|
|
|
},
|
|
|
|
|
[availableLanguages]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const footer = (
|
|
|
|
|
<Button
|
|
|
|
|
disabled={!canUpload}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
if (file && payload && language) {
|
|
|
|
|
const id = payload.radarrId;
|
|
|
|
|
const task = createTask(
|
|
|
|
|
file.name,
|
|
|
|
|
id,
|
|
|
|
|
MoviesApi.uploadSubtitles.bind(MoviesApi),
|
|
|
|
|
id,
|
|
|
|
|
{
|
|
|
|
|
file: file,
|
|
|
|
|
forced,
|
|
|
|
|
hi: false,
|
|
|
|
|
language: language.code2,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
dispatchTask(TaskGroupName, [task], "Uploading subtitles...");
|
|
|
|
|
closeModal(props.modalKey);
|
|
|
|
|
const upload = useCallback(() => {
|
|
|
|
|
if (payload === null || pending.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { radarrId } = payload;
|
|
|
|
|
|
|
|
|
|
const tasks = pending.map((v) => {
|
|
|
|
|
const { file, language, forced } = v;
|
|
|
|
|
|
|
|
|
|
return createTask(
|
|
|
|
|
file.name,
|
|
|
|
|
radarrId,
|
|
|
|
|
MoviesApi.uploadSubtitles.bind(MoviesApi),
|
|
|
|
|
radarrId,
|
|
|
|
|
{
|
|
|
|
|
file: file,
|
|
|
|
|
forced,
|
|
|
|
|
hi: false,
|
|
|
|
|
language: language.code2,
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Upload
|
|
|
|
|
</Button>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
dispatchTask(TaskGroupName, tasks, "Uploading...");
|
|
|
|
|
setFiles([]);
|
|
|
|
|
closeModal();
|
|
|
|
|
}, [payload, closeModal, pending, setFiles]);
|
|
|
|
|
|
|
|
|
|
const modify = useCallback(
|
|
|
|
|
(row: Row<PendingSubtitle>, info?: PendingSubtitle) => {
|
|
|
|
|
setPending((pd) => {
|
|
|
|
|
const newPending = [...pd];
|
|
|
|
|
if (info) {
|
|
|
|
|
newPending[row.index] = info;
|
|
|
|
|
} else {
|
|
|
|
|
newPending.splice(row.index, 1);
|
|
|
|
|
}
|
|
|
|
|
return newPending;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<BaseModal title={`Upload - ${payload?.title}`} footer={footer} {...modal}>
|
|
|
|
|
<Container fluid>
|
|
|
|
|
<Form>
|
|
|
|
|
<Form.Group>
|
|
|
|
|
<Form.Label>Language</Form.Label>
|
|
|
|
|
const columns = useMemo<Column<PendingSubtitle>[]>(
|
|
|
|
|
() => [
|
|
|
|
|
{
|
|
|
|
|
id: "name",
|
|
|
|
|
Header: "File",
|
|
|
|
|
accessor: (d) => d.file.name,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Header: "Forced",
|
|
|
|
|
accessor: "forced",
|
|
|
|
|
Cell: ({ row, value, update }) => {
|
|
|
|
|
const { original, index } = row;
|
|
|
|
|
return (
|
|
|
|
|
<Form.Check
|
|
|
|
|
custom
|
|
|
|
|
id={BuildKey(index, original.file.name, "forced")}
|
|
|
|
|
checked={value}
|
|
|
|
|
onChange={(v) => {
|
|
|
|
|
const newInfo = { ...row.original };
|
|
|
|
|
newInfo.forced = v.target.checked;
|
|
|
|
|
update && update(row, newInfo);
|
|
|
|
|
}}
|
|
|
|
|
></Form.Check>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Header: "Language",
|
|
|
|
|
accessor: "language",
|
|
|
|
|
className: "w-25",
|
|
|
|
|
Cell: ({ row, update, value }) => {
|
|
|
|
|
return (
|
|
|
|
|
<LanguageSelector
|
|
|
|
|
options={availableLanguages}
|
|
|
|
|
value={language}
|
|
|
|
|
value={value}
|
|
|
|
|
onChange={(lang) => {
|
|
|
|
|
if (lang) {
|
|
|
|
|
setLanguage(lang);
|
|
|
|
|
if (lang && update) {
|
|
|
|
|
const newInfo = { ...row.original };
|
|
|
|
|
newInfo.language = lang;
|
|
|
|
|
update(row, newInfo);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
></LanguageSelector>
|
|
|
|
|
</Form.Group>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
accessor: "file",
|
|
|
|
|
Cell: ({ row, update }) => {
|
|
|
|
|
return (
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="light"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
update && update(row);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<FontAwesomeIcon icon={faTrash}></FontAwesomeIcon>
|
|
|
|
|
</Button>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
[availableLanguages]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const canUpload = pending.length > 0;
|
|
|
|
|
|
|
|
|
|
const footer = (
|
|
|
|
|
<Button disabled={!canUpload} onClick={upload}>
|
|
|
|
|
Upload
|
|
|
|
|
</Button>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<BaseModal title={`Upload - ${payload?.title}`} footer={footer} {...modal}>
|
|
|
|
|
<Container fluid className="flex-column">
|
|
|
|
|
<Form>
|
|
|
|
|
<Form.Group>
|
|
|
|
|
<Form.Label>Subtitle File</Form.Label>
|
|
|
|
|
<FileForm
|
|
|
|
|
emptyText="Select..."
|
|
|
|
|
onChange={(list) => {
|
|
|
|
|
setFile(list[0]);
|
|
|
|
|
}}
|
|
|
|
|
disabled={canUpload || availableLanguages.length === 0}
|
|
|
|
|
multiple
|
|
|
|
|
value={filelist}
|
|
|
|
|
onChange={setFiles}
|
|
|
|
|
></FileForm>
|
|
|
|
|
</Form.Group>
|
|
|
|
|
<Form.Group>
|
|
|
|
|
<Form.Check
|
|
|
|
|
custom
|
|
|
|
|
id="forced-checkbox"
|
|
|
|
|
defaultChecked={forced}
|
|
|
|
|
onChange={(e) => setForced(e.target.checked)}
|
|
|
|
|
label="Forced"
|
|
|
|
|
></Form.Check>
|
|
|
|
|
</Form.Group>
|
|
|
|
|
</Form>
|
|
|
|
|
<div hidden={!canUpload}>
|
|
|
|
|
<SimpleTable
|
|
|
|
|
columns={columns}
|
|
|
|
|
data={pending}
|
|
|
|
|
responsive={false}
|
|
|
|
|
update={modify}
|
|
|
|
|
></SimpleTable>
|
|
|
|
|
</div>
|
|
|
|
|
</Container>
|
|
|
|
|
</BaseModal>
|
|
|
|
|
);
|
|
|
|
|