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 ...
onMount(() => {
console.log("PlayerRoot mounted");
audioCtx.setElement(audioEl);
// Load state
@@ -25,56 +26,21 @@
}
// 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
$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);
});
// ... existing effect for persistence ...
// 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 ...
$effect(() => {
const track = player.currentTrack;
console.log("Playback effect triggered", {
trackId: track?.id,
src: track?.src,
});
if (audioEl) {
if (track) {
const newSrc = track.src;
@@ -83,7 +49,14 @@
// audioEl.src sets the attribute, currentSrc is the resolved URL
const newSrcAbsolute = new URL(newSrc, document.baseURI).href;
console.log("Src check", {
currentSrc,
newSrcAbsolute,
match: currentSrc === newSrcAbsolute,
});
if (currentSrc !== newSrcAbsolute) {
console.log("Setting new src", newSrc);
audioEl.src = newSrc;
audioEl.play().catch((e) => {
console.warn("Autoplay blocked or failed", e);
@@ -105,37 +78,25 @@
// ... existing callbacks ...
// 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() {
player.next();
}
// Sync MediaSession playback state with bound paused state
$effect(() => {
if ("mediaSession" in navigator) {
navigator.mediaSession.playbackState = audioCtx.paused
? "paused"
: "playing";
}
});
</script>
<audio
bind:this={audioEl}
ontimeupdate={onTimeUpdate}
ondurationchange={onDurationChange}
onplay={onPlay}
onpause={onPause}
bind:currentTime={audioCtx.currentTime}
bind:duration={audioCtx.duration}
bind:paused={audioCtx.paused}
onended={onEnded}
class="hidden"
></audio>

View File

@@ -13,23 +13,25 @@ export class AudioContext {
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() {
this.audioEl?.play();
this.paused = false;
}
pause() {
this.audioEl?.pause();
this.paused = true;
}
toggle() {
if (this.paused) this.play();
else this.pause();
this.paused = !this.paused;
}
seek(time: number) {
if (this.audioEl) {
this.audioEl.currentTime = Math.max(0, Math.min(time, this.duration));
}
// Seeking is done by updating currentTime, which is bound to the audio element.
this.currentTime = Math.max(0, Math.min(time, this.duration));
}
}