diff --git a/src/servers/sidecar/music/indexer.ts b/src/servers/sidecar/music/indexer.ts index e53a64d4..ddc9fba3 100644 --- a/src/servers/sidecar/music/indexer.ts +++ b/src/servers/sidecar/music/indexer.ts @@ -363,7 +363,11 @@ async function compressCover(srcAbs: string, destAbs: string): Promise } } -/** Grab a representative frame (~10% in, capped at 30s to skip intros) and compress it like a cover. */ +/** + * Poster = a representative frame, compressed like a cover. Seek ~10% in (capped at 30s) to skip + * intros/title cards, then let ffmpeg's `thumbnail` filter pick the most representative frame from the + * next ~300 (avoids black/uniform frames — e.g. a fade-in from black). + */ async function generateVideoPoster(srcAbs: string, destAbs: string, durationSec?: number): Promise { const ts = durationSec && durationSec > 0 ? Math.min(30, Math.max(1, Math.floor(durationSec * 0.1))) : 5; try { @@ -375,10 +379,10 @@ async function generateVideoPoster(srcAbs: string, destAbs: string, durationSec? String(ts), '-i', srcAbs, + '-vf', + `thumbnail=n=300,scale='min(iw,${COVER_MAX_PX})':'min(ih,${COVER_MAX_PX})':force_original_aspect_ratio=decrease`, '-frames:v', '1', - '-vf', - `scale='min(iw,${COVER_MAX_PX})':'min(ih,${COVER_MAX_PX})':force_original_aspect_ratio=decrease`, '-q:v', '5', destAbs,