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.

feat: initial facets collection

+129 -1
+16
src/common/facets/constants.js
··· 1 + /** 2 + * @import {Facet} from "~/definitions/types.d.ts" 3 + */ 4 + 5 + /** @type {Facet[]} */ 6 + export const STARTING_SET = [ 7 + { 8 + $type: "sh.diffuse.output.facet", 9 + id: "default/process-tracks", 10 + kind: "prelude", 11 + name: "Process Tracks", 12 + uri: "diffuse://facets/data/process-tracks/index.html", 13 + description: 14 + "Process all your audio inputs automatically when opening any interface facet.", 15 + }, 16 + ];
+7 -1
src/components/orchestrator/output/element.js
··· 3 3 4 4 import "~/components/configurator/output/element.js"; 5 5 import "~/components/transformer/output/refiner/default/element.js"; 6 + import "~/components/transformer/output/refiner/initial-contents/element.js"; 6 7 7 8 /** 8 9 * @import {RenderArg} from "~/common/element.d.ts" ··· 208 209 </dc-output> 209 210 210 211 <!-- ENTRY ⬆️ --> 212 + <dtor-initial-contents 213 + id="do-output__dtor-initial-contents" 214 + output-selector="#do-output__dc-output" 215 + ></dtor-initial-contents> 216 + 211 217 <dtor-default 212 218 id="do-output__output" 213 - output-selector="#do-output__dc-output" 219 + output-selector="#do-output__dtor-initial-contents" 214 220 ></dtor-default> 215 221 `; 216 222 }
+106
src/components/transformer/output/refiner/initial-contents/element.js
··· 1 + import * as IDB from "idb-keyval"; 2 + 3 + import { batch, computed, signal, untracked } from "~/common/signal.js"; 4 + import { OutputTransformer } from "../../base.js"; 5 + import { STARTING_SET } from "~/common/facets/constants.js"; 6 + 7 + /** 8 + * @import {OutputManagerDeputy} from "~/components/output/types.d.ts" 9 + */ 10 + 11 + const IDB_KEY = 12 + "diffuse/transformer/output/refiner/initial-contents/initialized"; 13 + 14 + //////////////////////////////////////////// 15 + // ELEMENT 16 + //////////////////////////////////////////// 17 + 18 + /** 19 + * @extends {OutputTransformer} 20 + */ 21 + class InitialContentsTransformer extends OutputTransformer { 22 + static NAME = "diffuse/transformer/output/refiner/initial-contents"; 23 + 24 + #flagLoaded = signal(false); 25 + #initialized = signal(false); 26 + 27 + constructor() { 28 + super(); 29 + 30 + const base = this.base(); 31 + 32 + // Load flag from IDB; gate collection() until resolved to prevent 33 + // a flash of defaults for a user who has previously cleared their collection. 34 + IDB.get(IDB_KEY).then((v) => { 35 + batch(() => { 36 + this.#initialized.value = !!v; 37 + this.#flagLoaded.value = true; 38 + }); 39 + }); 40 + 41 + /** @type {OutputManagerDeputy} */ 42 + const manager = { 43 + facets: { 44 + ...base.facets, 45 + collection: computed(() => { 46 + if (!this.#flagLoaded.get()) return { state: "loading" }; 47 + 48 + const col = base.facets.collection(); 49 + if (col.state !== "loaded") return col; 50 + 51 + if (col.data.length > 0) { 52 + // Set the flag the first time we observe non-empty data. 53 + // Covers data arriving from another device via sync. 54 + // untracked read avoids a circular dependency; the write still 55 + // notifies subscribers and queues a re-evaluation. 56 + if (!untracked(() => this.#initialized.value)) { 57 + this.#initialized.value = true; 58 + IDB.set(IDB_KEY, true); // fire-and-forget 59 + } 60 + return { state: "loaded", data: col.data }; 61 + } 62 + 63 + // Tracked read: keeps the computed subscribed to #initialized 64 + // so it re-runs if save() sets it to true with an empty array. 65 + if (this.#initialized.get()) { 66 + return { state: "loaded", data: col.data }; 67 + } 68 + 69 + return { state: "loaded", data: STARTING_SET }; 70 + }), 71 + 72 + save: async (newFacets) => { 73 + // Set the flag on any explicit save (covers the case where the 74 + // user's first action is removing a default from the list). 75 + if (!this.#initialized.value) { 76 + this.#initialized.value = true; 77 + IDB.set(IDB_KEY, true); // fire-and-forget 78 + } 79 + await base.facets.save(newFacets); 80 + }, 81 + }, 82 + 83 + playlistItems: base.playlistItems, 84 + themes: base.themes, 85 + tracks: base.tracks, 86 + ready: base.ready, 87 + }; 88 + 89 + this.facets = manager.facets; 90 + this.playlistItems = manager.playlistItems; 91 + this.themes = manager.themes; 92 + this.tracks = manager.tracks; 93 + this.ready = manager.ready; 94 + } 95 + } 96 + 97 + export default InitialContentsTransformer; 98 + 99 + //////////////////////////////////////////// 100 + // REGISTER 101 + //////////////////////////////////////////// 102 + 103 + export const CLASS = InitialContentsTransformer; 104 + export const NAME = "dtor-initial-contents"; 105 + 106 + customElements.define(NAME, CLASS);