music indexer: pick video poster via ffmpeg thumbnail filter (dodge black frames)

The fixed ~10% frame grab could land on a black/near-black frame for clips that
fade in from black (or on a title card). Keep the ~10% seek to skip intros, but
select the frame with `thumbnail=n=300` — ffmpeg picks the most representative
frame from the batch, which avoids uniform/black frames. Verified on a
fade-from-black video: luma ~122 (vs 0 at t=0), and it dodges the fade even when
seeking from the start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 15:05:14 +00:00
co-authored by Claude Opus 4.8
parent 4d3c17b2df
commit f408e4dd6f
+7 -3
View File
@@ -363,7 +363,11 @@ async function compressCover(srcAbs: string, destAbs: string): Promise<boolean>
}
}
/** 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<boolean> {
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,