feat: add resolve_keyframe helper to extract sorted-keyframe lookup

Adds a pure function that returns the latest keyframe at or before a
given time (with tolerance), replacing the inline lookup pattern that
appears multiple times in main.py. Includes 6 tests covering empty
list, before-first, exact match, between, after-last, and tolerance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 15:48:00 +02:00
parent b9e9fa927e
commit 8e8c8b9774
2 changed files with 48 additions and 1 deletions
+15
View File
@@ -53,6 +53,21 @@ def format_time(seconds: float) -> str:
return f"{m}:{s:04.1f}" return f"{m}:{s:04.1f}"
def resolve_keyframe(
keyframes: list[tuple[float, float, str | None, bool, bool]],
t: float,
tolerance: float = 0.05,
) -> tuple[float, float, str | None, bool, bool] | None:
"""Return the latest keyframe at or before *t*, or None."""
result = None
for kf in keyframes:
if kf[0] <= t + tolerance:
result = kf
else:
break
return result
def build_ffmpeg_command( def build_ffmpeg_command(
input_path: str, start: float, output_path: str, input_path: str, start: float, output_path: str,
short_side: int | None = None, short_side: int | None = None,
+33 -1
View File
@@ -1,5 +1,5 @@
import tempfile, os, json import tempfile, os, json
from main import build_export_path, format_time, build_ffmpeg_command, build_sequence_dir, build_audio_extract_command, build_annotation_json_path, upsert_clip_annotation from main import build_export_path, format_time, resolve_keyframe, build_ffmpeg_command, build_sequence_dir, build_audio_extract_command, build_annotation_json_path, upsert_clip_annotation
from main import ProcessedDB from main import ProcessedDB
@@ -369,3 +369,35 @@ def test_db_default_profile_backward_compat():
assert db.get_profiles() == ["default"] assert db.get_profiles() == ["default"]
finally: finally:
os.unlink(path) os.unlink(path)
# --- resolve_keyframe ---
def test_resolve_keyframe_empty():
assert resolve_keyframe([], 5.0) is None
def test_resolve_keyframe_before_first():
kfs = [(3.0, 0.5, None, False, False)]
assert resolve_keyframe(kfs, 1.0) is None
def test_resolve_keyframe_exact():
kfs = [(2.0, 0.3, "9:16", True, False)]
assert resolve_keyframe(kfs, 2.0) == (2.0, 0.3, "9:16", True, False)
def test_resolve_keyframe_between():
kfs = [
(1.0, 0.2, None, False, False),
(5.0, 0.8, "1:1", False, True),
]
assert resolve_keyframe(kfs, 3.0) == (1.0, 0.2, None, False, False)
def test_resolve_keyframe_after_last():
kfs = [
(1.0, 0.2, None, False, False),
(5.0, 0.8, "1:1", False, True),
]
assert resolve_keyframe(kfs, 10.0) == (5.0, 0.8, "1:1", False, True)
def test_resolve_keyframe_tolerance():
kfs = [(4.0, 0.5, None, True, True)]
assert resolve_keyframe(kfs, 3.96) == (4.0, 0.5, None, True, True)