A music player that connects to your cloud/distributed storage.
0
fork

Configure Feed

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

at e68f727ec6d8bde0a9a06f73af2ebae7f10ffc5f 120 lines 3.3 kB view raw
1import * as TID from "@atcute/tid"; 2import { html } from "lit-html"; 3 4import * as Output from "~/common/output.js"; 5import { SCHEME } from "~/components/input/https/constants.js"; 6import { parseURI } from "~/components/input/https/common.js"; 7import { effect } from "~/common/signal.js"; 8import foundation from "~/common/foundation.js"; 9 10import { setup } from "~/facets/connect/common.js"; 11 12foundation.setup({ title: "Connect HTTPS | Diffuse" }); 13 14//////////////////////////////////////////// 15// SETUP 16//////////////////////////////////////////// 17 18const [inputConfigurator, outputOrchestrator, sourcesOrchestrator] = 19 await Promise.all([ 20 foundation.configurator.input(), 21 foundation.orchestrator.output(), 22 foundation.orchestrator.sources(), 23 ]); 24 25await Promise.all([ 26 customElements.whenDefined(inputConfigurator.localName), 27 customElements.whenDefined(outputOrchestrator.localName), 28 customElements.whenDefined(sourcesOrchestrator.localName), 29]); 30 31//////////////////////////////////////////// 32// UI 33//////////////////////////////////////////// 34 35const { setItems, setError } = setup({ 36 title: "HTTPS", 37 hasOutput: false, 38 39 description: html` 40 <p>Add HTTPS urls as audio sources.</p> 41 `, 42 43 formFields: html` 44 <label>URL <input id="https-url" type="url" placeholder="https://example.com/audio.mp3" required></label> 45 `, 46 47 onSubmit: () => addUrl(), 48}); 49 50const urlInput = /** @type {HTMLInputElement} */ (document.querySelector("#https-url")); 51 52//////////////////////////////////////////// 53// REACTIVE LIST 54//////////////////////////////////////////// 55 56effect(() => { 57 const inputSources = sourcesOrchestrator.sources()[SCHEME] ?? []; 58 59 setItems( 60 inputSources.map((source) => { 61 const parsed = parseURI(source.uri); 62 return { 63 name: source.uri, 64 detail: parsed?.host ?? "", 65 isInput: true, 66 isOutput: false, 67 isSelectedOutput: false, 68 isDisabled: sourcesOrchestrator.isDisabled(source.uri), 69 onRemove: () => removeUrl(source.uri), 70 onToggleDisabled: () => sourcesOrchestrator.toggle(source.uri), 71 }; 72 }), 73 ); 74}); 75//////////////////////////////////////////// 76// ACTIONS 77//////////////////////////////////////////// 78 79/** @param {string} uri */ 80async function removeUrl(uri) { 81 setError(null); 82 try { 83 const tracks = await Output.data(outputOrchestrator.tracks); 84 const detachedTracks = await inputConfigurator.detach({ 85 fileUriOrScheme: uri, 86 tracks, 87 }); 88 89 if (detachedTracks) await outputOrchestrator.tracks.save(detachedTracks); 90 } catch (err) { 91 setError(err instanceof Error ? err.message : "Failed to remove URL"); 92 } 93} 94 95async function addUrl() { 96 const url = urlInput.value?.trim(); 97 if (!url) return; 98 99 const now = new Date().toISOString(); 100 const tracksCol = outputOrchestrator.tracks.collection(); 101 const existingTracks = tracksCol.state === "loaded" ? tracksCol.data : []; 102 103 await outputOrchestrator.tracks.save([ 104 ...existingTracks, 105 { 106 $type: "sh.diffuse.output.track", 107 id: TID.now(), 108 createdAt: now, 109 updatedAt: now, 110 kind: "placeholder", 111 uri: url, 112 }, 113 ]); 114} 115 116//////////////////////////////////////////// 117// 🚀 118//////////////////////////////////////////// 119 120foundation.ready();