import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { postSpotifyDownload, type InputType } from "../endpoints/spotify-download_POST.schema"; import { getSpotifyDownloadStatus, spotifyDownloadFileUrl, } from "../endpoints/spotify-download-status_GET.schema"; import { getSpotifySession } from "../endpoints/spotify-session_GET.schema"; import { getDesktopBridge } from "./desktopBridge"; const POLL_INTERVAL_MS = 1500; let canDownloadPromise: Promise | undefined; function loadCanDownload() { canDownloadPromise ??= getSpotifySession() .then((session) => { const allowed = Boolean(session.connected && session.canDownload); if (!allowed) canDownloadPromise = undefined; return allowed; }) .catch(() => { canDownloadPromise = undefined; return false; }); return canDownloadPromise; } function saveFromServer(jobId: string) { const anchor = document.createElement("a"); anchor.href = spotifyDownloadFileUrl(jobId); anchor.rel = "noopener"; document.body.appendChild(anchor); anchor.click(); anchor.remove(); } export function useSpotifyDownload() { const [busyKeys, setBusyKeys] = useState>(new Set()); const [canDownload, setCanDownload] = useState(false); const mounted = useRef(true); useEffect(() => { mounted.current = true; loadCanDownload().then((allowed) => { if (mounted.current) setCanDownload(allowed); }); return () => { mounted.current = false; }; }, []); function setBusy(key: string, busy: boolean) { setBusyKeys((current) => { const next = new Set(current); if (busy) next.add(key); else next.delete(key); return next; }); } async function startDownload(key: string, label: string, request: InputType) { if (busyKeys.has(key)) return; setBusy(key, true); const toastId = toast.loading(`Preparing ${label}…`); try { const { jobId } = await postSpotifyDownload(request); while (mounted.current) { await new Promise((resolve) => window.setTimeout(resolve, POLL_INTERVAL_MS)); const status = await getSpotifyDownloadStatus(jobId); if (status.status === "failed") throw new Error(status.error || "Download failed."); if (status.status === "ready") { const skipped = status.failed ? ` (${status.failed} track${status.failed === 1 ? "" : "s"} could not be found)` : ""; const desktop = getDesktopBridge(); if (desktop && status.savedPath) { const savedPath = status.savedPath; toast.success(`Saved ${label}${skipped}`, { id: toastId, description: savedPath, action: { label: "Show in folder", onClick: () => desktop.showInFolder(savedPath) }, }); } else { saveFromServer(jobId); toast.success(`Downloading ${status.fileName}${skipped}`, { id: toastId, description: undefined }); } return; } if (status.total > 1) { toast.loading(`Downloading ${label}: ${status.done} of ${status.total}`, { id: toastId, description: status.currentTitle, }); } } toast.dismiss(toastId); } catch (reason) { toast.error(reason instanceof Error ? reason.message : "Download failed.", { id: toastId }); } finally { if (mounted.current) setBusy(key, false); } } return { busyKeys, canDownload, startDownload }; }