Widen thumbnail sampling window past platform bumpers

Many course platforms (Pluralsight, Packt, ...) open with a generic
branded bumper animation running 10-20s before the actual course
title card. The 8s candidate window landed squarely inside that
bumper and grabbed the platform logo instead of anything
course-specific. Candidates now spread across the first ~25s.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-24 20:33:37 -04:00
co-authored by Claude Sonnet 5
parent de9c05d0d0
commit 8220bb542a
3 changed files with 19 additions and 12 deletions
+1
View File
@@ -1,3 +1,4 @@
2026-08-25 00:33 UTC — Widen thumbnail sampling window past platform bumpers
2026-08-25 00:26 UTC — Fix race condition in thumbnail candidate generation
2026-08-25 00:20 UTC — Add autoplay, progress rings, duplicate-lesson detection, title-card thumbnails
2026-08-24 23:22 UTC — Add Favorites, storage drill-down, shortcuts, and What's New
+1 -1
View File
@@ -1 +1 @@
2026-08-25 00:26 UTC — fix race condition in thumbnail candidate generation
2026-08-25 00:33 UTC — widen thumbnail sampling window past platform bumpers
+17 -11
View File
@@ -926,15 +926,16 @@ def _generate_course_thumbnail(course_dir: Path) -> Optional[str]:
added later is still picked up on the next request past the short
in-memory cache above.
Course intros typically show a title card (course/lesson name, maybe
a logo) for the first several seconds before cutting to the
presenter - a single frame at a fixed offset can easily land past
that cut and grab someone mid-sentence instead. Rather than guess one
offset, this samples a handful of candidates in the first ~8 seconds
and keeps the one with the largest resulting JPEG: a title card (text,
graphics, a logo) compresses to a noticeably bigger file than a blank
fade-in or a plain talking-head frame, which is a cheap enough proxy
for "has more going on" without any real image analysis.
Course intros typically run a branded bumper animation (10-20s on
some platforms) followed by a title card before cutting to the
presenter - a single frame at a fixed offset can easily land inside
the bumper or past the cut into someone mid-sentence instead. Rather
than guess one offset, this samples candidates spread across the
first ~25 seconds and keeps the one with the largest resulting JPEG:
a title card or logo (text, graphics) compresses to a noticeably
bigger file than a blank fade-in or a plain talking-head frame, which
is a cheap enough proxy for "has more going on" without any real
image analysis.
"""
video_files = sorted(
f for f in course_dir.rglob('*')
@@ -945,8 +946,13 @@ def _generate_course_thumbnail(course_dir: Path) -> Optional[str]:
source = video_files[0]
duration = _probe_media_duration_seconds(source) or 0
max_offset = min(8.0, duration * 0.5) if duration else 6.0
candidate_offsets = sorted({o for o in (1.0, 2.5, 4.0, 6.0) if o <= max_offset}) or [1.0]
# Many course platforms (Pluralsight, Packt, ...) open with a
# generic branded bumper animation running 10-20s before the actual
# course title card - an 8s window landed squarely inside that
# bumper and grabbed the platform logo instead. Spread candidates
# further in to reach past it.
max_offset = min(25.0, duration * 0.5) if duration else 15.0
candidate_offsets = sorted({o for o in (2.0, 5.0, 8.0, 12.0, 16.0, 20.0, 25.0) if o <= max_offset}) or [2.0]
output_path = course_dir / AUTO_THUMBNAIL_FILENAME
best_candidate = None