fix(cover): art reaches Now Playing on first play (restore + cold cache)

Two gaps left cover art missing for the most common play paths:
- Boot-restore preloaded the episode with cachedCoverPath??undefined racing
  the fire-and-forget prefetch; a cold preload + fast-path play re-applied
  art via video-add, which produces a NON-albumart track (verified) that
  mpv's Now Playing artwork logic ignores. load() now awaits the bounded
  fetch (covers ~300ms, 8s cap) so the cover is present at load-time.
- Removed the dead video-add re-apply (fast path + addCoverArt method +
  interface) and the play() late-add fallback; a cold-cache play now
  prefetches for next time instead.
- FeedPage prefetches covers for the focus window (single-flight, cached)
  so ordinary plays land on a warm cache.
Verified: preload with awaited cover -> albumart track present (2 tracks).
This commit is contained in:
2026-08-12 10:22:49 -04:00
parent deac6081ca
commit bd7d988741
3 changed files with 28 additions and 29 deletions

View File

@@ -20,6 +20,7 @@ import { createMemo, createEffect, For, Show, onMount, onCleanup } from "solid-j
import { useFeedStore } from "@/stores/feed";
import { useDownloadStore } from "@/stores/download";
import { useAppStore } from "@/stores/app";
import { prefetchCoverArt } from "@/utils/cover-art";
import { DownloadStatus } from "@/types/episode";
import { format } from "date-fns";
import { useTheme } from "@/context/ThemeContext";
@@ -63,6 +64,22 @@ function FeedPage() {
() => feedStore.getAllEpisodesChronological() as EpItem[],
);
// ── Cover warm-up ────────────────────────────────────────────────────────
// Prefetch covers for episodes around the focus (plus the top of the
// list) so plays land on a warm cache: cover-art-files only applies at
// file load, and there is no working runtime fallback. Single-flight +
// cache short-circuit keep repeat runs cheap (hits resolve immediately).
createEffect(() => {
const list = episodes();
const focusIdx = focusedEpIdx();
const start = Math.max(0, focusIdx - 10);
const end = Math.min(list.length, focusIdx + 11);
for (let i = start; i < end; i++) {
const item = list[i];
if (item?.feed.podcast.coverUrl) prefetchCoverArt(item.feed.podcast.coverUrl);
}
});
// ── Fetch More ───────────────────────────────────────────────────────────
// A "[Fetch More]" row at the bottom of the list advances every feed's
// loaded window by 50 episodes. manual mode: Enter on the row. auto mode: