player bar: the album line survives library plays, and lands with the title

Two halves of one defect family. The meta line preferred the queue item's
artist/album fields as a PAIR whenever either existed — but a library play
(playAlbum) writes only `artist`, with the record's name living inside
`sub` ("artist — album"), so `album: null` was taken at face value and
every library album lost its name from the bar (and the morning comment
claiming local rows carry neither field was simply wrong). Each half now
falls back to the `sub` split on its own, here and in the rail's byline —
which also restores the album for continuation items whose `sub` is a
bare artist.

And the line no longer trickles in: the buffering branch used to render
the artist alone, so the album flashed in a beat after the title when
playback started. The status gate is replaced by a REAL distinction — a
resolver-phase track has no `path` (playQueueIndex always writes one), so
"finding best source…" still shows as a bare label, and the moment a real
queue item owns the transport the full clickable line renders, buffering
or not. Measured: the first frame carrying the new title already carries
artist · album; no artist-only frame exists.
This commit is contained in:
KeelrLeek committed 2026-08-03 17:18:25 -05:00
1 parent e2cfed081c
commit 8cd56a433e
2 files changed
+30 -14

No files matched your search

+9 -1
View File
@@ -104,11 +104,19 @@
return sub.includes(" — ") ? sub.split(" — ")[0].trim() : sub;
});
// Artist / album split for the separate, clickable identity lines.
// Per field, like the player bar's: the item's own artist/album win when
// present (the continuation fill writes them beside a bare-artist `sub`),
// and each half falls back to the `sub` split on its own — a library play
// carries only `artist`, with the record's name living inside `sub`.
const metaParts = $derived.by(() => {
const sub = player.track?.sub ?? "";
return sub.includes(" — ")
const split = sub.includes(" — ")
? sub.split(" — ").map((s) => s.trim())
: [sub.trim(), ""];
return [
currentItem?.artist ?? split[0] ?? "",
currentItem?.album ?? split[1] ?? "",
];
});
const LOSSLESS = new Set(["FLAC", "WAV", "ALAC", "AIFF", "APE"]);
+21 -13
View File
@@ -43,21 +43,23 @@
const canScratch = $derived(!currentItem?.stream);
/** Artist and album for the separate, clickable meta lines.
*
* The queue item's OWN `artist` / `album` fields come first, and splitting
* `sub` on the em dash is only the fallback. `sub` is a display convenience
* that not every path fills the same way: the album-continuation fill
* (`maybeExtendAlbumQueue`) writes a bare artist into it while carrying the
* album right alongside, so a record played straight through lost its album
* name from the second track on — which is exactly what it looked like.
* Local library rows carry neither field, and those still fall back. */
* Per FIELD, not all-or-nothing. The queue paths disagree about what an
* item carries: the album-continuation fill writes artist AND album
* fields beside a bare-artist `sub`; a library play (`playAlbum`) writes
* only `artist`, with the record's name living inside `sub`
* ("artist — album"); old restored items may carry neither. Preferring
* the item's fields as a PAIR whenever either existed took `album: null`
* at face value and erased the record from every library play — each
* half now falls back to the `sub` split on its own. */
const metaParts = $derived.by(() => {
if (currentItem?.artist || currentItem?.album) {
return [currentItem.artist ?? "", currentItem.album ?? ""];
}
const sub = player.track?.sub ?? "";
return sub.includes(" — ")
const split = sub.includes(" — ")
? sub.split(" — ").map((s) => s.trim())
: [sub.trim(), ""];
return [
currentItem?.artist ?? split[0] ?? "",
currentItem?.album ?? split[1] ?? "",
];
});
const volumeIcon = $derived(
player.muted || player.volume === 0
@@ -791,8 +793,14 @@
<!-- Artist and album on ONE line, which is what a 62px bar can pay
for. The `.who` idiom from the album page: a 50%-opacity middot
between them, and no underline until hover. -->
{#if player.status === "buffering"}
<span class="who"><span class="sub">{metaParts[0] || "buffering…"}</span></span>
<!-- A resolver-phase track has no `path` (playQueueIndex always
writes one), and its `sub` IS the status line — show it bare.
The moment a real queue item owns the transport, the full
clickable line renders, buffering or not: gating it on
status=playing made the album flash in a beat after the
title and artist. -->
{#if player.track && !player.track.path}
<span class="who"><span class="sub">{player.track.sub || "buffering…"}</span></span>
{:else if player.track && (metaParts[0] || metaParts[1])}
<span class="who">
{#if metaParts[0]}