First working POC
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
<script lang="ts">
|
||||
import { downloads } from "$lib/stores/downloads";
|
||||
import { auth } from "$lib/stores/auth";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import DownloadButtonCore from "./DownloadButtonCore.svelte";
|
||||
import type { DownloadState } from "./DownloadButtonCore.svelte";
|
||||
|
||||
/**
|
||||
* Single audio track download button
|
||||
* @req: UR-011 - Download for offline playback
|
||||
* @req: UR-018 - Download entire albums or playlists
|
||||
* @req: DR-018 - Download buttons on library/album/player screens
|
||||
*/
|
||||
|
||||
interface Props {
|
||||
itemId: string;
|
||||
itemName?: string;
|
||||
artistName?: string;
|
||||
albumName?: string;
|
||||
size?: "sm" | "md" | "lg";
|
||||
className?: string;
|
||||
}
|
||||
|
||||
let { itemId, itemName = "", artistName = "", albumName = "", size = "md", className = "" }: Props = $props();
|
||||
|
||||
let isProcessing = $state(false);
|
||||
|
||||
// Find download for this item
|
||||
const downloadInfo = $derived(
|
||||
Object.values($downloads.downloads).find((d) => d.itemId === itemId)
|
||||
);
|
||||
|
||||
const status = $derived(downloadInfo?.status || "not_downloaded");
|
||||
const progress = $derived(downloadInfo?.progress || 0);
|
||||
|
||||
const buttonState = $derived<DownloadState>({
|
||||
status: (status as DownloadState["status"]) || "not_downloaded",
|
||||
progress: progress || 0,
|
||||
});
|
||||
|
||||
async function handleClick() {
|
||||
console.log("🖱️ Download button clicked! Current status:", status);
|
||||
if (isProcessing) return;
|
||||
|
||||
isProcessing = true;
|
||||
try {
|
||||
if (status === "completed") {
|
||||
// Delete download
|
||||
if (downloadInfo?.id) {
|
||||
await downloads.delete(downloadInfo.id);
|
||||
}
|
||||
} else if (status === "downloading" || status === "pending") {
|
||||
// Cancel download
|
||||
if (downloadInfo?.id) {
|
||||
await downloads.cancel(downloadInfo.id);
|
||||
}
|
||||
} else if (status === "failed") {
|
||||
// Retry failed download
|
||||
if (downloadInfo?.id) {
|
||||
await downloads.resume(downloadInfo.id);
|
||||
}
|
||||
} else {
|
||||
// Start download
|
||||
const userId = $auth.user?.id;
|
||||
if (!userId) {
|
||||
console.error("No user ID found");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const repo = auth.getRepository();
|
||||
|
||||
console.log("🎯 Starting download for item:", itemId);
|
||||
|
||||
// Get stream URL
|
||||
const streamUrl = await repo.getAudioStreamUrl(itemId);
|
||||
console.log(" Stream URL obtained:", streamUrl?.substring(0, 50) + "...");
|
||||
if (!streamUrl) {
|
||||
throw new Error("Failed to get stream URL");
|
||||
}
|
||||
|
||||
// Get target directory
|
||||
const targetDir = await invoke<string>("storage_get_path");
|
||||
console.log(" Target directory:", targetDir);
|
||||
|
||||
// Queue and start download in single atomic operation
|
||||
const downloadId = await invoke<number>("download_item_and_start", {
|
||||
itemId,
|
||||
userId,
|
||||
streamUrl,
|
||||
targetDir,
|
||||
itemName: itemName || undefined,
|
||||
artistName: artistName || undefined,
|
||||
albumName: albumName || undefined,
|
||||
});
|
||||
console.log(" Download queued and started with ID:", downloadId);
|
||||
|
||||
// Refresh downloads list
|
||||
await downloads.refresh(userId);
|
||||
} catch (e) {
|
||||
console.error("❌ Failed to start download:", e);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Download operation failed:", error);
|
||||
} finally {
|
||||
isProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getTitle(): string {
|
||||
switch (status) {
|
||||
case "completed":
|
||||
return "Downloaded - Click to remove";
|
||||
case "downloading":
|
||||
return `Downloading... ${Math.round(progress * 100)}%`;
|
||||
case "pending":
|
||||
return "Queued for download";
|
||||
case "paused":
|
||||
return "Download paused";
|
||||
case "failed":
|
||||
return "Download failed - Click to retry";
|
||||
default:
|
||||
return "Download for offline playback";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="p-2 rounded-full">
|
||||
<DownloadButtonCore {size} state={buttonState} title={getTitle()} onClick={handleClick} {isProcessing} {className} />
|
||||
</div>
|
||||
Reference in New Issue
Block a user