Experiment to rebuild Diffuse using web applets.
1import * as URI from "uri-js";
2
3import type {
4 Consult,
5 ConsultGrouping,
6 GroupConsult,
7 InputWorkerTasks,
8 Track,
9} from "@applets/core/types";
10import { groupTracksPerScheme, initialConnections, provide } from "@scripts/common";
11
12////////////////////////////////////////////
13// SETUP
14////////////////////////////////////////////
15const actions = {
16 consult,
17 contextualize,
18 groupConsult,
19 list,
20 resolve,
21};
22
23const { connections, tasks } = provide({
24 actions,
25 connections: initialConnections<InputWorkerTasks>(["file+local", "opensubsonic", "s3"]),
26 tasks: actions,
27});
28
29export type Actions = typeof actions;
30export type Tasks = typeof tasks;
31
32function isSupportedScheme(scheme: string) {
33 return !!connections[scheme];
34}
35
36////////////////////////////////////////////
37// ACTIONS
38////////////////////////////////////////////
39
40async function consult(fileUriOrScheme: string): Promise<Consult> {
41 const scheme = fileUriOrScheme.includes(":")
42 ? URI.parse(fileUriOrScheme).scheme || fileUriOrScheme
43 : fileUriOrScheme;
44
45 if (!isSupportedScheme(scheme)) {
46 return { supported: false, reason: "Unsupported scheme" };
47 }
48
49 const conn = await connections[scheme].promise;
50 return conn.consult(fileUriOrScheme);
51}
52
53async function contextualize(tracks: Track[]) {
54 const groups = groupTracks(tracks);
55 const promises = Object.entries(groups).map(async ([scheme, tracksGroup]: [string, Track[]]) => {
56 if (!isSupportedScheme(scheme) || tracksGroup.length === 0) return;
57 const conn = await connections[scheme].promise;
58 await conn.contextualize(tracksGroup);
59 });
60
61 await Promise.all(promises);
62}
63
64async function groupConsult(tracks: Track[]) {
65 const groups = groupTracksPerScheme(tracks);
66
67 const consultations: GroupConsult[] = await Promise.all(
68 Object.keys(groups).map(async (scheme) => {
69 if (!isSupportedScheme(scheme)) {
70 return {
71 [scheme]: {
72 available: false,
73 reason: "Unsupported scheme",
74 tracks: groups[scheme] || [],
75 },
76 };
77 }
78
79 const conn = await connections[scheme].promise;
80 const result = await conn.groupConsult(groups[scheme] || {});
81
82 return result;
83 }),
84 );
85
86 return consultations.reduce((acc: GroupConsult, c: GroupConsult) => {
87 return { ...acc, ...c };
88 }, {});
89}
90
91async function list(cachedTracks: Track[] = []) {
92 const groups = await groupConsult(cachedTracks);
93
94 Object.keys(connections).forEach((scheme) => {
95 if (!groups[scheme]) groups[scheme] = { available: true, tracks: [] };
96 });
97
98 const promises = Object.entries(groups).map(
99 async ([scheme, { available, tracks }]: [string, ConsultGrouping]) => {
100 if (!available) return tracks;
101 if (!isSupportedScheme(scheme)) return tracks;
102 const conn = await connections[scheme].promise;
103 return conn.list(tracks);
104 },
105 );
106
107 const nested = await Promise.all(promises);
108 const tracks = nested.flat(1);
109
110 return tracks;
111}
112
113async function resolve(args: { method: string; uri: string }) {
114 const scheme = args.uri.split(":", 1)[0];
115 if (!isSupportedScheme(scheme)) return undefined;
116
117 try {
118 const conn = await connections[scheme].promise;
119 return await conn.resolve(args);
120 } catch (err) {
121 console.error(`[configuration/input] Resolve error for scheme '${scheme}'.`, err);
122 }
123}
124
125////////////////////////////////////////////
126// 🛠️
127////////////////////////////////////////////
128
129function groupTracks(tracks: Track[]) {
130 const grouped = groupTracksPerScheme(
131 tracks,
132 Object.fromEntries(
133 Object.entries(connections).map(([k, _v]) => {
134 return [k, []];
135 }),
136 ),
137 );
138
139 return grouped;
140}