103 lines
2.4 KiB
Svelte
103 lines
2.4 KiB
Svelte
<script module lang="ts">
|
|
let activeMediaToken: symbol | null = null;
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
type SongType = 1 | 2 | 3 | number;
|
|
|
|
type SongEntryProps = {
|
|
animeName: string;
|
|
type: SongType;
|
|
number: number;
|
|
songName: string;
|
|
artistName: string | null;
|
|
fileName?: string | null;
|
|
showPlayer?: boolean;
|
|
};
|
|
|
|
let {
|
|
animeName,
|
|
type,
|
|
number,
|
|
songName,
|
|
artistName,
|
|
fileName = null,
|
|
showPlayer = false,
|
|
}: SongEntryProps = $props();
|
|
|
|
let paused = $state(true);
|
|
const mediaToken = Symbol("song-entry");
|
|
|
|
const typeLabelMap: Record<number, string> = {
|
|
1: "OP",
|
|
2: "ED",
|
|
3: "INS",
|
|
};
|
|
|
|
const typeLabel = $derived(typeLabelMap[type] ?? `T${type}`);
|
|
|
|
const displayTypeNumber = $derived.by(() => {
|
|
const num = Number(number);
|
|
if (!Number.isFinite(num) || num === 0) return typeLabel;
|
|
return `${typeLabel}${num}`;
|
|
});
|
|
|
|
const artistDisplay = $derived.by(
|
|
() => artistName?.trim() || "Unknown Artist",
|
|
);
|
|
|
|
const mediaTitle = $derived.by(() => `${animeName} — ${displayTypeNumber}`);
|
|
|
|
const mediaArtist = $derived.by(() => artistDisplay);
|
|
|
|
const mediaAlbum = $derived.by(() => `${animeName} (${displayTypeNumber})`);
|
|
|
|
$effect(() => {
|
|
if (!showPlayer || !fileName) return;
|
|
if (typeof navigator === "undefined") return;
|
|
const mediaSession = navigator.mediaSession;
|
|
if (!mediaSession || typeof MediaMetadata === "undefined") return;
|
|
|
|
if (!paused) {
|
|
activeMediaToken = mediaToken;
|
|
mediaSession.metadata = new MediaMetadata({
|
|
title: songName,
|
|
artist: mediaArtist,
|
|
album: mediaAlbum,
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (activeMediaToken !== mediaToken) return;
|
|
activeMediaToken = null;
|
|
});
|
|
</script>
|
|
|
|
<div class="rounded border px-3 py-2">
|
|
<div class="flex flex-wrap items-baseline gap-x-2 gap-y-1">
|
|
<span class="text-sm text-muted-foreground">{animeName}</span>
|
|
<span class="text-sm text-muted-foreground">•</span>
|
|
<span class="text-sm text-muted-foreground">{displayTypeNumber}</span>
|
|
</div>
|
|
|
|
<div class="mt-1 font-medium">
|
|
{songName}
|
|
<span class="text-sm text-muted-foreground">— {artistDisplay}</span>
|
|
</div>
|
|
|
|
{#if showPlayer && fileName}
|
|
<div class="mt-2">
|
|
<audio
|
|
class="w-full"
|
|
controls
|
|
preload="metadata"
|
|
title={`${mediaTitle} — ${songName} — ${mediaArtist}`}
|
|
bind:paused
|
|
>
|
|
<source src={`/cdn/${fileName}`} type="audio/mpeg" />
|
|
Your browser does not support the audio element.
|
|
</audio>
|
|
</div>
|
|
{/if}
|
|
</div>
|