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: orchestrators

+48 -57
+20
src/common/element.js
··· 295 295 } 296 296 return /** @type {InstanceType<C>} */ (el); 297 297 } 298 + 299 + /** 300 + * @template {HTMLElement} T 301 + * @param {DiffuseElement} parent 302 + * @param {string} attribute 303 + * @returns {T} 304 + */ 305 + export function query(parent, attribute) { 306 + const selector = parent.getAttribute(attribute); 307 + 308 + if (!selector) { 309 + throw new Error(`Missing required '${attribute}' attribute`); 310 + } 311 + 312 + /** @type {T | null} */ 313 + const element = document.querySelector(selector); 314 + if (!element) throw new Error(`Missing required '${selector}' element`); 315 + 316 + return element; 317 + }
+28 -57
src/component/orchestrator/process-tracks/element.js
··· 1 1 import deepDiff from "@fry69/deep-diff"; 2 2 3 - import { DiffuseElement } from "@common/element.js"; 3 + import { DiffuseElement, query } from "@common/element.js"; 4 4 import { signal } from "@common/signal.js"; 5 5 6 6 /** ··· 15 15 constructor() { 16 16 super(); 17 17 18 - this.inputSelector = this.getAttribute("input-selector"); 19 - this.outputSelector = this.getAttribute("output-selector"); 20 - this.metadataProcessorSelector = this.getAttribute( 21 - "metadata-processor-selector", 22 - ); 23 - 24 - if (!this.inputSelector) { 25 - throw new Error("Missing required `input-selector` attribute"); 26 - } 18 + /** @type {InputElement} */ 19 + this.input = query(this, "input-selector"); 27 20 28 - if (!this.outputSelector) { 29 - throw new Error("Missing required `output-selector` attribute"); 30 - } 21 + /** @type {OutputElement} */ 22 + this.output = query(this, "output-selector"); 31 23 32 - if (!this.metadataProcessorSelector) { 33 - throw new Error( 34 - "Missing required `metadata-processor-selector` attribute", 35 - ); 36 - } 24 + /** @type {import("@component/processor/metadata/element.js").CLASS} */ 25 + this.metadataProcessor = query(this, "metadata-processor-selector"); 37 26 } 38 27 39 28 // SIGNALS ··· 52 41 async connectedCallback() { 53 42 super.connectedCallback(); 54 43 55 - /** @type {OutputElement | null} */ 56 - const output = document.querySelector(this.outputSelector); 57 - 58 - // Check output element presence 59 - if (!output) throw new Error("Missing required `output` element"); 60 - 61 44 // Wait until defined 62 - await customElements.whenDefined(output.localName); 45 + await customElements.whenDefined(this.output.localName); 63 46 64 - // Process whenever tracks are loaded 47 + // Process whenever tracks are initially loaded 65 48 this.effect(() => { 66 - const state = output.tracks.state(); 49 + const state = this.output.tracks.state(); 67 50 if (state !== "loaded") return; 68 51 69 - this.process(output); 52 + this.process(); 70 53 }); 71 54 } 72 55 73 - /** 74 - * @param {OutputElement} output 75 - */ 76 - async process(output) { 77 - /** @type {InputElement | null} */ 78 - const input = document.querySelector(this.inputSelector); 56 + // ACTIONS 79 57 80 - // TODO 81 - /** @type {any} */ 82 - const metadataProcessor = document.querySelector( 83 - this.metadataProcessorSelector, 84 - ); 85 - 86 - // Check element presence 87 - if (!input) throw new Error("Missing required `input` element"); 88 - if (!metadataProcessor) { 89 - throw new Error("Missing required `metadata-processor` element"); 90 - } 91 - 92 - // Wait until defined 93 - await customElements.whenDefined(input.localName); 94 - await customElements.whenDefined(metadataProcessor.localName); 58 + async process() { 59 + await customElements.whenDefined(this.input.localName); 60 + await customElements.whenDefined(this.metadataProcessor.localName); 95 61 96 62 // Start 97 63 this.#isProcessing.value = true; 98 64 console.log("🪵 Processing initiated"); 99 65 100 - const cachedTracks = output.tracks.collection(); 66 + const cachedTracks = this.output.tracks.collection(); 101 67 102 68 // Contextualize 103 - await input.contextualize(cachedTracks); 69 + await this.input.contextualize(cachedTracks); 104 70 105 71 // List 106 - const tracks = await input.list(cachedTracks); 72 + const tracks = await this.input.list(cachedTracks); 107 73 108 74 // Fetch metadata if needed 109 - // TODO: Parallelisation 110 75 const tracksWithMetadata = await tracks.reduce( 111 76 /** 112 77 * @param {Promise<Track[]>} promise ··· 117 82 118 83 if (track.tags && track.stats) return [...acc, track]; 119 84 120 - const resGet = await input.resolve({ method: "GET", uri: track.uri }); 121 - const resHead = await input.resolve({ method: "HEAD", uri: track.uri }); 85 + const resGet = await this.input.resolve({ 86 + method: "GET", 87 + uri: track.uri, 88 + }); 89 + const resHead = await this.input.resolve({ 90 + method: "HEAD", 91 + uri: track.uri, 92 + }); 122 93 123 94 if (!resGet) return [...acc, track]; 124 95 125 - const { stats, tags } = await metadataProcessor.supply({ 96 + const { stats, tags } = await this.metadataProcessor.supply({ 126 97 urls: { get: resGet.url, head: resHead?.url || resGet.url }, 127 98 }); 128 99 ··· 136 107 const changed = !!diff; 137 108 138 109 // Save if changed 139 - if (changed) await output.tracks.save(tracksWithMetadata); 110 + if (changed) await this.output.tracks.save(tracksWithMetadata); 140 111 141 112 // Fin 142 113 console.log("🪵 Processing completed");