Experiment to rebuild Diffuse using web applets.
1<script>
2 import { applets } from "@web-applets/sdk";
3
4 import type { Output, Track, TrackStats, TrackTags } from "@applets/core/types.d.ts";
5 import { applet, waitUntilAppletIsReady } from "@scripts/theme";
6
7 ////////////////////////////////////////////
8 // SETUP
9 ////////////////////////////////////////////
10 const context = applets.register<{ ready: boolean }>();
11
12 // Initial data
13 context.data = {
14 ready: false,
15 };
16
17 // Applet connections
18 const configurator = {
19 input: await applet("../../configurator/input", { context: self.top || self.parent }),
20 };
21
22 const orchestrator = {
23 output: await applet<Output>("../../orchestrator/output-management", {
24 context: self.parent,
25 }),
26 };
27
28 const processor = {
29 metadataFetcher: await applet("../../processor/metadata-fetcher", { context: self.parent }),
30 };
31
32 // 🚀
33 process();
34
35 ////////////////////////////////////////////
36 // ACTIONS
37 ////////////////////////////////////////////
38 context.setActionHandler("process", process);
39
40 async function process() {
41 await waitUntilAppletIsReady(configurator.input);
42
43 const cachedTracks = orchestrator.output.data.tracks;
44 const tracks = await configurator.input.sendAction<Track[]>("list", cachedTracks, {
45 timeoutDuration: 60000 * 60 * 24,
46 });
47
48 // Process
49 const tracksWithMetadata = await tracks.reduce(
50 async (promise: Promise<Track[]>, track: Track) => {
51 const acc = await promise;
52
53 if (track.tags) return [...acc, track];
54
55 const getURL = await configurator.input.sendAction<string | undefined>(
56 "resolve",
57 { method: "GET", uri: track.uri },
58 {
59 timeoutDuration: 60000,
60 },
61 );
62
63 if (!getURL) return acc;
64
65 // TODO: Do we need to pass the HEAD URL too?
66 const meta = await processor.metadataFetcher.sendAction("extract", getURL, {
67 timeoutDuration: 60000,
68 });
69
70 const stats: TrackStats = {
71 duration: meta.format.duration,
72 };
73
74 const tags: TrackTags = {
75 album: meta.common.album,
76 artist: meta.common.artist,
77 title: meta.common.title,
78 };
79
80 return [...acc, { ...track, stats, tags }];
81 },
82 Promise.resolve([]),
83 );
84
85 // Save
86 await orchestrator.output.sendAction("tracks", tracksWithMetadata, {
87 timeoutDuration: 60000 * 2,
88 });
89
90 // Log
91 console.log("🪵 Processing completed");
92 }
93
94 ////////////////////////////////////////////
95 // 🚦
96 ////////////////////////////////////////////
97 context.data = { ready: true };
98</script>