Files
amqtrain/src/lib/components/player/PlayerRoot.svelte

146 lines
3.3 KiB
Svelte

<script lang="ts">
import { onMount, setContext } from "svelte";
import { player } from "$lib/player/store.svelte";
import { AudioContext, setAudioContext } from "./ctx.svelte";
import PlayerDesktop from "./PlayerDesktop.svelte";
import PlayerMobile from "./PlayerMobile.svelte";
// Initialize context
const audioCtx = new AudioContext();
setContext("amqtrain:player:audio-ctx", audioCtx);
let audioEl: HTMLAudioElement;
import { loadState, saveState } from "$lib/player/persist";
// ... existing imports ...
onMount(() => {
audioCtx.setElement(audioEl);
// Load state
const saved = loadState();
if (saved) {
player.init(saved);
}
// 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);
});
// 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;
if (audioEl) {
if (track) {
const newSrc = track.src;
if (audioEl.src !== newSrc) {
audioEl.src = newSrc;
audioEl.play().catch((e) => {
console.warn("Autoplay blocked or failed", e);
});
}
} else {
audioEl.removeAttribute("src");
}
// Update MediaSession playback state
if ("mediaSession" in navigator) {
navigator.mediaSession.playbackState = audioEl.paused
? "paused"
: "playing";
}
}
});
// ... 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();
}
</script>
<audio
bind:this={audioEl}
ontimeupdate={onTimeUpdate}
ondurationchange={onDurationChange}
onplay={onPlay}
onpause={onPause}
onended={onEnded}
class="hidden"
></audio>
<div class="contents">
<div class="lg:hidden">
<PlayerMobile />
</div>
<div class="hidden lg:block h-full">
<PlayerDesktop />
</div>
</div>