WIP: global player refactor pt. 1
This commit is contained in:
136
src/lib/components/player/PlayerRoot.svelte
Normal file
136
src/lib/components/player/PlayerRoot.svelte
Normal file
@@ -0,0 +1,136 @@
|
||||
<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 (track && audioEl) {
|
||||
// ...
|
||||
// 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"
|
||||
/>
|
||||
|
||||
<div class="contents">
|
||||
<div class="lg:hidden">
|
||||
<PlayerMobile />
|
||||
</div>
|
||||
<div class="hidden lg:block h-full">
|
||||
<PlayerDesktop />
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user