Improvements

This commit is contained in:
2026-07-23 14:45:28 +02:00
parent cc566208c5
commit 715a36cf6e
+47 -10
View File
@@ -1259,6 +1259,27 @@ def _generate_slides_json(directory: Path, verbose: bool) -> None:
print(f" [{slide_id}]") print(f" [{slide_id}]")
# Every user-tweakable video parameter with its default value. Written into
# each new videos.json entry (and backfilled onto existing ones) so nothing is
# an invisible optional. Auto-managed fields (output_file, duration, has_audio,
# is_shared, attribution) are intentionally omitted — they're set by the tool.
# end_on defaults to null = "use the marker-type default" (video → next_slide,
# narration → play to end); set it to "next_slide", "end", or "take" explicitly.
_VIDEO_DEFAULTS = {
"cutout": "square", # named zone from project.json cutouts
"layer": "above", # above | mid | below (relative to slides/narrator)
"filter": [], # preprocessing filter chain (empty = none)
"take": None, # max seconds to play (null = to next slide/end)
"skip": 0.0, # seconds to skip at the start
"zoom": 1.0, # scale within the cutout
"volume": 1.0, # audio volume multiplier
"use_audio_channels": "both", # both | left | right
"always_visible": False, # always on screen (like the talking head)
"pause_narration": 0.0, # seconds to freeze narration for a cutscene
"end_on": None, # null | next_slide | end | take
}
def _import_videos(videos_dir: Path, config, verbose: bool) -> None: def _import_videos(videos_dir: Path, config, verbose: bool) -> None:
"""Import video files into videos.json. """Import video files into videos.json.
@@ -1336,25 +1357,41 @@ def _import_videos(videos_dir: Path, config, verbose: bool) -> None:
print(f" Skipping {video_id} (already exists)") print(f" Skipping {video_id} (already exists)")
continue continue
# Build the video entry # Build the video entry with every tweakable parameter spelled out at
video_entry = { # its default, so nothing is an invisible optional (that's what makes
"source_file": video_file.name, # end_on/layer/take/… easy to miss). Auto-managed fields (duration,
"output_file": video_file.name, # has_audio) are filled in later by the metadata probe.
"cutout": "square", video_entry = {"source_file": video_file.name, **_VIDEO_DEFAULTS}
"filter": [],
}
if verbose: if verbose:
print(f" Added: {video_id}") print(f" Added: {video_id}")
existing_videos[video_id] = video_entry existing_videos[video_id] = video_entry
added_count += 1 added_count += 1
if added_count > 0 or removed_count > 0: # Backfill missing defaults onto existing (non-shared) entries so every knob
# is visible there too. setdefault only adds absent keys — user-set values
# and the ETL-projected cutout/layer are never overwritten.
backfilled = 0
for vid_id, entry in existing_videos.items():
if not isinstance(entry, dict) or entry.get("is_shared"):
continue
before = len(entry)
for k, v in _VIDEO_DEFAULTS.items():
entry.setdefault(k, list(v) if isinstance(v, list) else v)
if len(entry) != before:
backfilled += 1
if added_count > 0 or removed_count > 0 or backfilled > 0:
# Write updated videos.json # Write updated videos.json
with open(videos_json_path, "w", encoding="utf-8") as f: with open(videos_json_path, "w", encoding="utf-8") as f:
json.dump(existing_videos, f, indent=2) json.dump(existing_videos, f, indent=2)
if added_count > 0: bits = []
print(f" Updated {videos_json_path.name} (+{added_count} videos)") if added_count:
bits.append(f"+{added_count} new")
if backfilled:
bits.append(f"{backfilled} backfilled with defaults")
if bits:
print(f" Updated {videos_json_path.name} ({', '.join(bits)})")
else: else:
print(f" No new videos to add") print(f" No new videos to add")