* feat(nodes): add Easy_Utility — INT → padded STRING dispatcher First mode `int_to_padded_string`: takes an INT widget (with up/down arrows) and emits a zero-padded STRING (default `001`, no `v` prefix). The downstream `koolook_versioning.resolve_version_token` prepends `v` and re-pads, so wiring this into `EasyAIPipeline.version` / `Easy_VideoCombine.version` yields the standard `vNNN` token at execution. Designed for extension: the `mode` widget shipped from day one so adding further conversions (string→int, formatting variants, etc.) doesn't rewire saved workflows. Note: the previously-attempted JS preview-resolver refactor that aimed to fix the "preview shows stale version" bug was reverted in this worktree before commit — it didn't actually fix the bug (the real cause is the JS resolver not descending into ComfyUI subgraphs) and it broke shot_name resolution in the process. The preview-resolver work is NOT in this commit; only the Python node + tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(nodes): guard version widget against pysssss .replace crash PR #180 added a STRING `version` widget to EasyAIPipeline and Easy_VideoCombine. Three workflow states leave widget.value undefined or non-string when graphToPrompt iterates widgets: - Pre-#180 workflows replay an INT (e.g. `1`) into the new STRING slot. - Widget-to-input conversion voids the value in newer LiteGraph. - Easy_VideoCombine's dict-based widgets_values omits the new key entirely on workflows saved before #180. With pysssss/ComfyUI-Custom-Scripts installed, presetText.js patches every STRING TextWidget.serializeValue to run callbacks that do `value.replace(...)` for `{variable}` substitution. Any of the states above crashes graphToPrompt and turns Run into a no-op for the whole workflow ("Cannot read properties of undefined (reading 'replace')"). Fix: trap `widget.value` reads/writes on the version widget via `Object.defineProperty` so the property is always coerced to a string regardless of caller. `configurable: true` so downstream code can still override the descriptor if it needs to. Tests: 231 passing; both JS files parse OK. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ai-pipeline): resolve subgraph version preview * feat(video): add path-aware load video node * fix(ai-pipeline): preview connected text names * fix(pr184): address review cleanup --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
110 lines
4.8 KiB
Python
110 lines
4.8 KiB
Python
try:
|
|
from .k_easy_wan22_prompt import NODE_CLASS_MAPPINGS as wan_mappings
|
|
from .k_easy_wan22_prompt import NODE_DISPLAY_NAME_MAPPINGS as wan_display
|
|
|
|
from .k_easy_resize import NODE_CLASS_MAPPINGS as resize_mappings
|
|
from .k_easy_resize import NODE_DISPLAY_NAME_MAPPINGS as resize_display
|
|
|
|
from .k_ai_pipeline import NODE_CLASS_MAPPINGS as pipeline_mappings
|
|
from .k_ai_pipeline import NODE_DISPLAY_NAME_MAPPINGS as pipeline_display
|
|
|
|
from .k_easy_image_batch import NODE_CLASS_MAPPINGS as batch_mappings # Added for new VFX batch node
|
|
from .k_easy_image_batch import NODE_DISPLAY_NAME_MAPPINGS as batch_display # Added for new VFX batch node
|
|
|
|
from .k_easy_track import NODE_CLASS_MAPPINGS as cam_loader_mappings
|
|
from .k_easy_track import NODE_DISPLAY_NAME_MAPPINGS as cam_loader_display
|
|
|
|
from .k_easy_pattern import NODE_CLASS_MAPPINGS as pattern_mappings
|
|
from .k_easy_pattern import NODE_DISPLAY_NAME_MAPPINGS as pattern_display
|
|
|
|
from .k_easy_utility import NODE_CLASS_MAPPINGS as utility_mappings
|
|
from .k_easy_utility import NODE_DISPLAY_NAME_MAPPINGS as utility_display
|
|
|
|
from .forks.radiance_koolook import NODE_CLASS_MAPPINGS as radiance_koolook_mappings
|
|
from .forks.radiance_koolook import NODE_DISPLAY_NAME_MAPPINGS as radiance_koolook_display
|
|
|
|
from .forks.whatdreamscost_koolook import NODE_CLASS_MAPPINGS as whatdreamscost_koolook_mappings
|
|
from .forks.whatdreamscost_koolook import NODE_DISPLAY_NAME_MAPPINGS as whatdreamscost_koolook_display
|
|
except ImportError as _node_import_exc:
|
|
# The relative imports above require a parent-package context that
|
|
# only ComfyUI's custom-node loader provides. Pytest's package
|
|
# collector (which walks up from test files looking for ``__init__.py``)
|
|
# and static-analysis tools load this file as a standalone module,
|
|
# where the imports raise. Falling back to empty registries lets
|
|
# tooling import the package directory without crashing — tests
|
|
# access sibling modules (e.g. ``koolook_routes``) via absolute
|
|
# imports that don't need the package context.
|
|
print(
|
|
f"[Koolook] node registry skipped (non-Comfy import context): "
|
|
f"{_node_import_exc}"
|
|
)
|
|
NODE_CLASS_MAPPINGS = {}
|
|
NODE_DISPLAY_NAME_MAPPINGS = {}
|
|
else:
|
|
# VHS-dependent wrappers self-skip when VideoHelperSuite is absent, and
|
|
# these guards keep a local import surprise from hiding the core nodes.
|
|
video_load_mappings = {}
|
|
video_load_display = {}
|
|
try:
|
|
from .k_video_load import NODE_CLASS_MAPPINGS as video_load_mappings
|
|
from .k_video_load import NODE_DISPLAY_NAME_MAPPINGS as video_load_display
|
|
except ImportError as _exc:
|
|
print(f"[Koolook] Easy_LoadVideo registry skipped: {_exc}")
|
|
|
|
video_combine_mappings = {}
|
|
video_combine_display = {}
|
|
try:
|
|
from .k_video_combine import NODE_CLASS_MAPPINGS as video_combine_mappings
|
|
from .k_video_combine import NODE_DISPLAY_NAME_MAPPINGS as video_combine_display
|
|
except ImportError as _exc:
|
|
print(f"[Koolook] Easy_VideoCombine registry skipped: {_exc}")
|
|
|
|
# Register the Kforge Labs snapshot/preset endpoints. Failure here is
|
|
# non-fatal — the node mappings still load and the rest of the plugin
|
|
# works; only the snapshot feature in the sidebar is unavailable. Both
|
|
# the import itself AND the `install()` call are guarded: a missing
|
|
# `aiohttp` (extremely unusual since it's a ComfyUI hard-dep) or any
|
|
# other module-load exception falls through to the print without
|
|
# crashing the node registry.
|
|
try:
|
|
from . import koolook_routes # noqa: E402
|
|
|
|
if not koolook_routes.install():
|
|
print(
|
|
"[Koolook] PromptServer unavailable at import time; preset routes "
|
|
"(/koolook/presets/*) not registered for this session."
|
|
)
|
|
except Exception as _exc: # pragma: no cover
|
|
print(f"[Koolook] preset routes import failed; node mappings unaffected: {_exc}")
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
**wan_mappings,
|
|
**resize_mappings,
|
|
**pipeline_mappings,
|
|
**batch_mappings,
|
|
**cam_loader_mappings,
|
|
**pattern_mappings,
|
|
**utility_mappings,
|
|
**video_load_mappings,
|
|
**video_combine_mappings,
|
|
**radiance_koolook_mappings,
|
|
**whatdreamscost_koolook_mappings,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
**wan_display,
|
|
**resize_display,
|
|
**pipeline_display,
|
|
**batch_display,
|
|
**cam_loader_display,
|
|
**pattern_display,
|
|
**utility_display,
|
|
**video_load_display,
|
|
**video_combine_display,
|
|
**radiance_koolook_display,
|
|
**whatdreamscost_koolook_display,
|
|
}
|
|
|
|
WEB_DIRECTORY = "./web"
|
|
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|