import { useEffect } from "react"; import { ProxyImage } from "@/components/custom/proxyImage"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { toast } from "sonner"; import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useLibraryPageStatesStore } from "@/services/store"; import { formatBitrate, formatCodec, formatDurationString, formatFileSize, paginate } from "@/utils"; import { ArrowUpRightIcon, AudioLines, CircleArrowDown, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Music, Play, Search, Trash2, Video } from "lucide-react"; import { invoke } from "@tauri-apps/api/core"; import * as fs from "@tauri-apps/plugin-fs"; import { dirname } from "@tauri-apps/api/path"; import { DownloadState } from "@/types/download"; import { useQueryClient } from "@tanstack/react-query"; import { useDeleteDownloadState } from "@/services/mutations"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"; import { Checkbox } from "@/components/ui/checkbox"; import { Label } from "@/components/ui/label"; import { useNavigate } from "react-router-dom"; import { useLogger } from "@/helpers/use-logger"; import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty"; import PaginationBar from "@/components/custom/paginationBar"; interface CompletedDownloadProps { state: DownloadState; } interface CompletedDownloadsProps { downloads: DownloadState[]; } export function CompletedDownload({ state }: CompletedDownloadProps) { const downloadActions = useDownloadActionStatesStore(state => state.downloadActions); const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked); const queryClient = useQueryClient(); const downloadStateDeleter = useDeleteDownloadState(); const navigate = useNavigate(); const LOG = useLogger(); const openFile = async (filePath: string | null, app: string | null) => { if (filePath && await fs.exists(filePath)) { try { await invoke('open_file_with_app', { filePath: filePath, appName: app }).then(() => { toast.info(`${app === 'explorer' ? 'Revealing' : 'Opening'} file`, { description: `${app === 'explorer' ? 'Revealing' : 'Opening'} the file ${app === 'explorer' ? 'in' : 'with'} ${app ? app : 'default app'}.`, }) }); } catch (e) { console.error(e); toast.error(`Failed to ${app === 'explorer' ? 'reveal' : 'open'} file`, { description: `An error occurred while trying to ${app === 'explorer' ? 'reveal' : 'open'} the file.`, }) } } else { toast.info("File unavailable", { description: `The file you are trying to ${app === 'explorer' ? 'reveal' : 'open'} does not exist.`, }) } } const removeFromDownloads = async (downloadState: DownloadState, delete_file: boolean) => { if (delete_file && downloadState.filepath) { const isMutilplePlaylistItems = downloadState.playlist_id !== null && downloadState.playlist_indices !== null && downloadState.playlist_indices.includes(','); if (isMutilplePlaylistItems) { const dirPath = await dirname(downloadState.filepath); try { if (await fs.exists(dirPath)) { await fs.remove(dirPath, { recursive: true }); } else { console.error(`Directory not found: "${dirPath}"`); } } catch (e) { console.error(e); } } else { try { if (await fs.exists(downloadState.filepath)) { await fs.remove(downloadState.filepath); } else { console.error(`File not found: "${downloadState.filepath}"`); } } catch (e) { console.error(e); } } } downloadStateDeleter.mutate(downloadState.download_id, { onSuccess: (data) => { console.log("Download State deleted successfully:", data); queryClient.invalidateQueries({ queryKey: ['download-states'] }); if (delete_file && downloadState.filepath) { toast.success("Deleted from downloads", { description: `The download for ${isMutilplePlaylistItems ? 'playlist ' : ''}"${isMutilplePlaylistItems ? downloadState.playlist_title : downloadState.title}" has been deleted successfully.`, }); } else { toast.success("Removed from downloads", { description: `The download for ${isMutilplePlaylistItems ? 'playlist ' : ''}"${isMutilplePlaylistItems ? downloadState.playlist_title : downloadState.title}" has been removed successfully.`, }); } }, onError: (error) => { console.error("Failed to delete download state:", error); if (delete_file && downloadState.filepath) { toast.error("Failed to delete download", { description: `An error occurred while trying to delete the download for ${isMutilplePlaylistItems ? 'playlist ' : ''}"${isMutilplePlaylistItems ? downloadState.playlist_title : downloadState.title}".`, }); } else { toast.error("Failed to remove download", { description: `An error occurred while trying to remove the download for ${isMutilplePlaylistItems ? 'playlist ' : ''}"${isMutilplePlaylistItems ? downloadState.playlist_title : downloadState.title}".`, }); } } }) } const handleSearch = async (url: string, isPlaylist: boolean) => { try { LOG.info('NEODLP', `Received search request from library for URL: ${url}`); navigate('/'); const { setRequestedUrl, setAutoSubmitSearch } = useCurrentVideoMetadataStore.getState(); setRequestedUrl(url); setAutoSubmitSearch(true); toast.info(`Initiating ${isPlaylist ? 'Playlist' : 'Video'} Search`, { description: `Initiating search for the selected ${isPlaylist ? 'playlist' : 'video'}.`, }); } catch (e) { console.error(e); toast.error("Failed to initiate search", { description: "An error occurred while trying to initiate the search.", }); } } const itemActionStates = downloadActions[state.download_id] || { isResuming: false, isPausing: false, isCanceling: false, isDeleteFileChecked: false, }; const isPlaylist = state.playlist_id !== null && state.playlist_indices !== null; const isMutilplePlaylistItems = isPlaylist && state.playlist_indices && state.playlist_indices.includes(','); return (
{isMutilplePlaylistItems ? (
) : ( )} {isMutilplePlaylistItems ? ( Playlist ({state.playlist_indices?.split(',').length}) ) : ( {state.filetype && (state.filetype === 'video' || state.filetype === 'video+audio') && ( )}

{isMutilplePlaylistItems ? state.playlist_title : state.title}

{isMutilplePlaylistItems ? state.playlist_channel ?? 'unknown' : state.channel ?? 'unknown'} {state.host ? <> {state.host} : 'unknown'}

{isMutilplePlaylistItems ? ( <> {state.playlist_n_entries ?? 'unknown'} ) : ( <> {state.duration_string ? formatDurationString(state.duration_string) : 'unknown'} )} {state.filetype && (state.filetype === 'video' || state.filetype === 'video+audio') && ( )} {state.filetype && state.filetype === 'audio' && ( )} {(!state.filetype) || (state.filetype && state.filetype !== 'video' && state.filetype !== 'audio' && state.filetype !== 'video+audio') && ( )} {state.filesize ? formatFileSize(state.filesize) : 'unknown'} {state.vbr && state.abr ? ( formatBitrate(state.vbr + state.abr) ) : state.vbr ? ( formatBitrate(state.vbr) ) : state.abr ? ( formatBitrate(state.abr) ) : ( 'unknown' )}
{state.playlist_id && state.playlist_indices && !isMutilplePlaylistItems && ( Playlist ({state.playlist_indices} of {state.playlist_n_entries}) )} {state.vcodec && !isMutilplePlaylistItems && ( {formatCodec(state.vcodec)} )} {state.acodec && !isMutilplePlaylistItems && ( {formatCodec(state.acodec)} )} {state.dynamic_range && state.dynamic_range !== 'SDR' && !isMutilplePlaylistItems && ( {state.dynamic_range} )} {state.subtitle_id && ( ESUB )} {state.sponsorblock_mark && ( SPBLOCK(M) )} {state.sponsorblock_remove && ( SPBLOCK(R) )}
Remove from library? Are you sure you want to remove this download from the library? You can also delete the downloaded file by cheking the box below. This action cannot be undone.
{setIsDeleteFileChecked(state.download_id, !itemActionStates.isDeleteFileChecked)}} />
Cancel removeFromDownloads(state, itemActionStates.isDeleteFileChecked).then(() => { setIsDeleteFileChecked(state.download_id, false); }) }>Remove
); } export function CompletedDownloads({ downloads }: CompletedDownloadsProps) { const activeCompletedDownloadsPage = useLibraryPageStatesStore(state => state.activeCompletedDownloadsPage); const setActiveCompletedDownloadsPage = useLibraryPageStatesStore(state => state.setActiveCompletedDownloadsPage); const navigate = useNavigate(); const paginatedCompletedDownloads = paginate(downloads, activeCompletedDownloadsPage, 5); // Ensure current page is valid when downloads change useEffect(() => { if (downloads.length > 0 && activeCompletedDownloadsPage > paginatedCompletedDownloads.last_page) { setActiveCompletedDownloadsPage(paginatedCompletedDownloads.last_page); } }, [downloads.length, activeCompletedDownloadsPage, paginatedCompletedDownloads.last_page, setActiveCompletedDownloadsPage]); return (
{paginatedCompletedDownloads.data.length > 0 ? ( <> {paginatedCompletedDownloads.data.map((state) => { return ( ); })} {paginatedCompletedDownloads.pages.length > 1 && ( )} ) : ( No Completed Downloads You have not completed any downloads yet! Complete downloading something to see here :) )}
); }