{ ) : null} - {!data.rawFileDetails?.archive?.uncompressed ? ( + {isEmpty(uncompressedArchive) ? ( refetch()} diff --git a/src/client/components/ComicDetail/TorrentDownloads.tsx b/src/client/components/ComicDetail/TorrentDownloads.tsx new file mode 100644 index 0000000..4e2d7ed --- /dev/null +++ b/src/client/components/ComicDetail/TorrentDownloads.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import dayjs from "dayjs"; +import prettyBytes from "pretty-bytes"; + +export const TorrentDownloads = (props) => { + const { data } = props; + console.log(Object.values(data)); + return ( + <> + {data.map(({ torrent }) => { + return ( + + {torrent.name} + {torrent.hash} + + Added on {dayjs.unix(torrent.added_on).format("ddd, D MMM, YYYY")} + + + + {torrent.progress > 0 ? ( + <> + + + {Math.floor(torrent.progress * 100)}% + + {/* downloaded/left */} + + + + + + {prettyBytes(torrent.downloaded)} + + {/* uploaded */} + + + + + {prettyBytes(torrent.uploaded)} + + + > + ) : null} + + + {/* Peers */} + + + + + + {torrent.trackers_count} + + + + {/* Size */} + + + + + + {prettyBytes(torrent.total_size)} + + + + + ); + })} + > + ); +}; + +export default TorrentDownloads; diff --git a/src/client/components/ComicDetail/TorrentSearchPanel.tsx b/src/client/components/ComicDetail/TorrentSearchPanel.tsx index 983b561..f296e6a 100644 --- a/src/client/components/ComicDetail/TorrentSearchPanel.tsx +++ b/src/client/components/ComicDetail/TorrentSearchPanel.tsx @@ -1,16 +1,25 @@ -import React, { useCallback, ReactElement, useEffect, useState } from "react"; - -import { useQuery, useQueryClient } from "@tanstack/react-query"; +import React, { useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; import axios from "axios"; import { Form, Field } from "react-final-form"; -import { PROWLARR_SERVICE_BASE_URI } from "../../constants/endpoints"; +import { + PROWLARR_SERVICE_BASE_URI, + QBITTORRENT_SERVICE_BASE_URI, +} from "../../constants/endpoints"; +import { isEmpty, isNil } from "lodash"; +import ellipsize from "ellipsize"; +import prettyBytes from "pretty-bytes"; -export const TorrentSearchPanel = (props): ReactElement => { - const [prowlarrSettingsData, setProwlarrSettingsData] = useState({}); +export const TorrentSearchPanel = (props) => { + const { issueName, comicObjectId } = props; + // Initialize searchTerm with issueName from props + const [searchTerm, setSearchTerm] = useState({ issueName }); + const [torrentToDownload, setTorrentToDownload] = useState(""); - const { data } = useQuery({ - queryFn: async () => - axios({ + const { data, isSuccess, isLoading } = useQuery({ + queryKey: ["searchResults", searchTerm.issueName], + queryFn: async () => { + return await axios({ url: `${PROWLARR_SERVICE_BASE_URI}/search`, method: "POST", data: { @@ -18,58 +27,172 @@ export const TorrentSearchPanel = (props): ReactElement => { apiKey: "c4f42e265fb044dc81f7e88bd41c3367", offset: 0, categories: [7030], - query: "the darkness", + query: searchTerm.issueName, host: "localhost", limit: 100, type: "search", indexerIds: [2], }, - }), - queryKey: ["prowlarrSettingsData"], + }); + }, + enabled: !isNil(searchTerm.issueName) && searchTerm.issueName.trim() !== "", // Make sure searchTerm is not empty }); - console.log(data?.data); + const mutation = useMutation({ + mutationFn: async (newTorrent) => + axios.post(`${QBITTORRENT_SERVICE_BASE_URI}/addTorrent`, newTorrent), + onSuccess: async (data) => { + console.log(data); + }, + }); + const searchIndexer = (values) => { + setSearchTerm({ issueName: values.issueName }); // Update searchTerm based on the form submission + }; + const downloadTorrent = (evt) => { + const newTorrent = { + comicObjectId, + torrentToDownload: evt, + }; + mutation.mutate(newTorrent); + }; return ( <> {}} - initialValues={{}} - render={({ handleSubmit, form, submitting, pristine, values }) => ( + onSubmit={searchIndexer} + initialValues={searchTerm} + render={({ handleSubmit }) => ( - {({ input, meta }) => { - return ( - - - - - - - - - - Search Indexer - - - - - + {({ input, meta }) => ( + + + + {/* Icon placeholder */} + + + + + Search Indexer + + + + + - ); - }} + + )} )} /> + + + + The default search term is an auto-detected title; you may need to + change it to get better matches if the auto-detected one doesn't work. + + + {!isEmpty(data?.data) ? ( + + + + + + Name + + + Indexer + + + + Action + + + + + {data?.data.map((result, idx) => ( + + + {ellipsize(result.fileName, 90)} + {/* Seeders/Leechers */} + + + + + + + + {result.seeders} seeders + + + + + + + + + + {result.leechers} leechers + + + {/* Size */} + + + + + + + {prettyBytes(result.size)} + + + + {/* Files */} + + + + + + + {result.files} files + + + + + + + {result.indexer} + + + + downloadTorrent(result.downloadUrl)} + > + Download + + + + + + + ))} + + + + ) : null} > ); }; diff --git a/src/client/components/Library/Library.tsx b/src/client/components/Library/Library.tsx index 6d1f299..3d4bde2 100644 --- a/src/client/components/Library/Library.tsx +++ b/src/client/components/Library/Library.tsx @@ -178,7 +178,7 @@ export const Library = (): ReactElement => { - Torrent: {info.getValue().torrent.downloads.length} + Torrent: {info.getValue().torrent.length} diff --git a/src/client/components/Search/Search.tsx b/src/client/components/Search/Search.tsx index 07fe3db..ecc386d 100644 --- a/src/client/components/Search/Search.tsx +++ b/src/client/components/Search/Search.tsx @@ -1,9 +1,7 @@ import React, { useCallback, ReactElement, useState } from "react"; import { isNil, isEmpty } from "lodash"; import { IExtractedComicBookCoverFile, RootState } from "threetwo-ui-typings"; -import { importToDB } from "../../actions/fileops.actions"; -import { comicinfoAPICall } from "../../actions/comicinfo.actions"; -import { search } from "../../services/api/SearchApi"; + import { Form, Field } from "react-final-form"; import Card from "../shared/Carda"; import ellipsize from "ellipsize"; @@ -27,7 +25,6 @@ export const Search = ({}: ISearchProps): ReactElement => { const [comicVineMetadata, setComicVineMetadata] = useState({}); const getCVSearchResults = (searchQuery) => { setSearchQuery(searchQuery.search); - // queryClient.invalidateQueries({ queryKey: ["comicvineSearchResults"] }); }; const { @@ -146,6 +143,7 @@ export const Search = ({}: ISearchProps): ReactElement => { )} /> + {isLoading && <>Loading kaka...>} {!isNil(comicVineSearchResults?.data.results) && !isEmpty(comicVineSearchResults?.data.results) ? ( diff --git a/src/client/components/Settings/QbittorrentSettings/QbittorrentConnectionForm.tsx b/src/client/components/Settings/QbittorrentSettings/QbittorrentConnectionForm.tsx index 8b74121..e75ab4c 100644 --- a/src/client/components/Settings/QbittorrentSettings/QbittorrentConnectionForm.tsx +++ b/src/client/components/Settings/QbittorrentSettings/QbittorrentConnectionForm.tsx @@ -16,16 +16,7 @@ export const QbittorrentConnectionForm = (): ReactElement => { }); const hostDetails = data?.data?.bittorrent?.client?.host; // connect to qbittorrent client - const { data: connectionDetails } = useQuery({ - queryKey: [], - queryFn: async () => - await axios({ - url: "http://localhost:3060/api/qbittorrent/connect", - method: "POST", - data: hostDetails, - }), - enabled: !!hostDetails, - }); + // get qbittorrent client info const { data: qbittorrentClientInfo } = useQuery({ queryKey: ["qbittorrentClientInfo"], @@ -34,7 +25,6 @@ export const QbittorrentConnectionForm = (): ReactElement => { url: "http://localhost:3060/api/qbittorrent/getClientInfo", method: "GET", }), - enabled: !!connectionDetails, }); // Update action using a mutation const { mutate } = useMutation({ diff --git a/src/client/components/WantedComics/WantedComics.tsx b/src/client/components/WantedComics/WantedComics.tsx index 48435b0..4f06343 100644 --- a/src/client/components/WantedComics/WantedComics.tsx +++ b/src/client/components/WantedComics/WantedComics.tsx @@ -10,6 +10,7 @@ export const WantedComics = (props): ReactElement => { const { data: wantedComics, isSuccess, + isFetched, isError, isLoading, } = useQuery({ @@ -41,6 +42,7 @@ export const WantedComics = (props): ReactElement => { minWidth: 350, accessorFn: (data) => data, cell: (value) => { + console.log("ASDASd", value); const row = value.getValue()._source; return row && ; }, @@ -172,7 +174,7 @@ export const WantedComics = (props): ReactElement => { - {isSuccess ? ( + {isSuccess && wantedComics?.data.hits?.hits ? ( { - console.log(props); const { setter, apiAction } = props; const [selected, setSelected] = useState(); const [isPopperOpen, setIsPopperOpen] = useState(false); diff --git a/src/client/components/shared/MetadataPanel.tsx b/src/client/components/shared/MetadataPanel.tsx index f339548..781658d 100644 --- a/src/client/components/shared/MetadataPanel.tsx +++ b/src/client/components/shared/MetadataPanel.tsx @@ -16,7 +16,6 @@ interface IMetadatPanelProps { containerStyle: any; } export const MetadataPanel = (props: IMetadatPanelProps): ReactElement => { - console.log(props); const { rawFileDetails, inferredMetadata, diff --git a/src/client/constants/endpoints.ts b/src/client/constants/endpoints.ts index 30600fa..2fc2125 100644 --- a/src/client/constants/endpoints.ts +++ b/src/client/constants/endpoints.ts @@ -97,3 +97,10 @@ export const PROWLARR_SERVICE_BASE_URI = hostURIBuilder({ port: "3060", apiPath: `/api/prowlarr`, }); + +export const TORRENT_JOB_SERVICE_BASE_URI = hostURIBuilder({ + protocol: "http", + host: import.meta.env.UNDERLYING_HOSTNAME || "localhost", + port: "3000", + apiPath: `/api/torrentjobs`, +});
+ + The default search term is an auto-detected title; you may need to + change it to get better matches if the auto-detected one doesn't work. + +