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