From a5ecd84605cd46e2feab87b6275879a3962d76fb Mon Sep 17 00:00:00 2001 From: LASER-Yi Date: Sun, 22 Aug 2021 21:59:48 +0800 Subject: [PATCH] Add support of uploading multiple movie subtitles at the same time --- .../components/modals/MovieUploadModal.tsx | 224 +++++++++++++----- .../components/modals/SeriesUploadModal.tsx | 42 +--- 2 files changed, 168 insertions(+), 98 deletions(-) diff --git a/frontend/src/components/modals/MovieUploadModal.tsx b/frontend/src/components/modals/MovieUploadModal.tsx index f93465836..37785aada 100644 --- a/frontend/src/components/modals/MovieUploadModal.tsx +++ b/frontend/src/components/modals/MovieUploadModal.tsx @@ -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 = (props) => { const modal = props; - const availableLanguages = useEnabledLanguages(); - const { payload, closeModal } = useModalInformation( modal.modalKey ); - const [language, setLanguage] = useState>(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([]); - const [file, setFile] = useState>(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 = ( - + ); + }); + + dispatchTask(TaskGroupName, tasks, "Uploading..."); + setFiles([]); + closeModal(); + }, [payload, closeModal, pending, setFiles]); + + const modify = useCallback( + (row: Row, info?: PendingSubtitle) => { + setPending((pd) => { + const newPending = [...pd]; + if (info) { + newPending[row.index] = info; + } else { + newPending.splice(row.index, 1); + } + return newPending; + }); + }, + [] ); - return ( - - -
- - Language + const columns = useMemo[]>( + () => [ + { + id: "name", + Header: "File", + accessor: (d) => d.file.name, + }, + { + Header: "Forced", + accessor: "forced", + Cell: ({ row, value, update }) => { + const { original, index } = row; + return ( + { + const newInfo = { ...row.original }; + newInfo.forced = v.target.checked; + update && update(row, newInfo); + }} + > + ); + }, + }, + { + Header: "Language", + accessor: "language", + className: "w-25", + Cell: ({ row, update, value }) => { + return ( { - if (lang) { - setLanguage(lang); + if (lang && update) { + const newInfo = { ...row.original }; + newInfo.language = lang; + update(row, newInfo); } }} > - + ); + }, + }, + { + accessor: "file", + Cell: ({ row, update }) => { + return ( + + ); + }, + }, + ], + [availableLanguages] + ); + + const canUpload = pending.length > 0; + + const footer = ( + + ); + + return ( + + + - Subtitle File { - setFile(list[0]); - }} + disabled={canUpload || availableLanguages.length === 0} + multiple + value={filelist} + onChange={setFiles} > - - setForced(e.target.checked)} - label="Forced" - > - +
); diff --git a/frontend/src/components/modals/SeriesUploadModal.tsx b/frontend/src/components/modals/SeriesUploadModal.tsx index 7de4545fc..f0efa5a50 100644 --- a/frontend/src/components/modals/SeriesUploadModal.tsx +++ b/frontend/src/components/modals/SeriesUploadModal.tsx @@ -14,13 +14,7 @@ import React, { } from "react"; import { Button, Container, Form } from "react-bootstrap"; import { Column, TableUpdater } from "react-table"; -import { - AsyncButton, - FileForm, - LanguageSelector, - MessageIcon, - SimpleTable, -} from ".."; +import { FileForm, LanguageSelector, MessageIcon, SimpleTable } from ".."; import { dispatchTask } from "../../@modules/task"; import { createTask } from "../../@modules/task/utilites"; import { useProfileBy, useProfileItemsToLanguages } from "../../@redux/hooks"; @@ -53,8 +47,6 @@ const SeriesUploadModal: FunctionComponent = ({ modal.modalKey ); - const [uploading, setUpload] = useState(false); - const [pending, setPending] = useState([]); const profile = useProfileBy(payload?.profileId); @@ -119,7 +111,7 @@ const SeriesUploadModal: FunctionComponent = ({ [checkEpisodes] ); - const uploadSubtitles = useCallback(async () => { + const upload = useCallback(() => { if (payload === null || language === null) { return; } @@ -150,7 +142,9 @@ const SeriesUploadModal: FunctionComponent = ({ }); dispatchTask(TaskGroupName, tasks, "Uploading subtitles..."); - }, [payload, pending, language]); + setFiles([]); + closeModal(); + }, [payload, pending, language, closeModal, setFiles]); const canUpload = useMemo( () => @@ -234,7 +228,6 @@ const SeriesUploadModal: FunctionComponent = ({ return ( = ({ - { - closeModal(); - setFiles([]); - }} - > + ); return ( - +