import { faCaretDown, faCheck, faDownload, faInfoCircle, faTimes, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import React, { FunctionComponent, useCallback, useEffect, useMemo, useState, } from "react"; import { Badge, Button, Col, Collapse, Container, OverlayTrigger, Popover, Row, } from "react-bootstrap"; import { Column } from "react-table"; import { AsyncButton, BaseModal, BaseModalProps, LanguageText, LoadingIndicator, PageTable, useModalPayload, } from ".."; import { ProvidersApi } from "../../apis"; import { isMovie } from "../../utilites"; import "./msmStyle.scss"; type SupportType = Item.Movie | Item.Episode; enum SearchState { Ready, Searching, Finished, } interface Props { onSelect: (item: SupportType, result: SearchResultType) => Promise; onDownload?: () => void; } export const ManualSearchModal: FunctionComponent = ( props ) => { const { onSelect, onDownload, ...modal } = props; const [result, setResult] = useState([]); const [searchState, setSearchState] = useState(SearchState.Ready); const item = useModalPayload(modal.modalKey); const search = useCallback(async () => { if (item) { setSearchState(SearchState.Searching); let results: SearchResultType[] = []; if (isMovie(item)) { results = await ProvidersApi.movies(item.radarrId); } else { results = await ProvidersApi.episodes(item.sonarrEpisodeId); } setResult(results); setSearchState(SearchState.Finished); } }, [item]); useEffect(() => { if (item !== null) { setSearchState(SearchState.Ready); } }, [item]); const columns = useMemo[]>( () => [ { Header: "Score", accessor: (d) => `${d.score}%`, }, { accessor: "language", Cell: ({ row: { original }, value }) => { const lang: Language.Info = { code2: value, hi: original.hearing_impaired === "True", forced: original.forced === "True", name: "", }; return ( ); }, }, { Header: "Provider", accessor: "provider", Cell: (row) => { const value = row.value; const { url } = row.row.original; if (url) { return ( {value} ); } else { return value; } }, }, { Header: "Release", accessor: "release_info", className: "text-nowrap", Cell: (row) => { const value = row.value; const [open, setOpen] = useState(false); const items = useMemo( () => value.slice(1).map((v, idx) => ( {v} )), [value] ); if (value.length === 0) { return Cannot get release info; } const cls = [ "release-container", "d-flex", "justify-content-between", "align-items-center", ]; if (value.length > 1) { cls.push("release-multi"); } return (
setOpen((o) => !o)}>
{value[0]}
{items}
{value.length > 1 && ( )}
); }, }, { Header: "Upload", accessor: (d) => d.uploader ?? "-", }, { accessor: "matches", Cell: (row) => { const { matches, dont_matches } = row.row.original; return ; }, }, { accessor: "subtitle", Cell: ({ row, externalUpdate }) => { const result = row.original; return ( onSelect(item!, result)} onSuccess={() => externalUpdate && externalUpdate(row)} > ); }, }, ], [onSelect, item] ); const content = useMemo(() => { if (searchState === SearchState.Ready) { return (

{item?.path ?? ""}

); } else if (searchState === SearchState.Searching) { return ; } else { return (

{item?.path ?? ""}

); } }, [searchState, columns, result, search, item?.path, onDownload]); const footer = useMemo( () => ( ), [searchState, search] ); const title = useMemo(() => { let title = "Unknown"; if (item) { if (item.sceneName) { title = item.sceneName; } else if (isMovie(item)) { title = item.title; } else { title = item.title; } } return `Search - ${title}`; }, [item]); return ( {content} ); }; const StateIcon: FunctionComponent<{ matches: string[]; dont: string[] }> = ({ matches, dont, }) => { let icon = faCheck; let color = "var(--success)"; if (dont.length > 0) { icon = faInfoCircle; color = "var(--warning)"; } const matchElements = useMemo( () => matches.map((v, idx) => (

{v}

)), [matches] ); const dontElements = useMemo( () => dont.map((v, idx) => (

{v}

)), [dont] ); const popover = useMemo( () => ( {matchElements} {dontElements} ), [matchElements, dontElements] ); return ( ); };