feat: add external timeline nodes
This commit is contained in:
136
timeline_nodes.py
Normal file
136
timeline_nodes.py
Normal file
@@ -0,0 +1,136 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from comfy_api.latest import io
|
||||
|
||||
|
||||
TimelineSectionData = io.Custom("TIMELINE_SECTION")
|
||||
TimelineSectionSetData = io.Custom("TIMELINE_SECTION_SET")
|
||||
TimelineData = io.Custom("TIMELINE")
|
||||
|
||||
|
||||
class TimelineSection(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="TimelineSectionCS",
|
||||
display_name="Timeline Section DUMAS",
|
||||
category="WhatDreamsCost DUMAS",
|
||||
description="Reusable timeline section with required text, optional image, and a duration in seconds.",
|
||||
inputs=[
|
||||
io.Image.Input(
|
||||
"image",
|
||||
optional=True,
|
||||
tooltip="Optional image for this timeline section. When omitted, the section becomes a text-only block.",
|
||||
),
|
||||
io.String.Input(
|
||||
"text",
|
||||
multiline=True,
|
||||
default="",
|
||||
tooltip="Required text/prompt for this timeline section.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"duration",
|
||||
default=1.0,
|
||||
min=0.1,
|
||||
max=1000.0,
|
||||
step=0.01,
|
||||
tooltip="Section duration in seconds.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
TimelineSectionData.Output(display_name="section"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, image=None, text="", duration=1.0) -> io.NodeOutput:
|
||||
payload = {
|
||||
"image": image,
|
||||
"text": (text or "").strip(),
|
||||
"duration": max(0.1, float(duration or 0.0)),
|
||||
}
|
||||
return io.NodeOutput(payload)
|
||||
|
||||
|
||||
class TimelineSectionSet(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="TimelineSectionSetCS",
|
||||
display_name="Timeline Section Set DUMAS",
|
||||
category="WhatDreamsCost DUMAS",
|
||||
description="Bundles up to five Timeline Section nodes into one reusable section set.",
|
||||
inputs=[
|
||||
TimelineSectionData.Input("section_1", optional=True),
|
||||
TimelineSectionData.Input("section_2", optional=True),
|
||||
TimelineSectionData.Input("section_3", optional=True),
|
||||
TimelineSectionData.Input("section_4", optional=True),
|
||||
TimelineSectionData.Input("section_5", optional=True),
|
||||
],
|
||||
outputs=[
|
||||
TimelineSectionSetData.Output(display_name="section_set"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(
|
||||
cls,
|
||||
section_1=None,
|
||||
section_2=None,
|
||||
section_3=None,
|
||||
section_4=None,
|
||||
section_5=None,
|
||||
) -> io.NodeOutput:
|
||||
sections = []
|
||||
for item in (section_1, section_2, section_3, section_4, section_5):
|
||||
if not item:
|
||||
continue
|
||||
text = (item.get("text") or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
sections.append(
|
||||
{
|
||||
"image": item.get("image"),
|
||||
"text": text,
|
||||
"duration": max(0.1, float(item.get("duration") or 0.0)),
|
||||
}
|
||||
)
|
||||
|
||||
return io.NodeOutput({"sections": sections})
|
||||
|
||||
|
||||
class Timeline(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="TimelineCS",
|
||||
display_name="Timeline DUMAS",
|
||||
category="WhatDreamsCost DUMAS",
|
||||
description="Builds an external timeline payload for LTX Director from a section set and total duration.",
|
||||
inputs=[
|
||||
TimelineSectionSetData.Input(
|
||||
"section_set",
|
||||
optional=True,
|
||||
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=[
|
||||
TimelineData.Output(display_name="timeline"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, section_set=None, duration=5.0) -> io.NodeOutput:
|
||||
payload = {
|
||||
"duration": max(0.1, float(duration or 0.0)),
|
||||
"sections": list((section_set or {}).get("sections") or []),
|
||||
}
|
||||
return io.NodeOutput(payload)
|
||||
Reference in New Issue
Block a user