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

Configure Feed

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

refactor: output configuration

+175 -96
+13
src/_includes/layouts/diffuse.vto
··· 40 40 <do-offline></do-offline> 41 41 <script src="components/orchestrator/offline/element.js" type="module"></script> 42 42 43 + <!-- Import map --> 44 + <script type="importmap"> 45 + { 46 + "imports": { 47 + "~/": "./", 48 + 49 + "@atcute/tid": "./vendor/@atcute/tid/index.js", 50 + "@awesome.me/webawesome/dist/": "./vendor/@awesome.me/webawesome/", 51 + "@awesome.me/webawesome/dist-cdn/": "./vendor/@awesome.me/webawesome/" 52 + } 53 + } 54 + </script> 55 + 43 56 <!-- Scripts --> 44 57 {{ for url of scripts }} 45 58 <script src="{{ url }}" type="module"></script>
+28
src/common/facets/prelude.js
··· 1 + /** 2 + * @import {Facet} from "~/definitions/types.d.ts" 3 + */ 4 + 5 + import { loadURI } from "../loader.js"; 6 + 7 + /** 8 + * @param {Facet[]} facets 9 + * @param {HTMLElement} [container] 10 + */ 11 + export async function insertPreludes(facets, container) { 12 + container ??= document.body; 13 + 14 + const range = document.createRange(); 15 + range.selectNode(container); 16 + 17 + const preludes = facets 18 + .filter((f) => f.kind === "prelude") 19 + .sort((a, b) => a.name.localeCompare(b.name)); 20 + 21 + for (const prelude of preludes) { 22 + const html = prelude.html ?? 23 + (prelude.uri ? await loadURI(prelude.uri) : ""); 24 + if (!html) continue; 25 + const preludeFragment = range.createContextualFragment(html); 26 + container.append(preludeFragment); 27 + } 28 + }
+72 -8
src/components/configurator/output/element.js
··· 37 37 38 38 const def = this.#defaultOutput.value; 39 39 if (def) return def.facets.collection(); 40 + if (this.hasDefault()) return { state: "loading" }; 40 41 41 42 return this.#setupFinished.value 42 43 ? { state: "loaded", data: this.#memory.facets.value } ··· 68 69 69 70 const def = this.#defaultOutput.value; 70 71 if (def) return def.playlistItems.collection(); 72 + if (this.hasDefault()) return { state: "loading" }; 71 73 72 74 return this.#setupFinished.value 73 75 ? { state: "loaded", data: this.#memory.playlistItems.value } ··· 99 101 100 102 const def = this.#defaultOutput.value; 101 103 if (def) return def.themes.collection(); 104 + if (this.hasDefault()) return { state: "loading" }; 102 105 103 106 return this.#setupFinished.value 104 107 ? { state: "loaded", data: this.#memory.themes.value } ··· 130 133 131 134 const def = this.#defaultOutput.value; 132 135 if (def) return def.tracks.collection(); 136 + if (this.hasDefault()) return { state: "loading" }; 133 137 134 138 return this.#setupFinished.value 135 139 ? { state: "loaded", data: this.#memory.tracks.value } ··· 173 177 this.themes = manager.themes; 174 178 this.tracks = manager.tracks; 175 179 this.ready = manager.ready; 180 + 181 + // Effects 182 + 183 + /** 184 + * When there's a selected output and its collection changes, 185 + * save it to the default output or memory. 186 + */ 187 + this.effect(() => { 188 + const out = this.#selected.value; 189 + if (!out) return; 190 + 191 + const col = out.facets.collection(); 192 + if (col.state !== "loaded") return; 193 + 194 + const def = this.#defaultOutput.value; 195 + if (def) def.facets.save(col.data); 196 + else this.#memory.facets.set(col.data); 197 + }); 198 + 199 + this.effect(() => { 200 + const out = this.#selected.value; 201 + if (!out) return; 202 + 203 + const col = out.playlistItems.collection(); 204 + if (col.state !== "loaded") return; 205 + 206 + const def = this.#defaultOutput.value; 207 + if (def) def.playlistItems.save(col.data); 208 + else this.#memory.playlistItems.set(col.data); 209 + }); 210 + 211 + this.effect(() => { 212 + const out = this.#selected.value; 213 + if (!out) return; 214 + 215 + const col = out.themes.collection(); 216 + if (col.state !== "loaded") return; 217 + 218 + const def = this.#defaultOutput.value; 219 + if (def) def.themes.save(col.data); 220 + else this.#memory.themes.set(col.data); 221 + }); 222 + 223 + this.effect(() => { 224 + const out = this.#selected.value; 225 + if (!out) return; 226 + 227 + const col = out.tracks.collection(); 228 + if (col.state !== "loaded") return; 229 + 230 + const def = this.#defaultOutput.value; 231 + if (def) def.tracks.save(col.data); 232 + else this.#memory.tracks.set(col.data); 233 + }); 176 234 } 177 235 178 236 // SIGNALS ··· 226 284 227 285 // Outputs 228 286 const def_ault = this.getAttribute("default"); 229 - const selectedOutputId = localStorage.getItem( 230 - `${STORAGE_PREFIX}/selected/id`, 231 - ); 287 + const selectedOutputId = this.#selectedOutputId(); 232 288 233 289 batch(() => { 234 290 /** @type {Set<string>} */ ··· 288 344 this.#selected.value = await this.#findOutput(id); 289 345 }; 290 346 347 + #selectedOutputId() { 348 + return localStorage.getItem(`${STORAGE_PREFIX}/selected/id`); 349 + } 350 + 291 351 /** 292 352 * @override 293 353 */ ··· 315 375 await this.#selectOutput(null); 316 376 }; 317 377 318 - loadSelected = async () => { 319 - const selectedOutputId = localStorage.getItem( 320 - `${STORAGE_PREFIX}/selected/id`, 321 - ); 378 + hasDefault() { 379 + return this.hasAttribute("default"); 380 + } 322 381 323 - const selectedOutput = await this.#findOutput(selectedOutputId); 382 + hasSelected() { 383 + return this.#selectedOutputId() !== null; 384 + } 385 + 386 + loadSelected = async () => { 387 + const selectedOutput = await this.#findOutput(this.#selectedOutputId()); 324 388 this.#selected.value = selectedOutput; 325 389 }; 326 390
+2
src/components/configurator/output/types.d.ts
··· 5 5 & OutputElement 6 6 & { 7 7 deselect: () => Promise<void>; 8 + hasDefault: () => boolean; 9 + hasSelected: () => boolean; 8 10 loadSelected: () => Promise<void>; 9 11 options: () => Promise<Array<OutputOption<ElementType>>>; 10 12 select: (id: string) => Promise<void>;
+8
src/components/orchestrator/output/element.js
··· 87 87 return this.outputConfigurator.deselect; 88 88 } 89 89 90 + get hasDefault() { 91 + return this.outputConfigurator.hasDefault; 92 + } 93 + 94 + get hasSelected() { 95 + return this.outputConfigurator.hasSelected; 96 + } 97 + 90 98 get loadSelected() { 91 99 return this.outputConfigurator.loadSelected; 92 100 }
+8 -1
src/components/transformer/output/bytes/dasl-sync/element.js
··· 131 131 132 132 return computed(() => { 133 133 if (!isReady.get()) isReady.value = true; 134 + if (kind === "facets") { 135 + console.log("🫠", container.get()); 136 + } 134 137 return container.get(); 135 138 }); 136 139 }; ··· 414 417 return { 415 418 collection: computed(() => { 416 419 const c = container(); 417 - if (!c.cid) return { state: "loading" }; 420 + 421 + if (remote.collection().state === "loading") { 422 + return { state: "loading" }; 423 + } 424 + 418 425 return { state: "loaded", data: c.data }; 419 426 }), 420 427 reload: remote.reload,
+1
src/facets/data/input-bundle/index.html
··· 1 + <script type="module" src="./index.inline.js"></script>
src/facets/data/input-bundle/index.inline.js

This is a binary file and will not be displayed.

-2
src/facets/data/output-bundle/index.inline.js
··· 38 38 const set = output.activated(); 39 39 const newlyActicated = set.difference(previouslyActivated); 40 40 41 - console.log("Activated", set); 42 - 43 41 previouslyActivated = set; 44 42 45 43 Array.from(newlyActicated).map((id) => {
+4 -1
src/facets/data/process-tracks/index.inline.js
··· 1 1 import foundation from "~/common/facets/foundation.js"; 2 - foundation.orchestrator.processTracks({ disableWhenReady: false }); 2 + 3 + foundation.orchestrator.processTracks({ 4 + disableWhenReady: false, 5 + });
+7 -14
src/facets/l/index.js
··· 1 1 import foundation from "~/common/facets/foundation.js"; 2 2 import * as CID from "~/common/cid.js"; 3 3 import * as Output from "~/common/output.js"; 4 - import { createLoader, loadURI, renderError } from "~/common/loader.js"; 4 + import { createLoader, renderError } from "~/common/loader.js"; 5 + import { insertPreludes } from "~/common/facets/prelude.js"; 5 6 6 7 // Output element 7 8 const output = await foundation.orchestrator.output(); ··· 35 36 } 36 37 } 37 38 39 + // Remove loading animation 38 40 container.innerHTML = ""; 39 41 42 + // Execute all the prelude facets 43 + await insertPreludes(facets, container); 44 + 45 + // Execute main facet 40 46 const range = document.createRange(); 41 47 range.selectNode(container); 42 48 const documentFragment = range.createContextualFragment(facet.html ?? ""); 43 - 44 - const preludes = facets 45 - .filter((f) => f.kind === "prelude") 46 - .sort((a, b) => a.name.localeCompare(b.name)); 47 - 48 - for (const prelude of preludes) { 49 - const html = prelude.html ?? 50 - (prelude.uri ? await loadURI(prelude.uri) : ""); 51 - if (!html) continue; 52 - const preludeFragment = range.createContextualFragment(html); 53 - container.append(preludeFragment); 54 - } 55 - 56 49 container.append(documentFragment); 57 50 }, 58 51 });
-12
src/facets/l/index.vto
··· 18 18 </div> 19 19 </div> 20 20 </div> 21 - 22 - <script type="importmap"> 23 - { 24 - "imports": { 25 - "~/": "./", 26 - 27 - "@atcute/tid": "./vendor/@atcute/tid/index.js", 28 - "@awesome.me/webawesome/dist/": "./vendor/@awesome.me/webawesome/", 29 - "@awesome.me/webawesome/dist-cdn/": "./vendor/@awesome.me/webawesome/" 30 - } 31 - } 32 - </script>
+28 -28
src/index.js
··· 1 - import { GROUP } from "~/common/facets/foundation.js"; 2 - import * as Output from "~/common/output.js"; 1 + //////////////////////////////////////////// 2 + // DEMO 3 + //////////////////////////////////////////// 3 4 4 - import InputConfigurator from "~/components/configurator/input/element.js"; 5 - import MetadataProcessor from "~/components/processor/metadata/element.js"; 6 - import OutputOrchestrator from "~/components/orchestrator/output/element.js"; 7 - import ProcessTracksOrchestrator from "~/components/orchestrator/process-tracks/element.js"; 8 - import S3Input from "~/components/input/s3/element.js"; 5 + import { insertPreludes } from "./common/facets/prelude.js"; 9 6 10 - // Add components to DOM 11 - const s3 = new S3Input(); 12 - const input = new InputConfigurator(); 13 - input.setAttribute("group", GROUP); 14 - input.append(s3); 7 + const addDemoBtn = document.querySelector("#add-sample-content"); 15 8 16 - const output = new OutputOrchestrator(); 17 - output.setAttribute("group", GROUP); 9 + async function addSampleContent() { 10 + if (!addDemoBtn) return; 18 11 19 - const metadataProcessor = new MetadataProcessor(); 20 - metadataProcessor.setAttribute("group", GROUP); 12 + addDemoBtn.setAttribute("disabled", ""); 13 + addDemoBtn.innerHTML = `<span> 14 + <i class="ph-fill ph-hourglass-medium"></i> 15 + Loading dependencies 16 + </span>`; 21 17 22 - document.body.append(input, output, metadataProcessor); 18 + const { default: foundation } = await import("~/common/facets/foundation.js"); 19 + const Output = await import("~/common/output.js"); 23 20 24 - const pto = new ProcessTracksOrchestrator(); 25 - pto.setAttribute("group", GROUP); 26 - pto.setAttribute("input-selector", input.selector); 27 - pto.setAttribute("output-selector", output.selector); 28 - pto.setAttribute("metadata-processor-selector", metadataProcessor.selector); 21 + const output = await foundation.orchestrator.output(); 22 + const input = await foundation.orchestrator.input(); 23 + const pto = await foundation.orchestrator.processTracks({ 24 + disableWhenReady: true, 25 + }); 29 26 30 - document.body.append(pto); 27 + // Execute prelude 28 + await insertPreludes( 29 + await Output.data(output.facets), 30 + ); 31 31 32 - // Demo 33 - const addDemoBtn = document.querySelector("#add-sample-content"); 32 + /** @type {import("~/components/input/s3/element.js").CLASS | null} */ 33 + const s3 = input.querySelector("di-s3"); 34 34 35 - async function addSampleContent() { 36 - if (!addDemoBtn) return; 35 + if (!s3) { 36 + throw new Error("S3 input not found"); 37 + } 37 38 38 - addDemoBtn.setAttribute("disabled", ""); 39 39 addDemoBtn.innerHTML = `<span> 40 40 <i class="ph-fill ph-hourglass-medium"></i> 41 41 Adding source
+4 -18
src/testing/index.vto
··· 1 - <html> 2 - <head> 3 - <base href="../" /> 4 - </head> 5 - <body> 6 - <script type="importmap"> 7 - { 8 - "imports": { 9 - "~/": "./", 10 - 11 - "@atcute/tid": "./vendor/@atcute/tid/index.js", 12 - "@awesome.me/webawesome/dist/": "./vendor/@awesome.me/webawesome/", 13 - "@awesome.me/webawesome/dist-cdn/": "./vendor/@awesome.me/webawesome/" 14 - } 15 - } 16 - </script> 17 - </body> 18 - </html> 1 + --- 2 + layout: layouts/diffuse.vto 3 + base: ../ 4 + ---
-12
src/themes/l/index.vto
··· 19 19 </div> 20 20 </div> 21 21 </div> 22 - 23 - <script type="importmap"> 24 - { 25 - "imports": { 26 - "~/": "./", 27 - 28 - "@atcute/tid": "./vendor/@atcute/tid/index.js", 29 - "@awesome.me/webawesome/dist/": "./vendor/@awesome.me/webawesome/", 30 - "@awesome.me/webawesome/dist-cdn/": "./vendor/@awesome.me/webawesome/" 31 - } 32 - } 33 - </script>