feat: add V3 (comfy_api) dual-API wrapper and input tooltips; bump 2.1.4

V3 io.ComfyNode schema delegates to the V1 class so logic is not forked.
comfy_entrypoint exported import-guarded; V1 NODE_CLASS_MAPPINGS remain
authoritative on the 0.25.0 loader (no double registration). Verified
ComfyUI 0.25.0.
This commit is contained in:
BRADSEC
2026-06-20 19:30:49 +10:00
parent 93f3f29f01
commit 23dd8cb1a2
4 changed files with 106 additions and 10 deletions
+4
View File
@@ -76,6 +76,10 @@ Resolution Selector Plus (model: All, resolution: "1920x1080 (16:9 Landscape)")
---
## Compatibility
Dual API: exports the legacy V1 `NODE_CLASS_MAPPINGS` and a V3 `comfy_entrypoint` (`comfy_api`). Verified on ComfyUI 0.25.0. On builds whose loader reads `NODE_CLASS_MAPPINGS` first, the V1 path is used and `comfy_entrypoint` is skipped, so nodes are not registered twice.
## Support
If you find this useful, please consider [starring the repo](https://github.com/bradsec/ComfyUI_ResolutionSelectorPlus). Stars help other people discover these nodes.
+7 -1
View File
@@ -2,4 +2,10 @@ from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
WEB_DIRECTORY = "./js"
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
try:
from .nodes import comfy_entrypoint # noqa: F401
__all__.append('comfy_entrypoint')
except ImportError:
pass
+94 -8
View File
@@ -247,6 +247,26 @@ def parse_resolution_string(resolution_str):
raise ValueError(f"Invalid resolution format: {resolution_str}")
# Tooltips (shared by both API wrappers).
TIP_MODEL = "Image model. Filters the resolution presets to that model's recommended sizes. 'All' shows every preset."
TIP_RESOLUTION = "Preset resolution. The list filters to the selected model."
TIP_MULT = "Multiplies the preset width and height (1x to 4x)."
TIP_BATCH = "Number of latent samples in the preset latent batch."
TIP_CW = "Custom width in pixels. 0 disables the custom outputs. Must satisfy the model's divisibility and bounds."
TIP_CH = "Custom height in pixels. 0 disables the custom outputs. Must satisfy the model's divisibility and bounds."
TIP_CMULT = "Multiplies the custom width and height (1x to 4x)."
TIP_CBATCH = "Number of latent samples in the custom latent batch."
OUTPUT_TIPS = {
"width": "Preset width in pixels after multiplier.",
"height": "Preset height in pixels after multiplier.",
"latent": "Empty latent for the preset resolution.",
"custom_width": "Custom width after multiplier, or 0 when custom is disabled.",
"custom_height": "Custom height after multiplier, or 0 when custom is disabled.",
"custom_latent": "Empty latent for the custom resolution.",
}
class ResolutionSelector:
"""
Enhanced resolution selector supporting multiple image generation models.
@@ -276,20 +296,24 @@ class ResolutionSelector:
return {
"required": {
"model": (model_list, {
"default": "SDXL"
"default": "SDXL",
"tooltip": TIP_MODEL,
}),
"resolution": (all_resolutions, {
"default": "1024x1024 (1:1 Square)"
"default": "1024x1024 (1:1 Square)",
"tooltip": TIP_RESOLUTION,
}),
"resolution_multiplier": (["1x", "2x", "3x", "4x"], {
"default": "1x"
"default": "1x",
"tooltip": TIP_MULT,
}),
"batch_size": ("INT", {
"default": 1,
"min": 1,
"max": 64,
"step": 1,
"display": "number"
"display": "number",
"tooltip": TIP_BATCH,
}),
},
"optional": {
@@ -298,24 +322,28 @@ class ResolutionSelector:
"min": 0,
"max": 4096,
"step": 8,
"display": "number"
"display": "number",
"tooltip": TIP_CW,
}),
"custom_height": ("INT", {
"default": 0,
"min": 0,
"max": 4096,
"step": 8,
"display": "number"
"display": "number",
"tooltip": TIP_CH,
}),
"custom_multiplier": (["1x", "2x", "3x", "4x"], {
"default": "1x"
"default": "1x",
"tooltip": TIP_CMULT,
}),
"custom_batch": ("INT", {
"default": 1,
"min": 1,
"max": 64,
"step": 1,
"display": "number"
"display": "number",
"tooltip": TIP_CBATCH,
}),
}
}
@@ -463,3 +491,61 @@ NODE_CLASS_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = {
"ResolutionSelectorPlus": "Resolution Selector Plus",
}
# -- V3 node (import-guarded comfy_api schema) ---------------------------------
# Thin adapter: execute delegates to the V1 class so the logic is never forked.
try:
from comfy_api.v0_0_2 import io, ComfyExtension
class ResolutionSelectorPlusV3(io.ComfyNode):
@classmethod
def define_schema(cls) -> io.Schema:
model_list = ["All"] + list(MODEL_RESOLUTIONS.keys())
all_resolutions = get_all_resolutions()
mult = ["1x", "2x", "3x", "4x"]
return io.Schema(
node_id="ResolutionSelectorPlus",
display_name="Resolution Selector Plus",
category="utils",
description="Model-aware resolution presets, custom dimensions, and empty latent output.",
inputs=[
io.Combo.Input("model", options=model_list, default="SDXL", tooltip=TIP_MODEL),
io.Combo.Input("resolution", options=all_resolutions,
default="1024x1024 (1:1 Square)", tooltip=TIP_RESOLUTION),
io.Combo.Input("resolution_multiplier", options=mult, default="1x", tooltip=TIP_MULT),
io.Int.Input("batch_size", default=1, min=1, max=64, step=1, tooltip=TIP_BATCH),
io.Int.Input("custom_width", default=0, min=0, max=4096, step=8, optional=True, tooltip=TIP_CW),
io.Int.Input("custom_height", default=0, min=0, max=4096, step=8, optional=True, tooltip=TIP_CH),
io.Combo.Input("custom_multiplier", options=mult, default="1x", optional=True, tooltip=TIP_CMULT),
io.Int.Input("custom_batch", default=1, min=1, max=64, step=1, optional=True, tooltip=TIP_CBATCH),
],
outputs=[
io.Int.Output(id="width", display_name="width", tooltip=OUTPUT_TIPS["width"]),
io.Int.Output(id="height", display_name="height", tooltip=OUTPUT_TIPS["height"]),
io.Latent.Output(id="latent", display_name="latent", tooltip=OUTPUT_TIPS["latent"]),
io.Int.Output(id="custom_width", display_name="custom_width", tooltip=OUTPUT_TIPS["custom_width"]),
io.Int.Output(id="custom_height", display_name="custom_height", tooltip=OUTPUT_TIPS["custom_height"]),
io.Latent.Output(id="custom_latent", display_name="custom_latent", tooltip=OUTPUT_TIPS["custom_latent"]),
],
)
@classmethod
def execute(cls, model, resolution, resolution_multiplier="1x", batch_size=1,
custom_width=0, custom_height=0, custom_multiplier="1x", custom_batch=1) -> io.NodeOutput:
result = ResolutionSelector().select_resolution(
model, resolution, resolution_multiplier, batch_size,
custom_width, custom_height, custom_multiplier, custom_batch)
return io.NodeOutput(*result)
class ResolutionSelectorPlusExtension(ComfyExtension):
async def get_node_list(self):
return [ResolutionSelectorPlusV3]
async def comfy_entrypoint() -> "ResolutionSelectorPlusExtension":
return ResolutionSelectorPlusExtension()
except ImportError:
# Older ComfyUI without comfy_api: V1 mappings above are the only path.
pass
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_resolutionselectorplus"
description = "Custom node for ComfyUI providing easy resolution and empty latent selection for image generation workflows."
version = "2.1.3"
version = "2.1.4"
license = {file = "LICENSE"}
[project.urls]