Compare commits

...

52 Commits

Author SHA1 Message Date
CenFun
3c9d8c6039
Merge dfd953b2ae into c8dce94c03 2025-12-02 05:25:01 +01:00
Dr.Lt.Data
c8dce94c03 update DB
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
2025-12-01 12:23:52 +09:00
Dr.Lt.Data
06496d07b3 update DB
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
2025-11-29 01:43:52 +09:00
painter890602
a97f98c9cc
Add PainterFLF2V custom node (#2311)
* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-29 01:23:25 +09:00
Dr.Lt.Data
8d0406f74f update DB 2025-11-28 18:32:02 +09:00
Dr.Lt.Data
c64d14701d update DB
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2025-11-28 08:59:09 +09:00
Dr.Lt.Data
00332ae444 update DB 2025-11-28 08:02:05 +09:00
akawana
e8deb3d8fe
Add Utils Extra custom node to the list (#2313)
* Add Utils Extra custom node to the list

Added a new custom node entry for Utils Extra with details.

* Update description in custom-node-list.json

Expanded the description to include additional functionalities of the utility tools.
2025-11-28 08:00:38 +09:00
obvirm
8b234c99cf
Add ComfyUI-WhisperXX custom node entry (#2314)
* Add ComfyUI-WhisperXX custom node entry

Added a new custom node entry for ComfyUI-WhisperXX with details.

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-28 07:59:25 +09:00
Rzgar
1f986d9c45
Add entry for Qwen Image Size Picker (#2312) 2025-11-28 07:56:02 +09:00
Dr.Lt.Data
bacb8fb3cd update DB
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
2025-11-27 00:23:54 +09:00
Dr.Lt.Data
e4a90089ab fixed: a bug where updating ComfyUI using Update: ComfyUI Stable Version did not updating ComfyUI's dependencies 2025-11-26 21:54:28 +09:00
Dr.Lt.Data
674b9f3705 update DB 2025-11-26 21:41:55 +09:00
Dr.Lt.Data
4941fb8aa0 fixed: scanner.py
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2025-11-26 08:58:02 +09:00
Dr.Lt.Data
183af0dfa5 update DB
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2025-11-25 12:59:01 +09:00
Dr.Lt.Data
45ac5429f8 "update DB" 2025-11-25 12:46:44 +09:00
Dr.Lt.Data
c771977a95 update DB
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2025-11-24 23:10:06 +09:00
Dr.Lt.Data
668d7bbb2c update DB 2025-11-24 22:56:38 +09:00
akawana
926cfabb58
Add Keybinding Extra (keyboard shortcut extension) (#2306)
* Add Keybinding Extra custom node

Added a new custom node for Keybinding Extra with relevant details.

* Enhance description for Keybinding Extra

Updated the description for the Keybinding Extra to provide more detail about its functionality.

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-24 22:55:44 +09:00
Dr.Lt.Data
a9a8d05115 update DB 2025-11-24 22:54:26 +09:00
Eric Rollei
e368f4366a
Add Download Tools for ComfyUI (#2298)
Added new download tools for ComfyUI with extensive features for media downloading and web scraping.
2025-11-24 22:51:50 +09:00
Dr.Lt.Data
dc5bddbc17 update DB
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
2025-11-24 02:00:50 +09:00
icekiub-ai
358a480408
IcyHider Nodes (#2304)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-24 00:17:22 +09:00
Dr.Lt.Data
c96fdb3c7a update DB 2025-11-22 10:36:00 +09:00
Dr.Lt.Data
c090abcc02 update DB 2025-11-22 09:46:14 +09:00
kjqwer
1ff02be35f
add node (#2282)
* add node

* add node
2025-11-22 09:45:21 +09:00
Dr.Lt.Data
10fbfb88f7 update DB 2025-11-22 09:43:20 +09:00
MadiatorLabs
9753df72ed
Added ComfyUI-RunpodDirect to node list (#2291) 2025-11-22 09:41:54 +09:00
Dr.Lt.Data
095cc3f792 Merge PR #2297: Add PDF Tools and update AAA Metadata System
Resolved merge conflict with PR #2297 by integrating:
- PDF Tools - Advanced PDF Processing & OCR (new entry)
- AAA Metadata System (updated with enhanced description and metadata)
- HYPIR Image Restoration (preserved from main branch)

All entries use consistent spacing and JSON formatting.
2025-11-22 09:33:58 +09:00
Dr.Lt.Data
656171037b
Update custom-node-list.json
HYPIR-ComfyUI was a separated PR.
2025-11-22 09:28:40 +09:00
Dr.Lt.Data
7ac10f9442 update DB 2025-11-22 09:25:07 +09:00
yuanyuan-spec
3925ba27b4
feat: Add HunyuanVideo-1.5 nodes (#2300)
* feat: Add HunyuanVideo-1.5 nodes

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <dr.lt.data@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-22 09:23:18 +09:00
Dr.Lt.Data
44ba79aa31 update DB 2025-11-22 09:15:50 +09:00
Eric Rollei
14d0e31268
Add HYPIR Image Restoration nodes to custom-node-list (#2299)
Added custom ComfyUI nodes for HYPIR image restoration, including details on author, title, reference, and description.
2025-11-22 09:12:27 +09:00
Dr.Lt.Data
033acffad1 update DB 2025-11-22 08:42:06 +09:00
Writili
d29ff808a5
I added my node to the JSON file (#2287)
* Update custom-node-list.json

Added my node to the JSON

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-22 08:40:35 +09:00
Dr.Lt.Data
dc9b6d655b update DB 2025-11-22 08:40:02 +09:00
Casual Gamer
d340c85013
feat: add ComfyUI Text Processor to node list (#2295) 2025-11-22 08:39:00 +09:00
Dr.Lt.Data
e328353664 update DB 2025-11-21 00:33:43 +09:00
Eric Rollei
02785af8fd
Merge pull request #2 from EricRollei/EricRollei-patch-1
Add HYPIR Image Restoration entry to custom-node-list
2025-11-20 01:39:02 -08:00
Eric Rollei
736ae5d63e
Add HYPIR Image Restoration entry to custom-node-list
Added a new entry for HYPIR Image Restoration including author, title, reference, files, install type, description, and nodename pattern.
2025-11-20 01:38:39 -08:00
Eric Rollei
e1eeb617d2
Merge pull request #1 from EricRollei/EricRollei-patch-1
Add AAA Metadata System entry to custom-node-list
2025-11-20 01:34:27 -08:00
Eric Rollei
23b6c7f0de
Add AAA Metadata System entry to custom-node-list
Added a new entry for the AAA Metadata System with detailed features and installation instructions.
2025-11-20 01:34:04 -08:00
Eric Rollei
997f97e1fc
Add PDF Tools for advanced PDF processing and OCR
Added a new entry for advanced PDF processing tools, including OCR and image parsing capabilities.
2025-11-20 01:10:01 -08:00
Dr.Lt.Data
ff335ff1a0 update DB 2025-11-19 23:12:01 +09:00
Dr.Lt.Data
cb3036ef81 modified: scanner.py – updated main so it can be imported 2025-11-19 22:43:28 +09:00
Dr.Lt.Data
f762906188 update DB 2025-11-19 22:42:14 +09:00
cellzero
dde7920f8c
Add ComfyUI-Animon node (#2293)
* Add ComfyUI-Animon node

* Update custom-node-list.json

* Remove and re-add ComfyUI-Animon entry in JSON

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-19 22:41:13 +09:00
Dr.Lt.Data
1a0d24110a update DB 2025-11-19 22:38:35 +09:00
Devin Garner
e79f6c4471
Add new node for ComfyUI_Make-It-Animatable (#2292)
* Add new node for ComfyUI_Make-It-Animatable

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-11-19 22:37:20 +09:00
Dr.Lt.Data
a8a7024a84 update DB 2025-11-19 18:46:14 +09:00
cenfun
dfd953b2ae fix search sorting 2025-03-15 21:24:41 +08:00
15 changed files with 12884 additions and 9329 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@ import manager_downloader
from node_package import InstalledNodePackage
version_code = [3, 37, 1]
version_code = [3, 37, 2]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
@ -2533,6 +2533,7 @@ def update_to_stable_comfyui(repo_path):
else:
logging.info(f"[ComfyUI-Manager] Updating ComfyUI: {current_tag} -> {latest_tag}")
repo.git.checkout(latest_tag)
execute_install_script("ComfyUI", repo_path, instant_execution=False, no_deps=False)
return 'updated', latest_tag
except:
traceback.print_exc()

View File

@ -347,6 +347,55 @@ export function md5(inputString) {
return rh(a)+rh(b)+rh(c)+rh(d);
}
const levenArray = [];
const levenCodeCache = [];
export const leven = (first, second) => {
if (first === second) {
return 0;
}
const swap = first;
if (first.length > second.length) {
first = second;
second = swap;
}
let firstLength = first.length;
let secondLength = second.length;
while (firstLength > 0 && (first.charCodeAt(~-firstLength) === second.charCodeAt(~-secondLength))) {
firstLength--;
secondLength--;
}
let start = 0;
while (start < firstLength && (first.charCodeAt(start) === second.charCodeAt(start))) {
start++;
}
firstLength -= start;
secondLength -= start;
if (firstLength === 0) {
return secondLength;
}
let bCharacterCode;
let result;
let temporary;
let temporary2;
let index = 0;
let index2 = 0;
while (index < firstLength) {
levenCodeCache[index] = first.charCodeAt(start + index);
levenArray[index] = ++index;
}
while (index2 < secondLength) {
bCharacterCode = second.charCodeAt(start + index2);
temporary = index2++;
result = index2;
for (index = 0; index < firstLength; index++) {
temporary2 = bCharacterCode === levenCodeCache[index] ? temporary : temporary + 1;
temporary = levenArray[index];
result = levenArray[index] = temporary > result ? (temporary2 > result ? result + 1 : temporary2) : (temporary2 > temporary ? temporary + 1 : temporary2);
}
}
return result;
}
export async function fetchData(route, options) {
let err;
const res = await api.fetchApi(route, options).catch(e => {
@ -595,12 +644,10 @@ export function showPopover(target, text, className, options) {
}
let $tooltip;
export function hideTooltip(target) {
export function hideTooltip() {
if ($tooltip) {
$tooltip.style.display = "none";
$tooltip.innerHTML = "";
$tooltip.style.top = "0px";
$tooltip.style.left = "0px";
$tooltip.remove();
$tooltip = null;
}
}
export function showTooltip(target, text, className = 'cn-tooltip', styleMap = {}) {
@ -639,11 +686,7 @@ function initTooltip () {
}
};
const mouseleaveHandler = (e) => {
const target = e.target;
const text = target.getAttribute('tooltip');
if (text) {
hideTooltip(target);
}
hideTooltip();
};
document.body.removeEventListener('mouseenter', mouseenterHandler, true);
document.body.removeEventListener('mouseleave', mouseleaveHandler, true);

View File

@ -7,7 +7,7 @@ import {
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
showPopover, hidePopover
showPopover, hidePopover, leven
} from "./common.js";
// https://cenfun.github.io/turbogrid/api.html
@ -418,11 +418,7 @@ export class CustomNodesManager {
".cn-manager-keywords": {
input: (e) => {
const keywords = `${e.target.value}`.trim();
if (keywords !== this.keywords) {
this.keywords = keywords;
this.updateGrid();
}
this.onKeywordsChange(e);
},
focus: (e) => e.target.select()
},
@ -539,7 +535,7 @@ export class CustomNodesManager {
this.addHighlight(d.rowItem);
if (d.columnItem.id === "nodes") {
if (d.columnItem && d.columnItem.id === "nodes") {
this.showNodes(d);
return;
}
@ -596,6 +592,14 @@ export class CustomNodesManager {
return autoHeightColumns.includes(columnItem.id)
},
rowFilteredSort: () => {
if (this.keywords) {
return {
id: 'sort_score'
};
}
},
// updateGrid handler for filter and keywords
rowFilter: (rowItem) => {
@ -612,12 +616,109 @@ export class CustomNodesManager {
}
}
// calculate sort score
if (shouldShown && this.keywords) {
rowItem.sort_score = this.calculateSortScore(rowItem, searchableColumns);
}
return shouldShown;
}
});
}
onKeywordsChange(e) {
this.grid.showLoading();
// debounce for performance
clearTimeout(this.timeKeywords);
this.timeKeywords = setTimeout(() => {
this.grid.hideLoading();
const keywords = `${e.target.value}`.trim();
if (keywords !== this.keywords) {
this.keywords = keywords;
if (keywords) {
this.grid.removeSortColumn();
} else {
this.grid.sortRows("id", {
sortAsc: true
});
}
this.updateGrid();
}
}, 300);
}
calculateSortScore(rowItem, searchableColumns) {
const keywords = this.keywords.split(/\s+/g).filter((s) => s);
const lowerKeywords = keywords.map(k => k.toLowerCase());
const matchedList = searchableColumns.map(id => {
const { highlightKey, textKey } = this.grid.options.highlightKeywords;
const highlight = rowItem[`${highlightKey}${id}`];
if (!highlight) {
return;
}
const text = `${rowItem[`${textKey}${id}`] || rowItem[id]}`;
const lowerText = text.toLowerCase();
const matchedItems = keywords.map((key, i) => {
// multiple matched
const lowerKey = lowerKeywords[i];
const len = lowerKey.length;
const matches = [];
let index = lowerText.indexOf(lowerKey);
while (index !== -1) {
matches.push(index);
index = lowerText.indexOf(lowerKey, index + len);
}
if (!matches.length) {
return
}
const distances = matches.map(start => {
const end = start + len
const str = text.slice(start, end);
let distance = leven(key, str);
const prev = text.slice(start - 1, start);
if (prev) {
if (/[A-Za-z]/.test(prev)) {
distance += 1;
} else if (/[0-9]/.test(prev)) {
distance += 0.8;
}
}
const next = text.slice(end, end + 1);
if (next) {
if (/[A-Za-z]/.test(next)) {
distance += 0.8;
} else if (/[0-9]/.test(next)) {
distance += 0.5;
}
}
return distance;
});
// console.log(rowItem.title, distances)
return {
// min
distance: Math.min.apply(null, distances)
}
}).filter(it => it);
if (matchedItems.length < keywords.length) {
return;
}
return {
// avg
distance: matchedItems.map(it => it.distance).reduce((p, v) => p + v, 0) / matchedItems.length
}
}).filter(it => it);
// by distance
let distance = Math.min.apply(null, matchedList.map(it => it.distance));
// by matched count
distance += 1 - matchedList.length / searchableColumns.length;
// by stars
const stars = TG.Util.toNum(rowItem.stars);
distance += 1 - stars / 10000;
// score
return 1 / distance;
}
hasAlternatives() {
return this.filter === ShowMode.ALTERNATIVES
}
@ -757,6 +858,7 @@ export class CustomNodesManager {
id: "nodes",
name: "Nodes",
width: 100,
sortAsc: false,
formatter: (v, rowItem, columnItem) => {
if (!rowItem.nodes) {
return '';
@ -797,6 +899,7 @@ export class CustomNodesManager {
id: 'stars',
name: '★',
align: 'center',
sortAsc: false,
classMap: "cn-pack-stars",
formatter: (stars) => {
if (stars < 0) {
@ -812,6 +915,7 @@ export class CustomNodesManager {
name: 'Last Update',
align: 'center',
type: 'date',
sortAsc: false,
width: 100,
classMap: "cn-pack-last-update",
formatter: (last_update) => {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -169,6 +169,16 @@
],
"install_type": "git-clone",
"description": "A fork of KJNodes for ComfyUI.\nVarious quality of life -nodes for ComfyUI, mostly just visual stuff to improve usability"
},
{
"author": "huixingyun",
"title": "ComfyUI-SoundFlow",
"reference": "https://github.com/huixingyun/ComfyUI-SoundFlow",
"files": [
"https://github.com/huixingyun/ComfyUI-SoundFlow"
],
"install_type": "git-clone",
"description": "forked from https://github.com/fredconex/ComfyUI-SoundFlow (removed)"
}
]
}

View File

@ -1,5 +1,155 @@
{
"custom_nodes": [
{
"author": "PozzettiAndrea",
"title": "ComfyUI-CameraAnalysis [REMOVED]",
"reference": "https://github.com/PozzettiAndrea/ComfyUI-CameraAnalysis",
"files": [
"https://github.com/PozzettiAndrea/ComfyUI-CameraAnalysis"
],
"install_type": "git-clone",
"description": "Extracts camera intrinsic parameters from image EXIF data."
},
{
"author": "fuzr0dah",
"title": "comfyui-sceneassembly [REMOVED]",
"reference": "https://github.com/fuzr0dah/comfyui-sceneassembly",
"files": [
"https://github.com/fuzr0dah/comfyui-sceneassembly"
],
"install_type": "git-clone",
"description": "A bunch of nodes I created that I also find useful."
},
{
"author": "rslosch",
"title": "ComfyUI-EZ_Prompts [REMOVED]",
"reference": "https://github.com/rslosch/ComfyUI-EZ_Prompts",
"files": [
"https://github.com/rslosch/ComfyUI-EZ_Prompts"
],
"install_type": "git-clone",
"description": "A ComfyUI custom node extension that provides easy-to-use prompt templates and wildcards for AI image generation."
},
{
"author": "hvppycoding",
"title": "hvppyflow [REMOVED]",
"reference": "https://github.com/hvppycoding/hvppyflow",
"files": [
"https://github.com/hvppycoding/hvppyflow"
],
"install_type": "git-clone",
"description": "ComfyUI nodes for Automated Workflow"
},
{
"author": "cedarconnor",
"title": "ComfyUI-GEN3C-Gsplat [REMOVED]",
"reference": "https://github.com/cedarconnor/ComfyUI-GEN3C-Gsplat",
"files": [
"https://github.com/cedarconnor/ComfyUI-GEN3C-Gsplat"
],
"install_type": "git-clone",
"description": "A custom ComfyUI node pack that bridges Cosmos/GEN3C video generation with in-graph Gaussian Splat (3DGS) training. It adds camera/trajectory tooling, dataset exporters, and two training backends (Nerfstudio CLI wrapper and an in-process gsplat optimizer) so artists can go from prompt to splat entirely inside ComfyUI.\nNOTE: The files in the repo are not organized."
},
{
"author": "dowa-git",
"title": "comfyui-dowa [REMOVED]",
"reference": "https://github.com/dowa-git/comfyui-dowa",
"files": [
"https://github.com/dowa-git/comfyui-dowa"
],
"install_type": "git-clone",
"description": "Professional navigation bar widget for ComfyUI with JWT-based user authentication, workflow templates, and team collaboration features in a purple gradient design."
},
{
"author": "Fablestarexpanse",
"title": "Timer-Node-Comfyui [REMOVED]",
"reference": "https://github.com/Fablestarexpanse/Timer-Node-Comfyui",
"files": [
"https://github.com/Fablestarexpanse/Timer-Node-Comfyui"
],
"install_type": "git-clone",
"description": "A custom ComfyUI node that displays live processing time in a red digital countdown clock format, perfect for monitoring image generation times and tracking performance between workflow nodes."
},
{
"author": "cedarconnor",
"title": "ComfyUI-OmniX [REMOVED]",
"reference": "https://github.com/cedarconnor/ComfyUI-OmniX",
"files": [
"https://github.com/cedarconnor/ComfyUI-OmniX"
],
"install_type": "git-clone",
"description": "Extract comprehensive scene properties from 360-degree equirectangular panoramas, including depth, normals, and PBR materials, using OmniX adapters with Flux."
},
{
"author": "cedarconnor",
"title": "ComfyUI-DiT360 [REMOVED]",
"reference": "https://github.com/cedarconnor/ComfyUI-DiT360",
"files": [
"https://github.com/cedarconnor/ComfyUI-DiT360"
],
"install_type": "git-clone",
"description": "Generate high-fidelity 360-degree panoramic images using the DiT360 diffusion transformer model in ComfyUI."
},
{
"author": "PozzettiAndrea",
"title": "ComfyUI-AnyTop [REMOVED]",
"reference": "https://github.com/PozzettiAndrea/ComfyUI-AnyTop",
"files": [
"https://github.com/PozzettiAndrea/ComfyUI-AnyTop"
],
"install_type": "git-clone",
"description": "Standalone ComfyUI custom nodes for AnyTop - Universal Motion Generation for Any Skeleton Topology."
},
{
"author": "penposs",
"title": "ComfyUI-Banana-Node [REMOVED]",
"reference": "https://github.com/penposs/ComfyUI-Banana-Node",
"files": [
"https://github.com/penposs/ComfyUI-Banana-Node"
],
"install_type": "git-clone",
"description": "A custom node for ComfyUI that generates images using Googles Gemini 2.5 Flash Image Preview API."
},
{
"author": "spiralmountain",
"title": "ComfyUI_HDNodes [REMOVED]",
"reference": "https://github.com/spiralmountain/ComfyUI_HDNodes",
"files": [
"https://github.com/spiralmountain/ComfyUI_HDNodes"
],
"install_type": "git-clone",
"description": "Custom nodes for ComfyUI that enable video generation using ByteDance's Seedance model via [a/Fal.ai](https://fal.ai/)."
},
{
"author": "fredconex",
"title": "Sync Edit [REMOVED]",
"reference": "https://github.com/fredconex/ComfyUI-SyncEdit",
"files": [
"https://github.com/fredconex/ComfyUI-SyncEdit"
],
"install_type": "git-clone",
"description": "This node allow to intercept changes on the input string and choose between use the current one or sync with incoming new one."
},
{
"author": "fredconex",
"title": "ComfyUI-SoundFlow [REMOVED]",
"reference": "https://github.com/fredconex/ComfyUI-SoundFlow",
"files": [
"https://github.com/fredconex/ComfyUI-SoundFlow"
],
"install_type": "git-clone",
"description": "This is a bunch of nodes for ComfyUI to help with sound work."
},
{
"author": "fredconex",
"title": "SongBloom [REMOVED]",
"reference": "https://github.com/fredconex/ComfyUI-SongBloom",
"files": [
"https://github.com/fredconex/ComfyUI-SongBloom"
],
"install_type": "git-clone",
"description": "ComfyUI Nodes for SongBloom"
},
{
"author": "EQXai",
"title": "ComfyUI_EQX [REMOVED]",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
[project]
name = "comfyui-manager"
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
version = "3.37.1"
version = "3.37.2"
license = { file = "LICENSE.txt" }
dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]

View File

@ -78,36 +78,14 @@ Examples:
return args
# Parse arguments
args = parse_arguments()
# Determine mode
scan_only_mode = args.scan_only is not None
url_list_file = args.scan_only if scan_only_mode else None
# Determine temp_dir
if args.temp_dir:
temp_dir = args.temp_dir
elif args.temp_dir_positional:
temp_dir = args.temp_dir_positional
else:
temp_dir = os.path.join(os.getcwd(), ".tmp")
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)
# Determine skip flags
skip_update = args.skip_update or args.skip_all
skip_stat_update = args.skip_stat_update or args.skip_all or scan_only_mode
if not skip_stat_update:
auth = Auth.Token(os.environ.get('GITHUB_TOKEN'))
g = Github(auth=auth)
else:
g = None
print(f"TEMP DIR: {temp_dir}")
# Module-level variables (will be set in main if running as script)
args = None
scan_only_mode = False
url_list_file = None
temp_dir = None
skip_update = False
skip_stat_update = True
g = None
parse_cnt = 0
@ -127,10 +105,17 @@ def extract_nodes(code_text):
warnings.filterwarnings('ignore', category=DeprecationWarning)
parsed_code = ast.parse(code_text)
assignments = (node for node in parsed_code.body if isinstance(node, ast.Assign))
# Support both ast.Assign and ast.AnnAssign (for type-annotated assignments)
assignments = (node for node in parsed_code.body if isinstance(node, (ast.Assign, ast.AnnAssign)))
for assignment in assignments:
if isinstance(assignment.targets[0], ast.Name) and assignment.targets[0].id in ['NODE_CONFIG', 'NODE_CLASS_MAPPINGS']:
# Handle ast.AnnAssign (e.g., NODE_CLASS_MAPPINGS: Type = {...})
if isinstance(assignment, ast.AnnAssign):
if isinstance(assignment.target, ast.Name) and assignment.target.id in ['NODE_CONFIG', 'NODE_CLASS_MAPPINGS']:
node_class_mappings = assignment.value
break
# Handle ast.Assign (e.g., NODE_CLASS_MAPPINGS = {...})
elif isinstance(assignment.targets[0], ast.Name) and assignment.targets[0].id in ['NODE_CONFIG', 'NODE_CLASS_MAPPINGS']:
node_class_mappings = assignment.value
break
else:
@ -250,7 +235,8 @@ def scan_in_file(filename, is_builtin=False):
with open(filename, encoding='utf-8', errors='ignore') as file:
code = file.read()
pattern = r"_CLASS_MAPPINGS\s*=\s*{([^}]*)}"
# Support type annotations (e.g., NODE_CLASS_MAPPINGS: Type = {...}) and line continuations (\)
pattern = r"_CLASS_MAPPINGS\s*(?::\s*\w+\s*)?=\s*(?:\\\s*)?{([^}]*)}"
regex = re.compile(pattern, re.MULTILINE | re.DOTALL)
nodes = set()
@ -482,21 +468,21 @@ def update_custom_nodes(scan_only_mode=False, url_list_file=None):
raise ValueError("url_list_file is required in scan-only mode")
git_url_titles_preemptions = get_urls_from_list_file(url_list_file)
print(f"\n[Scan-Only Mode]")
print("\n[Scan-Only Mode]")
print(f" - URL source: {url_list_file}")
print(f" - GitHub stats: DISABLED")
print(" - GitHub stats: DISABLED")
print(f" - Git clone/pull: {'ENABLED' if not skip_update else 'DISABLED'}")
print(f" - Metadata: EMPTY")
print(" - Metadata: EMPTY")
else:
if not os.path.exists('custom-node-list.json'):
raise FileNotFoundError("custom-node-list.json not found")
git_url_titles_preemptions = get_git_urls_from_json('custom-node-list.json')
print(f"\n[Standard Mode]")
print(f" - URL source: custom-node-list.json")
print("\n[Standard Mode]")
print(" - URL source: custom-node-list.json")
print(f" - GitHub stats: {'ENABLED' if not skip_stat_update else 'DISABLED'}")
print(f" - Git clone/pull: {'ENABLED' if not skip_update else 'DISABLED'}")
print(f" - Metadata: FULL")
print(" - Metadata: FULL")
def process_git_url_title(url, title, preemptions, node_pattern):
name = os.path.basename(url)
@ -689,7 +675,14 @@ def gen_json(node_info, scan_only_mode=False):
data[git_url] = (nodes, metadata)
else:
print(f"WARN: {dirname} is removed from custom-node-list.json")
# Scan-only mode: Repository not in node_info (expected behavior)
# Construct URL from dirname (author_repo format)
if '_' in dirname:
parts = dirname.split('_', 1)
git_url = f"https://github.com/{parts[0]}/{parts[1]}"
data[git_url] = (nodes, metadata)
else:
print(f"WARN: {dirname} is removed from custom-node-list.json")
for file in node_files:
nodes, metadata = scan_in_file(file)
@ -775,24 +768,53 @@ def gen_json(node_info, scan_only_mode=False):
json.dump(data, file, indent=4, sort_keys=True)
print("### ComfyUI Manager Node Scanner ###")
if __name__ == "__main__":
# Parse arguments
args = parse_arguments()
if scan_only_mode:
print(f"\n# [Scan-Only Mode] Processing URL list: {url_list_file}\n")
else:
print("\n# [Standard Mode] Updating extensions\n")
# Determine mode
scan_only_mode = args.scan_only is not None
url_list_file = args.scan_only if scan_only_mode else None
# Update/clone repositories and collect node info
updated_node_info = update_custom_nodes(scan_only_mode, url_list_file)
# Determine temp_dir
if args.temp_dir:
temp_dir = args.temp_dir
elif args.temp_dir_positional:
temp_dir = args.temp_dir_positional
else:
temp_dir = os.path.join(os.getcwd(), ".tmp")
print("\n# Generating 'extension-node-map.json'...\n")
if not os.path.exists(temp_dir):
os.makedirs(temp_dir)
# Generate extension-node-map.json
gen_json(updated_node_info, scan_only_mode)
# Determine skip flags
skip_update = args.skip_update or args.skip_all
skip_stat_update = args.skip_stat_update or args.skip_all or scan_only_mode
print("\n✅ DONE.\n")
if not skip_stat_update:
auth = Auth.Token(os.environ.get('GITHUB_TOKEN'))
g = Github(auth=auth)
else:
g = None
if scan_only_mode:
print("Output: extension-node-map.json (node mappings only)")
else:
print("Output: extension-node-map.json (full metadata)")
print("### ComfyUI Manager Node Scanner ###")
if scan_only_mode:
print(f"\n# [Scan-Only Mode] Processing URL list: {url_list_file}\n")
else:
print("\n# [Standard Mode] Updating extensions\n")
# Update/clone repositories and collect node info
updated_node_info = update_custom_nodes(scan_only_mode, url_list_file)
print("\n# Generating 'extension-node-map.json'...\n")
# Generate extension-node-map.json
gen_json(updated_node_info, scan_only_mode)
print("\n✅ DONE.\n")
if scan_only_mode:
print("Output: extension-node-map.json (node mappings only)")
else:
print("Output: extension-node-map.json (full metadata)")