Files
amqtrain/src/lib/components/SongEntry.svelte
2026-02-05 23:51:27 -08:00

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>