Improvements
This commit is contained in:
+47
-10
@@ -1259,6 +1259,27 @@ def _generate_slides_json(directory: Path, verbose: bool) -> None:
|
||||
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:
|
||||
"""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)")
|
||||
continue
|
||||
|
||||
# Build the video entry
|
||||
video_entry = {
|
||||
"source_file": video_file.name,
|
||||
"output_file": video_file.name,
|
||||
"cutout": "square",
|
||||
"filter": [],
|
||||
}
|
||||
# Build the video entry with every tweakable parameter spelled out at
|
||||
# its default, so nothing is an invisible optional (that's what makes
|
||||
# end_on/layer/take/… easy to miss). Auto-managed fields (duration,
|
||||
# has_audio) are filled in later by the metadata probe.
|
||||
video_entry = {"source_file": video_file.name, **_VIDEO_DEFAULTS}
|
||||
if verbose:
|
||||
print(f" Added: {video_id}")
|
||||
|
||||
existing_videos[video_id] = video_entry
|
||||
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
|
||||
with open(videos_json_path, "w", encoding="utf-8") as f:
|
||||
json.dump(existing_videos, f, indent=2)
|
||||
if added_count > 0:
|
||||
print(f" Updated {videos_json_path.name} (+{added_count} videos)")
|
||||
bits = []
|
||||
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:
|
||||
print(f" No new videos to add")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user