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 input: await applet("/orchestrator/input-cache"),
18 queueAudio: await applet("/orchestrator/queue-audio"),
19 queueTracks: await applet("/orchestrator/queue-tracks"),
20};
21
22const ui = {
23 audio: await applet<AudioUI.State>("/theme/pilot/audio/", { setHeight: true }),
24};
25
26////////////////////////////////////////////
27// ⚙️ [Connections → Engines]
28// 🔉 AUDIO
29////////////////////////////////////////////
30
31// NOTE:
32// These could probably be optimised, but it works.
33
34reactive(
35 engine.audio,
36 (data) =>
37 data.isPlaying && (data.items[engine.queue.data.now?.id ?? Infinity]?.isPlaying ?? false),
38 (isPlaying) => ui.audio.sendAction("modifyIsPlaying", isPlaying),
39);
40
41reactive(
42 engine.audio,
43 (data) => data.items[engine.queue.data.now?.id ?? Infinity]?.progress ?? 0,
44 (progress: number) => ui.audio.sendAction("modifyProgress", progress),
45);
46
47////////////////////////////////////////////
48// 🌅 [Connections → UI]
49// 🔉 AUDIO
50////////////////////////////////////////////
51
52reactive(
53 ui.audio,
54 (data) => data.isPlaying,
55 async (isPlaying, setter) => {
56 const audioId = engine.queue.data.now?.id;
57
58 // Automatically start playing something if nothing is playing yet.
59 if (!audioId) {
60 if (isPlaying) {
61 const now = await engine.queue.sendAction("shift");
62 if (!now) {
63 console.warn("No tracks available yet, try again later.");
64 await ui.audio.sendAction("modifyIsPlaying", false);
65 setter(false);
66 }
67 }
68 return;
69 }
70
71 // Otherwise just control the audio
72 if (isPlaying) {
73 engine.audio.sendAction("play", { audioId });
74 } else {
75 engine.audio.sendAction("pause", { audioId });
76 }
77 },
78);
79
80reactive(
81 ui.audio,
82 (data: AudioUI.State) => data.seekPosition,
83 (seekPosition) => {
84 if (seekPosition !== undefined && engine.queue.data.now?.id) {
85 engine.audio.sendAction("seek", {
86 percentage: seekPosition,
87 audioId: engine.queue.data.now.id,
88 });
89 }
90 },
91);