Experiment to rebuild Diffuse using web applets.
0

Configure Feed

Select the types of activity you want to include in your feed.

1import type { URLTrack } from "webamp"; 2import Webamp from "webamp"; 3 4import type { ManagedOutput, ResolvedUri, Track } from "@applets/core/types.d.ts"; 5import { applet, inputUrl, wait } from "@scripts/applet/common"; 6 7//////////////////////////////////////////// 8// 🗂️ Applets 9//////////////////////////////////////////// 10const configurator = { 11 input: await applet("/configurator/input"), 12 output: await applet<ManagedOutput>("/configurator/output"), 13}; 14 15const orchestrator = { 16 input: await applet("/orchestrator/input-cache"), 17}; 18 19//////////////////////////////////////////// 20// ⚡ 21//////////////////////////////////////////// 22const amp = new Webamp({ 23 initialTracks: [], 24}); 25 26// Override 27const loadFromUrl = amp.media.loadFromUrl.bind(amp.media); 28 29async function loadOverride(uri: string, autoPlay: boolean) { 30 const resp = await inputUrl(configurator.input, uri); 31 if (!resp) throw new Error("Failed to resolve URI"); 32 return await loadFromUrl(resp.url, autoPlay); 33} 34 35amp.media.loadFromUrl = loadOverride.bind(amp.media); 36 37// Render 38const ampNode = document.createElement("div"); 39ampNode.style = "height: 100vh; left: 0; position: absolute; top: 0; width: 100%; z-index: -1000;"; 40document.body.appendChild(ampNode); 41amp.renderWhenReady(ampNode); 42 43// Wait for tracks to load 44wait(configurator.output, (d) => d?.tracks.state === "loaded").then(loadAndInsert); 45configurator.output.ondata = loadAndInsert; 46 47// Load & insert 48let inserting = false; 49 50async function loadAndInsert() { 51 if (configurator.output.data.tracks.state !== "loaded") return; 52 if (inserting) return; 53 inserting = true; 54 const tracks = await loadTracks(); 55 56 // TODO: This kinda messes up the UI, 57 // but at least the active audio doesn't stop playing. 58 amp.store.dispatch({ type: "REMOVE_ALL_TRACKS" }); 59 60 // TODO: Webamp blows up if you add too much tracks 61 amp.appendTracks(tracks.slice(0, 1000)); 62 63 const status = amp.getMediaStatus(); 64 if (status !== "PLAYING") amp.nextTrack(); 65 66 inserting = false; 67} 68 69//////////////////////////////////////////// 70// 🛠️ 71//////////////////////////////////////////// 72async function loadTracks(): Promise<URLTrack[]> { 73 const tracks = configurator.output.data.tracks.collection; 74 return tracks.map((track) => { 75 const urlTrack: URLTrack = { 76 url: track.uri, 77 metaData: { 78 title: track.tags?.title || "", 79 artist: track.tags?.artist || "", 80 album: track.tags?.album, 81 }, 82 duration: track.stats?.duration, 83 }; 84 85 return urlTrack; 86 }); 87}