Fix to the placement of
This commit is contained in:
@@ -1503,9 +1503,12 @@
|
||||
},
|
||||
"Logo": {
|
||||
"source_file": "Logo.mov",
|
||||
"duration": 14.0,
|
||||
"duration": 18.0,
|
||||
"has_audio": true,
|
||||
"is_shared": true
|
||||
"is_shared": true,
|
||||
"cutout": "fullscreen",
|
||||
"layer": "above",
|
||||
"pause_narration": 14.0
|
||||
},
|
||||
"MontageZoom": {
|
||||
"source_file": "MontageZoom.mp4",
|
||||
|
||||
@@ -1501,12 +1501,13 @@
|
||||
"has_audio": false,
|
||||
"is_shared": true
|
||||
},
|
||||
"Logo": {
|
||||
"source_file": "Logo.mov",
|
||||
"duration": 14.0,
|
||||
"source_file": "Logo.mov",
|
||||
"duration": 18.0,
|
||||
"has_audio": true,
|
||||
"is_shared": true
|
||||
},
|
||||
"is_shared": true,
|
||||
"cutout": "fullscreen",
|
||||
"layer": "above",
|
||||
"pause_narration": 14.0
|
||||
"MontageZoom": {
|
||||
"source_file": "MontageZoom.mp4",
|
||||
"duration": 17.0,
|
||||
|
||||
+26
-47
@@ -3744,6 +3744,7 @@ def _print_render_plan_details(plan, marker_timings, slides: dict, events=None)
|
||||
so markers the raw alignment marks unaligned still show their real position.
|
||||
"""
|
||||
from .models import CAMERA_PRESETS
|
||||
from .transformer import _SHORTHAND_PREFIXES
|
||||
|
||||
events_by_id = {e["id"]: e for e in (events or [])}
|
||||
|
||||
@@ -3817,44 +3818,13 @@ def _print_render_plan_details(plan, marker_timings, slides: dict, events=None)
|
||||
else:
|
||||
aligned_count += 1
|
||||
print(f' {marker_id:6} {_st}{conf_str} "{context}"')
|
||||
elif any(
|
||||
marker_id.startswith(p)
|
||||
for p in (
|
||||
"video:",
|
||||
"vft:",
|
||||
"vfb:",
|
||||
"vf2t:",
|
||||
"vf2b:",
|
||||
"vst:",
|
||||
"vsb:",
|
||||
"vftp:",
|
||||
"vfbp:",
|
||||
"vf2tp:",
|
||||
"vf2bp:",
|
||||
"vstp:",
|
||||
"vsbp:",
|
||||
elif (
|
||||
_vpfx := next(
|
||||
(p for p in _SHORTHAND_PREFIXES if marker_id.startswith(p)), None
|
||||
)
|
||||
):
|
||||
) or marker_id.startswith("video:"):
|
||||
aligned_count += 1
|
||||
pfx_len = next(
|
||||
len(p)
|
||||
for p in (
|
||||
"video:",
|
||||
"vft:",
|
||||
"vfb:",
|
||||
"vf2t:",
|
||||
"vf2b:",
|
||||
"vst:",
|
||||
"vsb:",
|
||||
"vftp:",
|
||||
"vfbp:",
|
||||
"vf2tp:",
|
||||
"vf2bp:",
|
||||
"vstp:",
|
||||
"vsbp:",
|
||||
)
|
||||
if marker_id.startswith(p)
|
||||
)
|
||||
pfx_len = len(_vpfx) if _vpfx else len("video:")
|
||||
# Handles are stored lowercased in videos.json (and the plan's video
|
||||
# events), so lowercase before the lookup — otherwise a camel-cased
|
||||
# marker like vst:KnightRotating misses and shows '?'.
|
||||
@@ -3863,33 +3833,42 @@ def _print_render_plan_details(plan, marker_timings, slides: dict, events=None)
|
||||
event = video_events_by_id.get(video_id)
|
||||
if event:
|
||||
cutout_name = event.cutout_name
|
||||
end_on = event.video_source.end_on or "next_slide"
|
||||
# The resolved per-occurrence policy (incl. inline overrides), not
|
||||
# just the videos.json default.
|
||||
end_on = event.end_on or event.video_source.end_on or "next_slide"
|
||||
layer_tag = f" [{event.layer}]"
|
||||
# FINAL (output-time) window from the plan — pause-shifted, same
|
||||
# base as the slides above. Showing start→end makes end_on visible:
|
||||
# the clip should stop at the next slide/video's time. (Previously
|
||||
# this printed the RAW pre-pause marker time, which looked like an
|
||||
# 18s drift against the pause-shifted slides.)
|
||||
t_str = (
|
||||
f"{_format_time(event.start_time)}→{_format_time(event.end_time)}"
|
||||
)
|
||||
else:
|
||||
# No resolved event — but the shorthand prefix itself fixes the
|
||||
# cutout and layer (vst: = square/above), so never show '?'.
|
||||
from .transformer import _SHORTHAND_PREFIXES
|
||||
|
||||
_pfx = next(
|
||||
(p for p in _SHORTHAND_PREFIXES if marker_id.startswith(p)), None
|
||||
)
|
||||
if _pfx:
|
||||
cutout_name, _layer = _SHORTHAND_PREFIXES[_pfx]
|
||||
if _vpfx:
|
||||
cutout_name, _layer = _SHORTHAND_PREFIXES[_vpfx]
|
||||
layer_tag = f" [{_layer}]"
|
||||
else:
|
||||
cutout_name = "?"
|
||||
layer_tag = ""
|
||||
end_on = "next_slide"
|
||||
t_str = _format_time(timing.timestamp) # no event → raw fallback
|
||||
|
||||
cache_ind = " 📁" if video_id in plan.cached_files else ""
|
||||
print(
|
||||
f" {marker_id:20} {time_str} in '{cutout_name}' [{end_on}]{layer_tag}{cache_ind}"
|
||||
f" {marker_id:28} {t_str} in '{cutout_name}' [{end_on}]{layer_tag}{cache_ind}"
|
||||
)
|
||||
elif marker_id.startswith("narration:"):
|
||||
aligned_count += 1
|
||||
video_id = marker_id[10:]
|
||||
video_id = marker_id[10:].lower()
|
||||
cache_ind = " 📁" if video_id in plan.cached_files else ""
|
||||
print(f" {marker_id:20} {time_str} (continuous){cache_ind}")
|
||||
# Final (output-time) start from the plan, consistent with slides/videos.
|
||||
_nev = video_events_by_id.get(video_id)
|
||||
_nt = _format_time(_nev.start_time) if _nev else time_str
|
||||
print(f" {marker_id:20} {_nt} (continuous){cache_ind}")
|
||||
elif marker_id in CAMERA_PRESETS:
|
||||
aligned_count += 1
|
||||
print(f" {time_str} [{marker_id}]")
|
||||
|
||||
@@ -450,6 +450,10 @@ class VideoEvent:
|
||||
cutout: "CutoutDefinition"
|
||||
cutout_name: str = "" # resolved cutout name (e.g. "fullscreen"), for display
|
||||
layer: str = "above" # "above" = on top of slides; "below" = behind slides
|
||||
# Resolved per-occurrence end policy (next_slide/next_video/end/loop/…). Kept so
|
||||
# the render-plan listing can report the ACTUAL end rule (incl. inline overrides),
|
||||
# not just the videos.json default. Purely informational; end_time is authoritative.
|
||||
end_on: str = ""
|
||||
# Resolved per-occurrence CSS-like cutout placement (see VideoSource).
|
||||
object_fit: str = "cover"
|
||||
object_position: str = "center"
|
||||
|
||||
@@ -1512,6 +1512,7 @@ def _extract_video_events(
|
||||
cutout=cutout,
|
||||
cutout_name=cutout_name,
|
||||
layer=layer,
|
||||
end_on=end_on or "",
|
||||
volume=volume,
|
||||
object_fit=object_fit,
|
||||
object_position=object_position,
|
||||
|
||||
Reference in New Issue
Block a user