Compare commits
364 Commits
feat/manag
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bba55d4d5a | ||
|
|
87111bd889 | ||
|
|
3661ffd3ab | ||
|
|
d8f111a5e3 | ||
|
|
ae5565ce68 | ||
|
|
e4c370a7d9 | ||
|
|
891005bcd3 | ||
|
|
d3a4a7a0fa | ||
|
|
10211d1a93 | ||
|
|
7f019a932b | ||
|
|
fae909de2f | ||
|
|
d8455ef6e5 | ||
|
|
934c994783 | ||
|
|
d0961d596d | ||
|
|
382df24764 | ||
|
|
bfcfa42125 | ||
|
|
2333886c34 | ||
|
|
0cdad3c886 | ||
|
|
eee23c543b | ||
|
|
f0a8812f5e | ||
|
|
a8d603f753 | ||
|
|
22acaa1d2c | ||
|
|
fe791ccee9 | ||
|
|
414557eee0 | ||
|
|
97d2741360 | ||
|
|
b95e5f1eae | ||
|
|
43b200dc91 | ||
|
|
29014699bb | ||
|
|
5576672957 | ||
|
|
5002606861 | ||
|
|
ba0fb343ff | ||
|
|
17e5ae6bc2 | ||
|
|
7a0186efc8 | ||
|
|
de64af4a68 | ||
|
|
4a852ac8a8 | ||
|
|
6784bfb98c | ||
|
|
c8f246d344 | ||
|
|
8b3d31a936 | ||
|
|
5e88d6445b | ||
|
|
fd7dff88df | ||
|
|
8cfee1f483 | ||
|
|
cf4d8e6125 | ||
|
|
c0e8a41d2a | ||
|
|
a02c27b1af | ||
|
|
712e1bac0d | ||
|
|
513ea46cbe | ||
|
|
b1919b6f95 | ||
|
|
43561d209b | ||
|
|
16dcbc5412 | ||
|
|
c8dd2d5cad | ||
|
|
4b37777066 | ||
|
|
95ecd85a12 | ||
|
|
5c475e3c15 | ||
|
|
f705ee6863 | ||
|
|
1f67c18989 | ||
|
|
de6d451c5b | ||
|
|
580296d6f3 | ||
|
|
a9e28fbce3 | ||
|
|
311779cb20 | ||
|
|
d2f8a89e87 | ||
|
|
84c95bf322 | ||
|
|
f75c801955 | ||
|
|
faa2f54371 | ||
|
|
4249ac193a | ||
|
|
c709274a28 | ||
|
|
c8f05e79db | ||
|
|
4d2887e99f | ||
|
|
29256a5154 | ||
|
|
82d42e4094 | ||
|
|
53850fb627 | ||
|
|
34b4c8ce46 | ||
|
|
e944841054 | ||
|
|
f6a5ff5552 | ||
|
|
01763b59d4 | ||
|
|
044173b2a1 | ||
|
|
99e7a88dbd | ||
|
|
01cd9fbb0e | ||
|
|
aaed1dc3d5 | ||
|
|
c8dce94c03 | ||
|
|
06496d07b3 | ||
|
|
a97f98c9cc | ||
|
|
8d0406f74f | ||
|
|
c64d14701d | ||
|
|
00332ae444 | ||
|
|
e8deb3d8fe | ||
|
|
8b234c99cf | ||
|
|
1f986d9c45 | ||
|
|
bacb8fb3cd | ||
|
|
e4a90089ab | ||
|
|
674b9f3705 | ||
|
|
4941fb8aa0 | ||
|
|
183af0dfa5 | ||
|
|
45ac5429f8 | ||
|
|
c771977a95 | ||
|
|
668d7bbb2c | ||
|
|
926cfabb58 | ||
|
|
a9a8d05115 | ||
|
|
e368f4366a | ||
|
|
dc5bddbc17 | ||
|
|
358a480408 | ||
|
|
c96fdb3c7a | ||
|
|
c090abcc02 | ||
|
|
1ff02be35f | ||
|
|
10fbfb88f7 | ||
|
|
9753df72ed | ||
|
|
095cc3f792 | ||
|
|
656171037b | ||
|
|
7ac10f9442 | ||
|
|
3925ba27b4 | ||
|
|
44ba79aa31 | ||
|
|
14d0e31268 | ||
|
|
033acffad1 | ||
|
|
d29ff808a5 | ||
|
|
dc9b6d655b | ||
|
|
d340c85013 | ||
|
|
e328353664 | ||
|
|
02785af8fd | ||
|
|
736ae5d63e | ||
|
|
e1eeb617d2 | ||
|
|
23b6c7f0de | ||
|
|
997f97e1fc | ||
|
|
ff335ff1a0 | ||
|
|
cb3036ef81 | ||
|
|
f762906188 | ||
|
|
dde7920f8c | ||
|
|
1a0d24110a | ||
|
|
e79f6c4471 | ||
|
|
a8a7024a84 | ||
|
|
d93d002da0 | ||
|
|
baaa0479e8 | ||
|
|
cc3bd7a056 | ||
|
|
4ecefb3b71 | ||
|
|
f24b5aa251 | ||
|
|
de547da4cd | ||
|
|
0f884166a6 | ||
|
|
63379f759d | ||
|
|
8fdff20243 | ||
|
|
5dfa07ca03 | ||
|
|
343645be6a | ||
|
|
91bf21d7a8 | ||
|
|
be6516cfd3 | ||
|
|
61f1e516a3 | ||
|
|
73b2278b45 | ||
|
|
aa625e30b6 | ||
|
|
29a46fe4ce | ||
|
|
5b3ee49530 | ||
|
|
a9158a101f | ||
|
|
feed8abb34 | ||
|
|
70decc740f | ||
|
|
5b5c83f8c5 | ||
|
|
773c06f40d | ||
|
|
737e6ad5ed | ||
|
|
81bca9c94e | ||
|
|
eef0654de2 | ||
|
|
997a00b8a2 | ||
|
|
4d25232c5f | ||
|
|
135befa101 | ||
|
|
44cac3fc43 | ||
|
|
449fa3510e | ||
|
|
d958af8aad | ||
|
|
09f8d5cb2d | ||
|
|
aedc99cefd | ||
|
|
b32cab6e9a | ||
|
|
a95186965e | ||
|
|
7067de1bb2 | ||
|
|
f45d878d21 | ||
|
|
a0532b938d | ||
|
|
6ad12b7652 | ||
|
|
02887c6c9b | ||
|
|
1b645e1cc3 | ||
|
|
0a4b2a0488 | ||
|
|
d4ce6ddc52 | ||
|
|
5a5b989533 | ||
|
|
b57cffb0fa | ||
|
|
72aa95cacf | ||
|
|
14ef448937 | ||
|
|
1c10607c06 | ||
|
|
41e53a1f2a | ||
|
|
cde83e9a38 | ||
|
|
6c206b1c72 | ||
|
|
a474219e7b | ||
|
|
3b8d25eb31 | ||
|
|
0faa0aa668 | ||
|
|
0fcdcc93a2 | ||
|
|
461d5e72fe | ||
|
|
3f030a2121 | ||
|
|
7fb8e8662f | ||
|
|
dd3ab9cff2 | ||
|
|
97b518de12 | ||
|
|
d2a795c866 | ||
|
|
8a3d65be20 | ||
|
|
b2126d8ba5 | ||
|
|
6386411d21 | ||
|
|
4250244136 | ||
|
|
77c4f9993d | ||
|
|
c7c8417577 | ||
|
|
9d0985ded8 | ||
|
|
3663e10e33 | ||
|
|
5f37a82c3c | ||
|
|
026bf1dfd7 | ||
|
|
643a6e5080 | ||
|
|
5267502896 | ||
|
|
c3c152122d | ||
|
|
afeac097e5 | ||
|
|
e5cea64132 | ||
|
|
26da78cf15 | ||
|
|
179a1e1ca0 | ||
|
|
b379d275d1 | ||
|
|
133cdfb203 | ||
|
|
2b79edd9be | ||
|
|
3862a92e04 | ||
|
|
f4e3817fcc | ||
|
|
61f0f5d67c | ||
|
|
87f57551ea | ||
|
|
ee51efed69 | ||
|
|
5dab865681 | ||
|
|
8c0581eebc | ||
|
|
a72f9f422c | ||
|
|
1354a8c970 | ||
|
|
00a5115267 | ||
|
|
00282eab7b | ||
|
|
bec128de58 | ||
|
|
9edfa7b4fa | ||
|
|
a9af70e5f0 | ||
|
|
910caf593f | ||
|
|
02dc072dc7 | ||
|
|
78fb354452 | ||
|
|
66f5eca7fa | ||
|
|
be95396a57 | ||
|
|
59cbed429f | ||
|
|
d49df7aebb | ||
|
|
0aa9faad2e | ||
|
|
1337def888 | ||
|
|
4b100c558b | ||
|
|
1425a71ece | ||
|
|
a8524508fe | ||
|
|
a5ff973d53 | ||
|
|
337c9aa2c7 | ||
|
|
f1448403ac | ||
|
|
d0b5f77ec6 | ||
|
|
9cb22ffb60 | ||
|
|
f556962d82 | ||
|
|
d28448d519 | ||
|
|
c590a88ffd | ||
|
|
a1fc6c817b | ||
|
|
5554e52799 | ||
|
|
ca749eb4d2 | ||
|
|
41ceee3d24 | ||
|
|
5acfd52986 | ||
|
|
ec4c7b2f6a | ||
|
|
22a3d8f95f | ||
|
|
06b89ca277 | ||
|
|
9e5ffbd00a | ||
|
|
39e92ed778 | ||
|
|
68a3ec567a | ||
|
|
28231e81b3 | ||
|
|
b2ee0feeaa | ||
|
|
5541b6b366 | ||
|
|
408a5fe27e | ||
|
|
bffc73f976 | ||
|
|
bd6edfc9dd | ||
|
|
2cb24e8a94 | ||
|
|
a49779c4d2 | ||
|
|
15a5a5f5df | ||
|
|
b5e0558d6e | ||
|
|
4d683b23fc | ||
|
|
c13da606b2 | ||
|
|
c792f9277c | ||
|
|
b430f42622 | ||
|
|
fee822f5ae | ||
|
|
192659ecbd | ||
|
|
810431b9e2 | ||
|
|
02d845adf3 | ||
|
|
89c7b960fb | ||
|
|
ed1e399a56 | ||
|
|
8a3ce1ae57 | ||
|
|
d89ff649f8 | ||
|
|
24a73b5d1c | ||
|
|
4d0c40ff8a | ||
|
|
b5a2bed539 | ||
|
|
0efb79f571 | ||
|
|
df944b9a0f | ||
|
|
2c11846430 | ||
|
|
0035c01186 | ||
|
|
34be3384fe | ||
|
|
ebbc7b3335 | ||
|
|
4ccc8c3086 | ||
|
|
af9ebc9568 | ||
|
|
ca4b61c5f0 | ||
|
|
393839b3ab | ||
|
|
dadfc96e00 | ||
|
|
a0a33aef03 | ||
|
|
99ed81e0f5 | ||
|
|
5b697db219 | ||
|
|
8e5bf46e14 | ||
|
|
9f649b0900 | ||
|
|
abb15e06d3 | ||
|
|
11a317493e | ||
|
|
e8cece0c1b | ||
|
|
1ab882f81d | ||
|
|
b9338186e3 | ||
|
|
7c3cbff425 | ||
|
|
1ff0afc633 | ||
|
|
bfe7ee8fba | ||
|
|
49c73ed10e | ||
|
|
f571baacf9 | ||
|
|
6f02e1114c | ||
|
|
e230f43565 | ||
|
|
0d9593e71b | ||
|
|
20778ecfb0 | ||
|
|
2ea991d960 | ||
|
|
119c107834 | ||
|
|
800a0d0449 | ||
|
|
95c43f0189 | ||
|
|
9c77176c7f | ||
|
|
ddb6a55cd6 | ||
|
|
56a4f6fdd7 | ||
|
|
8a30f788b5 | ||
|
|
380a1c2c8c | ||
|
|
cd8e8335cf | ||
|
|
6e1beb54a4 | ||
|
|
9217c965dd | ||
|
|
a4d71ef487 | ||
|
|
518f332047 | ||
|
|
9257d497b8 | ||
|
|
07cf5de4f7 | ||
|
|
43ad69e48d | ||
|
|
c62e236cc6 | ||
|
|
15a2fbb293 | ||
|
|
16800c3fa0 | ||
|
|
ce09f41aa3 | ||
|
|
47dc2f036a | ||
|
|
f27a154bfd | ||
|
|
79757366e8 | ||
|
|
2cd9a417d6 | ||
|
|
deb05c6cc3 | ||
|
|
b6f171de51 | ||
|
|
a58d5f6999 | ||
|
|
e0b3f3eb45 | ||
|
|
4bbc8594a7 | ||
|
|
3a377300e1 | ||
|
|
33a07e3a86 | ||
|
|
212cafc1d7 | ||
|
|
2643b3cbcc | ||
|
|
d445229b6d | ||
|
|
dab5c451b0 | ||
|
|
7bdf06131a | ||
|
|
854648d5af | ||
|
|
c5f7b97359 | ||
|
|
dd8a727ad6 | ||
|
|
6c627fe422 | ||
|
|
ee980e1caf | ||
|
|
22bfaf6527 | ||
|
|
48ab48cc30 | ||
|
|
a0b14d4127 | ||
|
|
03f9fe1a70 | ||
|
|
8915b8d796 | ||
|
|
c77ffeeec0 | ||
|
|
4acf5660b2 | ||
|
|
2d9f0a668c | ||
|
|
9e6cb246cc | ||
|
|
14544ca63d | ||
|
|
26b347c04c | ||
|
|
36f75d1811 |
60
README.md
60
README.md
@@ -5,6 +5,7 @@
|
|||||||

|

|
||||||
|
|
||||||
## NOTICE
|
## NOTICE
|
||||||
|
* V3.38: **Security patch** - Manager data migrated to protected path. See [Migration Guide](docs/en/v3.38-userdata-security-migration.md).
|
||||||
* V3.16: Support for `uv` has been added. Set `use_uv` in `config.ini`.
|
* V3.16: Support for `uv` has been added. Set `use_uv` in `config.ini`.
|
||||||
* V3.10: `double-click feature` is removed
|
* V3.10: `double-click feature` is removed
|
||||||
* This feature has been moved to https://github.com/ltdrdata/comfyui-connection-helper
|
* This feature has been moved to https://github.com/ltdrdata/comfyui-connection-helper
|
||||||
@@ -17,7 +18,7 @@
|
|||||||
|
|
||||||
To install ComfyUI-Manager in addition to an existing installation of ComfyUI, you can follow the following steps:
|
To install ComfyUI-Manager in addition to an existing installation of ComfyUI, you can follow the following steps:
|
||||||
|
|
||||||
1. goto `ComfyUI/custom_nodes` dir in terminal(cmd)
|
1. Go to `ComfyUI/custom_nodes` dir in terminal (cmd)
|
||||||
2. `git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager`
|
2. `git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager`
|
||||||
3. Restart ComfyUI
|
3. Restart ComfyUI
|
||||||
|
|
||||||
@@ -28,8 +29,8 @@ To install ComfyUI-Manager in addition to an existing installation of ComfyUI, y
|
|||||||
- standalone version
|
- standalone version
|
||||||
- select option: use windows default console window
|
- select option: use windows default console window
|
||||||
2. Download [scripts/install-manager-for-portable-version.bat](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-manager-for-portable-version.bat) into installed `"ComfyUI_windows_portable"` directory
|
2. Download [scripts/install-manager-for-portable-version.bat](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-manager-for-portable-version.bat) into installed `"ComfyUI_windows_portable"` directory
|
||||||
- Don't click. Right click the link and use save as...
|
- Don't click. Right-click the link and choose 'Save As...'
|
||||||
3. double click `install-manager-for-portable-version.bat` batch file
|
3. Double-click `install-manager-for-portable-version.bat` batch file
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ pip install comfy-cli
|
|||||||
comfy install
|
comfy install
|
||||||
```
|
```
|
||||||
|
|
||||||
Linux/OSX:
|
Linux/macOS:
|
||||||
```commandline
|
```commandline
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
@@ -57,13 +58,13 @@ comfy install
|
|||||||
* See also: https://github.com/Comfy-Org/comfy-cli
|
* See also: https://github.com/Comfy-Org/comfy-cli
|
||||||
|
|
||||||
|
|
||||||
### Installation[method4] (Installation for linux+venv: ComfyUI + ComfyUI-Manager)
|
### Installation[method4] (Installation for Linux+venv: ComfyUI + ComfyUI-Manager)
|
||||||
|
|
||||||
To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps:
|
To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps:
|
||||||
* **prerequisite: python-is-python3, python3-venv, git**
|
* **prerequisite: python-is-python3, python3-venv, git**
|
||||||
|
|
||||||
1. Download [scripts/install-comfyui-venv-linux.sh](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-comfyui-venv-linux.sh) into empty install directory
|
1. Download [scripts/install-comfyui-venv-linux.sh](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-comfyui-venv-linux.sh) into empty install directory
|
||||||
- Don't click. Right click the link and use save as...
|
- Don't click. Right-click the link and choose 'Save As...'
|
||||||
- ComfyUI will be installed in the subdirectory of the specified directory, and the directory will contain the generated executable script.
|
- ComfyUI will be installed in the subdirectory of the specified directory, and the directory will contain the generated executable script.
|
||||||
2. `chmod +x install-comfyui-venv-linux.sh`
|
2. `chmod +x install-comfyui-venv-linux.sh`
|
||||||
3. `./install-comfyui-venv-linux.sh`
|
3. `./install-comfyui-venv-linux.sh`
|
||||||
@@ -140,20 +141,27 @@ This repository provides Colab notebooks that allow you to install and use Comfy
|
|||||||
|
|
||||||
|
|
||||||
## Paths
|
## Paths
|
||||||
In `ComfyUI-Manager` V3.0 and later, configuration files and dynamically generated files are located under `<USER_DIRECTORY>/default/ComfyUI-Manager/`.
|
Starting from V3.38, Manager uses a protected system path for enhanced security.
|
||||||
|
|
||||||
* <USER_DIRECTORY>
|
* <USER_DIRECTORY>
|
||||||
* If executed without any options, the path defaults to ComfyUI/user.
|
* If executed without any options, the path defaults to ComfyUI/user.
|
||||||
* It can be set using --user-directory <USER_DIRECTORY>.
|
* It can be set using --user-directory <USER_DIRECTORY>.
|
||||||
|
|
||||||
* Basic config files: `<USER_DIRECTORY>/default/ComfyUI-Manager/config.ini`
|
| ComfyUI Version | Manager Path |
|
||||||
* Configurable channel lists: `<USER_DIRECTORY>/default/ComfyUI-Manager/channels.ini`
|
|-----------------|--------------|
|
||||||
* Configurable pip overrides: `<USER_DIRECTORY>/default/ComfyUI-Manager/pip_overrides.json`
|
| v0.3.76+ (with System User API) | `<USER_DIRECTORY>/__manager/` |
|
||||||
* Configurable pip blacklist: `<USER_DIRECTORY>/default/ComfyUI-Manager/pip_blacklist.list`
|
| Older versions | `<USER_DIRECTORY>/default/ComfyUI-Manager/` |
|
||||||
* Configurable pip auto fix: `<USER_DIRECTORY>/default/ComfyUI-Manager/pip_auto_fix.list`
|
|
||||||
* Saved snapshot files: `<USER_DIRECTORY>/default/ComfyUI-Manager/snapshots`
|
* Basic config files: `config.ini`
|
||||||
* Startup script files: `<USER_DIRECTORY>/default/ComfyUI-Manager/startup-scripts`
|
* Configurable channel lists: `channels.list`
|
||||||
* Component files: `<USER_DIRECTORY>/default/ComfyUI-Manager/components`
|
* Configurable pip overrides: `pip_overrides.json`
|
||||||
|
* Configurable pip blacklist: `pip_blacklist.list`
|
||||||
|
* Configurable pip auto fix: `pip_auto_fix.list`
|
||||||
|
* Saved snapshot files: `snapshots/`
|
||||||
|
* Startup script files: `startup-scripts/`
|
||||||
|
* Component files: `components/`
|
||||||
|
|
||||||
|
> **Note**: See [Migration Guide](docs/en/v3.38-userdata-security-migration.md) for upgrade details.
|
||||||
|
|
||||||
|
|
||||||
## `extra_model_paths.yaml` Configuration
|
## `extra_model_paths.yaml` Configuration
|
||||||
@@ -176,7 +184,7 @@ The following settings are applied based on the section marked as `is_default`.
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
## cm-cli: command line tools for power user
|
## cm-cli: command line tools for power users
|
||||||
* A tool is provided that allows you to use the features of ComfyUI-Manager without running ComfyUI.
|
* A tool is provided that allows you to use the features of ComfyUI-Manager without running ComfyUI.
|
||||||
* For more details, please refer to the [cm-cli documentation](docs/en/cm-cli.md).
|
* For more details, please refer to the [cm-cli documentation](docs/en/cm-cli.md).
|
||||||
|
|
||||||
@@ -222,7 +230,7 @@ The following settings are applied based on the section marked as `is_default`.
|
|||||||
* `<current timestamp>` Ensure that the timestamp is always unique.
|
* `<current timestamp>` Ensure that the timestamp is always unique.
|
||||||
* "components" should have the same structure as the content of the file stored in `<USER_DIRECTORY>/default/ComfyUI-Manager/components`.
|
* "components" should have the same structure as the content of the file stored in `<USER_DIRECTORY>/default/ComfyUI-Manager/components`.
|
||||||
* `<component name>`: The name should be in the format `<prefix>::<node name>`.
|
* `<component name>`: The name should be in the format `<prefix>::<node name>`.
|
||||||
* `<compnent nodeata>`: In the nodedata of the group node.
|
* `<component node data>`: In the node data of the group node.
|
||||||
* `<version>`: Only two formats are allowed: `major.minor.patch` or `major.minor`. (e.g. `1.0`, `2.2.1`)
|
* `<version>`: Only two formats are allowed: `major.minor.patch` or `major.minor`. (e.g. `1.0`, `2.2.1`)
|
||||||
* `<datetime>`: Saved time
|
* `<datetime>`: Saved time
|
||||||
* `<packname>`: If the packname is not empty, the category becomes packname/workflow, and it is saved in the <packname>.pack file in `<USER_DIRECTORY>/default/ComfyUI-Manager/components`.
|
* `<packname>`: If the packname is not empty, the category becomes packname/workflow, and it is saved in the <packname>.pack file in `<USER_DIRECTORY>/default/ComfyUI-Manager/components`.
|
||||||
@@ -240,7 +248,7 @@ The following settings are applied based on the section marked as `is_default`.
|
|||||||
* Dragging and dropping or pasting a single component will add a node. However, when adding multiple components, nodes will not be added.
|
* Dragging and dropping or pasting a single component will add a node. However, when adding multiple components, nodes will not be added.
|
||||||
|
|
||||||
|
|
||||||
## Support of missing nodes installation
|
## Support for installing missing nodes
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -279,10 +287,10 @@ The following settings are applied based on the section marked as `is_default`.
|
|||||||
* Logging to file feature
|
* Logging to file feature
|
||||||
* This feature is enabled by default and can be disabled by setting `file_logging = False` in the `config.ini`.
|
* This feature is enabled by default and can be disabled by setting `file_logging = False` in the `config.ini`.
|
||||||
|
|
||||||
* Fix node(recreate): When right-clicking on a node and selecting `Fix node (recreate)`, you can recreate the node. The widget's values are reset, while the connections maintain those with the same names.
|
* Fix node (recreate): When right-clicking on a node and selecting `Fix node (recreate)`, you can recreate the node. The widget's values are reset, while the connections maintain those with the same names.
|
||||||
* It is used to correct errors in nodes of old workflows created before, which are incompatible with the version changes of custom nodes.
|
* It is used to correct errors in nodes of old workflows created before, which are incompatible with the version changes of custom nodes.
|
||||||
|
|
||||||
* Double-Click Node Title: You can set the double click behavior of nodes in the ComfyUI-Manager menu.
|
* Double-Click Node Title: You can set the double-click behavior of nodes in the ComfyUI-Manager menu.
|
||||||
* `Copy All Connections`, `Copy Input Connections`: Double-clicking a node copies the connections of the nearest node.
|
* `Copy All Connections`, `Copy Input Connections`: Double-clicking a node copies the connections of the nearest node.
|
||||||
* This action targets the nearest node within a straight-line distance of 1000 pixels from the center of the node.
|
* This action targets the nearest node within a straight-line distance of 1000 pixels from the center of the node.
|
||||||
* In the case of `Copy All Connections`, it duplicates existing outputs, but since it does not allow duplicate connections, the existing output connections of the original node are disconnected.
|
* In the case of `Copy All Connections`, it duplicates existing outputs, but since it does not allow duplicate connections, the existing output connections of the original node are disconnected.
|
||||||
@@ -348,7 +356,7 @@ When you run the `scan.sh` script:
|
|||||||
|
|
||||||
* It updates the `github-stats.json`.
|
* It updates the `github-stats.json`.
|
||||||
* This uses the GitHub API, so set your token with `export GITHUB_TOKEN=your_token_here` to avoid quickly reaching the rate limit and malfunctioning.
|
* This uses the GitHub API, so set your token with `export GITHUB_TOKEN=your_token_here` to avoid quickly reaching the rate limit and malfunctioning.
|
||||||
* To skip this step, add the `--skip-update-stat` option.
|
* To skip this step, add the `--skip-stat-update` option.
|
||||||
|
|
||||||
* The `--skip-all` option applies both `--skip-update` and `--skip-stat-update`.
|
* The `--skip-all` option applies both `--skip-update` and `--skip-stat-update`.
|
||||||
|
|
||||||
@@ -356,9 +364,9 @@ When you run the `scan.sh` script:
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
* If your `git.exe` is installed in a specific location other than system git, please install ComfyUI-Manager and run ComfyUI. Then, specify the path including the file name in `git_exe = ` in the `<USER_DIRECTORY>/default/ComfyUI-Manager/config.ini` file that is generated.
|
* If your `git.exe` is installed in a specific location other than system git, please install ComfyUI-Manager and run ComfyUI. Then, specify the path including the file name in `git_exe = ` in the `<USER_DIRECTORY>/default/ComfyUI-Manager/config.ini` file that is generated.
|
||||||
* If updating ComfyUI-Manager itself fails, please go to the **ComfyUI-Manager** directory and execute the command `git update-ref refs/remotes/origin/main a361cc1 && git fetch --all && git pull`.
|
* If updating ComfyUI-Manager itself fails, please go to the **ComfyUI-Manager** directory and execute the command `git update-ref refs/remotes/origin/main a361cc1 && git fetch --all && git pull`.
|
||||||
* If you encounter the error message `Overlapped Object has pending operation at deallocation on Comfyui Manager load` under Windows
|
* If you encounter the error message `Overlapped Object has pending operation at deallocation on ComfyUI Manager load` under Windows
|
||||||
* Edit `config.ini` file: add `windows_selector_event_loop_policy = True`
|
* Edit `config.ini` file: add `windows_selector_event_loop_policy = True`
|
||||||
* if `SSL: CERTIFICATE_VERIFY_FAILED` error is occured.
|
* If the `SSL: CERTIFICATE_VERIFY_FAILED` error occurs.
|
||||||
* Edit `config.ini` file: add `bypass_ssl = True`
|
* Edit `config.ini` file: add `bypass_ssl = True`
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
4
check.sh
4
check.sh
@@ -37,7 +37,7 @@ find ~/.tmp/default -name "*.py" -print0 | xargs -0 grep -E "crypto|^_A="
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo CHECK3
|
echo CHECK3
|
||||||
find ~/.tmp/default -name "requirements.txt" | xargs grep "^\s*https\\?:"
|
find ~/.tmp/default -name "requirements.txt" | xargs grep "^\s*[^#]*https\?:"
|
||||||
find ~/.tmp/default -name "requirements.txt" | xargs grep "\.whl"
|
find ~/.tmp/default -name "requirements.txt" | xargs grep "^\s*[^#].*\.whl"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|||||||
6497
custom-node-list.json
Executable file → Normal file
6497
custom-node-list.json
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -139,9 +139,9 @@ You can set whether to use ComfyUI-Manager solely via CLI.
|
|||||||
`restore-dependencies`
|
`restore-dependencies`
|
||||||
|
|
||||||
* This command can be used if custom nodes are installed under the `ComfyUI/custom_nodes` path but their dependencies are not installed.
|
* This command can be used if custom nodes are installed under the `ComfyUI/custom_nodes` path but their dependencies are not installed.
|
||||||
* It is useful when starting a new cloud instance, like colab, where dependencies need to be reinstalled and installation scripts re-executed.
|
* It is useful when starting a new cloud instance, like Colab, where dependencies need to be reinstalled and installation scripts re-executed.
|
||||||
* It can also be utilized if ComfyUI is reinstalled and only the custom_nodes path has been backed up and restored.
|
* It can also be utilized if ComfyUI is reinstalled and only the custom_nodes path has been backed up and restored.
|
||||||
|
|
||||||
### 7. Clear
|
### 7. Clear
|
||||||
|
|
||||||
In the GUI, installations, updates, or snapshot restorations are scheduled to execute the next time ComfyUI is launched. The `clear` command clears this scheduled state, ensuring no pre-execution actions are applied.
|
In the GUI, installations, updates, or snapshot restorations are scheduled to execute the next time ComfyUI is launched. The `clear` command clears this scheduled state, ensuring no pre-execution actions are applied.
|
||||||
|
|||||||
230
docs/en/v3.38-userdata-security-migration.md
Normal file
230
docs/en/v3.38-userdata-security-migration.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
# ComfyUI-Manager V3.38: Userdata Security Migration Guide
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
ComfyUI-Manager V3.38 introduces a **security patch** that migrates Manager's configuration and data to a protected system path. This change leverages ComfyUI's new System User Protection API (PR #10966) to provide enhanced security isolation.
|
||||||
|
|
||||||
|
This guide explains what happens during the migration and how to handle various situations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Changed
|
||||||
|
|
||||||
|
### Finding Your Paths
|
||||||
|
|
||||||
|
When ComfyUI starts, it displays the full paths in the terminal:
|
||||||
|
|
||||||
|
```
|
||||||
|
** User directory: /path/to/ComfyUI/user
|
||||||
|
** ComfyUI-Manager config path: /path/to/ComfyUI/user/__manager/config.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for these lines in your startup log to find the exact location on your system. In this guide, paths are shown relative to the `user` directory.
|
||||||
|
|
||||||
|
### Path Migration
|
||||||
|
|
||||||
|
| Data | Legacy Path | New Path |
|
||||||
|
|------|-------------|----------|
|
||||||
|
| Configuration | `user/default/ComfyUI-Manager/` | `user/__manager/` |
|
||||||
|
| Snapshots | `user/default/ComfyUI-Manager/snapshots/` | `user/__manager/snapshots/` |
|
||||||
|
|
||||||
|
### Why This Change
|
||||||
|
|
||||||
|
In older ComfyUI versions, the `default/` directory was **unprotected** and accessible via web APIs. If you ran ComfyUI with `--listen 0.0.0.0` or similar options to allow external connections, this data **may have been tampered with** by malicious actors.
|
||||||
|
|
||||||
|
**Note:** If you only used ComfyUI locally (without `--listen` or with `--listen 127.0.0.1`), your data was not exposed to this vulnerability.
|
||||||
|
|
||||||
|
The new `__manager` path uses ComfyUI's protected system directory, which:
|
||||||
|
- **Cannot be accessed** from outside (protected by ComfyUI)
|
||||||
|
- Isolates system settings from user data
|
||||||
|
- Enables stricter security for remote access
|
||||||
|
|
||||||
|
**This is why only `config.ini` is automatically migrated** - other files (snapshots) may have been compromised and should be manually verified before copying.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Automatic Migration
|
||||||
|
|
||||||
|
When you start ComfyUI with the new System User Protection API, Manager automatically handles the migration:
|
||||||
|
|
||||||
|
### Step 1: Configuration Migration
|
||||||
|
|
||||||
|
Only `config.ini` is migrated automatically.
|
||||||
|
|
||||||
|
**Important**: Snapshots are **NOT** automatically migrated. You must copy them manually if needed.
|
||||||
|
|
||||||
|
### Step 2: Security Level Check
|
||||||
|
|
||||||
|
During migration, if your security level is below `normal` (i.e., `weak` or `normal-`), it will be automatically raised to `normal`. This is a safety measure because the security level setting itself may have been tampered with in the old version.
|
||||||
|
|
||||||
|
```
|
||||||
|
======================================================================
|
||||||
|
[ComfyUI-Manager] WARNING: Security level adjusted
|
||||||
|
- Previous: 'weak' → New: 'normal'
|
||||||
|
- Raised to prevent unauthorized remote access.
|
||||||
|
======================================================================
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need a lower security level, you can manually edit the config after migration.
|
||||||
|
|
||||||
|
### Step 3: Legacy Backup
|
||||||
|
|
||||||
|
Your entire legacy directory is moved to a backup location:
|
||||||
|
```
|
||||||
|
user/__manager/.legacy-manager-backup/
|
||||||
|
```
|
||||||
|
|
||||||
|
This backup is preserved until you manually delete it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Persistent Backup Notification
|
||||||
|
|
||||||
|
As long as the backup exists, Manager will remind you on **every startup**:
|
||||||
|
|
||||||
|
```
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
[ComfyUI-Manager] NOTICE: Legacy backup exists
|
||||||
|
- Your old Manager data was backed up to:
|
||||||
|
/path/to/ComfyUI/user/__manager/.legacy-manager-backup
|
||||||
|
- Please verify and remove it when no longer needed.
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
**To stop this notification**: Delete the `.legacy-manager-backup` folder inside `user/__manager/` after confirming you don't need any data from it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recovering Old Data
|
||||||
|
|
||||||
|
### Snapshots
|
||||||
|
|
||||||
|
If you need your old snapshots, copy the contents of `.legacy-manager-backup/snapshots/` to `user/__manager/snapshots/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Outdated ComfyUI Warning
|
||||||
|
|
||||||
|
If you're running an older version of ComfyUI without the System User Protection API, Manager will:
|
||||||
|
|
||||||
|
1. **Force security level to `strong`** - All installations are blocked
|
||||||
|
2. **Display warning message**:
|
||||||
|
|
||||||
|
```
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
[ComfyUI-Manager] ERROR: ComfyUI version is outdated!
|
||||||
|
- Most operations are blocked for security.
|
||||||
|
- ComfyUI update is still allowed.
|
||||||
|
- Please update ComfyUI to use Manager normally.
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution**: Update ComfyUI to v0.3.76 or later.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Levels
|
||||||
|
|
||||||
|
| Level | What's Allowed |
|
||||||
|
|-------|----------------|
|
||||||
|
| `strong` | ComfyUI update only. All other installations blocked. |
|
||||||
|
| `normal` | Install/update/remove registered custom nodes and models. |
|
||||||
|
| `normal-` | Above + Install via Git URL or pip (localhost only). |
|
||||||
|
| `weak` | All operations allowed, including from remote connections. |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- `strong` is forced on outdated ComfyUI versions.
|
||||||
|
- `normal` is the default and recommended for most users.
|
||||||
|
- `normal-` is for developers who need to install unregistered nodes locally.
|
||||||
|
- `weak` should only be used in isolated development environments.
|
||||||
|
|
||||||
|
### Changing Security Level
|
||||||
|
|
||||||
|
Edit `user/__manager/config.ini`:
|
||||||
|
```ini
|
||||||
|
[default]
|
||||||
|
security_level = normal
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Messages
|
||||||
|
|
||||||
|
### "comfyui_outdated" (HTTP 403)
|
||||||
|
|
||||||
|
This error appears when:
|
||||||
|
- Your ComfyUI doesn't have the System User Protection API
|
||||||
|
- All installations are blocked until you update ComfyUI
|
||||||
|
|
||||||
|
**Solution**: Update ComfyUI to the latest version.
|
||||||
|
|
||||||
|
### "security_level" (HTTP 403)
|
||||||
|
|
||||||
|
This error appears when:
|
||||||
|
- Your security level blocks the requested operation
|
||||||
|
- For example, `strong` level blocks all installations
|
||||||
|
|
||||||
|
**Solution**: Lower your security level in config.ini if appropriate for your use case.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Warning: Suspicious Path
|
||||||
|
|
||||||
|
If you see this error on an **older** ComfyUI:
|
||||||
|
|
||||||
|
```
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
[ComfyUI-Manager] ERROR: Suspicious path detected!
|
||||||
|
- '__manager' exists with low security level: 'weak'
|
||||||
|
- Please verify manually:
|
||||||
|
/path/to/ComfyUI/user/__manager/config.ini
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
```
|
||||||
|
|
||||||
|
On older ComfyUI versions, the `__manager` directory is not normally created. If this directory exists, it may have been created externally. For safety, manually verify the contents of this directory before updating ComfyUI.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### All my installations are blocked
|
||||||
|
|
||||||
|
**Check 1**: Is your ComfyUI updated?
|
||||||
|
- Old ComfyUI forces `security_level = strong`
|
||||||
|
- Update ComfyUI to resolve
|
||||||
|
|
||||||
|
**Check 2**: What's your security level?
|
||||||
|
- Check `user/__manager/config.ini`
|
||||||
|
- `security_level = strong` blocks all installations
|
||||||
|
|
||||||
|
### My snapshots are missing
|
||||||
|
|
||||||
|
Snapshots are not automatically migrated. You need to manually copy the `snapshots` folder from inside `.legacy-manager-backup` to the `user/__manager/` directory.
|
||||||
|
|
||||||
|
### I keep seeing the backup notification
|
||||||
|
|
||||||
|
Delete the `.legacy-manager-backup` folder inside `user/__manager/` after confirming you don't need any data from it.
|
||||||
|
|
||||||
|
### Snapshot restore is blocked
|
||||||
|
|
||||||
|
On old ComfyUI (without System User API), snapshot restore is blocked because security is forced to `strong`. Update ComfyUI to enable snapshot restore.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure Reference
|
||||||
|
|
||||||
|
```
|
||||||
|
user/
|
||||||
|
└── __manager/
|
||||||
|
├── config.ini # Manager configuration
|
||||||
|
├── channels.list # Custom node channels
|
||||||
|
├── snapshots/ # Environment snapshots
|
||||||
|
└── .legacy-manager-backup/ # Backup of old Manager data (temporary)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **ComfyUI**: v0.3.76 or later (with System User Protection API)
|
||||||
|
- **ComfyUI-Manager**: V3.38 or later
|
||||||
@@ -23,13 +23,13 @@ OPTIONS:
|
|||||||
## How To Use?
|
## How To Use?
|
||||||
* `python cm-cli.py` 를 통해서 실행 시킬 수 있습니다.
|
* `python cm-cli.py` 를 통해서 실행 시킬 수 있습니다.
|
||||||
* 예를 들어 custom node를 모두 업데이트 하고 싶다면
|
* 예를 들어 custom node를 모두 업데이트 하고 싶다면
|
||||||
* ComfyUI-Manager경로 에서 `python cm-cli.py update all` 를 command를 실행할 수 있습니다.
|
* ComfyUI-Manager 경로에서 `python cm-cli.py update all` 명령을 실행할 수 있습니다.
|
||||||
* ComfyUI 경로에서 실행한다면, `python custom_nodes/ComfyUI-Manager/cm-cli.py update all` 와 같이 cm-cli.py 의 경로를 지정할 수도 있습니다.
|
* ComfyUI 경로에서 실행한다면, `python custom_nodes/ComfyUI-Manager/cm-cli.py update all` 와 같이 cm-cli.py 의 경로를 지정할 수도 있습니다.
|
||||||
|
|
||||||
## Prerequisite
|
## Prerequisite
|
||||||
* ComfyUI 를 실행하는 python과 동일한 python 환경에서 실행해야 합니다.
|
* ComfyUI 를 실행하는 python과 동일한 python 환경에서 실행해야 합니다.
|
||||||
* venv를 사용할 경우 해당 venv를 activate 한 상태에서 실행해야 합니다.
|
* venv를 사용할 경우 해당 venv를 activate 한 상태에서 실행해야 합니다.
|
||||||
* portable 버전을 사용할 경우 run_nvidia_gpu.bat 파일이 있는 경로인 경우, 다음과 같은 방식으로 코맨드를 실행해야 합니다.
|
* portable 버전을 사용할 경우 run_nvidia_gpu.bat 파일이 있는 경로인 경우, 다음과 같은 방식으로 명령을 실행해야 합니다.
|
||||||
`.\python_embeded\python.exe ComfyUI\custom_nodes\ComfyUI-Manager\cm-cli.py update all`
|
`.\python_embeded\python.exe ComfyUI\custom_nodes\ComfyUI-Manager\cm-cli.py update all`
|
||||||
* ComfyUI 의 경로는 COMFYUI_PATH 환경 변수로 설정할 수 있습니다. 만약 생략할 경우 다음과 같은 경고 메시지가 나타나며, ComfyUI-Manager가 설치된 경로를 기준으로 상대 경로로 설정됩니다.
|
* ComfyUI 의 경로는 COMFYUI_PATH 환경 변수로 설정할 수 있습니다. 만약 생략할 경우 다음과 같은 경고 메시지가 나타나며, ComfyUI-Manager가 설치된 경로를 기준으로 상대 경로로 설정됩니다.
|
||||||
```
|
```
|
||||||
@@ -40,8 +40,8 @@ OPTIONS:
|
|||||||
|
|
||||||
### 1. --channel, --mode
|
### 1. --channel, --mode
|
||||||
* 정보 보기 기능과 커스텀 노드 관리 기능의 경우는 --channel과 --mode를 통해 정보 DB를 설정할 수 있습니다.
|
* 정보 보기 기능과 커스텀 노드 관리 기능의 경우는 --channel과 --mode를 통해 정보 DB를 설정할 수 있습니다.
|
||||||
* 예들 들어 `python cm-cli.py update all --channel recent --mode remote`와 같은 command를 실행할 경우, 현재 ComfyUI-Manager repo에 내장된 로컬의 정보가 아닌 remote의 최신 정보를 기준으로 동작하며, recent channel에 있는 목록을 대상으로만 동작합니다.
|
* 예를 들어 `python cm-cli.py update all --channel recent --mode remote`와 같은 명령을 실행할 경우, 현재 ComfyUI-Manager repo에 내장된 로컬의 정보가 아닌 remote의 최신 정보를 기준으로 동작하며, recent channel에 있는 목록을 대상으로만 동작합니다.
|
||||||
* --channel, --mode 는 `simple-show, show, install, uninstall, update, disable, enable, fix` command에서만 사용 가능합니다.
|
* --channel, --mode 는 `simple-show, show, install, uninstall, update, disable, enable, fix` 명령에서만 사용 가능합니다.
|
||||||
|
|
||||||
### 2. 관리 정보 보기
|
### 2. 관리 정보 보기
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ OPTIONS:
|
|||||||
* `[show|simple-show]` - `show`는 상세하게 정보를 보여주며, `simple-show`는 간단하게 정보를 보여줍니다.
|
* `[show|simple-show]` - `show`는 상세하게 정보를 보여주며, `simple-show`는 간단하게 정보를 보여줍니다.
|
||||||
|
|
||||||
|
|
||||||
`python cm-cli.py show installed` 와 같은 코맨드를 실행하면 설치된 커스텀 노드의 정보를 상세하게 보여줍니다.
|
`python cm-cli.py show installed` 와 같은 명령을 실행하면 설치된 커스텀 노드의 정보를 상세하게 보여줍니다.
|
||||||
```
|
```
|
||||||
-= ComfyUI-Manager CLI (V2.24) =-
|
-= ComfyUI-Manager CLI (V2.24) =-
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main
|
|||||||
[ DISABLED ] ComfyUI-Loopchain (author: Fannovel16)
|
[ DISABLED ] ComfyUI-Loopchain (author: Fannovel16)
|
||||||
```
|
```
|
||||||
|
|
||||||
`python cm-cli.py simple-show installed` 와 같은 코맨드를 이용해서 설치된 커스텀 노드의 정보를 간단하게 보여줍니다.
|
`python cm-cli.py simple-show installed` 와 같은 명령을 이용해서 설치된 커스텀 노드의 정보를 간단하게 보여줍니다.
|
||||||
|
|
||||||
```
|
```
|
||||||
-= ComfyUI-Manager CLI (V2.24) =-
|
-= ComfyUI-Manager CLI (V2.24) =-
|
||||||
@@ -89,7 +89,7 @@ ComfyUI-Loopchain
|
|||||||
* `installed`: enable, disable 여부와 상관없이 설치된 모든 노드를 보여줍니다
|
* `installed`: enable, disable 여부와 상관없이 설치된 모든 노드를 보여줍니다
|
||||||
* `not-installed`: 설치되지 않은 커스텀 노드의 목록을 보여줍니다.
|
* `not-installed`: 설치되지 않은 커스텀 노드의 목록을 보여줍니다.
|
||||||
* `all`: 모든 커스텀 노드의 목록을 보여줍니다.
|
* `all`: 모든 커스텀 노드의 목록을 보여줍니다.
|
||||||
* `snapshot`: 현재 설치된 커스텀 노드의 snapshot 정보를 보여줍니다. `show`롤 통해서 볼 경우는 json 출력 형태로 보여주며, `simple-show`를 통해서 볼 경우는 간단하게, 커밋 해시와 함께 보여줍니다.
|
* `snapshot`: 현재 설치된 커스텀 노드의 snapshot 정보를 보여줍니다. `show`를 통해서 볼 경우는 json 출력 형태로 보여주며, `simple-show`를 통해서 볼 경우는 간단하게, 커밋 해시와 함께 보여줍니다.
|
||||||
* `snapshot-list`: ComfyUI-Manager/snapshots 에 저장된 snapshot 파일의 목록을 보여줍니다.
|
* `snapshot-list`: ComfyUI-Manager/snapshots 에 저장된 snapshot 파일의 목록을 보여줍니다.
|
||||||
|
|
||||||
### 3. 커스텀 노드 관리 하기
|
### 3. 커스텀 노드 관리 하기
|
||||||
@@ -98,7 +98,7 @@ ComfyUI-Loopchain
|
|||||||
|
|
||||||
* `python cm-cli.py install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack ComfyUI_experiments` 와 같이 커스텀 노드의 이름을 나열해서 관리 기능을 적용할 수 있습니다.
|
* `python cm-cli.py install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack ComfyUI_experiments` 와 같이 커스텀 노드의 이름을 나열해서 관리 기능을 적용할 수 있습니다.
|
||||||
* 커스텀 노드의 이름은 `show`를 했을 때 보여주는 이름이며, git repository의 이름입니다.
|
* 커스텀 노드의 이름은 `show`를 했을 때 보여주는 이름이며, git repository의 이름입니다.
|
||||||
(추후 nickname 을 사용가능하돌고 업데이트 할 예정입니다.)
|
(추후 nickname을 사용 가능하도록 업데이트할 예정입니다.)
|
||||||
|
|
||||||
`[update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
|
`[update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ ComfyUI-Loopchain
|
|||||||
* `--pip-non-local-url`: web URL에 등록된 pip 패키지들에 대해서 복구를 수행
|
* `--pip-non-local-url`: web URL에 등록된 pip 패키지들에 대해서 복구를 수행
|
||||||
* `--pip-local-url`: local 경로를 지정하고 있는 pip 패키지들에 대해서 복구를 수행
|
* `--pip-local-url`: local 경로를 지정하고 있는 pip 패키지들에 대해서 복구를 수행
|
||||||
* `--user-directory`: 사용자 디렉토리 설정
|
* `--user-directory`: 사용자 디렉토리 설정
|
||||||
* `--restore-to`: 복구될 커스텀 노드가 설치될 경로. (이 옵션을 적용할 경우 오직 대상 경로에 설치된 custom nodes 만 설치된 것으로 인식함.)
|
* `--restore-to`: 복구될 커스텀 노드가 설치될 경로. (이 옵션을 적용할 경우 오직 대상 경로에 설치된 custom nodes만 설치된 것으로 인식함.)
|
||||||
|
|
||||||
### 5. CLI only mode
|
### 5. CLI only mode
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ ComfyUI-Manager를 CLI로만 사용할 것인지를 설정할 수 있습니다.
|
|||||||
`cli-only-mode [enable|disable]`
|
`cli-only-mode [enable|disable]`
|
||||||
|
|
||||||
* security 혹은 policy 의 이유로 GUI 를 통한 ComfyUI-Manager 사용을 제한하고 싶은 경우 이 모드를 사용할 수 있습니다.
|
* security 혹은 policy 의 이유로 GUI 를 통한 ComfyUI-Manager 사용을 제한하고 싶은 경우 이 모드를 사용할 수 있습니다.
|
||||||
* CLI only mode를 적용할 경우 ComfyUI-Manager 가 매우 제한된 상태로 로드되어, 내부적으로 제공하는 web API가 비활성화 되며, 메인 메뉴에서도 Manager 버튼이 표시되지 않습니다.
|
* CLI only mode를 적용할 경우 ComfyUI-Manager 가 매우 제한된 상태로 로드되어, 내부적으로 제공하는 web API가 비활성화되며, 메인 메뉴에서도 Manager 버튼이 표시되지 않습니다.
|
||||||
|
|
||||||
|
|
||||||
### 6. 의존성 설치
|
### 6. 의존성 설치
|
||||||
@@ -141,10 +141,10 @@ ComfyUI-Manager를 CLI로만 사용할 것인지를 설정할 수 있습니다.
|
|||||||
`restore-dependencies`
|
`restore-dependencies`
|
||||||
|
|
||||||
* `ComfyUI/custom_nodes` 하위 경로에 커스텀 노드들이 설치되어 있긴 하지만, 의존성이 설치되지 않은 경우 사용할 수 있습니다.
|
* `ComfyUI/custom_nodes` 하위 경로에 커스텀 노드들이 설치되어 있긴 하지만, 의존성이 설치되지 않은 경우 사용할 수 있습니다.
|
||||||
* colab 과 같이 cloud instance를 새로 시작하는 경우 의존성 재설치 및 설치 스크립트가 재실행 되어야 하는 경우 사용합니다.
|
* Colab과 같이 cloud instance를 새로 시작하는 경우 의존성 재설치 및 설치 스크립트가 재실행되어야 하는 경우 사용합니다.
|
||||||
* ComfyUI을 재설치할 경우, custom_nodes 경로만 백업했다가 재설치 할 경우 활용 가능합니다.
|
* ComfyUI를 재설치할 경우, custom_nodes 경로만 백업했다가 재설치할 경우 활용 가능합니다.
|
||||||
|
|
||||||
|
|
||||||
### 7. clear
|
### 7. clear
|
||||||
|
|
||||||
GUI에서 install, update를 하거나 snapshot 을 restore하는 경우 예약을 통해서 다음번 ComfyUI를 실행할 경우 실행되는 구조입니다. `clear` 는 이런 예약 상태를 clear해서, 아무런 사전 실행이 적용되지 않도록 합니다.
|
GUI에서 install, update를 하거나 snapshot을 restore하는 경우 예약을 통해서 다음번 ComfyUI를 실행할 경우 실행되는 구조입니다. `clear` 는 이런 예약 상태를 clear해서, 아무런 사전 실행이 적용되지 않도록 합니다.
|
||||||
|
|||||||
11959
extension-node-map.json
11959
extension-node-map.json
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
import time
|
||||||
|
|
||||||
import git
|
import git
|
||||||
import json
|
import json
|
||||||
@@ -219,7 +220,14 @@ def gitpull(path):
|
|||||||
repo.close()
|
repo.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
remote.pull()
|
try:
|
||||||
|
repo.git.pull('--ff-only')
|
||||||
|
except git.GitCommandError:
|
||||||
|
backup_name = f'backup_{time.strftime("%Y%m%d_%H%M%S")}'
|
||||||
|
repo.create_head(backup_name)
|
||||||
|
print(f"[ComfyUI-Manager] Cannot fast-forward. Backup created: {backup_name}")
|
||||||
|
repo.git.reset('--hard', f'{remote_name}/{branch_name}')
|
||||||
|
print(f"[ComfyUI-Manager] Reset to {remote_name}/{branch_name}")
|
||||||
|
|
||||||
repo.git.submodule('update', '--init', '--recursive')
|
repo.git.submodule('update', '--init', '--recursive')
|
||||||
new_commit_hash = repo.head.commit.hexsha
|
new_commit_hash = repo.head.commit.hexsha
|
||||||
|
|||||||
22226
github-stats-cache.json
Normal file
22226
github-stats-cache.json
Normal file
File diff suppressed because it is too large
Load Diff
13842
github-stats.json
13842
github-stats.json
File diff suppressed because it is too large
Load Diff
@@ -40,10 +40,11 @@ import cnr_utils
|
|||||||
import manager_util
|
import manager_util
|
||||||
import git_utils
|
import git_utils
|
||||||
import manager_downloader
|
import manager_downloader
|
||||||
|
import manager_migration
|
||||||
from node_package import InstalledNodePackage
|
from node_package import InstalledNodePackage
|
||||||
|
|
||||||
|
|
||||||
version_code = [3, 36]
|
version_code = [3, 38, 3]
|
||||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||||
|
|
||||||
|
|
||||||
@@ -214,9 +215,10 @@ def update_user_directory(user_dir):
|
|||||||
global manager_pip_blacklist_path
|
global manager_pip_blacklist_path
|
||||||
global manager_components_path
|
global manager_components_path
|
||||||
|
|
||||||
manager_files_path = os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
|
manager_files_path = manager_migration.get_manager_path(user_dir)
|
||||||
if not os.path.exists(manager_files_path):
|
if not os.path.exists(manager_files_path):
|
||||||
os.makedirs(manager_files_path)
|
os.makedirs(manager_files_path)
|
||||||
|
manager_migration.run_migration_checks(user_dir, manager_files_path)
|
||||||
|
|
||||||
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
|
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
|
||||||
if not os.path.exists(manager_snapshot_path):
|
if not os.path.exists(manager_snapshot_path):
|
||||||
@@ -1719,7 +1721,7 @@ def read_config():
|
|||||||
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
|
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
|
||||||
manager_util.bypass_ssl = get_bool('bypass_ssl', False)
|
manager_util.bypass_ssl = get_bool('bypass_ssl', False)
|
||||||
|
|
||||||
return {
|
result = {
|
||||||
'http_channel_enabled': get_bool('http_channel_enabled', False),
|
'http_channel_enabled': get_bool('http_channel_enabled', False),
|
||||||
'preview_method': default_conf.get('preview_method', manager_funcs.get_current_preview_method()).lower(),
|
'preview_method': default_conf.get('preview_method', manager_funcs.get_current_preview_method()).lower(),
|
||||||
'git_exe': default_conf.get('git_exe', ''),
|
'git_exe': default_conf.get('git_exe', ''),
|
||||||
@@ -1739,6 +1741,8 @@ def read_config():
|
|||||||
'security_level': default_conf.get('security_level', 'normal').lower(),
|
'security_level': default_conf.get('security_level', 'normal').lower(),
|
||||||
'db_mode': default_conf.get('db_mode', 'cache').lower(),
|
'db_mode': default_conf.get('db_mode', 'cache').lower(),
|
||||||
}
|
}
|
||||||
|
manager_migration.force_security_level_if_needed(result)
|
||||||
|
return result
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
import importlib.util
|
import importlib.util
|
||||||
@@ -1746,7 +1750,7 @@ def read_config():
|
|||||||
manager_util.use_uv = importlib.util.find_spec("uv") is not None and platform.system() != "Windows"
|
manager_util.use_uv = importlib.util.find_spec("uv") is not None and platform.system() != "Windows"
|
||||||
manager_util.bypass_ssl = False
|
manager_util.bypass_ssl = False
|
||||||
|
|
||||||
return {
|
result = {
|
||||||
'http_channel_enabled': False,
|
'http_channel_enabled': False,
|
||||||
'preview_method': manager_funcs.get_current_preview_method(),
|
'preview_method': manager_funcs.get_current_preview_method(),
|
||||||
'git_exe': '',
|
'git_exe': '',
|
||||||
@@ -1766,6 +1770,8 @@ def read_config():
|
|||||||
'security_level': 'normal', # strong | normal | normal- | weak
|
'security_level': 'normal', # strong | normal | normal- | weak
|
||||||
'db_mode': 'cache', # local | cache | remote
|
'db_mode': 'cache', # local | cache | remote
|
||||||
}
|
}
|
||||||
|
manager_migration.force_security_level_if_needed(result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_config():
|
def get_config():
|
||||||
@@ -2247,9 +2253,17 @@ def git_pull(path):
|
|||||||
|
|
||||||
current_branch = repo.active_branch
|
current_branch = repo.active_branch
|
||||||
remote_name = current_branch.tracking_branch().remote_name
|
remote_name = current_branch.tracking_branch().remote_name
|
||||||
remote = repo.remote(name=remote_name)
|
|
||||||
|
|
||||||
remote.pull()
|
try:
|
||||||
|
repo.git.pull('--ff-only')
|
||||||
|
except git.GitCommandError:
|
||||||
|
branch_name = current_branch.name
|
||||||
|
backup_name = f'backup_{time.strftime("%Y%m%d_%H%M%S")}'
|
||||||
|
repo.create_head(backup_name)
|
||||||
|
logging.info(f"[ComfyUI-Manager] Cannot fast-forward. Backup created: {backup_name}")
|
||||||
|
repo.git.reset('--hard', f'{remote_name}/{branch_name}')
|
||||||
|
logging.info(f"[ComfyUI-Manager] Reset to {remote_name}/{branch_name}")
|
||||||
|
|
||||||
repo.git.submodule('update', '--init', '--recursive')
|
repo.git.submodule('update', '--init', '--recursive')
|
||||||
|
|
||||||
repo.close()
|
repo.close()
|
||||||
@@ -2517,22 +2531,23 @@ def update_to_stable_comfyui(repo_path):
|
|||||||
logging.error('\t'+branch.name)
|
logging.error('\t'+branch.name)
|
||||||
return "fail", None
|
return "fail", None
|
||||||
|
|
||||||
versions, current_tag, _ = get_comfyui_versions(repo)
|
versions, current_tag, latest_tag = get_comfyui_versions(repo)
|
||||||
|
|
||||||
if len(versions) == 0 or (len(versions) == 1 and versions[0] == 'nightly'):
|
if latest_tag is None:
|
||||||
logging.info("[ComfyUI-Manager] Unable to update to the stable ComfyUI version.")
|
logging.info("[ComfyUI-Manager] Unable to update to the stable ComfyUI version.")
|
||||||
return "fail", None
|
return "fail", None
|
||||||
|
|
||||||
if versions[0] == 'nightly':
|
|
||||||
latest_tag = versions[1]
|
|
||||||
else:
|
|
||||||
latest_tag = versions[0]
|
|
||||||
|
|
||||||
if current_tag == latest_tag:
|
tag_ref = next((t for t in repo.tags if t.name == latest_tag), None)
|
||||||
|
if tag_ref is None:
|
||||||
|
logging.info(f"[ComfyUI-Manager] Unable to locate tag '{latest_tag}' in repository.")
|
||||||
|
return "fail", None
|
||||||
|
|
||||||
|
if repo.head.commit == tag_ref.commit:
|
||||||
return "skip", None
|
return "skip", None
|
||||||
else:
|
else:
|
||||||
logging.info(f"[ComfyUI-Manager] Updating ComfyUI: {current_tag} -> {latest_tag}")
|
logging.info(f"[ComfyUI-Manager] Updating ComfyUI: {current_tag} -> {latest_tag}")
|
||||||
repo.git.checkout(latest_tag)
|
repo.git.checkout(tag_ref.name)
|
||||||
|
execute_install_script("ComfyUI", repo_path, instant_execution=False, no_deps=False)
|
||||||
return 'updated', latest_tag
|
return 'updated', latest_tag
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@@ -2664,9 +2679,13 @@ def check_state_of_git_node_pack_single(item, do_fetch=False, do_update_check=Tr
|
|||||||
|
|
||||||
|
|
||||||
def get_installed_pip_packages():
|
def get_installed_pip_packages():
|
||||||
# extract pip package infos
|
try:
|
||||||
cmd = manager_util.make_pip_cmd(['freeze'])
|
# extract pip package infos
|
||||||
pips = subprocess.check_output(cmd, text=True).split('\n')
|
cmd = manager_util.make_pip_cmd(['freeze'])
|
||||||
|
pips = subprocess.check_output(cmd, text=True).split('\n')
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning("[ComfyUI-Manager] Could not enumerate pip packages for snapshot: %s", e)
|
||||||
|
return {}
|
||||||
|
|
||||||
res = {}
|
res = {}
|
||||||
for x in pips:
|
for x in pips:
|
||||||
@@ -3351,36 +3370,80 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
|
|||||||
|
|
||||||
|
|
||||||
def get_comfyui_versions(repo=None):
|
def get_comfyui_versions(repo=None):
|
||||||
if repo is None:
|
repo = repo or git.Repo(comfy_path)
|
||||||
repo = git.Repo(comfy_path)
|
|
||||||
|
|
||||||
|
remote_name = None
|
||||||
try:
|
try:
|
||||||
remote = get_remote_name(repo)
|
remote_name = get_remote_name(repo)
|
||||||
repo.remotes[remote].fetch()
|
repo.remotes[remote_name].fetch()
|
||||||
except:
|
except:
|
||||||
logging.error("[ComfyUI-Manager] Failed to fetch ComfyUI")
|
logging.error("[ComfyUI-Manager] Failed to fetch ComfyUI")
|
||||||
|
|
||||||
versions = [x.name for x in repo.tags if x.name.startswith('v')]
|
def parse_semver(tag_name):
|
||||||
|
match = re.match(r'^v(\d+)\.(\d+)\.(\d+)$', tag_name)
|
||||||
|
return tuple(int(x) for x in match.groups()) if match else None
|
||||||
|
|
||||||
# nearest tag
|
def normalize_describe(tag_name):
|
||||||
versions = sorted(versions, key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
|
if not tag_name:
|
||||||
versions = versions[:4]
|
return None
|
||||||
|
base = tag_name.split('-', 1)[0]
|
||||||
|
return base if parse_semver(base) else None
|
||||||
|
|
||||||
current_tag = repo.git.describe('--tags')
|
# Collect semver tags and sort descending (highest first)
|
||||||
|
semver_tags = []
|
||||||
|
for tag in repo.tags:
|
||||||
|
semver = parse_semver(tag.name)
|
||||||
|
if semver:
|
||||||
|
semver_tags.append((semver, tag.name))
|
||||||
|
semver_tags.sort(key=lambda x: x[0], reverse=True)
|
||||||
|
semver_tags = [name for _, name in semver_tags]
|
||||||
|
|
||||||
if current_tag not in versions:
|
latest_tag = semver_tags[0] if semver_tags else None
|
||||||
versions = sorted(versions + [current_tag], key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
|
|
||||||
versions = versions[:4]
|
|
||||||
|
|
||||||
main_branch = repo.heads.master
|
try:
|
||||||
latest_commit = main_branch.commit
|
described = repo.git.describe('--tags')
|
||||||
latest_tag = repo.git.describe('--tags', latest_commit.hexsha)
|
except Exception:
|
||||||
|
described = ''
|
||||||
|
|
||||||
if latest_tag != versions[0]:
|
try:
|
||||||
versions.insert(0, 'nightly')
|
exact_tag = repo.git.describe('--tags', '--exact-match')
|
||||||
else:
|
except Exception:
|
||||||
versions[0] = 'nightly'
|
exact_tag = ''
|
||||||
|
|
||||||
|
head_is_default = False
|
||||||
|
if remote_name:
|
||||||
|
try:
|
||||||
|
default_head_ref = repo.refs[f'{remote_name}/HEAD']
|
||||||
|
default_commit = default_head_ref.reference.commit
|
||||||
|
head_is_default = repo.head.commit == default_commit
|
||||||
|
except Exception:
|
||||||
|
head_is_default = False
|
||||||
|
|
||||||
|
nearest_semver = normalize_describe(described)
|
||||||
|
exact_semver = exact_tag if parse_semver(exact_tag) else None
|
||||||
|
|
||||||
|
if head_is_default and not exact_tag:
|
||||||
current_tag = 'nightly'
|
current_tag = 'nightly'
|
||||||
|
else:
|
||||||
|
current_tag = exact_tag or described or 'nightly'
|
||||||
|
|
||||||
|
# Prepare semver list for display: top 4 plus the current/nearest semver if missing
|
||||||
|
display_semver_tags = semver_tags[:4]
|
||||||
|
if exact_semver and exact_semver not in display_semver_tags:
|
||||||
|
display_semver_tags.append(exact_semver)
|
||||||
|
elif nearest_semver and nearest_semver not in display_semver_tags:
|
||||||
|
display_semver_tags.append(nearest_semver)
|
||||||
|
|
||||||
|
versions = ['nightly']
|
||||||
|
|
||||||
|
if current_tag and not exact_semver and current_tag not in versions and current_tag not in display_semver_tags:
|
||||||
|
versions.append(current_tag)
|
||||||
|
|
||||||
|
for tag in display_semver_tags:
|
||||||
|
if tag not in versions:
|
||||||
|
versions.append(tag)
|
||||||
|
|
||||||
|
versions = versions[:6]
|
||||||
|
|
||||||
return versions, current_tag, latest_tag
|
return versions, current_tag, latest_tag
|
||||||
|
|
||||||
|
|||||||
356
glob/manager_migration.py
Normal file
356
glob/manager_migration.py
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
"""
|
||||||
|
ComfyUI-Manager migration module.
|
||||||
|
Handles migration from legacy paths to new __manager path structure.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
# Startup notices for notice board
|
||||||
|
startup_notices = [] # List of (message, level) tuples
|
||||||
|
|
||||||
|
|
||||||
|
def add_startup_notice(message, level='warning'):
|
||||||
|
"""Add a notice to be displayed on Manager notice board.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message: HTML-formatted message string
|
||||||
|
level: 'warning', 'error', 'info'
|
||||||
|
"""
|
||||||
|
global startup_notices
|
||||||
|
startup_notices.append((message, level))
|
||||||
|
|
||||||
|
|
||||||
|
# Cache for API check (computed once per session)
|
||||||
|
_cached_has_system_user_api = None
|
||||||
|
|
||||||
|
|
||||||
|
def has_system_user_api():
|
||||||
|
"""Check if ComfyUI has the System User Protection API (PR #10966).
|
||||||
|
|
||||||
|
Result is cached for performance.
|
||||||
|
"""
|
||||||
|
global _cached_has_system_user_api
|
||||||
|
if _cached_has_system_user_api is None:
|
||||||
|
try:
|
||||||
|
import folder_paths
|
||||||
|
_cached_has_system_user_api = hasattr(folder_paths, 'get_system_user_directory')
|
||||||
|
except Exception:
|
||||||
|
_cached_has_system_user_api = False
|
||||||
|
return _cached_has_system_user_api
|
||||||
|
|
||||||
|
|
||||||
|
def get_manager_path(user_dir):
|
||||||
|
"""Get the appropriate manager files path based on ComfyUI version.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: manager_files_path
|
||||||
|
"""
|
||||||
|
if has_system_user_api():
|
||||||
|
return os.path.abspath(os.path.join(user_dir, '__manager'))
|
||||||
|
else:
|
||||||
|
return os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
|
||||||
|
|
||||||
|
|
||||||
|
def run_migration_checks(user_dir, manager_files_path):
|
||||||
|
"""Run all migration and security checks.
|
||||||
|
|
||||||
|
Call this after get_manager_path() to handle:
|
||||||
|
- Legacy config migration (new ComfyUI)
|
||||||
|
- Legacy backup notification (every startup)
|
||||||
|
- Suspicious directory detection (old ComfyUI)
|
||||||
|
- Outdated ComfyUI warning (old ComfyUI)
|
||||||
|
"""
|
||||||
|
if has_system_user_api():
|
||||||
|
migrated = migrate_legacy_config(user_dir, manager_files_path)
|
||||||
|
# Only check for legacy backup if migration didn't just happen
|
||||||
|
# (migration already shows backup location in its message)
|
||||||
|
if not migrated:
|
||||||
|
check_legacy_backup(manager_files_path)
|
||||||
|
else:
|
||||||
|
check_suspicious_manager(user_dir)
|
||||||
|
warn_outdated_comfyui()
|
||||||
|
|
||||||
|
|
||||||
|
def check_legacy_backup(manager_files_path):
|
||||||
|
"""Check for legacy backup and notify user to verify and remove it.
|
||||||
|
|
||||||
|
This runs on every startup to remind users about pending legacy backup.
|
||||||
|
"""
|
||||||
|
backup_dir = os.path.join(manager_files_path, '.legacy-manager-backup')
|
||||||
|
if not os.path.exists(backup_dir):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Terminal output
|
||||||
|
print("\n" + "-"*70)
|
||||||
|
print("[ComfyUI-Manager] NOTICE: Legacy backup exists")
|
||||||
|
print(" - Your old Manager data was backed up to:")
|
||||||
|
print(f" {backup_dir}")
|
||||||
|
print(" - Please verify and remove it when no longer needed.")
|
||||||
|
print("-"*70 + "\n")
|
||||||
|
|
||||||
|
# Notice board output
|
||||||
|
add_startup_notice(
|
||||||
|
"Legacy ComfyUI-Manager data backup exists. Please verify and remove when no longer needed. See terminal for details.",
|
||||||
|
level='info'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def check_suspicious_manager(user_dir):
|
||||||
|
"""Check for suspicious __manager directory on old ComfyUI.
|
||||||
|
|
||||||
|
On old ComfyUI without System User API, if __manager exists with low security,
|
||||||
|
warn the user to verify manually.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if suspicious setup detected
|
||||||
|
"""
|
||||||
|
if has_system_user_api():
|
||||||
|
return False # Not suspicious on new ComfyUI
|
||||||
|
|
||||||
|
suspicious_path = os.path.abspath(os.path.join(user_dir, '__manager'))
|
||||||
|
if not os.path.exists(suspicious_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
config_path = os.path.join(suspicious_path, 'config.ini')
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(config_path)
|
||||||
|
sec_level = config.get('default', 'security_level', fallback='normal').lower()
|
||||||
|
|
||||||
|
if sec_level in ['weak', 'normal-']:
|
||||||
|
# Terminal output
|
||||||
|
print("\n" + "!"*70)
|
||||||
|
print("[ComfyUI-Manager] ERROR: Suspicious path detected!")
|
||||||
|
print(f" - '__manager' exists with low security level: '{sec_level}'")
|
||||||
|
print(" - Please verify manually:")
|
||||||
|
print(f" {config_path}")
|
||||||
|
print("!"*70 + "\n")
|
||||||
|
|
||||||
|
# Notice board output
|
||||||
|
add_startup_notice(
|
||||||
|
"[Security Alert] Suspicious path detected. See terminal log for details.",
|
||||||
|
level='error'
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def warn_outdated_comfyui():
|
||||||
|
"""Warn user about outdated ComfyUI without System User API."""
|
||||||
|
if has_system_user_api():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Terminal output
|
||||||
|
print("\n" + "!"*70)
|
||||||
|
print("[ComfyUI-Manager] ERROR: ComfyUI version is outdated!")
|
||||||
|
print(" - Most operations are blocked for security.")
|
||||||
|
print(" - ComfyUI update is still allowed.")
|
||||||
|
print(" - Please update ComfyUI to use Manager normally.")
|
||||||
|
print("!"*70 + "\n")
|
||||||
|
|
||||||
|
# Notice board output
|
||||||
|
add_startup_notice(
|
||||||
|
"[Security Alert] ComfyUI outdated. Installations blocked (update allowed).<BR>"
|
||||||
|
"Update ComfyUI for normal operation.",
|
||||||
|
level='error'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_legacy_config(user_dir, manager_files_path):
|
||||||
|
"""Migrate ONLY config.ini to new __manager path if needed.
|
||||||
|
|
||||||
|
IMPORTANT: Only config.ini is migrated. Other files (snapshots, cache, etc.)
|
||||||
|
are NOT migrated - users must recreate them.
|
||||||
|
|
||||||
|
Scenarios:
|
||||||
|
1. Legacy exists, New doesn't exist → Migrate config.ini
|
||||||
|
2. Legacy exists, New exists → First update after upgrade
|
||||||
|
- Run ComfyUI dependency installation
|
||||||
|
- Rename legacy to .backup
|
||||||
|
3. Legacy doesn't exist → No migration needed
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if migration was performed
|
||||||
|
"""
|
||||||
|
if not has_system_user_api():
|
||||||
|
return False
|
||||||
|
|
||||||
|
legacy_dir = os.path.join(user_dir, 'default', 'ComfyUI-Manager')
|
||||||
|
legacy_config = os.path.join(legacy_dir, 'config.ini')
|
||||||
|
new_config = os.path.join(manager_files_path, 'config.ini')
|
||||||
|
|
||||||
|
if not os.path.exists(legacy_dir):
|
||||||
|
return False # No legacy directory, nothing to migrate
|
||||||
|
|
||||||
|
# IMPORTANT: Check for config.ini existence, not just directory
|
||||||
|
# (because makedirs() creates __manager before this function is called)
|
||||||
|
|
||||||
|
# Case: Both configs exist (first update after ComfyUI upgrade)
|
||||||
|
# This means user ran new ComfyUI at least once, creating __manager/config.ini
|
||||||
|
if os.path.exists(legacy_config) and os.path.exists(new_config):
|
||||||
|
_handle_first_update_migration(user_dir, legacy_dir, manager_files_path)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Case: Legacy config exists but new config doesn't (normal migration)
|
||||||
|
# This is the first run after ComfyUI upgrade
|
||||||
|
if os.path.exists(legacy_config) and not os.path.exists(new_config):
|
||||||
|
pass # Continue with normal migration below
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Terminal output
|
||||||
|
print("\n" + "-"*70)
|
||||||
|
print("[ComfyUI-Manager] NOTICE: Legacy config.ini detected")
|
||||||
|
print(f" - Old: {legacy_config}")
|
||||||
|
print(f" - New: {new_config}")
|
||||||
|
print(" - Migrating config.ini only (other files are NOT migrated).")
|
||||||
|
print(" - Security level below 'normal' will be raised.")
|
||||||
|
print("-"*70 + "\n")
|
||||||
|
|
||||||
|
_migrate_config_with_security_check(legacy_config, new_config)
|
||||||
|
|
||||||
|
# Move legacy directory to backup
|
||||||
|
_move_legacy_to_backup(legacy_dir, manager_files_path)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_first_update_migration(user_dir, legacy_dir, manager_files_path):
|
||||||
|
"""Handle first ComfyUI update when both legacy and new directories exist.
|
||||||
|
|
||||||
|
This scenario happens when:
|
||||||
|
- User was on old ComfyUI (using default/ComfyUI-Manager)
|
||||||
|
- ComfyUI was updated (now has System User API)
|
||||||
|
- Manager already created __manager on first new run
|
||||||
|
- But legacy directory still exists
|
||||||
|
|
||||||
|
Actions:
|
||||||
|
1. Run ComfyUI dependency installation
|
||||||
|
2. Move legacy to __manager/.legacy-manager-backup
|
||||||
|
"""
|
||||||
|
# Terminal output
|
||||||
|
print("\n" + "-"*70)
|
||||||
|
print("[ComfyUI-Manager] NOTICE: First update after ComfyUI upgrade detected")
|
||||||
|
print(" - Both legacy and new directories exist.")
|
||||||
|
print(" - Running ComfyUI dependency installation...")
|
||||||
|
print("-"*70 + "\n")
|
||||||
|
|
||||||
|
# Run ComfyUI dependency installation
|
||||||
|
# Path: glob/manager_migration.py → glob → comfyui-manager → custom_nodes → ComfyUI
|
||||||
|
try:
|
||||||
|
comfyui_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||||
|
requirements_path = os.path.join(comfyui_path, 'requirements.txt')
|
||||||
|
if os.path.exists(requirements_path):
|
||||||
|
subprocess.run([sys.executable, '-m', 'pip', 'install', '-r', requirements_path],
|
||||||
|
capture_output=True, check=False)
|
||||||
|
print("[ComfyUI-Manager] ComfyUI dependencies installation completed.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ComfyUI-Manager] WARNING: Failed to install ComfyUI dependencies: {e}")
|
||||||
|
|
||||||
|
# Move legacy to backup inside __manager
|
||||||
|
_move_legacy_to_backup(legacy_dir, manager_files_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _move_legacy_to_backup(legacy_dir, manager_files_path):
|
||||||
|
"""Move legacy directory to backup inside __manager.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Path to backup directory if successful, None if failed
|
||||||
|
"""
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
backup_dir = os.path.join(manager_files_path, '.legacy-manager-backup')
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(backup_dir):
|
||||||
|
shutil.rmtree(backup_dir) # Remove old backup if exists
|
||||||
|
shutil.move(legacy_dir, backup_dir)
|
||||||
|
|
||||||
|
# Terminal output (full paths shown here only)
|
||||||
|
print("\n" + "-"*70)
|
||||||
|
print("[ComfyUI-Manager] NOTICE: Legacy settings migrated")
|
||||||
|
print(f" - Old location: {legacy_dir}")
|
||||||
|
print(f" - Backed up to: {backup_dir}")
|
||||||
|
print(" - Please verify and remove the backup when no longer needed.")
|
||||||
|
print("-"*70 + "\n")
|
||||||
|
|
||||||
|
# Notice board output (no full paths for security)
|
||||||
|
add_startup_notice(
|
||||||
|
"Legacy ComfyUI-Manager data migrated. See terminal for details.",
|
||||||
|
level='info'
|
||||||
|
)
|
||||||
|
return backup_dir
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ComfyUI-Manager] WARNING: Failed to backup legacy directory: {e}")
|
||||||
|
add_startup_notice(
|
||||||
|
f"[MIGRATION] Failed to backup legacy directory: {e}",
|
||||||
|
level='warning'
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _migrate_config_with_security_check(legacy_path, new_path):
|
||||||
|
"""Migrate legacy config, raising security level only if below default."""
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
try:
|
||||||
|
config.read(legacy_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ComfyUI-Manager] WARNING: Failed to parse config.ini: {e}")
|
||||||
|
print(" - Creating fresh config with default settings.")
|
||||||
|
add_startup_notice(
|
||||||
|
"[MIGRATION] Failed to parse legacy config. Using defaults.",
|
||||||
|
level='warning'
|
||||||
|
)
|
||||||
|
return # Skip migration, let Manager create fresh config
|
||||||
|
|
||||||
|
# Security level hierarchy: strong > normal > normal- > weak
|
||||||
|
# Default is 'normal', only raise if below default
|
||||||
|
if 'default' in config:
|
||||||
|
current_level = config['default'].get('security_level', 'normal').lower()
|
||||||
|
below_default_levels = ['weak', 'normal-']
|
||||||
|
|
||||||
|
if current_level in below_default_levels:
|
||||||
|
config['default']['security_level'] = 'normal'
|
||||||
|
|
||||||
|
# Terminal output
|
||||||
|
print("\n" + "="*70)
|
||||||
|
print("[ComfyUI-Manager] WARNING: Security level adjusted")
|
||||||
|
print(f" - Previous: '{current_level}' → New: 'normal'")
|
||||||
|
print(" - Raised to prevent unauthorized remote access.")
|
||||||
|
print("="*70 + "\n")
|
||||||
|
|
||||||
|
# Notice board output
|
||||||
|
add_startup_notice(
|
||||||
|
f"[MIGRATION] Security level raised: '{current_level}' → 'normal'.<BR>"
|
||||||
|
"To prevent unauthorized remote access.",
|
||||||
|
level='warning'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(f" - Security level: '{current_level}' (no change needed)")
|
||||||
|
|
||||||
|
# Ensure directory exists
|
||||||
|
os.makedirs(os.path.dirname(new_path), exist_ok=True)
|
||||||
|
|
||||||
|
with open(new_path, 'w') as f:
|
||||||
|
config.write(f)
|
||||||
|
|
||||||
|
|
||||||
|
def force_security_level_if_needed(config_dict):
|
||||||
|
"""Force security level to 'strong' if on old ComfyUI.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_dict: Configuration dictionary to modify in-place
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if security level was forced
|
||||||
|
"""
|
||||||
|
if not has_system_user_api():
|
||||||
|
config_dict['security_level'] = 'strong'
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -22,6 +22,7 @@ import asyncio
|
|||||||
import queue
|
import queue
|
||||||
|
|
||||||
import manager_downloader
|
import manager_downloader
|
||||||
|
import manager_migration
|
||||||
|
|
||||||
|
|
||||||
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
|
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
|
||||||
@@ -276,6 +277,13 @@ import zipfile
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
|
|
||||||
|
def security_403_response():
|
||||||
|
"""Return appropriate 403 response based on ComfyUI version."""
|
||||||
|
if not manager_migration.has_system_user_api():
|
||||||
|
return web.json_response({"error": "comfyui_outdated"}, status=403)
|
||||||
|
return web.json_response({"error": "security_level"}, status=403)
|
||||||
|
|
||||||
|
|
||||||
def get_model_dir(data, show_log=False):
|
def get_model_dir(data, show_log=False):
|
||||||
if 'download_model_base' in folder_paths.folder_names_and_paths:
|
if 'download_model_base' in folder_paths.folder_names_and_paths:
|
||||||
models_base = folder_paths.folder_names_and_paths['download_model_base'][0][0]
|
models_base = folder_paths.folder_names_and_paths['download_model_base'][0][0]
|
||||||
@@ -732,7 +740,7 @@ async def fetch_updates(request):
|
|||||||
async def update_all(request):
|
async def update_all(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
return web.Response(status=403)
|
return security_403_response()
|
||||||
|
|
||||||
with task_worker_lock:
|
with task_worker_lock:
|
||||||
is_processing = task_worker_thread is not None and task_worker_thread.is_alive()
|
is_processing = task_worker_thread is not None and task_worker_thread.is_alive()
|
||||||
@@ -965,7 +973,7 @@ async def get_snapshot_list(request):
|
|||||||
async def remove_snapshot(request):
|
async def remove_snapshot(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
return web.Response(status=403)
|
return security_403_response()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
target = request.rel_url.query["target"]
|
target = request.rel_url.query["target"]
|
||||||
@@ -983,7 +991,7 @@ async def remove_snapshot(request):
|
|||||||
async def restore_snapshot(request):
|
async def restore_snapshot(request):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
return web.Response(status=403)
|
return security_403_response()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
target = request.rel_url.query["target"]
|
target = request.rel_url.query["target"]
|
||||||
@@ -1302,7 +1310,7 @@ async def fix_custom_node(request):
|
|||||||
async def install_custom_node_git_url(request):
|
async def install_custom_node_git_url(request):
|
||||||
if not is_allowed_security_level('high'):
|
if not is_allowed_security_level('high'):
|
||||||
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||||
return web.Response(status=403)
|
return security_403_response()
|
||||||
|
|
||||||
url = await request.text()
|
url = await request.text()
|
||||||
res = await core.gitclone_install(url)
|
res = await core.gitclone_install(url)
|
||||||
@@ -1322,7 +1330,7 @@ async def install_custom_node_git_url(request):
|
|||||||
async def install_custom_node_pip(request):
|
async def install_custom_node_pip(request):
|
||||||
if not is_allowed_security_level('high'):
|
if not is_allowed_security_level('high'):
|
||||||
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||||
return web.Response(status=403)
|
return security_403_response()
|
||||||
|
|
||||||
packages = await request.text()
|
packages = await request.text()
|
||||||
core.pip_install(packages.split(' '))
|
core.pip_install(packages.split(' '))
|
||||||
@@ -1594,6 +1602,16 @@ async def get_notice(request):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Prepend startup notices from manager_migration
|
||||||
|
for message, level in reversed(manager_migration.startup_notices):
|
||||||
|
if level == 'error':
|
||||||
|
style = 'color:red; background-color:white; font-weight:bold'
|
||||||
|
elif level == 'warning':
|
||||||
|
style = 'color:orange; background-color:white; font-weight:bold'
|
||||||
|
else:
|
||||||
|
style = 'color:blue; background-color:white'
|
||||||
|
markdown_content = f'<P style="{style}">{message}</P>' + markdown_content
|
||||||
|
|
||||||
return web.Response(text=markdown_content, status=200)
|
return web.Response(text=markdown_content, status=200)
|
||||||
else:
|
else:
|
||||||
return web.Response(text="Unable to retrieve Notice", status=200)
|
return web.Response(text="Unable to retrieve Notice", status=200)
|
||||||
@@ -1601,11 +1619,35 @@ async def get_notice(request):
|
|||||||
return web.Response(text="Unable to retrieve Notice", status=200)
|
return web.Response(text="Unable to retrieve Notice", status=200)
|
||||||
|
|
||||||
|
|
||||||
|
@routes.get("/manager/startup_alerts")
|
||||||
|
async def get_startup_alerts(request):
|
||||||
|
"""Return startup alerts for customAlert display on page load.
|
||||||
|
|
||||||
|
Returns JSON array of alerts that should be shown to user immediately.
|
||||||
|
All startup notices (error, warning, info) are returned.
|
||||||
|
"""
|
||||||
|
alerts = []
|
||||||
|
|
||||||
|
# Return all startup notices for alert display
|
||||||
|
for message, level in manager_migration.startup_notices:
|
||||||
|
# Convert HTML BR to newlines for customAlert
|
||||||
|
text = message.replace('<BR>', '\n').replace('<br>', '\n')
|
||||||
|
# Add [ComfyUI-Manager] prefix for customAlert (notice board shows in Manager UI anyway)
|
||||||
|
text = text.replace('[Security Alert]', '[ComfyUI-Manager] Security Alert:')
|
||||||
|
text = text.replace('[MIGRATION]', '[ComfyUI-Manager] Migration:')
|
||||||
|
alerts.append({
|
||||||
|
'message': text,
|
||||||
|
'level': level
|
||||||
|
})
|
||||||
|
|
||||||
|
return web.json_response(alerts)
|
||||||
|
|
||||||
|
|
||||||
@routes.get("/manager/reboot")
|
@routes.get("/manager/reboot")
|
||||||
def restart(self):
|
def restart(self):
|
||||||
if not is_allowed_security_level('middle'):
|
if not is_allowed_security_level('middle'):
|
||||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||||
return web.Response(status=403)
|
return security_403_response()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stdout.close_log()
|
sys.stdout.close_log()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import re
|
|||||||
import logging
|
import logging
|
||||||
import platform
|
import platform
|
||||||
import shlex
|
import shlex
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
cache_lock = threading.Lock()
|
cache_lock = threading.Lock()
|
||||||
@@ -34,18 +35,64 @@ def add_python_path_to_env():
|
|||||||
os.environ['PATH'] = os.path.dirname(sys.executable)+sep+os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(sys.executable)+sep+os.environ['PATH']
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=2)
|
||||||
|
def get_pip_cmd(force_uv=False):
|
||||||
|
"""
|
||||||
|
Get the base pip command, with automatic fallback to uv if pip is unavailable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force_uv (bool): If True, use uv directly without trying pip
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Base command for pip operations
|
||||||
|
"""
|
||||||
|
embedded = 'python_embeded' in sys.executable
|
||||||
|
|
||||||
|
# Try pip first (unless forcing uv)
|
||||||
|
if not force_uv:
|
||||||
|
try:
|
||||||
|
test_cmd = [sys.executable] + (['-s'] if embedded else []) + ['-m', 'pip', '--version']
|
||||||
|
subprocess.check_output(test_cmd, stderr=subprocess.DEVNULL, timeout=5)
|
||||||
|
return [sys.executable] + (['-s'] if embedded else []) + ['-m', 'pip']
|
||||||
|
except Exception:
|
||||||
|
logging.warning("[ComfyUI-Manager] `python -m pip` not available. Falling back to `uv`.")
|
||||||
|
|
||||||
|
# Try uv (either forced or pip failed)
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
# Try uv as Python module
|
||||||
|
try:
|
||||||
|
test_cmd = [sys.executable] + (['-s'] if embedded else []) + ['-m', 'uv', '--version']
|
||||||
|
subprocess.check_output(test_cmd, stderr=subprocess.DEVNULL, timeout=5)
|
||||||
|
logging.info("[ComfyUI-Manager] Using `uv` as Python module for pip operations.")
|
||||||
|
return [sys.executable] + (['-s'] if embedded else []) + ['-m', 'uv', 'pip']
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Try standalone uv
|
||||||
|
if shutil.which('uv'):
|
||||||
|
logging.info("[ComfyUI-Manager] Using standalone `uv` for pip operations.")
|
||||||
|
return ['uv', 'pip']
|
||||||
|
|
||||||
|
# Nothing worked
|
||||||
|
logging.error("[ComfyUI-Manager] Neither `python -m pip` nor `uv` are available. Cannot proceed with package operations.")
|
||||||
|
raise Exception("Neither `pip` nor `uv` are available for package management")
|
||||||
|
|
||||||
|
|
||||||
def make_pip_cmd(cmd):
|
def make_pip_cmd(cmd):
|
||||||
if 'python_embeded' in sys.executable:
|
"""
|
||||||
if use_uv:
|
Create a pip command by combining the cached base pip command with the given arguments.
|
||||||
return [sys.executable, '-s', '-m', 'uv', 'pip'] + cmd
|
|
||||||
else:
|
Args:
|
||||||
return [sys.executable, '-s', '-m', 'pip'] + cmd
|
cmd (list): List of pip command arguments (e.g., ['install', 'package'])
|
||||||
else:
|
|
||||||
# FIXED: https://github.com/ltdrdata/ComfyUI-Manager/issues/1667
|
Returns:
|
||||||
if use_uv:
|
list: Complete command list ready for subprocess execution
|
||||||
return [sys.executable, '-m', 'uv', 'pip'] + cmd
|
"""
|
||||||
else:
|
global use_uv
|
||||||
return [sys.executable, '-m', 'pip'] + cmd
|
base_cmd = get_pip_cmd(force_uv=use_uv)
|
||||||
|
return base_cmd + cmd
|
||||||
|
|
||||||
|
|
||||||
# DON'T USE StrictVersion - cannot handle pre_release version
|
# DON'T USE StrictVersion - cannot handle pre_release version
|
||||||
# try:
|
# try:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ This directory contains the JavaScript frontend implementation for ComfyUI-Manag
|
|||||||
## Sharing Components
|
## Sharing Components
|
||||||
|
|
||||||
- **comfyui-share-common.js**: Base functionality for workflow sharing features.
|
- **comfyui-share-common.js**: Base functionality for workflow sharing features.
|
||||||
- **comfyui-share-copus.js**: Integration with the ComfyUI Opus sharing platform.
|
- **comfyui-share-copus.js**: Integration with the ComfyUI Copus sharing platform.
|
||||||
- **comfyui-share-openart.js**: Integration with the OpenArt sharing platform.
|
- **comfyui-share-openart.js**: Integration with the OpenArt sharing platform.
|
||||||
- **comfyui-share-youml.js**: Integration with the YouML sharing platform.
|
- **comfyui-share-youml.js**: Integration with the YouML sharing platform.
|
||||||
|
|
||||||
@@ -47,4 +47,4 @@ CSS files are included for specific components:
|
|||||||
- **custom-nodes-manager.css**: Styling for the node management UI
|
- **custom-nodes-manager.css**: Styling for the node management UI
|
||||||
- **model-manager.css**: Styling for the model management UI
|
- **model-manager.css**: Styling for the model management UI
|
||||||
|
|
||||||
This frontend implementation provides a comprehensive yet user-friendly interface for managing the ComfyUI ecosystem.
|
This frontend implementation provides a comprehensive yet user-friendly interface for managing the ComfyUI ecosystem.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { api } from "../../scripts/api.js";
|
import { api } from "../../scripts/api.js";
|
||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { sleep, customConfirm, customAlert } from "./common.js";
|
import { sleep, customConfirm, customAlert, handle403Response, show_message } from "./common.js";
|
||||||
|
|
||||||
async function tryInstallCustomNode(event) {
|
async function tryInstallCustomNode(event) {
|
||||||
let msg = '-= [ComfyUI Manager] extension installation request =-\n\n';
|
let msg = '-= [ComfyUI Manager] extension installation request =-\n\n';
|
||||||
@@ -42,7 +42,7 @@ async function tryInstallCustomNode(event) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(response.status == 403) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
await handle403Response(response);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if(response.status == 400) {
|
else if(response.status == 400) {
|
||||||
@@ -54,7 +54,7 @@ async function tryInstallCustomNode(event) {
|
|||||||
|
|
||||||
let response = await api.fetchApi("/manager/reboot");
|
let response = await api.fetchApi("/manager/reboot");
|
||||||
if(response.status == 403) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
await handle403Response(response);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
|||||||
import {
|
import {
|
||||||
free_models, install_pip, install_via_git_url, manager_instance,
|
free_models, install_pip, install_via_git_url, manager_instance,
|
||||||
rebootAPI, setManagerInstance, show_message, customAlert, customPrompt,
|
rebootAPI, setManagerInstance, show_message, customAlert, customPrompt,
|
||||||
infoToast, showTerminal, setNeedRestart
|
infoToast, showTerminal, setNeedRestart, handle403Response
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
||||||
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
||||||
@@ -753,9 +753,9 @@ async function onQueueStatus(event) {
|
|||||||
|
|
||||||
const rebootButton = document.getElementById('cm-reboot-button5');
|
const rebootButton = document.getElementById('cm-reboot-button5');
|
||||||
rebootButton?.addEventListener("click",
|
rebootButton?.addEventListener("click",
|
||||||
function() {
|
async function() {
|
||||||
if(rebootAPI()) {
|
if(await rebootAPI()) {
|
||||||
manager_dialog.close();
|
manager_instance.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -780,8 +780,13 @@ async function updateAll(update_comfyui) {
|
|||||||
|
|
||||||
const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`);
|
const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`);
|
||||||
|
|
||||||
if (response.status == 401) {
|
if (response.status == 403) {
|
||||||
|
await handle403Response(response);
|
||||||
|
reset_action_buttons();
|
||||||
|
}
|
||||||
|
else if (response.status == 401) {
|
||||||
customAlert('Another task is already in progress. Please stop the ongoing task first.');
|
customAlert('Another task is already in progress. Please stop the ongoing task first.');
|
||||||
|
reset_action_buttons();
|
||||||
}
|
}
|
||||||
else if(response.status == 200) {
|
else if(response.status == 200) {
|
||||||
is_updating = true;
|
is_updating = true;
|
||||||
@@ -1453,6 +1458,31 @@ app.registerExtension({
|
|||||||
|
|
||||||
load_components();
|
load_components();
|
||||||
|
|
||||||
|
// Fetch and show startup alerts (critical errors like outdated ComfyUI)
|
||||||
|
// Poll until extensionManager.toast is ready (set in Vue onMounted)
|
||||||
|
const showStartupAlerts = async () => {
|
||||||
|
let toastWaitCount = 0;
|
||||||
|
const waitForToast = () => {
|
||||||
|
if (window['app']?.extensionManager?.toast) {
|
||||||
|
fetch('/manager/startup_alerts')
|
||||||
|
.then(response => response.ok ? response.json() : [])
|
||||||
|
.then(alerts => {
|
||||||
|
for (const alert of alerts) {
|
||||||
|
customAlert(alert.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => console.warn('[ComfyUI-Manager] Failed to fetch startup alerts:', e));
|
||||||
|
} else if (toastWaitCount < 300) { // Max 30 seconds (300 * 100ms)
|
||||||
|
toastWaitCount++;
|
||||||
|
setTimeout(waitForToast, 100);
|
||||||
|
} else {
|
||||||
|
console.warn('[ComfyUI-Manager] Timeout waiting for toast. Startup alerts skipped.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
waitForToast();
|
||||||
|
};
|
||||||
|
showStartupAlerts();
|
||||||
|
|
||||||
const menu = document.querySelector(".comfy-menu");
|
const menu = document.querySelector(".comfy-menu");
|
||||||
const separator = document.createElement("hr");
|
const separator = document.createElement("hr");
|
||||||
|
|
||||||
|
|||||||
40
js/common.js
40
js/common.js
@@ -100,6 +100,19 @@ export function show_message(msg) {
|
|||||||
app.ui.dialog.element.style.zIndex = 1100;
|
app.ui.dialog.element.style.zIndex = 1100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function handle403Response(res, defaultMessage) {
|
||||||
|
try {
|
||||||
|
const data = await res.json();
|
||||||
|
if(data.error === 'comfyui_outdated') {
|
||||||
|
show_message('ComfyUI version is outdated.<BR>Please update ComfyUI to use Manager normally.');
|
||||||
|
} else {
|
||||||
|
show_message(defaultMessage || 'This action is not allowed with this security level configuration.');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
show_message(defaultMessage || 'This action is not allowed with this security level configuration.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function sleep(ms) {
|
export async function sleep(ms) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
@@ -163,20 +176,23 @@ export async function customPrompt(title, message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function rebootAPI() {
|
export async function rebootAPI() {
|
||||||
if ('electronAPI' in window) {
|
if ('electronAPI' in window) {
|
||||||
window.electronAPI.restartApp();
|
window.electronAPI.restartApp();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
customConfirm("Are you sure you'd like to reboot the server?").then((isConfirmed) => {
|
const isConfirmed = await customConfirm("Are you sure you'd like to reboot the server?");
|
||||||
if (isConfirmed) {
|
if (isConfirmed) {
|
||||||
try {
|
try {
|
||||||
api.fetchApi("/manager/reboot");
|
const response = await api.fetchApi("/manager/reboot");
|
||||||
|
if (response.status == 403) {
|
||||||
|
await handle403Response(response);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
catch(exception) {}
|
|
||||||
}
|
}
|
||||||
});
|
catch(exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -216,7 +232,7 @@ export async function install_pip(packages) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(res.status == 403) {
|
if(res.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
await handle403Response(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +267,7 @@ export async function install_via_git_url(url, manager_dialog) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(res.status == 403) {
|
if(res.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
await handle403Response(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,9 +278,9 @@ export async function install_via_git_url(url, manager_dialog) {
|
|||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
rebootButton.addEventListener("click",
|
rebootButton.addEventListener("click",
|
||||||
function() {
|
async function() {
|
||||||
if(rebootAPI()) {
|
if(await rebootAPI()) {
|
||||||
manager_dialog.close();
|
manager_instance.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.cn-manager {
|
.cn-manager {
|
||||||
--grid-font: -apple-system, BlinkMacSystemFont, "Segue UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
--grid-font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||||
z-index: 1099;
|
z-index: 1099;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
|
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
|
||||||
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
|
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
|
||||||
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
|
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
|
||||||
showPopover, hidePopover
|
showPopover, hidePopover, handle403Response
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
|
|
||||||
// https://cenfun.github.io/turbogrid/api.html
|
// https://cenfun.github.io/turbogrid/api.html
|
||||||
@@ -1528,7 +1528,16 @@ export class CustomNodesManager {
|
|||||||
errorMsg = `'${item.title}': `;
|
errorMsg = `'${item.title}': `;
|
||||||
|
|
||||||
if(res.status == 403) {
|
if(res.status == 403) {
|
||||||
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
try {
|
||||||
|
const data = await res.json();
|
||||||
|
if(data.error === 'comfyui_outdated') {
|
||||||
|
errorMsg += `ComfyUI version is outdated. Please update ComfyUI to use Manager normally.\n`;
|
||||||
|
} else {
|
||||||
|
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
||||||
|
}
|
||||||
} else if(res.status == 404) {
|
} else if(res.status == 404) {
|
||||||
errorMsg += `With the current security level configuration, only custom nodes from the <B>"default channel"</B> can be installed.\n`;
|
errorMsg += `With the current security level configuration, only custom nodes from the <B>"default channel"</B> can be installed.\n`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { $el } from "../../scripts/ui.js";
|
import { $el } from "../../scripts/ui.js";
|
||||||
import {
|
import {
|
||||||
manager_instance, rebootAPI,
|
manager_instance, rebootAPI,
|
||||||
fetchData, md5, icons, show_message, customAlert, infoToast, showTerminal,
|
fetchData, md5, icons, show_message, customAlert, infoToast, showTerminal,
|
||||||
storeColumnWidth, restoreColumnWidth, loadCss
|
storeColumnWidth, restoreColumnWidth, loadCss, handle403Response
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import { api } from "../../scripts/api.js";
|
import { api } from "../../scripts/api.js";
|
||||||
|
|
||||||
@@ -477,7 +477,16 @@ export class ModelManager {
|
|||||||
errorMsg = `'${item.name}': `;
|
errorMsg = `'${item.name}': `;
|
||||||
|
|
||||||
if(res.status == 403) {
|
if(res.status == 403) {
|
||||||
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
try {
|
||||||
|
const data = await res.json();
|
||||||
|
if(data.error === 'comfyui_outdated') {
|
||||||
|
errorMsg += `ComfyUI version is outdated. Please update ComfyUI to use Manager normally.\n`;
|
||||||
|
} else {
|
||||||
|
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
errorMsg += await res.text() + '\n';
|
errorMsg += await res.text() + '\n';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { api } from "../../scripts/api.js"
|
import { api } from "../../scripts/api.js"
|
||||||
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
||||||
import { manager_instance, rebootAPI, show_message } from "./common.js";
|
import { manager_instance, rebootAPI, show_message, handle403Response } from "./common.js";
|
||||||
|
|
||||||
|
|
||||||
async function restore_snapshot(target) {
|
async function restore_snapshot(target) {
|
||||||
@@ -10,7 +10,7 @@ async function restore_snapshot(target) {
|
|||||||
const response = await api.fetchApi(`/snapshot/restore?target=${target}`, { cache: "no-store" });
|
const response = await api.fetchApi(`/snapshot/restore?target=${target}`, { cache: "no-store" });
|
||||||
|
|
||||||
if(response.status == 403) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
await handle403Response(response);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ async function remove_snapshot(target) {
|
|||||||
const response = await api.fetchApi(`/snapshot/remove?target=${target}`, { cache: "no-store" });
|
const response = await api.fetchApi(`/snapshot/remove?target=${target}`, { cache: "no-store" });
|
||||||
|
|
||||||
if(response.status == 403) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
await handle403Response(response);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,8 +145,8 @@ export class SnapshotManager extends ComfyDialog {
|
|||||||
if(btn_id) {
|
if(btn_id) {
|
||||||
const rebootButton = document.getElementById(btn_id);
|
const rebootButton = document.getElementById(btn_id);
|
||||||
const self = this;
|
const self = this;
|
||||||
rebootButton.onclick = function() {
|
rebootButton.onclick = async function() {
|
||||||
if(rebootAPI()) {
|
if(await rebootAPI()) {
|
||||||
self.close();
|
self.close();
|
||||||
self.manager_dialog.close();
|
self.manager_dialog.close();
|
||||||
}
|
}
|
||||||
|
|||||||
273
json-checker.py
273
json-checker.py
@@ -1,25 +1,264 @@
|
|||||||
import json
|
#!/usr/bin/env python3
|
||||||
import argparse
|
"""JSON Entry Validator
|
||||||
|
|
||||||
def check_json_syntax(file_path):
|
Validates JSON entries based on content structure.
|
||||||
|
|
||||||
|
Validation rules based on JSON content:
|
||||||
|
- {"custom_nodes": [...]}: Validates required fields (author, title, reference, files, install_type, description)
|
||||||
|
- {"models": [...]}: Validates JSON syntax only (no required fields)
|
||||||
|
- Other JSON structures: Validates JSON syntax only
|
||||||
|
|
||||||
|
Git repository URL validation (for custom_nodes):
|
||||||
|
1. URLs must NOT end with .git
|
||||||
|
2. URLs must follow format: https://github.com/{author}/{reponame}
|
||||||
|
3. .py and .js files are exempt from this check
|
||||||
|
|
||||||
|
Supported formats:
|
||||||
|
- Array format: [{...}, {...}]
|
||||||
|
- Object format: {"custom_nodes": [...]} or {"models": [...]}
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
# Required fields for each entry type
|
||||||
|
REQUIRED_FIELDS_CUSTOM_NODE = ['author', 'title', 'reference', 'files', 'install_type', 'description']
|
||||||
|
REQUIRED_FIELDS_MODEL = [] # model-list.json doesn't require field validation
|
||||||
|
|
||||||
|
# Pattern for valid GitHub repository URL (without .git suffix)
|
||||||
|
GITHUB_REPO_PATTERN = re.compile(r'^https://github\.com/[^/]+/[^/]+$')
|
||||||
|
|
||||||
|
|
||||||
|
def get_entry_context(entry: Dict) -> str:
|
||||||
|
"""Get identifying information from entry for error messages
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry: JSON entry
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
String with author and reference info
|
||||||
|
"""
|
||||||
|
parts = []
|
||||||
|
if 'author' in entry:
|
||||||
|
parts.append(f"author={entry['author']}")
|
||||||
|
if 'reference' in entry:
|
||||||
|
parts.append(f"ref={entry['reference']}")
|
||||||
|
if 'title' in entry:
|
||||||
|
parts.append(f"title={entry['title']}")
|
||||||
|
|
||||||
|
if parts:
|
||||||
|
return " | ".join(parts)
|
||||||
|
else:
|
||||||
|
# No identifying info - show actual entry content (truncated)
|
||||||
|
import json
|
||||||
|
entry_str = json.dumps(entry, ensure_ascii=False)
|
||||||
|
if len(entry_str) > 100:
|
||||||
|
entry_str = entry_str[:100] + "..."
|
||||||
|
return f"content={entry_str}"
|
||||||
|
|
||||||
|
|
||||||
|
def validate_required_fields(entry: Dict, entry_index: int, required_fields: List[str]) -> List[str]:
|
||||||
|
"""Validate that all required fields are present
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry: JSON entry to validate
|
||||||
|
entry_index: Index of entry in array (for error reporting)
|
||||||
|
required_fields: List of required field names
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of error descriptions (without entry prefix/context)
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for field in required_fields:
|
||||||
|
if field not in entry:
|
||||||
|
errors.append(f"Missing required field '{field}'")
|
||||||
|
elif entry[field] is None:
|
||||||
|
errors.append(f"Field '{field}' is null")
|
||||||
|
elif isinstance(entry[field], str) and not entry[field].strip():
|
||||||
|
errors.append(f"Field '{field}' is empty")
|
||||||
|
elif field == 'files' and not entry[field]: # Empty array
|
||||||
|
errors.append("Field 'files' is empty array")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_git_repo_urls(entry: Dict, entry_index: int) -> List[str]:
|
||||||
|
"""Validate git repository URLs in 'files' array
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Git repo URLs must NOT end with .git
|
||||||
|
- Must follow format: https://github.com/{author}/{reponame}
|
||||||
|
- .py and .js files are exempt
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry: JSON entry to validate
|
||||||
|
entry_index: Index of entry in array (for error reporting)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of error descriptions (without entry prefix/context)
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
if 'files' not in entry or not isinstance(entry['files'], list):
|
||||||
|
return errors
|
||||||
|
|
||||||
|
for file_url in entry['files']:
|
||||||
|
if not isinstance(file_url, str):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip .py and .js files - they're exempt from git repo validation
|
||||||
|
if file_url.endswith('.py') or file_url.endswith('.js'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if it's a GitHub URL (likely a git repo)
|
||||||
|
if 'github.com' in file_url:
|
||||||
|
# Error if URL ends with .git
|
||||||
|
if file_url.endswith('.git'):
|
||||||
|
errors.append(f"Git repo URL must NOT end with .git: {file_url}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Validate format: https://github.com/{author}/{reponame}
|
||||||
|
if not GITHUB_REPO_PATTERN.match(file_url):
|
||||||
|
errors.append(f"Invalid git repo URL format (expected https://github.com/author/reponame): {file_url}")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_entry(entry: Dict, entry_index: int, required_fields: List[str]) -> List[str]:
|
||||||
|
"""Validate a single JSON entry
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry: JSON entry to validate
|
||||||
|
entry_index: Index of entry in array (for error reporting)
|
||||||
|
required_fields: List of required field names
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of error messages (empty if valid)
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
# Check required fields
|
||||||
|
errors.extend(validate_required_fields(entry, entry_index, required_fields))
|
||||||
|
|
||||||
|
# Check git repository URLs
|
||||||
|
errors.extend(validate_git_repo_urls(entry, entry_index))
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_json_file(file_path: str) -> Tuple[bool, List[str]]:
|
||||||
|
"""Validate JSON file containing entries
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path: Path to JSON file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (is_valid, error_messages)
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
# Check file exists
|
||||||
|
path = Path(file_path)
|
||||||
|
if not path.exists():
|
||||||
|
return False, [f"File not found: {file_path}"]
|
||||||
|
|
||||||
|
# Load JSON
|
||||||
try:
|
try:
|
||||||
with open(file_path, 'r', encoding='utf-8') as file:
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
json_str = file.read()
|
data = json.load(f)
|
||||||
json.loads(json_str)
|
|
||||||
print(f"[ OK ] {file_path}")
|
|
||||||
except UnicodeDecodeError as e:
|
|
||||||
print(f"Unicode decode error: {e}")
|
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"[FAIL] {file_path}\n\n {e}\n")
|
return False, [f"Invalid JSON: {e}"]
|
||||||
except FileNotFoundError:
|
except Exception as e:
|
||||||
print(f"[FAIL] {file_path}\n\n File not found\n")
|
return False, [f"Error reading file: {e}"]
|
||||||
|
|
||||||
|
# Determine required fields based on JSON content
|
||||||
|
required_fields = []
|
||||||
|
|
||||||
|
# Validate structure - support both array and object formats
|
||||||
|
entries_to_validate = []
|
||||||
|
|
||||||
|
if isinstance(data, list):
|
||||||
|
# Direct array format: [{...}, {...}]
|
||||||
|
entries_to_validate = data
|
||||||
|
elif isinstance(data, dict):
|
||||||
|
# Object format: {"custom_nodes": [...]} or {"models": [...]}
|
||||||
|
# Determine validation based on keys
|
||||||
|
if 'custom_nodes' in data and isinstance(data['custom_nodes'], list):
|
||||||
|
required_fields = REQUIRED_FIELDS_CUSTOM_NODE
|
||||||
|
entries_to_validate = data['custom_nodes']
|
||||||
|
elif 'models' in data and isinstance(data['models'], list):
|
||||||
|
required_fields = REQUIRED_FIELDS_MODEL
|
||||||
|
entries_to_validate = data['models']
|
||||||
|
else:
|
||||||
|
# Other JSON structures (extension-node-map.json, etc.) - just validate JSON syntax
|
||||||
|
return True, []
|
||||||
|
else:
|
||||||
|
return False, ["JSON root must be either an array or an object containing arrays"]
|
||||||
|
|
||||||
|
# Validate each entry
|
||||||
|
for idx, entry in enumerate(entries_to_validate, start=1):
|
||||||
|
if not isinstance(entry, dict):
|
||||||
|
# Show actual value for type errors
|
||||||
|
entry_str = json.dumps(entry, ensure_ascii=False) if not isinstance(entry, str) else repr(entry)
|
||||||
|
if len(entry_str) > 150:
|
||||||
|
entry_str = entry_str[:150] + "..."
|
||||||
|
errors.append(f"\n❌ Entry #{idx}: Must be an object, got {type(entry).__name__}")
|
||||||
|
errors.append(f" Actual value: {entry_str}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
entry_errors = validate_entry(entry, idx, required_fields)
|
||||||
|
if entry_errors:
|
||||||
|
# Group errors by entry with context
|
||||||
|
context = get_entry_context(entry)
|
||||||
|
errors.append(f"\n❌ Entry #{idx} ({context}):")
|
||||||
|
for error in entry_errors:
|
||||||
|
errors.append(f" - {error}")
|
||||||
|
|
||||||
|
is_valid = len(errors) == 0
|
||||||
|
return is_valid, errors
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="JSON File Syntax Checker")
|
"""Main entry point"""
|
||||||
parser.add_argument("file_path", type=str, help="Path to the JSON file for syntax checking")
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python json-checker.py <json-file>")
|
||||||
|
print("\nValidates JSON entries based on content:")
|
||||||
|
print(" - {\"custom_nodes\": [...]}: Validates required fields (author, title, reference, files, install_type, description)")
|
||||||
|
print(" - {\"models\": [...]}: Validates JSON syntax only (no required fields)")
|
||||||
|
print(" - Other JSON structures: Validates JSON syntax only")
|
||||||
|
print("\nGit repo URL validation (for custom_nodes):")
|
||||||
|
print(" - URLs must NOT end with .git")
|
||||||
|
print(" - URLs must follow: https://github.com/{author}/{reponame}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
args = parser.parse_args()
|
file_path = sys.argv[1]
|
||||||
check_json_syntax(args.file_path)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
is_valid, errors = validate_json_file(file_path)
|
||||||
|
|
||||||
|
if is_valid:
|
||||||
|
print(f"✅ {file_path}: Validation passed")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print(f"Validating: {file_path}")
|
||||||
|
print("=" * 60)
|
||||||
|
print("❌ Validation failed!\n")
|
||||||
|
print("Errors:")
|
||||||
|
# Count actual errors (lines starting with " -")
|
||||||
|
error_count = sum(1 for e in errors if e.strip().startswith('-'))
|
||||||
|
for error in errors:
|
||||||
|
# Don't add ❌ prefix to grouped entries (they already have it)
|
||||||
|
if error.strip().startswith('❌'):
|
||||||
|
print(error)
|
||||||
|
else:
|
||||||
|
print(error)
|
||||||
|
print(f"\nTotal errors: {error_count}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
313
model-list.json
313
model-list.json
@@ -5355,6 +5355,317 @@
|
|||||||
"filename": "LBM_relighting.safetensors",
|
"filename": "LBM_relighting.safetensors",
|
||||||
"url": "https://huggingface.co/jasperai/LBM_relighting/resolve/main/model.safetensors",
|
"url": "https://huggingface.co/jasperai/LBM_relighting/resolve/main/model.safetensors",
|
||||||
"size": "5.02GB"
|
"size": "5.02GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image VAE",
|
||||||
|
"type": "VAE",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "vae/qwen-image",
|
||||||
|
"description": "VAE model for Qwen-Image",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI",
|
||||||
|
"filename": "qwen_image_vae.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors",
|
||||||
|
"size": "335MB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen 2.5 VL 7B Text Encoder (fp8_scaled)",
|
||||||
|
"type": "clip",
|
||||||
|
"base": "Qwen-2.5-VL",
|
||||||
|
"save_path": "text_encoders/qwen",
|
||||||
|
"description": "Qwen 2.5 VL 7B text encoder model (fp8_scaled)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI",
|
||||||
|
"filename": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||||
|
"size": "3.75GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen 2.5 VL 7B Text Encoder",
|
||||||
|
"type": "clip",
|
||||||
|
"base": "Qwen-2.5-VL",
|
||||||
|
"save_path": "text_encoders/qwen",
|
||||||
|
"description": "Qwen 2.5 VL 7B text encoder model",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI",
|
||||||
|
"filename": "qwen_2.5_vl_7b.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b.safetensors",
|
||||||
|
"size": "7.51GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image Diffusion Model (fp8_e4m3fn)",
|
||||||
|
"type": "diffusion_model",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "diffusion_models/qwen-image",
|
||||||
|
"description": "Qwen-Image diffusion model (fp8_e4m3fn)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI",
|
||||||
|
"filename": "qwen_image_fp8_e4m3fn.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_fp8_e4m3fn.safetensors",
|
||||||
|
"size": "4.89GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image Diffusion Model (bf16)",
|
||||||
|
"type": "diffusion_model",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "diffusion_models/qwen-image",
|
||||||
|
"description": "Qwen-Image diffusion model (bf16)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI",
|
||||||
|
"filename": "qwen_image_bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_bf16.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit 2509 Diffusion Model (fp8_e4m3fn)",
|
||||||
|
"type": "diffusion_model",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "diffusion_models/qwen-image-edit",
|
||||||
|
"description": "Qwen-Image-Edit 2509 diffusion model (fp8_e4m3fn)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI",
|
||||||
|
"filename": "qwen_image_edit_2509_fp8_e4m3fn.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_2509_fp8_e4m3fn.safetensors",
|
||||||
|
"size": "4.89GB"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit 2509 Diffusion Model (bf16)",
|
||||||
|
"type": "diffusion_model",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "diffusion_models/qwen-image-edit",
|
||||||
|
"description": "Qwen-Image-Edit 2509 diffusion model (bf16)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI",
|
||||||
|
"filename": "qwen_image_edit_2509_bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_2509_bf16.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit Diffusion Model (fp8_e4m3fn)",
|
||||||
|
"type": "diffusion_model",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "diffusion_models/qwen-image-edit",
|
||||||
|
"description": "Qwen-Image-Edit diffusion model (fp8_e4m3fn)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI",
|
||||||
|
"filename": "qwen_image_edit_fp8_e4m3fn.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_fp8_e4m3fn.safetensors",
|
||||||
|
"size": "4.89GB"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit Diffusion Model (bf16)",
|
||||||
|
"type": "diffusion_model",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "diffusion_models/qwen-image-edit",
|
||||||
|
"description": "Qwen-Image-Edit diffusion model (bf16)",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI",
|
||||||
|
"filename": "qwen_image_edit_bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_bf16.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 8steps V1.0",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 8-step LoRA model V1.0",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-8steps-V1.0.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-8steps-V1.0.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 4steps V1.0",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 4-step LoRA model V1.0",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-4steps-V1.0.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-4steps-V1.0.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 4steps V1.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 4-step LoRA model V1.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-4steps-V1.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-4steps-V1.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 4steps V2.0",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 4-step LoRA model V2.0",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-4steps-V2.0.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-4steps-V2.0.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 4steps V2.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 4-step LoRA model V2.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-4steps-V2.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-4steps-V2.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 8steps V1.1",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 8-step LoRA model V1.1",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-8steps-V1.1.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-8steps-V1.1.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 8steps V1.1 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 8-step LoRA model V1.1 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-8steps-V1.1-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-8steps-V1.1-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 8steps V2.0",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 8-step LoRA model V2.0",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-8steps-V2.0.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-8steps-V2.0.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Lightning 8steps V2.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "loras/qwen-image-lightning",
|
||||||
|
"description": "Qwen-Image-Lightning 8-step LoRA model V2.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Lightning-8steps-V2.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-8steps-V2.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-Lightning 4steps V1.0",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-Lightning 4-step LoRA model V1.0",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-Lightning-4steps-V1.0.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-Lightning-4steps-V1.0.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-Lightning 4steps V1.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-Lightning 4-step LoRA model V1.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-Lightning-4steps-V1.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-Lightning-4steps-V1.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-Lightning 8steps V1.0",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-Lightning 8-step LoRA model V1.0",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-Lightning-8steps-V1.0.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-Lightning-8steps-V1.0.safetensors",
|
||||||
|
"size": "9.78GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-Lightning 8steps V1.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-Lightning 8-step LoRA model V1.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-Lightning-8steps-V1.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-Lightning-8steps-V1.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-2509-Lightning 4steps V1.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-2509-Lightning 4-step LoRA model V1.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-2509-Lightning-4steps-V1.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-2509/Qwen-Image-Edit-2509-Lightning-4steps-V1.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-2509-Lightning 4steps V1.0 (fp32)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-2509-Lightning 4-step LoRA model V1.0 (fp32)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-2509-Lightning-4steps-V1.0-fp32.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-2509/Qwen-Image-Edit-2509-Lightning-4steps-V1.0-fp32.safetensors",
|
||||||
|
"size": "39.1GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-2509-Lightning 8steps V1.0 (bf16)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-2509-Lightning 8-step LoRA model V1.0 (bf16)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-2509-Lightning-8steps-V1.0-bf16.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-2509/Qwen-Image-Edit-2509-Lightning-8steps-V1.0-bf16.safetensors",
|
||||||
|
"size": "19.6GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image-Edit-2509-Lightning 8steps V1.0 (fp32)",
|
||||||
|
"type": "lora",
|
||||||
|
"base": "Qwen-Image-Edit",
|
||||||
|
"save_path": "loras/qwen-image-edit-lightning",
|
||||||
|
"description": "Qwen-Image-Edit-2509-Lightning 8-step LoRA model V1.0 (fp32)",
|
||||||
|
"reference": "https://huggingface.co/lightx2v/Qwen-Image-Lightning",
|
||||||
|
"filename": "Qwen-Image-Edit-2509-Lightning-8steps-V1.0-fp32.safetensors",
|
||||||
|
"url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-2509/Qwen-Image-Edit-2509-Lightning-8steps-V1.0-fp32.safetensors",
|
||||||
|
"size": "39.1GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image InstantX ControlNet Union",
|
||||||
|
"type": "controlnet",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "controlnet/qwen-image/instantx",
|
||||||
|
"description": "Qwen-Image InstantX ControlNet Union model",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image-InstantX-ControlNets",
|
||||||
|
"filename": "Qwen-Image-InstantX-ControlNet-Union.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image-InstantX-ControlNets/resolve/main/split_files/controlnet/Qwen-Image-InstantX-ControlNet-Union.safetensors",
|
||||||
|
"size": "2.54GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Qwen-Image InstantX ControlNet Inpainting",
|
||||||
|
"type": "controlnet",
|
||||||
|
"base": "Qwen-Image",
|
||||||
|
"save_path": "controlnet/qwen-image/instantx",
|
||||||
|
"description": "Qwen-Image InstantX ControlNet Inpainting model",
|
||||||
|
"reference": "https://huggingface.co/Comfy-Org/Qwen-Image-InstantX-ControlNets",
|
||||||
|
"filename": "Qwen-Image-InstantX-ControlNet-Inpainting.safetensors",
|
||||||
|
"url": "https://huggingface.co/Comfy-Org/Qwen-Image-InstantX-ControlNets/resolve/main/split_files/controlnet/Qwen-Image-InstantX-ControlNet-Inpainting.safetensors",
|
||||||
|
"size": "2.54GB"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
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
@@ -169,6 +169,16 @@
|
|||||||
],
|
],
|
||||||
"install_type": "git-clone",
|
"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"
|
"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)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,890 @@
|
|||||||
{
|
{
|
||||||
"custom_nodes": [
|
"custom_nodes": [
|
||||||
|
{
|
||||||
|
"author": "cdanielp",
|
||||||
|
"title": "COMFYUI_PROMPTMODELS [REMOVED]",
|
||||||
|
"reference": "https://github.com/cdanielp/COMFYUI_PROMPTMODELS",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/cdanielp/COMFYUI_PROMPTMODELS"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom nodes for ComfyUI by PROMPTMODELS."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "mcrataobrabo",
|
||||||
|
"title": "comfyui-smart-lora-downloader - Automatically Fetch Missing LoRAs [REMOVED]",
|
||||||
|
"reference": "https://github.com/mcrataobrabo/comfyui-smart-lora-downloader",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/mcrataobrabo/comfyui-smart-lora-downloader"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Automatically detect and download missing LoRAs for ComfyUI workflows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "KANAsho34636",
|
||||||
|
"title": "ComfyUI-NaturalSort-ImageLoader [REMOVED]",
|
||||||
|
"reference": "https://github.com/KANAsho34636/ComfyUI-NaturalSort-ImageLoader",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/KANAsho34636/ComfyUI-NaturalSort-ImageLoader"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom image loader node supporting natural number sorting with multiple sort modes (natural, lexicographic, modification time, creation time, reverse natural). (Description by CC)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "johninthewinter",
|
||||||
|
"title": "comfyui-fal-flux-2-John [REMOVED]",
|
||||||
|
"reference": "https://github.com/johninthewinter/comfyui-fal-flux-2-John",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/johninthewinter/comfyui-fal-flux-2-John"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom nodes for ComfyUI that integrate with fal.ai's FLUX 2 and FLUX 1 LoRA APIs for text-to-image generation."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "LargeModGames",
|
||||||
|
"title": "ComfyUI LoRA Auto Downloader [REMOVED]",
|
||||||
|
"reference": "https://github.com/LargeModGames/comfyui-smart-lora-downloader",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/LargeModGames/comfyui-smart-lora-downloader"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Automatically download missing LoRAs from CivitAI and detect missing LoRAs in workflows. Features smart directory detection and easy installation."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "DiffusionWave",
|
||||||
|
"title": "PickResolution_DiffusionWave [DEPRECATED]",
|
||||||
|
"reference": "https://github.com/DiffusionWave/PickResolution_DiffusionWave",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/DiffusionWave/PickResolution_DiffusionWave"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A custom node for ComfyUI that allows selecting a base resolution, applying a custom scaling value based on FLOAT (up to 10 decimal places), and adding an extra integer value. Outputs include both INT and FLOAT resolutions, making it perfect for you to play around with."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "geltz",
|
||||||
|
"title": "ComfyUI-geltz [REMOVED]",
|
||||||
|
"reference": "https://github.com/geltz/ComfyUI-geltz",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/geltz/ComfyUI-geltz"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Various custom nodes; guidance, latents, sampling, tokenization, etc."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "anilsathyan7",
|
||||||
|
"title": "ComfyUI-Crystal-Upscaler [REMOVED]",
|
||||||
|
"reference": "https://github.com/anilsathyan7/ComfyUI-Crystal-Upscaler",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/anilsathyan7/ComfyUI-Crystal-Upscaler"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI custom node for image upscaling using crystal upscaling technology. (Description by CC)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "nohikomiso",
|
||||||
|
"title": "ComfyUI-ImageFolderPicker [REMOVED/UNSAFE]",
|
||||||
|
"reference": "https://github.com/nohikomiso/ComfyUI-ImageFolderPicker",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/nohikomiso/ComfyUI-ImageFolderPicker"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom ComfyUI node for browsing local server folders and selecting images via thumbnail display in a grid interface. (Description by CC)[w/This nodepack has a vulnerability that allows it to retrieve a list of files from arbitrary paths.]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "rzasharp79",
|
||||||
|
"title": "ComfyUI--SolarFlare [REMOVED]",
|
||||||
|
"reference": "https://github.com/rzasharp79/ComfyUI--SolarFlare",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/rzasharp79/ComfyUI--SolarFlare"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: Qwen Image, ..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "shinich39",
|
||||||
|
"title": "comfyui-no-one-above-me [REMOVED]",
|
||||||
|
"reference": "https://github.com/shinich39/comfyui-no-one-above-me",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/shinich39/comfyui-no-one-above-me"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Fix node to top."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "octapus8085",
|
||||||
|
"title": "OpenAI-comfyui-O [REMOVED]",
|
||||||
|
"reference": "https://github.com/Spicely/Comfyui-File-Utils",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Spicely/Comfyui-File-Utils"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "This plugin provides multiple file-handling and utility nodes for ComfyUI, including: image saving, audio saving, video saving, video composition, audio-to-subtitle conversion, and random number generation nodes. These nodes not only process files but also return their absolute file paths.\nNOTE: The files in the repo are not organized.[w/This nodepack contains a node that has a vulnerability allowing write to arbitrary file paths.]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "yemanou",
|
||||||
|
"title": "NABA Image (Gemini REST) Node [REMOVED]",
|
||||||
|
"reference": "https://github.com/yemanou/ComfyUI-NABA",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/yemanou/ComfyUI-NABA"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Simplified Gemini 2.5 Flash Image Preview node for ComfyUI. REST-only for stability, two optional reference images, padded aspect ratio resizing (no stretching), and basic sampling controls. All extra debug layers, SDK path, multi-seed, and legacy compatibility code removed to avoid crashes."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "comrender",
|
||||||
|
"title": "ComfyUI-Nano-Banana-Resizer [REMOVED]",
|
||||||
|
"reference": "https://github.com/comrender/ComfyUI-Nano-Banana-Resizer",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/comrender/ComfyUI-Nano-Banana-Resizer"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A ComfyUI custom node that automatically calculates optimal output dimensions for Google's Nano Banana image editing model, supporting 22 aspect ratio buckets and ensuring pixel-perfect outputs without shifting or cropping."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "comrender",
|
||||||
|
"title": "ComfyUI-edge-match-checker [REMOVED]",
|
||||||
|
"reference": "https://github.com/comrender/ComfyUI-edge-match-checker",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/comrender/ComfyUI-edge-match-checker"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Node comparing two image masks or images with adjustable overlap threshold (default 95%) for detecting minor shifts and mismatches in proportions, suitable for automated post-processing validation. (Description by CC)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "comrender",
|
||||||
|
"title": "ComfyUI-gpt5_image_text [REMOVED]",
|
||||||
|
"reference": "https://github.com/comrender/ComfyUI-gpt5_image_text",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/comrender/ComfyUI-gpt5_image_text"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A ComfyUI custom node for vision + text analysis using GPT-5 and GPT-4o with direct API key input, system prompt, temperature, max tokens, and multi-image support."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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 Google’s 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]",
|
||||||
|
"reference": "https://github.com/EQXai/ComfyUI_EQX",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/EQXai/ComfyUI_EQX"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: SaveImage_EQX, File Image Selector, Load Prompt From File - EQX, LoraStackEQX_random, Extract Filename - EQX, Extract LORA name - EQX, NSFW Detector EQX, NSFW Detector Advanced EQX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "wizdroid",
|
||||||
|
"title": "Wizdroid ComfyUI Outfit Selection [REMOVED]",
|
||||||
|
"reference": "https://github.com/wizdroid/wizdroid-fashionista",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/wizdroid/wizdroid-fashionista"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A comprehensive outfit generation system for ComfyUI with AI-powered prompt enhancement and dynamic outfit composition."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "enternalsaga",
|
||||||
|
"title": "NBA-ComfyUINode [REMOVED]",
|
||||||
|
"reference": "https://github.com/enternalsaga/NBA-ComfyUINode-public",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/enternalsaga/NBA-ComfyUINode-public"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Version 1.2.1 - Dependency cleanup and archived LineSelector node\nA comprehensive collection of custom nodes for ComfyUI, providing advanced image processing, workflow control, and utility functions to enhance your AI image generation workflows."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "sselpah",
|
||||||
|
"title": "ComfyUI-sselpah-nodes [REMOVED]",
|
||||||
|
"reference": "https://github.com/sselpah/ComfyUI-sselpah-nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/sselpah/ComfyUI-sselpah-nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Extension of IPAdapter implementation by cubiq and whoever contributed to that repository"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "vsaan212",
|
||||||
|
"title": "ComfyUI Text Split Node [REMOVED]",
|
||||||
|
"reference": "https://github.com/vsaan212/Comfy-ui-textsplit",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/vsaan212/Comfy-ui-textsplit"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A custom ComfyUI node that splits text into multiple outputs for feeding complex multi-scene renders. This node allows you to dynamically control the number of splits and use custom separators."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "EnragedAntelope",
|
||||||
|
"title": "ComfyUI-Doubutsu-Describer [DEPRECATED]",
|
||||||
|
"reference": "https://github.com/EnragedAntelope/ComfyUI-Doubutsu-Describer",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/EnragedAntelope/ComfyUI-Doubutsu-Describer"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "This custom node for ComfyUI allows you to use the Doubutsu small VLM model to describe images. Credit and further information on Doubutsu: [a/https://huggingface.co/qresearch/doubutsu-2b-pt-756](https://huggingface.co/qresearch/doubutsu-2b-pt-756)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "vsaan212",
|
||||||
|
"title": "ComfyUI Subject Selector [DEPRECATED]",
|
||||||
|
"reference": "https://github.com/vsaan212/ComfyUI_subjectselector",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/vsaan212/ComfyUI_subjectselector"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI_subjectselector is a custom ComfyUI node that allows you to manage and select text-based subject descriptions directly from the workflow UI. This node was designed to pair seamlessly with [a/ComfyUI-textsplit](https://github.com/vsaan212/Comfy-ui-textsplit), providing a clean, modular way to feed descriptive text prompts into your generation pipeline."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "agxagi",
|
||||||
|
"title": "Autoregressive Transformer and Rolling Diffusion Sampler for ComfyUI [REMOVED]",
|
||||||
|
"reference": "https://github.com/agxagi/ComfyUI-GPT4o-Image-Gen-FLUX-DEV",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/agxagi/ComfyUI-GPT4o-Image-Gen-FLUX-DEV"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A custom ComfyUI node that implements an Autoregressive Transformer and Rolling Diffusion-like Decoder using Black Forest Lab's Flux-Dev model for accurate text-to-image generation, similar to GPT-4o's image generation approach.\nNOTE: The files in the repo are not organized."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "walke2019",
|
||||||
|
"title": "ComfyUI-GGUF-VisionLM [REMOVED]",
|
||||||
|
"reference": "https://github.com/walke2019/ComfyUI-GGUF-VisionLM",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/walke2019/ComfyUI-GGUF-VisionLM"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI nodes for running GGUF quantized Qwen2.5-VL models using llama.cpp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "neocrz",
|
||||||
|
"title": "comfyui-tinyae [REMOVED]",
|
||||||
|
"reference": "https://github.com/neocrz/comfyui-tinyae",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/neocrz/comfyui-tinyae"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: TinyAE Encode (Image/Video), TinyAE Decode (Image/Video), TinyAE Encode Tiled (Image), TinyAE Decode Tiled (Image)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Laser-one",
|
||||||
|
"title": "ComfyUI-align-pose [REMOVED]",
|
||||||
|
"reference": "https://github.com/Laser-one/ComfyUI-align-pose",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Laser-one/ComfyUI-align-pose"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES:align pose"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "nomadoor",
|
||||||
|
"title": "ComfyUI Video Stabilizer",
|
||||||
|
"reference": "https://github.com/nomadoor/ComfyUI-Video-Stabilizer",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/nomadoor/ComfyUI-Video-Stabilizer"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Two complementary stabiliser nodes for ComfyUI: Video Stabilizer (Classic), Video Stabilizer (Flow)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "0xhappydev",
|
||||||
|
"title": "comfyui-qwen-image-tools",
|
||||||
|
"reference": "https://github.com/0xhappydev/comfyui-qwen-image-tools",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/0xhappydev/comfyui-qwen-image-tools"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom nodes for Qwen-Image-Edit with multi-image support, more flexibility around the vision transformer (qwen2.5-vl), custom system prompts, and some other experimental things to come."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Rathius-Saranoth",
|
||||||
|
"title": "Rathius ComfyUI Nodes",
|
||||||
|
"reference": "https://github.com/Rathius-Saranoth/rathius-comfyui-nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Rathius-Saranoth/rathius-comfyui-nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom nodes for ComfyUI by Rathius"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Hiero207",
|
||||||
|
"title": "Hiero-Nodes [REMOVED]",
|
||||||
|
"id": "hiero",
|
||||||
|
"reference": "https://github.com/Hiero207/ComfyUI-Hiero-Nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Hiero207/ComfyUI-Hiero-Nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Nodes:Post to Discord w/ Webhook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "NeoDroleDeGueule",
|
||||||
|
"title": "comfyui-image-mixer",
|
||||||
|
"reference": "https://github.com/NeoDroleDeGueule/comfyui-image-mixer [REMOVED]",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/NeoDroleDeGueule/comfyui-image-mixer"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A ComfyUI custom node that blends two images in latent space using a mix factor slider."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Glarus-akash",
|
||||||
|
"title": "ComfyUI_Image_Upscaler [REMOVED]",
|
||||||
|
"reference": "https://github.com/Glarus-akash/ComfyUI_Image_Upscaler",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Glarus-akash/ComfyUI_Image_Upscaler"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Welcome to the Image Upscaler & Restorer project! This tool utilizes the [a/GFPGAN](https://github.com/TencentARC/GFPGAN) algorithm to enhance and restore images, providing a seamless way to improve image quality."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "styletransfer",
|
||||||
|
"title": "Sequential Group Controller for ComfyUI [REMOVED]",
|
||||||
|
"reference": "https://github.com/styletransfer/ComfyUI_SequentialGroupController",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/styletransfer/ComfyUI_SequentialGroupController"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Control which groups execute based on iteration ranges - a simplified alternative to complex conditional branching workflows."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "xl0",
|
||||||
|
"title": "q_tools [REMOVED]",
|
||||||
|
"reference": "https://github.com/xl0/q_tools",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/xl0/q_tools"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: QLoadLatent, QLinearScheduler, QPreviewLatent, QGaussianLatent, QUniformLatent, QKSampler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "tmode-1960",
|
||||||
|
"title": "comfyui-ta-nodes-pack [REMOVED]",
|
||||||
|
"reference": "https://github.com/tmode-1960/comfyui-ta-nodes-pack",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/tmode-1960/comfyui-ta-nodes-pack"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Model loaders with an additional model name output"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Shadetail",
|
||||||
|
"title": "Eagleshadow Custom Nodes [REMOVED]",
|
||||||
|
"id": "eagleshadow",
|
||||||
|
"reference": "https://github.com/Shadetail/ComfyUI_Eagleshadow",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Shadetail/ComfyUI_Eagleshadow"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Custom nodes for ComfyUI by Eagleshadow."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "manycore-maas",
|
||||||
|
"title": "ComfyUI-SpatialGen [REMOVED]",
|
||||||
|
"reference": "https://github.com/manycore-maas/ComfyUI-SpatialGen",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/manycore-maas/ComfyUI-SpatialGen"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Scene Viewer of SpatialGen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "YinBailiang",
|
||||||
|
"title": "MergeBlockWeighted_fo_ComfyUI [REMOVED]",
|
||||||
|
"id": "mergeblockweighted_fo_comfyui",
|
||||||
|
"reference": "https://github.com/YinBailiang/MergeBlockWeighted_fo_ComfyUI",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/YinBailiang/MergeBlockWeighted_fo_ComfyUI"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Nodes: MergeBlockWeighted"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "facok",
|
||||||
|
"title": "ComfyUI-FokToolset [REMOVED]",
|
||||||
|
"reference": "https://github.com/facok/ComfyUI-FokToolset",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/facok/ComfyUI-FokToolset"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: Fok Preprocess Ref Image (Phantom)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Elawphant",
|
||||||
|
"title": "ComfyUI-MusicGen [WIP]",
|
||||||
|
"id": "musicgen",
|
||||||
|
"reference": "https://github.com/Elawphant/ComfyUI-MusicGen",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Elawphant/ComfyUI-MusicGen"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI for Meta MusicGen."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "isaac-mcfadyen",
|
||||||
|
"title": "ComfyUI-QwenClip [REMOVED]",
|
||||||
|
"reference": "https://github.com/isaac-mcfadyen/ComfyUI-QwenClip",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/isaac-mcfadyen/ComfyUI-QwenClip"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A variety of random text encoder tools intended for use with ComfyUI and Qwen Image/Qwen Image Edit. More (may) be added as I try out various modifications to Qwen Image."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Gaotian",
|
||||||
|
"title": "KLComfyUI-Nodes [REMOVED]",
|
||||||
|
"reference": "https://github.com/Gaotian-cpu/KLComfyUI-Nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Gaotian-cpu/KLComfyUI-Nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: Single Video_Img Callback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "geltz",
|
||||||
|
"title": "Momentum Guidance for ComfyUI [REMOVED]",
|
||||||
|
"reference": "https://github.com/geltz/ComfyUI-MomentumGuidance",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/geltz/ComfyUI-MomentumGuidance"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Momentum Guidance (MG) is a training-free guidance method that reduces computational cost by 40% compared to standard guidance techniques like CFG or PAG."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "GeekyGhost",
|
||||||
|
"title": "Studio42 Image, Audio, and Video Editing Suite for ComfyUI [REMOVED]",
|
||||||
|
"reference": "https://github.com/GeekyGhost/24oiduts-ComfyUI",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/GeekyGhost/24oiduts-ComfyUI"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Studio42 is a comprehensive suite of advanced custom nodes that brings professional-grade image and video editing capabilities to ComfyUI. Designed for efficiency, quality, and creative flexibility, this suite provides cutting-edge background removal, layer composition, and patch manipulation tools used in modern VFX and content creation workflows."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "rvage",
|
||||||
|
"title": "ComfyUI-RvTools-X [REMOVED]",
|
||||||
|
"reference": "https://github.com/r-vage/ComfyUI-RvTools-X",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/r-vage/ComfyUI-RvTools-X"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI custom nodes and utilities for workflow building, type conversions, checkpoint/pipe loaders and file utilities."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "heyburns",
|
||||||
|
"title": "LinxUtil [REMOVED]",
|
||||||
|
"reference": "https://github.com/heyburns/LinxUtil",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/heyburns/LinxUtil"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Utility nodes for ComfyUI. Created solely for my own use case, shared as a courtesy only.\nNOTE: The files in the repo are not organized."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "fcanfora",
|
||||||
|
"title": "comfyui-camera-tools [REMOVED]",
|
||||||
|
"reference": "https://github.com/fcanfora/comfyui-camera-tools",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/fcanfora/comfyui-camera-tools"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: Load Camera From File, Load 3D, Load 3D - Animation, Preview 3D, Preview 3D - Animation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "ziwang-com",
|
||||||
|
"title": "comfyui-deepseek-r1 [REMOVED]",
|
||||||
|
"reference": "https://github.com/ziwang-com/comfyui-deepseek-r1",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/ziwang-com/comfyui-deepseek-r1"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Comfyui-deepseek-r1 Node Plugin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "leeguandong",
|
||||||
|
"title": "ComfyUI nodes to use Xverse [REMOVED]",
|
||||||
|
"reference": "https://github.com/leeguandong/ComfyUI_Xverse",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/leeguandong/ComfyUI_Xverse"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "The ComfyUI version of [a/XVerse](https://github.com/bytedance/XVerse)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Dehypnotic",
|
||||||
|
"title": "Dehypnotic Save nodes [REMOVED]",
|
||||||
|
"reference": "https://github.com/Dehypnotic/comfyui-dehypnotic-save-nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Dehypnotic/comfyui-dehypnotic-save-nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Save toolkit for audio, image, and video: MP3 audio export with VBR/CBR options, multi-format image saving with workflow/thumbnail metadata, and video + frame encoding (MP4/MKV/WEBM/MOV) — all sharing whitelist-safe paths and rich placeholder templating."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "znuost10",
|
||||||
|
"title": "comfyui-multi-float-output [REMOVED]",
|
||||||
|
"reference": "https://github.com/znuost10/comfyui-multi-float-output",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/znuost10/comfyui-multi-float-output"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "System monitoring API endpoints for ComfyUI by otoy SKW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "rakki194",
|
||||||
|
"title": "ComfyUI_WolfSigmas [UNSAFE/REMOVED]",
|
||||||
|
"reference": "https://github.com/rakki194/ComfyUI_WolfSigmas",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/rakki194/ComfyUI_WolfSigmas"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "This custom nodepack for ComfyUI provides a suite of tools for generating and manipulating sigma schedules for diffusion models. These nodes are particularly useful for fine-tuning the sampling process, experimenting with different step counts, and adapting schedules for specific models.[w/Security Warning: Remote Code Execution]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Maff3u",
|
||||||
|
"title": "MattiaNodes - Points Editor On Cropped [REMOVED]",
|
||||||
|
"reference": "https://github.com/Maff3u/MattiaNodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/Maff3u/MattiaNodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A standalone ComfyUI custom node for interactive coordinate editing with crop factor correction.\nNOTE: The files in the repo are not organized."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "rakki194",
|
||||||
|
"title": "ComfyUI-ImageCompare [REMOVED]",
|
||||||
|
"reference": "https://github.com/rakki194/ComfyUI-ImageCompare",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/rakki194/ComfyUI-ImageCompare"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A simple custom node for ComfyUI that allows you to compare two images (or batches of images) side-by-side within the UI."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "APZmedia",
|
||||||
|
"title": "NormalMapLightEstimator [REMOVED]",
|
||||||
|
"reference": "https://github.com/APZmedia/Comfyui-LightDirection-estimation",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/APZmedia/Comfyui-LightDirection-estimation"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A ComfyUI custom node for estimating light direction and quality from normal maps using luma masking. The system analyzes surface normals to infer lighting information for downstream tasks like adaptive relighting, directional masking, or stylized effects."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "APZmedia",
|
||||||
|
"title": "ComfyUI APZmedia PSD Tools [REMOVED]",
|
||||||
|
"reference": "https://github.com/APZmedia/APZmedia-ComfyUI-PSDtools",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/APZmedia/APZmedia-ComfyUI-PSDtools"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "This extension provides PSD layer saving functionalities with mask support for ComfyUI."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "huixingyun",
|
||||||
|
"title": "ComfyUI-HX-Pimg [REMOVED]",
|
||||||
|
"reference": "https://github.com/huixingyun/ComfyUI-HX-Pimg",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/huixingyun/ComfyUI-HX-Pimg"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Some custom nodes used for pimg (a comfyui controller deployed in huixingyun)."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "rvage",
|
||||||
|
"title": "ComfyUI-RvToolsX [REMOVED]",
|
||||||
|
"reference": "https://github.com/r-vage/ComfyUI-RvToolsX",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/r-vage/ComfyUI-RvToolsX"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI custom nodes and utilities for workflow building, type conversions, checkpoint/pipe loaders and file utilities."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "usman2003",
|
||||||
|
"title": "ComfyUI-RaceDetect [REMOVED]",
|
||||||
|
"reference": "https://github.com/usman2003/ComfyUI-RaceDetect",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/usman2003/ComfyUI-RaceDetect"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: Race Detection V2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "lihaoyun6",
|
||||||
|
"title": "ComfyUI-CSV-Random-Picker [REMOVED]",
|
||||||
|
"reference": "https://github.com/lihaoyun6/ComfyUI-CSV-Random-Picker",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/lihaoyun6/ComfyUI-CSV-Random-Picker"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "String random picker for ComfyUI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "r-vage",
|
||||||
|
"title": "ComfyUI-RvTools_v2 [REMOVED]",
|
||||||
|
"reference": "https://github.com/r-vage/ComfyUI-RvTools_v2",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/r-vage/ComfyUI-RvTools_v2"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "this node contains a lot of small little helpers like switches, passers and selectors that i use a lot to build my workflows."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "Yuxi Liu",
|
||||||
|
"title": "comfyui-ddu [REMOVED]",
|
||||||
|
"reference": "https://github.com/YL-Lyx/Comfyui-ddu-toolchain",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/YL-Lyx/Comfyui-ddu-toolchain"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ai-driven toolchain for digital design and fabrication "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "lu64k",
|
||||||
|
"title": "SK-Nodes [REMOVED]",
|
||||||
|
"reference": "https://github.com/lu64k/SK-Nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/lu64k/SK-Nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES:image select, Load AnyLLM, Ask LLM, OpenAI DAlle Node, SK Text_String, SK Random File Name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "SiggEye",
|
||||||
|
"title": "FaceCanon — Consistent Faces at Any Resolution [REMOVED]",
|
||||||
|
"reference": "https://github.com/SiggEye/FaceCanon",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/SiggEye/FaceCanon"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "FaceCanon scales a detected face to a canonical pixel size, lets you run your favorite face detailer at that sweet spot, then maps the result back into the original image with seamless blending. The payoff is consistent face style no matter the input resolution or framing."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "AlfredClark",
|
||||||
|
"title": "ComfyUI-ModelSpec [REMOVED]",
|
||||||
|
"reference": "https://github.com/AlfredClark/ComfyUI-ModelSpec",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/AlfredClark/ComfyUI-ModelSpec"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "ComfyUI model metadata editing nodes."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "VraethrDalkr",
|
||||||
|
"title": "ComfyUI-ProgressiveBlend [REMOVED]",
|
||||||
|
"reference": "https://github.com/VraethrDalkr/ComfyUI-ProgressiveBlend",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/VraethrDalkr/ComfyUI-ProgressiveBlend"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A collection of custom nodes for ComfyUI that enable progressive blending and color matching effects across image batches/video frames."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "xmarked-ai",
|
||||||
|
"title": "ComfyUI_misc [REMOVED]",
|
||||||
|
"reference": "https://github.com/xmarked-ai/ComfyUI_misc",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/xmarked-ai/ComfyUI_misc"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "NODES: Ace IntegerX, Ace FloatX, Ace Color FixX, White Balance X, Depth Displace X, Empty Latent X, KSampler Combo X, ..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "sm079",
|
||||||
|
"title": "ComfyUI-Face-Detection [REMOVED]",
|
||||||
|
"reference": "https://github.com/sm079/ComfyUI-Face-Detection",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/sm079/ComfyUI-Face-Detection"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "face detection nodes for comfyui"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "42lux",
|
||||||
|
"title": "ComfyUI-42lux [REMOVED]",
|
||||||
|
"reference": "https://github.com/42lux/ComfyUI-42lux",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/42lux/ComfyUI-42lux"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "A collection of custom nodes for ComfyUI focused on enhanced sampling, model optimization, and quality improvements."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "lucak5s",
|
||||||
|
"title": "ComfyUI GFPGAN [REMOVED]",
|
||||||
|
"reference": "https://github.com/lucak5s/comfyui_gfpgan",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/lucak5s/comfyui_gfpgan"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Face restoration with GFPGAN."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "impactframes",
|
||||||
|
"title": "IF_AI_tools [DEPRECATED]",
|
||||||
|
"id": "impactframes-tools",
|
||||||
|
"reference": "https://github.com/if-ai/ComfyUI-IF_AI_tools",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/if-ai/ComfyUI-IF_AI_tools"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Various AI tools to use in Comfy UI. Starting with VL and prompt making tools using Ollma as backend will evolve as I find time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "netroxin",
|
||||||
|
"title": "comfyui_netro [REMOVED]",
|
||||||
|
"reference": "https://github.com/netroxin/comfyui_netro",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/netroxin/comfyui_netro"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "#Camera Movement Prompt Node for ComfyUI\nThis custom node script for ComfyUI generates descriptive camera movement prompts based on user-selected movement options for Wan2.2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"author": "aistudynow",
|
"author": "aistudynow",
|
||||||
"title": "comfyui-HunyuanImage-2.1 [REMOVED]",
|
"title": "comfyui-HunyuanImage-2.1 [REMOVED]",
|
||||||
@@ -672,16 +1557,6 @@
|
|||||||
"install_type": "git-clone",
|
"install_type": "git-clone",
|
||||||
"description": "This node provides advanced text-to-speech functionality powered by KokoroTTS. Follow the instructions below to install, configure, and use the node within your portable ComfyUI installation."
|
"description": "This node provides advanced text-to-speech functionality powered by KokoroTTS. Follow the instructions below to install, configure, and use the node within your portable ComfyUI installation."
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"author": "MushroomFleet",
|
|
||||||
"title": "DJZ-Pedalboard [REMOVED]",
|
|
||||||
"reference": "https://github.com/MushroomFleet/DJZ-Pedalboard",
|
|
||||||
"files": [
|
|
||||||
"https://github.com/MushroomFleet/DJZ-Pedalboard"
|
|
||||||
],
|
|
||||||
"install_type": "git-clone",
|
|
||||||
"description": "This project provides a collection of custom nodes designed for enhanced audio effects in ComfyUI. With an intuitive pedalboard interface, users can easily integrate and manipulate various audio effects within their workflows."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"author": "MushroomFleet",
|
"author": "MushroomFleet",
|
||||||
"title": "SVG Suite for ComfyUI [REMOVED]",
|
"title": "SVG Suite for ComfyUI [REMOVED]",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -361,6 +361,16 @@
|
|||||||
],
|
],
|
||||||
"install_type": "git-clone",
|
"install_type": "git-clone",
|
||||||
"description": "Vibe Coded ComfyUI Custom Nodes"
|
"description": "Vibe Coded ComfyUI Custom Nodes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "aiforhumans",
|
||||||
|
"title": "XDev Nodes - Complete Toolkit",
|
||||||
|
"reference": "https://github.com/aiforhumans/comfyui-xdev-nodes",
|
||||||
|
"files": [
|
||||||
|
"https://github.com/aiforhumans/comfyui-xdev-nodes"
|
||||||
|
],
|
||||||
|
"install_type": "git-clone",
|
||||||
|
"description": "Complete ComfyUI development toolkit with 8 professional nodes including VAE tools, universal type testing, and comprehensive debugging infrastructure."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,15 @@ cm_global.register_api('cm.is_import_failed_extension', is_import_failed_extensi
|
|||||||
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
custom_nodes_base_path = folder_paths.get_folder_paths('custom_nodes')[0]
|
custom_nodes_base_path = folder_paths.get_folder_paths('custom_nodes')[0]
|
||||||
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))
|
|
||||||
|
# Check for System User API availability (PR #10966)
|
||||||
|
_has_system_user_api = hasattr(folder_paths, 'get_system_user_directory')
|
||||||
|
|
||||||
|
if _has_system_user_api:
|
||||||
|
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), '__manager'))
|
||||||
|
else:
|
||||||
|
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))
|
||||||
|
|
||||||
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
||||||
manager_pip_blacklist_path = os.path.join(manager_files_path, "pip_blacklist.list")
|
manager_pip_blacklist_path = os.path.join(manager_files_path, "pip_blacklist.list")
|
||||||
restore_snapshot_path = os.path.join(manager_files_path, "startup-scripts", "restore-snapshot.json")
|
restore_snapshot_path = os.path.join(manager_files_path, "startup-scripts", "restore-snapshot.json")
|
||||||
@@ -516,7 +524,8 @@ check_bypass_ssl()
|
|||||||
|
|
||||||
# Perform install
|
# Perform install
|
||||||
processed_install = set()
|
processed_install = set()
|
||||||
script_list_path = os.path.join(folder_paths.user_directory, "default", "ComfyUI-Manager", "startup-scripts", "install-scripts.txt")
|
# Use manager_files_path for consistency (fixes path inconsistency bug)
|
||||||
|
script_list_path = os.path.join(manager_files_path, "startup-scripts", "install-scripts.txt")
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
|
||||||
|
|
||||||
|
|
||||||
@@ -793,7 +802,11 @@ def execute_startup_script():
|
|||||||
|
|
||||||
|
|
||||||
# Check if script_list_path exists
|
# Check if script_list_path exists
|
||||||
if os.path.exists(script_list_path):
|
# Block startup-scripts on old ComfyUI (security measure)
|
||||||
|
if not _has_system_user_api:
|
||||||
|
if os.path.exists(script_list_path):
|
||||||
|
print("[ComfyUI-Manager] Startup scripts blocked on old ComfyUI version.")
|
||||||
|
elif os.path.exists(script_list_path):
|
||||||
execute_startup_script()
|
execute_startup_script()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-manager"
|
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."
|
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
||||||
version = "3.36"
|
version = "3.38.3"
|
||||||
license = { file = "LICENSE.txt" }
|
license = { file = "LICENSE.txt" }
|
||||||
dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]
|
dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ GitPython
|
|||||||
PyGithub
|
PyGithub
|
||||||
matrix-nio
|
matrix-nio
|
||||||
transformers
|
transformers
|
||||||
huggingface-hub>0.20
|
huggingface-hub
|
||||||
typer
|
typer
|
||||||
rich
|
rich
|
||||||
typing-extensions
|
typing-extensions
|
||||||
|
|||||||
1015
scanner.py
1015
scanner.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user