Improving de-shimy trip

This commit is contained in:
2026-07-16 17:18:15 +02:00
parent fa8512ff3d
commit e5bb437768
+47 -10
View File
@@ -3691,6 +3691,32 @@ def _parse_slide_range(slides_arg: str) -> tuple[str, Optional[str]]:
return start_slide, end_slide return start_slide, end_slide
def _resolve_pause_duration(
entry: dict, video_id: str, videos_dir: Path, shared_duration: dict[str, float]
) -> Optional[float]:
"""Resolve a clip's duration for auto-setting pause_narration.
Tries, in order: the local videos.json entry's own 'duration', the shared
library's duration (for is_shared clips whose metadata lives elsewhere), then
a direct ffprobe of the source file. Returns None if none succeed.
"""
dur = entry.get("duration") or shared_duration.get(video_id.lower())
if dur:
return float(dur)
source_file = entry.get("source_file")
if source_file:
candidate = videos_dir / source_file
if candidate.exists():
try:
from .preprocessor import get_video_duration
return round(get_video_duration(candidate), 3)
except Exception:
return None
return None
def _project_markers_to_videos( def _project_markers_to_videos(
markers: list[str], videos_json_path: Path, config, project_path: Path = None markers: list[str], videos_json_path: Path, config, project_path: Path = None
) -> None: ) -> None:
@@ -3737,11 +3763,12 @@ def _project_markers_to_videos(
if not projection: if not projection:
return return
# Build a case-insensitive index of shared_assets pause_narration values. # Build case-insensitive indexes of shared_assets pause_narration and duration.
# When a video is marked is_shared but its local entry is missing pause_narration, # When a video is marked is_shared its metadata lives in the shared canonical
# we pull the value from the shared canonical entry so it's never lost when # entry, not the local one — so a pause-prefix marker on a shared clip would
# the ETL writes back cutout/layer under a lowercase key. # otherwise never get pause_narration set (the local entry has no duration).
_shared_pause: dict[str, float] = {} _shared_pause: dict[str, float] = {}
_shared_duration: dict[str, float] = {}
for _shared_candidate in [ for _shared_candidate in [
project_path / "shared_assets" / "videos.json", project_path / "shared_assets" / "videos.json",
project_path.parent / "shared_assets" / "videos.json", project_path.parent / "shared_assets" / "videos.json",
@@ -3754,6 +3781,9 @@ def _project_markers_to_videos(
pn = _v.get("pause_narration") pn = _v.get("pause_narration")
if pn: if pn:
_shared_pause[_k.lower()] = float(pn) _shared_pause[_k.lower()] = float(pn)
dur = _v.get("duration")
if dur:
_shared_duration[_k.lower()] = float(dur)
except (json.JSONDecodeError, OSError): except (json.JSONDecodeError, OSError):
pass pass
break break
@@ -3773,12 +3803,19 @@ def _project_markers_to_videos(
video_changed = False video_changed = False
for field, value in fields.items(): for field, value in fields.items():
if field == "_auto_pause": if field == "_auto_pause":
# Write pause_narration = duration only when: # A pause-prefix marker (vftp:, vfbp:, …) means "freeze the
# narration for this clip's whole length", so pause_narration
# must equal the clip's duration. Set it whenever:
# - marker is a pause-prefix (value is True) # - marker is a pause-prefix (value is True)
# - pause_narration not already set (preserve manual overrides) # - pause_narration not already set (preserve manual overrides)
# - duration is known (probed by import) # - a duration can be resolved (local entry, shared library,
if value and not entry.get("pause_narration") and entry.get("duration"): # or by probing the file as a last resort)
entry["pause_narration"] = entry["duration"] if value and not entry.get("pause_narration"):
dur = _resolve_pause_duration(
entry, video_id, json_path.parent, _shared_duration
)
if dur:
entry["pause_narration"] = dur
changed = True changed = True
video_changed = True video_changed = True
elif entry.get(field) != value: elif entry.get(field) != value:
@@ -3786,8 +3823,8 @@ def _project_markers_to_videos(
changed = True changed = True
video_changed = True video_changed = True
# For is_shared entries: inherit pause_narration from shared_assets if # For is_shared entries: inherit pause_narration from shared_assets if
# not already set locally (handles case where explicit pause_narration # still not set (handles an explicit pause_narration that lives on a
# lives on a different-case key in the shared library). # different-case key in the shared library).
if entry.get("is_shared") and not entry.get("pause_narration"): if entry.get("is_shared") and not entry.get("pause_narration"):
shared_pn = _shared_pause.get(video_id.lower()) shared_pn = _shared_pause.get(video_id.lower())
if shared_pn: if shared_pn: