mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2026-05-13 18:37:25 +08:00
Compare commits
21 Commits
e80258b38a
...
64ae41ef44
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64ae41ef44 | ||
|
|
7a8fc44f90 | ||
|
|
8d5c12037f | ||
|
|
d370403e2d | ||
|
|
e67e35795e | ||
|
|
ccf6d98457 | ||
|
|
113324728e | ||
|
|
f2a3d39e26 | ||
|
|
ec72d983ad | ||
|
|
a3aabfd72c | ||
|
|
03272b1f70 | ||
|
|
abf9c654b3 | ||
|
|
bbc223a76c | ||
|
|
aba857a350 | ||
|
|
74c2518894 | ||
|
|
98e0098ddd | ||
|
|
ed56212fa0 | ||
|
|
1bdcd1bdbf | ||
|
|
e04ed0eda7 | ||
|
|
02aa67b541 | ||
|
|
67d03530a3 |
@ -1705,6 +1705,17 @@
|
||||
"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": "Kyreo",
|
||||
"title": "ComfyUI-CharacterPromptBuffer",
|
||||
"id": "comfyui-characterpromptbuffer",
|
||||
"reference": "https://github.com/Kyreo/ComfyUI-CharacterPromptBuffer",
|
||||
"files": [
|
||||
"https://github.com/Kyreo/ComfyUI-CharacterPromptBuffer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes for generating multiple character prompt variations in a single queue run. Includes Character Prompt Manager and Variation Buffer."
|
||||
},
|
||||
{
|
||||
"author": "Gourieff",
|
||||
"title": "ComfyUI-FutureWarningIgnore",
|
||||
@ -3393,6 +3404,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for SCAIL input processing"
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-NativeLooping_testing",
|
||||
"reference": "https://github.com/kijai/ComfyUI-NativeLooping_testing",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-NativeLooping_testing"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Temporary repository for testing candidate for native ComfyUI loop nodes. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "hhhzzyang",
|
||||
"title": "Comfyui-Lama",
|
||||
@ -13943,6 +13964,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "A Matchering audio mastering/matching node for ComfyUI."
|
||||
},
|
||||
{
|
||||
"author": "marduk191",
|
||||
"title": "comfyui-nucleus",
|
||||
"reference": "https://github.com/marduk191/comfyui-nucleus",
|
||||
"files": [
|
||||
"https://github.com/marduk191/comfyui-nucleus"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nucleus Image (MoE diffusion) support for ComfyUI — backport of PR #13471"
|
||||
},
|
||||
{
|
||||
"author": "haohaocreates",
|
||||
"title": "ComfyUI-HH-Image-Selector",
|
||||
@ -28904,56 +28935,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Text translation node for ComfyUI: No need to apply for a translation API key, just use it. Currently supports more than thirty translation platforms."
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI Auto LoRA",
|
||||
"reference": "https://github.com/Charonartist/comfyui-auto-lora-v2",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-auto-lora-v2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a ComfyUI custom node that automatically detects trigger words from text prompts and applies the corresponding LoRA models."
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI Smart Resize Node",
|
||||
"reference": "https://github.com/Charonartist/comfyui-smart-resize-node",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-smart-resize-node"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Smart resize node for ComfyUI that handles portrait/landscape images with short/long side specification"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI Tag Remover",
|
||||
"reference": "https://github.com/Charonartist/comfyui-tag-remover",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-tag-remover"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node for removing specified tags and their content from text"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "comfyui-last-frame-extractor",
|
||||
"reference": "https://github.com/Charonartist/comfyui-last-frame-extractor",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-last-frame-extractor"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a ComfyUI custom node that extracts the last frame (image) from an input image batch. It is particularly useful when you want to obtain the final scene or frame in a video generation workflow."
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "comfyui-lmstudio-conversation",
|
||||
"reference": "https://github.com/Charonartist/comfyui-lmstudio-conversation",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-lmstudio-conversation"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for LM Studio integration with conversation history support "
|
||||
},
|
||||
{
|
||||
"author": "ptmaster",
|
||||
"title": "ComfyUI-Load-Diffusion-Model-to-Muti-GPUs",
|
||||
@ -30004,6 +29985,26 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for FLUX.2 Klein conditioning: region-aware text enhancement, sectioned prompt encoding, and corrected reference-latent mixing with multi-reference support."
|
||||
},
|
||||
{
|
||||
"author": "xmarre",
|
||||
"title": "ComfyUI-DiffAid-Patches",
|
||||
"reference": "https://github.com/xmarre/ComfyUI-DiffAid-Patches",
|
||||
"files": [
|
||||
"https://github.com/xmarre/ComfyUI-DiffAid-Patches"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node pack implementing Diff-Aid-inspired inference-time text-conditioning patches for Flux and SDXL models."
|
||||
},
|
||||
{
|
||||
"author": "xmarre",
|
||||
"title": "ComfyUI-TIDE",
|
||||
"reference": "https://github.com/xmarre/ComfyUI-TIDE",
|
||||
"files": [
|
||||
"https://github.com/xmarre/ComfyUI-TIDE"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node implementing TIDE (Text-Informed Dynamic Extrapolation with Step-Aware Temperature Control) for diffusion models."
|
||||
},
|
||||
{
|
||||
"author": "Pigidiy",
|
||||
"title": "ComfyUI-LikeSpiderAI-UI",
|
||||
@ -30799,16 +30800,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for Telegram bot integration"
|
||||
},
|
||||
{
|
||||
"author": "leonardomiramondi",
|
||||
"title": "Flux Context ComfyUI Node",
|
||||
"reference": "https://github.com/leonardomiramondi/flux-context-comfyui",
|
||||
"files": [
|
||||
"https://github.com/leonardomiramondi/flux-context-comfyui"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node for Flux Context (Kontext) image editing"
|
||||
},
|
||||
{
|
||||
"author": "kpsss34",
|
||||
"title": "ComfyUI kpsss34 Custom Node",
|
||||
@ -33740,6 +33731,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "This project is a custom node for ComfyUI that integrates the power of the Google Gemini 2.5 Flash Image (“Nano Banana”) API. It provides a single versatile node, the Gemini Nano Banana, which allows you to perform image generation and editing operations directly within your workflows."
|
||||
},
|
||||
{
|
||||
"author": "orion4d",
|
||||
"title": "Orion4D_AutoCachedPreview",
|
||||
"reference": "https://github.com/orion4d/Orion4D_AutoCachedPreview",
|
||||
"files": [
|
||||
"https://github.com/orion4d/Orion4D_AutoCachedPreview"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A custom node for ComfyUI that allows you to cache an image and its mask to avoid recalculating upstream steps in your workflow."
|
||||
},
|
||||
{
|
||||
"author": "Fabio Sarracino",
|
||||
"title": "VibeVoice ComfyUI",
|
||||
@ -37264,6 +37265,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Geekatplay Studio tiled generative upscale helpers for ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "GeekatplayStudio",
|
||||
"title": "ComfyUI-cluster",
|
||||
"reference": "https://github.com/GeekatplayStudio/ComfyUI-cluster",
|
||||
"files": [
|
||||
"https://github.com/GeekatplayStudio/ComfyUI-cluster"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Ollama-driven routing nodes and curated workflows for ComfyUI with checkpoint, LoRA, and Flux split-component flows plus image-guided variants using vision analysis."
|
||||
},
|
||||
{
|
||||
"author": "wouterverweirder",
|
||||
"title": "ComfyUI PenPlotter",
|
||||
@ -39179,16 +39190,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom ComfyUI node supporting wildcard text processing from files with YAML tags, randomization, latent ratio selection and preset aspect ratios."
|
||||
},
|
||||
{
|
||||
"author": "bpmpnaito",
|
||||
"title": "comfyui-imageviewer",
|
||||
"reference": "https://github.com/bpmpnaito/comfyui-imageviewer",
|
||||
"files": [
|
||||
"https://github.com/bpmpnaito/comfyui-imageviewer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Image viewer node that displays preview of images directly in the node."
|
||||
},
|
||||
{
|
||||
"author": "ChangeTheConstants",
|
||||
"title": "SeedVarianceEnhancer",
|
||||
@ -42354,6 +42355,16 @@
|
||||
"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": "DemonAlone",
|
||||
"title": "DemonAlone-StyleSelector-ComfyUI",
|
||||
"reference": "https://github.com/DemonAlone/DemonAlone-StyleSelector-ComfyUI",
|
||||
"files": [
|
||||
"https://github.com/DemonAlone/DemonAlone-StyleSelector-ComfyUI"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Prompt Style Selector with Preview, Multiple Selecting, Search and Local Base."
|
||||
},
|
||||
{
|
||||
"author": "tabisheva",
|
||||
"title": "comfyui-segs-profile",
|
||||
@ -45188,6 +45199,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "A visual pill-based prompt composer node for ComfyUI. Features 4 prompt panels (Quality, Main, Aesthetic, Negative), tag browser, drag-to-reorder pills, weight control, presets, Lucky prompt generator, manual override mode, and wildcard (.yaml) file loader."
|
||||
},
|
||||
{
|
||||
"author": "cowneko",
|
||||
"title": "CWK_Checkpoints_Preset_Manager",
|
||||
"reference": "https://github.com/cowneko/CWK_Checkpoints_Preset_Manager",
|
||||
"files": [
|
||||
"https://github.com/cowneko/CWK_Checkpoints_Preset_Manager"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node combining per-model preset system with full-featured model manager, CivitAI integration, and GGUF support for browsing and organizing checkpoints."
|
||||
},
|
||||
{
|
||||
"author": "dogodg3838",
|
||||
"title": "ComfyUI-NvEye",
|
||||
@ -45310,6 +45331,26 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI Qwen 3.5 Prompting nodes (captionate image, improve prompt, etc)"
|
||||
},
|
||||
{
|
||||
"author": "artemko7v",
|
||||
"title": "ComfyUI Prompt Enhance Nodes",
|
||||
"reference": "https://github.com/ArtemKo7v/ComfyUI-Prompt-Magic",
|
||||
"files": [
|
||||
"https://github.com/ArtemKo7v/ComfyUI-Prompt-Magic"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI prompt enhance nodes and string utilities"
|
||||
},
|
||||
{
|
||||
"author": "artemko7v",
|
||||
"title": "ComfyUI Complex Prompt Nodes",
|
||||
"reference": "https://github.com/ArtemKo7v/ComfyUI-Complex-Prompt",
|
||||
"files": [
|
||||
"https://github.com/ArtemKo7v/ComfyUI-Complex-Prompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node for working with complex prompts with support for variables, randomness, and basic logic."
|
||||
},
|
||||
{
|
||||
"author": "TakkunRed",
|
||||
"title": "comfyui_checkpoint_preset_manager",
|
||||
@ -45444,6 +45485,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "A floating preview window node for ComfyUI. Ideal for multi-monitor setups."
|
||||
},
|
||||
{
|
||||
"author": "nekodificador",
|
||||
"title": "NKD Klein Tools",
|
||||
"reference": "https://github.com/Nekodificador/ComfyUI-NKD-Klein-Tools",
|
||||
"files": [
|
||||
"https://github.com/Nekodificador/ComfyUI-NKD-Klein-Tools"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NKD Klein Presampling and Postsampling nodes for Flux Klein workflows in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "IMGLAB-net",
|
||||
"title": "IMGLAB_ComfyUI",
|
||||
@ -45534,6 +45585,16 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Fork of ComfyUI-Inpaint-CropAndStitch adapted for Nano Banana 2. Adds NB2 Mask Generator, exact-resolution cropping and feathered alpha compositing in the stitch step."
|
||||
},
|
||||
{
|
||||
"author": "amortegui84",
|
||||
"title": "Tile Upscale NB2",
|
||||
"reference": "https://github.com/amortegui84/comfyui-tile-upscale-nb2",
|
||||
"files": [
|
||||
"https://github.com/amortegui84/comfyui-tile-upscale-nb2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Tile-based upscaling nodes for ComfyUI — Nano Banana 2 compatible"
|
||||
},
|
||||
{
|
||||
"author": "hqrz",
|
||||
"title": "ComfyUI Japanese Romaji Converter",
|
||||
@ -46007,16 +46068,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Split a multiline prompt into up to 12 numbered STRING outputs using a user-defined delimiter. Useful for multi-segment video workflows."
|
||||
},
|
||||
{
|
||||
"author": "Kyreo",
|
||||
"title": "comfyui-characterpromptbuffer",
|
||||
"reference": "https://github.com/Kyreo/ComfyUI-CharacterPromptBuffer",
|
||||
"files": [
|
||||
"https://github.com/Kyreo/ComfyUI-CharacterPromptBuffer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for generating character prompt variations as batch"
|
||||
},
|
||||
{
|
||||
"author": "Phykrex",
|
||||
"title": "comfyui-momo-nodes",
|
||||
@ -46047,6 +46098,296 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Personal ComfyUI custom nodes."
|
||||
},
|
||||
{
|
||||
"author": "wos-ai-studio",
|
||||
"title": "ComfyUI-Title-Memo",
|
||||
"reference": "https://github.com/xujianjian2004/ComfyUI-Title-Memo",
|
||||
"files": [
|
||||
"https://github.com/xujianjian2004/ComfyUI-Title-Memo"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Add title, comment and memo functions to nodes, which support custom styles and automatic word wrapping, compatible with Nodes 2.0."
|
||||
},
|
||||
{
|
||||
"author": "ussaaron",
|
||||
"title": "FrameFuse",
|
||||
"reference": "https://github.com/headline-design/comfyui-framefuse",
|
||||
"files": [
|
||||
"https://github.com/headline-design/comfyui-framefuse"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for stitching a still frame onto the start or end of an IMAGE video batch and trimming extra tail frames with optional audio sync alignment."
|
||||
},
|
||||
{
|
||||
"author": "takkun",
|
||||
"title": "ComfyUI-StepByStep-Sampler",
|
||||
"reference": "https://github.com/TakkunRed/ComfyUI-StepByStep-Sampler",
|
||||
"files": [
|
||||
"https://github.com/TakkunRed/ComfyUI-StepByStep-Sampler"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI StepByStep Sampler is a plugin for ComfyUI that provides a step-by-step sampling method for image generation. It allows users to generate images in a more controlled and iterative manner, making it easier to achieve desired results."
|
||||
},
|
||||
{
|
||||
"author": "serhiiyashyn-sf",
|
||||
"title": "Face-Aligned Center",
|
||||
"reference": "https://github.com/serhiiyashyn-sf/comfyui-face-aligned-center",
|
||||
"files": [
|
||||
"https://github.com/serhiiyashyn-sf/comfyui-face-aligned-center"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Batch-aware character centering for ComfyUI. Given a character sheet (multiple angles), scales every image so the face ends up at the same size and canvas position — including back-view angles, via a silhouette fallback tied to the batch's face scale. Includes a Fine-Tune node for per-image zoom/nudge with a live canvas preview, and an Anime Face Detect node for crop+mask using lbpcascade_animeface."
|
||||
},
|
||||
{
|
||||
"author": "newgrit1004",
|
||||
"title": "Qwen3 Triton TTS",
|
||||
"reference": "https://github.com/newgrit1004/ComfyUI-Qwen3-TTS-Triton",
|
||||
"files": [
|
||||
"https://github.com/newgrit1004/ComfyUI-Qwen3-TTS-Triton"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node wrapping qwen3-tts-triton for 7-mode Qwen3-TTS inference (Triton kernel fusion + TurboQuant KV cache)"
|
||||
},
|
||||
{
|
||||
"author": "mahilkr",
|
||||
"title": "HunyuanWorld 3D World Generation",
|
||||
"reference": "https://github.com/krmahil/comfyui-hunyuan-world",
|
||||
"files": [
|
||||
"https://github.com/krmahil/comfyui-hunyuan-world"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for immersive 3D world generation using Tencent HunyuanWorld 1.0"
|
||||
},
|
||||
{
|
||||
"author": "machinedelusions",
|
||||
"title": "ComfyUI-FL-LTXTools",
|
||||
"reference": "https://github.com/filliptm/ComfyUI-FL-LTXTools",
|
||||
"files": [
|
||||
"https://github.com/filliptm/ComfyUI-FL-LTXTools"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Experimental tools and motion controls for LTX-Video in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "intelliprompt",
|
||||
"title": "comfy-intelliprompt",
|
||||
"reference": "https://github.com/galpt/comfy-intelliPrompt",
|
||||
"files": [
|
||||
"https://github.com/galpt/comfy-intelliPrompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "intelliPrompt - An intelligent prompt optimizer for ComfyUI that fixes typos, balances parentheses, and enhances prompts"
|
||||
},
|
||||
{
|
||||
"author": "enviral-design",
|
||||
"title": "Enviral Design Node Pack",
|
||||
"reference": "https://github.com/EnviralDesign/comfyUI-enviral-design-node-pack",
|
||||
"files": [
|
||||
"https://github.com/EnviralDesign/comfyUI-enviral-design-node-pack"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Small, dependency-light ComfyUI utility nodes from Enviral Design."
|
||||
},
|
||||
{
|
||||
"author": "eniewold",
|
||||
"title": "Subworkflow (reusable workflows)",
|
||||
"reference": "https://github.com/eniewold/ComfyUI-Subworkflow",
|
||||
"files": [
|
||||
"https://github.com/eniewold/ComfyUI-Subworkflow"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Use ComfyUI workflows as reusable subworkflows via Subworkflow Input, Subworkflow Output, and Subworkflow nodes"
|
||||
},
|
||||
{
|
||||
"author": "dorpxam",
|
||||
"title": "LTX-2 Microscope",
|
||||
"reference": "https://github.com/dorpxam/ComfyUI-LTX2-Microscope",
|
||||
"files": [
|
||||
"https://github.com/dorpxam/ComfyUI-LTX2-Microscope"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "48-Layers Latent Previewer for Lightrick's LTX-2 model."
|
||||
},
|
||||
{
|
||||
"author": "dailydoseofaiart",
|
||||
"title": "ComfyUI-FPSFrameDrop",
|
||||
"reference": "https://github.com/dailydoseofaiart/ComfyUI-FPSFrameDrop",
|
||||
"files": [
|
||||
"https://github.com/dailydoseofaiart/ComfyUI-FPSFrameDrop"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A node to drop frames from the output images to force the video to a lower FPS at the same playback speed."
|
||||
},
|
||||
{
|
||||
"author": "Emiewn",
|
||||
"title": "ComfyUI-Emiewn-Nodes",
|
||||
"reference": "https://github.com/emiewnn/ComfyUI-Emiewn-Nodes",
|
||||
"files": [
|
||||
"https://github.com/emiewnn/ComfyUI-Emiewn-Nodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom nodes for ComfyUI: Drag & drop image paste, interactive UI crop, WAN I2V bucket resolution, and GIMM-VFI frame interpolation."
|
||||
},
|
||||
{
|
||||
"author": "jetthuangai",
|
||||
"title": "ComfyUI-JH-PixelPro",
|
||||
"reference": "https://github.com/jetthuangai/ComfyUI-JH-PixelPro",
|
||||
"files": [
|
||||
"https://github.com/jetthuangai/ComfyUI-JH-PixelPro"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "GPU-powered pro-grade image suite cho retouch chân dung. v0.1.0 alpha: Frequency Separation (N-01) + Sub-Pixel Mask Refiner (N-02). Kornia core, tensor thuần không rời VRAM."
|
||||
},
|
||||
{
|
||||
"author": "xxchinenxx",
|
||||
"title": "Qwen Clothing Selector",
|
||||
"reference": "https://github.com/xxchinenxx/ComfyUI-QwenClothingSelector",
|
||||
"files": [
|
||||
"https://github.com/xxchinenxx/ComfyUI-QwenClothingSelector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for Qwen-Image-Edit outfit/clothing edits — toggles, presets, and identity-preserving prompt builders. Useful for fashion edits, costume changes, and outfit swaps."
|
||||
},
|
||||
{
|
||||
"author": "xav",
|
||||
"title": "XAV Anima Style Selector",
|
||||
"reference": "https://github.com/XAV-Games/comfyui-xav-anima-style-selector",
|
||||
"files": [
|
||||
"https://github.com/XAV-Games/comfyui-xav-anima-style-selector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for quick and easy style selection for the Anima model"
|
||||
},
|
||||
{
|
||||
"author": "wsq194",
|
||||
"title": "Yeban Workflow Manager",
|
||||
"reference": "https://github.com/wsq194/yeban-workflow-manager",
|
||||
"files": [
|
||||
"https://github.com/wsq194/yeban-workflow-manager"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI workflow manager plugin with auto-save, version history, sidebar integration and more."
|
||||
},
|
||||
{
|
||||
"author": "szymonj",
|
||||
"title": "LoRA Range Loader",
|
||||
"reference": "https://github.com/esp-dev/comfyui-lora-range-loader",
|
||||
"files": [
|
||||
"https://github.com/esp-dev/comfyui-lora-range-loader"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node: load a LoRA from current selection and automatically advance current within a first/last filename range."
|
||||
},
|
||||
{
|
||||
"author": "mitch-avis",
|
||||
"title": "ComfyUI-HoldCounter",
|
||||
"reference": "https://github.com/mitch-avis/ComfyUI-HoldCounter",
|
||||
"files": [
|
||||
"https://github.com/mitch-avis/ComfyUI-HoldCounter"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node that emits a held, range-bound integer index with multiple advancement modes (loop, clamp, pingpong, random, shuffle) — useful as a Load Image batch index that advances every N runs."
|
||||
},
|
||||
{
|
||||
"author": "halr9000",
|
||||
"title": "Procgen 9000",
|
||||
"reference": "https://github.com/halr9000/procgen9000",
|
||||
"files": [
|
||||
"https://github.com/halr9000/procgen9000"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Procedural image generation toolkit designed as input to image edit workflows."
|
||||
},
|
||||
{
|
||||
"author": "capacap",
|
||||
"title": "ComfyUI-Selective-Sigma-Detailer",
|
||||
"reference": "https://github.com/Capacap/ComfyUI-Selective-Sigma-Detailer",
|
||||
"files": [
|
||||
"https://github.com/Capacap/ComfyUI-Selective-Sigma-Detailer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI sampler that boosts detail only in latent regions that are already dense at the moment the schedule activates."
|
||||
},
|
||||
{
|
||||
"author": "brosequist",
|
||||
"title": "comfyui-pipeline-barrier",
|
||||
"reference": "https://github.com/brosequist/ComfyUI-PipelineBarrier",
|
||||
"files": [
|
||||
"https://github.com/brosequist/ComfyUI-PipelineBarrier"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node that force-flushes GPU caches between pipeline stages to prevent OOM kills"
|
||||
},
|
||||
{
|
||||
"author": "amrnidal999-tech",
|
||||
"title": "Realisim Enhancor",
|
||||
"reference": "https://github.com/amrnidal999-tech/comfyui-realisim-enhancor",
|
||||
"files": [
|
||||
"https://github.com/amrnidal999-tech/comfyui-realisim-enhancor"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI image enhancement node with JPEG degradation, noise, blur, sharpening, contrast, and color controls."
|
||||
},
|
||||
{
|
||||
"author": "rikanrino",
|
||||
"title": "Rikannodes",
|
||||
"reference": "https://github.com/rikanrino/Rikannodes",
|
||||
"files": [
|
||||
"https://github.com/rikanrino/Rikannodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "kijai ComfyUI-PromptRelay with fps and max frame output"
|
||||
},
|
||||
{
|
||||
"author": "mexxmillion",
|
||||
"title": "ComfyUI-VLMPrompt",
|
||||
"reference": "https://github.com/mexxmillion/ComfyUI-VLMPrompt",
|
||||
"files": [
|
||||
"https://github.com/mexxmillion/ComfyUI-VLMPrompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for local VLM prompt generation with GGUF and Hugging Face backends."
|
||||
},
|
||||
{
|
||||
"author": "IA-gyz",
|
||||
"title": "comfyui-VarBoard",
|
||||
"reference": "https://github.com/IA-gyz/comfyui-VarBoard",
|
||||
"files": [
|
||||
"https://github.com/IA-gyz/comfyui-VarBoard"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Variables Board is a floating control center for ComfyUI workflows that centralizes parameters into a customizable overlay."
|
||||
},
|
||||
{
|
||||
"author": "hassan-mb",
|
||||
"title": "HB ComfyUI Nodes",
|
||||
"reference": "https://github.com/HassanEclipse/comfyui-hb-party",
|
||||
"files": [
|
||||
"https://github.com/HassanEclipse/comfyui-hb-party"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Utility nodes for ComfyUI featuring a dynamic Text Preset Switch with workflow-safe persistence and Node 2.0 support."
|
||||
},
|
||||
{
|
||||
"author": "Cordux",
|
||||
"title": "ComfyUI-PromptTagBuilder",
|
||||
"reference": "https://github.com/Cordux/ComfyUI-PromptTagBuilder",
|
||||
"files": [
|
||||
"https://github.com/Cordux/ComfyUI-PromptTagBuilder"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Flexible ComfyUI node that simplifies prompt building through organized dropdown categories for tag-based models."
|
||||
},
|
||||
{
|
||||
"author": "alikonfilms",
|
||||
"title": "comfyui-alikonfilms",
|
||||
"reference": "https://github.com/alikonfilms/comfyui_alikonfilms",
|
||||
"files": [
|
||||
"https://github.com/alikonfilms/comfyui_alikonfilms"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A CLIP text encoder with 18 cinematic camera movement presets (dolly, pan, tilt, zoom, orbit and more). Subject-aware and free-camera modes, blend slider to mix your prompt with camera movements, and a live text output to preview the final prompt."
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
10940
github-stats.json
10940
github-stats.json
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -816,6 +819,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.post("/manager/queue/update_all")
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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", {
|
||||
|
||||
457
js/common.js
457
js/common.js
@ -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();
|
||||
@ -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) {
|
||||
@ -1918,7 +1852,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];
|
||||
@ -1965,6 +1902,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;
|
||||
|
||||
@ -2034,6 +2013,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;
|
||||
|
||||
|
||||
@ -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
699
js/node-usage-analyzer.css
Normal 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
742
js/node-usage-analyzer.js
Normal 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";
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,5 @@
|
||||
{
|
||||
"custom_nodes": [
|
||||
{
|
||||
"author": "andreszs",
|
||||
"title": "ComfyUI-Lora-Pipeline",
|
||||
"reference": "https://github.com/andreszs/ComfyUI-Lora-Pipeline",
|
||||
"files": [
|
||||
"https://github.com/andreszs/ComfyUI-Lora-Pipeline"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Area-based LoRA and conditioning workflow tools for ComfyUI with multi-region control."
|
||||
},
|
||||
{
|
||||
"author": "Zinigo",
|
||||
"title": "Prompt Builder [NAME CONFLICT]",
|
||||
"reference": "https://github.com/zinigo-creations/comfyui-prompt-builder",
|
||||
"files": [
|
||||
"https://github.com/zinigo-creations/comfyui-prompt-builder"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Dropdown-based prompt builder for ComfyUI. Create characters, scenes, and styles without writing prompts. Designed for beginners and fast iteration."
|
||||
},
|
||||
{
|
||||
"author": "ethanfel",
|
||||
"title": "Comfyui-Return-Run-Logic",
|
||||
@ -461,16 +441,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "RunningHub Nano Banana Pro API node for ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "DazzleNodes",
|
||||
"title": "ComfyUI-DazzleSwitch",
|
||||
"reference": "https://github.com/DazzleNodes/ComfyUI-DazzleSwitch",
|
||||
"files": [
|
||||
"https://github.com/DazzleNodes/ComfyUI-DazzleSwitch"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Smart switch node for ComfyUI with dropdown-based input selection and INT override for cascading workflows. Route any data type through a named dropdown instead of moving noodles."
|
||||
},
|
||||
{
|
||||
"author": "Echoflare",
|
||||
"title": "ComfyUI-Reverse-Proxy-Fix",
|
||||
@ -1324,16 +1294,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom ComfyUI nodes for JSON processing and transcription workflows, including text-to-JSON conversion, SRT subtitle parsing, and file saving. (Description by CC)[w/This nodepack contains a node that has a vulnerability allowing write to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "ShammiG",
|
||||
"title": "ComfyUI_Text_Tools_SG [UNSAFE]",
|
||||
"reference": "https://github.com/ShammiG/ComfyUI_Text_Tools_SG",
|
||||
"files": [
|
||||
"https://github.com/ShammiG/ComfyUI_Text_Tools_SG"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Text Editor node with Markdown editing plus quick shortcuts, Text Viewer node, with extra features plus Text Merge, Text Save and Load Text from anywhere nodes.[w/This nodepack contains a node that has a vulnerability allowing write to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "Smyshnikof",
|
||||
"title": "ComfyUI-PresetDownloadManager [UNSAFE]",
|
||||
@ -1914,17 +1874,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: StringToListNode"
|
||||
},
|
||||
{
|
||||
"author": "krakenunbound",
|
||||
"title": "Kraken Discord Bot",
|
||||
"id": "kraken-discord-bot",
|
||||
"reference": "https://github.com/krakenunbound/kraken-discord-bot",
|
||||
"files": [
|
||||
"https://github.com/krakenunbound/kraken-discord-bot"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "All-in-one Discord bot node for AI image generation. Simple setup - just add token, select model, and queue. Includes style presets, rate limiting, and queue management."
|
||||
},
|
||||
{
|
||||
"author": "quinteroac",
|
||||
"title": "comfyui_api_executor_nodes",
|
||||
@ -3668,16 +3617,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node for a frame by frame Diffusion."
|
||||
},
|
||||
{
|
||||
"author": "tfernd",
|
||||
"title": "Auto CPU Offload for ComfyUI [WIP]",
|
||||
"reference": "https://github.com/tfernd/ComfyUI-AutoCPUOffload",
|
||||
"files": [
|
||||
"https://github.com/tfernd/ComfyUI-AutoCPUOffload"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This extension introduces an 'Auto CPU Offload' node designed to reduce GPU VRAM usage by automatically offloading model components to the CPU. It intelligently manages the movement of model layers between the GPU and CPU, aiming to keep only the necessary parts in VRAM during inference."
|
||||
},
|
||||
{
|
||||
"author": "hujuying",
|
||||
"title": "comfyui_gemini_banana_api [WIP]",
|
||||
@ -4440,26 +4379,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "First universal metadata system for AI image generation, with template-driven architecture allowing easy extension to new services; comprehensive dependency tracking with automatic download resolution; lossless conversion between platform formats where possible; future-proof design with extensible schema and validation system.[w/This nodepack has a vulnerability that allows remote access to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI LoRA Random Selector",
|
||||
"reference": "https://github.com/Charonartist/comfyui-lora-random-selector",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-lora-random-selector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: WanMoeKSampler, WanMoeKSamplerAdvanced"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI LoRA Random Selector [WIP]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-lora-random-selector",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-lora-random-selector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node that randomly selects LoRA files by category and automatically applies corresponding trigger words.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "idoru",
|
||||
"title": "Filestash Upload Node [UNSAFE]",
|
||||
@ -5020,16 +4939,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "This project is the comfyui implementation of ComfyUI_SZtools, a labeling and naming tool developed for Kontext's local training package T2ITrainer.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "stalkervr",
|
||||
"title": "Custom Path Nodes for ComfyUI [UNSAFE]",
|
||||
"reference": "https://github.com/stalkervr/comfyui-custom-path-nodes",
|
||||
"files": [
|
||||
"https://github.com/stalkervr/comfyui-custom-path-nodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes for path handling and image cropping.[w/This nodepack contains a node that has a vulnerability allowing access to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "gorillaframeai",
|
||||
"title": "GF_pixtral_node [WIP]",
|
||||
@ -5511,16 +5420,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Trim Image Batch, Create Image Batch, Select Image Batch by Mask, Advanced Batch Creator"
|
||||
},
|
||||
{
|
||||
"author": "stalkervr",
|
||||
"title": "comfyui-custom-path-nodes [UNSAFE]",
|
||||
"reference": "https://github.com/stalkervr/comfyui-custom-path-nodes",
|
||||
"files": [
|
||||
"https://github.com/stalkervr/comfyui-custom-path-nodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes for path handling and image cropping.[w/This nodepack has a vulnerability that allows remote access to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "vovler",
|
||||
"title": "comfyui-vovlertools",
|
||||
@ -6182,16 +6081,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node that ingests GitHub repositories and outputs their content as text along with token count.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI-send-eagle-pro",
|
||||
"reference": "https://github.com/Charonartist/ComfyUI-send-eagle-pro_2",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/ComfyUI-send-eagle-pro_2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Eagle integration extension node for ComfyUI (Pro version)"
|
||||
},
|
||||
{
|
||||
"author": "Mervent",
|
||||
"title": "comfyui-yaml-prompt",
|
||||
@ -9703,16 +9592,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes:ComfyFlux Size\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "yojimbodayne",
|
||||
"title": "ComfyUI-Dropbox-API [WIP]",
|
||||
"reference": "https://github.com/yojimbodayne/ComfyUI-Dropbox-API",
|
||||
"files": [
|
||||
"https://github.com/yojimbodayne/ComfyUI-Dropbox-API"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This custom nodepackage for ComfyUI allows users to interact with Dropbox API, enabling image, text, and video uploads, downloads, and management directly from ComfyUI workflows.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "ilovejohnwhite",
|
||||
"title": "Kolors Awesome Prompts [WIP]",
|
||||
@ -10241,16 +10120,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes:Load SD3DiffusersPipeline, SD3 ControlNet Sampler"
|
||||
},
|
||||
{
|
||||
"author": "AustinMroz",
|
||||
"title": "ComfyUI-SD3-Medium-CN-Diffusers [WIP]",
|
||||
"reference": "https://github.com/ZHO-ZHO-ZHO/ComfyUI-SD3-Medium-CN-Diffusers",
|
||||
"files": [
|
||||
"https://github.com/AustinMroz/ComfyUI-WorkflowCheckpointing"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI SD3-Medium ControlNet (Diffusers)"
|
||||
},
|
||||
{
|
||||
"author": "redhottensors",
|
||||
"title": "ComfyUI-ODE",
|
||||
|
||||
@ -341,7 +341,6 @@
|
||||
"ImageBlendText",
|
||||
"ImageBlendV1",
|
||||
"ImageGridSplitter",
|
||||
"ImageRatioCrop",
|
||||
"Load_Images_Advance",
|
||||
"Load_Images_V1",
|
||||
"PD Image Resize_V1",
|
||||
@ -413,6 +412,7 @@
|
||||
"PD_image_to_text_v1",
|
||||
"PD_imagesave_path",
|
||||
"PD_load_image_v1",
|
||||
"PD_lora_loader",
|
||||
"PD_name_replacewordorder",
|
||||
"PD_number_star",
|
||||
"PD_number_start",
|
||||
@ -667,14 +667,6 @@
|
||||
"title_aux": "SplatViwer_comfyUI"
|
||||
}
|
||||
],
|
||||
"https://github.com/AiSatan/ComfyUI_CSM": [
|
||||
[
|
||||
"CSM_Transformers_Node"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_CSM [NAME CONFLICT]"
|
||||
}
|
||||
],
|
||||
"https://github.com/AkiEvansDev/ComfyUI-Tools": [
|
||||
[
|
||||
"AE.AnySwitch",
|
||||
@ -838,15 +830,15 @@
|
||||
"TS_AudioPreview",
|
||||
"TS_BGRM_BiRefNet",
|
||||
"TS_BatchPromptLoader",
|
||||
"TS_CPULoraMerger",
|
||||
"TS_Color_Grade",
|
||||
"TS_Color_Match",
|
||||
"TS_DeflickerNode",
|
||||
"TS_Despill",
|
||||
"TS_FileBrowser",
|
||||
"TS_FilePathLoader",
|
||||
"TS_FilmGrain",
|
||||
"TS_Film_Emulation",
|
||||
"TS_FloatSlider",
|
||||
"TS_Frame_Interpolation",
|
||||
"TS_Free_Video_Memory",
|
||||
"TS_GetImageMegapixels",
|
||||
"TS_GetImageSizeSide",
|
||||
@ -860,11 +852,13 @@
|
||||
"TS_Int_Slider",
|
||||
"TS_Keyer",
|
||||
"TS_LTX_FirstLastFrame",
|
||||
"TS_LamaCleanup",
|
||||
"TS_Math_Int",
|
||||
"TS_ModelConverter",
|
||||
"TS_ModelConverterAdvanced",
|
||||
"TS_ModelConverterAdvancedDirect",
|
||||
"TS_ModelScanner",
|
||||
"TS_MultiReference",
|
||||
"TS_MusicStems",
|
||||
"TS_PromptBuilder",
|
||||
"TS_Qwen3_VL_V3",
|
||||
@ -876,6 +870,7 @@
|
||||
"TS_SileroTTS",
|
||||
"TS_Smart_Switch",
|
||||
"TS_StylePromptSelector",
|
||||
"TS_SuperPrompt",
|
||||
"TS_VideoDepthNode",
|
||||
"TS_Video_Upscale_With_Model",
|
||||
"TS_WAN_SafeResize"
|
||||
@ -1297,6 +1292,7 @@
|
||||
],
|
||||
"https://github.com/Chargeuk/ComfyUI-vts-nodes": [
|
||||
[
|
||||
"VAELoader VTS",
|
||||
"VTS Add Text To list",
|
||||
"VTS Calculate Upscale Amount",
|
||||
"VTS Clean Text",
|
||||
@ -1315,8 +1311,11 @@
|
||||
"VTS Create Character Mask",
|
||||
"VTS Delete Saved Images",
|
||||
"VTS Fix Image Tags",
|
||||
"VTS Frame Interpolate",
|
||||
"VTS Image Batch Extend With Overlap",
|
||||
"VTS Image Composite Masked",
|
||||
"VTS Image Composite Masked Old",
|
||||
"VTS Image From Batch",
|
||||
"VTS Image To Disk",
|
||||
"VTS Image Upscale With Model",
|
||||
"VTS Images Crop From Masks",
|
||||
@ -1327,6 +1326,8 @@
|
||||
"VTS Merge Delimited Text",
|
||||
"VTS Merge Text",
|
||||
"VTS Merge Text Lists",
|
||||
"VTS Prompt Batcher",
|
||||
"VTS Random Prompt Builder",
|
||||
"VTS Reduce Batch Size",
|
||||
"VTS Render People Kps",
|
||||
"VTS Repeat Text As List",
|
||||
@ -1339,6 +1340,7 @@
|
||||
"VTS To Text",
|
||||
"VTS To Text List",
|
||||
"VTS VAE Decode Tiled",
|
||||
"VTSLTXAddVideoICLoRAGuide",
|
||||
"VTS_Load_Pose_Keypoints",
|
||||
"Vts Text To Batch Prompt"
|
||||
],
|
||||
@ -1346,28 +1348,6 @@
|
||||
"title_aux": "ComfyUI-vts-nodes [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/Charonartist/ComfyUI-send-eagle-pro_2": [
|
||||
[
|
||||
"Batch Send Media to Eagle",
|
||||
"Send Audio to Eagle",
|
||||
"Send Eagle with text",
|
||||
"Send Media to Eagle",
|
||||
"Send Media to Eagle (Advanced)",
|
||||
"Send Video to Eagle",
|
||||
"Send Webp Image to Eagle"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-send-eagle-pro"
|
||||
}
|
||||
],
|
||||
"https://github.com/Charonartist/comfyui-lora-random-selector": [
|
||||
[
|
||||
"LoRARandomSelector"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI LoRA Random Selector [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/ChrisColeTech/ComfyUI-Get-Random-File": [
|
||||
[
|
||||
"Get Image File By Index",
|
||||
@ -1664,14 +1644,6 @@
|
||||
"title_aux": "comfyui-djb-utils"
|
||||
}
|
||||
],
|
||||
"https://github.com/DazzleNodes/ComfyUI-DazzleSwitch": [
|
||||
[
|
||||
"DazzleSwitch"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-DazzleSwitch"
|
||||
}
|
||||
],
|
||||
"https://github.com/DeTK/ComfyUI-Switch": [
|
||||
[
|
||||
"NodeSwitch"
|
||||
@ -1972,6 +1944,7 @@
|
||||
"Base64ToImageNode by IAT",
|
||||
"FloatInputNode by IAT",
|
||||
"GPTReversePrompt by IAT",
|
||||
"ImageColorPaletteExtractor by IAT",
|
||||
"ImageMatchSize by IAT",
|
||||
"ImageResizeLongestSide by IAT",
|
||||
"ImageResizeToSDXL by IAT",
|
||||
@ -1981,6 +1954,7 @@
|
||||
"Qwen35ReversePrompt by IAT",
|
||||
"QwenKontextTranslator by IAT",
|
||||
"QwenTranslator by IAT",
|
||||
"SaveAudioMP3WithCover by IAT",
|
||||
"SeedGeneratorNode by IAT",
|
||||
"SmartPathBuilderNode by IAT",
|
||||
"TextInputNode by IAT"
|
||||
@ -3205,6 +3179,7 @@
|
||||
"MpiInt",
|
||||
"MpiJsonLoad",
|
||||
"MpiJsonSave",
|
||||
"MpiListCount",
|
||||
"MpiLogger",
|
||||
"MpiLoraModel",
|
||||
"MpiLoraModelClip",
|
||||
@ -3347,6 +3322,7 @@
|
||||
"DownloadCivitaiModel",
|
||||
"ExtraCheckpointData",
|
||||
"ExtractTagFromString",
|
||||
"MergeData",
|
||||
"PrepareCheckpoint",
|
||||
"PrepareLoRA",
|
||||
"PromptTidy",
|
||||
@ -3830,6 +3806,7 @@
|
||||
[
|
||||
"DualEndpointColorBlendScheduler",
|
||||
"GemmaAPITextEncode",
|
||||
"LightLeaksTransition",
|
||||
"MaskClampedCrop",
|
||||
"MaskClampedCropSticky"
|
||||
],
|
||||
@ -4138,6 +4115,8 @@
|
||||
"UniRigLoadMesh",
|
||||
"UniRigLoadModel",
|
||||
"UniRigLoadRiggedMesh",
|
||||
"UniRigLoadSkeletonModel",
|
||||
"UniRigLoadSkinningModel",
|
||||
"UniRigOrientationCheck",
|
||||
"UniRigPreviewRiggedMesh",
|
||||
"UniRigSaveMesh",
|
||||
@ -4549,20 +4528,6 @@
|
||||
"title_aux": "ComfyUI-Mojen-Nodeset"
|
||||
}
|
||||
],
|
||||
"https://github.com/ShammiG/ComfyUI_Text_Tools_SG": [
|
||||
[
|
||||
"Text Tools Editor-SG",
|
||||
"Text Tools Load Text FilePath-SG",
|
||||
"Text Tools Load Text-SG",
|
||||
"Text Tools Merge Text Multi-SG",
|
||||
"Text Tools Merge Text-SG",
|
||||
"Text Tools Save Text File-SG",
|
||||
"Text Tools Viewer-SG"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_Text_Tools_SG [UNSAFE]"
|
||||
}
|
||||
],
|
||||
"https://github.com/Shinsplat/ComfyUI-Shinsplat": [
|
||||
[
|
||||
"Clip Text Encode (Shinsplat)",
|
||||
@ -4740,6 +4705,7 @@
|
||||
"AdvancedSchedulerSelector",
|
||||
"ApplyPipeline",
|
||||
"AsyncDiffConfig",
|
||||
"AttentionBackendConfig",
|
||||
"BalancedConfig",
|
||||
"BitsAndBytesQuantizationConfig",
|
||||
"CheckpointSelector",
|
||||
@ -4768,6 +4734,7 @@
|
||||
"TorchAOQuantizationConfig",
|
||||
"TorchConfig",
|
||||
"UnsafeModelSelector",
|
||||
"WanSampler",
|
||||
"ZImageSampler"
|
||||
],
|
||||
{
|
||||
@ -4804,135 +4771,6 @@
|
||||
"title_aux": "PMSnodes [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/Solarish/ComfyUI-MidnightLook": [
|
||||
[
|
||||
"CameraBasicFromChaoJie",
|
||||
"CameraCombineFromChaoJie",
|
||||
"CameraJoinFromChaoJie",
|
||||
"CameraTrajectoryFromChaoJie",
|
||||
"CogVideoXFunInpaintSampler",
|
||||
"CogVideoXFunT2VSampler",
|
||||
"CogVideoXFunV2VSampler",
|
||||
"CombineFlux2Pipeline",
|
||||
"CombineQwenImagePipeline",
|
||||
"CombineWan2_2Pipeline",
|
||||
"CombineWan2_2VaceFunPipeline",
|
||||
"CombineWanPipeline",
|
||||
"CombineZImagePipeline",
|
||||
"CreateTrajectoryBasedOnKJNodes",
|
||||
"Flux2ControlSampler",
|
||||
"Flux2T2ISampler",
|
||||
"FunAttention",
|
||||
"FunCompile",
|
||||
"FunRiflex",
|
||||
"FunTextBox",
|
||||
"ImageCollectNode",
|
||||
"ImageMaximumNode",
|
||||
"ImageToCanny",
|
||||
"ImageToDepth",
|
||||
"ImageToPose",
|
||||
"LoadCogVideoXFunLora",
|
||||
"LoadCogVideoXFunModel",
|
||||
"LoadFlux2ControlNetInModel",
|
||||
"LoadFlux2ControlNetInPipeline",
|
||||
"LoadFlux2Lora",
|
||||
"LoadFlux2Model",
|
||||
"LoadFlux2TextEncoderModel",
|
||||
"LoadFlux2TransformerModel",
|
||||
"LoadFlux2VAEModel",
|
||||
"LoadQwenImageControlNetInModel",
|
||||
"LoadQwenImageControlNetInPipeline",
|
||||
"LoadQwenImageLora",
|
||||
"LoadQwenImageModel",
|
||||
"LoadQwenImageProcessor",
|
||||
"LoadQwenImageTextEncoderModel",
|
||||
"LoadQwenImageTransformerModel",
|
||||
"LoadQwenImageVAEModel",
|
||||
"LoadVaceWanTransformer3DModel",
|
||||
"LoadWan2_2FunLora",
|
||||
"LoadWan2_2FunModel",
|
||||
"LoadWan2_2Lora",
|
||||
"LoadWan2_2Model",
|
||||
"LoadWan2_2TransformerModel",
|
||||
"LoadWan2_2VaceFunModel",
|
||||
"LoadWanClipEncoderModel",
|
||||
"LoadWanFunLora",
|
||||
"LoadWanFunModel",
|
||||
"LoadWanLora",
|
||||
"LoadWanModel",
|
||||
"LoadWanTextEncoderModel",
|
||||
"LoadWanTransformerModel",
|
||||
"LoadWanVAEModel",
|
||||
"LoadZImageControlNetInModel",
|
||||
"LoadZImageControlNetInPipeline",
|
||||
"LoadZImageLora",
|
||||
"LoadZImageModel",
|
||||
"LoadZImageTextEncoderModel",
|
||||
"LoadZImageTransformerModel",
|
||||
"LoadZImageVAEModel",
|
||||
"MidnightLook-AnyToString",
|
||||
"MidnightLook-CanvasExpand",
|
||||
"MidnightLook-CropDataToBBox",
|
||||
"MidnightLook-CropForInpaint",
|
||||
"MidnightLook-DeepFaceCrop",
|
||||
"MidnightLook-DeepFaceVerify",
|
||||
"MidnightLook-Detailer",
|
||||
"MidnightLook-DisplayAny",
|
||||
"MidnightLook-ExpandCropMask",
|
||||
"MidnightLook-GrowMaskWithBlur",
|
||||
"MidnightLook-ImageCompare",
|
||||
"MidnightLook-IterativeUpscale",
|
||||
"MidnightLook-LatentSizePresets",
|
||||
"MidnightLook-LoadImageByURL",
|
||||
"MidnightLook-LoopEnd",
|
||||
"MidnightLook-LoopStart",
|
||||
"MidnightLook-MediaPipeFaceCrop",
|
||||
"MidnightLook-PasteAfterInpaint",
|
||||
"MidnightLook-PreFill",
|
||||
"MidnightLook-PresetPrompt",
|
||||
"MidnightLook-Qwen25Load",
|
||||
"MidnightLook-Qwen25Run",
|
||||
"MidnightLook-QwenGuidance",
|
||||
"MidnightLook-QwenSmartCropPad",
|
||||
"MidnightLook-SAM2Loader",
|
||||
"MidnightLook-StringToBBox",
|
||||
"MidnightLook-TextBox",
|
||||
"MidnightLook-URLLoRALoader",
|
||||
"MidnightLook-UploadToR2",
|
||||
"MidnightLook-UpscalerProvider",
|
||||
"MidnightLook-VRAMClear",
|
||||
"MidnightLook-ZImageCNLoader",
|
||||
"MidnightLook-ZImageCNSampler",
|
||||
"MidnightLook-ZImageInpaintSampler",
|
||||
"MidnightLook-ZImageLoader",
|
||||
"MidnightLook-ZImageOutpaintSampler",
|
||||
"MidnightLook-ZImagePrompt",
|
||||
"PassThroughImage",
|
||||
"QwenImageControlSampler",
|
||||
"QwenImageEditPlusSampler",
|
||||
"QwenImageEditSampler",
|
||||
"QwenImageT2VSampler",
|
||||
"VideoToCanny",
|
||||
"VideoToDepth",
|
||||
"VideoToOpenpose",
|
||||
"Wan2_2FunInpaintSampler",
|
||||
"Wan2_2FunT2VSampler",
|
||||
"Wan2_2FunV2VSampler",
|
||||
"Wan2_2I2VSampler",
|
||||
"Wan2_2T2VSampler",
|
||||
"Wan2_2VaceFunSampler",
|
||||
"WanFunInpaintSampler",
|
||||
"WanFunT2VSampler",
|
||||
"WanFunV2VSampler",
|
||||
"WanI2VSampler",
|
||||
"WanT2VSampler",
|
||||
"ZImageControlSampler",
|
||||
"ZImageT2ISampler"
|
||||
],
|
||||
{
|
||||
"title_aux": "fyUI-MidnightLook [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/Soliton80/ComfyUI-Watermark-Detection-YOLO": [
|
||||
[
|
||||
"WatermarkDetector",
|
||||
@ -4996,6 +4834,8 @@
|
||||
],
|
||||
"https://github.com/StableDiffusionVN/SDVN_Comfy_node": [
|
||||
[
|
||||
"InpaintCropImproved",
|
||||
"InpaintStitchImproved",
|
||||
"SDVM Image List Repeat",
|
||||
"SDVN API chatbot",
|
||||
"SDVN Any From List",
|
||||
@ -5459,6 +5299,17 @@
|
||||
"title_aux": "ComfyUI-yolov5-face [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/V-woodpecker-V/comfyui-stiffy-nodes": [
|
||||
[
|
||||
"StiffyComboNode",
|
||||
"StiffyComplexPresetNode",
|
||||
"StiffyDecoderNode",
|
||||
"StiffySimplePresetNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "comfyui-stiffy-nodes"
|
||||
}
|
||||
],
|
||||
"https://github.com/VectorASD/ComfyUI-VectorASD": [
|
||||
[
|
||||
"ASD_CLIPLoader",
|
||||
@ -5808,6 +5659,7 @@
|
||||
"BlenderCombineXYZ",
|
||||
"BlenderCrop",
|
||||
"BlenderGamma",
|
||||
"BlenderGradientTexture",
|
||||
"BlenderHueSaturationValue",
|
||||
"BlenderInvertColor",
|
||||
"BlenderLensDistortion",
|
||||
@ -6474,6 +6326,7 @@
|
||||
"https://github.com/baoanhng/ComfyUI-utils": [
|
||||
[
|
||||
"TextJoiner",
|
||||
"TextJoinerTags",
|
||||
"TextSplitter"
|
||||
],
|
||||
{
|
||||
@ -6495,13 +6348,13 @@
|
||||
],
|
||||
"https://github.com/basenc/Comfyui-Nodes-basenc": [
|
||||
[
|
||||
"ChatMessagesCreate",
|
||||
"CustomOpenAIChatCompletion",
|
||||
"CustomOpenAIResponse",
|
||||
"DimensionsPresetPicker",
|
||||
"EnvVarNode",
|
||||
"Eval",
|
||||
"JMESPathSelect",
|
||||
"RescaleToDimensions",
|
||||
"ResponseInputAppend",
|
||||
"WanVideoSize"
|
||||
],
|
||||
{
|
||||
@ -7167,6 +7020,7 @@
|
||||
"https://github.com/comfyanonymous/ComfyUI": [
|
||||
[
|
||||
"APG",
|
||||
"ARVideoI2V",
|
||||
"AddNoise",
|
||||
"AlignYourStepsScheduler",
|
||||
"AudioAdjustVolume",
|
||||
@ -7190,6 +7044,8 @@
|
||||
"ByteDance2FirstLastFrameNode",
|
||||
"ByteDance2ReferenceNode",
|
||||
"ByteDance2TextToVideoNode",
|
||||
"ByteDanceCreateImageAsset",
|
||||
"ByteDanceCreateVideoAsset",
|
||||
"ByteDanceFirstLastFrameNode",
|
||||
"ByteDanceImageNode",
|
||||
"ByteDanceImageReferenceNode",
|
||||
@ -7275,6 +7131,7 @@
|
||||
"ElevenLabsTextToSoundEffects",
|
||||
"ElevenLabsTextToSpeech",
|
||||
"ElevenLabsVoiceSelector",
|
||||
"EmptyARVideoLatent",
|
||||
"EmptyAceStep1.5LatentAudio",
|
||||
"EmptyAceStepLatentAudio",
|
||||
"EmptyAudio",
|
||||
@ -7307,6 +7164,8 @@
|
||||
"FluxProExpandNode",
|
||||
"FluxProFillNode",
|
||||
"FluxProUltraImageNode",
|
||||
"FrameInterpolate",
|
||||
"FrameInterpolationModelLoader",
|
||||
"FreSca",
|
||||
"FreeU",
|
||||
"FreeU_V2",
|
||||
@ -7318,6 +7177,7 @@
|
||||
"GeminiImageNode",
|
||||
"GeminiInputFiles",
|
||||
"GeminiNanoBanana2",
|
||||
"GeminiNanoBanana2V2",
|
||||
"GeminiNode",
|
||||
"GenerateTracks",
|
||||
"GetImageSize",
|
||||
@ -7329,6 +7189,10 @@
|
||||
"GrokVideoNode",
|
||||
"GrokVideoReferenceNode",
|
||||
"GrowMask",
|
||||
"HappyHorseImageToVideoApi",
|
||||
"HappyHorseReferenceVideoApi",
|
||||
"HappyHorseTextToVideoApi",
|
||||
"HappyHorseVideoEditApi",
|
||||
"HitPawGeneralImageEnhance",
|
||||
"HitPawVideoEnhance",
|
||||
"Hunyuan3Dv2Conditioning",
|
||||
@ -7413,7 +7277,6 @@
|
||||
"LTXAVTextEncoderLoader",
|
||||
"LTXVAddGuide",
|
||||
"LTXVAudioVAEDecode",
|
||||
"LTXVAudioVAEEncode",
|
||||
"LTXVAudioVAELoader",
|
||||
"LTXVConcatAVLatent",
|
||||
"LTXVConditioning",
|
||||
@ -7453,6 +7316,7 @@
|
||||
"LazyCache",
|
||||
"Load3D",
|
||||
"LoadAudio",
|
||||
"LoadBackgroundRemovalModel",
|
||||
"LoadImage",
|
||||
"LoadImageDataSetFromFolder",
|
||||
"LoadImageMask",
|
||||
@ -7472,8 +7336,10 @@
|
||||
"LtxvApiImageToVideo",
|
||||
"LtxvApiTextToVideo",
|
||||
"LumaConceptsNode",
|
||||
"LumaImageEditNode2",
|
||||
"LumaImageModifyNode",
|
||||
"LumaImageNode",
|
||||
"LumaImageNode2",
|
||||
"LumaImageToVideoNode",
|
||||
"LumaReferenceNode",
|
||||
"LumaVideoNode",
|
||||
@ -7529,9 +7395,6 @@
|
||||
"ModelSamplingSD3",
|
||||
"ModelSamplingStableCascade",
|
||||
"ModelSave",
|
||||
"MoonvalleyImg2VideoNode",
|
||||
"MoonvalleyTxt2VideoNode",
|
||||
"MoonvalleyVideo2VideoNode",
|
||||
"Morphology",
|
||||
"NAGuidance",
|
||||
"NormalizeVideoLatentStart",
|
||||
@ -7542,6 +7405,7 @@
|
||||
"OpenAIGPTImage1",
|
||||
"OpenAIInputFiles",
|
||||
"OpenAIVideoSora2",
|
||||
"OpticalFlowLoader",
|
||||
"OptimalStepsScheduler",
|
||||
"Painter",
|
||||
"PatchModelAddDownscale",
|
||||
@ -7595,6 +7459,7 @@
|
||||
"RegexExtract",
|
||||
"RegexMatch",
|
||||
"RegexReplace",
|
||||
"RemoveBackground",
|
||||
"RenormCFG",
|
||||
"RepeatImageBatch",
|
||||
"RepeatLatentBatch",
|
||||
@ -7616,6 +7481,10 @@
|
||||
"RunwayImageToVideoNodeGen3a",
|
||||
"RunwayImageToVideoNodeGen4",
|
||||
"RunwayTextToImageNode",
|
||||
"SAM3_Detect",
|
||||
"SAM3_TrackPreview",
|
||||
"SAM3_TrackToMask",
|
||||
"SAM3_VideoTrack",
|
||||
"SDPoseDrawKeypoints",
|
||||
"SDPoseFaceBBoxes",
|
||||
"SDPoseKeypointExtractor",
|
||||
@ -7624,6 +7493,7 @@
|
||||
"SUPIRApply",
|
||||
"SV3D_Conditioning",
|
||||
"SVD_img2vid_Conditioning",
|
||||
"SamplerARVideo",
|
||||
"SamplerCustom",
|
||||
"SamplerCustomAdvanced",
|
||||
"SamplerDPMAdaptative",
|
||||
@ -7769,6 +7639,7 @@
|
||||
"TomePatchModel",
|
||||
"TopazImageEnhance",
|
||||
"TopazVideoEnhance",
|
||||
"TopazVideoEnhanceV2",
|
||||
"TorchCompileModel",
|
||||
"TrainLoraNode",
|
||||
"TrimAudioDuration",
|
||||
@ -7799,8 +7670,14 @@
|
||||
"VAEEncodeTiled",
|
||||
"VAELoader",
|
||||
"VAESave",
|
||||
"VOIDInpaintConditioning",
|
||||
"VOIDQuadmaskPreprocess",
|
||||
"VOIDSampler",
|
||||
"VOIDWarpedNoise",
|
||||
"VOIDWarpedNoiseSource",
|
||||
"VPScheduler",
|
||||
"Veo3FirstLastFrameNode",
|
||||
"Veo3VideoGenerationNode",
|
||||
"VeoVideoGenerationNode",
|
||||
"Video Slice",
|
||||
"VideoLinearCFGGuidance",
|
||||
@ -9121,6 +8998,7 @@
|
||||
"HolafLutGenerator",
|
||||
"HolafLutSaver",
|
||||
"HolafMaskToBoolean",
|
||||
"HolafNucleusImage",
|
||||
"HolafOverlayNode",
|
||||
"HolafRemote",
|
||||
"HolafRemoteSelector",
|
||||
@ -10509,15 +10387,6 @@
|
||||
"title_aux": "ComfyUI_was_image"
|
||||
}
|
||||
],
|
||||
"https://github.com/krakenunbound/kraken-discord-bot": [
|
||||
[
|
||||
"KrakenDiscordBot",
|
||||
"KrakenDiscordBotStatus"
|
||||
],
|
||||
{
|
||||
"title_aux": "Kraken Discord Bot"
|
||||
}
|
||||
],
|
||||
"https://github.com/krich-cto/ComfyUI-Flow-Control": [
|
||||
[
|
||||
"CLIPLoaderGGUF",
|
||||
@ -10656,18 +10525,25 @@
|
||||
],
|
||||
"https://github.com/lazybuttalented/ComfyUI_LBT": [
|
||||
[
|
||||
"LBT_BooleanAND",
|
||||
"LBT_CombineImagesFromBatch",
|
||||
"LBT_CombineImagesFromList",
|
||||
"LBT_CropByMask",
|
||||
"LBT_GetFolderInfo",
|
||||
"LBT_ListInfo",
|
||||
"LBT_LoadImageFromPath",
|
||||
"LBT_LoadImagesFromFolder",
|
||||
"LBT_LoadImagesFromList",
|
||||
"LBT_LoadMultilineText",
|
||||
"LBT_LoadTextFromFolder",
|
||||
"LBT_LoadVideoFromFolder",
|
||||
"LBT_SaveImage",
|
||||
"LBT_SaveVideo",
|
||||
"LBT_ShowTextEditable",
|
||||
"LBT_StringToList",
|
||||
"LBT_TextImageLibraryComparison"
|
||||
"LBT_SwitchNoPause",
|
||||
"LBT_TextImageLibraryComparison",
|
||||
"LBT_TextKeywordMatch"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_LBT [WIP]"
|
||||
@ -11340,12 +11216,18 @@
|
||||
"KM_Aspect_Ratio_Selector2",
|
||||
"KM_CFGGuider",
|
||||
"KM_Color_Correct",
|
||||
"KM_Color_Match",
|
||||
"KM_Downscale_Image",
|
||||
"KM_Extract_Images",
|
||||
"KM_Merge_Images",
|
||||
"KM_Resize_Image",
|
||||
"KM_Resize_Image_With_Model",
|
||||
"KM_Safe_Mask_Bounds",
|
||||
"KM_Safe_SEGS_Bounds",
|
||||
"KM_Select_Every_Nth_Image",
|
||||
"KM_Select_Image",
|
||||
"KM_Split_Images",
|
||||
"KM_Video_Blend",
|
||||
"KM_Video_Image_Color_Match",
|
||||
"KM_WanVideoToVideo",
|
||||
"WanImageToVideo"
|
||||
@ -11755,6 +11637,45 @@
|
||||
"title_aux": "ComfyUI-TextOverlay"
|
||||
}
|
||||
],
|
||||
"https://github.com/nekotxt/ComfyUI-NTX-support-nodes": [
|
||||
[
|
||||
"ApplyLoraStack",
|
||||
"AutogrowNode",
|
||||
"CLIPTextEncodeWithCutoff",
|
||||
"CollectModelNtxdata",
|
||||
"ConvertLoraStackToString",
|
||||
"ConvertLoraStringToStack",
|
||||
"CreateImageLatent",
|
||||
"DictGet",
|
||||
"DictSet",
|
||||
"DictSetMulti",
|
||||
"DynamicComboNode",
|
||||
"DynamicTwinNode",
|
||||
"GenerationDataGet",
|
||||
"GenerationDataMaxSize",
|
||||
"GenerationDataSet",
|
||||
"ListCount",
|
||||
"ListGet",
|
||||
"ListSet",
|
||||
"LoadCharInfo",
|
||||
"LoadCharacterInfo",
|
||||
"LoadCheckpointInfo",
|
||||
"LoadCustomVae",
|
||||
"LoraStack",
|
||||
"MergeLoraStacks",
|
||||
"PipeBase",
|
||||
"PromptChainer",
|
||||
"ReplaceTextParameters",
|
||||
"RerouteBase",
|
||||
"SaveMultipleImages",
|
||||
"SwitchAny",
|
||||
"SwitchNode",
|
||||
"Test"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-NTX-support-nodes [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/neo0801/my-comfy-node": [
|
||||
[
|
||||
"DeepMosaicGetImageMosaicMask",
|
||||
@ -11889,9 +11810,11 @@
|
||||
"LoRATextDualInput",
|
||||
"LoraToCivitaiUrl",
|
||||
"LoraWildcardGenerator",
|
||||
"LoraWildcardGeneratorV2",
|
||||
"RepeatTextLines",
|
||||
"SDPromptSaverOptimized",
|
||||
"SDPromptSaverWithCompression",
|
||||
"SeedStepN",
|
||||
"TIPONobinCustom",
|
||||
"TextSplit3"
|
||||
],
|
||||
{
|
||||
@ -12334,6 +12257,7 @@
|
||||
"przewodo ImageScaleFactor",
|
||||
"przewodo ImageSizer",
|
||||
"przewodo IsInputDisabled",
|
||||
"przewodo LTXVAEDriftFix",
|
||||
"przewodo LtxKeyFrameIndexes",
|
||||
"przewodo SendFirstValidValue",
|
||||
"przewodo SwapAnyComparison",
|
||||
@ -12405,38 +12329,6 @@
|
||||
"title_aux": "ComfyUI-Qimi-Tiler"
|
||||
}
|
||||
],
|
||||
"https://github.com/qlikpetersen/ComfyUI-AI_Tools": [
|
||||
[
|
||||
"CreateListJSON",
|
||||
"CreateListString",
|
||||
"DoLogin",
|
||||
"FixLinksAndRevLinks",
|
||||
"HttpRequest",
|
||||
"Image_Attachment",
|
||||
"IncludeInSpiderData",
|
||||
"JSON_Attachment",
|
||||
"Json2String",
|
||||
"LoadSpiderData",
|
||||
"PNGtoImage",
|
||||
"Query_OpenAI",
|
||||
"RemoveCircularReferences",
|
||||
"RunPython",
|
||||
"RunPythonGriptapeTool",
|
||||
"SaveSpiderData",
|
||||
"SpiderCrawl",
|
||||
"SpiderSplit",
|
||||
"String2Json",
|
||||
"String_Attachment",
|
||||
"TextMultiSave"
|
||||
],
|
||||
{
|
||||
"author": "kierdran",
|
||||
"description": "Tools for agentic testing",
|
||||
"nickname": "ai_tools",
|
||||
"title": "AI_Tools",
|
||||
"title_aux": "ComfyUI-AI_Tools [UNSAFE]"
|
||||
}
|
||||
],
|
||||
"https://github.com/quinteroac/comfyui_api_executor_nodes": [
|
||||
[
|
||||
"AnyTo",
|
||||
@ -12599,6 +12491,7 @@
|
||||
"Seed 32-bit [Eclipse]",
|
||||
"Seed [Eclipse]",
|
||||
"Show Any [Eclipse]",
|
||||
"Show Text [Eclipse]",
|
||||
"Smart Detection [Eclipse]",
|
||||
"Smart Detection [SML]",
|
||||
"Smart Folder [Eclipse]",
|
||||
@ -12869,12 +12762,18 @@
|
||||
"Canny Edge",
|
||||
"Combine RGB Channels",
|
||||
"Create Empty Frames",
|
||||
"Crop Guide Frames",
|
||||
"Get Image Dimensions",
|
||||
"Image Grayscale",
|
||||
"LTXVMultiKeyframeGuide",
|
||||
"LTXVMultiLatentGuide",
|
||||
"Load Image Folder",
|
||||
"Load Images",
|
||||
"Load Images From List",
|
||||
"Pad Batch to 4n+1",
|
||||
"Pad Batch to kn+1",
|
||||
"Repeat Frames",
|
||||
"Resample Frames",
|
||||
"Resize Frame",
|
||||
"Save Image Folder",
|
||||
"Select Image From Batch",
|
||||
@ -13541,40 +13440,6 @@
|
||||
"title_aux": "ComfyUI-StalkerVr"
|
||||
}
|
||||
],
|
||||
"https://github.com/stalkervr/comfyui-custom-path-nodes": [
|
||||
[
|
||||
"AnyCollector",
|
||||
"ContextPipeIn",
|
||||
"ContextPipeOut",
|
||||
"ContextPipeReroute",
|
||||
"DataFileLoader",
|
||||
"ImageAspectRatioFixer",
|
||||
"ImageBatchCrop",
|
||||
"ImageGridCropper",
|
||||
"JsonArraySplitter",
|
||||
"JsonFieldRemover",
|
||||
"JsonFieldReplaceAdvanced",
|
||||
"JsonFieldValueExtractor",
|
||||
"JsonPathLoader",
|
||||
"JsonPromptToTextPromptConverter",
|
||||
"JsonToString",
|
||||
"ListItemExtractor",
|
||||
"LoopAny",
|
||||
"PathPipeIn",
|
||||
"PathPipeOut",
|
||||
"PathPipeReroute",
|
||||
"PromptPartJoin",
|
||||
"SavePath",
|
||||
"StringCollector",
|
||||
"StringConcatenation",
|
||||
"StringListToString",
|
||||
"StringWrapper",
|
||||
"WanVideoMultiPrompt"
|
||||
],
|
||||
{
|
||||
"title_aux": "comfyui-custom-path-nodes [UNSAFE]"
|
||||
}
|
||||
],
|
||||
"https://github.com/starsFriday/ComfyUI-Audio-Subtitle": [
|
||||
[
|
||||
"AudioSubtitle"
|
||||
@ -13765,7 +13630,8 @@
|
||||
"Supaidauen_Text_Concat",
|
||||
"Supaidauen_Text_Replace",
|
||||
"Supaidauen_Text_Wildcard",
|
||||
"Supaidauen_Text_w_Options_Replace_LoRA"
|
||||
"Supaidauen_Text_w_Options_Replace_LoRA",
|
||||
"Supaidauen_ZippedPromptFromTextAdvanced"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-supaidauen [WIP]"
|
||||
@ -13944,14 +13810,6 @@
|
||||
"title_aux": "mc_audio"
|
||||
}
|
||||
],
|
||||
"https://github.com/tfernd/ComfyUI-AutoCPUOffload": [
|
||||
[
|
||||
"AutoCPUOffload"
|
||||
],
|
||||
{
|
||||
"title_aux": "Auto CPU Offload for ComfyUI [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/tg-tjmitchell/comfyui-custom-node-lister": [
|
||||
[
|
||||
"CustomNodeLister"
|
||||
@ -15052,20 +14910,6 @@
|
||||
"title_aux": "ComfyUI-SEQLToolNode"
|
||||
}
|
||||
],
|
||||
"https://github.com/yojimbodayne/ComfyUI-Dropbox-API": [
|
||||
[
|
||||
"FetchTokenFromDropbox",
|
||||
"PostImagesToDropboxAPI",
|
||||
"PostPromptsToDropboxAPI",
|
||||
"PullImagesFromDropboxAPI",
|
||||
"PullTextFromDropboxAPI",
|
||||
"PullVideosFromDropboxAPI",
|
||||
"VideoCombineAndExportToDropboxAPI"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-Dropbox-API [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/yuvraj108c/ComfyUI-HYPIR": [
|
||||
[
|
||||
"HYPIRProcess",
|
||||
@ -15223,6 +15067,7 @@
|
||||
"MultiLineOperationZV",
|
||||
"PatternFillNodeZV",
|
||||
"ProductionDisplacementMapNodeZV",
|
||||
"PromptSelectorWithTimeoutZV",
|
||||
"RandomSelectListZV",
|
||||
"SaveImageToPathZV",
|
||||
"SaveTxtToPathZV",
|
||||
@ -15231,6 +15076,7 @@
|
||||
"TxtCounterNodeZV",
|
||||
"UniversalBBOXToMaskZV",
|
||||
"Veo31Image2VideoSubmitZV",
|
||||
"VideoCounterNodeZV",
|
||||
"VideoGeneratorFFmpegZV",
|
||||
"VideoSceneDetectorZV",
|
||||
"VideoSpeedZV",
|
||||
@ -15255,21 +15101,6 @@
|
||||
"title_aux": "ComfyUI-prompt-library"
|
||||
}
|
||||
],
|
||||
"https://github.com/zinigo-creations/comfyui-prompt-builder": [
|
||||
[
|
||||
"ActionNode",
|
||||
"CharacterNode",
|
||||
"CombinePromptNode",
|
||||
"CompositionNode",
|
||||
"EnvironmentNode",
|
||||
"NSFWNode",
|
||||
"PresetCharacterNode",
|
||||
"StylePresetNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "Prompt Builder [NAME CONFLICT]"
|
||||
}
|
||||
],
|
||||
"https://github.com/zjkhurry/comfyui_MetalFX": [
|
||||
[
|
||||
"metalFXImg"
|
||||
@ -15315,14 +15146,6 @@
|
||||
"title_aux": "ComfyUI Stash"
|
||||
}
|
||||
],
|
||||
"https://raw.githubusercontent.com/jp0215/comfyUI_padding-resize_node/main/PaddingNode.py": [
|
||||
[
|
||||
"function"
|
||||
],
|
||||
{
|
||||
"title_aux": "comfyUI_padding-resize_node"
|
||||
}
|
||||
],
|
||||
"https://raw.githubusercontent.com/komojini/ComfyUI_Prompt_Template_CustomNodes/main/prompt_with_template.py": [
|
||||
[
|
||||
"ObjectPromptWithTemplate",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,125 @@
|
||||
{
|
||||
"custom_nodes": [
|
||||
{
|
||||
"author": "yojimbodayne",
|
||||
"title": "ComfyUI-Dropbox-API [WIP] [REMOVED]",
|
||||
"reference": "https://github.com/yojimbodayne/ComfyUI-Dropbox-API",
|
||||
"files": [
|
||||
"https://github.com/yojimbodayne/ComfyUI-Dropbox-API"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This custom nodepackage for ComfyUI allows users to interact with Dropbox API, enabling image, text, and video uploads, downloads, and management directly from ComfyUI workflows.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "tfernd",
|
||||
"title": "Auto CPU Offload for ComfyUI [WIP] [REMOVED]",
|
||||
"reference": "https://github.com/tfernd/ComfyUI-AutoCPUOffload",
|
||||
"files": [
|
||||
"https://github.com/tfernd/ComfyUI-AutoCPUOffload"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This extension introduces an 'Auto CPU Offload' node designed to reduce GPU VRAM usage by automatically offloading model components to the CPU. It intelligently manages the movement of model layers between the GPU and CPU, aiming to keep only the necessary parts in VRAM during inference."
|
||||
},
|
||||
{
|
||||
"author": "stalkervr",
|
||||
"title": "Custom Path Nodes for ComfyUI [UNSAFE] [REMOVED]",
|
||||
"reference": "https://github.com/stalkervr/comfyui-custom-path-nodes",
|
||||
"files": [
|
||||
"https://github.com/stalkervr/comfyui-custom-path-nodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes for path handling and image cropping.[w/This nodepack contains a node that has a vulnerability allowing access to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI-send-eagle-pro [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/ComfyUI-send-eagle-pro_2",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/ComfyUI-send-eagle-pro_2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Eagle integration extension node for ComfyUI (Pro version)"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI LoRA Random Selector [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-lora-random-selector",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-lora-random-selector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: WanMoeKSampler, WanMoeKSamplerAdvanced"
|
||||
},
|
||||
{
|
||||
"author": "bpmpnaito",
|
||||
"title": "comfyui-imageviewer [REMOVED]",
|
||||
"reference": "https://github.com/bpmpnaito/comfyui-imageviewer",
|
||||
"files": [
|
||||
"https://github.com/bpmpnaito/comfyui-imageviewer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Image viewer node that displays preview of images directly in the node."
|
||||
},
|
||||
{
|
||||
"author": "leonardomiramondi",
|
||||
"title": "Flux Context ComfyUI Node [REMOVED]",
|
||||
"reference": "https://github.com/leonardomiramondi/flux-context-comfyui",
|
||||
"files": [
|
||||
"https://github.com/leonardomiramondi/flux-context-comfyui"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node for Flux Context (Kontext) image editing"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "comfyui-lmstudio-conversation [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-lmstudio-conversation",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-lmstudio-conversation"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for LM Studio integration with conversation history support "
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "comfyui-last-frame-extractor [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-last-frame-extractor",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-last-frame-extractor"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a ComfyUI custom node that extracts the last frame (image) from an input image batch. It is particularly useful when you want to obtain the final scene or frame in a video generation workflow."
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI Tag Remover [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-tag-remover",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-tag-remover"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node for removing specified tags and their content from text"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI Smart Resize Node [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-smart-resize-node",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-smart-resize-node"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Smart resize node for ComfyUI that handles portrait/landscape images with short/long side specification"
|
||||
},
|
||||
{
|
||||
"author": "Charonartist",
|
||||
"title": "ComfyUI Auto LoRA [REMOVED]",
|
||||
"reference": "https://github.com/Charonartist/comfyui-auto-lora-v2",
|
||||
"files": [
|
||||
"https://github.com/Charonartist/comfyui-auto-lora-v2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a ComfyUI custom node that automatically detects trigger words from text prompts and applies the corresponding LoRA models."
|
||||
},
|
||||
{
|
||||
"author": "qlikpetersen",
|
||||
"title": "ComfyUI-AI_Tools [UNSAFE] [REMOVED]",
|
||||
|
||||
@ -1,5 +1,385 @@
|
||||
{
|
||||
"custom_nodes": [
|
||||
{
|
||||
"author": "artemko7v",
|
||||
"title": "ComfyUI Complex Prompt Nodes",
|
||||
"reference": "https://github.com/ArtemKo7v/ComfyUI-Complex-Prompt",
|
||||
"files": [
|
||||
"https://github.com/ArtemKo7v/ComfyUI-Complex-Prompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node for working with complex prompts with support for variables, randomness, and basic logic."
|
||||
},
|
||||
{
|
||||
"author": "orion4d",
|
||||
"title": "Orion4D_AutoCachedPreview",
|
||||
"reference": "https://github.com/orion4d/Orion4D_AutoCachedPreview",
|
||||
"files": [
|
||||
"https://github.com/orion4d/Orion4D_AutoCachedPreview"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A custom node for ComfyUI that allows you to cache an image and its mask to avoid recalculating upstream steps in your workflow."
|
||||
},
|
||||
{
|
||||
"author": "alikonfilms",
|
||||
"title": "comfyui-alikonfilms",
|
||||
"reference": "https://github.com/alikonfilms/comfyui_alikonfilms",
|
||||
"files": [
|
||||
"https://github.com/alikonfilms/comfyui_alikonfilms"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A CLIP text encoder with 18 cinematic camera movement presets (dolly, pan, tilt, zoom, orbit and more). Subject-aware and free-camera modes, blend slider to mix your prompt with camera movements, and a live text output to preview the final prompt."
|
||||
},
|
||||
{
|
||||
"author": "mexxmillion",
|
||||
"title": "ComfyUI-VLMPrompt",
|
||||
"reference": "https://github.com/mexxmillion/ComfyUI-VLMPrompt",
|
||||
"files": [
|
||||
"https://github.com/mexxmillion/ComfyUI-VLMPrompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for local VLM prompt generation with GGUF and Hugging Face backends."
|
||||
},
|
||||
{
|
||||
"author": "hassan-mb",
|
||||
"title": "HB ComfyUI Nodes",
|
||||
"reference": "https://github.com/HassanEclipse/comfyui-hb-party",
|
||||
"files": [
|
||||
"https://github.com/HassanEclipse/comfyui-hb-party"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Utility nodes for ComfyUI featuring a dynamic Text Preset Switch with workflow-safe persistence and Node 2.0 support."
|
||||
},
|
||||
{
|
||||
"author": "rikanrino",
|
||||
"title": "Rikannodes",
|
||||
"reference": "https://github.com/rikanrino/Rikannodes",
|
||||
"files": [
|
||||
"https://github.com/rikanrino/Rikannodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "kijai ComfyUI-PromptRelay with fps and max frame output"
|
||||
},
|
||||
{
|
||||
"author": "Cordux",
|
||||
"title": "ComfyUI-PromptTagBuilder",
|
||||
"reference": "https://github.com/Cordux/ComfyUI-PromptTagBuilder",
|
||||
"files": [
|
||||
"https://github.com/Cordux/ComfyUI-PromptTagBuilder"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Flexible ComfyUI node that simplifies prompt building through organized dropdown categories for tag-based models."
|
||||
},
|
||||
{
|
||||
"author": "GeekatplayStudio",
|
||||
"title": "ComfyUI-cluster",
|
||||
"reference": "https://github.com/GeekatplayStudio/ComfyUI-cluster",
|
||||
"files": [
|
||||
"https://github.com/GeekatplayStudio/ComfyUI-cluster"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Ollama-driven routing nodes and curated workflows for ComfyUI with checkpoint, LoRA, and Flux split-component flows plus image-guided variants using vision analysis."
|
||||
},
|
||||
{
|
||||
"author": "cowneko",
|
||||
"title": "CWK_Checkpoints_Preset_Manager",
|
||||
"reference": "https://github.com/cowneko/CWK_Checkpoints_Preset_Manager",
|
||||
"files": [
|
||||
"https://github.com/cowneko/CWK_Checkpoints_Preset_Manager"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node combining per-model preset system with full-featured model manager, CivitAI integration, and GGUF support for browsing and organizing checkpoints."
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-NativeLooping_testing",
|
||||
"reference": "https://github.com/kijai/ComfyUI-NativeLooping_testing",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-NativeLooping_testing"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Temporary repository for testing candidate for native ComfyUI loop nodes. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "IA-gyz",
|
||||
"title": "comfyui-VarBoard",
|
||||
"reference": "https://github.com/IA-gyz/comfyui-VarBoard",
|
||||
"files": [
|
||||
"https://github.com/IA-gyz/comfyui-VarBoard"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Variables Board is a floating control center for ComfyUI workflows that centralizes parameters into a customizable overlay."
|
||||
},
|
||||
{
|
||||
"author": "wsq194",
|
||||
"title": "Yeban Workflow Manager",
|
||||
"reference": "https://github.com/wsq194/yeban-workflow-manager",
|
||||
"files": [
|
||||
"https://github.com/wsq194/yeban-workflow-manager"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI workflow manager plugin with auto-save, version history, sidebar integration and more."
|
||||
},
|
||||
{
|
||||
"author": "nekodificador",
|
||||
"title": "NKD Klein Tools",
|
||||
"reference": "https://github.com/Nekodificador/ComfyUI-NKD-Klein-Tools",
|
||||
"files": [
|
||||
"https://github.com/Nekodificador/ComfyUI-NKD-Klein-Tools"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NKD Klein Presampling and Postsampling nodes for Flux Klein workflows in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "szymonj",
|
||||
"title": "LoRA Range Loader",
|
||||
"reference": "https://github.com/esp-dev/comfyui-lora-range-loader",
|
||||
"files": [
|
||||
"https://github.com/esp-dev/comfyui-lora-range-loader"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node: load a LoRA from current selection and automatically advance current within a first/last filename range."
|
||||
},
|
||||
{
|
||||
"author": "brosequist",
|
||||
"title": "comfyui-pipeline-barrier",
|
||||
"reference": "https://github.com/brosequist/ComfyUI-PipelineBarrier",
|
||||
"files": [
|
||||
"https://github.com/brosequist/ComfyUI-PipelineBarrier"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node that force-flushes GPU caches between pipeline stages to prevent OOM kills"
|
||||
},
|
||||
{
|
||||
"author": "artemko7v",
|
||||
"title": "ComfyUI Prompt Enhance Nodes",
|
||||
"reference": "https://github.com/ArtemKo7v/ComfyUI-Prompt-Magic",
|
||||
"files": [
|
||||
"https://github.com/ArtemKo7v/ComfyUI-Prompt-Magic"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI prompt enhance nodes and string utilities"
|
||||
},
|
||||
{
|
||||
"author": "mitch-avis",
|
||||
"title": "ComfyUI-HoldCounter",
|
||||
"reference": "https://github.com/mitch-avis/ComfyUI-HoldCounter",
|
||||
"files": [
|
||||
"https://github.com/mitch-avis/ComfyUI-HoldCounter"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node that emits a held, range-bound integer index with multiple advancement modes (loop, clamp, pingpong, random, shuffle) — useful as a Load Image batch index that advances every N runs."
|
||||
},
|
||||
{
|
||||
"author": "capacap",
|
||||
"title": "ComfyUI-Selective-Sigma-Detailer",
|
||||
"reference": "https://github.com/Capacap/ComfyUI-Selective-Sigma-Detailer",
|
||||
"files": [
|
||||
"https://github.com/Capacap/ComfyUI-Selective-Sigma-Detailer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI sampler that boosts detail only in latent regions that are already dense at the moment the schedule activates."
|
||||
},
|
||||
{
|
||||
"author": "xav",
|
||||
"title": "XAV Anima Style Selector",
|
||||
"reference": "https://github.com/XAV-Games/comfyui-xav-anima-style-selector",
|
||||
"files": [
|
||||
"https://github.com/XAV-Games/comfyui-xav-anima-style-selector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for quick and easy style selection for the Anima model"
|
||||
},
|
||||
{
|
||||
"author": "xxchinenxx",
|
||||
"title": "Qwen Clothing Selector",
|
||||
"reference": "https://github.com/xxchinenxx/ComfyUI-QwenClothingSelector",
|
||||
"files": [
|
||||
"https://github.com/xxchinenxx/ComfyUI-QwenClothingSelector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for Qwen-Image-Edit outfit/clothing edits — toggles, presets, and identity-preserving prompt builders. Useful for fashion edits, costume changes, and outfit swaps."
|
||||
},
|
||||
{
|
||||
"author": "halr9000",
|
||||
"title": "Procgen 9000",
|
||||
"reference": "https://github.com/halr9000/procgen9000",
|
||||
"files": [
|
||||
"https://github.com/halr9000/procgen9000"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Procedural image generation toolkit designed as input to image edit workflows."
|
||||
},
|
||||
{
|
||||
"author": "amrnidal999-tech",
|
||||
"title": "Realisim Enhancor",
|
||||
"reference": "https://github.com/amrnidal999-tech/comfyui-realisim-enhancor",
|
||||
"files": [
|
||||
"https://github.com/amrnidal999-tech/comfyui-realisim-enhancor"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI image enhancement node with JPEG degradation, noise, blur, sharpening, contrast, and color controls."
|
||||
},
|
||||
{
|
||||
"author": "xmarre",
|
||||
"title": "ComfyUI-TIDE",
|
||||
"reference": "https://github.com/xmarre/ComfyUI-TIDE",
|
||||
"files": [
|
||||
"https://github.com/xmarre/ComfyUI-TIDE"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node implementing TIDE (Text-Informed Dynamic Extrapolation with Step-Aware Temperature Control) for diffusion models."
|
||||
},
|
||||
{
|
||||
"author": "xmarre",
|
||||
"title": "ComfyUI-DiffAid-Patches",
|
||||
"reference": "https://github.com/xmarre/ComfyUI-DiffAid-Patches",
|
||||
"files": [
|
||||
"https://github.com/xmarre/ComfyUI-DiffAid-Patches"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI custom node pack implementing Diff-Aid-inspired inference-time text-conditioning patches for Flux and SDXL models."
|
||||
},
|
||||
{
|
||||
"author": "wos-ai-studio",
|
||||
"title": "ComfyUI-Title-Memo",
|
||||
"reference": "https://github.com/xujianjian2004/ComfyUI-Title-Memo",
|
||||
"files": [
|
||||
"https://github.com/xujianjian2004/ComfyUI-Title-Memo"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A lightweight ComfyUI canvas annotation node with rich styling, built-in presets, and custom presets."
|
||||
},
|
||||
{
|
||||
"author": "takkun",
|
||||
"title": "ComfyUI-StepByStep-Sampler",
|
||||
"reference": "https://github.com/TakkunRed/ComfyUI-StepByStep-Sampler",
|
||||
"files": [
|
||||
"https://github.com/TakkunRed/ComfyUI-StepByStep-Sampler"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI StepByStep Sampler is a plugin for ComfyUI that provides a step-by-step sampling method for image generation. It allows users to generate images in a more controlled and iterative manner, making it easier to achieve desired results."
|
||||
},
|
||||
{
|
||||
"author": "marduk191",
|
||||
"title": "comfyui-nucleus",
|
||||
"reference": "https://github.com/marduk191/comfyui-nucleus",
|
||||
"files": [
|
||||
"https://github.com/marduk191/comfyui-nucleus"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nucleus Image (MoE diffusion) support for ComfyUI — backport of PR #13471"
|
||||
},
|
||||
{
|
||||
"author": "ussaaron",
|
||||
"title": "FrameFuse",
|
||||
"reference": "https://github.com/headline-design/comfyui-framefuse",
|
||||
"files": [
|
||||
"https://github.com/headline-design/comfyui-framefuse"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for stitching a still frame onto the start or end of an IMAGE video batch and trimming extra tail frames with optional audio sync alignment."
|
||||
},
|
||||
{
|
||||
"author": "eniewold",
|
||||
"title": "Subworkflow (reusable workflows)",
|
||||
"reference": "https://github.com/eniewold/ComfyUI-Subworkflow",
|
||||
"files": [
|
||||
"https://github.com/eniewold/ComfyUI-Subworkflow"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Use ComfyUI workflows as reusable subworkflows via Subworkflow Input, Subworkflow Output, and Subworkflow nodes"
|
||||
},
|
||||
{
|
||||
"author": "machinedelusions",
|
||||
"title": "ComfyUI-FL-LTXTools",
|
||||
"reference": "https://github.com/filliptm/ComfyUI-FL-LTXTools",
|
||||
"files": [
|
||||
"https://github.com/filliptm/ComfyUI-FL-LTXTools"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Experimental tools and motion controls for LTX-Video in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "serhiiyashyn-sf",
|
||||
"title": "Face-Aligned Center",
|
||||
"reference": "https://github.com/serhiiyashyn-sf/comfyui-face-aligned-center",
|
||||
"files": [
|
||||
"https://github.com/serhiiyashyn-sf/comfyui-face-aligned-center"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Batch-aware character centering for ComfyUI. Given a character sheet (multiple angles), scales every image so the face ends up at the same size and canvas position — including back-view angles, via a silhouette fallback tied to the batch's face scale. Includes a Fine-Tune node for per-image zoom/nudge with a live canvas preview, and an Anime Face Detect node for crop+mask using lbpcascade_animeface."
|
||||
},
|
||||
{
|
||||
"author": "amortegui84",
|
||||
"title": "Tile Upscale NB2",
|
||||
"reference": "https://github.com/amortegui84/comfyui-tile-upscale-nb2",
|
||||
"files": [
|
||||
"https://github.com/amortegui84/comfyui-tile-upscale-nb2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Tile-based upscaling nodes for ComfyUI — Nano Banana 2 compatible"
|
||||
},
|
||||
{
|
||||
"author": "dorpxam",
|
||||
"title": "LTX-2 Microscope",
|
||||
"reference": "https://github.com/dorpxam/ComfyUI-LTX2-Microscope",
|
||||
"files": [
|
||||
"https://github.com/dorpxam/ComfyUI-LTX2-Microscope"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "48-Layers Latent Previewer for Lightrick's LTX-2 model."
|
||||
},
|
||||
{
|
||||
"author": "enviral-design",
|
||||
"title": "Enviral Design Node Pack",
|
||||
"reference": "https://github.com/EnviralDesign/comfyUI-enviral-design-node-pack",
|
||||
"files": [
|
||||
"https://github.com/EnviralDesign/comfyUI-enviral-design-node-pack"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Small, dependency-light ComfyUI utility nodes from Enviral Design."
|
||||
},
|
||||
{
|
||||
"author": "newgrit1004",
|
||||
"title": "Qwen3 Triton TTS",
|
||||
"reference": "https://github.com/newgrit1004/ComfyUI-Qwen3-TTS-Triton",
|
||||
"files": [
|
||||
"https://github.com/newgrit1004/ComfyUI-Qwen3-TTS-Triton"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node wrapping qwen3-tts-triton for 7-mode Qwen3-TTS inference (Triton kernel fusion + TurboQuant KV cache)"
|
||||
},
|
||||
{
|
||||
"author": "intelliprompt",
|
||||
"title": "comfy-intelliprompt",
|
||||
"reference": "https://github.com/galpt/comfy-intelliPrompt",
|
||||
"files": [
|
||||
"https://github.com/galpt/comfy-intelliPrompt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "intelliPrompt - An intelligent prompt optimizer for ComfyUI that fixes typos, balances parentheses, and enhances prompts"
|
||||
},
|
||||
{
|
||||
"author": "mahilkr",
|
||||
"title": "HunyuanWorld 3D World Generation",
|
||||
"reference": "https://github.com/krmahil/comfyui-hunyuan-world",
|
||||
"files": [
|
||||
"https://github.com/krmahil/comfyui-hunyuan-world"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes for immersive 3D world generation using Tencent HunyuanWorld 1.0"
|
||||
},
|
||||
{
|
||||
"author": "dailydoseofaiart",
|
||||
"title": "ComfyUI-FPSFrameDrop",
|
||||
"reference": "https://github.com/dailydoseofaiart/ComfyUI-FPSFrameDrop",
|
||||
"files": [
|
||||
"https://github.com/dailydoseofaiart/ComfyUI-FPSFrameDrop"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A node to drop frames from the output images to force the video to a lower FPS at the same playback speed."
|
||||
},
|
||||
{
|
||||
"author": "comfyui-attic",
|
||||
"title": "External LoRA Loader",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
24
openapi.yaml
24
openapi.yaml
@ -259,6 +259,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:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user