A music player that connects to your cloud/distributed storage.

refactor: isPlaying + hasEnded audio signals

+22 -25
+16 -21
src/components/engine/audio/element.js
··· 30 30 #items = signal(/** @type {Audio[]} */ ([])); 31 31 #volume = signal(0.5); 32 32 33 - $hasEnded = signal(false); 34 - $isPlaying = signal(false); 35 - 36 33 // STATE 37 34 38 - hasEnded = this.$hasEnded.get; 39 - isPlaying = this.$isPlaying.get; 40 35 items = this.#items.get; 41 36 volume = this.#volume.get; 42 37 ··· 56 51 play: { strategy: "leaderOnly", fn: this.play }, 57 52 seek: { strategy: "leaderOnly", fn: this.seek }, 58 53 supply: { strategy: "replicate", fn: this.supply }, 59 - 60 - setHasEnded: { strategy: "replicate", fn: this.$hasEnded.set }, 61 - setIsPlaying: { strategy: "replicate", fn: this.$isPlaying.set }, 62 54 }, 63 55 ); 64 56 ··· 68 60 this.play = actions.play; 69 61 this.seek = actions.seek; 70 62 this.supply = actions.supply; 71 - 72 - this.$hasEnded.set = actions.setHasEnded; 73 - this.$isPlaying.set = actions.setIsPlaying; 74 63 } 75 64 } 76 65 ··· 270 259 } 271 260 272 261 /** 262 + * Convenience signal to track if something is, or was, playing. 263 + */ 264 + isPlaying() { 265 + return computed(() => { 266 + const item = this.items()?.[0]; 267 + if (!item) return false; 268 + 269 + const state = this.state(item.id); 270 + if (!state) return false; 271 + 272 + return state.isPlaying() || state.hasEnded() || state.progress() === 1; 273 + }); 274 + } 275 + 276 + /** 273 277 * Get the state of a single audio item. 274 278 * 275 279 * @param {string} audioId ··· 321 325 this.$state = { 322 326 duration: signal(0), 323 327 hasEnded: signal(false), 324 - isPlaying: signal(true), 328 + isPlaying: signal(false), 325 329 isPreload: signal(this.hasAttribute("preload")), 326 330 loadingState: signal(/** @type {LoadingState} */ ("loading")), 327 331 progress: signal(ip ? parseFloat(ip) : 0), ··· 422 426 audio.currentTime = 0; 423 427 424 428 engineItem(audio)?.$state.hasEnded.set(true); 425 - engineItem(audio)?.engine?.$hasEnded.set(true); 426 429 } 427 430 428 431 /** ··· 440 443 */ 441 444 pauseEvent(event) { 442 445 const audio = /** @type {HTMLAudioElement} */ (event.target); 443 - 444 446 const item = engineItem(audio); 445 - const itemState = item?.$state; 446 - const ended = itemState 447 - ? itemState.hasEnded.value || itemState.progress.value === 1 448 - : false; 449 447 450 448 item?.$state.isPlaying.set(false); 451 - item?.engine?.$isPlaying.set(ended); 452 449 } 453 450 454 451 /** ··· 460 457 const item = engineItem(audio); 461 458 item?.$state.hasEnded.set(false); 462 459 item?.$state.isPlaying.set(true); 463 - item?.engine?.$hasEnded.set(false); 464 - item?.engine?.$isPlaying.set(true); 465 460 466 461 // In case audio was preloaded: 467 462 if (audio.readyState === 4) finishedLoading(event);
+5 -2
src/components/orchestrator/queue-audio/element.js
··· 50 50 if (!this.queue) return; 51 51 52 52 const activeTrack = this.queue.now(); 53 - const isPlaying = untracked(this.audio.isPlaying); 53 + const isPlaying = untracked(this.audio.isPlaying()); 54 54 55 55 // Resolve URIs 56 56 const resolvedUri = activeTrack ··· 86 86 if (!this.audio) return; 87 87 if (!this.queue) return; 88 88 89 - if (this.audio.hasEnded()) await this.queue.shift(); 89 + const now = this.queue.now(); 90 + const aud = now ? this.audio.state(now.id) : undefined; 91 + 92 + if (aud?.hasEnded()) await this.queue.shift(); 90 93 } 91 94 } 92 95
+1 -2
src/themes/blur/artwork-controller/element.js
··· 76 76 }); 77 77 78 78 #isPlaying = computed(() => { 79 - return !!this.$queue.value?.now() && 80 - this.$audio.value?.isPlaying() === true; 79 + return this.$audio.value?.isPlaying()(); 81 80 }); 82 81 83 82 // LIFECYCLE