Experiment to rebuild Diffuse using web applets.
1import * as IDB from "idb-keyval";
2import * as URI from "uri-js";
3import QS from "query-string";
4
5import type { Track } from "@applets/core/types.d.ts";
6import type { Handles } from "./types";
7import { isAudioFile } from "@scripts/input/common";
8import { IDB_HANDLES, SCHEME } from "./constants";
9
10////////////////////////////////////////////
11// 🛠️
12////////////////////////////////////////////
13export async function fetchHandles(): Promise<Handles> {
14 return (await IDB.get(IDB_HANDLES)) ?? {};
15}
16
17export async function fetchHandlesList() {
18 return Object.entries(await fetchHandles()).map(([id, handle]) => {
19 return { id, handle };
20 });
21}
22export function groupTracksByHandle(tracks: Track[]) {
23 return tracks.reduce((acc: Record<string, { tracks: Track[] }>, track: Track) => {
24 const id = trackHandleId(track);
25 if (!id) return acc;
26
27 const obj = { tracks: acc[id] ? [...acc[id].tracks, track] : [track] };
28 return { ...acc, [id]: obj };
29 }, {});
30}
31
32export function isSupported() {
33 return !!(globalThis as any).showDirectoryPicker;
34}
35
36export function trackCid(track: Track): string | undefined {
37 const a = URI.parse(track.uri);
38 const cid = a.query ? QS.parse(a.query).cid || undefined : undefined;
39 return Array.isArray(cid) && cid[0] ? cid[0] : typeof cid === "string" ? cid : undefined;
40}
41
42export function trackHandleId(track: Track): string | undefined {
43 const a = URI.parse(track.uri);
44 return a.host;
45}
46
47export async function recursiveList(
48 dir: FileSystemDirectoryHandle,
49 rootHandleId: string,
50 path: string[],
51): Promise<Track[]> {
52 const tracks: Track[] = [];
53
54 for await (const item of dir.values()) {
55 if (item.kind === "file" && isAudioFile(item.name)) {
56 const uri = URI.serialize({
57 scheme: SCHEME,
58 host: rootHandleId,
59 path: `${path.length ? "/" + path.join("/") : ""}/${item.name}`,
60 });
61
62 const track: Track = {
63 id: crypto.randomUUID(),
64 uri,
65 };
66
67 tracks.push(track);
68 } else if (item.kind === "directory") {
69 const nestedItems = await recursiveList(item as FileSystemDirectoryHandle, rootHandleId, [
70 ...path,
71 item.name,
72 ]);
73
74 tracks.push(...nestedItems);
75 }
76 }
77
78 return tracks;
79}