WIP: global player pt. 5 svelte bindings

This commit is contained in:
2026-02-10 00:09:41 -08:00
parent 4fb1d7865f
commit cfd45b6815
2 changed files with 36 additions and 73 deletions

View File

@@ -16,6 +16,7 @@
// ... existing imports ... // ... existing imports ...
onMount(() => { onMount(() => {
console.log("PlayerRoot mounted");
audioCtx.setElement(audioEl); audioCtx.setElement(audioEl);
// Load state // Load state
@@ -25,56 +26,21 @@
} }
// Setup MediaSession // Setup MediaSession
if ("mediaSession" in navigator) { // ...
navigator.mediaSession.setActionHandler("play", () => {
audioCtx.paused = false;
});
navigator.mediaSession.setActionHandler("pause", () => {
audioCtx.paused = true;
});
navigator.mediaSession.setActionHandler("previoustrack", () =>
player.prev(),
);
navigator.mediaSession.setActionHandler("nexttrack", () => player.next());
navigator.mediaSession.setActionHandler("stop", () => {
audioCtx.paused = true;
audioCtx.currentTime = 0;
});
}
}); });
// Persist state changes // ... existing effect for persistence ...
$effect(() => {
// Create a dependency on all persisted fields
const state = {
queue: player.queue,
currentId: player.currentId,
volume: player.volume,
isMuted: player.isMuted,
minimized: !player.uiOpen,
};
saveState(state);
});
// Update MediaSession metadata // Update MediaSession metadata
$effect(() => { // ...
const track = player.currentTrack;
if (track && "mediaSession" in navigator) {
navigator.mediaSession.metadata = new MediaMetadata({
title: track.title,
artist: track.artist,
album: track.album || track.animeName,
artwork: [
// We could add artwork here if available in track
// { src: track.artworkUrl, sizes: '512x512', type: 'image/png' }
],
});
}
});
// ... existing effect for playback ... // ... existing effect for playback ...
$effect(() => { $effect(() => {
const track = player.currentTrack; const track = player.currentTrack;
console.log("Playback effect triggered", {
trackId: track?.id,
src: track?.src,
});
if (audioEl) { if (audioEl) {
if (track) { if (track) {
const newSrc = track.src; const newSrc = track.src;
@@ -83,7 +49,14 @@
// audioEl.src sets the attribute, currentSrc is the resolved URL // audioEl.src sets the attribute, currentSrc is the resolved URL
const newSrcAbsolute = new URL(newSrc, document.baseURI).href; const newSrcAbsolute = new URL(newSrc, document.baseURI).href;
console.log("Src check", {
currentSrc,
newSrcAbsolute,
match: currentSrc === newSrcAbsolute,
});
if (currentSrc !== newSrcAbsolute) { if (currentSrc !== newSrcAbsolute) {
console.log("Setting new src", newSrc);
audioEl.src = newSrc; audioEl.src = newSrc;
audioEl.play().catch((e) => { audioEl.play().catch((e) => {
console.warn("Autoplay blocked or failed", e); console.warn("Autoplay blocked or failed", e);
@@ -105,37 +78,25 @@
// ... existing callbacks ... // ... existing callbacks ...
// Bindings and Event Listeners // Bindings and Event Listeners
function onTimeUpdate() {
audioCtx.currentTime = audioEl.currentTime;
}
function onDurationChange() {
audioCtx.duration = audioEl.duration;
}
function onPlay() {
audioCtx.paused = false;
if ("mediaSession" in navigator)
navigator.mediaSession.playbackState = "playing";
}
function onPause() {
audioCtx.paused = true;
if ("mediaSession" in navigator)
navigator.mediaSession.playbackState = "paused";
}
function onEnded() { function onEnded() {
player.next(); player.next();
} }
// Sync MediaSession playback state with bound paused state
$effect(() => {
if ("mediaSession" in navigator) {
navigator.mediaSession.playbackState = audioCtx.paused
? "paused"
: "playing";
}
});
</script> </script>
<audio <audio
bind:this={audioEl} bind:this={audioEl}
ontimeupdate={onTimeUpdate} bind:currentTime={audioCtx.currentTime}
ondurationchange={onDurationChange} bind:duration={audioCtx.duration}
onplay={onPlay} bind:paused={audioCtx.paused}
onpause={onPause}
onended={onEnded} onended={onEnded}
class="hidden" class="hidden"
></audio> ></audio>

View File

@@ -13,23 +13,25 @@ export class AudioContext {
this.audioEl = el; this.audioEl = el;
} }
// Bindings will handle state updates, but we need methods to control play/pause
// from other components.
// Since we bind to `this.paused`, toggling it here will trigger the audio element.
play() { play() {
this.audioEl?.play(); this.paused = false;
} }
pause() { pause() {
this.audioEl?.pause(); this.paused = true;
} }
toggle() { toggle() {
if (this.paused) this.play(); this.paused = !this.paused;
else this.pause();
} }
seek(time: number) { seek(time: number) {
if (this.audioEl) { // Seeking is done by updating currentTime, which is bound to the audio element.
this.audioEl.currentTime = Math.max(0, Math.min(time, this.duration)); this.currentTime = Math.max(0, Math.min(time, this.duration));
}
} }
} }