mirror of https://github.com/morpheus65535/bazarr
241 lines
6.3 KiB
TypeScript
241 lines
6.3 KiB
TypeScript
import { faBookmark as farBookmark } from "@fortawesome/free-regular-svg-icons";
|
|
import {
|
|
faBookmark,
|
|
faBriefcase,
|
|
faHistory,
|
|
faUser,
|
|
} from "@fortawesome/free-solid-svg-icons";
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { useShowOnlyDesired } from "@redux/hooks";
|
|
import { useDownloadEpisodeSubtitles } from "apis/hooks";
|
|
import {
|
|
ActionButton,
|
|
EpisodeHistoryModal,
|
|
GroupTable,
|
|
SubtitleToolModal,
|
|
TextPopover,
|
|
useShowModal,
|
|
} from "components";
|
|
import { ManualSearchModal } from "components/modals/ManualSearchModal";
|
|
import React, { FunctionComponent, useCallback, useMemo } from "react";
|
|
import { Badge, ButtonGroup } from "react-bootstrap";
|
|
import { Column, TableUpdater } from "react-table";
|
|
import { BuildKey, filterSubtitleBy } from "utilities";
|
|
import { useProfileItemsToLanguages } from "utilities/languages";
|
|
import { SubtitleAction } from "./components";
|
|
|
|
interface Props {
|
|
series?: Item.Series;
|
|
episodes: Item.Episode[];
|
|
disabled?: boolean;
|
|
profile?: Language.Profile;
|
|
}
|
|
|
|
const Table: FunctionComponent<Props> = ({
|
|
series,
|
|
episodes,
|
|
profile,
|
|
disabled,
|
|
}) => {
|
|
const showModal = useShowModal();
|
|
|
|
const onlyDesired = useShowOnlyDesired();
|
|
|
|
const profileItems = useProfileItemsToLanguages(profile);
|
|
const { mutateAsync } = useDownloadEpisodeSubtitles();
|
|
|
|
const download = useCallback(
|
|
(item: Item.Episode, result: SearchResultType) => {
|
|
const {
|
|
language,
|
|
hearing_impaired: hi,
|
|
forced,
|
|
provider,
|
|
subtitle,
|
|
original_format,
|
|
} = result;
|
|
const { sonarrSeriesId: seriesId, sonarrEpisodeId: episodeId } = item;
|
|
|
|
return mutateAsync({
|
|
seriesId,
|
|
episodeId,
|
|
form: {
|
|
language,
|
|
hi,
|
|
forced,
|
|
provider,
|
|
subtitle,
|
|
original_format: original_format,
|
|
},
|
|
});
|
|
},
|
|
[mutateAsync]
|
|
);
|
|
|
|
const columns: Column<Item.Episode>[] = useMemo<Column<Item.Episode>[]>(
|
|
() => [
|
|
{
|
|
accessor: "monitored",
|
|
Cell: (row) => {
|
|
return (
|
|
<FontAwesomeIcon
|
|
title={row.value ? "monitored" : "unmonitored"}
|
|
icon={row.value ? faBookmark : farBookmark}
|
|
></FontAwesomeIcon>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
accessor: "season",
|
|
Cell: (row) => {
|
|
return `Season ${row.value}`;
|
|
},
|
|
},
|
|
{
|
|
Header: "Episode",
|
|
accessor: "episode",
|
|
},
|
|
{
|
|
Header: "Title",
|
|
accessor: "title",
|
|
className: "text-nowrap",
|
|
Cell: ({ value, row }) => (
|
|
<TextPopover text={row.original.sceneName} delay={1}>
|
|
<span>{value}</span>
|
|
</TextPopover>
|
|
),
|
|
},
|
|
{
|
|
Header: "Audio",
|
|
accessor: "audio_language",
|
|
Cell: (row) => {
|
|
return row.value.map((v) => (
|
|
<Badge variant="secondary" key={v.code2}>
|
|
{v.name}
|
|
</Badge>
|
|
));
|
|
},
|
|
},
|
|
{
|
|
Header: "Subtitles",
|
|
accessor: "missing_subtitles",
|
|
Cell: ({ row }) => {
|
|
const episode = row.original;
|
|
|
|
const seriesid = episode.sonarrSeriesId;
|
|
|
|
const elements = useMemo(() => {
|
|
const episodeid = episode.sonarrEpisodeId;
|
|
|
|
const missing = episode.missing_subtitles.map((val, idx) => (
|
|
<SubtitleAction
|
|
missing
|
|
key={BuildKey(idx, val.code2, "missing")}
|
|
seriesId={seriesid}
|
|
episodeId={episodeid}
|
|
subtitle={val}
|
|
></SubtitleAction>
|
|
));
|
|
|
|
let raw_subtitles = episode.subtitles;
|
|
if (onlyDesired) {
|
|
raw_subtitles = filterSubtitleBy(raw_subtitles, profileItems);
|
|
}
|
|
|
|
const subtitles = raw_subtitles.map((val, idx) => (
|
|
<SubtitleAction
|
|
key={BuildKey(idx, val.code2, "valid")}
|
|
seriesId={seriesid}
|
|
episodeId={episodeid}
|
|
subtitle={val}
|
|
></SubtitleAction>
|
|
));
|
|
|
|
return [...missing, ...subtitles];
|
|
}, [episode, seriesid]);
|
|
|
|
return elements;
|
|
},
|
|
},
|
|
{
|
|
Header: "Actions",
|
|
accessor: "sonarrEpisodeId",
|
|
Cell: ({ row, update }) => {
|
|
return (
|
|
<ButtonGroup>
|
|
<ActionButton
|
|
icon={faUser}
|
|
disabled={series?.profileId === null || disabled}
|
|
onClick={() => {
|
|
update && update(row, "manual-search");
|
|
}}
|
|
></ActionButton>
|
|
<ActionButton
|
|
icon={faHistory}
|
|
disabled={disabled}
|
|
onClick={() => {
|
|
update && update(row, "history");
|
|
}}
|
|
></ActionButton>
|
|
<ActionButton
|
|
icon={faBriefcase}
|
|
disabled={disabled}
|
|
onClick={() => {
|
|
update && update(row, "tools");
|
|
}}
|
|
></ActionButton>
|
|
</ButtonGroup>
|
|
);
|
|
},
|
|
},
|
|
],
|
|
[onlyDesired, profileItems, series, disabled]
|
|
);
|
|
|
|
const updateRow = useCallback<TableUpdater<Item.Episode>>(
|
|
(row, modalKey: string) => {
|
|
if (modalKey === "tools") {
|
|
showModal(modalKey, [row.original]);
|
|
} else {
|
|
showModal(modalKey, row.original);
|
|
}
|
|
},
|
|
[showModal]
|
|
);
|
|
|
|
const maxSeason = useMemo(
|
|
() =>
|
|
episodes.reduce<number>((prev, curr) => Math.max(prev, curr.season), 0),
|
|
[episodes]
|
|
);
|
|
|
|
return (
|
|
<React.Fragment>
|
|
<GroupTable
|
|
columns={columns}
|
|
data={episodes}
|
|
update={updateRow}
|
|
initialState={{
|
|
sortBy: [
|
|
{ id: "season", desc: true },
|
|
{ id: "episode", desc: true },
|
|
],
|
|
groupBy: ["season"],
|
|
expanded: {
|
|
[`season:${maxSeason}`]: true,
|
|
},
|
|
}}
|
|
emptyText="No Episode Found For This Series"
|
|
></GroupTable>
|
|
<SubtitleToolModal modalKey="tools" size="lg"></SubtitleToolModal>
|
|
<EpisodeHistoryModal modalKey="history" size="lg"></EpisodeHistoryModal>
|
|
<ManualSearchModal
|
|
modalKey="manual-search"
|
|
download={download}
|
|
></ManualSearchModal>
|
|
</React.Fragment>
|
|
);
|
|
};
|
|
|
|
export default Table;
|