From 7748e787126bdd7b932784bfe61de047b15591e5 Mon Sep 17 00:00:00 2001 From: jenstandstad Date: Thu, 6 Aug 2026 12:59:15 +0200 Subject: [PATCH] Case insensitivity bite --- gnommo/cli.py | 5 ++++- gnommo/renderer.py | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/gnommo/cli.py b/gnommo/cli.py index d2c89be..339e82b 100644 --- a/gnommo/cli.py +++ b/gnommo/cli.py @@ -1138,7 +1138,10 @@ def _sync_shared_videos_to_local( if local_json_path.exists(): local_videos = _read_json(local_json_path) - _METADATA_FIELDS = ("duration", "has_audio") + # source_file is canonical from shared_assets/videos.json — repair it if a local + # entry drifted (e.g. an old import lowercased it to "outrovideo2.mov" while the + # real file is "OutroVideo2.mov"), which breaks the case-sensitive render rig. + _METADATA_FIELDS = ("duration", "has_audio", "source_file") added = [] metadata_updated = [] diff --git a/gnommo/renderer.py b/gnommo/renderer.py index 317fce5..84a4a7f 100644 --- a/gnommo/renderer.py +++ b/gnommo/renderer.py @@ -278,6 +278,28 @@ def render(plan: RenderPlan, output_path: Path, verbose: bool = False, log=None) ) +def _ci_resolve(path: Path) -> Path: + """Case-insensitive fallback for a file path. + + If `path` doesn't exist but a sibling with the same name in a different case + does, return that sibling. macOS's default filesystem is case-INsensitive, so a + `source_file` whose stored case drifted from the real file (e.g. "outrovideo2.mov" + vs "OutroVideo2.mov") still resolves locally — but on the case-SENSITIVE Linux of + the render rig / WSL it would otherwise hard-fail with "not found". This makes the + two behave the same. Returns `path` unchanged if no match (caller handles absence). + """ + if path.exists(): + return path + parent = path.parent + if not parent.is_dir(): + return path + target = path.name.lower() + for entry in parent.iterdir(): + if entry.name.lower() == target: + return entry + return path + + def _resolve_video_path( videos_dir: Path, video_source: VideoSource, @@ -326,6 +348,11 @@ def _resolve_video_path( else: resolved = source_path + # Tolerate case drift between the stored source_file and the real file — a no-op + # on macOS (case-insensitive) but the difference between working and "not found" + # on the case-sensitive render rig / WSL. + resolved = _ci_resolve(resolved) + if not resolved.exists(): # File not found anywhere — substitute PlaceholderVideo so FFmpeg doesn't crash placeholder = None