WIP: global player pt. 5 svelte bindings
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user