From c1f4483a66abe3f03c096ee5e474fea5f9c7f342 Mon Sep 17 00:00:00 2001 From: Alexander Nicolay Date: Thu, 16 Jul 2026 23:48:38 +0200 Subject: [PATCH 1/2] Poster frame for shot videos --- src/matebot/sitegen.py | 17 ++++++++++++++++- src/matebot/web/app.js | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/matebot/sitegen.py b/src/matebot/sitegen.py index 2cbff4f..6192b6e 100644 --- a/src/matebot/sitegen.py +++ b/src/matebot/sitegen.py @@ -11,6 +11,8 @@ import importlib.resources import json import logging +import shutil +import subprocess from pathlib import Path from .slog import Shot, SlogError, parse_slog @@ -88,7 +90,20 @@ def _video_info(shots_dir: Path, out_dir: Path, sid: str) -> dict: offset = float(json.loads((shots_dir / f"{sid}.video.json").read_text())["offset"]) except (OSError, ValueError, KeyError): pass - return {"video": f"video/{sid}.mp4", "video_offset": offset} + info = {"video": f"video/{sid}.mp4", "video_offset": offset} + # poster frame: phones don't decode a frame until play, showing black + poster = out_dir / "video" / f"{sid}.jpg" + if (not poster.exists() or poster.stat().st_mtime < mp4.stat().st_mtime) and shutil.which("ffmpeg"): + proc = subprocess.run( + ["ffmpeg", "-hide_banner", "-loglevel", "error", "-y", "-ss", "0.5", + "-i", str(mp4), "-frames:v", "1", "-vf", "scale=640:-2", str(poster)], + capture_output=True, + ) + if proc.returncode != 0: + poster.unlink(missing_ok=True) + if poster.exists(): + info["poster"] = f"video/{sid}.jpg" + return info def generate(shots_dir: str | Path, out_dir: str | Path, *, title: str = "Shot Journal") -> int: diff --git a/src/matebot/web/app.js b/src/matebot/web/app.js index 01cc9b4..0dd456e 100644 --- a/src/matebot/web/app.js +++ b/src/matebot/web/app.js @@ -92,7 +92,7 @@ function renderDetail(id, shot, compareId, compare) { if (shot.video) { const holder = document.createElement("div"); holder.className = "chart-card video-card"; - holder.innerHTML = ` + holder.innerHTML = ` `; charts.appendChild(holder); VIDEO = holder.querySelector("video"); From b495f9eb92c04b4ce34494fde4af9b3c61630be4 Mon Sep 17 00:00:00 2001 From: Alexander Nicolay Date: Fri, 17 Jul 2026 00:17:50 +0200 Subject: [PATCH 2/2] Line length --- src/matebot/sitegen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/matebot/sitegen.py b/src/matebot/sitegen.py index 6192b6e..9beb58c 100644 --- a/src/matebot/sitegen.py +++ b/src/matebot/sitegen.py @@ -93,7 +93,8 @@ def _video_info(shots_dir: Path, out_dir: Path, sid: str) -> dict: info = {"video": f"video/{sid}.mp4", "video_offset": offset} # poster frame: phones don't decode a frame until play, showing black poster = out_dir / "video" / f"{sid}.jpg" - if (not poster.exists() or poster.stat().st_mtime < mp4.stat().st_mtime) and shutil.which("ffmpeg"): + stale = not poster.exists() or poster.stat().st_mtime < mp4.stat().st_mtime + if stale and shutil.which("ffmpeg"): proc = subprocess.run( ["ffmpeg", "-hide_banner", "-loglevel", "error", "-y", "-ss", "0.5", "-i", str(mp4), "-frames:v", "1", "-vf", "scale=640:-2", str(poster)],