A music player that connects to your cloud/distributed storage. diffuse.sh
Something went wrong. Try again.
4.4 kB · 170 lines
JavaScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171import deepDiff from "@fry69/deep-diff";
import * as Output from "~/common/output.js";import { BroadcastableDiffuseElement, defineElement, query } from "~/common/element.js";import { groupTracksPerScheme } from "~/common/utils.js";import { signal } from "~/common/signal.js";
import { DISABLED_KEY } from "./constants.js";import { parseDisabledUris, uriKey } from "./common.js";
/** * @import {InputElement, Source} from "@specs/components/input/types.d.ts" * @import {OutputElement} from "@specs/components/output/types.d.ts" */
////////////////////////////////////////////// ELEMENT////////////////////////////////////////////
class Sources extends BroadcastableDiffuseElement { static NAME = "diffuse/orchestrator/sources";
// SIGNALS
#sources = signal(/** @type {{ [scheme: string]: Source[] }} */ ({})); #disabled = signal(/** @type {string[]} */ ([]));
// STATE
sources = this.#sources.get; disabled = this.#disabled.get;
#output = signal(/** @type {OutputElement | null} */ (null));
// METHODS
/** * Returns whether the given source URI is disabled. * Strips query params before comparing, matching how {@link toggle} stores keys. * * @param {string} uri * @returns {boolean} */ isDisabled(uri) { return this.#disabled.get().includes(uriKey(uri)); }
/** * @param {string} uri */ async toggle(uri) { const key = uriKey(uri);
const output = this.#output.value; if (!output) { console.warn("Output element is not available yet."); return; }
const settings = await Output.data(output.settings); const existing = settings.find((s) => s.key === DISABLED_KEY);
let disabled = parseDisabledUris(settings);
if (disabled.includes(key)) { disabled = disabled.filter((u) => u !== key); } else { disabled = [...disabled, key]; }
const value = JSON.stringify(disabled); const updated = existing ? settings.map((s) => s.key === DISABLED_KEY ? { ...s, value } : s ) : [ ...settings, { $type: /** @type {"sh.diffuse.output.setting"} */ ( "sh.diffuse.output.setting" ), id: crypto.randomUUID(), key: DISABLED_KEY, value, }, ];
await output.settings.save(updated); }
// LIFECYCLE
/** * @override */ async connectedCallback() { super.connectedCallback();
/** @type {InputElement} */ const input = query(this, "input-selector");
/** @type {OutputElement} */ const output = query(this, "output-selector");
// Wait until defined await customElements.whenDefined(input.localName); await customElements.whenDefined(output.localName);
// Signals this.#output.value = output;
// Effects this.effect(() => { const col = output.settings.collection(); if (col.state !== "loaded") { this.#disabled.value = []; return; } this.#disabled.value = parseDisabledUris(col.data); });
// Single input mode + dependencies const singleInputMode = !!input.SCHEME; const deps = /** @type {{ [k: string]: InputElement }} */ (singleInputMode ? {} : input.dependencies());
// Effects this.effect(() => { const col = output.tracks.collection(); const tracks = col.state === "loaded" ? col.data : []; const groups = groupTracksPerScheme(tracks);
/** @type {{ [scheme: string]: Source[] }} */ const record = {};
Object.entries(groups).map(([scheme, tracks]) => { /** @type {Source[]} */ let sources;
if (singleInputMode) { if (input.SCHEME === scheme) { sources = input.sources(tracks); } else { sources = []; } } else { const dep = deps[scheme]; if (!dep) sources = tracks.map((t) => ({ label: t.uri, uri: t.uri })); else sources = dep.sources(tracks); }
record[scheme] = sources; });
if (deepDiff(this.#sources.value, record)) { this.#sources.value = record; } }); }}
export default Sources;
////////////////////////////////////////////// REGISTER////////////////////////////////////////////
export const CLASS = Sources;export const NAME = "do-sources";
defineElement(NAME, CLASS);