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.

feat: path-collections orchestrator

+101
+101
src/components/orchestrator/path-collections/element.js
··· 1 + import { computed } from "~/common/signal.js"; 2 + import { OutputTransformer } from "~/components/transformer/output/base.js"; 3 + 4 + /** 5 + * @import {PlaylistItem, Track} from "~/definitions/types.d.ts" 6 + */ 7 + 8 + //////////////////////////////////////////// 9 + // ELEMENT 10 + //////////////////////////////////////////// 11 + 12 + class PathCollectionsOrchestrator extends OutputTransformer { 13 + static NAME = "diffuse/orchestrator/path-collections"; 14 + 15 + constructor() { 16 + super(); 17 + 18 + const base = this.base(); 19 + 20 + const ephemeralItems = computed(() => { 21 + return createEphemeralItems(base.tracks.collection() ?? []); 22 + }); 23 + 24 + this.facets = base.facets; 25 + this.playlistItems = { 26 + ...base.playlistItems, 27 + collection: computed(() => { 28 + const stored = base.playlistItems.collection() ?? []; 29 + return [...stored, ...ephemeralItems()]; 30 + }), 31 + /** @type {(typeof base.playlistItems.save)} */ 32 + save: async (items) => { 33 + await base.playlistItems.save( 34 + (items || []).filter((p) => !p.ephemeral), 35 + ); 36 + }, 37 + }; 38 + this.themes = base.themes; 39 + this.tracks = base.tracks; 40 + 41 + this.ready = base.ready; 42 + } 43 + } 44 + 45 + /** 46 + * @param {Track[]} tracks 47 + * @returns {PlaylistItem[]} 48 + */ 49 + function createEphemeralItems(tracks) { 50 + /** @type {PlaylistItem[]} */ 51 + const items = []; 52 + 53 + /** @type {Set<string>} */ 54 + const segmentsAdded = new Set(); 55 + 56 + tracks.forEach((track) => { 57 + const segment = pathSegment(track.uri); 58 + if (!segment) return; 59 + 60 + if (segmentsAdded.has(segment)) return; 61 + 62 + /** @type {PlaylistItem} */ 63 + const item = { 64 + $type: "sh.diffuse.output.playlistItem", 65 + id: `path-collections/${track.id}`, 66 + playlist: segment, 67 + criteria: [{ field: "uri", value: /** @type {any} */ (track.uri) }], 68 + ephemeral: true, 69 + }; 70 + 71 + items.push(item); 72 + segmentsAdded.add(segment); 73 + }); 74 + 75 + return items; 76 + } 77 + 78 + /** 79 + * @param {string} uri 80 + * @returns {string | undefined} 81 + */ 82 + function pathSegment(uri) { 83 + try { 84 + const url = new URL(uri); 85 + const segment = url.pathname.split("/").filter(Boolean)[0]; 86 + return segment || undefined; 87 + } catch { 88 + return undefined; 89 + } 90 + } 91 + 92 + export default PathCollectionsOrchestrator; 93 + 94 + //////////////////////////////////////////// 95 + // REGISTER 96 + //////////////////////////////////////////// 97 + 98 + export const CLASS = PathCollectionsOrchestrator; 99 + export const NAME = "do-path-collections"; 100 + 101 + customElements.define(NAME, CLASS);