Derive external timeline duration from sections
This commit is contained in:
@@ -11589,14 +11589,10 @@ app.registerExtension({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawDuration =
|
|
||||||
self._resolveNodeLinkedValue(timelineNode, "duration", { decimals: 3 }) ??
|
|
||||||
parseFloat(self._readNodeWidgetValue(timelineNode, "duration") || 0);
|
|
||||||
const duration = Math.max(0.1, Number.isFinite(rawDuration) ? rawDuration : 5.0);
|
|
||||||
|
|
||||||
const sectionSetNode = self._findLinkedOriginNode(timelineNode, "section_set");
|
const sectionSetNode = self._findLinkedOriginNode(timelineNode, "section_set");
|
||||||
const setClass = sectionSetNode?.comfyClass || sectionSetNode?.type || "";
|
const setClass = sectionSetNode?.comfyClass || sectionSetNode?.type || "";
|
||||||
const sections = [];
|
const sections = [];
|
||||||
|
let duration = 0;
|
||||||
if (sectionSetNode && setClass === "TimelineSectionSetCS") {
|
if (sectionSetNode && setClass === "TimelineSectionSetCS") {
|
||||||
for (let i = 1; i <= 5; i++) {
|
for (let i = 1; i <= 5; i++) {
|
||||||
const sectionNode = self._findLinkedOriginNode(sectionSetNode, `section_${i}`);
|
const sectionNode = self._findLinkedOriginNode(sectionSetNode, `section_${i}`);
|
||||||
@@ -11610,6 +11606,7 @@ app.registerExtension({
|
|||||||
self._resolveNodeLinkedValue(sectionNode, "duration", { decimals: 3 }) ??
|
self._resolveNodeLinkedValue(sectionNode, "duration", { decimals: 3 }) ??
|
||||||
parseFloat(self._readNodeWidgetValue(sectionNode, "duration") || 0);
|
parseFloat(self._readNodeWidgetValue(sectionNode, "duration") || 0);
|
||||||
const sectionDuration = Math.max(0.1, Number.isFinite(rawSectionDuration) ? rawSectionDuration : 1.0);
|
const sectionDuration = Math.max(0.1, Number.isFinite(rawSectionDuration) ? rawSectionDuration : 1.0);
|
||||||
|
duration += sectionDuration;
|
||||||
const imageSource = self._extractLinkedImageSource(sectionNode, "image");
|
const imageSource = self._extractLinkedImageSource(sectionNode, "image");
|
||||||
sections.push({
|
sections.push({
|
||||||
text,
|
text,
|
||||||
@@ -11620,7 +11617,7 @@ app.registerExtension({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { duration, sections };
|
return { duration: Math.max(0.1, duration), sections };
|
||||||
};
|
};
|
||||||
this._syncTimelineFromLink = function () {
|
this._syncTimelineFromLink = function () {
|
||||||
const payload = self._buildExternalTimelinePayload();
|
const payload = self._buildExternalTimelinePayload();
|
||||||
|
|||||||
@@ -177,11 +177,10 @@ def _build_runtime_timeline_payload(external_timeline, frame_rate: float) -> tup
|
|||||||
return tdata, "", "", 0.0, 0
|
return tdata, "", "", 0.0, 0
|
||||||
|
|
||||||
sections = external_timeline.get("sections") or []
|
sections = external_timeline.get("sections") or []
|
||||||
duration_seconds = max(0.1, float(external_timeline.get("duration") or 0.0))
|
|
||||||
duration_frames = max(1, int(round(duration_seconds * frame_rate)))
|
|
||||||
current_start = 0
|
current_start = 0
|
||||||
local_prompts = []
|
local_prompts = []
|
||||||
segment_lengths = []
|
segment_lengths = []
|
||||||
|
total_duration_seconds = 0.0
|
||||||
|
|
||||||
for index, section in enumerate(sections):
|
for index, section in enumerate(sections):
|
||||||
if not isinstance(section, dict):
|
if not isinstance(section, dict):
|
||||||
@@ -191,6 +190,7 @@ def _build_runtime_timeline_payload(external_timeline, frame_rate: float) -> tup
|
|||||||
continue
|
continue
|
||||||
section_seconds = max(0.1, float(section.get("duration") or 0.0))
|
section_seconds = max(0.1, float(section.get("duration") or 0.0))
|
||||||
section_frames = max(1, int(round(section_seconds * frame_rate)))
|
section_frames = max(1, int(round(section_seconds * frame_rate)))
|
||||||
|
total_duration_seconds += section_seconds
|
||||||
seg = {
|
seg = {
|
||||||
"id": f"external_{index}",
|
"id": f"external_{index}",
|
||||||
"start": current_start,
|
"start": current_start,
|
||||||
@@ -205,6 +205,8 @@ def _build_runtime_timeline_payload(external_timeline, frame_rate: float) -> tup
|
|||||||
segment_lengths.append(str(section_frames))
|
segment_lengths.append(str(section_frames))
|
||||||
current_start += section_frames
|
current_start += section_frames
|
||||||
|
|
||||||
|
duration_seconds = max(0.1, float(total_duration_seconds or external_timeline.get("duration") or 0.0))
|
||||||
|
duration_frames = max(1, int(round(duration_seconds * frame_rate)))
|
||||||
return tdata, " | ".join(local_prompts), ",".join(segment_lengths), duration_seconds, duration_frames
|
return tdata, " | ".join(local_prompts), ",".join(segment_lengths), duration_seconds, duration_frames
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -106,21 +106,13 @@ class Timeline(io.ComfyNode):
|
|||||||
node_id="TimelineCS",
|
node_id="TimelineCS",
|
||||||
display_name="Timeline DUMAS",
|
display_name="Timeline DUMAS",
|
||||||
category="WhatDreamsCost DUMAS",
|
category="WhatDreamsCost DUMAS",
|
||||||
description="Builds an external timeline payload for LTX Director from a section set and total duration.",
|
description="Builds an external timeline payload for LTX Director from a section set, deriving the total duration from the sections.",
|
||||||
inputs=[
|
inputs=[
|
||||||
TimelineSectionSetData.Input(
|
TimelineSectionSetData.Input(
|
||||||
"section_set",
|
"section_set",
|
||||||
optional=True,
|
optional=True,
|
||||||
tooltip="Optional section set. When omitted, the timeline payload contains no sections.",
|
tooltip="Optional section set. When omitted, the timeline payload contains no sections.",
|
||||||
),
|
),
|
||||||
io.Float.Input(
|
|
||||||
"duration",
|
|
||||||
default=5.0,
|
|
||||||
min=0.1,
|
|
||||||
max=1000.0,
|
|
||||||
step=0.01,
|
|
||||||
tooltip="Total timeline duration in seconds.",
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
outputs=[
|
outputs=[
|
||||||
TimelineData.Output(display_name="timeline"),
|
TimelineData.Output(display_name="timeline"),
|
||||||
@@ -128,9 +120,11 @@ class Timeline(io.ComfyNode):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute(cls, section_set=None, duration=5.0) -> io.NodeOutput:
|
def execute(cls, section_set=None, duration=None) -> io.NodeOutput:
|
||||||
|
sections = list((section_set or {}).get("sections") or [])
|
||||||
|
total_duration = sum(max(0.1, float(item.get("duration") or 0.0)) for item in sections)
|
||||||
payload = {
|
payload = {
|
||||||
"duration": max(0.1, float(duration or 0.0)),
|
"duration": max(0.1, float(total_duration or 0.0)),
|
||||||
"sections": list((section_set or {}).get("sections") or []),
|
"sections": sections,
|
||||||
}
|
}
|
||||||
return io.NodeOutput(payload)
|
return io.NodeOutput(payload)
|
||||||
|
|||||||
Reference in New Issue
Block a user