Two small fixes:
1. Directory scanner sort inversion:
The Dashboard's fast-path for oldest/newest sort assumes activeData
is stored newest-first (generated sessions prepend new items). The
scanner was writing oldest-first, so both sort modes appeared inverted.
Fix: sort files by mtime DESCENDING (newest first) and assign
gen_index via (total-1-i) so oldest=0, newest=N-1 is preserved.
2. Video click-to-fullscreen removed:
Clicking a video in the Dashboard no longer triggers browser
fullscreen — the interaction was disruptive. Videos still autoplay
when visible and double-click still toggles favorite.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Oldest/Newest sort in the Dashboard uses (gen_index ?? id) as the sort
key. Scanned items had no gen_index and their id was a scan-time
timestamp + random number, which didn't reflect file chronology at all.
Result: Oldest and Newest sort produced effectively random order.
Fix:
- os.scandir captures mtime alongside each file path
- Files sorted by (mtime, path) ascending — oldest first
- Each item gets a sequential gen_index (0 = oldest, N-1 = newest)
- Applied to both new-scan path (_process_single_image) and
cached-manifest path (existing sessions get re-indexed on next scan)
Newest files sort to top in Newest mode, bottom in Oldest mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds _probe_mp4_dimensions() — a minimal ISO BMFF container parser that
extracts real width/height from MP4/MOV/M4V files without any new
dependencies. Reads only box headers (a few hundred bytes) by navigating
moov → trak → tkhd and parsing the 16.16 fixed-point dimensions.
Handles:
- 32-bit and 64-bit box sizes (size=1 largesize)
- Version 0 and version 1 tkhd boxes (time field sizing differs)
- Multiple tracks — audio tracks have 0x0 dimensions, loop until a
video track with non-zero dimensions is found
- Container boxes (moov, trak, mdia, minf, stbl, edts) recursively
- Graceful fallback to 1280x720 default if parsing fails (WebM, corrupt)
Also fixes cached-manifest path: if a video entry exists in a previous
scan's manifest but has missing or stale default (1280x720) dimensions,
re-probe the actual file to get real values. This fixes existing sessions
where videos were scanned before this probe was added.
Resolves the "all square cards" issue where the grid's average aspect
ratio calculation was poisoned by uniform 1280x720 defaults across all
videos in the dataset.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds video file support throughout the Dashboard with zero new Python
dependencies — browsers handle all playback, metadata, and thumbnails
natively via HTML5 <video> elements.
directory_scanner.py:
- Add VIDEO_EXTENSIONS (.mp4, .webm, .mov, .m4v) to scan list
- _process_single_image() detects videos by extension and creates a
video manifest item with media_type="video"
- Videos get default 1280x720 dimensions; browser updates on loadedmetadata
- Image items now tagged with media_type="image" for symmetry
Dashboard (logic_ui.js createCard):
- Renders <video preload="none" muted loop playsinline> for video items
- Hides REVISE and upscale buttons for videos (don't apply)
- Shows "▶ VIDEO" badge in top-left corner
- Hover-play: videos play on mouseenter, pause+reset on mouseleave
- Click: requests native browser fullscreen with controls
- loadedmetadata handler updates card aspect ratio from videoWidth/videoHeight
Dashboard (logic_virtual.js):
- Lazy loader extended to swap data-src → src for <video> elements
CSS (report.css):
- .video-badge styling (purple pill, top-left)
- .card video positioning (absolute, cover-fit)
Works with any codec the browser supports (H.264, VP9, AV1, H.265).
Existing features unchanged: favorites, rejects, sorting, filtering,
DOM card pool, merge sessions, quick favorite hotkeys all work on videos.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>