Compare commits

...

9 Commits

Author SHA1 Message Date
jfcantu
dcdc166427
Merge 1bdcd1bdbf into e8e0e884f2 2026-01-15 08:13:49 -06:00
Dr.Lt.Data
e8e0e884f2 update DB
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
2026-01-15 22:01:15 +09:00
loz2754
379fad3809
Add AUN ComfyUI Nodes to custom node list (#2494) 2026-01-15 21:33:48 +09:00
Dr.Lt.Data
bb0ef5bdc3 update DB
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2026-01-15 12:54:22 +09:00
Dr.Lt.Data
9617b0e56e update DB 2026-01-14 01:38:25 +09:00
John Cantu
1bdcd1bdbf Merge branch 'main' of https://github.com/jfcantu/ComfyUI-Manager 2025-12-14 18:11:34 -08:00
John Cantu
e04ed0eda7 update README.md for node usage analyzeer 2025-09-14 23:10:10 -07:00
John Cantu
02aa67b541 Merge branch 'main' of https://github.com/jfcantu/ComfyUI-Manager 2025-09-14 22:52:41 -07:00
John Cantu
67d03530a3 Changes and new code for Node Usage Analyzer 2025-09-14 22:49:54 -07:00
18 changed files with 9392 additions and 6104 deletions

View File

@ -9596,6 +9596,16 @@
"install_type": "git-clone",
"description": "Automatically archives generated files to Amazon S3 or S3-compatible storage services"
},
{
"author": "olduvai-jp",
"title": "ComfyUI-S3-IO",
"reference": "https://github.com/olduvai-jp/ComfyUI-S3-IO",
"files": [
"https://github.com/olduvai-jp/ComfyUI-S3-IO"
],
"install_type": "git-clone",
"description": "S3-backed input/output nodes for ComfyUI to browse, load images/videos from S3 buckets and push outputs back to S3 automatically."
},
{
"author": "AiMiDi",
"title": "ComfyUI-Aimidi-nodes",
@ -12905,6 +12915,16 @@
"install_type": "git-clone",
"description": "A visual ComfyUI latent canvas dimensions selector"
},
{
"author": "GraftingRayman",
"title": "ComfyUI-Games",
"reference": "https://github.com/GraftingRayman/ComfyUI-Games",
"files": [
"https://github.com/GraftingRayman/ComfyUI-Games"
],
"install_type": "git-clone",
"description": "ComfyUI node providing Tetris game functionality. (Description by CC)"
},
{
"author": "royceschultz",
"title": "ComfyUI-Notifications",
@ -16841,6 +16861,16 @@
"install_type": "git-clone",
"description": "This repository provides a custom ComfyUI node for running object detection with the [a/Qwen 2.5 VL](https://github.com/QwenLM/Qwen2.5-VL) model. The node downloads the selected model on demand, runs a detection prompt and outputs bounding boxes that can be used with segmentation nodes such as [a/SAM2](https://github.com/kijai/ComfyUI-segment-anything-2)."
},
{
"author": "TTPlanetPig",
"title": "Comfyui_DreamID-V_wrapper",
"reference": "https://github.com/TTPlanetPig/Comfyui_DreamID-V_wrapper",
"files": [
"https://github.com/TTPlanetPig/Comfyui_DreamID-V_wrapper"
],
"install_type": "git-clone",
"description": "A simple and efficient ComfyUI integration for DreamID-V, a model for identity-preserving video generation that animates reference images using motion from pose videos."
},
{
"author": "camenduru",
"title": "ComfyUI-TostAI",
@ -21248,6 +21278,16 @@
"install_type": "git-clone",
"description": "Node for Cartesia Sonic-3 that calls the `/tts/bytes` endpoint and returns: file_path, bytes, url"
},
{
"author": "PauldeLavallaz",
"title": "[WIP] comfyui_morpheus_model_management",
"reference": "https://github.com/PauldeLavallaz/comfyui_morpheus_model_management",
"files": [
"https://github.com/PauldeLavallaz/comfyui_morpheus_model_management"
],
"install_type": "git-clone",
"description": "Nodo personalizzato per ComfyUI che consente di sfogliare una libreria locale di immagini di talent con interfaccia gallery, filtri avanzati e output multipli. (Description by CC)\nNOTE: The files in the repo are not organized."
},
{
"author": "huanngzh",
"title": "ComfyUI-MVAdapter",
@ -24748,6 +24788,16 @@
"install_type": "git-clone",
"description": "This repository contains custom nodes for Stability AI API which supports SD3.0 and 3.5."
},
{
"author": "aicuai",
"title": "comfyui-save-image-watermark",
"reference": "https://github.com/aicuai/comfyui-save-image-watermark",
"files": [
"https://github.com/aicuai/comfyui-save-image-watermark"
],
"install_type": "git-clone",
"description": "Save images with visible watermarks (logo/text), invisible watermarks (LSB steganography), and metadata embedding. Supports PNG/JPEG/WebP with browser download."
},
{
"author": "benda1989",
"title": "GKK·CosyVoice",
@ -37592,16 +37642,6 @@
"install_type": "git-clone",
"description": "Color match nodes for ComfyUI that color-match target images against reference images with manual or auto-ramped blending, ideal for smooth color transitions between video clips."
},
{
"author": "Wladimir Palant",
"title": "image-resize-comfyui",
"reference": "https://github.com/ussoewwin/image_resize_comfyui",
"files": [
"https://github.com/ussoewwin/image_resize_comfyui"
],
"install_type": "git-clone",
"description": "Advanced image resizing node for ComfyUI with aspect ratio preservation and mask support"
},
{
"author": "jianghong-zhu",
"title": "ComfyUI-AdvancedCameraPrompts",
@ -40275,6 +40315,16 @@
"install_type": "git-clone",
"description": "ComfyUI custom node: load an MP4 and output first/last frame as IMAGE."
},
{
"author": "esp-dev",
"title": "comfyui-loadheicimage",
"reference": "https://github.com/esp-dev/comfyui-loadheicimage",
"files": [
"https://github.com/esp-dev/comfyui-loadheicimage"
],
"install_type": "git-clone",
"description": "ComfyUI custom node that loads images (including HEIC/HEIF) and provides browser-friendly previews."
},
{
"author": "mudknight",
"title": "comfyui-mudknight-utils",
@ -40316,16 +40366,6 @@
"install_type": "git-clone",
"description": "A ComfyUI node that generates a VACE control video and mask for a smooth transition between two videos"
},
{
"author": "WASasquatch",
"title": "ComfyUI_Viewer",
"reference": "https://github.com/WASasquatch/ComfyUI_Viewer",
"files": [
"https://github.com/WASasquatch/ComfyUI_Viewer"
],
"install_type": "git-clone",
"description": "Extensible content viewer for ComfyUI: HTML, Markdown (LaTeX, Mermaid, etc), Code, Images, and more"
},
{
"author": "Xyc2016",
"title": "Comfyui_Fd_Nodes",
@ -40446,16 +40486,6 @@
"install_type": "git-clone",
"description": "A minimal, opinionated ComfyUI custom node that emits portrait (0°) and/or landscape (90°) latent variants in a single run."
},
{
"author": "alexcong",
"title": "ComfyUI-SwinIR",
"reference": "https://github.com/alexcong/ComfyUI-SwinIR",
"files": [
"https://github.com/alexcong/ComfyUI-SwinIR"
],
"install_type": "git-clone",
"description": "A ComfyUI custom node for SwinIR (Swin Transformer for Image Restoration) supporting image super-resolution and denoising."
},
{
"author": "zisb",
"title": "comfyui-texture-packer",
@ -41097,6 +41127,16 @@
"install_type": "git-clone",
"description": "Lightweight post-processing node for Qwen3-4B conditioning in Z-Image Turbo workflows that refines conditioning with per-token normalization, optional self-attention, and MLP refinement. (Description by CC)"
},
{
"author": "capitan01R",
"title": "ComfyUI-CapitanZiT-Scheduler",
"reference": "https://github.com/capitan01R/ComfyUI-CapitanZiT-Scheduler",
"files": [
"https://github.com/capitan01R/ComfyUI-CapitanZiT-Scheduler"
],
"install_type": "git-clone",
"description": "A lightweight ComfyUI custom scheduler & sigma generator for Z-Image-Turbo. Delivers a stable linear sigma schedule (1.0 → 0.0) for rectified-flow/flow-matching, boosting few-step generation (8-9 steps) with superior consistency, reduced noise, and full compatibility with the model's distilled pipeline."
},
{
"author": "advancedtech-sk",
"title": "ComfyUI-GROUT",
@ -41127,16 +41167,6 @@
"install_type": "git-clone",
"description": "Automatically disables Load Image nodes without images, useful for workflows with optional reference images. (Description by CC)"
},
{
"author": "Enferlain",
"title": "ComfyUI-A1111-cond",
"reference": "https://github.com/Enferlain/ComfyUI-A1111-cond",
"files": [
"https://github.com/Enferlain/ComfyUI-A1111-cond"
],
"install_type": "git-clone",
"description": "A custom ComfyUI node that implements A1111-style prompt handling with proper isolation and emphasis math."
},
{
"author": "NickPittas",
"title": "ComfyUI_CameraAngleSelector",
@ -41167,6 +41197,16 @@
"install_type": "git-clone",
"description": "A dedicated ComfyUI custom node designed to streamline the process of converting transparent images (RGBA) into masks and high-quality mask previews."
},
{
"author": "tackcrypto1031",
"title": "tk_comfyui_view_and_light",
"reference": "https://github.com/tackcrypto1031/tk_comfyui_view_and_light",
"files": [
"https://github.com/tackcrypto1031/tk_comfyui_view_and_light"
],
"install_type": "git-clone",
"description": "TK View and Light: A ComfyUI node for 3D camera and lighting control"
},
{
"author": "patientx",
"title": "CFZ-SwitchMenu",
@ -41238,8 +41278,208 @@
"install_type": "git-clone",
"description": "Provide a simple interface to simplify prompt writing."
},
{
"author": "Suzu008",
"title": "ComfyUI-CryptIO",
"reference": "https://github.com/Suzu008/ComfyUI-CryptIO",
"files": [
"https://github.com/Suzu008/ComfyUI-CryptIO"
],
"install_type": "git-clone",
"description": "A collection of custom nodes for ComfyUI"
},
{
"author": "IRCSS",
"title": "comfyUI-blender-wrapper",
"reference": "https://github.com/IRCSS/comfyUI-blender-wrapper",
"files": [
"https://github.com/IRCSS/comfyUI-blender-wrapper"
],
"install_type": "git-clone",
"description": "ComfyUI Blender Wrapper lets you call Blender in headless mode from ComfyUI (or any Python environment), run reusable pipeline stages stored inside files, and pass configs in/out via JSON. It's meant for tech-art / asset-pipeline tasks like cleanup, decimation, unwrap, baking, rigging, etc."
},
{
"author": "calibancode",
"title": "ComfyUI-bevvy",
"reference": "https://github.com/calibancode/ComfyUI-bevvy",
"files": [
"https://github.com/calibancode/ComfyUI-bevvy"
],
"install_type": "git-clone",
"description": "ComfyUI custom node that saves images as WebP."
},
{
"author": "joe002",
"title": "comfyui-deterministic-nodes",
"reference": "https://github.com/joe002/comfyui-deterministic-nodes",
"files": [
"https://github.com/joe002/comfyui-deterministic-nodes"
],
"install_type": "git-clone",
"description": "Batch-invariant inference nodes for guaranteed reproducibility in ComfyUI"
},
{
"author": "joe002",
"title": "comfyui-conduit-optimizer",
"reference": "https://github.com/joe002/comfyui-conduit-optimizer",
"files": [
"https://github.com/joe002/comfyui-conduit-optimizer"
],
"install_type": "git-clone",
"description": "Non-linear inference optimization for ComfyUI: 4-tier VRAM, speculative generation, precision routing"
},
{
"author": "joe002",
"title": "comfyui-rtx4090-nodes",
"reference": "https://github.com/joe002/comfyui-rtx4090-nodes",
"files": [
"https://github.com/joe002/comfyui-rtx4090-nodes"
],
"install_type": "git-clone",
"description": "High-performance ComfyUI nodes optimized for RTX 4090: batch processing, memory management, GPU monitoring"
},
{
"author": "aadityamundhalia",
"title": "ComfyUI-ollama-aditya",
"reference": "https://github.com/aadityamundhalia/ComfyUI-ollama-aditya",
"files": [
"https://github.com/aadityamundhalia/ComfyUI-ollama-aditya"
],
"install_type": "git-clone",
"description": "Custom ComfyUI node for integrating Ollama LLMs into your image generation workflows."
},
{
"author": "maximilianwicen",
"title": "ComfyUI-MaxTools",
"reference": "https://github.com/maximilianwicen/ComfyUI-MaxTools",
"files": [
"https://github.com/maximilianwicen/ComfyUI-MaxTools"
],
"install_type": "git-clone",
"description": "A small collection of custom nodes for ComfyUI, featuring Max Quick Image Size node for image-to-image or image-to-video workflows. (Description by CC)"
},
{
"author": "bhhtr12",
"title": "ComfyUI-ollama-stop",
"reference": "https://github.com/bhhtr12/ComfyUI-ollama-stop",
"files": [
"https://github.com/bhhtr12/ComfyUI-ollama-stop"
],
"install_type": "git-clone",
"description": "Passthrough node that instantly unloads any running ollama model mid workflow. No API calls, just accepts plain string as a model name and executes 'ollama stop <model>' command in your system."
},
{
"author": "DemonAlone",
"title": "SimpeStringGenerator_ComfyUI",
"reference": "https://github.com/DemonAlone/SimpeStringGenerator_ComfyUI",
"files": [
"https://github.com/DemonAlone/SimpeStringGenerator_ComfyUI"
],
"install_type": "git-clone",
"description": "A collection of nodes that provide dynamic dropdown selectors for Samplers, Schedulers, Checkpoints, and Diffusion Models, outputting a comma-separated string for use in XY plots."
},
{
"author": "tabisheva",
"title": "comfyui-segs-profile",
"reference": "https://github.com/tabisheva/comfyui-segs-profile",
"files": [
"https://github.com/tabisheva/comfyui-segs-profile"
],
"install_type": "git-clone",
"description": "A tiny ComfyUI custom node that detects whether a face is in profile using SEGS eye detections."
},
{
"author": "QuackPhuc",
"title": "ComfyUI-FisheyeTransform",
"reference": "https://github.com/QuackPhuc/ComfyUI-FisheyeTransform",
"files": [
"https://github.com/QuackPhuc/ComfyUI-FisheyeTransform"
],
"install_type": "git-clone",
"description": "Custom nodes for handling fisheye camera distortion in ComfyUI inpainting workflows."
},
{
"author": "1x1r",
"title": "comfyui-upscale-by-model",
"reference": "https://github.com/1x1r/comfyui-upscale-by-model",
"files": [
"https://github.com/1x1r/comfyui-upscale-by-model"
],
"install_type": "git-clone",
"description": "This custom node allow upscaling an image by a factor using a model."
},
{
"author": "XelaNull",
"title": "ComfyUI-MobileFriendly",
"reference": "https://github.com/XelaNull/ComfyUI-MobileFriendly",
"files": [
"https://github.com/XelaNull/ComfyUI-MobileFriendly"
],
"install_type": "git-clone",
"description": "Comprehensive mobile UI enhancement for ComfyUI that transforms the desktop-focused interface into a touch-friendly experience optimized for iPhone, iPad, and Android devices."
},
{
"author": "danieljanata",
"title": "ComfyUI-Prompting-System",
"reference": "https://github.com/danieljanata/ComfyUI-Prompting-System",
"files": [
"https://github.com/danieljanata/ComfyUI-Prompting-System"
],
"install_type": "git-clone",
"description": "Comprehensive prompt management system for ComfyUI with database storage, thumbnail management, advanced search, and cross-platform support."
},
{
"author": "SorenWeile",
"title": "ComfyUI_MetaSaver",
"reference": "https://github.com/SorenWeile/ComfyUI_MetaSaver",
"files": [
"https://github.com/SorenWeile/ComfyUI_MetaSaver"
],
"install_type": "git-clone",
"description": "A powerful ComfyUI custom node for saving images with flexible custom metadata fields embedded in PNG files."
},
{
"author": "theluminhub",
"title": "ComfyUI-Lumin-Upload",
"reference": "https://github.com/theluminhub/ComfyUI-Lumin-Upload",
"files": [
"https://github.com/theluminhub/ComfyUI-Lumin-Upload"
],
"install_type": "git-clone",
"description": "Upload your ComfyUI generated images and workflow metadata to Lumin."
},
{
"author": "RCAKangle",
"title": "ComfyUI_LLM_Embeder",
"reference": "https://github.com/RCAKangle/ComfyUI_LLM_Embeder",
"files": [
"https://github.com/RCAKangle/ComfyUI_LLM_Embeder"
],
"install_type": "git-clone",
"description": "Local LLM chat nodes for ComfyUI, with a clean handoff path to downstream prompt optimization."
},
{
"author": "loz2754",
"title": "AUN ComfyUI Nodes",
"id": "aun-comfyui-nodes",
"reference": "https://github.com/loz2754/AUN-ComfyUI-Nodes",
"files": [
"https://github.com/loz2754/AUN-ComfyUI-Nodes"
],
"install_type": "git-clone",
"description": "A collection of workflow helper nodes focused on organization + control (bypass/mute/collapse/group control), prompt/text utilities, file/path helpers, and image/video save helpers (optional VHS integration)."
},
{
"author": "SergPoletaev",
"title": "ComfyUI-SPoletNodes",
"id": "ComfyUI-SPoletNodes",
"reference": "https://github.com/SergPoletaev/ComfyUI-SPoletNodes",
"files": [
"https://github.com/SergPoletaev/ComfyUI-SPoletNodes"
],
"install_type": "git-clone",
"description": "Custom nodes for image preview and saving"
},

View File

@ -20,7 +20,7 @@
],
"https://github.com/0nikod/ComfyUI-Simple-Prompt": [
[
"vue-basic"
"SimplePrompt"
],
{
"title_aux": "ComfyUI-Simple-Prompt"
@ -507,6 +507,14 @@
"title_aux": "Comfyui-Gelbooru"
}
],
"https://github.com/1x1r/comfyui-upscale-by-model": [
[
"UpscaleImageByUsingModel"
],
{
"title_aux": "comfyui-upscale-by-model"
}
],
"https://github.com/1zhangyy1/comfyui-vidu-nodes": [
[
"Character2Video",
@ -587,8 +595,8 @@
],
"https://github.com/3R3BOS/ComfyUI-3R3BOS-Pack": [
[
"Image Comparer (3R3BOS)",
"Visual Gatekeeper (3R3BOS)"
"Batch Selector (3R3BOS)",
"Image Comparer (3R3BOS)"
],
{
"title_aux": "ComfyUI-3R3BOS-Pack"
@ -2730,7 +2738,8 @@
],
"https://github.com/Anzhc/SDXL-Flux2VAE-ComfyUI-Node": [
[
"EmptySDXLFlux2LatentImage"
"EmptySDXLFlux2LatentImage",
"TargetTimeConditioning"
],
{
"title_aux": "SDXL-Flux2VAE-ComfyUI-Node"
@ -5963,6 +5972,17 @@
"title_aux": "RangeToString"
}
],
"https://github.com/DemonAlone/SimpeStringGenerator_ComfyUI": [
[
"DiffusionModelGeneratorNode",
"ModelGeneratorNode",
"SamplerGeneratorNode",
"SchedulerGeneratorNode"
],
{
"title_aux": "SimpeStringGenerator_ComfyUI"
}
],
"https://github.com/DemonNCoding/PromptGenerator12Columns": [
[
"PromptGenerator12Columns_Empty",
@ -8718,6 +8738,14 @@
"title_aux": "ComfyUI Visual Dimension Selector"
}
],
"https://github.com/GraftingRayman/ComfyUI-Games": [
[
"TetrisNode"
],
{
"title_aux": "ComfyUI-Games"
}
],
"https://github.com/GraftingRayman/ComfyUI-PuLID-Flux-GR": [
[
"GRApplyPulidFlux",
@ -8774,7 +8802,7 @@
"GR Text Overlay",
"GR Tile and Border Image",
"GR Tile and Border Image Random Flip",
"GRBatchLoader",
"GRAudioSelector",
"GRImageSelector",
"GRLoraLoader",
"GRMenuHook",
@ -10021,6 +10049,49 @@
"title_aux": "Notification Bridge"
}
],
"https://github.com/IRCSS/comfyUI-blender-wrapper": [
[
"BlenderGenericNode",
"CV2InpaintTexture",
"DownloadAndLoadHy3DDelightModel",
"DownloadAndLoadHy3DPaintModel",
"Hy3DApplyTexture",
"Hy3DBPT",
"Hy3DBakeFromMultiview",
"Hy3DCameraConfig",
"Hy3DDelightImage",
"Hy3DDiffusersSchedulerConfig",
"Hy3DExportMesh",
"Hy3DFastSimplifyMesh",
"Hy3DGenerateMesh",
"Hy3DGenerateMeshMultiView",
"Hy3DGetMeshPBRTextures",
"Hy3DIMRemesh",
"Hy3DLoadMesh",
"Hy3DMeshInfo",
"Hy3DMeshUVWrap",
"Hy3DMeshVerticeInpaintTexture",
"Hy3DModelLoader",
"Hy3DNvdiffrastRenderer",
"Hy3DPostprocessMesh",
"Hy3DRenderMultiView",
"Hy3DRenderMultiViewDepth",
"Hy3DRenderSingleView",
"Hy3DSampleMultiView",
"Hy3DSetMeshPBRAttributes",
"Hy3DSetMeshPBRTextures",
"Hy3DTorchCompileSettings",
"Hy3DUploadMesh",
"Hy3DVAEDecode",
"Hy3DVAELoader",
"Hy3D_2_1SimpleMeshGen",
"MESHToTrimesh",
"TrimeshToMESH"
],
{
"title_aux": "comfyUI-blender-wrapper"
}
],
"https://github.com/ITurchenko/ComfyUI-SizeFromArray": [
[
"SizeFromArray"
@ -13032,6 +13103,20 @@
"title_aux": "comfyui-vram-overlay"
}
],
"https://github.com/MajoorWaldi/ComfyUI-Majoor-ImageOps": [
[
"ImageOpsBlur",
"ImageOpsClamp",
"ImageOpsColorAjust",
"ImageOpsInvert",
"ImageOpsMerge",
"ImageOpsPreview",
"ImageOpsTransform"
],
{
"title_aux": "ComfyUI-Majoor-ImageOps"
}
],
"https://github.com/Makeezi/ComfyUI-promptLAB": [
[
"PromptLAB"
@ -13736,11 +13821,13 @@
"Remove Background",
"ReplaceAlpha",
"Resize Image and Mask by Side",
"SEGS Normalize for Video",
"Save Folder as ZIP",
"Save To Zip",
"SaveFolderAsZip",
"Spritesheet Builder",
"Spritesheet Preview",
"Stabilizer Trim",
"VideoMaskEditor",
"WAN Frame Calculator"
],
@ -15128,6 +15215,14 @@
"title_aux": "Claude Prompt Generator"
}
],
"https://github.com/PauldeLavallaz/comfyui_morpheus_model_management": [
[
"MorpheusModelManagement"
],
{
"title_aux": "[WIP] comfyui_morpheus_model_management"
}
],
"https://github.com/PenguinTeo/Comfyui-GeminiBanana": [
[
"Gemini3ImageNode"
@ -15863,6 +15958,16 @@
"title_aux": "ComfyUI-RED-UNO"
}
],
"https://github.com/QuackPhuc/ComfyUI-FisheyeTransform": [
[
"FisheyeRedistort",
"FisheyeStrengthEstimate",
"FisheyeUndistort"
],
{
"title_aux": "ComfyUI-FisheyeTransform"
}
],
"https://github.com/QuietNoise/comfyui_queue_manager": [
[
"Workflow Name"
@ -15879,6 +15984,16 @@
"title_aux": "Universal LLM Node for ComfyUI"
}
],
"https://github.com/RCAKangle/ComfyUI_LLM_Embeder": [
[
"ChatHistoryViewer",
"ChatNode",
"LLMConfigNode"
],
{
"title_aux": "ComfyUI_LLM_Embeder"
}
],
"https://github.com/RUiNtheExtinct/comfyui-save-file-extended": [
[
"LoadAudioExtended",
@ -17291,6 +17406,19 @@
"title_aux": "HF-Flux-ComfyUI"
}
],
"https://github.com/SergPoletaev/ComfyUI-SPoletNodes": [
[
"EnhancedVideoPreview",
"GetImageSizeWithPreview",
"Save Images & Preview",
"UltimateMemoryCleaner",
"Video Concat (FFmpeg)",
"VideoBatchCrossfade"
],
{
"title_aux": "ComfyUI-SPoletNodes"
}
],
"https://github.com/ServiceStack/comfy-asset-downloader": [
[
"AssetDownloader"
@ -18171,6 +18299,15 @@
"title_aux": "MBM's Music Visualizer"
}
],
"https://github.com/SorenWeile/ComfyUI_MetaSaver": [
[
"MetaSaver",
"MetaSaverDynamic"
],
{
"title_aux": "ComfyUI_MetaSaver"
}
],
"https://github.com/SozeInc/ComfyUI-Mobile": [
[
"Send Notification (Mobile)",
@ -18712,6 +18849,7 @@
"Basic data handling: TimeExtract",
"Basic data handling: TimeFormat",
"Basic data handling: TimeNow",
"Basic data handling: TimeNowUTC",
"Basic data handling: TimeParse",
"Basic data handling: TimeSubtractDelta",
"Basic data handling: TimeToUnix",
@ -19233,6 +19371,21 @@
"title_aux": "Comfyroll Studio"
}
],
"https://github.com/Suzu008/ComfyUI-CryptIO": [
[
"PreviewImageCryptIO",
"PreviewVideoCryptIO",
"SaveImageCryptIO",
"SaveVideoCryptIO",
"TextDecrypt",
"TextEncrypt",
"UploadImageCryptIO",
"UploadVideoCryptIO"
],
{
"title_aux": "ComfyUI-CryptIO"
}
],
"https://github.com/SuzumiyaAkizuki/ComfyUI-LLM_Prompt_XML_Formatter": [
[
"LLM_Prompt_Formatter",
@ -19521,6 +19674,17 @@
"title_aux": "tri3d-comfyui-nodes"
}
],
"https://github.com/TTPlanetPig/Comfyui_DreamID-V_wrapper": [
[
"DreamIDV_ConditioningPrep_TTP",
"DreamIDV_ModelLoader_Wrapper_TTP",
"DreamIDV_PoseExtractor_TTP",
"DreamIDV_Sampler_Wrapper_TTP"
],
{
"title_aux": "Comfyui_DreamID-V_wrapper"
}
],
"https://github.com/TTPlanetPig/Comfyui_Hunyuan3D": [
[
"GifImageViewerNode",
@ -20083,6 +20247,8 @@
[
"CharacterLoraSelect",
"ChromaActionSelect",
"EasyArrayFilter",
"EasyBasicJsonExtractor",
"EasyCLIPLoader",
"EasyCheckpointLoader",
"EasyFileName",
@ -20100,6 +20266,8 @@
"LoadImagesFromDirectoryPath",
"LoadRandomImageFromFolderPath",
"QwenActionSelect",
"TileAssembly",
"TileBreak",
"UserSelect",
"WanActionSelect"
],
@ -22485,6 +22653,14 @@
"title_aux": "ComfyUI_Detonate"
}
],
"https://github.com/aadityamundhalia/ComfyUI-ollama-aditya": [
[
"OllamaPromptGenerator"
],
{
"title_aux": "ComfyUI-ollama-aditya"
}
],
"https://github.com/abdozmantar/ComfyUI-DeepExtract": [
[
"VocalAndSoundRemoverNode"
@ -22948,6 +23124,16 @@
"title_aux": "aicu-comfyui-stability-ai-api"
}
],
"https://github.com/aicuai/comfyui-save-image-watermark": [
[
"ExtractInvisibleWatermark",
"Local Save",
"LocalSaveImageWithWatermark"
],
{
"title_aux": "comfyui-save-image-watermark"
}
],
"https://github.com/aidec/Comfyui_TextBatch_aidec": [
[
"DataTempManager",
@ -23232,7 +23418,6 @@
"GetImagesFromBatchIndexed",
"GetLatentRangeFromBatch",
"GetLatentSizeAndCount",
"Image Comparer (rgthree)",
"ImageAddMulti",
"ImageAndMaskPreview",
"ImageBatchExtendWithOverlap",
@ -23257,6 +23442,7 @@
"ImagePadKJ",
"ImagePass",
"ImagePrepForICLora",
"ImageResizeByMegapixels",
"ImageResizeKJ",
"ImageResizeKJv2",
"ImageTensorList",
@ -23275,6 +23461,7 @@
"LoadImagesFromFolderKJ",
"LoadVideosFromFolder",
"Mask_transform_sum",
"MathExpression_UTK",
"MergeBatch",
"MergeImageChannels",
"PadImageBatchInterleaved",
@ -23587,6 +23774,8 @@
"GeminiConvertRasterToVector",
"GeminiFLUXResolutions",
"GeminiImageGenerator",
"GeminiLoadImagePath",
"GeminiLoadImagesFromDir",
"GeminiSVGPreview",
"GeminiSaveSVG",
"GeminiSaveText",
@ -23894,10 +24083,15 @@
"XJSamplerAdapter",
"XJSaveImageWithMetadata",
"XJSchedulerAdapter",
"XJSegsAutoAdjustHookProvider",
"XJSegsColorCorrectHSVHookProvider",
"XJSegsColorCorrectRGBHookProvider",
"XJSegsColorMatchHookProvider",
"XJSegsCount",
"XJSegsExtractor",
"XJSegsFilter",
"XJSegsFilterByLabel",
"XJSegsMerge",
"XJSegsPick",
"XJSegsStitcher",
"XJSegsWildcardPrompt",
@ -25593,6 +25787,14 @@
"title_aux": "ComfyUI-Hunyuan-Image-3"
}
],
"https://github.com/bhhtr12/ComfyUI-ollama-stop": [
[
"OllamaStopNode"
],
{
"title_aux": "ComfyUI-ollama-stop"
}
],
"https://github.com/bhvbhushan/ComfyUI-LoRABlockWeight": [
[
"HierarchicalLoRAWeightEditor",
@ -26861,6 +27063,14 @@
"title_aux": "Arc2Face ComfyUI Node Library"
}
],
"https://github.com/calibancode/ComfyUI-bevvy": [
[
"SaveImageWebP"
],
{
"title_aux": "ComfyUI-bevvy"
}
],
"https://github.com/camenduru/ComfyUI-TostAI": [
[
"SendToTostAI"
@ -26878,6 +27088,14 @@
"title_aux": "Capitan-ConditioningEnhancer"
}
],
"https://github.com/capitan01R/ComfyUI-CapitanZiT-Scheduler": [
[
"CapitanZiTLinearSigma"
],
{
"title_aux": "ComfyUI-CapitanZiT-Scheduler"
}
],
"https://github.com/cardenluo/ComfyUI-Apt_Preset": [
[
"AD_DrawSchedule",
@ -26897,6 +27115,8 @@
"AD_sch_value",
"AD_slice_Condi",
"AI_GLM4",
"AI_GLM_image",
"AI_GLM_text",
"AI_Ollama_image",
"AI_Ollama_text",
"AI_PresetSave",
@ -27187,7 +27407,6 @@
"sum_lora",
"sum_stack_AD",
"sum_stack_Kontext",
"sum_stack_QwenEdit",
"sum_stack_QwenEditPlus",
"sum_stack_Wan",
"sum_stack_image",
@ -29566,6 +29785,13 @@
"MaskComposite",
"MaskPreview",
"MaskToImage",
"MeshyAnimateModelNode",
"MeshyImageToModelNode",
"MeshyMultiImageToModelNode",
"MeshyRefineNode",
"MeshyRigModelNode",
"MeshyTextToModelNode",
"MeshyTextureNode",
"MinimaxHailuoVideoNode",
"MinimaxImageToVideoNode",
"MinimaxSubjectToVideoNode",
@ -30753,6 +30979,17 @@
"title_aux": "ComfyUI-TTS"
}
],
"https://github.com/danieljanata/ComfyUI-Prompting-System": [
[
"PS_MetadataCleaner",
"PS_MetadataReader",
"PS_PromptSaver",
"PS_SmartText"
],
{
"title_aux": "ComfyUI-Prompting-System"
}
],
"https://github.com/danielvw/ComfyUI-WanMove-Adapter": [
[
"CoordsToWanTracks"
@ -30924,6 +31161,7 @@
"PromptCameraSelector",
"PromptConstructor",
"PromptLightingSelector",
"Test1",
"TiledKSampler",
"TiledKSamplerWithUpscaler",
"TrainingDatasetSaver"
@ -32348,6 +32586,14 @@
"title_aux": "ComfyUI-enricos-nodes"
}
],
"https://github.com/esp-dev/comfyui-loadheicimage": [
[
"LoadImagePlusHEIC"
],
{
"title_aux": "comfyui-loadheicimage"
}
],
"https://github.com/esp-dev/comfyui-videoframenode": [
[
"VideoFirstLastFrame"
@ -37581,6 +37827,51 @@
"title_aux": "HouseKeeper"
}
],
"https://github.com/joe002/comfyui-conduit-optimizer": [
[
"ConduitApply",
"ConduitBatchOptimizer",
"ConduitCacheClear",
"ConduitCore",
"ConduitEmbeddingCache",
"ConduitGate",
"ConduitLatentCache",
"ConduitPath",
"ConduitPool",
"ConduitPrecisionPatcher",
"ConduitSeal",
"ConduitSense",
"ConduitSpeculativeKSampler"
],
{
"title_aux": "comfyui-conduit-optimizer"
}
],
"https://github.com/joe002/comfyui-deterministic-nodes": [
[
"CascadeRefiner",
"ChecksumValidator",
"DeterministicSampler",
"ECHOContextNode",
"MoERouterNode"
],
{
"title_aux": "comfyui-deterministic-nodes"
}
],
"https://github.com/joe002/comfyui-rtx4090-nodes": [
[
"BatchImageProcessor",
"BatchLatentProcessor",
"GPUMonitor",
"MemoryManager",
"RTX4090Optimizer",
"TensorRTAutoConverter"
],
{
"title_aux": "comfyui-rtx4090-nodes"
}
],
"https://github.com/joeriben/ai4artsed_comfyui_nodes": [
[
"ai4artsed_conditioning_fusion",
@ -41670,6 +41961,81 @@
"title_aux": "ComfyUI-Replace-First-Frame-Last-Frame"
}
],
"https://github.com/loz2754/AUN-ComfyUI-Nodes": [
[
"AUNAddToPrompt",
"AUNAny",
"AUNBookmark",
"AUNBoolean",
"AUNCFG",
"AUNCheckpointLoaderWithClipSkip",
"AUNEmptyLatent",
"AUNExtractModelName",
"AUNExtractPowerLoras",
"AUNExtractWidgetValue",
"AUNGetActiveNodeTitle",
"AUNGetConnectedNodeTitles",
"AUNGraphScraper",
"AUNImageLoadResize",
"AUNImageResize",
"AUNImageSingleBatch3",
"AUNImg2Img",
"AUNImgLoader",
"AUNInputs",
"AUNInputsHybrid",
"AUNKSamplerPlusv3",
"AUNModelNamePass",
"AUNModelShorten",
"AUNMultiBypassIndex",
"AUNMultiGroupUniversal",
"AUNMultiMuteIndex",
"AUNMultiNegPrompt",
"AUNMultiUniversal",
"AUNNameCrop",
"AUNNodeStateController",
"AUNPathFilename",
"AUNPathFilenameVideo",
"AUNRandomAnySwitch",
"AUNRandomIndexSwitch",
"AUNRandomNumber",
"AUNRandomTextIndexSwitch",
"AUNSaveImage",
"AUNSaveVideo",
"AUNSetBypassByTitle",
"AUNSetBypassStateGroup",
"AUNSetCollapseAndBypassStateAdvanced",
"AUNSetMuteByTitle",
"AUNSetMuteStateGroup",
"AUNShowTextWithTitle",
"AUNSingleLabelSwitch",
"AUNStrip",
"AUNSwitchFloat",
"AUNTextIndexSwitch",
"AUNTextIndexSwitch3",
"AUNTitleImagePreview",
"AnyType(str)",
"AudioInputOptions",
"JNodes_AnyToString",
"JNodes_ConditioningInOut",
"JNodes_FloatLiteral",
"JNodes_GetCleanFilename",
"JNodes_GetComfyDirectory",
"JNodes_GetLeafDirectory",
"JNodes_GetOutputDirectory",
"JNodes_GetTempDirectory",
"JNodes_IntLiteral",
"JNodes_ModelInOut",
"JNodes_StringLiteral",
"JNodes_SubdirectorySelector",
"JoinVideosInDirectory",
"KSamplerInputs",
"MainFolderManualName",
"TextSwitch2InputWithTextOutput"
],
{
"title_aux": "AUN ComfyUI Nodes"
}
],
"https://github.com/lquesada/ComfyUI-Inpaint-CropAndStitch": [
[
"InpaintCropImproved",
@ -43107,6 +43473,14 @@
"title_aux": "comfyui-sora-node"
}
],
"https://github.com/maximilianwicen/ComfyUI-MaxTools": [
[
"MaxQuickImageSize"
],
{
"title_aux": "ComfyUI-MaxTools"
}
],
"https://github.com/maxious/comfyui-dap": [
[
"DAP_ERP_to_Cubemap",
@ -45418,6 +45792,57 @@
"title_aux": "ComfyUI-HfLoader"
}
],
"https://github.com/olduvai-jp/ComfyUI-S3-IO": [
[
"LoadImageS3",
"LoadVideoUploadS3",
"SaveImageS3",
"VHS_AudioToVHSAudio",
"VHS_BatchManager",
"VHS_DuplicateImages",
"VHS_DuplicateLatents",
"VHS_DuplicateMasks",
"VHS_GetImageCount",
"VHS_GetLatentCount",
"VHS_GetMaskCount",
"VHS_LoadAudio",
"VHS_LoadAudioUpload",
"VHS_LoadImagePath",
"VHS_LoadImages",
"VHS_LoadImagesPath",
"VHS_LoadVideo",
"VHS_LoadVideoFFmpeg",
"VHS_LoadVideoFFmpegPath",
"VHS_LoadVideoPath",
"VHS_MergeImages",
"VHS_MergeLatents",
"VHS_MergeMasks",
"VHS_PruneOutputs",
"VHS_SelectEveryNthImage",
"VHS_SelectEveryNthLatent",
"VHS_SelectEveryNthMask",
"VHS_SelectFilename",
"VHS_SelectImages",
"VHS_SelectLatents",
"VHS_SelectLatest",
"VHS_SelectMasks",
"VHS_SplitImages",
"VHS_SplitLatents",
"VHS_SplitMasks",
"VHS_Unbatch",
"VHS_VAEDecodeBatched",
"VHS_VAEEncodeBatched",
"VHS_VHSAudioToAudio",
"VHS_VideoCombine",
"VHS_VideoInfo",
"VHS_VideoInfoLoaded",
"VHS_VideoInfoSource",
"VideoCombineS3"
],
{
"title_aux": "ComfyUI-S3-IO"
}
],
"https://github.com/oleksandr612/ComfyUI-Counter": [
[
"Simple Counter"
@ -46611,6 +47036,7 @@
"Lora Loader Str",
"MaskEmptyFloatNode",
"MaskPassOrPlaceholder",
"MonoToStereoConverter",
"ParametricEQNode",
"PonyFaceEnhancementPipelineWithInjection",
"PonyUpscaleSamplerWithInjection",
@ -49833,6 +50259,7 @@
"LoRAExtractKnee",
"LoRAExtractQuantile",
"LoRAExtractRatio",
"LoRAMergeToModel",
"LoRAMetaKeys",
"LoRAMultiMerge",
"LoRAPruneKeys",
@ -51922,6 +52349,14 @@
"title_aux": "SANA_LOWVRAM"
}
],
"https://github.com/tabisheva/comfyui-segs-profile": [
[
"SEGSIsProfile"
],
{
"title_aux": "comfyui-segs-profile"
}
],
"https://github.com/tackcrypto1031/tk_comfyui_img2mask": [
[
"TK_Image2Mask"
@ -51930,6 +52365,14 @@
"title_aux": "tk_comfyui_img2mask"
}
],
"https://github.com/tackcrypto1031/tk_comfyui_view_and_light": [
[
"TK_View_And_Light"
],
{
"title_aux": "tk_comfyui_view_and_light"
}
],
"https://github.com/takemetosiberia/ComfyUI-SAMURAI--SAM2-": [
[
"SAMURAIBoxInputNode",
@ -52191,6 +52634,14 @@
"title_aux": "Divergent Nodes"
}
],
"https://github.com/theluminhub/ComfyUI-Lumin-Upload": [
[
"AssetManagerNode"
],
{
"title_aux": "ComfyUI-Lumin-Upload"
}
],
"https://github.com/theshubzworld/ComfyUI-FaceCalloutNode": [
[
"FaceCalloutEffect",
@ -53270,8 +53721,7 @@
"DisTorchPurgeVRAMV2",
"MemoryManager",
"ModelPatchMemoryCleaner",
"PatchSageAttentionDM",
"SafeMemoryManager"
"PatchSageAttentionDM"
],
{
"title_aux": "ComfyUI-DistorchMemoryManager"
@ -53296,14 +53746,6 @@
"title_aux": "ComfyUI-QwenImageLoraLoader"
}
],
"https://github.com/ussoewwin/image_resize_comfyui": [
[
"ImageResizeAdvanced"
],
{
"title_aux": "image-resize-comfyui"
}
],
"https://github.com/vadimcro/VKRiez-Edge": [
[
"VKriezEnhancedEdgePreprocessor",
@ -54378,23 +54820,15 @@
],
"https://github.com/willmiao/ComfyUI-Lora-Manager": [
[
"BasicScheduler",
"CFGGuider",
"CLIPTextEncode",
"DebugMetadata",
"KSamplerSelect",
"LoraDemoNode",
"LoraManagerLoader",
"LoraManagerTextLoader",
"LoraPoolNode",
"LoraRandomizerNode",
"LoraStacker",
"PromptLoraManager",
"SamplerCustomAdvanced",
"SaveImageLM",
"TSC_EfficientLoader",
"TriggerWordToggle",
"VAEDecode",
"WanVideoLoraSelectFromText",
"WanVideoLoraSelectLM"
],

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,10 @@ import threading
import re
import shutil
import git
import glob
import json
from datetime import datetime
from contextlib import contextmanager
from server import PromptServer
import manager_core as core
@ -762,6 +765,86 @@ async def fetch_updates(request):
except:
traceback.print_exc()
return web.Response(status=400)
@routes.get("/customnode/get_node_types_in_workflows")
async def get_node_types_in_workflows(request):
try:
# get our username from the request header
user_id = PromptServer.instance.user_manager.get_request_user_id(request)
# get the base workflow directory (TODO: figure out if non-standard directories are possible, and how to find them)
workflow_files_base_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), user_id, "workflows"))
logging.debug(f"workflows base path: {workflow_files_base_path}")
# workflow directory doesn't actually exist, return 204 (No Content)
if not os.path.isdir(workflow_files_base_path):
logging.debug("workflows base path doesn't exist - nothing to do...")
return web.Response(status=204)
# get all JSON files under the workflow directory
workflow_file_relative_paths: list[str] = glob.glob(pathname="**/*.json", root_dir=workflow_files_base_path, recursive=True)
logging.debug(f"found the following workflows: {workflow_file_relative_paths}")
# set up our list of workflow/node-lists
workflow_node_mappings: list[dict[str, str | list[str]]] = []
# iterate over each found JSON file
for workflow_file_path in workflow_file_relative_paths:
try:
workflow_file_absolute_path = os.path.abspath(os.path.join(workflow_files_base_path, workflow_file_path))
logging.debug(f"starting work on {workflow_file_absolute_path}")
# load the JSON file
workflow_file_data = json.load(open(workflow_file_absolute_path, "r"))
# make sure there's a nodes key (otherwise this might not actually be a workflow file)
if "nodes" not in workflow_file_data:
logging.warning(f"{workflow_file_path} has no 'nodes' key (possibly invalid?) - skipping...")
# skip to next file
continue
# now this looks like a valid file, so let's get to work
new_mapping = {"workflow_file_name": workflow_file_path}
# we can't use an actual set, because you can't use dicts as set members
node_set = []
# iterate over each node in the workflow
for node in workflow_file_data["nodes"]:
if "id" not in node:
logging.warning(f"Found a node with no ID - possibly corrupt/invalid workflow?")
continue
# if there's no type, throw a warning
if "type" not in node:
logging.warning(f"Node type not found in {workflow_file_path} for node ID {node['id']}")
# skip to next node
continue
node_data_to_return = {"type": node["type"]}
if "properties" not in node:
logging.warning(f"Node ${node['id']} has no properties field - can't determine cnr_id")
else:
for property_key in ["cnr_id", "ver"]:
if property_key in node["properties"]:
node_data_to_return[property_key] = node["properties"][property_key]
# add it to the list for this workflow
if not node_data_to_return in node_set:
node_set.append(node_data_to_return)
# annoyingly, Python can't serialize sets to JSON
new_mapping["node_types"] = list(node_set)
workflow_node_mappings.append(new_mapping)
except Exception as e:
logging.warning(f"Couldn't open {workflow_file_path}: {e}")
return web.json_response(workflow_node_mappings, content_type='application/json')
except:
traceback.print_exc()
return web.Response(status=500)
@routes.get("/manager/queue/update_all")

View File

@ -9,6 +9,7 @@ This directory contains the JavaScript frontend implementation for ComfyUI-Manag
- **model-manager.js**: Handles the model management interface for downloading and organizing AI models.
- **components-manager.js**: Manages reusable workflow components system.
- **snapshot.js**: Implements the snapshot system for backing up and restoring installations.
- **node-usage-analyzer.js**: Implements the UI for analyzing node usage in workflows.
## Sharing Components
@ -46,5 +47,6 @@ The frontend follows a modular component-based architecture:
CSS files are included for specific components:
- **custom-nodes-manager.css**: Styling for the node management UI
- **model-manager.css**: Styling for the model management UI
- **node-usage-analyzer.css**: Styling for the node usage analyzer UI
This frontend implementation provides a comprehensive yet user-friendly interface for managing the ComfyUI ecosystem.

View File

@ -18,6 +18,7 @@ import {
} from "./common.js";
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
import { CustomNodesManager } from "./custom-nodes-manager.js";
import { NodeUsageAnalyzer } from "./node-usage-analyzer.js";
import { ModelManager } from "./model-manager.js";
import { SnapshotManager } from "./snapshot.js";
import { buildGuiFrame, createSettingsCombo } from "./comfyui-gui-builder.js";
@ -909,6 +910,17 @@ class ManagerMenuDialog extends ComfyDialog {
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.IN_WORKFLOW);
}
}),
$el("button.cm-button", {
type: "button",
textContent: "Node Usage Analyzer",
onclick:
() => {
if(!NodeUsageAnalyzer.instance) {
NodeUsageAnalyzer.instance = new NodeUsageAnalyzer(app, self);
}
NodeUsageAnalyzer.instance.show(NodeUsageAnalyzer.SortMode.BY_PACKAGE);
}
}),
$el("div", {}, []),
$el("button.p-button.p-component.cm-button", {

View File

@ -122,9 +122,9 @@ export async function customConfirm(message) {
let res = await
window['app'].extensionManager.dialog
.confirm({
title: 'Confirm',
message: message
});
title: 'Confirm',
message: message
});
return res;
}
@ -164,9 +164,9 @@ export async function customPrompt(title, message) {
let res = await
window['app'].extensionManager.dialog
.prompt({
title: title,
message: message
});
title: title,
message: message
});
return res;
}
@ -667,4 +667,449 @@ function initTooltip () {
document.body.addEventListener('mouseleave', mouseleaveHandler, true);
}
export async function uninstallNodes(nodeList, options = {}) {
const {
title = `${nodeList.length} custom nodes`,
onProgress = () => {},
onError = () => {},
onSuccess = () => {},
channel = 'default',
mode = 'default'
} = options;
// Check if queue is busy
let stats = await api.fetchApi('/manager/queue/status');
stats = await stats.json();
if (stats.is_processing) {
customAlert(`[ComfyUI-Manager] There are already tasks in progress. Please try again after it is completed. (${stats.done_count}/${stats.total_count})`);
return { success: false, error: 'Queue is busy' };
}
// Confirmation dialog for uninstall
const confirmed = await customConfirm(`Are you sure uninstall ${title}?`);
if (!confirmed) {
return { success: false, error: 'User cancelled' };
}
let errorMsg = "";
let target_items = [];
await api.fetchApi('/manager/queue/reset');
for (const nodeItem of nodeList) {
target_items.push(nodeItem);
onProgress(`Uninstall ${nodeItem.title || nodeItem.name} ...`);
const data = nodeItem.originalData || nodeItem;
data.channel = channel;
data.mode = mode;
data.ui_id = nodeItem.hash || md5(nodeItem.name || nodeItem.title);
const res = await api.fetchApi(`/manager/queue/uninstall`, {
method: 'POST',
body: JSON.stringify(data)
});
if (res.status != 200) {
errorMsg = `'${nodeItem.title || nodeItem.name}': `;
if (res.status == 403) {
errorMsg += `This action is not allowed with this security level configuration.\n`;
} else if (res.status == 404) {
errorMsg += `With the current security level configuration, only custom nodes from the <B>"default channel"</B> can be uninstalled.\n`;
} else {
errorMsg += await res.text() + '\n';
}
break;
}
}
if (errorMsg) {
onError(errorMsg);
show_message("[Uninstall Errors]\n" + errorMsg);
return { success: false, error: errorMsg, targets: target_items };
} else {
await api.fetchApi('/manager/queue/start');
onSuccess(target_items);
showTerminal();
return { success: true, targets: target_items };
}
}
// ===========================================================================================
// Workflow Utilities Consolidation
export async function getWorkflowNodeTypes() {
try {
const res = await fetchData('/customnode/get_node_types_in_workflows');
if (res.status === 200) {
return { success: true, data: res.data };
} else if (res.status === 204) {
// No workflows found - return empty list
return { success: true, data: [] };
} else {
return { success: false, error: res.error };
}
} catch (error) {
return { success: false, error: error };
}
}
export function findPackageByCnrId(cnrId, nodePackages, installedOnly = true) {
if (!cnrId || !nodePackages) {
return null;
}
// Tier 1: Direct key match
if (nodePackages[cnrId]) {
const pack = nodePackages[cnrId];
if (!installedOnly || pack.state !== "not-installed") {
return { key: cnrId, pack: pack };
}
}
// Tier 2: Case-insensitive match
const cnrIdLower = cnrId.toLowerCase();
for (const packKey of Object.keys(nodePackages)) {
if (packKey.toLowerCase() === cnrIdLower) {
const pack = nodePackages[packKey];
if (!installedOnly || pack.state !== "not-installed") {
return { key: packKey, pack: pack };
}
}
}
// Tier 3: URL/reference contains match
for (const packKey of Object.keys(nodePackages)) {
const pack = nodePackages[packKey];
// Skip non-installed packages if installedOnly is true
if (installedOnly && pack.state === "not-installed") {
continue;
}
// Check if reference URL contains cnr_id
if (pack.reference && pack.reference.includes(cnrId)) {
return { key: packKey, pack: pack };
}
// Check if any file URL contains cnr_id
if (pack.files && Array.isArray(pack.files)) {
for (const fileUrl of pack.files) {
if (fileUrl.includes(cnrId)) {
return { key: packKey, pack: pack };
}
}
}
}
return null;
}
export async function analyzeWorkflowUsage(nodePackages) {
const result = await getWorkflowNodeTypes();
if (!result.success) {
return { success: false, error: result.error };
}
const workflowNodeList = result.data;
const usageMap = new Map();
const workflowDetailsMap = new Map();
if (workflowNodeList && Array.isArray(workflowNodeList)) {
const cnrIdCounts = new Map();
const cnrIdToWorkflows = new Map();
// Process each workflow
workflowNodeList.forEach((workflowObj, workflowIndex) => {
if (workflowObj.node_types && Array.isArray(workflowObj.node_types)) {
const workflowCnrIds = new Set();
// Get workflow filename
const workflowFilename = workflowObj.workflow_file_name ||
workflowObj.filename ||
workflowObj.file ||
workflowObj.name ||
workflowObj.path ||
`Workflow ${workflowIndex + 1}`;
// Count nodes per cnr_id in this workflow
const workflowCnrIdCounts = new Map();
workflowObj.node_types.forEach(nodeTypeObj => {
const cnrId = nodeTypeObj.cnr_id;
if (cnrId && cnrId !== "comfy-core") {
// Track unique cnr_ids per workflow
workflowCnrIds.add(cnrId);
// Count nodes per cnr_id in this specific workflow
const workflowNodeCount = workflowCnrIdCounts.get(cnrId) || 0;
workflowCnrIdCounts.set(cnrId, workflowNodeCount + 1);
}
});
// Record workflow details for each unique cnr_id found in this workflow
workflowCnrIds.forEach(cnrId => {
// Count occurrences of this cnr_id across all workflows
const currentCount = cnrIdCounts.get(cnrId) || 0;
cnrIdCounts.set(cnrId, currentCount + 1);
// Track workflow details
if (!cnrIdToWorkflows.has(cnrId)) {
cnrIdToWorkflows.set(cnrId, []);
}
cnrIdToWorkflows.get(cnrId).push({
filename: workflowFilename,
nodeCount: workflowCnrIdCounts.get(cnrId) || 0
});
});
}
});
// Map cnr_id to installed packages with workflow details
cnrIdCounts.forEach((count, cnrId) => {
const workflowDetails = cnrIdToWorkflows.get(cnrId) || [];
const foundPackage = findPackageByCnrId(cnrId, nodePackages, true);
if (foundPackage) {
usageMap.set(foundPackage.key, count);
workflowDetailsMap.set(foundPackage.key, workflowDetails);
}
});
}
return {
success: true,
usageMap: usageMap,
workflowDetailsMap: workflowDetailsMap
};
}
// Size formatting utilities - consolidated from model-manager.js and node-usage-analyzer.js
export function formatSize(v) {
const base = 1000;
const units = ['', 'K', 'M', 'G', 'T', 'P'];
const space = '';
const postfix = 'B';
if (v <= 0) {
return `0${space}${postfix}`;
}
for (let i = 0, l = units.length; i < l; i++) {
const min = Math.pow(base, i);
const max = Math.pow(base, i + 1);
if (v > min && v <= max) {
const unit = units[i];
if (unit) {
const n = v / min;
const nl = n.toString().split('.')[0].length;
const fl = Math.max(3 - nl, 1);
v = n.toFixed(fl);
}
v = v + space + unit + postfix;
break;
}
}
return v;
}
// for size sort
export function sizeToBytes(v) {
if (typeof v === "number") {
return v;
}
if (typeof v === "string") {
const n = parseFloat(v);
const unit = v.replace(/[0-9.B]+/g, "").trim().toUpperCase();
if (unit === "K") {
return n * 1000;
}
if (unit === "M") {
return n * 1000 * 1000;
}
if (unit === "G") {
return n * 1000 * 1000 * 1000;
}
if (unit === "T") {
return n * 1000 * 1000 * 1000 * 1000;
}
}
return v;
}
// Flyover component - consolidated from custom-nodes-manager.js and node-usage-analyzer.js
export function createFlyover(container, options = {}) {
const {
enableHover = false,
hoverHandler = null,
context = null
} = options;
const $flyover = document.createElement("div");
$flyover.className = "cn-flyover";
$flyover.innerHTML = `<div class="cn-flyover-header">
<div class="cn-flyover-close">${icons.arrowRight}</div>
<div class="cn-flyover-title"></div>
<div class="cn-flyover-close">${icons.close}</div>
</div>
<div class="cn-flyover-body"></div>`
container.appendChild($flyover);
const $flyoverTitle = $flyover.querySelector(".cn-flyover-title");
const $flyoverBody = $flyover.querySelector(".cn-flyover-body");
let width = '50%';
let visible = false;
let timeHide;
const closeHandler = (e) => {
if ($flyover === e.target || $flyover.contains(e.target)) {
return;
}
clearTimeout(timeHide);
timeHide = setTimeout(() => {
flyover.hide();
}, 100);
}
const displayHandler = () => {
if (visible) {
$flyover.classList.remove("cn-slide-in-right");
} else {
$flyover.classList.remove("cn-slide-out-right");
$flyover.style.width = '0px';
$flyover.style.display = "none";
}
}
const flyover = {
show: (titleHtml, bodyHtml) => {
clearTimeout(timeHide);
if (context && context.element) {
context.element.removeEventListener("click", closeHandler);
}
$flyoverTitle.innerHTML = titleHtml;
$flyoverBody.innerHTML = bodyHtml;
$flyover.style.display = "block";
$flyover.style.width = width;
if(!visible) {
$flyover.classList.add("cn-slide-in-right");
}
visible = true;
setTimeout(() => {
if (context && context.element) {
context.element.addEventListener("click", closeHandler);
}
}, 100);
},
hide: (now) => {
visible = false;
if (context && context.element) {
context.element.removeEventListener("click", closeHandler);
}
if(now) {
displayHandler();
return;
}
$flyover.classList.add("cn-slide-out-right");
}
}
$flyover.addEventListener("animationend", (e) => {
displayHandler();
});
// Add hover handlers if enabled
if (enableHover && hoverHandler) {
$flyover.addEventListener("mouseenter", hoverHandler, true);
$flyover.addEventListener("mouseleave", hoverHandler, true);
}
$flyover.addEventListener("click", (e) => {
if(e.target.classList.contains("cn-flyover-close")) {
flyover.hide();
return;
}
// Forward other click events to the provided handler or context
if (context && context.handleFlyoverClick) {
context.handleFlyoverClick(e);
}
});
return flyover;
}
// Shared UI State Methods - consolidated from multiple managers
export function createUIStateManager(element, selectors) {
return {
showSelection: (msg) => {
const el = element.querySelector(selectors.selection);
if (el) el.innerHTML = msg;
},
showError: (err) => {
const el = element.querySelector(selectors.message);
if (el) {
const msg = err ? `<font color="red">${err}</font>` : "";
el.innerHTML = msg;
}
},
showMessage: (msg, color) => {
const el = element.querySelector(selectors.message);
if (el) {
if (color) {
msg = `<font color="${color}">${msg}</font>`;
}
el.innerHTML = msg;
}
},
showStatus: (msg, color) => {
const el = element.querySelector(selectors.status);
if (el) {
if (color) {
msg = `<font color="${color}">${msg}</font>`;
}
el.innerHTML = msg;
}
},
showLoading: (grid) => {
if (grid) {
grid.showLoading();
grid.showMask({
opacity: 0.05
});
}
},
hideLoading: (grid) => {
if (grid) {
grid.hideLoading();
grid.hideMask();
}
},
showRefresh: () => {
const el = element.querySelector(selectors.refresh);
if (el) el.style.display = "block";
},
showStop: () => {
const el = element.querySelector(selectors.stop);
if (el) el.style.display = "block";
},
hideStop: () => {
const el = element.querySelector(selectors.stop);
if (el) el.style.display = "none";
}
};
}
initTooltip();

View File

@ -8,7 +8,7 @@ import {
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
showPopover, hidePopover, handle403Response
showPopover, hidePopover, getWorkflowNodeTypes, findPackageByCnrId, analyzeWorkflowUsage, createFlyover
} from "./common.js";
// https://cenfun.github.io/turbogrid/api.html
@ -42,6 +42,8 @@ const ShowMode = {
FAVORITES: "Favorites",
ALTERNATIVES: "Alternatives",
IN_WORKFLOW: "In Workflow",
USED_IN_ANY_WORKFLOW: "Used In Any Workflow",
NOT_USED_IN_ANY_WORKFLOW: "Installed and Unused",
};
export class CustomNodesManager {
@ -271,6 +273,14 @@ export class CustomNodesManager {
label: "In Workflow",
value: ShowMode.IN_WORKFLOW,
hasData: false
}, {
label: "Used In Any Workflow",
value: ShowMode.USED_IN_ANY_WORKFLOW,
hasData: false
}, {
label: "Installed and Unused",
value: ShowMode.NOT_USED_IN_ANY_WORKFLOW,
hasData: false
}, {
label: "Missing",
value: ShowMode.MISSING,
@ -521,7 +531,11 @@ export class CustomNodesManager {
const grid = new TG.Grid(container);
this.grid = grid;
this.flyover = this.createFlyover(container);
this.flyover = createFlyover(container, {
enableHover: true,
hoverHandler: this.handleFlyoverHover.bind(this),
context: this
});
let prevViewRowsLength = -1;
grid.bind('onUpdated', (e, d) => {
@ -1063,143 +1077,63 @@ export class CustomNodesManager {
hidePopover();
}
createFlyover(container) {
const $flyover = document.createElement("div");
$flyover.className = "cn-flyover";
$flyover.innerHTML = `<div class="cn-flyover-header">
<div class="cn-flyover-close">${icons.arrowRight}</div>
<div class="cn-flyover-title"></div>
<div class="cn-flyover-close">${icons.close}</div>
</div>
<div class="cn-flyover-body"></div>`
container.appendChild($flyover);
const $flyoverTitle = $flyover.querySelector(".cn-flyover-title");
const $flyoverBody = $flyover.querySelector(".cn-flyover-body");
let width = '50%';
let visible = false;
let timeHide;
const closeHandler = (e) => {
if ($flyover === e.target || $flyover.contains(e.target)) {
return;
}
clearTimeout(timeHide);
timeHide = setTimeout(() => {
flyover.hide();
}, 100);
}
const hoverHandler = (e) => {
if(e.type === "mouseenter") {
if(e.target.classList.contains("cn-nodes-name")) {
this.showNodePreview(e.target);
}
return;
}
this.hideNodePreview();
}
const displayHandler = () => {
if (visible) {
$flyover.classList.remove("cn-slide-in-right");
} else {
$flyover.classList.remove("cn-slide-out-right");
$flyover.style.width = '0px';
$flyover.style.display = "none";
}
}
const flyover = {
show: (titleHtml, bodyHtml) => {
clearTimeout(timeHide);
this.element.removeEventListener("click", closeHandler);
$flyoverTitle.innerHTML = titleHtml;
$flyoverBody.innerHTML = bodyHtml;
$flyover.style.display = "block";
$flyover.style.width = width;
if(!visible) {
$flyover.classList.add("cn-slide-in-right");
}
visible = true;
setTimeout(() => {
this.element.addEventListener("click", closeHandler);
}, 100);
},
hide: (now) => {
visible = false;
this.element.removeEventListener("click", closeHandler);
if(now) {
displayHandler();
return;
}
$flyover.classList.add("cn-slide-out-right");
}
}
$flyover.addEventListener("animationend", (e) => {
displayHandler();
});
$flyover.addEventListener("mouseenter", hoverHandler, true);
$flyover.addEventListener("mouseleave", hoverHandler, true);
$flyover.addEventListener("click", (e) => {
handleFlyoverHover(e) {
if(e.type === "mouseenter") {
if(e.target.classList.contains("cn-nodes-name")) {
const nodeName = e.target.innerText;
const nodeItem = this.nodeMap[nodeName];
if (!nodeItem) {
copyText(nodeName).then((res) => {
if (res) {
e.target.setAttribute("action", "Copied");
e.target.classList.add("action");
setTimeout(() => {
e.target.classList.remove("action");
e.target.removeAttribute("action");
}, 1000);
}
});
return;
}
this.showNodePreview(e.target);
}
return;
}
this.hideNodePreview();
}
const [x, y, w, h] = app.canvas.ds.visible_area;
const dpi = Math.max(window.devicePixelRatio ?? 1, 1);
const node = window.LiteGraph?.createNode(
nodeItem.name,
nodeItem.display_name,
{
pos: [x + (w-300) / dpi / 2, y]
handleFlyoverClick(e) {
if(e.target.classList.contains("cn-nodes-name")) {
const nodeName = e.target.innerText;
const nodeItem = this.nodeMap[nodeName];
if (!nodeItem) {
copyText(nodeName).then((res) => {
if (res) {
e.target.setAttribute("action", "Copied");
e.target.classList.add("action");
setTimeout(() => {
e.target.classList.remove("action");
e.target.removeAttribute("action");
}, 1000);
}
);
if (node) {
app.graph.add(node);
e.target.setAttribute("action", "Added to Workflow");
e.target.classList.add("action");
setTimeout(() => {
e.target.classList.remove("action");
e.target.removeAttribute("action");
}, 1000);
}
});
return;
}
if(e.target.classList.contains("cn-nodes-pack")) {
const hash = e.target.getAttribute("hash");
const rowItem = this.grid.getRowItemBy("hash", hash);
//console.log(rowItem);
this.grid.scrollToRow(rowItem);
this.addHighlight(rowItem);
return;
}
if(e.target.classList.contains("cn-flyover-close")) {
flyover.hide();
return;
}
});
return flyover;
const [x, y, w, h] = app.canvas.ds.visible_area;
const dpi = Math.max(window.devicePixelRatio ?? 1, 1);
const node = window.LiteGraph?.createNode(
nodeItem.name,
nodeItem.display_name,
{
pos: [x + (w-300) / dpi / 2, y]
}
);
if (node) {
app.graph.add(node);
e.target.setAttribute("action", "Added to Workflow");
e.target.classList.add("action");
setTimeout(() => {
e.target.classList.remove("action");
e.target.removeAttribute("action");
}, 1000);
}
return;
}
if(e.target.classList.contains("cn-nodes-pack")) {
const hash = e.target.getAttribute("hash");
const rowItem = this.grid.getRowItemBy("hash", hash);
//console.log(rowItem);
this.grid.scrollToRow(rowItem);
this.addHighlight(rowItem);
return;
}
}
showNodes(d) {
@ -1874,7 +1808,10 @@ export class CustomNodesManager {
for(let k in allUsedNodes) {
var item;
if(allUsedNodes[k].properties.cnr_id) {
item = this.custom_nodes[allUsedNodes[k].properties.cnr_id];
const foundPackage = findPackageByCnrId(allUsedNodes[k].properties.cnr_id, this.custom_nodes, false);
if (foundPackage) {
item = foundPackage.pack;
}
}
else if(allUsedNodes[k].properties.aux_id) {
item = aux_id_to_pack[allUsedNodes[k].properties.aux_id];
@ -1921,6 +1858,48 @@ export class CustomNodesManager {
return hashMap;
}
async getUsedInAnyWorkflow() {
this.showStatus(`Loading workflow usage analysis ...`);
const result = await analyzeWorkflowUsage(this.custom_nodes);
if (!result.success) {
this.showError(`Failed to get workflow data: ${result.error}`);
return {};
}
const hashMap = {};
// Convert usage map keys to hash map
result.usageMap.forEach((count, packageKey) => {
const pack = this.custom_nodes[packageKey];
if (pack && pack.hash) {
hashMap[pack.hash] = true;
}
});
return hashMap;
}
async getNotUsedInAnyWorkflow() {
this.showStatus(`Loading workflow usage analysis ...`);
// Get the used packages first using common utility
const usedHashMap = await this.getUsedInAnyWorkflow();
const notUsedHashMap = {};
// Find all installed packages that are NOT in the used list
for(let k in this.custom_nodes) {
let nodepack = this.custom_nodes[k];
// Only consider installed packages
if (nodepack.state !== "not-installed" && !usedHashMap[nodepack.hash]) {
notUsedHashMap[nodepack.hash] = true;
}
}
return notUsedHashMap;
}
async loadData(show_mode = ShowMode.NORMAL) {
const isElectron = 'electronAPI' in window;
@ -1990,6 +1969,10 @@ export class CustomNodesManager {
hashMap = await this.getFavorites();
} else if(this.show_mode == ShowMode.IN_WORKFLOW) {
hashMap = await this.getNodepackInWorkflow();
} else if(this.show_mode == ShowMode.USED_IN_ANY_WORKFLOW) {
hashMap = await this.getUsedInAnyWorkflow();
} else if(this.show_mode == ShowMode.NOT_USED_IN_ANY_WORKFLOW) {
hashMap = await this.getNotUsedInAnyWorkflow();
}
filterItem.hashMap = hashMap;

View File

@ -3,7 +3,7 @@ import { $el } from "../../scripts/ui.js";
import {
manager_instance, rebootAPI,
fetchData, md5, icons, show_message, customAlert, infoToast, showTerminal,
storeColumnWidth, restoreColumnWidth, loadCss, handle403Response
storeColumnWidth, restoreColumnWidth, loadCss, formatSize, sizeToBytes
} from "./common.js";
import { api } from "../../scripts/api.js";
@ -359,7 +359,7 @@ export class ModelManager {
width: 100,
formatter: (size) => {
if (typeof size === "number") {
return this.formatSize(size);
return formatSize(size);
}
return size;
}
@ -582,7 +582,7 @@ export class ModelManager {
models.forEach((item, i) => {
const { type, base, name, reference, installed } = item;
item.originalData = JSON.parse(JSON.stringify(item));
item.size = this.sizeToBytes(item.size);
item.size = sizeToBytes(item.size);
item.hash = md5(name + reference);
item.id = i + 1;
@ -659,7 +659,6 @@ export class ModelManager {
const { models } = res.data;
this.modelList = this.getModelList(models);
// console.log("models", this.modelList);
this.updateFilter();
@ -671,56 +670,6 @@ export class ModelManager {
// ===========================================================================================
formatSize(v) {
const base = 1000;
const units = ['', 'K', 'M', 'G', 'T', 'P'];
const space = '';
const postfix = 'B';
if (v <= 0) {
return `0${space}${postfix}`;
}
for (let i = 0, l = units.length; i < l; i++) {
const min = Math.pow(base, i);
const max = Math.pow(base, i + 1);
if (v > min && v <= max) {
const unit = units[i];
if (unit) {
const n = v / min;
const nl = n.toString().split('.')[0].length;
const fl = Math.max(3 - nl, 1);
v = n.toFixed(fl);
}
v = v + space + unit + postfix;
break;
}
}
return v;
}
// for size sort
sizeToBytes(v) {
if (typeof v === "number") {
return v;
}
if (typeof v === "string") {
const n = parseFloat(v);
const unit = v.replace(/[0-9.B]+/g, "").trim().toUpperCase();
if (unit === "K") {
return n * 1000;
}
if (unit === "M") {
return n * 1000 * 1000;
}
if (unit === "G") {
return n * 1000 * 1000 * 1000;
}
if (unit === "T") {
return n * 1000 * 1000 * 1000 * 1000;
}
}
return v;
}
showSelection(msg) {
this.element.querySelector(".cmm-manager-selection").innerHTML = msg;
}

699
js/node-usage-analyzer.css Normal file
View File

@ -0,0 +1,699 @@
.nu-manager {
--grid-font: -apple-system, BlinkMacSystemFont, "Segue UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
z-index: 1099;
width: 80%;
height: 80%;
display: flex;
flex-direction: column;
gap: 10px;
color: var(--fg-color);
font-family: arial, sans-serif;
text-underline-offset: 3px;
outline: none;
}
.nu-manager .nu-flex-auto {
flex: auto;
}
.nu-manager button {
font-size: 16px;
color: var(--input-text);
background-color: var(--comfy-input-bg);
border-radius: 8px;
border-color: var(--border-color);
border-style: solid;
margin: 0;
padding: 4px 8px;
min-width: 100px;
}
.nu-manager button:disabled,
.nu-manager input:disabled,
.nu-manager select:disabled {
color: gray;
}
.nu-manager button:disabled {
background-color: var(--comfy-input-bg);
}
.nu-manager .nu-manager-restart {
display: none;
background-color: #500000;
color: white;
}
.nu-manager .nu-manager-stop {
display: none;
background-color: #500000;
color: white;
}
.nu-manager .nu-manager-back {
align-items: center;
justify-content: center;
}
.arrow-icon {
height: 1em;
width: 1em;
margin-right: 5px;
transform: translateY(2px);
}
.cn-icon {
display: block;
width: 16px;
height: 16px;
}
.cn-icon svg {
display: block;
margin: 0;
pointer-events: none;
}
.nu-manager-header {
display: flex;
flex-wrap: wrap;
gap: 5px;
align-items: center;
padding: 0 5px;
}
.nu-manager-header label {
display: flex;
gap: 5px;
align-items: center;
}
.nu-manager-filter {
height: 28px;
line-height: 28px;
}
.nu-manager-keywords {
height: 28px;
line-height: 28px;
padding: 0 5px 0 26px;
background-size: 16px;
background-position: 5px center;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20pointer-events%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%23888%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m21%2021-4.486-4.494M19%2010.5a8.5%208.5%200%201%201-17%200%208.5%208.5%200%200%201%2017%200%22%2F%3E%3C%2Fsvg%3E");
}
.nu-manager-status {
padding-left: 10px;
}
.nu-manager-grid {
flex: auto;
border: 1px solid var(--border-color);
overflow: hidden;
position: relative;
}
.nu-manager-selection {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
}
.nu-manager-message {
position: relative;
}
.nu-manager-footer {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
}
.nu-manager-grid .tg-turbogrid {
font-family: var(--grid-font);
font-size: 15px;
background: var(--bg-color);
}
.nu-manager-grid .tg-turbogrid .tg-highlight::after {
position: absolute;
top: 0;
left: 0;
content: "";
display: block;
width: 100%;
height: 100%;
box-sizing: border-box;
background-color: #80bdff11;
pointer-events: none;
}
.nu-manager-grid .nu-pack-name a {
color: skyblue;
text-decoration: none;
word-break: break-word;
}
.nu-manager-grid .cn-pack-desc a {
color: #5555FF;
font-weight: bold;
text-decoration: none;
}
.nu-manager-grid .tg-cell a:hover {
text-decoration: underline;
}
.nu-manager-grid .cn-pack-version {
line-height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
gap: 5px;
}
.nu-manager-grid .cn-pack-nodes {
line-height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 5px;
cursor: pointer;
height: 100%;
}
.nu-manager-grid .cn-pack-nodes:hover {
text-decoration: underline;
}
.nu-manager-grid .cn-pack-conflicts {
color: orange;
}
.cn-popover {
position: fixed;
z-index: 10000;
padding: 20px;
color: #1e1e1e;
filter: drop-shadow(1px 5px 5px rgb(0 0 0 / 30%));
overflow: hidden;
}
.cn-flyover {
position: absolute;
top: 0;
right: 0;
z-index: 1000;
display: none;
width: 50%;
height: 100%;
background-color: var(--comfy-menu-bg);
animation-duration: 0.2s;
animation-fill-mode: both;
flex-direction: column;
}
.cn-flyover::before {
position: absolute;
top: 0;
content: "";
z-index: 10;
display: block;
width: 10px;
height: 100%;
pointer-events: none;
left: -10px;
background-image: linear-gradient(to left, rgb(0 0 0 / 20%), rgb(0 0 0 / 0%));
}
.cn-flyover-header {
height: 45px;
display: flex;
align-items: center;
gap: 5px;
border-bottom: 1px solid var(--border-color);
}
.cn-flyover-close {
display: flex;
align-items: center;
padding: 0 10px;
justify-content: center;
cursor: pointer;
opacity: 0.8;
height: 100%;
}
.cn-flyover-close:hover {
opacity: 1;
}
.cn-flyover-close svg {
display: block;
margin: 0;
pointer-events: none;
width: 20px;
height: 20px;
}
.cn-flyover-title {
display: flex;
align-items: center;
font-weight: bold;
gap: 10px;
flex: auto;
}
.cn-flyover-body {
height: calc(100% - 45px);
overflow-y: auto;
position: relative;
background-color: var(--comfy-menu-secondary-bg);
}
@keyframes cn-slide-in-right {
from {
visibility: visible;
transform: translate3d(100%, 0, 0);
}
to {
transform: translate3d(0, 0, 0);
}
}
.cn-slide-in-right {
animation-name: cn-slide-in-right;
}
@keyframes cn-slide-out-right {
from {
transform: translate3d(0, 0, 0);
}
to {
visibility: hidden;
transform: translate3d(100%, 0, 0);
}
}
.cn-slide-out-right {
animation-name: cn-slide-out-right;
}
.cn-nodes-list {
width: 100%;
}
.cn-nodes-row {
display: flex;
align-items: center;
gap: 10px;
}
.cn-nodes-row:nth-child(odd) {
background-color: rgb(0 0 0 / 5%);
}
.cn-nodes-row:hover {
background-color: rgb(0 0 0 / 10%);
}
.cn-nodes-sn {
text-align: right;
min-width: 35px;
color: var(--drag-text);
flex-shrink: 0;
font-size: 12px;
padding: 8px 5px;
}
.cn-nodes-name {
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
position: relative;
padding: 8px 5px;
}
.cn-nodes-name::after {
content: attr(action);
position: absolute;
pointer-events: none;
top: 50%;
left: 100%;
transform: translate(5px, -50%);
font-size: 12px;
color: var(--drag-text);
background-color: var(--comfy-input-bg);
border-radius: 10px;
border: 1px solid var(--border-color);
padding: 3px 8px;
display: none;
}
.cn-nodes-name.action::after {
display: block;
}
.cn-nodes-name:hover {
text-decoration: underline;
}
.cn-nodes-conflict .cn-nodes-name,
.cn-nodes-conflict .cn-icon {
color: orange;
}
.cn-conflicts-list {
display: flex;
flex-wrap: wrap;
gap: 5px;
align-items: center;
padding: 5px 0;
}
.cn-conflicts-list b {
font-weight: normal;
color: var(--descrip-text);
}
.cn-nodes-pack {
cursor: pointer;
color: skyblue;
}
.cn-nodes-pack:hover {
text-decoration: underline;
}
.cn-pack-badge {
font-size: 12px;
font-weight: normal;
background-color: var(--comfy-input-bg);
border-radius: 10px;
border: 1px solid var(--border-color);
padding: 3px 8px;
color: var(--error-text);
}
.cn-preview {
min-width: 300px;
max-width: 500px;
min-height: 120px;
overflow: hidden;
font-size: 12px;
pointer-events: none;
padding: 12px;
color: var(--fg-color);
}
.cn-preview-header {
display: flex;
gap: 8px;
align-items: center;
border-bottom: 1px solid var(--comfy-input-bg);
padding: 5px 10px;
}
.cn-preview-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: grey;
position: relative;
filter: drop-shadow(1px 2px 3px rgb(0 0 0 / 30%));
}
.cn-preview-dot.cn-preview-optional::after {
content: "";
position: absolute;
pointer-events: none;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--comfy-input-bg);
border-radius: 50%;
width: 3px;
height: 3px;
}
.cn-preview-dot.cn-preview-grid {
border-radius: 0;
}
.cn-preview-dot.cn-preview-grid::before {
content: '';
position: absolute;
border-left: 1px solid var(--comfy-input-bg);
border-right: 1px solid var(--comfy-input-bg);
width: 4px;
height: 100%;
left: 2px;
top: 0;
z-index: 1;
}
.cn-preview-dot.cn-preview-grid::after {
content: '';
position: absolute;
border-top: 1px solid var(--comfy-input-bg);
border-bottom: 1px solid var(--comfy-input-bg);
width: 100%;
height: 4px;
left: 0;
top: 2px;
z-index: 1;
}
.cn-preview-name {
flex: auto;
font-size: 14px;
}
.cn-preview-io {
display: flex;
justify-content: space-between;
padding: 10px 10px;
}
.cn-preview-column > div {
display: flex;
gap: 10px;
align-items: center;
height: 18px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.cn-preview-input {
justify-content: flex-start;
}
.cn-preview-output {
justify-content: flex-end;
}
.cn-preview-list {
display: flex;
flex-direction: column;
gap: 3px;
padding: 0 10px 10px 10px;
}
.cn-preview-switch {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
background: var(--bg-color);
border: 2px solid var(--border-color);
border-radius: 10px;
text-wrap: nowrap;
padding: 2px 20px;
gap: 10px;
}
.cn-preview-switch::before,
.cn-preview-switch::after {
position: absolute;
pointer-events: none;
top: 50%;
transform: translate(0, -50%);
color: var(--fg-color);
opacity: 0.8;
}
.cn-preview-switch::before {
content: "◀";
left: 5px;
}
.cn-preview-switch::after {
content: "▶";
right: 5px;
}
.cn-preview-value {
color: var(--descrip-text);
}
.cn-preview-string {
min-height: 30px;
max-height: 300px;
background: var(--bg-color);
color: var(--descrip-text);
border-radius: 3px;
padding: 3px 5px;
overflow-y: auto;
overflow-x: hidden;
}
.cn-preview-description {
margin: 0px 10px 10px 10px;
padding: 6px;
background: var(--border-color);
color: var(--descrip-text);
border-radius: 5px;
font-style: italic;
word-break: break-word;
}
.cn-tag-list {
display: flex;
flex-wrap: wrap;
gap: 5px;
align-items: center;
margin-bottom: 5px;
}
.cn-tag-list > div {
background-color: var(--border-color);
border-radius: 5px;
padding: 0 5px;
}
.cn-install-buttons {
display: flex;
flex-direction: column;
gap: 3px;
padding: 3px;
align-items: center;
justify-content: center;
height: 100%;
}
.cn-selected-buttons {
display: flex;
gap: 5px;
align-items: center;
padding-right: 20px;
}
.nu-manager .cn-btn-enable {
background-color: #333399;
color: white;
}
.nu-manager .cn-btn-disable {
background-color: #442277;
color: white;
}
.nu-manager .cn-btn-update {
background-color: #1155AA;
color: white;
}
.nu-manager .cn-btn-try-update {
background-color: Gray;
color: white;
}
.nu-manager .cn-btn-try-fix {
background-color: #6495ED;
color: white;
}
.nu-manager .cn-btn-import-failed {
background-color: #AA1111;
font-size: 10px;
font-weight: bold;
color: white;
}
.nu-manager .cn-btn-install {
background-color: black;
color: white;
}
.nu-manager .cn-btn-try-install {
background-color: Gray;
color: white;
}
.nu-manager .cn-btn-uninstall {
background-color: #993333;
color: white;
}
.nu-manager .cn-btn-reinstall {
background-color: #993333;
color: white;
}
.nu-manager .cn-btn-switch {
background-color: #448833;
color: white;
}
@keyframes nu-btn-loading-bg {
0% {
left: 0;
}
100% {
left: -105px;
}
}
.nu-manager button.nu-btn-loading {
position: relative;
overflow: hidden;
border-color: rgb(0 119 207 / 80%);
background-color: var(--comfy-input-bg);
}
.nu-manager button.nu-btn-loading::after {
position: absolute;
top: 0;
left: 0;
content: "";
width: 500px;
height: 100%;
background-image: repeating-linear-gradient(
-45deg,
rgb(0 119 207 / 30%),
rgb(0 119 207 / 30%) 10px,
transparent 10px,
transparent 15px
);
animation: nu-btn-loading-bg 2s linear infinite;
}
.nu-manager-light .nu-pack-name a {
color: blue;
}
.nu-manager-light .cm-warn-note {
background-color: #ccc !important;
}
.nu-manager-light .cn-btn-install {
background-color: #333;
}

742
js/node-usage-analyzer.js Normal file
View File

@ -0,0 +1,742 @@
import { app } from "../../scripts/app.js";
import { $el } from "../../scripts/ui.js";
import {
manager_instance,
fetchData, md5, show_message, customAlert, infoToast, showTerminal,
storeColumnWidth, restoreColumnWidth, loadCss, uninstallNodes,
analyzeWorkflowUsage, sizeToBytes, createFlyover, createUIStateManager
} from "./common.js";
import { api } from "../../scripts/api.js";
// https://cenfun.github.io/turbogrid/api.html
import TG from "./turbogrid.esm.js";
loadCss("./node-usage-analyzer.css");
const gridId = "model";
const pageHtml = `
<div class="nu-manager-header">
<div class="nu-manager-status"></div>
<input type="text" class="nu-manager-keywords" placeholder="Filter keywords..." />
<div class="nu-flex-auto"></div>
</div>
<div class="nu-manager-grid"></div>
<div class="nu-manager-selection"></div>
<div class="nu-manager-message"></div>
<div class="nu-manager-footer">
<button class="nu-manager-back">
<svg class="arrow-icon" width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 8H18M2 8L8 2M2 8L8 14" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Back
</button>
<button class="nu-manager-refresh">Refresh</button>
<button class="nu-manager-stop">Stop</button>
<div class="nu-flex-auto"></div>
</div>
`;
export class NodeUsageAnalyzer {
static instance = null;
static SortMode = {
BY_PACKAGE: 'by_package'
};
constructor(app, manager_dialog) {
this.app = app;
this.manager_dialog = manager_dialog;
this.id = "nu-manager";
this.filter = '';
this.type = '';
this.base = '';
this.keywords = '';
this.init();
// Initialize shared UI state manager
this.ui = createUIStateManager(this.element, {
selection: ".nu-manager-selection",
message: ".nu-manager-message",
status: ".nu-manager-status",
refresh: ".nu-manager-refresh",
stop: ".nu-manager-stop"
});
api.addEventListener("cm-queue-status", this.onQueueStatus);
}
init() {
this.element = $el("div", {
parent: document.body,
className: "comfy-modal nu-manager"
});
this.element.innerHTML = pageHtml;
this.bindEvents();
this.initGrid();
}
bindEvents() {
const eventsMap = {
".nu-manager-selection": {
click: (e) => {
const target = e.target;
const mode = target.getAttribute("mode");
if (mode === "install") {
this.installModels(this.selectedModels, target);
} else if (mode === "uninstall") {
this.uninstallModels(this.selectedModels, target);
}
}
},
".nu-manager-refresh": {
click: () => {
app.refreshComboInNodes();
}
},
".nu-manager-stop": {
click: () => {
api.fetchApi('/manager/queue/reset');
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
}
},
".nu-manager-back": {
click: (e) => {
this.close()
manager_instance.show();
}
}
};
Object.keys(eventsMap).forEach(selector => {
const target = this.element.querySelector(selector);
if (target) {
const events = eventsMap[selector];
if (events) {
Object.keys(events).forEach(type => {
target.addEventListener(type, events[type]);
});
}
}
});
}
// ===========================================================================================
initGrid() {
const container = this.element.querySelector(".nu-manager-grid");
const grid = new TG.Grid(container);
this.grid = grid;
this.flyover = createFlyover(container, { context: this });
grid.bind('onUpdated', (e, d) => {
this.ui.showStatus(`${grid.viewRows.length.toLocaleString()} installed packages`);
});
grid.bind('onSelectChanged', (e, changes) => {
this.renderSelected();
});
grid.bind("onColumnWidthChanged", (e, columnItem) => {
storeColumnWidth(gridId, columnItem)
});
grid.bind('onClick', (e, d) => {
const { rowItem } = d;
const target = d.e.target;
const mode = target.getAttribute("mode");
if (mode === "install") {
this.installModels([rowItem], target);
return;
}
if (mode === "uninstall") {
this.uninstallModels([rowItem], target);
return;
}
// Handle click on usage count
if (d.columnItem.id === "used_in_count" && rowItem.used_in_count > 0) {
this.showUsageDetails(rowItem);
return;
}
});
grid.setOption({
theme: 'dark',
selectVisible: true,
selectMultiple: true,
selectAllVisible: true,
textSelectable: true,
scrollbarRound: true,
frozenColumn: 1,
rowNotFound: "No Results",
rowHeight: 40,
bindWindowResize: true,
bindContainerResize: true,
cellResizeObserver: (rowItem, columnItem) => {
const autoHeightColumns = ['name', 'description'];
return autoHeightColumns.includes(columnItem.id)
}
});
}
renderGrid() {
// update theme
const colorPalette = this.app.ui.settings.settingsValues['Comfy.ColorPalette'];
Array.from(this.element.classList).forEach(cn => {
if (cn.startsWith("nu-manager-")) {
this.element.classList.remove(cn);
}
});
this.element.classList.add(`nu-manager-${colorPalette}`);
const options = {
theme: colorPalette === "light" ? "" : "dark"
};
const rows = this.modelList || [];
const columns = [{
id: 'title',
name: 'Title',
width: 200,
minWidth: 100,
maxWidth: 500,
classMap: 'nu-pack-name',
formatter: function (name, rowItem, columnItem, cellNode) {
return `<a href=${rowItem.reference} target="_blank"><b>${name}</b></a>`;
}
}, {
id: 'used_in_count',
name: 'Used in',
width: 100,
formatter: function (usedCount, rowItem, columnItem) {
if (!usedCount || usedCount === 0) {
return '0';
}
const plural = usedCount > 1 ? 's' : '';
return `<div class="cn-pack-nodes" style="cursor: pointer;">${usedCount} workflow${plural}</div>`;
}
}, {
id: 'action',
name: 'Action',
width: 160,
minWidth: 140,
maxWidth: 200,
sortable: false,
align: 'center',
formatter: function (action, rowItem, columnItem) {
// Only show uninstall button for installed packages
if (rowItem.originalData && rowItem.originalData.state && rowItem.originalData.state !== "not-installed") {
return `<div class="cn-install-buttons"><button class="nu-btn-uninstall" mode="uninstall">Uninstall</button></div>`;
}
return '';
}
}];
restoreColumnWidth(gridId, columns);
this.grid.setData({
options,
rows,
columns
});
this.grid.render();
}
updateGrid() {
if (this.grid) {
this.grid.update();
}
}
showUsageDetails(rowItem) {
const workflowList = rowItem.workflowDetails;
if (!workflowList || workflowList.length === 0) {
return;
}
let titleHtml = `<div class="cn-nodes-pack">${rowItem.title}</div>`;
const list = [];
list.push(`<div class="cn-nodes-list">`);
workflowList.forEach((workflow, i) => {
list.push(`<div class="cn-nodes-row">`);
list.push(`<div class="cn-nodes-sn">${i + 1}</div>`);
list.push(`<div class="cn-nodes-name">${workflow.filename}</div>`);
list.push(`<div class="cn-nodes-details">${workflow.nodeCount} node${workflow.nodeCount > 1 ? 's' : ''}</div>`);
list.push(`</div>`);
});
list.push("</div>");
const bodyHtml = list.join("");
this.flyover.show(titleHtml, bodyHtml);
}
renderSelected() {
const selectedList = this.grid.getSelectedRows();
if (!selectedList.length) {
this.ui.showSelection("");
return;
}
const installedSelected = selectedList.filter(item =>
item.originalData && item.originalData.state && item.originalData.state !== "not-installed"
);
if (installedSelected.length === 0) {
this.ui.showSelection(`<span>Selected <b>${selectedList.length}</b> packages (none can be uninstalled)</span>`);
return;
}
this.selectedModels = installedSelected;
this.ui.showSelection(`
<div class="nu-selected-buttons">
<span>Selected <b>${installedSelected.length}</b> installed packages</span>
<button class="nu-btn-uninstall" mode="uninstall">Uninstall Selected</button>
</div>
`);
}
// ===========================================================================================
async installModels(list, btn) {
let stats = await api.fetchApi('/manager/queue/status');
stats = await stats.json();
if (stats.is_processing) {
customAlert(`[ComfyUI-Manager] There are already tasks in progress. Please try again after it is completed. (${stats.done_count}/${stats.total_count})`);
return;
}
btn.classList.add("nu-btn-loading");
this.ui.showError("");
let needRefresh = false;
let errorMsg = "";
await api.fetchApi('/manager/queue/reset');
let target_items = [];
for (const item of list) {
this.grid.scrollRowIntoView(item);
target_items.push(item);
this.ui.showStatus(`Install ${item.name} ...`);
const data = item.originalData;
data.ui_id = item.hash;
const res = await api.fetchApi(`/manager/queue/install_model`, {
method: 'POST',
body: JSON.stringify(data)
});
if (res.status != 200) {
errorMsg = `'${item.name}': `;
if (res.status == 403) {
errorMsg += `This action is not allowed with this security level configuration.\n`;
} else {
errorMsg += await res.text() + '\n';
}
break;
}
}
this.install_context = { btn: btn, targets: target_items };
if (errorMsg) {
this.ui.showError(errorMsg);
show_message("[Installation Errors]\n" + errorMsg);
// reset
for (let k in target_items) {
const item = target_items[k];
this.grid.updateCell(item, "installed");
}
}
else {
await api.fetchApi('/manager/queue/start');
this.ui.showStop();
showTerminal();
}
}
async uninstallModels(list, btn) {
btn.classList.add("nu-btn-loading");
this.ui.showError("");
const result = await uninstallNodes(list, {
title: list.length === 1 ? list[0].title || list[0].name : `${list.length} custom nodes`,
channel: 'default',
mode: 'default',
onProgress: (msg) => {
this.showStatus(msg);
},
onError: (errorMsg) => {
this.showError(errorMsg);
},
onSuccess: (targets) => {
this.showStatus(`Uninstalled ${targets.length} custom node(s) successfully`);
this.showMessage(`To apply the uninstalled custom nodes, please restart ComfyUI and refresh browser.`, "red");
// Update the grid to reflect changes
for (let item of targets) {
if (item.originalData) {
item.originalData.state = "not-installed";
}
this.grid.updateRow(item);
}
}
});
if (result.success) {
this.showStop();
}
btn.classList.remove("nu-btn-loading");
}
async onQueueStatus(event) {
let self = NodeUsageAnalyzer.instance;
if (event.detail.status == 'in_progress' && (event.detail.ui_target == 'model_manager' || event.detail.ui_target == 'nodepack_manager')) {
const hash = event.detail.target;
const item = self.grid.getRowItemBy("hash", hash);
if (item) {
item.refresh = true;
self.grid.setRowSelected(item, false);
item.selectable = false;
self.grid.updateRow(item);
}
}
else if (event.detail.status == 'done') {
self.hideStop();
self.onQueueCompleted(event.detail);
}
}
async onQueueCompleted(info) {
let result = info.model_result || info.nodepack_result;
if (!result || result.length == 0) {
return;
}
let self = NodeUsageAnalyzer.instance;
if (!self.install_context) {
return;
}
let btn = self.install_context.btn;
self.hideLoading();
btn.classList.remove("nu-btn-loading");
let errorMsg = "";
for (let hash in result) {
let v = result[hash];
if (v != 'success' && v != 'skip')
errorMsg += v + '\n';
}
for (let k in self.install_context.targets) {
let item = self.install_context.targets[k];
if (info.model_result) {
self.grid.updateCell(item, "installed");
} else if (info.nodepack_result) {
// Handle uninstall completion
if (item.originalData) {
item.originalData.state = "not-installed";
}
self.grid.updateRow(item);
}
}
if (errorMsg) {
self.showError(errorMsg);
show_message("Operation Error:\n" + errorMsg);
} else {
if (info.model_result) {
self.showStatus(`Install ${Object.keys(result).length} models successfully`);
self.showRefresh();
self.showMessage(`To apply the installed model, please click the 'Refresh' button.`, "red");
} else if (info.nodepack_result) {
self.showStatus(`Uninstall ${Object.keys(result).length} custom node(s) successfully`);
self.showMessage(`To apply the uninstalled custom nodes, please restart ComfyUI and refresh browser.`, "red");
}
}
infoToast('Tasks done', `[ComfyUI-Manager] All tasks in the queue have been completed.\n${info.done_count}/${info.total_count}`);
self.install_context = undefined;
}
getModelList(models) {
const typeMap = new Map();
const baseMap = new Map();
models.forEach((item, i) => {
const { type, base, name, reference, installed } = item;
// CRITICAL FIX: Do NOT overwrite originalData - it contains the needed state field!
item.size = sizeToBytes(item.size);
item.hash = md5(name + reference);
if (installed === "True") {
item.selectable = false;
}
typeMap.set(type, type);
baseMap.set(base, base);
});
const typeList = [];
typeMap.forEach(type => {
typeList.push({
label: type,
value: type
});
});
typeList.sort((a, b) => {
const au = a.label.toUpperCase();
const bu = b.label.toUpperCase();
if (au !== bu) {
return au > bu ? 1 : -1;
}
return 0;
});
this.typeList = [{
label: "All",
value: ""
}].concat(typeList);
const baseList = [];
baseMap.forEach(base => {
baseList.push({
label: base,
value: base
});
});
baseList.sort((a, b) => {
const au = a.label.toUpperCase();
const bu = b.label.toUpperCase();
if (au !== bu) {
return au > bu ? 1 : -1;
}
return 0;
});
this.baseList = [{
label: "All",
value: ""
}].concat(baseList);
return models;
}
// ===========================================================================================
async loadData() {
this.showLoading();
this.showStatus(`Analyzing node usage ...`);
const mode = manager_instance.datasrc_combo.value;
const nodeListRes = await fetchData(`/customnode/getlist?mode=${mode}&skip_update=true`);
if (nodeListRes.error) {
this.showError("Failed to get custom node list.");
this.hideLoading();
return;
}
const { channel, node_packs } = nodeListRes.data;
delete node_packs['comfyui-manager'];
this.installed_custom_node_packs = node_packs;
// Use the consolidated workflow analysis utility
const result = await analyzeWorkflowUsage(node_packs);
if (!result.success) {
if (result.error.toString().includes('204')) {
this.showMessage("No workflows were found for analysis.");
} else {
this.showError(result.error);
this.hideLoading();
return;
}
}
// Transform node_packs into models format - ONLY INSTALLED PACKAGES
const models = [];
Object.keys(node_packs).forEach((packKey, index) => {
const pack = node_packs[packKey];
// Only include installed packages (filter out "not-installed" packages)
if (pack.state === "not-installed") {
return; // Skip non-installed packages
}
const usedCount = result.usageMap?.get(packKey) || 0;
const workflowDetails = result.workflowDetailsMap?.get(packKey) || [];
models.push({
title: pack.title || packKey,
reference: pack.reference || pack.files?.[0] || '#',
used_in_count: usedCount,
workflowDetails: workflowDetails,
name: packKey,
originalData: pack
});
});
// Sort by usage count (descending) then by title
models.sort((a, b) => {
if (b.used_in_count !== a.used_in_count) {
return b.used_in_count - a.used_in_count;
}
return a.title.localeCompare(b.title);
});
this.modelList = this.getModelList(models);
this.renderGrid();
this.hideLoading();
}
// ===========================================================================================
showSelection(msg) {
this.element.querySelector(".nu-manager-selection").innerHTML = msg;
}
showError(err) {
this.showMessage(err, "red");
}
showMessage(msg, color) {
if (color) {
msg = `<font color="${color}">${msg}</font>`;
}
this.element.querySelector(".nu-manager-message").innerHTML = msg;
}
showStatus(msg, color) {
if (color) {
msg = `<font color="${color}">${msg}</font>`;
}
this.element.querySelector(".nu-manager-status").innerHTML = msg;
}
showLoading() {
// this.setDisabled(true);
if (this.grid) {
this.grid.showLoading();
this.grid.showMask({
opacity: 0.05
});
}
}
hideLoading() {
// this.setDisabled(false);
if (this.grid) {
this.grid.hideLoading();
this.grid.hideMask();
}
}
setDisabled(disabled) {
const $close = this.element.querySelector(".nu-manager-close");
const $refresh = this.element.querySelector(".nu-manager-refresh");
const $stop = this.element.querySelector(".nu-manager-stop");
const list = [
".nu-manager-header input",
".nu-manager-header select",
".nu-manager-footer button",
".nu-manager-selection button"
].map(s => {
return Array.from(this.element.querySelectorAll(s));
})
.flat()
.filter(it => {
return it !== $close && it !== $refresh && it !== $stop;
});
list.forEach($elem => {
if (disabled) {
$elem.setAttribute("disabled", "disabled");
} else {
$elem.removeAttribute("disabled");
}
});
Array.from(this.element.querySelectorAll(".nu-btn-loading")).forEach($elem => {
$elem.classList.remove("nu-btn-loading");
});
}
showRefresh() {
this.element.querySelector(".nu-manager-refresh").style.display = "block";
}
showStop() {
this.element.querySelector(".nu-manager-stop").style.display = "block";
}
hideStop() {
this.element.querySelector(".nu-manager-stop").style.display = "none";
}
setKeywords(keywords = "") {
this.keywords = keywords;
this.element.querySelector(".nu-manager-keywords").value = keywords;
}
show(sortMode) {
this.element.style.display = "flex";
this.setKeywords("");
this.showSelection("");
this.showMessage("");
this.loadData();
}
close() {
this.element.style.display = "none";
}
}

View File

@ -1,5 +1,75 @@
{
"custom_nodes": [
{
"author": "cosmicbuffalo",
"title": "comfyui-mobile-frontend",
"reference": "https://github.com/cosmicbuffalo/comfyui-mobile-frontend",
"files": [
"https://github.com/cosmicbuffalo/comfyui-mobile-frontend"
],
"install_type": "git-clone",
"description": "An experimental dedicated mobile-first frontend for ComfyUI."
},
{
"author": "tdrminglin",
"title": "Comfyui-hymotionbridge",
"reference": "https://github.com/tdrminglin/Comfyui-hymotionbridge",
"files": [
"https://github.com/tdrminglin/Comfyui-hymotionbridge"
],
"install_type": "git-clone",
"description": "NODES: HYMotionToNLFBridge, HYMotionToSCAILBridge"
},
{
"author": "joe002",
"title": "comfyui-rtx-remix [UNSAFE]",
"reference": "https://github.com/joe002/comfyui-rtx-remix",
"files": [
"https://github.com/joe002/comfyui-rtx-remix"
],
"install_type": "git-clone",
"description": "RTX Remix texture pipeline integration nodes for ComfyUI[w/This nodepack contains a path traversal vulnerability.]"
},
{
"author": "NakanoSanku",
"title": "ComfyUI-Gemini [NAME CONFLICT]",
"reference": "https://github.com/NakanoSanku/ComfyUI-Gemini",
"files": [
"https://github.com/NakanoSanku/ComfyUI-Gemini"
],
"install_type": "git-clone",
"description": "Custom ComfyUI nodes for Google Gemini AI with text generation and image generation capabilities using the Python SDK."
},
{
"author": "Saganaki22",
"title": "ComfyUI-NovaSR",
"reference": "https://github.com/Saganaki22/ComfyUI-NovaSR",
"files": [
"https://github.com/Saganaki22/ComfyUI-NovaSR"
],
"install_type": "git-clone",
"description": "ComfyUI node for NovaSR - Ultra-fast audio super resolution (3600x realtime, 50KB model)"
},
{
"author": "GokuHiki",
"title": "ComfyUI-Goku-Tools",
"reference": "https://github.com/GokuHiki/ComfyUI-Goku-Tools",
"files": [
"https://github.com/GokuHiki/ComfyUI-Goku-Tools"
],
"install_type": "git-clone",
"description": "ComfyUI custom nodes including FirstNonFalse utility. (Description by CC)"
},
{
"author": "endman100",
"title": "ComfyUI_tensor_script [WIP]",
"reference": "https://github.com/endman100/ComfyUI_tensor_script",
"files": [
"https://github.com/endman100/ComfyUI_tensor_script"
],
"install_type": "git-clone",
"description": "Utility nodes for tensor manipulation including squeeze, unsqueeze, and shape operations. (Description by CC)\nNOTE: The files in the repo are not organized."
},
{
"author": "CarlMarkswx",
"title": "ComfyUI-Mirror-Download [UNSAFE]",
@ -10220,16 +10290,6 @@
"install_type": "git-clone",
"description": "Nodes:CLIPTextEncodeAndEnhance.\nNOTE:Translation:This is a wrapper that simply makes it easy to install an existing node via git."
},
{
"author": "umisetokikaze",
"title": "comfyui_mergekit [WIP]",
"reference": "https://github.com/umisetokikaze/comfyui_mergekit",
"files": [
"https://github.com/umisetokikaze/comfyui_mergekit"
],
"install_type": "git-clone",
"description": "Nodes:DefineSaveName, SetModels, get_skip, LoadLR, LoadTarget, SetTokenizer, Merge, SetLayer, SetModels"
},
{
"author": "Video3DGenResearch",
"title": "ComfyUI Batch Input Node",

View File

@ -2127,6 +2127,14 @@
"title_aux": "ComfyUI-GoddessLabs-NodePack"
}
],
"https://github.com/GokuHiki/ComfyUI-Goku-Tools": [
[
"FirstNonFalse"
],
{
"title_aux": "ComfyUI-Goku-Tools"
}
],
"https://github.com/Goldlionren/ComfyUI-CleanSlate": [
[
"CleanSlateCleanup"
@ -4295,6 +4303,14 @@
"title_aux": "ComfyUI Port for Google's Prompt-to-Prompt"
}
],
"https://github.com/Saganaki22/ComfyUI-NovaSR": [
[
"NovaSR"
],
{
"title_aux": "ComfyUI-NovaSR"
}
],
"https://github.com/Saganaki22/ComfyUI-ytdl_nodes": [
[
"YTDLDownloader",
@ -7181,6 +7197,13 @@
"MaskComposite",
"MaskPreview",
"MaskToImage",
"MeshyAnimateModelNode",
"MeshyImageToModelNode",
"MeshyMultiImageToModelNode",
"MeshyRefineNode",
"MeshyRigModelNode",
"MeshyTextToModelNode",
"MeshyTextureNode",
"MinimaxHailuoVideoNode",
"MinimaxImageToVideoNode",
"MinimaxSubjectToVideoNode",
@ -8089,6 +8112,20 @@
"title_aux": "ComfyUI-augmentation"
}
],
"https://github.com/endman100/ComfyUI_tensor_script": [
[
"LatentSqueeze",
"LatentUnsqueeze",
"TensorEmpty",
"TensorGetShape",
"TensorShowShape",
"TensorSqueeze",
"TensorUnsqueeze"
],
{
"title_aux": "ComfyUI_tensor_script [WIP]"
}
],
"https://github.com/enlo/ComfyUI-CheckpointSettings": [
[
"CheckPointSettingsListMerger",
@ -9549,6 +9586,20 @@
"title_aux": "jn_node_suite_comfyui [WIP]"
}
],
"https://github.com/joe002/comfyui-rtx-remix": [
[
"RTXRemixBatchLoader",
"RTXRemixGeneratePBR",
"RTXRemixHashLookup",
"RTXRemixIterateTextures",
"RTXRemixLoadCapture",
"RTXRemixProjectInfo",
"RTXRemixSaveToMod"
],
{
"title_aux": "comfyui-rtx-remix [UNSAFE]"
}
],
"https://github.com/jonathan-bryant/ComfyUI-ImageStraightener": [
[
"AutoStraightenImage"
@ -12524,6 +12575,7 @@
"ImageBlendByMask",
"Image_Color_Noise",
"ModifyMask",
"SU_LoadImagePath",
"SamplingParameters",
"SystemMessagePresets",
"TextEncodeFlux2SystemPrompt",
@ -12680,21 +12732,19 @@
],
"https://github.com/sprited-ai/sprited-comfyui-nodes": [
[
"FlattenImageList",
"LoopExtractorNodeV2",
"LoopMomentumNode",
"LoopTrimNode",
"LoopExtractorNodeV3",
"MakeGrid",
"PixelRGBStats",
"PreviewVideo",
"ShotSplitByCutScore",
"SliceBatch",
"SliceLatents",
"SpriteDXAntiCorruptionV1",
"SpriteDX_ParseInt",
"SpritedMakeGrid",
"URLToVideo",
"VideoDownloader",
"VideoEvenShotSplitter",
"VideoShotSplitter",
"VideoShotSplitterV0",
"VideoShotSplitterV2",
"VideoShotSplitterV3"
"VideoEvenShotSplitter"
],
{
"title_aux": "Sprited ComfyUI Nodes [WIP]"
@ -13093,6 +13143,15 @@
"title_aux": "ComfyUI_SceneSplitter"
}
],
"https://github.com/tdrminglin/Comfyui-hymotionbridge": [
[
"HYMotionToNLFBridge",
"HYMotionToSCAILBridge"
],
{
"title_aux": "Comfyui-hymotionbridge"
}
],
"https://github.com/techidsk/comfyui_molook_nodes": [
[
"ImageOutpaintPadding(Molook)",
@ -13446,27 +13505,6 @@
"title_aux": "ComfyUI_u5_EasyScripter [UNSAFE]"
}
],
"https://github.com/umisetokikaze/comfyui_mergekit": [
[
"DefineSaveName",
"LoadLR",
"LoadTarget",
"Merge",
"SetLayer",
"SetModels",
"SetTokenizer",
"create models list",
"get skip layers",
"get_skip",
"load and save tokenizer",
"loding llm model",
"loding target model",
"str to parsed layers"
],
{
"title_aux": "comfyui_mergekit [WIP]"
}
],
"https://github.com/unanan/ComfyUI-Dist": [
[
"LoadImageFromLAN",
@ -14099,6 +14137,7 @@
"MultiplyNode",
"NumberNode",
"OutpaintingPadNode",
"PerfectPixelNode",
"PrependTagsNode",
"PrintAnyNode",
"PrintImageNode",

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,25 @@
{
"custom_nodes": [
{
"author": "Wladimir Palant",
"title": "image-resize-comfyui [REMOVED]",
"reference": "https://github.com/ussoewwin/image_resize_comfyui",
"files": [
"https://github.com/ussoewwin/image_resize_comfyui"
],
"install_type": "git-clone",
"description": "Advanced image resizing node for ComfyUI with aspect ratio preservation and mask support"
},
{
"author": "umisetokikaze",
"title": "comfyui_mergekit [REMOVED]",
"reference": "https://github.com/umisetokikaze/comfyui_mergekit",
"files": [
"https://github.com/umisetokikaze/comfyui_mergekit"
],
"install_type": "git-clone",
"description": "Nodes:DefineSaveName, SetModels, get_skip, LoadLR, LoadTarget, SetTokenizer, Merge, SetLayer, SetModels"
},
{
"author": "LSDJesus",
"title": "ComfyUI-Luna-Collection [REMOVED]",

View File

@ -1,5 +1,240 @@
{
"custom_nodes": [
{
"author": "loz2754",
"title": "AUN ComfyUI Nodes",
"id": "aun-comfyui-nodes",
"reference": "https://github.com/loz2754/AUN-ComfyUI-Nodes",
"files": [
"https://github.com/loz2754/AUN-ComfyUI-Nodes"
],
"install_type": "git-clone",
"description": "A collection of workflow helper nodes focused on organization + control (bypass/mute/collapse/group control), prompt/text utilities, file/path helpers, and image/video save helpers (optional VHS integration)."
},
{
"author": "SergPoletaev",
"title": "ComfyUI-SPoletNodes",
"id": "ComfyUI-SPoletNodes",
"reference": "https://github.com/SergPoletaev/ComfyUI-SPoletNodes",
"files": [
"https://github.com/SergPoletaev/ComfyUI-SPoletNodes"
],
"install_type": "git-clone",
"description": "Custom nodes for image preview and saving"
},
{
"author": "capitan01R",
"title": "ComfyUI-CapitanZiT-Scheduler",
"reference": "https://github.com/capitan01R/ComfyUI-CapitanZiT-Scheduler",
"files": [
"https://github.com/capitan01R/ComfyUI-CapitanZiT-Scheduler"
],
"install_type": "git-clone",
"description": "A lightweight ComfyUI custom scheduler & sigma generator for Z-Image-Turbo. Delivers a stable linear sigma schedule (1.0 → 0.0) for rectified-flow/flow-matching, boosting few-step generation (8-9 steps) with superior consistency, reduced noise, and full compatibility with the model's distilled pipeline."
},
{
"author": "joe002",
"title": "comfyui-deterministic-nodes",
"reference": "https://github.com/joe002/comfyui-deterministic-nodes",
"files": [
"https://github.com/joe002/comfyui-deterministic-nodes"
],
"install_type": "git-clone",
"description": "Batch-invariant inference nodes for guaranteed reproducibility in ComfyUI"
},
{
"author": "joe002",
"title": "comfyui-conduit-optimizer",
"reference": "https://github.com/joe002/comfyui-conduit-optimizer",
"files": [
"https://github.com/joe002/comfyui-conduit-optimizer"
],
"install_type": "git-clone",
"description": "Non-linear inference optimization for ComfyUI: 4-tier VRAM, speculative generation, precision routing"
},
{
"author": "joe002",
"title": "comfyui-rtx4090-nodes",
"reference": "https://github.com/joe002/comfyui-rtx4090-nodes",
"files": [
"https://github.com/joe002/comfyui-rtx4090-nodes"
],
"install_type": "git-clone",
"description": "High-performance ComfyUI nodes optimized for RTX 4090: batch processing, memory management, GPU monitoring"
},
{
"author": "tackcrypto1031",
"title": "tk_comfyui_view_and_light",
"reference": "https://github.com/tackcrypto1031/tk_comfyui_view_and_light",
"files": [
"https://github.com/tackcrypto1031/tk_comfyui_view_and_light"
],
"install_type": "git-clone",
"description": "TK View and Light: A ComfyUI node for 3D camera and lighting control"
},
{
"author": "XelaNull",
"title": "ComfyUI-MobileFriendly",
"reference": "https://github.com/XelaNull/ComfyUI-MobileFriendly",
"files": [
"https://github.com/XelaNull/ComfyUI-MobileFriendly"
],
"install_type": "git-clone",
"description": "Comprehensive mobile UI enhancement for ComfyUI that transforms the desktop-focused interface into a touch-friendly experience optimized for iPhone, iPad, and Android devices."
},
{
"author": "aadityamundhalia",
"title": "ComfyUI-ollama-aditya",
"reference": "https://github.com/aadityamundhalia/ComfyUI-ollama-aditya",
"files": [
"https://github.com/aadityamundhalia/ComfyUI-ollama-aditya"
],
"install_type": "git-clone",
"description": "Custom ComfyUI node for integrating Ollama LLMs into your image generation workflows."
},
{
"author": "maximilianwicen",
"title": "ComfyUI-MaxTools",
"reference": "https://github.com/maximilianwicen/ComfyUI-MaxTools",
"files": [
"https://github.com/maximilianwicen/ComfyUI-MaxTools"
],
"install_type": "git-clone",
"description": "A small collection of custom nodes for ComfyUI, featuring Max Quick Image Size node for image-to-image or image-to-video workflows. (Description by CC)"
},
{
"author": "bhhtr12",
"title": "ComfyUI-ollama-stop",
"reference": "https://github.com/bhhtr12/ComfyUI-ollama-stop",
"files": [
"https://github.com/bhhtr12/ComfyUI-ollama-stop"
],
"install_type": "git-clone",
"description": "Passthrough node that instantly unloads any running ollama model mid workflow. No API calls, just accepts plain string as a model name and executes 'ollama stop <model>' command in your system."
},
{
"author": "DemonAlone",
"title": "SimpeStringGenerator_ComfyUI",
"reference": "https://github.com/DemonAlone/SimpeStringGenerator_ComfyUI",
"files": [
"https://github.com/DemonAlone/SimpeStringGenerator_ComfyUI"
],
"install_type": "git-clone",
"description": "A collection of nodes that provide dynamic dropdown selectors for Samplers, Schedulers, Checkpoints, and Diffusion Models, outputting a comma-separated string for use in XY plots."
},
{
"author": "tabisheva",
"title": "comfyui-segs-profile",
"reference": "https://github.com/tabisheva/comfyui-segs-profile",
"files": [
"https://github.com/tabisheva/comfyui-segs-profile"
],
"install_type": "git-clone",
"description": "A tiny ComfyUI custom node that detects whether a face is in profile using SEGS eye detections."
},
{
"author": "QuackPhuc",
"title": "ComfyUI-FisheyeTransform",
"reference": "https://github.com/QuackPhuc/ComfyUI-FisheyeTransform",
"files": [
"https://github.com/QuackPhuc/ComfyUI-FisheyeTransform"
],
"install_type": "git-clone",
"description": "Custom nodes for handling fisheye camera distortion in ComfyUI inpainting workflows."
},
{
"author": "1x1r",
"title": "comfyui-upscale-by-model",
"reference": "https://github.com/1x1r/comfyui-upscale-by-model",
"files": [
"https://github.com/1x1r/comfyui-upscale-by-model"
],
"install_type": "git-clone",
"description": "This custom node allow upscaling an image by a factor using a model."
},
{
"author": "RCAKangle",
"title": "ComfyUI_LLM_Embeder",
"reference": "https://github.com/RCAKangle/ComfyUI_LLM_Embeder",
"files": [
"https://github.com/RCAKangle/ComfyUI_LLM_Embeder"
],
"install_type": "git-clone",
"description": "Local LLM chat nodes for ComfyUI, with a clean handoff path to downstream prompt optimization."
},
{
"author": "esp-dev",
"title": "comfyui-loadheicimage",
"reference": "https://github.com/esp-dev/comfyui-loadheicimage",
"files": [
"https://github.com/esp-dev/comfyui-loadheicimage"
],
"install_type": "git-clone",
"description": "ComfyUI custom node that loads images (including HEIC/HEIF) and provides browser-friendly previews."
},
{
"author": "olduvai-jp",
"title": "ComfyUI-S3-IO",
"reference": "https://github.com/olduvai-jp/ComfyUI-S3-IO",
"files": [
"https://github.com/olduvai-jp/ComfyUI-S3-IO"
],
"install_type": "git-clone",
"description": "S3-backed input/output nodes for ComfyUI to browse, load images/videos from S3 buckets and push outputs back to S3 automatically."
},
{
"author": "theluminhub",
"title": "ComfyUI-Lumin-Upload",
"reference": "https://github.com/theluminhub/ComfyUI-Lumin-Upload",
"files": [
"https://github.com/theluminhub/ComfyUI-Lumin-Upload"
],
"install_type": "git-clone",
"description": "Upload your ComfyUI generated images and workflow metadata to Lumin."
},
{
"author": "SorenWeile",
"title": "ComfyUI_MetaSaver",
"reference": "https://github.com/SorenWeile/ComfyUI_MetaSaver",
"files": [
"https://github.com/SorenWeile/ComfyUI_MetaSaver"
],
"install_type": "git-clone",
"description": "A powerful ComfyUI custom node for saving images with flexible custom metadata fields embedded in PNG files."
},
{
"author": "TTPlanetPig",
"title": "Comfyui_DreamID-V_wrapper",
"reference": "https://github.com/TTPlanetPig/Comfyui_DreamID-V_wrapper",
"files": [
"https://github.com/TTPlanetPig/Comfyui_DreamID-V_wrapper"
],
"install_type": "git-clone",
"description": "A simple and efficient ComfyUI integration for DreamID-V, a model for identity-preserving video generation that animates reference images using motion from pose videos."
},
{
"author": "danieljanata",
"title": "ComfyUI-Prompting-System",
"reference": "https://github.com/danieljanata/ComfyUI-Prompting-System",
"files": [
"https://github.com/danieljanata/ComfyUI-Prompting-System"
],
"install_type": "git-clone",
"description": "Comprehensive prompt management system for ComfyUI with database storage, thumbnail management, advanced search, and cross-platform support."
},
{
"author": "PauldeLavallaz",
"title": "[WIP] comfyui_morpheus_model_management",
"reference": "https://github.com/PauldeLavallaz/comfyui_morpheus_model_management",
"files": [
"https://github.com/PauldeLavallaz/comfyui_morpheus_model_management"
],
"install_type": "git-clone",
"description": "Nodo personalizzato per ComfyUI che consente di sfogliare una libreria locale di immagini di talent con interfaccia gallery, filtri avanzati e output multipli. (Description by CC)\nNOTE: The files in the repo are not organized."
},
{
"author": "sinanzoo2nd",
"title": "ComfyUI Seed Wildcard Pack",
@ -31,6 +266,56 @@
"install_type": "git-clone",
"description": "Provide a simple interface to simplify prompt writing."
},
{
"author": "Suzu008",
"title": "ComfyUI-CryptIO",
"reference": "https://github.com/Suzu008/ComfyUI-CryptIO",
"files": [
"https://github.com/Suzu008/ComfyUI-CryptIO"
],
"install_type": "git-clone",
"description": "A collection of custom nodes for ComfyUI"
},
{
"author": "IRCSS",
"title": "comfyUI-blender-wrapper",
"reference": "https://github.com/IRCSS/comfyUI-blender-wrapper",
"files": [
"https://github.com/IRCSS/comfyUI-blender-wrapper"
],
"install_type": "git-clone",
"description": "ComfyUI Blender Wrapper lets you call Blender in headless mode from ComfyUI (or any Python environment), run reusable pipeline stages stored inside files, and pass configs in/out via JSON. It's meant for tech-art / asset-pipeline tasks like cleanup, decimation, unwrap, baking, rigging, etc."
},
{
"author": "calibancode",
"title": "ComfyUI-bevvy",
"reference": "https://github.com/calibancode/ComfyUI-bevvy",
"files": [
"https://github.com/calibancode/ComfyUI-bevvy"
],
"install_type": "git-clone",
"description": "ComfyUI custom node that saves images as WebP."
},
{
"author": "GraftingRayman",
"title": "ComfyUI-Games",
"reference": "https://github.com/GraftingRayman/ComfyUI-Games",
"files": [
"https://github.com/GraftingRayman/ComfyUI-Games"
],
"install_type": "git-clone",
"description": "ComfyUI node providing Tetris game functionality. (Description by CC)"
},
{
"author": "aicuai",
"title": "comfyui-save-image-watermark",
"reference": "https://github.com/aicuai/comfyui-save-image-watermark",
"files": [
"https://github.com/aicuai/comfyui-save-image-watermark"
],
"install_type": "git-clone",
"description": "Save images with visible watermarks (logo/text), invisible watermarks (LSB steganography), and metadata embedding. Supports PNG/JPEG/WebP with browser download."
},
{
"author": "migero",
"title": "ComfyUI-Equirectangular-Strip",
@ -428,334 +713,6 @@
],
"install_type": "git-clone",
"description": "Simple node to patch ComfyUI generation with the SDXL Flux2VAE arch support."
},
{
"author": "KrakenUnbound",
"title": "Kraken Tools",
"id": "kraken-tools",
"reference": "https://github.com/krakenunbound/comfyui-kraken-tools",
"files": [
"https://github.com/krakenunbound/comfyui-kraken-tools"
],
"install_type": "git-clone",
"description": "15 productivity nodes: Kraken Unbound Prompt (vision-enabled prompt builder with Qwen2-VL), WAN Prompt Splitter (cinematic styling), Ollama Prompt Chat (LLM enhancement), LoRA Loader with CivitAI trigger fetching, Dual CLIP Loader (Flux/SD3/SDXL), smart KSampler (AMP handling for WAN/Flow/FP8), Empty Latent with aspect presets, Upscale & Tile Calculator for Ultimate SD Upscale, Resolution Helper, Image Processor, WAN Helper, and more."
},
{
"author": "18yz153",
"title": "ComfyUI-Persona-Director",
"reference": "https://github.com/c/ComfyUI-Persona-Director",
"files": [
"https://github.com/18yz153/ComfyUI-Persona-Director"
],
"install_type": "git-clone",
"description": "A visual state machine for consistent character generation. It intelligently maintains character identity, outfits, and locations across multiple generations using LLM-driven state management."
},
{
"author": "bulldog68",
"title": "ComfyUI_FMJ_SaveImageVersions",
"description": "Image saving with complete metadata (prompts, seed, software versions) + smart loading.",
"reference": "https://github.com/bulldog68/ComfyUI_FMJ_SaveImageVersions",
"files": [
"https://github.com/bulldog68/ComfyUI_FMJ_SaveImageVersions"
],
"install_type": "git-clone",
"tags": ["save image", "metadonne"],
"license": "GNU V3"
},
{
"author": "GonDesign",
"title": "ComfyUI-HaoranWanxImageEdit",
"reference": "https://github.com/GonDesign/ComfyUI-HaoranWanxImageEdit",
"files": [
"https://github.com/GonDesign/ComfyUI-HaoranWanxImageEdit"
],
"install_type": "git-clone",
"description": "API plugin for Alibaba Cloud Wanx 2.1 Image Editing model. Supports 10 functions including stylization, inpainting, and outpainting."
},
{
"author": "BWDrum",
"title": "ComfyUI Random Wildcard Loader",
"id": "random-wildcard-loader",
"reference": "https://github.com/BWDrum/ComfyUI-RandomWildcardLoader",
"files": [
"https://github.com/BWDrum/ComfyUI-RandomWildcardLoader"
],
"install_type": "git-clone",
"description": "A custom node for randomized prompt generation with __wildcard__ expansion, subfolder filtering, prefix/suffix support, and seed-based reproducibility."
},
{
"author": "solidlime",
"title": "Random Image Picker",
"reference": "https://github.com/solidlime/Comfyui-Random_Image_Picker",
"files": [
"https://github.com/solidlime/Comfyui-Random_Image_Picker"
],
"install_type": "git-clone",
"description": "ComfyUI custom node for flexible image loading with file picker and random folder selection. Features instant preview, auto mode switching, and browser-based file selection.",
"nodename_pattern": "RandomImagePicker"
},
{
"author": "mengqin",
"title": "Twinflow Node for ComfyUI",
"reference": "https://github.com/mengqin/ComfyUI-TwinFlow",
"files": [
"https://github.com/mengqin/ComfyUI-TwinFlow"
],
"install_type": "git-clone",
"description": "This is a set of sampling nodes specifically designed for fine-tuning Twinflow models."
},
{
"author": "shmbatom",
"title": "Comfyui-ImageAB-Compare",
"id": "Comfyui-ImageAB-Compare",
"reference": "https://github.com/shmbatom/Comfyui-ImageAB-Compare",
"files": [
"https://github.com/shmbatom/Comfyui-ImageAB-Compare"
],
"install_type": "git-clone",
"description": "image split comparison horizontally/vertically, real-time mouse interaction to adjust split ratios, bidirectional linkage between slider and mouse, and the ability to export comparison images with precise split lines."
},
{
"author": "DanrisiUA",
"title": "ComfyUI-ZImage-LoRA-Merger",
"reference": "https://github.com/DanrisiUA/ComfyUI-ZImage-LoRA-Merger",
"files": [
"https://github.com/DanrisiUA/ComfyUI-ZImage-LoRA-Merger"
],
"install_type": "git-clone",
"description": "Custom nodes for combining multiple LoRAs without overexposure on distilled models like Z-Image Turbo"
},
{
"author": "pixixai",
"title": "ComfyUI-AlignLayout",
"reference": "https://github.com/pixixai/ComfyUI-AlignLayout",
"files": [
"https://github.com/pixixai/ComfyUI-AlignLayout"
],
"install_type": "git-clone",
"description": "Productivity enhancement extension for ComfyUI featuring radial menus and mouse flick gestures for efficient node alignment, distribution, and resizing. (Description by CC)"
},
{
"author": "MechaBabyAi",
"title": "ComfyUI-MechaBabyNodeSearch",
"reference": "https://github.com/MechaBabyAi/ComfyUI-MechaBabyNodeSearch",
"files": [
"https://github.com/MechaBabyAi/ComfyUI-MechaBabyNodeSearch"
],
"install_type": "git-clone",
"description": "Enhance ComfyUI workflow by providing powerful node search, attribute search, and port navigation features with Ctrl+F shortcut support."
},
{
"author": "yangrui511",
"title": "ComfyUI-Text-Preserve",
"reference": "https://github.com/yangrui511/ComfyUI-Text-Preserve",
"files": [
"https://github.com/yangrui511/ComfyUI-Text-Preserve"
],
"install_type": "git-clone",
"description": "Custom node providing text preservation preprocessing for ComfyUI using OCR to identify text regions and apply blur/noise fusion to non-text areas. (Description by CC)"
},
{
"author": "Atsushi888",
"title": "easy_prompt_selector_for_comfyui",
"reference": "https://github.com/Atsushi888/easy_prompt_selector_for_comfyui",
"files": [
"https://github.com/Atsushi888/easy_prompt_selector_for_comfyui"
],
"install_type": "git-clone",
"description": "A simple custom node for ComfyUI that loads and provides an all-in-one dropdown selector to build a prompt string."
},
{
"author": "princepainter",
"title": "ComfyUI-PainterLTXV2",
"reference": "https://github.com/princepainter/ComfyUI-PainterLTXV2",
"files": [
"https://github.com/princepainter/ComfyUI-PainterLTXV2"
],
"install_type": "git-clone",
"description": "ComfyUI custom nodes providing LTXV audio-video separation sampling and latent preparation capabilities for professional video generation workflows."
},
{
"author": "logicalor",
"title": "comfyui_path_sanitizer",
"reference": "https://github.com/logicalor/comfyui_path_sanitizer",
"files": [
"https://github.com/logicalor/comfyui_path_sanitizer"
],
"install_type": "git-clone",
"description": "A ComfyUI custom node that sanitizes strings for use as filesystem paths"
},
{
"author": "rzgarespo",
"title": "ComfyUI-diffusiondb",
"reference": "https://github.com/rzgarespo/ComfyUI-diffusiondb",
"files": [
"https://github.com/rzgarespo/ComfyUI-diffusiondb"
],
"install_type": "git-clone",
"description": "This code gives you the quick access to 14 million text-to-image prompts from the DiffusionDB dataset."
},
{
"author": "bryanmcguire",
"title": "comfyui-flux2fun-controlnet",
"reference": "https://github.com/bryanmcguire/comfyui-flux2fun-controlnet",
"files": [
"https://github.com/bryanmcguire/comfyui-flux2fun-controlnet"
],
"install_type": "git-clone",
"description": "ComfyUI implementation of FLUX.2-dev-Fun-Controlnet-Union from Alibaba's VideoX-Fun"
},
{
"author": "CypherNaught-0x",
"title": "ComfyUI_resolution_presets",
"reference": "https://github.com/CypherNaught-0x/ComfyUI_resolution_presets",
"files": [
"https://github.com/CypherNaught-0x/ComfyUI_resolution_presets"
],
"install_type": "git-clone",
"description": "A ComfyUI extension providing optimized resolution presets for multiple AI image generation models with support for various aspect ratios and two node variants."
},
{
"author": "vjumpkung",
"title": "ComfyUI-Musubi-Tuner-LoRA-Loader",
"reference": "https://github.com/vjumpkung/ComfyUI-Musubi-Tuner-LoRA-Loader",
"files": [
"https://github.com/vjumpkung/ComfyUI-Musubi-Tuner-LoRA-Loader"
],
"install_type": "git-clone",
"description": "A ComfyUI custom node that enables direct loading of musubi-tuner based LoRAs (Z-Image Turbo, Hunyuan Video 1.5) with automatic in-memory conversion and caching."
},
{
"author": "SnJake",
"title": "SnJake_Baikal_Swin_Anime",
"reference": "https://github.com/SnJake/SnJake_Baikal_Swin_Anime",
"files": [
"https://github.com/SnJake/SnJake_Baikal_Swin_Anime"
],
"install_type": "git-clone",
"description": "SnJake Baikal-Swin-Anime x2 is a custom ComfyUI node for upscaling anime/illustration images with a dedicated restoration model."
},
{
"author": "kishida",
"title": "comfyui-text-renderer",
"reference": "https://github.com/kishida/comfyui-text-renderer",
"files": [
"https://github.com/kishida/comfyui-text-renderer"
],
"install_type": "git-clone",
"description": "Text render node for ComfyUI"
},
{
"author": "aliabougazia",
"title": "comfyui_pt_security_scanner",
"reference": "https://github.com/aliabougazia/comfyui_pt_security_scanner",
"files": [
"https://github.com/aliabougazia/comfyui_pt_security_scanner"
],
"install_type": "git-clone",
"description": "A ComfyUI custom node that scans PyTorch model files for potential security vulnerabilities without executing them."
},
{
"author": "PBandDev",
"title": "comfyui-node-organizer",
"reference": "https://github.com/PBandDev/comfyui-node-organizer",
"files": [
"https://github.com/PBandDev/comfyui-node-organizer"
],
"install_type": "git-clone",
"description": "ComfyUI extension to organize nodes"
},
{
"author": "SanDiegoDude",
"title": "ComfyUI-Soprano-TTS",
"reference": "https://github.com/SanDiegoDude/ComfyUI-Soprano-TTS",
"files": [
"https://github.com/SanDiegoDude/ComfyUI-Soprano-TTS"
],
"install_type": "git-clone",
"description": "Ultra-lightweight, high-fidelity text-to-speech for ComfyUI using Soprano TTS."
},
{
"author": "PixWizardry",
"title": "ComfyUI_PixQwenImageEditEnhanced",
"reference": "https://github.com/PixWizardry/ComfyUI_PixQwenImageEditEnhanced",
"files": [
"https://github.com/PixWizardry/ComfyUI_PixQwenImageEditEnhanced"
],
"install_type": "git-clone",
"description": "An enhanced Vision-Language Model (VLM) conditioning node for ComfyUI designed for the Qwen-Image series, supporting up to 5 reference images with customizable system prompts and token tracking."
},
{
"author": "RyukoMatoiFan",
"title": "ComfyUI-STARFlow",
"reference": "https://github.com/RyukoMatoiFan/ComfyUI-STARFlow",
"files": [
"https://github.com/RyukoMatoiFan/ComfyUI-STARFlow"
],
"install_type": "git-clone",
"description": "Custom nodes for STARFlow text-to-image generation in ComfyUI, including checkpoint loader, text encoder, sampler, and VAE decoder."
},
{
"author": "danielwolber-wood",
"title": "ComfyUI-FString",
"reference": "https://github.com/danielwolber-wood/ComfyUI-FString",
"files": [
"https://github.com/danielwolber-wood/ComfyUI-FString"
],
"install_type": "git-clone",
"description": "A custom node for ComfyUI that allows you to format strings using Python's string formatting syntax."
},
{
"author": "danielwolber-wood",
"title": "ComfyUI-Inspector",
"reference": "https://github.com/danielwolber-wood/ComfyUI-Inspector",
"files": [
"https://github.com/danielwolber-wood/ComfyUI-Inspector"
],
"install_type": "git-clone",
"description": "A custom node for ComfyUI that allows you to inspect any input data with detailed metadata and visual preview."
},
{
"author": "EricRorich",
"title": "ComfyUI-face-shaper",
"reference": "https://github.com/EricRorich/ComfyUI-face-shaper",
"files": [
"https://github.com/EricRorich/ComfyUI-face-shaper"
],
"install_type": "git-clone",
"description": "A custom ComfyUI node that draws parametric facial masks with black lines on white or transparent backgrounds. (Description by CC)"
},
{
"author": "danielwolber-wood",
"title": "ComfyUI-QuickResolutionSelector",
"reference": "https://github.com/danielwolber-wood/ComfyUI-QuickResolutionSelector",
"files": [
"https://github.com/danielwolber-wood/ComfyUI-QuickResolutionSelector"
],
"install_type": "git-clone",
"description": "A simple custom node for ComfyUI that allows you to quickly select resolution presets from a dropdown menu."
},
{
"author": "fmartinellidev",
"title": "ComfyUI-Prompt_util_pack",
"reference": "https://github.com/fmartinellidev/ComfyUI-Prompt_util_pack",
"files": [
"https://github.com/fmartinellidev/ComfyUI-Prompt_util_pack"
],
"install_type": "git-clone",
"description": "A modular toolkit for advanced prompt engineering in ComfyUI designed for dataset creation, LoRA training, and controlled variation."
},
{
"author": "Niutonian",
"title": "comfyui_Niutonian_GLM_4_6V",
"reference": "https://github.com/Niutonian/comfyui_Niutonian_GLM_4_6V",
"files": [
"https://github.com/Niutonian/comfyui_Niutonian_GLM_4_6V"
],
"install_type": "git-clone",
"description": "This is the transformer-based implementation of Niutonian GLM-4.6V nodes for ComfyUI with memory optimizations."
}
]
}

View File

@ -20,7 +20,7 @@
],
"https://github.com/0nikod/ComfyUI-Simple-Prompt": [
[
"vue-basic"
"SimplePrompt"
],
{
"title_aux": "ComfyUI-Simple-Prompt"
@ -507,6 +507,14 @@
"title_aux": "Comfyui-Gelbooru"
}
],
"https://github.com/1x1r/comfyui-upscale-by-model": [
[
"UpscaleImageByUsingModel"
],
{
"title_aux": "comfyui-upscale-by-model"
}
],
"https://github.com/1zhangyy1/comfyui-vidu-nodes": [
[
"Character2Video",
@ -587,8 +595,8 @@
],
"https://github.com/3R3BOS/ComfyUI-3R3BOS-Pack": [
[
"Image Comparer (3R3BOS)",
"Visual Gatekeeper (3R3BOS)"
"Batch Selector (3R3BOS)",
"Image Comparer (3R3BOS)"
],
{
"title_aux": "ComfyUI-3R3BOS-Pack"
@ -2730,7 +2738,8 @@
],
"https://github.com/Anzhc/SDXL-Flux2VAE-ComfyUI-Node": [
[
"EmptySDXLFlux2LatentImage"
"EmptySDXLFlux2LatentImage",
"TargetTimeConditioning"
],
{
"title_aux": "SDXL-Flux2VAE-ComfyUI-Node"
@ -5963,6 +5972,17 @@
"title_aux": "RangeToString"
}
],
"https://github.com/DemonAlone/SimpeStringGenerator_ComfyUI": [
[
"DiffusionModelGeneratorNode",
"ModelGeneratorNode",
"SamplerGeneratorNode",
"SchedulerGeneratorNode"
],
{
"title_aux": "SimpeStringGenerator_ComfyUI"
}
],
"https://github.com/DemonNCoding/PromptGenerator12Columns": [
[
"PromptGenerator12Columns_Empty",
@ -8718,6 +8738,14 @@
"title_aux": "ComfyUI Visual Dimension Selector"
}
],
"https://github.com/GraftingRayman/ComfyUI-Games": [
[
"TetrisNode"
],
{
"title_aux": "ComfyUI-Games"
}
],
"https://github.com/GraftingRayman/ComfyUI-PuLID-Flux-GR": [
[
"GRApplyPulidFlux",
@ -8774,7 +8802,7 @@
"GR Text Overlay",
"GR Tile and Border Image",
"GR Tile and Border Image Random Flip",
"GRBatchLoader",
"GRAudioSelector",
"GRImageSelector",
"GRLoraLoader",
"GRMenuHook",
@ -10021,6 +10049,49 @@
"title_aux": "Notification Bridge"
}
],
"https://github.com/IRCSS/comfyUI-blender-wrapper": [
[
"BlenderGenericNode",
"CV2InpaintTexture",
"DownloadAndLoadHy3DDelightModel",
"DownloadAndLoadHy3DPaintModel",
"Hy3DApplyTexture",
"Hy3DBPT",
"Hy3DBakeFromMultiview",
"Hy3DCameraConfig",
"Hy3DDelightImage",
"Hy3DDiffusersSchedulerConfig",
"Hy3DExportMesh",
"Hy3DFastSimplifyMesh",
"Hy3DGenerateMesh",
"Hy3DGenerateMeshMultiView",
"Hy3DGetMeshPBRTextures",
"Hy3DIMRemesh",
"Hy3DLoadMesh",
"Hy3DMeshInfo",
"Hy3DMeshUVWrap",
"Hy3DMeshVerticeInpaintTexture",
"Hy3DModelLoader",
"Hy3DNvdiffrastRenderer",
"Hy3DPostprocessMesh",
"Hy3DRenderMultiView",
"Hy3DRenderMultiViewDepth",
"Hy3DRenderSingleView",
"Hy3DSampleMultiView",
"Hy3DSetMeshPBRAttributes",
"Hy3DSetMeshPBRTextures",
"Hy3DTorchCompileSettings",
"Hy3DUploadMesh",
"Hy3DVAEDecode",
"Hy3DVAELoader",
"Hy3D_2_1SimpleMeshGen",
"MESHToTrimesh",
"TrimeshToMESH"
],
{
"title_aux": "comfyUI-blender-wrapper"
}
],
"https://github.com/ITurchenko/ComfyUI-SizeFromArray": [
[
"SizeFromArray"
@ -13032,6 +13103,20 @@
"title_aux": "comfyui-vram-overlay"
}
],
"https://github.com/MajoorWaldi/ComfyUI-Majoor-ImageOps": [
[
"ImageOpsBlur",
"ImageOpsClamp",
"ImageOpsColorAjust",
"ImageOpsInvert",
"ImageOpsMerge",
"ImageOpsPreview",
"ImageOpsTransform"
],
{
"title_aux": "ComfyUI-Majoor-ImageOps"
}
],
"https://github.com/Makeezi/ComfyUI-promptLAB": [
[
"PromptLAB"
@ -13736,11 +13821,13 @@
"Remove Background",
"ReplaceAlpha",
"Resize Image and Mask by Side",
"SEGS Normalize for Video",
"Save Folder as ZIP",
"Save To Zip",
"SaveFolderAsZip",
"Spritesheet Builder",
"Spritesheet Preview",
"Stabilizer Trim",
"VideoMaskEditor",
"WAN Frame Calculator"
],
@ -15128,6 +15215,14 @@
"title_aux": "Claude Prompt Generator"
}
],
"https://github.com/PauldeLavallaz/comfyui_morpheus_model_management": [
[
"MorpheusModelManagement"
],
{
"title_aux": "[WIP] comfyui_morpheus_model_management"
}
],
"https://github.com/PenguinTeo/Comfyui-GeminiBanana": [
[
"Gemini3ImageNode"
@ -15863,6 +15958,16 @@
"title_aux": "ComfyUI-RED-UNO"
}
],
"https://github.com/QuackPhuc/ComfyUI-FisheyeTransform": [
[
"FisheyeRedistort",
"FisheyeStrengthEstimate",
"FisheyeUndistort"
],
{
"title_aux": "ComfyUI-FisheyeTransform"
}
],
"https://github.com/QuietNoise/comfyui_queue_manager": [
[
"Workflow Name"
@ -15879,6 +15984,16 @@
"title_aux": "Universal LLM Node for ComfyUI"
}
],
"https://github.com/RCAKangle/ComfyUI_LLM_Embeder": [
[
"ChatHistoryViewer",
"ChatNode",
"LLMConfigNode"
],
{
"title_aux": "ComfyUI_LLM_Embeder"
}
],
"https://github.com/RUiNtheExtinct/comfyui-save-file-extended": [
[
"LoadAudioExtended",
@ -17291,6 +17406,19 @@
"title_aux": "HF-Flux-ComfyUI"
}
],
"https://github.com/SergPoletaev/ComfyUI-SPoletNodes": [
[
"EnhancedVideoPreview",
"GetImageSizeWithPreview",
"Save Images & Preview",
"UltimateMemoryCleaner",
"Video Concat (FFmpeg)",
"VideoBatchCrossfade"
],
{
"title_aux": "ComfyUI-SPoletNodes"
}
],
"https://github.com/ServiceStack/comfy-asset-downloader": [
[
"AssetDownloader"
@ -18171,6 +18299,15 @@
"title_aux": "MBM's Music Visualizer"
}
],
"https://github.com/SorenWeile/ComfyUI_MetaSaver": [
[
"MetaSaver",
"MetaSaverDynamic"
],
{
"title_aux": "ComfyUI_MetaSaver"
}
],
"https://github.com/SozeInc/ComfyUI-Mobile": [
[
"Send Notification (Mobile)",
@ -18712,6 +18849,7 @@
"Basic data handling: TimeExtract",
"Basic data handling: TimeFormat",
"Basic data handling: TimeNow",
"Basic data handling: TimeNowUTC",
"Basic data handling: TimeParse",
"Basic data handling: TimeSubtractDelta",
"Basic data handling: TimeToUnix",
@ -19233,6 +19371,21 @@
"title_aux": "Comfyroll Studio"
}
],
"https://github.com/Suzu008/ComfyUI-CryptIO": [
[
"PreviewImageCryptIO",
"PreviewVideoCryptIO",
"SaveImageCryptIO",
"SaveVideoCryptIO",
"TextDecrypt",
"TextEncrypt",
"UploadImageCryptIO",
"UploadVideoCryptIO"
],
{
"title_aux": "ComfyUI-CryptIO"
}
],
"https://github.com/SuzumiyaAkizuki/ComfyUI-LLM_Prompt_XML_Formatter": [
[
"LLM_Prompt_Formatter",
@ -19521,6 +19674,17 @@
"title_aux": "tri3d-comfyui-nodes"
}
],
"https://github.com/TTPlanetPig/Comfyui_DreamID-V_wrapper": [
[
"DreamIDV_ConditioningPrep_TTP",
"DreamIDV_ModelLoader_Wrapper_TTP",
"DreamIDV_PoseExtractor_TTP",
"DreamIDV_Sampler_Wrapper_TTP"
],
{
"title_aux": "Comfyui_DreamID-V_wrapper"
}
],
"https://github.com/TTPlanetPig/Comfyui_Hunyuan3D": [
[
"GifImageViewerNode",
@ -20083,6 +20247,8 @@
[
"CharacterLoraSelect",
"ChromaActionSelect",
"EasyArrayFilter",
"EasyBasicJsonExtractor",
"EasyCLIPLoader",
"EasyCheckpointLoader",
"EasyFileName",
@ -20100,6 +20266,8 @@
"LoadImagesFromDirectoryPath",
"LoadRandomImageFromFolderPath",
"QwenActionSelect",
"TileAssembly",
"TileBreak",
"UserSelect",
"WanActionSelect"
],
@ -22485,6 +22653,14 @@
"title_aux": "ComfyUI_Detonate"
}
],
"https://github.com/aadityamundhalia/ComfyUI-ollama-aditya": [
[
"OllamaPromptGenerator"
],
{
"title_aux": "ComfyUI-ollama-aditya"
}
],
"https://github.com/abdozmantar/ComfyUI-DeepExtract": [
[
"VocalAndSoundRemoverNode"
@ -22948,6 +23124,16 @@
"title_aux": "aicu-comfyui-stability-ai-api"
}
],
"https://github.com/aicuai/comfyui-save-image-watermark": [
[
"ExtractInvisibleWatermark",
"Local Save",
"LocalSaveImageWithWatermark"
],
{
"title_aux": "comfyui-save-image-watermark"
}
],
"https://github.com/aidec/Comfyui_TextBatch_aidec": [
[
"DataTempManager",
@ -23232,7 +23418,6 @@
"GetImagesFromBatchIndexed",
"GetLatentRangeFromBatch",
"GetLatentSizeAndCount",
"Image Comparer (rgthree)",
"ImageAddMulti",
"ImageAndMaskPreview",
"ImageBatchExtendWithOverlap",
@ -23257,6 +23442,7 @@
"ImagePadKJ",
"ImagePass",
"ImagePrepForICLora",
"ImageResizeByMegapixels",
"ImageResizeKJ",
"ImageResizeKJv2",
"ImageTensorList",
@ -23275,6 +23461,7 @@
"LoadImagesFromFolderKJ",
"LoadVideosFromFolder",
"Mask_transform_sum",
"MathExpression_UTK",
"MergeBatch",
"MergeImageChannels",
"PadImageBatchInterleaved",
@ -23587,6 +23774,8 @@
"GeminiConvertRasterToVector",
"GeminiFLUXResolutions",
"GeminiImageGenerator",
"GeminiLoadImagePath",
"GeminiLoadImagesFromDir",
"GeminiSVGPreview",
"GeminiSaveSVG",
"GeminiSaveText",
@ -23894,10 +24083,15 @@
"XJSamplerAdapter",
"XJSaveImageWithMetadata",
"XJSchedulerAdapter",
"XJSegsAutoAdjustHookProvider",
"XJSegsColorCorrectHSVHookProvider",
"XJSegsColorCorrectRGBHookProvider",
"XJSegsColorMatchHookProvider",
"XJSegsCount",
"XJSegsExtractor",
"XJSegsFilter",
"XJSegsFilterByLabel",
"XJSegsMerge",
"XJSegsPick",
"XJSegsStitcher",
"XJSegsWildcardPrompt",
@ -25593,6 +25787,14 @@
"title_aux": "ComfyUI-Hunyuan-Image-3"
}
],
"https://github.com/bhhtr12/ComfyUI-ollama-stop": [
[
"OllamaStopNode"
],
{
"title_aux": "ComfyUI-ollama-stop"
}
],
"https://github.com/bhvbhushan/ComfyUI-LoRABlockWeight": [
[
"HierarchicalLoRAWeightEditor",
@ -26861,6 +27063,14 @@
"title_aux": "Arc2Face ComfyUI Node Library"
}
],
"https://github.com/calibancode/ComfyUI-bevvy": [
[
"SaveImageWebP"
],
{
"title_aux": "ComfyUI-bevvy"
}
],
"https://github.com/camenduru/ComfyUI-TostAI": [
[
"SendToTostAI"
@ -26878,6 +27088,14 @@
"title_aux": "Capitan-ConditioningEnhancer"
}
],
"https://github.com/capitan01R/ComfyUI-CapitanZiT-Scheduler": [
[
"CapitanZiTLinearSigma"
],
{
"title_aux": "ComfyUI-CapitanZiT-Scheduler"
}
],
"https://github.com/cardenluo/ComfyUI-Apt_Preset": [
[
"AD_DrawSchedule",
@ -26897,6 +27115,8 @@
"AD_sch_value",
"AD_slice_Condi",
"AI_GLM4",
"AI_GLM_image",
"AI_GLM_text",
"AI_Ollama_image",
"AI_Ollama_text",
"AI_PresetSave",
@ -27187,7 +27407,6 @@
"sum_lora",
"sum_stack_AD",
"sum_stack_Kontext",
"sum_stack_QwenEdit",
"sum_stack_QwenEditPlus",
"sum_stack_Wan",
"sum_stack_image",
@ -29566,6 +29785,13 @@
"MaskComposite",
"MaskPreview",
"MaskToImage",
"MeshyAnimateModelNode",
"MeshyImageToModelNode",
"MeshyMultiImageToModelNode",
"MeshyRefineNode",
"MeshyRigModelNode",
"MeshyTextToModelNode",
"MeshyTextureNode",
"MinimaxHailuoVideoNode",
"MinimaxImageToVideoNode",
"MinimaxSubjectToVideoNode",
@ -30753,6 +30979,17 @@
"title_aux": "ComfyUI-TTS"
}
],
"https://github.com/danieljanata/ComfyUI-Prompting-System": [
[
"PS_MetadataCleaner",
"PS_MetadataReader",
"PS_PromptSaver",
"PS_SmartText"
],
{
"title_aux": "ComfyUI-Prompting-System"
}
],
"https://github.com/danielvw/ComfyUI-WanMove-Adapter": [
[
"CoordsToWanTracks"
@ -30924,6 +31161,7 @@
"PromptCameraSelector",
"PromptConstructor",
"PromptLightingSelector",
"Test1",
"TiledKSampler",
"TiledKSamplerWithUpscaler",
"TrainingDatasetSaver"
@ -32348,6 +32586,14 @@
"title_aux": "ComfyUI-enricos-nodes"
}
],
"https://github.com/esp-dev/comfyui-loadheicimage": [
[
"LoadImagePlusHEIC"
],
{
"title_aux": "comfyui-loadheicimage"
}
],
"https://github.com/esp-dev/comfyui-videoframenode": [
[
"VideoFirstLastFrame"
@ -37581,6 +37827,51 @@
"title_aux": "HouseKeeper"
}
],
"https://github.com/joe002/comfyui-conduit-optimizer": [
[
"ConduitApply",
"ConduitBatchOptimizer",
"ConduitCacheClear",
"ConduitCore",
"ConduitEmbeddingCache",
"ConduitGate",
"ConduitLatentCache",
"ConduitPath",
"ConduitPool",
"ConduitPrecisionPatcher",
"ConduitSeal",
"ConduitSense",
"ConduitSpeculativeKSampler"
],
{
"title_aux": "comfyui-conduit-optimizer"
}
],
"https://github.com/joe002/comfyui-deterministic-nodes": [
[
"CascadeRefiner",
"ChecksumValidator",
"DeterministicSampler",
"ECHOContextNode",
"MoERouterNode"
],
{
"title_aux": "comfyui-deterministic-nodes"
}
],
"https://github.com/joe002/comfyui-rtx4090-nodes": [
[
"BatchImageProcessor",
"BatchLatentProcessor",
"GPUMonitor",
"MemoryManager",
"RTX4090Optimizer",
"TensorRTAutoConverter"
],
{
"title_aux": "comfyui-rtx4090-nodes"
}
],
"https://github.com/joeriben/ai4artsed_comfyui_nodes": [
[
"ai4artsed_conditioning_fusion",
@ -41670,6 +41961,81 @@
"title_aux": "ComfyUI-Replace-First-Frame-Last-Frame"
}
],
"https://github.com/loz2754/AUN-ComfyUI-Nodes": [
[
"AUNAddToPrompt",
"AUNAny",
"AUNBookmark",
"AUNBoolean",
"AUNCFG",
"AUNCheckpointLoaderWithClipSkip",
"AUNEmptyLatent",
"AUNExtractModelName",
"AUNExtractPowerLoras",
"AUNExtractWidgetValue",
"AUNGetActiveNodeTitle",
"AUNGetConnectedNodeTitles",
"AUNGraphScraper",
"AUNImageLoadResize",
"AUNImageResize",
"AUNImageSingleBatch3",
"AUNImg2Img",
"AUNImgLoader",
"AUNInputs",
"AUNInputsHybrid",
"AUNKSamplerPlusv3",
"AUNModelNamePass",
"AUNModelShorten",
"AUNMultiBypassIndex",
"AUNMultiGroupUniversal",
"AUNMultiMuteIndex",
"AUNMultiNegPrompt",
"AUNMultiUniversal",
"AUNNameCrop",
"AUNNodeStateController",
"AUNPathFilename",
"AUNPathFilenameVideo",
"AUNRandomAnySwitch",
"AUNRandomIndexSwitch",
"AUNRandomNumber",
"AUNRandomTextIndexSwitch",
"AUNSaveImage",
"AUNSaveVideo",
"AUNSetBypassByTitle",
"AUNSetBypassStateGroup",
"AUNSetCollapseAndBypassStateAdvanced",
"AUNSetMuteByTitle",
"AUNSetMuteStateGroup",
"AUNShowTextWithTitle",
"AUNSingleLabelSwitch",
"AUNStrip",
"AUNSwitchFloat",
"AUNTextIndexSwitch",
"AUNTextIndexSwitch3",
"AUNTitleImagePreview",
"AnyType(str)",
"AudioInputOptions",
"JNodes_AnyToString",
"JNodes_ConditioningInOut",
"JNodes_FloatLiteral",
"JNodes_GetCleanFilename",
"JNodes_GetComfyDirectory",
"JNodes_GetLeafDirectory",
"JNodes_GetOutputDirectory",
"JNodes_GetTempDirectory",
"JNodes_IntLiteral",
"JNodes_ModelInOut",
"JNodes_StringLiteral",
"JNodes_SubdirectorySelector",
"JoinVideosInDirectory",
"KSamplerInputs",
"MainFolderManualName",
"TextSwitch2InputWithTextOutput"
],
{
"title_aux": "AUN ComfyUI Nodes"
}
],
"https://github.com/lquesada/ComfyUI-Inpaint-CropAndStitch": [
[
"InpaintCropImproved",
@ -43107,6 +43473,14 @@
"title_aux": "comfyui-sora-node"
}
],
"https://github.com/maximilianwicen/ComfyUI-MaxTools": [
[
"MaxQuickImageSize"
],
{
"title_aux": "ComfyUI-MaxTools"
}
],
"https://github.com/maxious/comfyui-dap": [
[
"DAP_ERP_to_Cubemap",
@ -45418,6 +45792,57 @@
"title_aux": "ComfyUI-HfLoader"
}
],
"https://github.com/olduvai-jp/ComfyUI-S3-IO": [
[
"LoadImageS3",
"LoadVideoUploadS3",
"SaveImageS3",
"VHS_AudioToVHSAudio",
"VHS_BatchManager",
"VHS_DuplicateImages",
"VHS_DuplicateLatents",
"VHS_DuplicateMasks",
"VHS_GetImageCount",
"VHS_GetLatentCount",
"VHS_GetMaskCount",
"VHS_LoadAudio",
"VHS_LoadAudioUpload",
"VHS_LoadImagePath",
"VHS_LoadImages",
"VHS_LoadImagesPath",
"VHS_LoadVideo",
"VHS_LoadVideoFFmpeg",
"VHS_LoadVideoFFmpegPath",
"VHS_LoadVideoPath",
"VHS_MergeImages",
"VHS_MergeLatents",
"VHS_MergeMasks",
"VHS_PruneOutputs",
"VHS_SelectEveryNthImage",
"VHS_SelectEveryNthLatent",
"VHS_SelectEveryNthMask",
"VHS_SelectFilename",
"VHS_SelectImages",
"VHS_SelectLatents",
"VHS_SelectLatest",
"VHS_SelectMasks",
"VHS_SplitImages",
"VHS_SplitLatents",
"VHS_SplitMasks",
"VHS_Unbatch",
"VHS_VAEDecodeBatched",
"VHS_VAEEncodeBatched",
"VHS_VHSAudioToAudio",
"VHS_VideoCombine",
"VHS_VideoInfo",
"VHS_VideoInfoLoaded",
"VHS_VideoInfoSource",
"VideoCombineS3"
],
{
"title_aux": "ComfyUI-S3-IO"
}
],
"https://github.com/oleksandr612/ComfyUI-Counter": [
[
"Simple Counter"
@ -46611,6 +47036,7 @@
"Lora Loader Str",
"MaskEmptyFloatNode",
"MaskPassOrPlaceholder",
"MonoToStereoConverter",
"ParametricEQNode",
"PonyFaceEnhancementPipelineWithInjection",
"PonyUpscaleSamplerWithInjection",
@ -49833,6 +50259,7 @@
"LoRAExtractKnee",
"LoRAExtractQuantile",
"LoRAExtractRatio",
"LoRAMergeToModel",
"LoRAMetaKeys",
"LoRAMultiMerge",
"LoRAPruneKeys",
@ -51922,6 +52349,14 @@
"title_aux": "SANA_LOWVRAM"
}
],
"https://github.com/tabisheva/comfyui-segs-profile": [
[
"SEGSIsProfile"
],
{
"title_aux": "comfyui-segs-profile"
}
],
"https://github.com/tackcrypto1031/tk_comfyui_img2mask": [
[
"TK_Image2Mask"
@ -51930,6 +52365,14 @@
"title_aux": "tk_comfyui_img2mask"
}
],
"https://github.com/tackcrypto1031/tk_comfyui_view_and_light": [
[
"TK_View_And_Light"
],
{
"title_aux": "tk_comfyui_view_and_light"
}
],
"https://github.com/takemetosiberia/ComfyUI-SAMURAI--SAM2-": [
[
"SAMURAIBoxInputNode",
@ -52191,6 +52634,14 @@
"title_aux": "Divergent Nodes"
}
],
"https://github.com/theluminhub/ComfyUI-Lumin-Upload": [
[
"AssetManagerNode"
],
{
"title_aux": "ComfyUI-Lumin-Upload"
}
],
"https://github.com/theshubzworld/ComfyUI-FaceCalloutNode": [
[
"FaceCalloutEffect",
@ -53270,8 +53721,7 @@
"DisTorchPurgeVRAMV2",
"MemoryManager",
"ModelPatchMemoryCleaner",
"PatchSageAttentionDM",
"SafeMemoryManager"
"PatchSageAttentionDM"
],
{
"title_aux": "ComfyUI-DistorchMemoryManager"
@ -53296,14 +53746,6 @@
"title_aux": "ComfyUI-QwenImageLoraLoader"
}
],
"https://github.com/ussoewwin/image_resize_comfyui": [
[
"ImageResizeAdvanced"
],
{
"title_aux": "image-resize-comfyui"
}
],
"https://github.com/vadimcro/VKRiez-Edge": [
[
"VKriezEnhancedEdgePreprocessor",
@ -54378,23 +54820,15 @@
],
"https://github.com/willmiao/ComfyUI-Lora-Manager": [
[
"BasicScheduler",
"CFGGuider",
"CLIPTextEncode",
"DebugMetadata",
"KSamplerSelect",
"LoraDemoNode",
"LoraManagerLoader",
"LoraManagerTextLoader",
"LoraPoolNode",
"LoraRandomizerNode",
"LoraStacker",
"PromptLoraManager",
"SamplerCustomAdvanced",
"SaveImageLM",
"TSC_EfficientLoader",
"TriggerWordToggle",
"VAEDecode",
"WanVideoLoraSelectFromText",
"WanVideoLoraSelectLM"
],

View File

@ -250,6 +250,30 @@ paths:
type: object
additionalProperties:
$ref: '#/components/schemas/NodePackageMetadata'
/customnode/get_node_types_in_workflows:
get:
summary: List node types used by all user workflows
description: Scan through all workflows in the Comfy user directory, and return a list of all node types used in each one.
responses:
'200':
description: Successful operation
content:
application/json:
schema:
type: array
items:
type: object
properties:
workflow_file_name:
type: string
node_types:
type: array
items:
type: string
'500':
description: Error occurred
/customnode/alternatives:
get: