A music player that connects to your cloud/distributed storage.
at v4 102 lines 2.5 kB view raw
1import { computed } from "~/common/signal.js"; 2import { 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 12class 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 const col = base.tracks.collection(); 22 return createEphemeralItems(col.state === "loaded" ? col.data : []); 23 }); 24 25 this.facets = base.facets; 26 this.playlistItems = { 27 ...base.playlistItems, 28 collection: computed(() => { 29 const col = base.playlistItems.collection(); 30 if (col.state !== "loaded") return col; 31 return { state: "loaded", data: [...col.data, ...ephemeralItems()] }; 32 }), 33 /** @type {(typeof base.playlistItems.save)} */ 34 save: async (items) => { 35 await base.playlistItems.save( 36 (items || []).filter((p) => !p.ephemeral), 37 ); 38 }, 39 }; 40 this.tracks = base.tracks; 41 42 this.ready = base.ready; 43 } 44} 45 46/** 47 * @param {Track[]} tracks 48 * @returns {PlaylistItem[]} 49 */ 50function createEphemeralItems(tracks) { 51 /** @type {PlaylistItem[]} */ 52 const items = []; 53 54 /** @type {Set<string>} */ 55 const segmentsAdded = new Set(); 56 57 tracks.forEach((track) => { 58 const segment = pathSegment(track.uri); 59 if (!segment) return; 60 61 if (segmentsAdded.has(segment)) return; 62 63 /** @type {PlaylistItem} */ 64 const item = { 65 $type: "sh.diffuse.output.playlistItem", 66 id: `path-collections/${track.id}`, 67 playlist: segment, 68 criteria: [{ field: "uri", value: /** @type {any} */ (track.uri) }], 69 ephemeral: true, 70 }; 71 72 items.push(item); 73 segmentsAdded.add(segment); 74 }); 75 76 return items; 77} 78 79/** 80 * @param {string} uri 81 * @returns {string | undefined} 82 */ 83function pathSegment(uri) { 84 try { 85 const url = new URL(uri); 86 const segment = url.pathname.split("/").filter(Boolean)[0]; 87 return segment || undefined; 88 } catch { 89 return undefined; 90 } 91} 92 93export default PathCollectionsOrchestrator; 94 95//////////////////////////////////////////// 96// REGISTER 97//////////////////////////////////////////// 98 99export const CLASS = PathCollectionsOrchestrator; 100export const NAME = "do-path-collections"; 101 102customElements.define(NAME, CLASS);