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.

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