Experiment to rebuild Diffuse using web applets.
1import { applet, reactive } from "@scripts/applet/common";
2
3////////////////////////////////////////////
4// 🗂️ Applets
5////////////////////////////////////////////
6import type * as AudioEngine from "@applets/engine/audio/types.d.ts";
7import type * as QueueEngine from "@applets/engine/queue/types.d.ts";
8
9import type * as AudioUI from "@applets/theme/pilot/audio/types";
10
11const engine = {
12 audio: await applet<AudioEngine.State>("/engine/audio"),
13 queue: await applet<QueueEngine.State>("/engine/queue"),
14};
15
16const orchestrator = {
17 primary: await applet("/orchestrator/primary"),
18};
19
20const ui = {
21 audio: await applet<AudioUI.State>("/theme/pilot/audio/", { setHeight: true }),
22};
23
24////////////////////////////////////////////
25// ⚙️ [Connections → Engines]
26// 🔉 AUDIO
27////////////////////////////////////////////
28
29// NOTE:
30// These could probably be optimised, but it works.
31
32reactive(
33 engine.audio,
34 (data) =>
35 data.isPlaying && (data.items[engine.queue.data.now?.id ?? Infinity]?.isPlaying ?? false),
36 (isPlaying) => ui.audio.sendAction("modifyIsPlaying", isPlaying),
37);
38
39reactive(
40 engine.audio,
41 (data) => data.items[engine.queue.data.now?.id ?? Infinity]?.progress ?? 0,
42 (progress: number) => ui.audio.sendAction("modifyProgress", progress),
43);
44
45////////////////////////////////////////////
46// 🌅 [Connections → UI]
47// 🔉 AUDIO
48////////////////////////////////////////////
49
50reactive(
51 ui.audio,
52 (data) => data.isPlaying,
53 async (isPlaying, setter) => {
54 const audioId = engine.queue.data.now?.id;
55
56 // Automatically start playing something if nothing is playing yet.
57 if (!audioId) {
58 if (isPlaying) {
59 const now = await engine.queue.sendAction("shift", { groupId: "main" });
60 if (!now) {
61 console.warn("No tracks available yet, try again later.");
62 await ui.audio.sendAction("modifyIsPlaying", false);
63 setter(false);
64 }
65 }
66 return;
67 }
68
69 // Otherwise just control the audio
70 if (isPlaying) {
71 engine.audio.sendAction("play", { audioId });
72 } else {
73 engine.audio.sendAction("pause", { audioId });
74 }
75 },
76);
77
78reactive(
79 ui.audio,
80 (data: AudioUI.State) => data.seekPosition,
81 (seekPosition) => {
82 if (seekPosition !== undefined && engine.queue.data.now?.id) {
83 engine.audio.sendAction("seek", {
84 percentage: seekPosition,
85 audioId: engine.queue.data.now.id,
86 });
87 }
88 },
89);