DownloadButton.tsx
⎇
Raw
1import "./DownloadButton.css";
2import type { MediaFile, Directory, FileListing } from "music-server-shared/types";
3import { deleteFile, download, signalMap, type SignalMapEntry } from "../offline";
4import { createSignal, type Accessor, type ResourceActions } from "solid-js";
5import type { AppOptions } from "../types";
6import { joinPath } from "../utils";
7import { DeleteSVG, DownloadSVG, RefreshSVG } from "./SVG";
8import { LoadingSpinner } from "./LoadingScreen";
9
10interface DownloadButtonProps {
11 fileName: string;
12 item: MediaFile | Directory;
13 fetchFiles: ResourceActions<FileListing>;
14 isOffline: Accessor<boolean>;
15 currentDir: Accessor<string>;
16 options: Accessor<AppOptions>;
17}
18
19function formatProgress(bytes: number): string {
20 if (bytes === 0) return "Queued...";
21
22 const k = 1024;
23 const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
24 const i = Math.floor(Math.log(bytes) / Math.log(k));
25 const value = bytes / k ** i;
26
27 return `${value.toFixed(2)} ${sizes[i]}`;
28}
29
30export function DownloadButton(props: DownloadButtonProps) {
31 const fullPath = joinPath(props.currentDir(), props.fileName);
32 let signal = signalMap.get(fullPath);
33 if (!signal) {
34 signal = createSignal<SignalMapEntry>();
35 signalMap.set(fullPath, signal);
36 }
37 const [getProgress] = signal;
38
39 return (
40 <div
41 class="download-item"
42 onClick={(event) => {
43 event.stopPropagation();
44 if (!props.isOffline())
45 download(props.fileName, props.item, props.currentDir(), props.currentDir, props.options(), props.fetchFiles);
46 else deleteFile(props.fileName, props.item, props.currentDir(), props.fetchFiles);
47 }}
48 >
49 {(() => {
50 const progress = getProgress();
51 if (progress === undefined) {
52 if (props.isOffline()) {
53 //only happens if this is a directory
54 return (
55 <button title="Purge the cache from all files recursively in this directory">
56 <DeleteSVG />
57 </button>
58 );
59 }
60 return (
61 <button title="Cache this file/directory on your browser for offline use">
62 <DownloadSVG />
63 </button>
64 );
65 }
66 if (progress === "DirectoryProgress") return <LoadingSpinner center={true} />;
67 if (progress === "CachedFile") {
68 if (props.isOffline()) {
69 return (
70 <button title="Purge this file from cache">
71 <DeleteSVG />
72 </button>
73 );
74 }
75 return (
76 <button title="Re-download this file">
77 <RefreshSVG />
78 </button>
79 );
80 }
81
82 if ("bytes" in progress) return <span>{formatProgress(progress.bytes)}</span>;
83 console.log(progress);
84 console.error("Unexpected", progress);
85 })()}
86 </div>
87 );
88}
89