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 213 lines 6.3 kB view raw
1import { BroadcastableDiffuseElement } from "~/common/element.js"; 2import { batch, computed, signal, untracked } from "~/common/signal.js"; 3import { strictEquality } from "~/common/compare.js"; 4 5/** 6 * @import {Facet, PlaylistItem, Setting, Track} from "~/definitions/types.d.ts" 7 * @import {SignalWriter} from "~/common/signal.d.ts"; 8 * @import {OutputManager, OutputManagerProperties} from "./types.d.ts" 9 */ 10 11export class BroadcastedOutputElement extends BroadcastableDiffuseElement { 12 /** 13 * @param {OutputManager<any>} manager 14 */ 15 replicateSavedData(manager) { 16 // Broadcast if needed 17 if (!this.hasAttribute("group")) return; 18 19 /** 20 * @template T 21 * @param {{ save: (data: T) => Promise<void>; set: SignalWriter<T> }} _ 22 * @returns {(data: T) => Promise<void>} 23 */ 24 const fn = ({ save, set }) => async (data) => { 25 await untracked(async () => { 26 if (await this.isLeader()) { 27 return save(data); 28 } else { 29 return set(data); 30 } 31 }); 32 }; 33 34 const ogFacetsSave = manager.facets.save.bind(this); 35 const ogPlaylistItemsSave = manager.playlistItems.save.bind(this); 36 const ogSettingsSave = manager.settings.save.bind(this); 37 const ogTracksSave = manager.tracks.save.bind(this); 38 39 const actions = this.broadcast(this.identifier, { 40 saveFacets: { 41 strategy: "replicate", 42 fn: fn({ save: ogFacetsSave, set: manager.signals.facets.set }), 43 }, 44 savePlaylistItems: { 45 strategy: "replicate", 46 fn: fn({ 47 save: ogPlaylistItemsSave, 48 set: manager.signals.playlistItems.set, 49 }), 50 }, 51 saveSettings: { 52 strategy: "replicate", 53 fn: fn({ save: ogSettingsSave, set: manager.signals.settings.set }), 54 }, 55 saveTracks: { 56 strategy: "replicate", 57 fn: fn({ save: ogTracksSave, set: manager.signals.tracks.set }), 58 }, 59 }); 60 61 if (actions) { 62 manager.facets.save = actions.saveFacets; 63 manager.playlistItems.save = actions.savePlaylistItems; 64 manager.settings.save = actions.saveSettings; 65 manager.tracks.save = actions.saveTracks; 66 } 67 } 68} 69 70/** 71 * @template [Encoding=null] 72 * @param {OutputManagerProperties<Encoding>} _ 73 * @returns {OutputManager<Encoding>} 74 */ 75export function outputManager( 76 { init, facets, playlistItems, settings, tracks }, 77) { 78 const c = signal( 79 /** @type {Encoding extends null ? Facet[] : Encoding} */ (facets 80 .empty()), 81 ); 82 const cs = signal( 83 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), 84 { compare: strictEquality }, 85 ); 86 87 const pl = signal( 88 /** @type {Encoding extends null ? PlaylistItem[] : Encoding} */ (playlistItems 89 .empty()), 90 ); 91 const pls = signal( 92 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), 93 { compare: strictEquality }, 94 ); 95 96 const s = signal( 97 /** @type {Encoding extends null ? Setting[] : Encoding} */ (settings 98 .empty()), 99 ); 100 const ss = signal( 101 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), 102 { compare: strictEquality }, 103 ); 104 105 const t = signal( 106 /** @type {Encoding extends null ? Track[] : Encoding} */ (tracks.empty()), 107 ); 108 const ts = signal( 109 /** @type {"loading" | "loaded" | "sleeping"} */ ("sleeping"), 110 { compare: strictEquality }, 111 ); 112 113 async function loadFacets() { 114 if (init && (await init()) === false) return; 115 cs.value = "loading"; 116 c.value = await facets.get(); 117 cs.value = "loaded"; 118 } 119 120 async function loadPlaylistItems() { 121 if (init && (await init()) === false) return; 122 pls.value = "loading"; 123 pl.value = await playlistItems.get(); 124 pls.value = "loaded"; 125 } 126 127 async function loadSettings() { 128 if (init && (await init()) === false) return; 129 ss.value = "loading"; 130 s.value = await settings.get(); 131 ss.value = "loaded"; 132 } 133 134 async function loadTracks() { 135 if (init && (await init()) === false) return; 136 ts.value = "loading"; 137 t.value = await tracks.get(); 138 ts.value = "loaded"; 139 } 140 141 return { 142 facets: { 143 collection: computed(() => { 144 if (untracked(() => cs.value === "sleeping")) loadFacets(); 145 return cs.value === "loaded" 146 ? { state: "loaded", data: c.value } 147 : { state: "loading" }; 148 }), 149 reload: loadFacets, 150 save: async (newFacets) => { 151 batch(() => { 152 if (untracked(() => cs.value === "sleeping")) cs.value = "loaded"; 153 c.value = newFacets; 154 }); 155 await facets.put(newFacets); 156 }, 157 }, 158 playlistItems: { 159 collection: computed(() => { 160 if (untracked(() => pls.value === "sleeping")) loadPlaylistItems(); 161 return pls.value === "loaded" 162 ? { state: "loaded", data: pl.value } 163 : { state: "loading" }; 164 }), 165 reload: loadPlaylistItems, 166 save: async (newPlaylistItems) => { 167 batch(() => { 168 if (untracked(() => pls.value === "sleeping")) pls.value = "loaded"; 169 pl.value = newPlaylistItems; 170 }); 171 await playlistItems.put(newPlaylistItems); 172 }, 173 }, 174 settings: { 175 collection: computed(() => { 176 if (untracked(() => ss.value === "sleeping")) loadSettings(); 177 return ss.value === "loaded" 178 ? { state: "loaded", data: s.value } 179 : { state: "loading" }; 180 }), 181 reload: loadSettings, 182 save: async (newSettings) => { 183 batch(() => { 184 if (untracked(() => ss.value === "sleeping")) ss.value = "loaded"; 185 s.value = newSettings; 186 }); 187 await settings.put(newSettings); 188 }, 189 }, 190 tracks: { 191 collection: computed(() => { 192 if (untracked(() => ts.value === "sleeping")) loadTracks(); 193 return ts.value === "loaded" 194 ? { state: "loaded", data: t.value } 195 : { state: "loading" }; 196 }), 197 reload: loadTracks, 198 save: async (newTracks) => { 199 batch(() => { 200 if (untracked(() => ts.value === "sleeping")) ts.value = "loaded"; 201 t.value = newTracks; 202 }); 203 await tracks.put(newTracks); 204 }, 205 }, 206 signals: { 207 facets: c, 208 playlistItems: pl, 209 settings: s, 210 tracks: t, 211 }, 212 }; 213}