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.

fix: demo button

+83 -14
+36
src/components/configurator/output/element.js
··· 40 40 41 41 return this.#memory.facets.value; 42 42 }), 43 + loaded: () => { 44 + const out = this.#selected.value; 45 + if (out) return out.facets.loaded(); 46 + 47 + const def = this.#defaultOutput.value; 48 + if (def) return def.facets.loaded(); 49 + 50 + return Promise.resolve(); 51 + }, 43 52 reload: () => { 44 53 const def = this.#defaultOutput.value; 45 54 if (def) def.facets.reload(); ··· 78 87 79 88 return this.#memory.playlistItems.value; 80 89 }), 90 + loaded: () => { 91 + const out = this.#selected.value; 92 + if (out) return out.playlistItems.loaded(); 93 + 94 + const def = this.#defaultOutput.value; 95 + if (def) return def.playlistItems.loaded(); 96 + 97 + return Promise.resolve(); 98 + }, 81 99 reload: () => { 82 100 const def = this.#defaultOutput.value; 83 101 if (def) def.playlistItems.reload(); ··· 116 134 117 135 return this.#memory.themes.value; 118 136 }), 137 + loaded: () => { 138 + const out = this.#selected.value; 139 + if (out) return out.themes.loaded(); 140 + 141 + const def = this.#defaultOutput.value; 142 + if (def) return def.themes.loaded(); 143 + 144 + return Promise.resolve(); 145 + }, 119 146 reload: () => { 120 147 const def = this.#defaultOutput.value; 121 148 if (def) def.themes.reload(); ··· 154 181 155 182 return this.#memory.tracks.value; 156 183 }), 184 + loaded: () => { 185 + const out = this.#selected.value; 186 + if (out) return out.tracks.loaded(); 187 + 188 + const def = this.#defaultOutput.value; 189 + if (def) return def.tracks.loaded(); 190 + 191 + return Promise.resolve(); 192 + }, 157 193 reload: () => { 158 194 const def = this.#defaultOutput.value; 159 195 if (def) def.tracks.reload();
+26 -11
src/components/output/common.js
··· 1 1 import deepDiff from "@fry69/deep-diff"; 2 - import { batch, computed, signal, untracked } from "@common/signal.js"; 2 + import { batch, computed, effect, signal, untracked } from "@common/signal.js"; 3 3 4 4 /** 5 5 * @import {Facet, PlaylistItem, Theme, Track} from "@definitions/types.d.ts" 6 + * @import {SignalReader} from "@common/signal.d.ts"; 6 7 * @import {OutputManager, OutputManagerProperties} from "./types.d.ts" 7 8 */ 8 9 9 10 /** 10 11 * @template [Encoding=null] 11 12 * @param {OutputManagerProperties<Encoding>} _ 12 - * @param {{ compare?: boolean }} [signalOpts] 13 13 * @returns {OutputManager<Encoding>} 14 14 */ 15 15 export function outputManager( 16 16 { init, facets, playlistItems, themes, tracks }, 17 - signalOpts, 18 17 ) { 19 - const compareOpt = signalOpts?.compare 20 - ? { compare: (a, b) => !deepDiff(a, b) } 21 - : undefined; 22 - 23 18 const c = signal( 24 19 /** @type {Encoding extends null ? Facet[] : Encoding} */ (facets 25 20 .empty()), 26 - compareOpt, 27 21 ); 28 22 const cs = signal( 29 23 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), ··· 32 26 const pl = signal( 33 27 /** @type {Encoding extends null ? PlaylistItem[] : Encoding} */ (playlistItems 34 28 .empty()), 35 - compareOpt, 36 29 ); 37 30 const pls = signal( 38 31 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), ··· 40 33 41 34 const th = signal( 42 35 /** @type {Encoding extends null ? Theme[] : Encoding} */ (themes.empty()), 43 - compareOpt, 44 36 ); 45 37 const ths = signal( 46 38 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), ··· 48 40 49 41 const t = signal( 50 42 /** @type {Encoding extends null ? Track[] : Encoding} */ (tracks.empty()), 51 - compareOpt, 52 43 ); 53 44 const ts = signal( 54 45 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), 55 46 ); 56 47 48 + /** 49 + * @param {() => void} loader 50 + * @param {SignalReader<"loading" | "loaded" | "sleeping">} state 51 + */ 52 + function promiseLoadedState(loader, state) { 53 + return () => 54 + new Promise((resolve) => { 55 + const stop = effect(() => { 56 + if (state() === "loaded") { 57 + stop(); 58 + resolve(void 0); 59 + } 60 + }); 61 + 62 + if (state() === "sleeping") { 63 + loader(); 64 + } 65 + }); 66 + } 67 + 57 68 async function loadFacets() { 58 69 if (init && (await init()) === false) return; 59 70 cs.value = "loading"; ··· 88 99 if (untracked(() => cs.value === "sleeping")) loadFacets(); 89 100 return c.value; 90 101 }), 102 + loaded: promiseLoadedState(loadFacets, cs.get), 91 103 reload: loadFacets, 92 104 save: async (newFacets) => { 93 105 batch(() => { ··· 103 115 if (untracked(() => pls.value === "sleeping")) loadPlaylistItems(); 104 116 return pl.value; 105 117 }), 118 + loaded: promiseLoadedState(loadPlaylistItems, pls.get), 106 119 reload: loadPlaylistItems, 107 120 save: async (newPlaylistItems) => { 108 121 batch(() => { ··· 118 131 if (untracked(() => ths.value === "sleeping")) loadThemes(); 119 132 return th.value; 120 133 }), 134 + loaded: promiseLoadedState(loadThemes, ths.get), 121 135 reload: loadThemes, 122 136 save: async (newThemes) => { 123 137 batch(() => { ··· 133 147 if (untracked(() => ts.value === "sleeping")) loadTracks(); 134 148 return t.value; 135 149 }), 150 + loaded: promiseLoadedState(loadTracks, ts.get), 136 151 reload: loadTracks, 137 152 save: async (newTracks) => { 138 153 batch(() => {
+4
src/components/output/types.d.ts
··· 18 18 export type OutputManager<Encoding = null> = { 19 19 facets: { 20 20 collection: SignalReader<Encoding extends null ? Facet[] : Encoding>; 21 + loaded: () => Promise<void>; 21 22 reload: () => Promise<void>; 22 23 save: ( 23 24 facets: Encoding extends null ? Facet[] : Encoding, ··· 26 27 }; 27 28 playlistItems: { 28 29 collection: SignalReader<Encoding extends null ? PlaylistItem[] : Encoding>; 30 + loaded: () => Promise<void>; 29 31 reload: () => Promise<void>; 30 32 save: ( 31 33 playlistItems: Encoding extends null ? PlaylistItem[] : Encoding, ··· 40 42 }; 41 43 themes: { 42 44 collection: SignalReader<Encoding extends null ? Theme[] : Encoding>; 45 + loaded: () => Promise<void>; 43 46 reload: () => Promise<void>; 44 47 save: ( 45 48 themes: Encoding extends null ? Theme[] : Encoding, ··· 48 51 }; 49 52 tracks: { 50 53 collection: SignalReader<Encoding extends null ? Track[] : Encoding>; 54 + loaded: () => Promise<void>; 51 55 reload: () => Promise<void>; 52 56 save: (tracks: Encoding extends null ? Track[] : Encoding) => Promise<void>; 53 57 state: SignalReader<"loading" | "loaded" | "sleeping">;
+12
src/components/transformer/output/base.js
··· 46 46 collection: computed(() => { 47 47 return this.output.signal()?.facets?.collection(); 48 48 }), 49 + loaded: () => { 50 + return this.output.signal()?.facets?.loaded() ?? Promise.resolve(); 51 + }, 49 52 reload: () => { 50 53 return this.output.signal()?.facets?.reload() ?? 51 54 Promise.resolve(); ··· 63 66 collection: computed(() => { 64 67 return this.output.signal()?.playlistItems?.collection(); 65 68 }), 69 + loaded: () => { 70 + return this.output.signal()?.playlistItems?.loaded() ?? Promise.resolve(); 71 + }, 66 72 reload: () => { 67 73 return this.output.signal()?.playlistItems?.reload() ?? 68 74 Promise.resolve(); ··· 80 86 collection: computed(() => { 81 87 return this.output.signal()?.themes?.collection(); 82 88 }), 89 + loaded: () => { 90 + return this.output.signal()?.themes?.loaded() ?? Promise.resolve(); 91 + }, 83 92 reload: () => { 84 93 return this.output.signal()?.themes?.reload() ?? 85 94 Promise.resolve(); ··· 97 106 collection: computed(() => { 98 107 return this.output.signal()?.tracks?.collection(); 99 108 }), 109 + loaded: () => { 110 + return this.output.signal()?.tracks?.loaded() ?? Promise.resolve(); 111 + }, 100 112 reload: () => { 101 113 return this.output.signal()?.tracks?.reload() ?? Promise.resolve(); 102 114 },
+5 -3
src/index.js
··· 1 1 import { GROUP } from "@common/facets/foundation.js"; 2 2 3 + import { effect } from "@common/signal.js"; 4 + 3 5 import InputConfigurator from "@components/configurator/input/element.js"; 4 6 import MetadataProcessor from "@components/processor/metadata/element.js"; 5 7 import OutputOrchestrator from "@components/orchestrator/output/element.js"; ··· 41 43 </span>`; 42 44 43 45 const demo = await s3.demo(); 44 - const tracks = output.tracks.collection(); 45 - 46 - await output.tracks.save([...tracks, demo.track]); 46 + await output.tracks.loaded(); 47 47 48 48 addDemoBtn.innerHTML = `<span> 49 49 <i class="ph-fill ph-hourglass-medium"></i> 50 50 Processing source 51 51 </span>`; 52 + 53 + await output.tracks.save([...output.tracks.collection(), demo.track]); 52 54 53 55 await pto.process(); 54 56