Compare commits

..

511 Commits

Author SHA1 Message Date
Benjamin Lu
43fe6f8290 Improve comfyui version listing 2025-12-01 20:55:30 -08:00
Dr.Lt.Data
d7799964de fixed: Issue where an invalid channel exception occurred when using the default channel
- Mismatch issue between ltdrdata/ and Comfy-Org/
modified: /v2/customnode/installed – cnr_id was being returned in a normalized form
modified: /v2/customnode/installed – when both an enabled nodepack and a disabled nodepack existed, modified to report only the enabled nodepack
fixed: Removed unnecessary warning messages printed during nodepack installation
2025-09-06 03:35:43 +09:00
Dr.Lt.Data
5378f0a8e9 bump version 2025-09-04 08:39:37 +09:00
Jin Yi
e13bf68775 Fix JSON serialization error in bulk import fail info API (#2119)
* fix: import failed info bulk api bug fix

* fix: Remove unused ImportFailInfoBulkResponse import
2025-09-04 08:36:46 +09:00
Dr.Lt.Data
d970fe68ea Merge branch 'main' into draft-v4 2025-09-03 01:24:47 +09:00
Dr.Lt.Data
63ba5fed09 update DB 2025-09-03 01:07:30 +09:00
Dr.Lt.Data
98a8464933 update DB 2025-09-03 00:16:55 +09:00
S4MUEL
7e3e6726e0 Add ComfyUI-Prepack to custom nodes list (#2121)
* Add ComfyUI-S4Tool-Image to custom nodes list

Add ComfyUI-S4Tool-Image to custom nodes list

* Update custom-node-list.json

Add custom-node : ComfyUI-S4Motion

* Add ComfyUI-S4Tool-Text to custom node list

Text rendering and styling nodes for ComfyUI. This extension provides a basic text renderer, multiple font loaders, and a style node that adds stroke, shadow, gradient fill, and opacity control.

* Add ComfyUI-Prepack to custom node list

A small, practical bundle of ComfyUI nodes that streamlines common workflows.

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-09-03 00:15:49 +09:00
Dr.Lt.Data
09567b2bb2 update DB 2025-09-03 00:15:34 +09:00
Frief84
f3bd116184 Add ComfyUI-LoRAWeightAxisXY (#2120)
* Add ComfyUI-LoRAWeightAxisXY

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-09-03 00:12:50 +09:00
Dr.Lt.Data
7509737563 update DB 2025-09-02 12:59:44 +09:00
Dr.Lt.Data
cfb815d879 update DB 2025-09-01 12:05:21 +09:00
Dr.Lt.Data
44241fb967 update DB 2025-09-01 07:31:34 +09:00
mengqin
c4b45129bd Update DB. (#2118) 2025-09-01 06:53:35 +09:00
Dr.Lt.Data
70741008ca Update DB 2025-08-31 18:11:54 +09:00
daehwa
6c2d2cae2a Add ComfyUI-NanoBananaAPI node entry (#2115) 2025-08-31 17:22:18 +09:00
gsusgg
28f13d3311 Add ComfyUI-CozyGen custom node entry (#2113)
Added a new custom node entry for ComfyUI-CozyGen with details.
2025-08-31 17:20:43 +09:00
Dr.Lt.Data
4e31aaa8fb update DB 2025-08-30 10:47:43 +09:00
dehypnotic
ba99f0c2cc Update custom-node-list.json (#2112) 2025-08-30 10:41:28 +09:00
Dr.Lt.Data
e0a96b4937 update DB 2025-08-29 13:00:32 +09:00
Dr.Lt.Data
82c055f527 update DB 2025-08-29 07:59:21 +09:00
Makki Shizu
f94008192c Update custom-node-list.json (#2110) 2025-08-29 07:47:26 +09:00
Fabio Sarracino
3895d5279e Add VibeVoice ComfyUI node (#2109) 2025-08-29 07:45:41 +09:00
Dr.Lt.Data
41be94690f bump version 2025-08-28 00:27:03 +09:00
Dr.Lt.Data
3d85ecc525 update DB 2025-08-28 00:25:45 +09:00
Dr.Lt.Data
7da00796e5 update DB 2025-08-27 12:21:31 +09:00
Dr.Lt.Data
6086419cb6 update DB 2025-08-27 07:51:36 +09:00
Dr.Lt.Data
5bc1f2f2c0 update DB 2025-08-26 19:39:38 +09:00
Changrz
32a83b211e Update Rodin Plugin url (#2102)
Co-authored-by: WhiteGiven <c15838568211@163.com>
2025-08-26 19:03:05 +09:00
Alex
bead7b3a7f Add Custom Node - Save Checkpoint with Metadata (#2105)
* Added entry for ComfyUI-SaveCheckpointWithMetadata

* Added entry for ComfyUI-SaveCheckpointWithMetadata in git-clone section
2025-08-26 19:01:52 +09:00
jialuw0830
815d6d6572 Add Eigen AI FLUX API Plugin to custom node list (#2104) 2025-08-26 18:59:51 +09:00
Christian Byrne
fbecbee4c3 Merge pull request #2106 from viva-jinyi/revert-legacy-hardcoding
Revert "As a temporary measure, the new UI will use the legacy/... ba…
2025-08-25 18:27:57 -07:00
Jin Yi
b9a7d2a78c Revert "As a temporary measure, the new UI will use the legacy/... backend structure."
This reverts commit 121a5a1888.
2025-08-26 10:07:32 +09:00
Dr.Lt.Data
95ce812992 update DB 2025-08-25 12:59:46 +09:00
Dr.Lt.Data
9a36f4748c update DB 2025-08-25 08:06:43 +09:00
Dr.Lt.Data
50b7849a35 update DB 2025-08-25 07:27:39 +09:00
Dr.Lt.Data
6f1245b27c update DB 2025-08-25 06:30:51 +09:00
dehypnotic
cc87ed3899 Update custom-node-list.json (#2097)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-08-25 06:28:06 +09:00
Dr.Lt.Data
1d9037fefe update DB 2025-08-25 06:27:46 +09:00
Daxamur
03016e2d16 Add DaxNodes to custom node list (#2100) 2025-08-25 06:26:28 +09:00
Dr.Lt.Data
bdfb70a58a bump version 2025-08-24 15:58:23 +09:00
Dr.Lt.Data
3d41617f4e update DB 2025-08-23 17:54:00 +09:00
Dr.Lt.Data
35151ffdd1 update DB 2025-08-23 09:20:01 +09:00
Dr.Lt.Data
4527d41a7a update DB 2025-08-22 21:13:29 +09:00
dehypnotic
553cba12f3 Update custom-node-list.json (#2096)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-08-22 20:54:35 +09:00
Dr.Lt.Data
00fb9c88e1 modified: remove matrix-nio dependency from the requirements.txt
modified: The matrix share feature is now only available when the `matrix-nio` dependency is installed.

If `matrix-nio` is not installed:
1. Apply a strikethrough to the matrix checkbox text in the share UI and display a tooltip.
2. A warning is logged at startup indicating that `matrix-nio` is missing, along with the installation command.

fixed: Corrected an issue where PR #2025 was merged into draft-v4 but applied only to `legacy/..` and not to `glob/..`
2025-08-22 20:46:32 +09:00
Dr.Lt.Data
116e068ac3 update DB 2025-08-22 12:41:08 +09:00
Dr.Lt.Data
1010dd2d28 update DB 2025-08-22 07:35:26 +09:00
Dr.Lt.Data
68bc8302fd Update publish-to-pypi.yml 2025-08-22 06:17:55 +09:00
Dr.Lt.Data
596dad5cda Update publish-to-pypi.yml 2025-08-22 06:14:51 +09:00
Dr.Lt.Data
a924c280fb Update publish-to-pypi.yml 2025-08-22 06:08:59 +09:00
Dr.Lt.Data
7354242906 update workflow 2025-08-22 06:05:27 +09:00
Dr.Lt.Data
3d0bcf5979 update workflow 2025-08-22 06:00:26 +09:00
Dr.Lt.Data
e7d0b158e9 update DB 2025-08-22 05:41:35 +09:00
Dr.Lt.Data
10ff90787c Merge branch 'main' into draft-v4 2025-08-21 12:48:17 +09:00
Dr.Lt.Data
330c4657b1 update DB 2025-08-21 12:25:20 +09:00
Dr.Lt.Data
72a109f109 update DB 2025-08-21 07:29:53 +09:00
licyk
cf45c51dfb Add HDM-ext to custom-node-list (#2094) 2025-08-21 06:52:09 +09:00
Dr.Lt.Data
0b013adb34 update DB 2025-08-20 12:24:39 +09:00
Dr.Lt.Data
7457d91f64 update DB 2025-08-20 07:44:09 +09:00
Dr.Lt.Data
7fe1159426 update DB 2025-08-20 05:23:08 +09:00
renderartist
c2665e3677 Update custom-node-list.json (#2091)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-08-20 05:10:13 +09:00
Dr.Lt.Data
d63de803a4 update DB 2025-08-20 04:02:02 +09:00
Dr.Lt.Data
11aca3513c update DB 2025-08-20 03:53:51 +09:00
Joel Andrés Navarro Navarro
561c9f40e5 Update custom-node-list.json (#2089) 2025-08-20 03:49:46 +09:00
Saquib Alam
54ed13aadf add nodes for omini-kontext framework (#2087) 2025-08-20 03:47:56 +09:00
Dr.Lt.Data
109cc21337 update DB 2025-08-19 07:48:17 +09:00
Dr.Lt.Data
7e46b30fa5 update DB 2025-08-18 12:33:30 +09:00
Dr.Lt.Data
0ba112c2c7 update DB 2025-08-18 07:47:41 +09:00
david
fc15d94170 Update custom-node-list.json (#2086) 2025-08-18 07:38:28 +09:00
Dr.Lt.Data
dcb37d9c55 update DB 2025-08-17 18:23:05 +09:00
Marco Zanella
755b9d6342 Add ComfyUI-BooleanExpression to custom-node-list (#2084) 2025-08-17 17:53:24 +09:00
Joel Andrés Navarro Navarro
3d6151c94f Update custom-node-list.json (#2085) 2025-08-17 17:51:20 +09:00
jupo-ai
590bd8c4b9 Update custom-node-list.json (#2083) 2025-08-17 07:05:03 +09:00
Dr.Lt.Data
e99aafd876 update DB 2025-08-16 10:26:33 +09:00
Dr.Lt.Data
1f0adf8bcf update DB 2025-08-16 09:53:13 +09:00
jupo-ai
dbd5d5fb43 Update custom-node-list.json (#2082)
* Update custom-node-list.json

* Update custom-node-list.json
2025-08-16 09:36:35 +09:00
Dr.Lt.Data
a8b0e3641b update DB 2025-08-15 10:13:33 +09:00
AfterGlow.SYX
9efb350be9 Update custom-node-list.json (#2081) 2025-08-15 10:08:10 +09:00
Dr.Lt.Data
8d9820b3fb update DB 2025-08-14 23:24:08 +09:00
Dr.Lt.Data
103f89551a update DB 2025-08-14 22:00:23 +09:00
Dr.Lt.Data
6030d961ad update DB 2025-08-14 12:01:24 +09:00
Dr.Lt.Data
ee08c9e17f update DB 2025-08-14 07:42:41 +09:00
Dr.Lt.Data
48dd9a3240 update DB 2025-08-14 02:35:34 +09:00
Baverne
e122e206a6 Add TiledWan (#2078)
* Add TiledWan

* Add TiledWan

* Add TiledWan
2025-08-14 02:21:37 +09:00
Dr.Lt.Data
398b905758 update DB 2025-08-13 12:12:36 +09:00
Dr.Lt.Data
dc2ec08fe3 update DB 2025-08-13 07:44:54 +09:00
Dr.Lt.Data
3bf5edf5c9 update DB 2025-08-12 10:34:55 +09:00
Dr.Lt.Data
134bca526c update DB 2025-08-12 09:52:15 +09:00
Dr.Lt.Data
3393e58b06 update DB 2025-08-11 22:52:13 +09:00
Dr.Lt.Data
648d7e73c6 Merge branch 'main' into draft-v4 2025-08-11 12:51:34 +09:00
Dr.Lt.Data
eab6cdeee4 bump version 2025-08-11 12:48:38 +09:00
Christian Byrne
e8ec1ce8e3 recurse when finding nodes in workflow (#2070) 2025-08-11 12:47:20 +09:00
Dr.Lt.Data
b3581564ed update DB 2025-08-11 12:28:12 +09:00
S4MUEL
29e1bd95fd Add ComfyUI S4Motion to custom-node-list.json (#2072)
* Add ComfyUI-S4Tool-Image to custom nodes list

Add ComfyUI-S4Tool-Image to custom nodes list

* Update custom-node-list.json

Add custom-node : ComfyUI-S4Motion
2025-08-11 12:23:16 +09:00
Dr.Lt.Data
8bff401c14 update DB 2025-08-11 08:47:56 +09:00
Dr.Lt.Data
41798e9255 update DB 2025-08-11 07:44:25 +09:00
Dr.Lt.Data
9e4f0228d1 update DB 2025-08-10 20:54:49 +09:00
Dr.Lt.Data
76ee93c98c update DB 2025-08-10 11:25:27 +09:00
ericKuang
fb1a89efb7 Update custom-node-list.json (#2068)
Add ComfyUI-Only node:
Pain Point Solved: Eliminates the need to manually move .latent files into the ComfyUI input directory.
2025-08-10 11:16:32 +09:00
Dr.Lt.Data
aface43554 update DB 2025-08-10 11:02:38 +09:00
Dr.Lt.Data
a35f0157b2 update DB 2025-08-10 10:20:57 +09:00
Dr.Lt.Data
9b32162906 update DB 2025-08-09 15:13:30 +09:00
Dr.Lt.Data
21bba62572 update DB 2025-08-09 12:35:05 +09:00
Dr.Lt.Data
302327d6b3 update DB 2025-08-09 07:54:04 +09:00
Dr.Lt.Data
5667e8bcbb update DB 2025-08-08 23:13:50 +09:00
Dr.Lt.Data
ae66bd0e31 update DB 2025-08-08 12:15:46 +09:00
Dr.Lt.Data
48dfadc02d update DB 2025-08-08 07:54:54 +09:00
Dr.Lt.Data
3df6272bb6 update DB 2025-08-08 07:37:49 +09:00
CY-CHENYUE
e7f9bcda01 Update custom-node-list.json (#2064) 2025-08-08 07:35:24 +09:00
Dr.Lt.Data
205044ca66 update DB 2025-08-07 12:19:21 +09:00
Dr.Lt.Data
d497eb1f00 update DB 2025-08-07 08:42:22 +09:00
Dr.Lt.Data
4e6f970ee9 update DB 2025-08-06 12:14:25 +09:00
Dr.Lt.Data
0b6cdda6f5 update DB 2025-08-06 08:59:45 +09:00
Dr.Lt.Data
a896ded763 update DB 2025-08-06 07:26:55 +09:00
Dr.Lt.Data
fb5dd9ebc2 update DB 2025-08-05 12:24:03 +09:00
Dr.Lt.Data
c8b7db6c38 update DB 2025-08-05 08:57:36 +09:00
Dr.Lt.Data
44a3191be3 update DB 2025-08-05 07:16:04 +09:00
Dr.Lt.Data
b4f7cdc9e7 update DB 2025-08-05 06:20:52 +09:00
Alex Furer
8da07018d5 Update custom-node-list.json (#2058)
* Update custom-node-list.json

Added my custom node "AF-EditGeneratedPrompt", which let's one pipe a generated prompt, edit it, or use the node as a regular prompting node. Thank you for your efforts!

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-08-05 06:19:40 +09:00
Dr.Lt.Data
0c19a27065 update DB 2025-08-04 20:13:27 +09:00
jqy-yo
3296b0ecdf Add ComfyUI Gemini Nodes by jqy-yo (#2057)
Add entry for comfyui-gemini-nodes - a collection of custom nodes for integrating Google Gemini API with ComfyUI, providing AI capabilities for text generation, image generation, and video analysis.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: jqy-yo <jqy-yo@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-04 19:58:59 +09:00
Uygar
0a07261124 Update custom-node-list.json (#2055) 2025-08-04 12:12:13 +09:00
Dr.Lt.Data
33106d0ecf update DB 2025-08-04 12:10:52 +09:00
Novice_Chen
5bb887206a add new node:ComfyUI-XingLiu (#2040) 2025-08-04 12:09:22 +09:00
Dr.Lt.Data
b30b0e27cb update DB 2025-08-04 08:59:56 +09:00
Dr.Lt.Data
363736489c update DB 2025-08-04 08:59:40 +09:00
Dr.Lt.Data
8dbf5e87a0 update DB 2025-08-04 07:39:25 +09:00
Dr.Lt.Data
0b30f2cb50 update DB 2025-08-04 07:02:06 +09:00
Brekel
ba5265dac4 Update custom-node-list.json (#2054)
Add ComfyUI-Brekel
2025-08-04 06:16:37 +09:00
Dr.Lt.Data
ecb9c65917 update DB 2025-08-04 06:16:24 +09:00
jupo-ai
8a98474600 Update custom-node-list.json (#2051) 2025-08-04 06:09:28 +09:00
Radiating Reverberations
b072216e67 Add Wan2.2 models from Comfy-Org (#2050) 2025-08-04 06:08:44 +09:00
Dr.Lt.Data
cfb3181716 update DB 2025-08-02 08:03:23 +09:00
Dr.Lt.Data
ab684cdc99 update DB 2025-08-01 12:22:27 +09:00
Dr.Lt.Data
facadc3a44 update DB 2025-08-01 07:29:09 +09:00
Christian Byrne
f599bc22d7 Merge pull request #2047 from viva-jinyi/feat/pydantic-validation-bulk-api
Add Pydantic validation to import_fail_info_bulk endpoint
2025-07-31 12:34:20 -07:00
Dr.Lt.Data
281319d2da update DB 2025-08-01 00:08:52 +09:00
Simlym
5cb203685c Update custom-node-list.json (#2045) 2025-07-31 23:44:48 +09:00
Jin Yi
300c6e7406 feat: Add Pydantic validation to import_fail_info_bulk endpoint
- Regenerated Pydantic models from updated OpenAPI specification
- Updated import_fail_info_bulk route handler to use ImportFailInfoBulkRequest/Response models
- Replaced manual JSON validation with Pydantic model validation
- Added proper error handling with ValidationError
- Updated data_models/__init__.py to export new models

Following the process outlined in data_models/README.md for type safety and consistency.
2025-07-31 14:15:21 +09:00
Dr.Lt.Data
9c4d6a0773 Merge branch 'main' into draft-v4 2025-07-31 12:44:02 +09:00
Dr.Lt.Data
01fa37900b update DB 2025-07-31 12:32:47 +09:00
Dr.Lt.Data
edbe744e17 update DB 2025-07-31 07:57:27 +09:00
Jin Yi
2a32a1a4a8 Add bulk API endpoint for import fail info (#2039)
* feat(api): Implement endpoint for bulk import failure info

Adds the `/v2/customnode/import_fail_info_bulk` endpoint to allow
fetching multiple import error statuses in a single request.

* chore(api): Update OpenAPI spec for new bulk endpoint

Adds the `import_fail_info_bulk` route and its corresponding
request/response schemas to `openapi.yaml`.
2025-07-31 07:43:49 +09:00
Dr.Lt.Data
404bdb21e6 update DB 2025-07-30 18:39:08 +09:00
PD19 Anime
b260c9a512 Update custom-node-list.json (#2044) 2025-07-30 18:33:29 +09:00
Yuan-Man
4b941adb6a Add ComfyUI-SkyworkUniPic (#2043) 2025-07-30 18:32:15 +09:00
copusDev
bd752550a8 feat: change web icon (#2042)
Co-authored-by: john <john@server31.io>
2025-07-30 18:31:56 +09:00
Dr.Lt.Data
b8b71bb961 update DB 2025-07-30 12:16:25 +09:00
Kevin Lin
5aaf7a4092 Update custom node listing (#2041) 2025-07-30 12:03:28 +09:00
Dr.Lt.Data
030e02ffb8 update DB 2025-07-30 08:57:38 +09:00
Jin Yi
60746c6253 [feat] Add bulk import failure info API endpoint (#2035)
* [feat] Add bulk import failure info API endpoint

- Add import_fail_info_bulk endpoint to both glob and legacy manager servers
- Supports bulk processing of cnr_ids and urls arrays in single request
- Maintains same error handling pattern as original import_fail_info API
- Reduces API calls from N to 1 for conflict detection optimization
- Validates input parameters and provides proper error responses

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* modified: remove manager button completely. Now, even when using the legacy UI, it must always be accessed through the menu.

* chore(api): Add temporary cache reload for import_fail_info_bulk

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dr.Lt.Data <dr.lt.data@gmail.com>
2025-07-30 07:57:19 +09:00
Dr.Lt.Data
d962aa03f4 update DB 2025-07-30 07:37:26 +09:00
Dr.Lt.Data
121a5a1888 As a temporary measure, the new UI will use the legacy/... backend structure.
The glob/... version will be applied later after the cacheless implementation is completed.
2025-07-30 01:13:17 +09:00
Dr.Lt.Data
9e4a2aae43 update DB 2025-07-30 00:02:30 +09:00
rainlizard
ee6eb685e7 Add Whirlpool Upscaler (#2037)
* Added Whirlpool Upscaler

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-29 23:52:57 +09:00
Dr.Lt.Data
09a38a32ce update DB 2025-07-29 21:30:45 +09:00
Android zhang
d13b19d43d Update custom-node-list.json (#2036)
Add ComfyUI-MoGe2
2025-07-29 21:02:18 +09:00
Dr.Lt.Data
5316ec1b4d Merge branch 'main' into draft-v4 2025-07-29 12:18:55 +09:00
Dr.Lt.Data
e730dca1ad update DB 2025-07-29 12:13:35 +09:00
Dr.Lt.Data
8da30640bb update DB
fixed: scanner.py
2025-07-29 07:45:05 +09:00
Dr.Lt.Data
6f4eb88e07 update DB 2025-07-28 12:15:58 +09:00
Dr.Lt.Data
d9592b9dab update DB 2025-07-28 08:57:58 +09:00
Dr.Lt.Data
b87ada72aa update DB 2025-07-28 07:04:57 +09:00
Dr.Lt.Data
83363ba1f0 update DB 2025-07-27 21:36:48 +09:00
Dr.Lt.Data
a2a7349ce4 Merge branch 'main' into draft-v4 2025-07-27 16:07:57 +09:00
Dr.Lt.Data
23ebe7f718 update DB 2025-07-27 15:04:41 +09:00
Dr.Lt.Data
e04264cfa3 update DB 2025-07-27 10:45:00 +09:00
Shmuel Ronen
8d29e5037f Add ComfyUI-HiggsAudio_Wrapper to custom node list (#2034) 2025-07-27 10:28:27 +09:00
Dr.Lt.Data
6926ed45b0 update DB 2025-07-26 21:05:02 +09:00
Dr.Lt.Data
736b85b8bb update DB 2025-07-26 20:51:43 +09:00
Nanthakumar
9e3361bc31 Update custom-node-list.json (#2031) 2025-07-26 20:37:40 +09:00
Dr.Lt.Data
6e10381020 update DB 2025-07-26 11:13:08 +09:00
Dr.Lt.Data
a1d37d379c update DB 2025-07-26 09:34:57 +09:00
comfyuistudio
07d87db7a2 Update custom-node-listAdd ComfyUI-Studio-nodes to custom_nodes registry.json (#2029)
* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-26 09:29:31 +09:00
Dr.Lt.Data
4e556673d2 update DB 2025-07-26 09:27:00 +09:00
AIWarper
f421304fc1 Update custom-node-list.json (#2028) 2025-07-26 09:25:34 +09:00
Dr.Lt.Data
6867616973 Merge branch 'main' into draft-v4 2025-07-25 12:26:42 +09:00
Dr.Lt.Data
c9271b1686 update DB 2025-07-25 12:19:45 +09:00
Dr.Lt.Data
12eb6863da update DB 2025-07-25 08:58:56 +09:00
Dr.Lt.Data
4834874091 fixed: ruff check 2025-07-25 07:26:48 +09:00
Dr.Lt.Data
8759ebf200 bump version 2025-07-25 07:03:14 +09:00
YAN Wenkun
d4715aebef Migrate matrix-client to matrix-nio (#2025) 2025-07-25 06:59:46 +09:00
Dr.Lt.Data
0fe2ade7bb update DB 2025-07-25 06:59:32 +09:00
Dr.Lt.Data
0c71565535 update DB 2025-07-24 21:28:41 +09:00
Dr.Lt.Data
cf8029ecd4 Merge branch 'main' into draft-v4 2025-07-24 12:41:48 +09:00
Dr.Lt.Data
6a637091a2 update DB 2025-07-24 12:10:49 +09:00
Dr.Lt.Data
31eba60012 update DB 2025-07-24 09:00:09 +09:00
Dr.Lt.Data
51e58e9078 update DB 2025-07-24 07:07:58 +09:00
Dr.Lt.Data
4a1e76730a fixed: security_check - robust checking
https://github.com/Comfy-Org/ComfyUI-Manager/issues/2002
2025-07-24 02:44:43 +09:00
Dr.Lt.Data
5599bb028b fixed: security_check - robust checking
https://github.com/Comfy-Org/ComfyUI-Manager/issues/2002
2025-07-24 02:38:53 +09:00
Dr.Lt.Data
552c6da0cc modified: download_url - provide more informative error messages
https://github.com/Comfy-Org/ComfyUI-Manager/issues/2016
2025-07-24 02:30:07 +09:00
Dr.Lt.Data
cc6817a891 fixed: cnr_utils – fixed improper behavior of bypass_ssl
https://github.com/Comfy-Org/ComfyUI-Manager/issues/2017
2025-07-24 02:15:31 +09:00
Dr.Lt.Data
fb48d1b485 update DB 2025-07-24 02:06:14 +09:00
Uygar
1c336dad6b ComfyUI-Artha-Gemini custom node (#2024)
* Add files via upload

* Update custom-node-list.json
2025-07-24 02:01:31 +09:00
Dr.Lt.Data
a4940d46cd update DB 2025-07-24 02:01:16 +09:00
猫大好き
499b2f44c1 Add builmenlabo custom node entry (#2020)
* Add files via upload

* Add files via upload

* Delete manager_registration.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-24 01:59:13 +09:00
Yuan-Man
2b200c9281 Add ComfyUI-HiggsAudio (#2023) 2025-07-24 01:58:09 +09:00
Dr.Lt.Data
36a900c98f update DB 2025-07-23 12:50:44 +09:00
Dr.Lt.Data
5236b03f66 update DB 2025-07-23 07:32:34 +09:00
kpsss34
8be35e3621 Update custom-node-list.json (#2021)
Rename: ComfyUI-kpsss34-Sana to ComfyUI-kpsss34
2025-07-23 07:31:26 +09:00
Dariusz L
509f00fe89 Add Comfyui-LayerForge (#2022)
Add the "Comfyui-LayerForge" node to the community list.
2025-07-23 07:30:43 +09:00
Dr.Lt.Data
a98b87f148 update DB 2025-07-22 12:17:42 +09:00
Dr.Lt.Data
ae9b2b3b72 update DB 2025-07-22 08:59:51 +09:00
Dr.Lt.Data
02e1ec0ae3 update DB 2025-07-22 07:32:38 +09:00
Vaishnav V Nair
daefb0f120 Update custom-node-list.json (#2018)
first custom node
2025-07-22 07:22:18 +09:00
Dr.Lt.Data
ff0604e3b6 update DB 2025-07-21 12:14:49 +09:00
Dr.Lt.Data
20e41e22fa update DB 2025-07-21 08:59:07 +09:00
Dr.Lt.Data
59264c1fd9 Merge branch 'main' into draft-v4 2025-07-20 19:23:24 +09:00
Dr.Lt.Data
a0e3bdd594 update DB 2025-07-20 19:15:45 +09:00
brucew4yn3rp
6580aaf3ad Added Save Image (Selective Metadata) node (#2012) 2025-07-20 18:57:27 +09:00
Dr.Lt.Data
0b46701b60 update DB 2025-07-20 18:57:10 +09:00
Edoardo Carmignani
0bb4effede Add ComfyUI-ExtraLinks (#2009)
A one-click collection of alternate connection styles for ComfyUI.
2025-07-20 18:21:25 +09:00
Dr.Lt.Data
b07082a52d update DB 2025-07-19 18:16:26 +09:00
StrawBerryFist
04f267f5a7 Add StrawberryFist VRAM Optimizer node to custom-node-list.json (#2007)
* Add StrawberryFist VRAM Optimizer node to custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-19 18:15:22 +09:00
Dr.Lt.Data
03ccce2804 fixed: cm-cli - provides pip dependency restoration using the options --pip-non-url, --pip-non-local-url, and --pip-local-url.
https://github.com/Comfy-Org/ComfyUI-Manager/issues/2008
2025-07-19 06:51:07 +09:00
Dr.Lt.Data
e894bd9f24 update DB 2025-07-18 07:50:14 +09:00
Dr.Lt.Data
10e6988273 update DB 2025-07-18 07:26:51 +09:00
Erehr
905b61e5d8 Publish ComfyUI-Eagle-Autosend (#2006) 2025-07-18 07:25:55 +09:00
Dr.Lt.Data
ee69d393ae update DB
update scanner script
2025-07-17 12:22:13 +09:00
Dr.Lt.Data
cab39973ae update DB 2025-07-17 12:10:40 +09:00
Dr.Lt.Data
d93f5d07bb update DB 2025-07-17 08:57:16 +09:00
Dr.Lt.Data
ba00ffe1ae update DB 2025-07-17 07:39:11 +09:00
Gilad Schreiber
6afaf5eaf5 Add LTX-Video 0.9.8 distilled models (#2005)
- Add LTX-Video 2B Distilled v0.9.8 (6.34GB)
- Add LTX-Video 2B Distilled FP8 v0.9.8 (4.46GB)
- Add LTX-Video 13B Distilled v0.9.8 (28.6GB)
- Add LTX-Video 13B Distilled FP8 v0.9.8 (15.7GB)

These v0.9.8 models feature improved prompt understanding and detail generation.
Both 2B and 13B variants available in standard and FP8 quantized versions.

Co-authored-by: gschreiber <gschreiber@infra-image-generator.c.ltx-research-vms.internal>
2025-07-17 07:38:53 +09:00
Dr.Lt.Data
d30459cc34 update DB 2025-07-16 12:31:58 +09:00
Dr.Lt.Data
e92fbb7b1b update DB 2025-07-16 12:24:26 +09:00
aiaiaikkk
42d464b532 Update custom-node-list.json (#2004)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-16 12:22:34 +09:00
Dr.Lt.Data
c2e9e5c63a update DB 2025-07-16 07:28:23 +09:00
Creepybits
bc36726925 Update custom-node-list.json (#2001)
Add Save To OneDrive node for ComfyUI
2025-07-16 07:08:59 +09:00
Dr.Lt.Data
22725b0188 add missing file 2025-07-15 18:52:17 +09:00
Dr.Lt.Data
7abbff8c31 update DB 2025-07-15 12:14:23 +09:00
Android zhang
6236f4bcf4 Add ComfyUI nodes to use Distill-Any-Depth prediction (#1999) 2025-07-15 06:27:32 +09:00
Jukka Seppänen
3c3e80f77f Add WanVideoWrapper (#1998)
* Add IC-Light nodes and models

* Add Florence2 and LuminaWrapper -nodes

https://github.com/kijai/ComfyUI-Florence2
https://github.com/kijai/ComfyUI-LuminaWrapper

* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

* Add segment-anything-2

* Update custom-node-list.json

* Add T5 encoder models

* Update custom-node-list.json

* Add PyramidFlowWrapper

* Add HunyuanVideoWrapper

* Add ComfyUI-WanVideoWrapper
2025-07-15 06:25:56 +09:00
Dr.Lt.Data
4aae2fb289 update DB 2025-07-14 20:29:22 +09:00
Dr.Lt.Data
66ff07752f update DB 2025-07-14 19:04:10 +09:00
LaoMaoBoss
5cf92f2742 Add ComfyUI-WBLESS (#1990)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-14 19:03:33 +09:00
Dr.Lt.Data
6d3fddc474 update DB 2025-07-14 19:02:41 +09:00
Dr.Lt.Data
66d4ad6174 update DB 2025-07-14 18:58:05 +09:00
ChenNing
2a366a1607 Add ComfyUI_Image_Pin (#1992) 2025-07-14 18:56:22 +09:00
Dr.Lt.Data
d87a0995b4 update DB 2025-07-14 18:55:31 +09:00
Dr.Lt.Data
9a73a41e04 update DB 2025-07-14 18:55:11 +09:00
company8
ba041b36bc Update custom-node-list.json (#1993) 2025-07-14 18:54:18 +09:00
Eses
f5f9de69b4 Add EsesImageCompare node to node list (#1994)
Co-authored-by: eses <13034046+quasiblob@users.noreply.github.com>
2025-07-14 18:53:29 +09:00
Yuan-Man
71e56c62e8 Add ComfyUI-ThinkSound (#1989) 2025-07-14 18:52:27 +09:00
Dr.Lt.Data
a0b0c2b963 feat: initial implementation of middleware-based security policy 2025-07-12 11:31:07 +09:00
Dr.Lt.Data
0f496619fd update DB 2025-07-12 11:07:46 +09:00
Dr.Lt.Data
5fdd6a441a update DB 2025-07-12 09:07:33 +09:00
Dr.Lt.Data
00f287bb63 fixed: ruff check 2025-07-12 06:15:09 +09:00
Dr.Lt.Data
785268efa6 modified: By default, do not forcefully downgrade numpy to below version 2. I believe enough of a grace period has now been given.
https://github.com/Comfy-Org/ComfyUI-Manager/issues/1981#issuecomment-3058772842
2025-07-12 06:07:10 +09:00
Dr.Lt.Data
2c976d9394 update DB 2025-07-12 05:54:51 +09:00
Dr.Lt.Data
1e32582642 fixed: broken db 2025-07-12 05:29:32 +09:00
IsItDanOrAi
6f8f6d07f5 Update custom-node-list.json (#1980) 2025-07-12 05:28:36 +09:00
Gilad Schreiber
3958111e76 Add LTX-Video ICLoRA models for depth, pose, and canny control (#1988)
- Add LTX-Video ICLoRA Depth 13B v0.9.7 (81.9MB)
- Add LTX-Video ICLoRA Pose 13B v0.9.7 (151MB)
- Add LTX-Video ICLoRA Canny 13B v0.9.7 (81.9MB)

These In-Context LoRA models enable precise control for video-to-video generation
with depth, pose, and canny edge conditioning respectively.

Co-authored-by: gschreiber <gschreiber@infra-image-generator.c.ltx-research-vms.internal>
2025-07-12 05:20:21 +09:00
Dr.Lt.Data
86fcc4af74 update DB 2025-07-10 12:33:19 +09:00
Dr.Lt.Data
2fd26756df update DB 2025-07-10 07:41:25 +09:00
Eses
478f4b74d8 add ComfyUI-EsesImageTransform node (#1987)
Co-authored-by: eses <13034046+quasiblob@users.noreply.github.com>
2025-07-10 07:36:40 +09:00
Dr.Lt.Data
73d0d2a1bb update DB 2025-07-09 22:59:44 +09:00
Dr.Lt.Data
546db08ec4 update DB 2025-07-09 08:56:44 +09:00
Dr.Lt.Data
0dd41a8670 update DB 2025-07-09 07:19:11 +09:00
PD19 Anime
82c0c89f46 Add ComfyUI-PD19Anime-Nodes to custom node list (#1975)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-09 06:38:43 +09:00
Dr.Lt.Data
f4ce0fd5f1 Merge branch 'main' into draft-v4 2025-07-08 12:21:47 +09:00
Dr.Lt.Data
c3798bf4c2 update DB 2025-07-08 12:12:31 +09:00
Dr.Lt.Data
ff80b6ccb0 update DB 2025-07-08 08:58:03 +09:00
Eses
e729217116 add ComfyUI-EsesImageEffectCurves node (#1976)
Co-authored-by: eses <13034046+quasiblob@users.noreply.github.com>
2025-07-08 08:56:58 +09:00
Dr.Lt.Data
94c695daca update DB 2025-07-08 08:56:11 +09:00
FortunaCournot
9f189f0420 Stereoscopic Nodes added (#1978) 2025-07-08 08:55:24 +09:00
Bas Nijholt
ad09e53f60 Remove file argument from logging.error in manager_server.py (#1977)
Otherwise this results in:
```python
TypeError: Logger._log() got an unexpected keyword argument 'file' 
```
2025-07-08 08:48:16 +09:00
Dr.Lt.Data
092a7a5f3f update DB 2025-07-07 23:38:10 +09:00
Dr.Lt.Data
f45649bd25 update DB 2025-07-07 12:59:28 +09:00
Dr.Lt.Data
2595cc5ed7 bump version 2025-07-07 01:05:25 +09:00
Dr.Lt.Data
2f62190c6f update DB 2025-07-07 01:00:58 +09:00
Alexander Piskun
577314984c fix(Windows, numpy): fix for cm-cli usage (#1972) 2025-07-06 22:36:49 +09:00
Dr.Lt.Data
f0346b955b update DB 2025-07-06 16:57:36 +09:00
Dr.Lt.Data
70139ded4a bump version 2025-07-06 13:40:50 +09:00
Dr.Lt.Data
bf379900e1 update DB 2025-07-06 13:40:17 +09:00
Dr.Lt.Data
9bafc90f5e update DB 2025-07-06 08:31:22 +09:00
Alexander Piskun
fce0d9e88e fix(Windows, numpy): do not use 'uv' by default (#1971) 2025-07-06 08:23:31 +09:00
namtb96
2b3b154989 Add OmniGen2 Simple Node (#1970)
* add OmniGen2 custom node

* Change extenions name
2025-07-06 08:22:02 +09:00
Dr.Lt.Data
948d2440a1 update DB 2025-07-05 09:40:28 +09:00
Dr.Lt.Data
5adbe1ce7a update DB 2025-07-05 06:42:32 +09:00
vrgamegirl19
8157d34ffa Add VRGameDevGirl’s Video Enhancement Nodes (#1966)
* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-05 06:26:15 +09:00
Dr.Lt.Data
3ec8cb2204 update DB 2025-07-05 06:06:16 +09:00
Dr.Lt.Data
0daa826543 fixed: invalid default config.ini
https://github.com/Comfy-Org/ComfyUI-Manager/issues/1967
2025-07-04 17:54:26 +09:00
Dr.Lt.Data
a66028da58 update DB 2025-07-04 08:53:35 +09:00
Dr.Lt.Data
807c9e6872 update DB 2025-07-04 07:02:41 +09:00
Dr.Lt.Data
e71f3774ba modified: If uv is available, set use_uv to True by default. 2025-07-03 12:32:50 +09:00
Dr.Lt.Data
dd7314bf10 update DB 2025-07-03 12:22:59 +09:00
Dr.Lt.Data
f33bc127dc update DB 2025-07-03 07:31:25 +09:00
Creepybits
db92b87782 Update custom-node-list.json (#1965)
* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-03 07:08:40 +09:00
Dr.Lt.Data
eba41c8693 update DB 2025-07-02 21:38:06 +09:00
sunxAI
c855308162 Update DB (#1963)
* Update custom-node-list.json

update

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-07-02 21:32:13 +09:00
Dr.Lt.Data
73d971bed8 bump version 2025-07-02 12:33:16 +09:00
copusDev
bcfe0c2874 feat: copus content add rating (#1962)
Co-authored-by: john <john@server31.io>
2025-07-02 12:32:17 +09:00
Dr.Lt.Data
931ff666ae update DB 2025-07-02 12:02:20 +09:00
Dr.Lt.Data
18b6d86cc4 update DB 2025-07-02 08:57:41 +09:00
Dr.Lt.Data
086040f858 bump version 2025-07-01 12:55:13 +09:00
Dr.Lt.Data
adbeb527d6 added: middleware manager for security policy 2025-07-01 12:54:29 +09:00
Dr.Lt.Data
043176168d Merge branch 'main' into draft-v4 2025-07-01 12:35:39 +09:00
Dr.Lt.Data
3c5efa0662 update DB 2025-07-01 12:18:14 +09:00
Dr.Lt.Data
9b739bcbbf update DB 2025-07-01 08:57:40 +09:00
Dr.Lt.Data
db89076e48 update DB 2025-07-01 07:30:59 +09:00
Dr.Lt.Data
19b341ef18 update DB 2025-07-01 01:04:40 +09:00
Dr.Lt.Data
be3713b1a3 update DB 2025-07-01 00:21:53 +09:00
Dr.Lt.Data
99c4415cfb update DB 2025-06-30 21:29:41 +09:00
方长君
7b311f2ccf Add MultiSaveImage custom node (#1956) 2025-06-30 21:13:20 +09:00
Dr.Lt.Data
4aeabfe0a7 update DB 2025-06-30 07:34:20 +09:00
Dr.Lt.Data
431ed02194 update DB 2025-06-30 07:25:27 +09:00
KarmaSwint
07f587ed83 Add KarmaNodes to Comfy Registry (#1958)
Co-authored-by: Karma Swint <karmaaswint@gmail.com>
2025-06-30 07:16:43 +09:00
S4MUEL
0408341d82 Add ComfyUI-S4Tool-Image to custom nodes list (#1957)
Add ComfyUI-S4Tool-Image to custom nodes list
2025-06-30 07:16:33 +09:00
Dr.Lt.Data
5b3c9432f3 update DB 2025-06-29 15:48:08 +09:00
Dr.Lt.Data
4a197e63f9 update DB 2025-06-28 23:31:08 +09:00
Dr.Lt.Data
ad79a2ef45 Merge branch 'main' into draft-v4 2025-06-28 19:59:19 +09:00
Dr.Lt.Data
0876a12fe9 update DB 2025-06-28 19:33:20 +09:00
Dr.Lt.Data
c43c7ecc03 update DB 2025-06-28 18:15:49 +09:00
Dr.Lt.Data
4a6dee3044 update DB 2025-06-28 08:45:28 +09:00
Dr.Lt.Data
019acdd840 update DB 2025-06-28 08:22:30 +09:00
PeterMikhai
1c98512720 Update custom-node-list.json (#1955)
* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-06-28 08:21:18 +09:00
Dr.Lt.Data
43041cebed modified: Do not modify generated_models.py directly; use openapi.yaml instead. 2025-06-28 07:54:17 +09:00
Dr.Lt.Data
23a09ad546 update DB 2025-06-27 12:23:33 +09:00
Dr.Lt.Data
0836e8fe7c update DB 2025-06-27 07:23:09 +09:00
Dr.Lt.Data
90196af8f8 update DB 2025-06-27 01:48:34 +09:00
Dr.Lt.Data
002e549a86 modified: security policy
- Strengthened the default security policy
- Subdivided the risky levels high and middle into high+, high, middle+, and middle
- Added support for personal_cloud network mode
- Updated README.md

fixed: invalid security message
fixed: legacy - crash when security policy violation occurred

modified: default 'use_uv' is now True
2025-06-27 01:38:38 +09:00
Dr.Lt.Data
1de6f859bf Merge branch 'main' into draft-v4 2025-06-26 23:21:04 +09:00
Dr.Lt.Data
566fe05772 update DB 2025-06-26 22:56:48 +09:00
uinodes
18772c6292 Update custom-node-list.json (#1953) 2025-06-26 22:34:15 +09:00
Yuan-Man
6278bddc9b Add ComfyUI-PosterCraft (#1952) 2025-06-26 22:33:02 +09:00
Dr.Lt.Data
f74bf71735 update DB 2025-06-26 08:58:08 +09:00
Dr.Lt.Data
efe9ed68b2 update DB 2025-06-26 06:56:56 +09:00
Ambrosinus
7c1e75865d Add ComfyUI-ATk-Nodes plugin (#1949)
* Update custom-node-list.json

* Update custom-node-list.json

fixing the correct insertion of new entries in alphabetical order.
2025-06-26 06:37:29 +09:00
Dr.Lt.Data
89530fc4e7 Merge branch 'main' into draft-v4 2025-06-25 12:58:50 +09:00
Dr.Lt.Data
a0aee41f1a fixed: Support configuration with use_uv enabled in environments where only uv exists without pip.
https://github.com/Comfy-Org/ComfyUI-Manager/issues/1828
2025-06-25 12:44:26 +09:00
Dr.Lt.Data
2049dd75f4 update DB 2025-06-25 12:17:07 +09:00
Dr.Lt.Data
0864c35ba9 update DB 2025-06-25 07:27:45 +09:00
Dr.Lt.Data
92c9f66671 update DB 2025-06-25 00:52:31 +09:00
Dr.Lt.Data
223d6dad51 Merge branch 'main' into draft-v4 2025-06-25 00:46:12 +09:00
Dr.Lt.Data
815784e809 fixed: Fix issue where some nodepacks were displayed redundantly in custom nodes manager. 2025-06-25 00:18:18 +09:00
Dr.Lt.Data
2795d00d1e update DB 2025-06-24 23:39:31 +09:00
Dr.Lt.Data
86dd0b4963 update DB 2025-06-24 07:17:40 +09:00
Dr.Lt.Data
77a4f4819f update DB 2025-06-24 00:18:16 +09:00
Dr.Lt.Data
b63d603482 update DB 2025-06-23 23:40:54 +09:00
Dr.Lt.Data
e569b4e613 update DB 2025-06-23 12:35:42 +09:00
Gero Doll
8a70997546 Add ComfyUI Face Detection Node (#1947) 2025-06-23 12:29:58 +09:00
Dr.Lt.Data
80d0a0f882 update DB 2025-06-23 08:47:23 +09:00
Dr.Lt.Data
70b3997874 update DB 2025-06-23 06:53:30 +09:00
Dr.Lt.Data
e8e4311068 update DB 2025-06-22 18:43:10 +09:00
Christian Byrne
cb0fa5829d Merge pull request #1915 from Comfy-Org/feat/implement-batch-tracking-clean
[feat] Implement comprehensive batch tracking and OpenAPI-driven data models
2025-06-21 19:46:23 -07:00
bymyself
a66f86d4af cleanup records older than 16 days 2025-06-21 16:57:54 -07:00
bymyself
35d98dcea8 add batch_id to history task items 2025-06-21 16:45:50 -07:00
bymyself
38fefde06d add embedded python to system state 2025-06-21 16:29:40 -07:00
bymyself
75ecb31f8c add frontend version to system state capture 2025-06-21 16:28:00 -07:00
bymyself
77133375ad [fix] Ensure batch history is written when queue becomes empty 2025-06-21 16:01:25 -07:00
Dr.Lt.Data
c58b93ff51 update DB 2025-06-22 00:31:46 +09:00
Dr.Lt.Data
7d8ebfe91b update DB 2025-06-22 00:08:43 +09:00
Dr.Lt.Data
810381eab2 update DB 2025-06-22 00:03:44 +09:00
Dr.Lt.Data
61dc6cf2de update DB 2025-06-21 23:35:58 +09:00
NumZ
0205ebad2a Add ComfyUI-SeedVR2_VideoUpscaler Nodes (#1945)
* Update custom-node-list.json for Comfyui-Orpheus

add custom nodes from https://github.com/numz/Comfyui-Orpheus

* Update custom-node-list.json

add ComfyUI-SeedVR2_VideoUpscaler Node
2025-06-21 23:34:47 +09:00
Dr.Lt.Data
09a94133ac update DB 2025-06-21 23:34:05 +09:00
Dr.Lt.Data
1eb3c3b219 update DB 2025-06-21 23:25:10 +09:00
Alejandro Olivares Mompó
457845bb51 Add Kaizen Package by aleolidev (#1946) 2025-06-21 23:18:54 +09:00
Yuan-Man
0c11b46585 Add ComfyUI-OmniGen2 (#1944) 2025-06-21 23:17:36 +09:00
Dr.Lt.Data
c35100d9e9 update DB 2025-06-21 00:51:05 +09:00
Dr.Lt.Data
847031cb04 update DB 2025-06-20 12:33:28 +09:00
bymyself
d1ca6288a3 apply formatting 2025-06-19 16:41:16 -07:00
bymyself
624ad4cfe6 remove debug comments 2025-06-19 16:39:14 -07:00
Dr.Lt.Data
f8d87bb452 update DB 2025-06-20 07:38:39 +09:00
Dr.Lt.Data
f60b3505e0 update DB 2025-06-19 20:44:57 +09:00
Dr.Lt.Data
addefbc511 update DB 2025-06-19 12:55:15 +09:00
Dr.Lt.Data
c4314b25a3 update DB 2025-06-19 07:34:54 +09:00
Dr.Lt.Data
921bb86127 update DB 2025-06-18 12:37:38 +09:00
bymyself
d912fb0f8b [fix] Remove unused imports to fix Ruff linting errors 2025-06-17 15:27:21 -07:00
bymyself
e8fc053a32 [fix] Update data models to Pydantic v2 syntax to fix TypeError 2025-06-17 15:12:25 -07:00
bymyself
ce3b2bab39 refactor 2025-06-17 14:58:34 -07:00
bymyself
15e3699535 [cleanup] Remove outdated temp_queue_batch comment 2025-06-17 14:44:58 -07:00
bymyself
a4bf6bddbf [refactor] Use Pydantic models for query parameter validation
- Added query parameter models to OpenAPI spec for GET endpoints
- Regenerated data models to include new query param models
- Replaced manual validation with Pydantic model validation
- Removed obsolete validate_required_params helper function
- Provides better error messages and type safety for API endpoints

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-17 14:42:25 -07:00
bymyself
f1b3c6b735 [refactor] Move model utility functions to model_utils module 2025-06-17 14:24:31 -07:00
bymyself
e923434d08 [fix] Update client filtering to handle tuple structure in pending_tasks 2025-06-17 13:52:00 -07:00
bymyself
ddc9cd0fd5 [fix] Use tuples in TaskQueue heap for proper comparison support 2025-06-17 13:42:47 -07:00
bymyself
d081db0c30 [cleanup] Remove dead code do_update_all function
- Removed do_update_all function that was never called and only returned an error
- Removed "update-all" from OperationType enum as it's no longer used
- Regenerated data models to reflect the enum change

The update_all functionality now properly creates individual update tasks through the API endpoint rather than being a single monolithic task.

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-17 13:27:51 -07:00
bymyself
14298b0859 [fix] Remove unused imports to fix linting errors 2025-06-17 13:08:52 -07:00
bymyself
03ecda3cfe [feat] Implement comprehensive system state capture for batch records 2025-06-17 13:08:35 -07:00
bymyself
350cb767c3 [feat] Regenerate data models with enhanced ComfyUISystemState
- Add SecurityLevel and RiskLevel enums to generated models
- Enhance ComfyUISystemState with additional system information fields:
  - comfyui_root_path: ComfyUI installation directory
  - model_paths: Map of model types to configured paths
  - manager_version: ComfyUI Manager version
  - security_level: Current security configuration
  - network_mode: Network mode (online/offline/private)
  - cli_args: Selected CLI arguments
  - custom_nodes_count: Total number of custom nodes
  - failed_imports: List of failed imports
  - pip_packages: Installed pip packages

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-17 13:06:14 -07:00
bymyself
f450dcbb57 [feat] Add SecurityLevel and RiskLevel enums to OpenAPI schema
- Add SecurityLevel enum with strong/normal/normal-/weak values
- Add RiskLevel enum with block/high/middle values
- These will be used for security policy management

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-17 13:05:59 -07:00
bymyself
32e003965a fix files description in api 2025-06-17 10:36:52 -07:00
bymyself
65f0764338 fix duplicated schemas in openapi 2025-06-17 10:36:31 -07:00
bymyself
1bdb026079 explain glob vs legacy in claude memory 2025-06-17 10:36:08 -07:00
Dr.Lt.Data
b3a7fb9c3e update DB 2025-06-17 23:53:40 +09:00
Lord Lethris
c143c81a7e Update custom-node-list.json (#1941) 2025-06-17 23:46:54 +09:00
Dr.Lt.Data
dd389ba0f8 update DB 2025-06-17 22:34:28 +09:00
seeo
46b1649ab8 Update custom-node-list.json (#1940) 2025-06-17 22:24:24 +09:00
Dr.Lt.Data
89710412e4 fixed: indentation error 2025-06-17 07:27:46 +09:00
Dr.Lt.Data
931973b632 update DB 2025-06-17 07:22:13 +09:00
Dr.Lt.Data
60aaa838e3 update DB 2025-06-17 00:52:22 +09:00
Dr.Lt.Data
7e51286313 Merge branch 'main' into draft-v4 2025-06-17 00:33:31 +09:00
Dr.Lt.Data
1246538bbb fixed: Issue where installation status was not properly recognized when the nodepack ID registered in the registry was not normalized.
- ex) `ComfyUI-Crystools`

https://github.com/Comfy-Org/ComfyUI-Manager/issues/1834#issuecomment-2937370214
2025-06-17 00:31:51 +09:00
Dr.Lt.Data
80518abf9d update DB 2025-06-16 22:42:41 +09:00
Leon Wong
fc1ae2a18e added comfyui-leon-nodes to ustom-node-list.json (#1937) 2025-06-16 22:17:45 +09:00
Yuan-Man
3fd8d2049c Add ComfyUI-Hunyuan3D-2.1 (#1936) 2025-06-16 22:16:50 +09:00
Dr.Lt.Data
35a6bcf20c update DB 2025-06-16 12:52:05 +09:00
Dr.Lt.Data
0d75fc331e update DB 2025-06-16 07:28:55 +09:00
Dr.Lt.Data
0a23e793e3 update DB 2025-06-15 15:43:09 +09:00
Dr.Lt.Data
2c1c03e063 update DB 2025-06-15 14:27:27 +09:00
Çağlayan Karagözler
64059d2949 Added ComfyUI-YouTubeUploader to custom nodes json (#1933)
* Update custom-node-list.json

Added ComfyUI-YouTubeUploader

* Update custom-node-list.json

* Update custom-node-list.json

Added proper link

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-06-15 14:13:03 +09:00
Dr.Lt.Data
648aa7c4d3 update DB 2025-06-14 18:56:19 +09:00
bymyself
c888ea6435 [fix] Reduce excessive logging output to debug level
- Convert batch tracking messages to debug level (batch start, history saved)
- Convert task processing details to debug level
- Convert cache update messages to debug level
- Replace print() with logging.debug() for task processing
- Keep user-relevant messages at info level (ComfyUI updates, installation success)
- Resolves verbose output appearing without --verbose flag
2025-06-13 20:39:18 -07:00
bymyself
b089db79c5 [fix] Restore proper thread-based TaskQueue worker management
- Fix async/sync mismatch in TaskQueue worker implementation
- Use threading.Thread with asyncio.run() as originally designed
- Remove incorrect async task approach that caused blocking issues
- TaskQueue now properly manages its own thread lifecycle
- Resolves WebSocket message delivery and task processing issues
2025-06-13 20:27:41 -07:00
bymyself
7a73f5db73 [fix] Update CI to only check changed files
- Add tj-actions/changed-files to detect modified files in PR
- Only run OpenAPI validation if openapi.yaml was changed
- Only run Python linting on changed Python files (excluding legacy/)
- Remove incorrect "pip install ast" dependency
- Remove non-standard AST parsing and import checks
- Makes CI more efficient and prevents unrelated failures
2025-06-13 19:41:07 -07:00
bymyself
a96e7b114e [chore] Regenerate data models after OpenAPI fixes
- Updated generated_models.py to reflect OpenAPI 3.1 nullable format changes
- Models now use Optional[type] instead of nullable: true
- All affected models regenerated with datamodel-codegen
- Syntax and linting checks pass
2025-06-13 19:41:07 -07:00
bymyself
0148b5a3cc [fix] Fix OpenAPI validation errors for CI compliance
- Convert all nullable: true to OpenAPI 3.1 format using type: [type, 'null']
- Fix invalid array schema definition in ManagerMappings using oneOf
- Add default security: [] configuration to satisfy security-defined rule
- All 41 validation errors resolved, spec now passes with 0 errors
- 141 warnings remain (mostly missing operationId and example validation)
2025-06-13 19:41:07 -07:00
bymyself
2120a0aa79 [chore] Add dist/ to gitignore to exclude build artifacts 2025-06-13 19:40:27 -07:00
bymyself
706b6d8317 [refactor] Remove legacy thread management for TaskQueue
- Add proper async worker management to TaskQueue class
- Remove redundant task_worker_thread and task_worker_lock global variables
- Replace manual threading with async task management
- Update is_processing() logic to use TaskQueue state instead of thread status
- Implement automatic worker cleanup when queue processing completes
- Simplify queue start endpoint to use TaskQueue.start_worker()
2025-06-13 19:40:27 -07:00
bymyself
a59e6e176e [refactor] Remove redundant ExecutionStatus NamedTuple
- Eliminate TaskQueue.ExecutionStatus NamedTuple in favor of generated TaskExecutionStatus Pydantic model
- Remove manual conversion logic between NamedTuple and Pydantic model
- Use single source of truth for task execution status
- Clean up unused imports (Literal, NamedTuple)
- Maintain consistent data model usage throughout TaskQueue
2025-06-13 19:37:57 -07:00
bymyself
1d575fb654 [refactor] Replace non-standard OpenAPI validation with Redoc CLI
- Replace deprecated openapi-spec-validator with @redocly/cli
- Remove fragile custom regex-based route alignment script
- Use industry-standard OpenAPI validation tooling
- Switch from Python to Node.js for validation pipeline
- New validation catches 41 errors and 141 warnings that old validator missed
2025-06-13 19:37:57 -07:00
bymyself
98af8dc849 add claude memory 2025-06-13 19:37:57 -07:00
bymyself
4d89c69109 add installed packs to openapi 2025-06-13 19:37:57 -07:00
bymyself
b73dc6121f refresh cache before reporting status 2025-06-13 19:37:57 -07:00
bymyself
b55e1404b1 return installed pack list on status update 2025-06-13 19:37:57 -07:00
bymyself
0be0a2e6d7 migrate to data models for all routes 2025-06-13 19:37:57 -07:00
bymyself
3afafdb884 remove dist dir 2025-06-13 19:37:57 -07:00
bymyself
884b503728 [feat] Add comprehensive Pydantic validation to all API endpoints
- Updated all POST endpoints to use proper Pydantic model validation:
  - `/v2/manager/queue/task` - validates QueueTaskItem
  - `/v2/manager/queue/install_model` - validates ModelMetadata
  - `/v2/manager/queue/reinstall` - validates InstallPackParams
  - `/v2/customnode/import_fail_info` - validates cnr_id/url fields

- Added proper error handling with ValidationError for detailed error messages
- Updated TaskQueue.put() to handle both dict and Pydantic model inputs
- Added missing imports: InstallPackParams, ModelMetadata, ValidationError

Benefits:
- Early validation catches invalid data at API boundaries
- Better error messages for clients with specific validation failures
- Type safety throughout the request processing pipeline
- Consistent validation behavior across all endpoints

All ruff checks pass and validation is now enabled by default.
2025-06-13 19:37:57 -07:00
bymyself
7f1ebbe081 [cleanup] Remove completed TODO comments and fix ruff issues
- Removed completed TODO comments about code quality checks and client_id handling
- Updated comments to reflect implemented features
- Fixed ruff linting errors:
  - Removed duplicate constant definitions
  - Added missing locale import
  - Fixed unused imports
  - Moved is_local_mode logic to security_utils module
  - Added model_dir_name_map import to model_utils

All ruff checks now pass successfully.
2025-06-13 19:37:57 -07:00
bymyself
c8882dcb7c [feat] Implement comprehensive batch tracking and OpenAPI-driven data models
Enhances ComfyUI Manager with robust batch execution tracking and unified data model architecture:

- Implemented automatic batch history serialization with before/after system state snapshots
- Added comprehensive state management capturing installed nodes, models, and ComfyUI version info
- Enhanced task queue with proper client ID handling and WebSocket notifications
- Migrated all data models to OpenAPI-generated Pydantic models for consistency
- Added documentation for new TaskQueue methods (done_count, total_count, finalize)
- Fixed 64 linting errors with proper imports and code cleanup

Technical improvements:
- All models now auto-generated from openapi.yaml ensuring API/implementation consistency
- Batch tracking captures complete system state at operation start and completion
- Enhanced REST endpoints with comprehensive documentation
- Removed manual model files in favor of single source of truth
- Added helper methods for system state capture and batch lifecycle management
2025-06-13 19:36:55 -07:00
bymyself
601f1bf452 [feat] Add client_id support to task queue system
- Add client_id field to QueueTaskItem and TaskHistoryItem models
- Implement client-specific WebSocket message routing
- Add client filtering to queue status and history endpoints
- Follow ComfyUI patterns for session management
- Create data_models package for better code organization
2025-06-13 19:33:05 -07:00
Dr.Lt.Data
274bb81a08 update DB 2025-06-14 10:06:34 +09:00
Dr.Lt.Data
e2c90b4681 update DB 2025-06-13 22:41:52 +09:00
Dr.Lt.Data
fa0a98ac6e update DB 2025-06-13 12:53:51 +09:00
Dr.Lt.Data
e6e7b42415 update DB 2025-06-13 03:01:18 +09:00
Dr.Lt.Data
0b7ef2e1d4 update DB 2025-06-12 18:21:40 +09:00
Yuan-Man
2fac67a9f9 Add ComfyUI-Vui (#1930) 2025-06-12 18:15:32 +09:00
Dr.Lt.Data
8b9892de2e update DB 2025-06-12 12:31:04 +09:00
Dr.Lt.Data
b3290dc909 update DB 2025-06-12 12:24:22 +09:00
LargeModGames
3e3176eddb Update custom-node-list.json for new node: Add ComfyUI LoRA Auto Downloader (#1929)
* Add ComfyUI LoRA Auto Downloader extension

Adding ComfyUI LoRA Auto Downloader extension to the registry.
- Automatically downloads missing LoRAs from CivitAI
- Detects missing LoRAs in workflows
- Smart directory detection

* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-06-12 12:22:50 +09:00
Dr.Lt.Data
b1ef84894a update DB 2025-06-12 12:22:02 +09:00
hassan-sd
c6cffc92c4 Update custom-node-list.json for new node: comfyui-image-prompt-loader (#1928)
https://github.com/hassan-sd/comfyui-image-prompt-loader

Load images with automatic prompt extraction from Civitai URLs, caption files, or EXIF metadata. Features smart dataset detection and dynamic preview updates.
2025-06-12 12:16:27 +09:00
Dr.Lt.Data
efb9fd2712 update DB 2025-06-12 07:21:17 +09:00
Dr.Lt.Data
94b294ff93 update DB 2025-06-12 07:17:09 +09:00
Dr.Lt.Data
99a9e33648 update DB 2025-06-11 22:11:42 +09:00
gitadmini
055d94a919 add node extractstoryboards (#1927)
* add node extractstoryboards

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-06-11 22:00:32 +09:00
Dr.Lt.Data
0978005240 update DB 2025-06-11 12:31:34 +09:00
Yuan-Man
1f796581ec Add ComfyUI-Direct3D-S2 node (#1925) 2025-06-11 07:31:56 +09:00
Dr.Lt.Data
f3a1716dad update DB 2025-06-11 07:23:14 +09:00
Zachary
a1c3a0db1f add my custom node for read metadata from filepath. (#1926) 2025-06-11 06:59:54 +09:00
Dr.Lt.Data
9f80cc8a6b update DB 2025-06-10 12:27:20 +09:00
Dr.Lt.Data
133786846e update DB 2025-06-10 07:28:53 +09:00
keit
bdf297a5c6 Add ComfyUI-keitNodes (#1924) 2025-06-10 07:28:02 +09:00
Dr.Lt.Data
6767254eb0 update DB 2025-06-10 07:27:48 +09:00
11dogzi
691cebd479 CYBERPUNK-STYLE-DIY (#1923) 2025-06-10 07:26:14 +09:00
xiaowc
f3932cbf29 Add Comfyui-Dynamic-Params Node Plugin (#1922)
* Update custom-node-list.json to add Comfyui-Dynamic-Params Node

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-06-10 07:25:52 +09:00
Dr.Lt.Data
3f73a97037 update DB 2025-06-10 07:25:40 +09:00
Erehr
226f1f5be4 Add ComfyUI-EreNodes (#1921)
* Add ComfyUI-EreNodes

* Update custom-node-list.json
2025-06-10 07:23:53 +09:00
Dr.Lt.Data
7e45c07660 update DB 2025-06-10 07:23:40 +09:00
INuBq8
0c815036b9 Update custom-node-list.json (#1920) 2025-06-10 07:22:31 +09:00
Dr.Lt.Data
3870abfd2d Merge branch 'main' into draft-v4 2025-06-09 12:37:10 +09:00
Dr.Lt.Data
ae9fdd0255 update DB 2025-06-09 07:19:09 +09:00
Vlad Bondarovich
b3874ee6fd Update custom-node-list.json (#1917) 2025-06-09 06:06:15 +09:00
Eric W. Burns
62af4891f3 Update custom-node-list.json (#1912)
Submitting my new custom nodes at https://github.com/burnsbert/ComfyUI-EBU-Workflow for inclusion, thanks!
2025-06-09 06:02:16 +09:00
Budi Hartono
2176e0c0ad Add CAS Aspect Ratio Presets Node for ComfyUI to custom-node-list.json (#1910)
Add a custom node to quickly create empty latents in common resolutions and aspect ratios for SD 1.5, SDXL, Flux, Chroma, and HiDream. Choose from curated presets or generate by axis and aspect ratio. Appears in the 'latent' node group.
2025-06-09 06:01:18 +09:00
Dr.Lt.Data
cac105b0d5 fixed: prevent halting when log flushing fails.
https://github.com/Comfy-Org/ComfyUI-Manager/issues/1794
2025-06-08 06:54:39 +09:00
Dr.Lt.Data
cd7c42cc23 update DB 2025-06-08 06:39:30 +09:00
Dr.Lt.Data
a3fb847773 fixed: Don't override preview method if --preview-method is given
https://github.com/Comfy-Org/ComfyUI-Manager/issues/1887
2025-06-08 06:33:42 +09:00
Dr.Lt.Data
5c2f4f9e4b fixed: Issue where cloning Comfy-Org/ComfyUI-Manager would cause mismatches with ltdrdata/ComfyUI-Manager, resulting in it not being recognized properly.
https://github.com/Comfy-Org/ComfyUI-Manager/issues/1900
2025-06-08 06:24:19 +09:00
Dr.Lt.Data
0a511d5b87 update DB 2025-06-08 05:00:25 +09:00
Dr.Lt.Data
efe1aad5db update DB 2025-06-07 16:20:15 +09:00
Dr.Lt.Data
eed4c53df0 update DB 2025-06-07 12:55:45 +09:00
Dr.Lt.Data
9c08a6314b update DB 2025-06-07 12:32:42 +09:00
Pigidiy
a6b2d2c722 Add ComfyUI-LikeSpiderAI-UI (UI Framework for Node Creators) (#1907)
This PR adds a declarative UI framework for ComfyUI nodes: ComfyUI-LikeSpiderAI-UI.

Highlights:
- Minimalistic base class: LikeSpiderUINode
- Built-in input schema with auto-generated UI
- Example node: AudioExport (supports mp3/wav/flac + bitrate/filename)
- Designed for extensibility and clean UX

Author: Pigidiy
2025-06-07 12:31:47 +09:00
Dr.Lt.Data
8303e7c043 Merge branch 'main' into draft-v4
# Conflicts:
#	comfyui_manager/common/README.md
#	comfyui_manager/glob/manager_core.py
#	comfyui_manager/js/README.md
#	pyproject.toml
2025-06-01 06:23:11 +09:00
Dr.Lt.Data
35464654c1 fixed: cm_global importing error 2025-05-19 06:10:25 +09:00
Dr.Lt.Data
ec9d52d482 Merge branch 'main' into draft-v4 2025-05-19 06:07:31 +09:00
Dr.Lt.Data
90ce448380 Merge branch 'main' into draft-v4 2025-05-12 12:21:18 +09:00
Dr.Lt.Data
56125839ac Merge branch 'main' into draft-v4 2025-04-29 00:30:02 +09:00
Dr.Lt.Data
cd49799bed fixed: crash related to deleted CNR node after installed
modified: convert cm-cli.sh to cm-cli command
2025-04-28 00:13:31 +09:00
Dr.Lt.Data
d547a05106 Merge branch 'main' into draft-v4 2025-04-27 23:17:18 +09:00
Dr.Lt.Data
db0b57a14c Merge branch 'main' into draft-v4 2025-04-24 08:44:50 +09:00
Dr.Lt.Data
2048ac87a9 modified: glob.core - make default network mode as public.
Network mode does not simply determine whether the CNR cache is used. Even after switching to cacheless in the future, it will continue to be used as a policy for user environments.
2025-04-24 08:41:17 +09:00
Dr.Lt.Data
9adf6de850 fixed: missing channels.list.template
modified: /ltdrdata -> /Comfy-Org
modified: set default network as public instead of offline
2025-04-23 08:58:47 +09:00
Dr.Lt.Data
7657c7866f fixed: perform reload when starting task worker 2025-04-22 12:39:09 +09:00
Dr.Lt.Data
d638f75117 modified: prevent displaying ComfyUI-Manager on list 2025-04-22 02:39:56 +09:00
Dr.Lt.Data
efff6b2c18 Merge branch 'main' into draft-v4 2025-04-22 01:20:57 +09:00
Dr.Lt.Data
0c46434164 fixed: avoid except:
fixed: prestartup_script - remove useless exception handling when fallback resolving comfy_path
2025-04-21 12:42:50 +09:00
Dr.Lt.Data
0bb8947c02 Merge branch 'main' into draft-v4 2025-04-21 12:12:27 +09:00
Christian Byrne
09e8e8798c Add is_legacy_manager_ui route from the legacy package as well (#1748)
* add `is_legacy_manager_ui` route to `legacy` package  as well

* add static
2025-04-15 18:36:38 +09:00
Christian Byrne
abfd85602e Only load legacy FE extension if --enable-manager-legacy-ui is set (#1746)
* only load JS extensions when legacy arg is set

* add `is_legacy_manager_ui` endpoint
2025-04-15 08:03:04 +09:00
Dr.Lt.Data
1816bb748e use --enable-manager-legacy-ui cli arg instead of env variable 2025-04-15 01:36:35 +09:00
Dr.Lt.Data
05ceab68f8 restructuring
the existing cache-based implementation will be retained as a fallback under legacy/..., while glob/... will be updated to a cacheless implementation.
2025-04-13 09:26:02 +09:00
Christian Byrne
46a37907e6 add development guide (#1739) 2025-04-13 08:40:28 +09:00
Dr.Lt.Data
7fc8ba587e fixed: don't disable legacy ComfyUI-Manager unless --disable-comfyui is set 2025-04-12 21:24:29 +09:00
Dr.Lt.Data
7a35bd9d9a Merge branch 'main' into draft-v4 2025-04-12 21:22:34 +09:00
Dr.Lt.Data
a76ef49d2d Merge branch 'feat/cacheless-v2' into draft-v4 2025-04-12 20:11:33 +09:00
Dr.Lt.Data
bb0fcf6ea6 added: should_be_disabled function 2025-04-12 19:35:41 +09:00
Dr.Lt.Data
539e0a1534 Merge branch 'main' into draft-v4 2025-04-12 19:06:24 +09:00
Dr.Lt.Data
aaae6ce304 Merge branch 'feat/queue_batch' into draft-v4 2025-04-12 19:05:48 +09:00
bymyself
3c413840d7 use parsed version and id even when no cnr map exists 2025-04-11 16:33:12 -07:00
bymyself
29ca93fcb4 fix: installed nodes should still be initialized in offline mode 2025-04-11 15:56:03 -07:00
bymyself
9dc8e630a0 fix is_legacy_front should be a function still 2025-04-10 18:24:34 -07:00
bymyself
10105ad737 if pip package, force offline mode 2025-04-10 13:09:56 -07:00
bymyself
5738ea861a don't load legacy web dir when --disable-manager arg set 2025-04-09 22:19:56 -07:00
Dr.Lt.Data
dbd25b0f0a Merge branch 'main' into feat/cacheless 2025-04-10 12:20:29 +09:00
bymyself
0de9d36c28 enable legacy manager frontend during beta phase 2025-04-09 14:59:32 -07:00
bymyself
05f1a8ab0d add missing v2 prefix to customnode/installed route 2025-04-09 14:59:06 -07:00
bymyself
5ce170b7ce don't handle queue in legacy front if element is not visible 2025-04-09 14:58:39 -07:00
bymyself
2b47aad076 don't show menu buttons if past comfyui front 1.16 2025-04-09 14:58:21 -07:00
bymyself
b4dc59331d fix merge conflict 2025-04-09 14:57:53 -07:00
bymyself
81e84fad78 add workflow to publish to pypi 2025-04-09 08:59:39 -07:00
Dr.Lt.Data
42e8a959dd Modify the structure to be installable via pip. 2025-04-09 08:59:37 -07:00
Dr.Lt.Data
208ca31836 support installation of system added nodepack
modified: install_by_id - Change the install path of the CNR node added by the system to be based on the repo URL instead of the CNR ID.
2025-04-09 08:57:56 -07:00
Dr.Lt.Data
a128baf894 fixed: ruff check 2025-03-25 23:40:15 +09:00
Dr.Lt.Data
57b847eebf fixed: failed[..].ui_id -> failed 2025-03-24 23:12:45 +09:00
Dr.Lt.Data
149257e4f1 Merge branch 'main' into feat/queue_batch 2025-03-24 22:53:13 +09:00
Dr.Lt.Data
212b8e7ed2 feat: support task batch
POST /v2/manager/queue/batch
GET /v2/manager/queue/history_list
GET /v2/manager/queue/history?id={id}
GET /v2/manager/queue/abort_current
2025-03-24 22:49:38 +09:00
Dr.Lt.Data
01ac9c895a Modify the structure to be installable via pip. 2025-03-19 22:15:53 +09:00
Dr.Lt.Data
ebcb14e6aa support installation of system added nodepack
modified: install_by_id - Change the install path of the CNR node added by the system to be based on the repo URL instead of the CNR ID.
2025-03-19 07:41:39 +09:00
57 changed files with 40181 additions and 12058 deletions

70
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: CI
on:
push:
branches: [ main, feat/*, fix/* ]
pull_request:
branches: [ main ]
jobs:
validate-openapi:
name: Validate OpenAPI Specification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check if OpenAPI changed
id: openapi-changed
uses: tj-actions/changed-files@v44
with:
files: openapi.yaml
- name: Setup Node.js
if: steps.openapi-changed.outputs.any_changed == 'true'
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install Redoc CLI
if: steps.openapi-changed.outputs.any_changed == 'true'
run: |
npm install -g @redocly/cli
- name: Validate OpenAPI specification
if: steps.openapi-changed.outputs.any_changed == 'true'
run: |
redocly lint openapi.yaml
code-quality:
name: Code Quality Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for proper diff
- name: Get changed Python files
id: changed-py-files
uses: tj-actions/changed-files@v44
with:
files: |
**/*.py
files_ignore: |
comfyui_manager/legacy/**
- name: Setup Python
if: steps.changed-py-files.outputs.any_changed == 'true'
uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Install dependencies
if: steps.changed-py-files.outputs.any_changed == 'true'
run: |
pip install ruff
- name: Run ruff linting on changed files
if: steps.changed-py-files.outputs.any_changed == 'true'
run: |
echo "Changed files: ${{ steps.changed-py-files.outputs.all_changed_files }}"
echo "${{ steps.changed-py-files.outputs.all_changed_files }}" | xargs -r ruff check

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch:
push:
branches:
- main
- draft-v4
paths:
- "pyproject.toml"
@@ -21,7 +21,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
python-version: '3.x'
- name: Install build dependencies
run: |
@@ -31,28 +31,28 @@ jobs:
- name: Get current version
id: current_version
run: |
CURRENT_VERSION=$(grep -oP 'version = "\K[^"]+' pyproject.toml)
CURRENT_VERSION=$(grep -oP '^version = "\K[^"]+' pyproject.toml)
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"
- name: Build package
run: python -m build
- name: Create GitHub Release
id: create_release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: dist/*
tag_name: v${{ steps.current_version.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
# - name: Create GitHub Release
# id: create_release
# uses: softprops/action-gh-release@v2
# env:
# GITHUB_TOKEN: ${{ github.token }}
# with:
# files: dist/*
# tag_name: v${{ steps.current_version.outputs.version }}
# draft: false
# prerelease: false
# generate_release_notes: true
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc
with:
password: ${{ secrets.PYPI_TOKEN }}
skip-existing: true
verbose: true
verbose: true

View File

@@ -1,25 +0,0 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- main-blocked
paths:
- "pyproject.toml"
permissions:
issues: write
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'ltdrdata' || github.repository_owner == 'Comfy-Org' }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@v1
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}

1
.gitignore vendored
View File

@@ -19,5 +19,6 @@ pip_overrides.json
check2.sh
/venv/
build
dist
*.egg-info
.env

View File

@@ -215,13 +215,14 @@ The following settings are applied based on the section marked as `is_default`.
downgrade_blacklist = <Set a list of packages to prevent downgrades. List them separated by commas.>
security_level = <Set the security level => strong|normal|normal-|weak>
always_lazy_install = <Whether to perform dependency installation on restart even in environments other than Windows.>
network_mode = <Set the network mode => public|private|offline>
network_mode = <Set the network mode => public|private|offline|personal_cloud>
```
* network_mode:
- public: An environment that uses a typical public network.
- private: An environment that uses a closed network, where a private node DB is configured via `channel_url`. (Uses cache if available)
- offline: An environment that does not use any external connections when using an offline network. (Uses cache if available)
- personal_cloud: Applies relaxed security features in cloud environments such as Google Colab or Runpod, where strong security is not required.
## Additional Feature
@@ -312,31 +313,33 @@ When you run the `scan.sh` script:
## Security policy
* Edit `config.ini` file: add `security_level = <LEVEL>`
* `strong`
* doesn't allow `high` and `middle` level risky feature
* `normal`
* doesn't allow `high` level risky feature
* `middle` level risky feature is available
* `normal-`
* doesn't allow `high` level risky feature if `--listen` is specified and not starts with `127.`
* `middle` level risky feature is available
* `weak`
* all feature is available
* `high` level risky features
* `Install via git url`, `pip install`
* Installation of custom nodes registered not in the `default channel`.
* Fix custom nodes
* `middle` level risky features
* Uninstall/Update
* Installation of custom nodes registered in the `default channel`.
* Restore/Remove Snapshot
* Restart
* `low` level risky features
* Update ComfyUI
The security settings are applied based on whether the ComfyUI server's listener is non-local and whether the network mode is set to `personal_cloud`.
* **non-local**: When the server is launched with `--listen` and is bound to a network range other than the local `127.` range, allowing remote IP access.
* **personal\_cloud**: When the `network_mode` is set to `personal_cloud`.
### Risky Level Table
| Risky Level | features |
|-------------|---------------------------------------------------------------------------------------------------------------------------------------|
| high+ | * `Install via git url`, `pip install`<BR>* Installation of nodepack registered not in the `default channel`. |
| high | * Fix nodepack |
| middle+ | * Uninstall/Update<BR>* Installation of nodepack registered in the `default channel`.<BR>* Restore/Remove Snapshot<BR>* Install model |
| middle | * Restart |
| low | * Update ComfyUI |
### Security Level Table
| Security Level | local | non-local (personal_cloud) | non-local (not personal_cloud) |
|----------------|--------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|--------------------------------|
| strong | * Only `weak` level risky features are allowed | * Only `weak` level risky features are allowed | * Only `weak` level risky features are allowed |
| normal | * `high+` and `high` level risky features are not allowed<BR>* `middle+` and `middle` level risky features are available | * `high+` and `high` level risky features are not allowed<BR>* `middle+` and `middle` level risky features are available | * `high+`, `high` and `middle+` level risky features are not allowed<BR>* `middle` level risky features are available
| normal- | * All features are available | * `high+` and `high` level risky features are not allowed<BR>* `middle+` and `middle` level risky features are available | * `high+`, `high` and `middle+` level risky features are not allowed<BR>* `middle` level risky features are available
| weak | * All features are available | * All features are available | * `high+` and `middle+` level risky features are not allowed<BR>* `high`, `middle` and `low` level risky features are available
# Disclaimer

View File

@@ -2,20 +2,16 @@
This directory contains the Python backend modules that power ComfyUI-Manager, handling the core functionality of node management, downloading, security, and server operations.
## Core Modules
## Directory Structure
- **glob/** - code for new cacheless ComfyUI-Manager
- **legacy/** - code for legacy ComfyUI-Manager
## Core Modules
- **manager_core.py**: The central implementation of management functions, handling configuration, installation, updates, and node management.
- **manager_server.py**: Implements server functionality and API endpoints for the web interface to interact with the backend.
- **manager_downloader.py**: Handles downloading operations for models, extensions, and other resources.
- **manager_util.py**: Provides utility functions used throughout the system.
## Specialized Modules
- **cm_global.py**: Maintains global variables and state management across the system.
- **cnr_utils.py**: Helper utilities for interacting with the custom node registry (CNR).
- **git_utils.py**: Git-specific utilities for repository operations.
- **node_package.py**: Handles the packaging and installation of node extensions.
- **security_check.py**: Implements the multi-level security system for installation safety.
- **share_3rdparty.py**: Manages integration with third-party sharing platforms.
## Architecture

View File

@@ -1,5 +1,10 @@
import os
import logging
from aiohttp import web
from .common.manager_security import HANDLER_POLICY
from .common import manager_security
from comfy.cli_args import args
def prestartup():
from . import prestartup_script # noqa: F401
@@ -7,8 +12,6 @@ def prestartup():
def start():
from comfy.cli_args import args
logging.info('[START] ComfyUI-Manager')
from .common import cm_global # noqa: F401
@@ -17,15 +20,21 @@ def start():
try:
from .legacy import manager_server # noqa: F401
from .legacy import share_3rdparty # noqa: F401
from .legacy import manager_core as core
import nodes
logging.info("[ComfyUI-Manager] Legacy UI is enabled.")
nodes.EXTENSION_WEB_DIRS['comfyui-manager-legacy'] = os.path.join(os.path.dirname(__file__), 'js')
except Exception as e:
print("Error enabling legacy ComfyUI Manager frontend:", e)
core = None
else:
from .glob import manager_server # noqa: F401
from .glob import share_3rdparty # noqa: F401
from .glob import manager_core as core
if core is not None:
manager_security.is_personal_cloud_mode = core.get_config()['network_mode'].lower() == 'personal_cloud'
def should_be_disabled(fullpath:str) -> bool:
@@ -33,8 +42,6 @@ def should_be_disabled(fullpath:str) -> bool:
1. Disables the legacy ComfyUI-Manager.
2. The blocklist can be expanded later based on policies.
"""
from comfy.cli_args import args
if not args.disable_manager:
# In cases where installation is done via a zip archive, the directory name may not be comfyui-manager, and it may not contain a git repository.
# It is assumed that any installed legacy ComfyUI-Manager will have at least 'comfyui-manager' in its directory name.
@@ -43,3 +50,55 @@ def should_be_disabled(fullpath:str) -> bool:
return True
return False
def get_client_ip(request):
peername = request.transport.get_extra_info("peername")
if peername is not None:
host, port = peername
return host
return "unknown"
def create_middleware():
connected_clients = set()
is_local_mode = manager_security.is_loopback(args.listen)
@web.middleware
async def manager_middleware(request: web.Request, handler):
nonlocal connected_clients
# security policy for remote environments
prev_client_count = len(connected_clients)
client_ip = get_client_ip(request)
connected_clients.add(client_ip)
next_client_count = len(connected_clients)
if prev_client_count == 1 and next_client_count > 1:
manager_security.multiple_remote_alert()
policy = manager_security.get_handler_policy(handler)
is_banned = False
# policy check
if len(connected_clients) > 1:
if is_local_mode:
if HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NON_LOCAL in policy:
is_banned = True
if HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD in policy:
is_banned = not manager_security.is_personal_cloud_mode
if HANDLER_POLICY.BANNED in policy:
is_banned = True
if is_banned:
logging.warning(f"[Manager] Banning request from {client_ip}: {request.path}")
response = web.Response(text="[Manager] This request is banned.", status=403)
else:
response: web.Response = await handler(request)
return response
return manager_middleware

View File

@@ -46,10 +46,7 @@ comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
cm_global.pip_blacklist = {'torch', 'torchaudio', 'torchsde', 'torchvision'}
cm_global.pip_downgrade_blacklist = ['torch', 'torchaudio', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']
if sys.version_info < (3, 13):
cm_global.pip_overrides = {'numpy': 'numpy<2'}
else:
cm_global.pip_overrides = {}
cm_global.pip_overrides = {}
if os.path.exists(os.path.join(manager_util.comfyui_manager_path, "pip_overrides.json")):
with open(os.path.join(manager_util.comfyui_manager_path, "pip_overrides.json"), 'r', encoding="UTF-8", errors="ignore") as json_file:
@@ -152,9 +149,6 @@ class Ctx:
with open(context.manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
cm_global.pip_overrides = json.load(json_file)
if sys.version_info < (3, 13):
cm_global.pip_overrides = {'numpy': 'numpy<2'}
if os.path.exists(context.manager_pip_blacklist_path):
with open(context.manager_pip_blacklist_path, 'r', encoding="UTF-8", errors="ignore") as f:
for x in f.readlines():
@@ -676,7 +670,7 @@ def install(
cmd_ctx.set_channel_mode(channel, mode)
cmd_ctx.set_no_deps(no_deps)
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
for_each_nodes(nodes, act=install_node, exit_on_fail=exit_on_fail)
pip_fixer.fix_broken()

View File

@@ -0,0 +1,16 @@
# ComfyUI-Manager: Core Backend (glob)
This directory contains the Python backend modules that power ComfyUI-Manager, handling the core functionality of node management, downloading, security, and server operations.
## Core Modules
- **manager_downloader.py**: Handles downloading operations for models, extensions, and other resources.
- **manager_util.py**: Provides utility functions used throughout the system.
## Specialized Modules
- **cm_global.py**: Maintains global variables and state management across the system.
- **cnr_utils.py**: Helper utilities for interacting with the custom node registry (CNR).
- **git_utils.py**: Git-specific utilities for repository operations.
- **node_package.py**: Handles the packaging and installation of node extensions.
- **security_check.py**: Implements the multi-level security system for installation safety.

View File

@@ -180,7 +180,7 @@ def install_node(node_id, version=None):
else:
url = f"{base_url}/nodes/{node_id}/install?version={version}"
response = requests.get(url)
response = requests.get(url, verify=not manager_util.bypass_ssl)
if response.status_code == 200:
# Convert the API response to a NodeVersion object
return map_node_version(response.json())
@@ -191,7 +191,7 @@ def install_node(node_id, version=None):
def all_versions_of_node(node_id):
url = f"{base_url}/nodes/{node_id}/versions?statuses=NodeVersionStatusActive&statuses=NodeVersionStatusPending"
response = requests.get(url)
response = requests.get(url, verify=not manager_util.bypass_ssl)
if response.status_code == 200:
return response.json()
else:
@@ -211,6 +211,7 @@ def read_cnr_info(fullpath):
project = data.get('project', {})
name = project.get('name').strip().lower()
original_name = project.get('name')
# normalize version
# for example: 2.5 -> 2.5.0
@@ -222,6 +223,7 @@ def read_cnr_info(fullpath):
if name and version: # repository is optional
return {
"id": name,
"original_name": original_name,
"version": version,
"url": repository
}

View File

@@ -106,4 +106,3 @@ def get_comfyui_tag():
except Exception:
return None

View File

@@ -4,6 +4,7 @@ class NetworkMode(enum.Enum):
PUBLIC = "public"
PRIVATE = "private"
OFFLINE = "offline"
PERSONAL_CLOUD = "personal_cloud"
class SecurityLevel(enum.Enum):
STRONG = "strong"

View File

@@ -46,6 +46,8 @@ def git_url(fullpath):
for k, v in config.items():
if k.startswith('remote ') and 'url' in v:
if 'Comfy-Org/ComfyUI-Manager' in v['url']:
return "https://github.com/ltdrdata/ComfyUI-Manager"
return v['url']
return None

View File

@@ -55,7 +55,11 @@ def download_url(model_url: str, model_dir: str, filename: str):
return aria2_download_url(model_url, model_dir, filename)
else:
from torchvision.datasets.utils import download_url as torchvision_download_url
return torchvision_download_url(model_url, model_dir, filename)
try:
return torchvision_download_url(model_url, model_dir, filename)
except Exception as e:
logging.error(f"[ComfyUI-Manager] Failed to download: {model_url} / {repr(e)}")
raise
def aria2_find_task(dir: str, filename: str):

View File

@@ -0,0 +1,36 @@
from enum import Enum
is_personal_cloud_mode = False
handler_policy = {}
class HANDLER_POLICY(Enum):
MULTIPLE_REMOTE_BAN_NON_LOCAL = 1
MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD = 2
BANNED = 3
def is_loopback(address):
import ipaddress
try:
return ipaddress.ip_address(address).is_loopback
except ValueError:
return False
def do_nothing():
pass
def get_handler_policy(x):
return handler_policy.get(x) or set()
def add_handler_policy(x, policy):
s = handler_policy.get(x)
if s is None:
s = set()
handler_policy[x] = s
s.add(policy)
multiple_remote_alert = do_nothing

View File

@@ -15,7 +15,6 @@ import re
import logging
import platform
import shlex
from . import cm_global
cache_lock = threading.Lock()
@@ -25,6 +24,7 @@ comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '
cache_dir = os.path.join(comfyui_manager_path, '.cache') # This path is also updated together in **manager_core.update_user_directory**.
use_uv = False
bypass_ssl = False
def is_manager_pip_package():
return not os.path.exists(os.path.join(comfyui_manager_path, '..', 'custom_nodes'))
@@ -140,7 +140,7 @@ async def get_data(uri, silent=False):
print(f"FETCH DATA from: {uri}", end="")
if uri.startswith("http"):
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=not bypass_ssl)) as session:
headers = {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
@@ -330,6 +330,32 @@ torch_torchvision_torchaudio_version_map = {
}
def torch_rollback(prev):
spec = prev.split('+')
if len(spec) > 1:
platform = spec[1]
else:
cmd = make_pip_cmd(['install', '--force', 'torch', 'torchvision', 'torchaudio'])
subprocess.check_output(cmd, universal_newlines=True)
logging.error(cmd)
return
torch_ver = StrictVersion(spec[0])
torch_ver = f"{torch_ver.major}.{torch_ver.minor}.{torch_ver.patch}"
torch_torchvision_torchaudio_ver = torch_torchvision_torchaudio_version_map.get(torch_ver)
if torch_torchvision_torchaudio_ver is None:
cmd = make_pip_cmd(['install', '--pre', 'torch', 'torchvision', 'torchaudio',
'--index-url', f"https://download.pytorch.org/whl/nightly/{platform}"])
logging.info("[ComfyUI-Manager] restore PyTorch to nightly version")
else:
torchvision_ver, torchaudio_ver = torch_torchvision_torchaudio_ver
cmd = make_pip_cmd(['install', f'torch=={torch_ver}', f'torchvision=={torchvision_ver}', f"torchaudio=={torchaudio_ver}",
'--index-url', f"https://download.pytorch.org/whl/{platform}"])
logging.info(f"[ComfyUI-Manager] restore PyTorch to {torch_ver}+{platform}")
subprocess.check_output(cmd, universal_newlines=True)
class PIPFixer:
def __init__(self, prev_pip_versions, comfyui_path, manager_files_path):
@@ -337,32 +363,6 @@ class PIPFixer:
self.comfyui_path = comfyui_path
self.manager_files_path = manager_files_path
def torch_rollback(self):
spec = self.prev_pip_versions['torch'].split('+')
if len(spec) > 0:
platform = spec[1]
else:
cmd = make_pip_cmd(['install', '--force', 'torch', 'torchvision', 'torchaudio'])
subprocess.check_output(cmd, universal_newlines=True)
logging.error(cmd)
return
torch_ver = StrictVersion(spec[0])
torch_ver = f"{torch_ver.major}.{torch_ver.minor}.{torch_ver.patch}"
torch_torchvision_torchaudio_ver = torch_torchvision_torchaudio_version_map.get(torch_ver)
if torch_torchvision_torchaudio_ver is None:
cmd = make_pip_cmd(['install', '--pre', 'torch', 'torchvision', 'torchaudio',
'--index-url', f"https://download.pytorch.org/whl/nightly/{platform}"])
logging.info("[ComfyUI-Manager] restore PyTorch to nightly version")
else:
torchvision_ver, torchaudio_ver = torch_torchvision_torchaudio_ver
cmd = make_pip_cmd(['install', f'torch=={torch_ver}', f'torchvision=={torchvision_ver}', f"torchaudio=={torchaudio_ver}",
'--index-url', f"https://download.pytorch.org/whl/{platform}"])
logging.info(f"[ComfyUI-Manager] restore PyTorch to {torch_ver}+{platform}")
subprocess.check_output(cmd, universal_newlines=True)
def fix_broken(self):
new_pip_versions = get_installed_packages(True)
@@ -384,7 +384,7 @@ class PIPFixer:
elif self.prev_pip_versions['torch'] != new_pip_versions['torch'] \
or self.prev_pip_versions['torchvision'] != new_pip_versions['torchvision'] \
or self.prev_pip_versions['torchaudio'] != new_pip_versions['torchaudio']:
self.torch_rollback()
torch_rollback(self.prev_pip_versions['torch'])
except Exception as e:
logging.error("[ComfyUI-Manager] Failed to restore PyTorch")
logging.error(e)
@@ -415,32 +415,14 @@ class PIPFixer:
if len(targets) > 0:
for x in targets:
if sys.version_info < (3, 13):
cmd = make_pip_cmd(['install', f"{x}=={versions[0].version_string}", "numpy<2"])
subprocess.check_output(cmd, universal_newlines=True)
cmd = make_pip_cmd(['install', f"{x}=={versions[0].version_string}"])
subprocess.check_output(cmd, universal_newlines=True)
logging.info(f"[ComfyUI-Manager] 'opencv' dependencies were fixed: {targets}")
except Exception as e:
logging.error("[ComfyUI-Manager] Failed to restore opencv")
logging.error(e)
# fix numpy
if sys.version_info >= (3, 13):
logging.info("[ComfyUI-Manager] In Python 3.13 and above, PIP Fixer does not downgrade `numpy` below version 2.0. If you need to force a downgrade of `numpy`, please use `pip_auto_fix.list`.")
else:
try:
np = new_pip_versions.get('numpy')
if cm_global.pip_overrides.get('numpy') == 'numpy<2':
if np is not None:
if StrictVersion(np) >= StrictVersion('2'):
cmd = make_pip_cmd(['install', "numpy<2"])
subprocess.check_output(cmd , universal_newlines=True)
logging.info("[ComfyUI-Manager] 'numpy' dependency were fixed")
except Exception as e:
logging.error("[ComfyUI-Manager] Failed to restore numpy")
logging.error(e)
# fix missing frontend
try:
# NOTE: package name in requirements is 'comfyui-frontend-package'
@@ -540,3 +522,69 @@ def robust_readlines(fullpath):
print(f"[ComfyUI-Manager] Failed to recognize encoding for: {fullpath}")
return []
def restore_pip_snapshot(pips, options):
non_url = []
local_url = []
non_local_url = []
for k, v in pips.items():
# NOTE: skip torch related packages
if k.startswith("torch==") or k.startswith("torchvision==") or k.startswith("torchaudio==") or k.startswith("nvidia-"):
continue
if v == "":
non_url.append(k)
else:
if v.startswith('file:'):
local_url.append(v)
else:
non_local_url.append(v)
# restore other pips
failed = []
if '--pip-non-url' in options:
# try all at once
res = 1
try:
res = subprocess.check_output(make_pip_cmd(['install'] + non_url))
except Exception:
pass
# fallback
if res != 0:
for x in non_url:
res = 1
try:
res = subprocess.check_output(make_pip_cmd(['install', '--no-deps', x]))
except Exception:
pass
if res != 0:
failed.append(x)
if '--pip-non-local-url' in options:
for x in non_local_url:
res = 1
try:
res = subprocess.check_output(make_pip_cmd(['install', '--no-deps', x]))
except Exception:
pass
if res != 0:
failed.append(x)
if '--pip-local-url' in options:
for x in local_url:
res = 1
try:
res = subprocess.check_output(make_pip_cmd(['install', '--no-deps', x]))
except Exception:
pass
if res != 0:
failed.append(x)
print(f"Installation failed for pip packages: {failed}")

View File

@@ -2,6 +2,8 @@ import sys
import subprocess
import os
from . import manager_util
def security_check():
print("[START] Security scan")
@@ -66,18 +68,23 @@ https://blog.comfy.org/comfyui-statement-on-the-ultralytics-crypto-miner-situati
"lolMiner": [os.path.join(comfyui_path, 'lolMiner')]
}
installed_pips = subprocess.check_output([sys.executable, '-m', "pip", "freeze"], text=True)
installed_pips = subprocess.check_output(manager_util.make_pip_cmd(["freeze"]), text=True)
detected = set()
try:
anthropic_info = subprocess.check_output([sys.executable, '-m', "pip", "show", "anthropic"], text=True, stderr=subprocess.DEVNULL)
anthropic_reqs = [x for x in anthropic_info.split('\n') if x.startswith("Requires")][0].split(': ')[1]
if "pycrypto" in anthropic_reqs:
location = [x for x in anthropic_info.split('\n') if x.startswith("Location")][0].split(': ')[1]
for fi in os.listdir(location):
if fi.startswith("anthropic"):
guide["ComfyUI_LLMVISION"] = f"\n0.Remove {os.path.join(location, fi)}" + guide["ComfyUI_LLMVISION"]
detected.add("ComfyUI_LLMVISION")
anthropic_info = subprocess.check_output(manager_util.make_pip_cmd(["show", "anthropic"]), text=True, stderr=subprocess.DEVNULL)
requires_lines = [x for x in anthropic_info.split('\n') if x.startswith("Requires")]
if requires_lines:
anthropic_reqs = requires_lines[0].split(": ", 1)[1]
if "pycrypto" in anthropic_reqs:
location_lines = [x for x in anthropic_info.split('\n') if x.startswith("Location")]
if location_lines:
location = location_lines[0].split(": ", 1)[1]
for fi in os.listdir(location):
if fi.startswith("anthropic"):
guide["ComfyUI_LLMVISION"] = (f"\n0.Remove {os.path.join(location, fi)}" + guide["ComfyUI_LLMVISION"])
detected.add("ComfyUI_LLMVISION")
except subprocess.CalledProcessError:
pass

View File

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,7 @@ datamodel-codegen \
--use-subclass-enum \
--field-constraints \
--strict-types bytes \
--use-double-quotes \
--input openapi.yaml \
--output comfyui_manager/data_models/generated_models.py \
--output-model-type pydantic_v2.BaseModel

View File

@@ -30,9 +30,15 @@ from .generated_models import (
InstalledModelInfo,
ComfyUIVersionInfo,
# Import Fail Info Models
ImportFailInfoBulkRequest,
ImportFailInfoBulkResponse,
ImportFailInfoItem,
ImportFailInfoItem1,
# Other models
Kind,
StatusStr,
OperationType,
OperationResult,
ManagerPackInfo,
ManagerPackInstalled,
SelectedVersion,
@@ -42,7 +48,16 @@ from .generated_models import (
ManagerPackInstallType,
ManagerPack,
InstallPackParams,
UpdatePackParams,
UpdateAllPacksParams,
UpdateComfyUIParams,
FixPackParams,
UninstallPackParams,
DisablePackParams,
EnablePackParams,
UpdateAllQueryParams,
UpdateComfyUIQueryParams,
ComfyUISwitchVersionQueryParams,
QueueStatus,
ManagerMappings,
ModelMetadata,
@@ -53,8 +68,8 @@ from .generated_models import (
HistoryResponse,
HistoryListResponse,
InstallType,
OperationType,
Result,
SecurityLevel,
RiskLevel,
)
__all__ = [
@@ -79,9 +94,15 @@ __all__ = [
"InstalledModelInfo",
"ComfyUIVersionInfo",
# Import Fail Info Models
"ImportFailInfoBulkRequest",
"ImportFailInfoBulkResponse",
"ImportFailInfoItem",
"ImportFailInfoItem1",
# Other models
"Kind",
"StatusStr",
"OperationType",
"OperationResult",
"ManagerPackInfo",
"ManagerPackInstalled",
"SelectedVersion",
@@ -91,7 +112,16 @@ __all__ = [
"ManagerPackInstallType",
"ManagerPack",
"InstallPackParams",
"UpdatePackParams",
"UpdateAllPacksParams",
"UpdateComfyUIParams",
"FixPackParams",
"UninstallPackParams",
"DisablePackParams",
"EnablePackParams",
"UpdateAllQueryParams",
"UpdateComfyUIQueryParams",
"ComfyUISwitchVersionQueryParams",
"QueueStatus",
"ManagerMappings",
"ModelMetadata",
@@ -102,6 +132,6 @@ __all__ = [
"HistoryResponse",
"HistoryListResponse",
"InstallType",
"OperationType",
"Result",
"SecurityLevel",
"RiskLevel",
]

View File

@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: openapi.yaml
# timestamp: 2025-06-08T08:07:38+00:00
# timestamp: 2025-07-31T04:52:26+00:00
from __future__ import annotations
@@ -11,213 +11,298 @@ from typing import Any, Dict, List, Optional, Union
from pydantic import BaseModel, Field, RootModel
class Kind(str, Enum):
install = 'install'
uninstall = 'uninstall'
update = 'update'
update_all = 'update-all'
update_comfyui = 'update-comfyui'
fix = 'fix'
disable = 'disable'
enable = 'enable'
install_model = 'install-model'
class OperationType(str, Enum):
install = "install"
uninstall = "uninstall"
update = "update"
update_comfyui = "update-comfyui"
fix = "fix"
disable = "disable"
enable = "enable"
install_model = "install-model"
class QueueTaskItem(BaseModel):
ui_id: str = Field(..., description='Unique identifier for the task')
client_id: str = Field(..., description='Client identifier that initiated the task')
kind: Kind = Field(..., description='Type of task being performed')
class StatusStr(str, Enum):
success = 'success'
error = 'error'
skip = 'skip'
class OperationResult(str, Enum):
success = "success"
failed = "failed"
skipped = "skipped"
error = "error"
skip = "skip"
class TaskExecutionStatus(BaseModel):
status_str: StatusStr = Field(..., description='Overall task execution status')
completed: bool = Field(..., description='Whether the task completed')
messages: List[str] = Field(..., description='Additional status messages')
status_str: OperationResult
completed: bool = Field(..., description="Whether the task completed")
messages: List[str] = Field(..., description="Additional status messages")
class ManagerMessageName(str, Enum):
cm_task_completed = 'cm-task-completed'
cm_task_started = 'cm-task-started'
cm_queue_status = 'cm-queue-status'
cm_task_completed = "cm-task-completed"
cm_task_started = "cm-task-started"
cm_queue_status = "cm-queue-status"
class ManagerPackInfo(BaseModel):
id: str = Field(
...,
description='Either github-author/github-repo or name of pack from the registry',
description="Either github-author/github-repo or name of pack from the registry",
)
version: str = Field(..., description='Semantic version or Git commit hash')
ui_id: Optional[str] = Field(None, description='Task ID - generated internally')
version: str = Field(..., description="Semantic version or Git commit hash")
ui_id: Optional[str] = Field(None, description="Task ID - generated internally")
class ManagerPackInstalled(BaseModel):
ver: str = Field(
...,
description='The version of the pack that is installed (Git commit hash or semantic version)',
description="The version of the pack that is installed (Git commit hash or semantic version)",
)
cnr_id: Optional[str] = Field(
None, description='The name of the pack if installed from the registry'
None, description="The name of the pack if installed from the registry"
)
aux_id: Optional[str] = Field(
None,
description='The name of the pack if installed from github (author/repo-name format)',
description="The name of the pack if installed from github (author/repo-name format)",
)
enabled: bool = Field(..., description='Whether the pack is enabled')
enabled: bool = Field(..., description="Whether the pack is enabled")
class SelectedVersion(str, Enum):
latest = 'latest'
nightly = 'nightly'
latest = "latest"
nightly = "nightly"
class ManagerChannel(str, Enum):
default = 'default'
recent = 'recent'
legacy = 'legacy'
forked = 'forked'
dev = 'dev'
tutorial = 'tutorial'
default = "default"
recent = "recent"
legacy = "legacy"
forked = "forked"
dev = "dev"
tutorial = "tutorial"
class ManagerDatabaseSource(str, Enum):
remote = 'remote'
local = 'local'
cache = 'cache'
remote = "remote"
local = "local"
cache = "cache"
class ManagerPackState(str, Enum):
installed = 'installed'
disabled = 'disabled'
not_installed = 'not_installed'
import_failed = 'import_failed'
needs_update = 'needs_update'
installed = "installed"
disabled = "disabled"
not_installed = "not_installed"
import_failed = "import_failed"
needs_update = "needs_update"
class ManagerPackInstallType(str, Enum):
git_clone = 'git-clone'
copy = 'copy'
cnr = 'cnr'
git_clone = "git-clone"
copy = "copy"
cnr = "cnr"
class UpdateState(str, Enum):
false = 'false'
true = 'true'
class SecurityLevel(str, Enum):
strong = "strong"
normal = "normal"
normal_ = "normal-"
weak = "weak"
class RiskLevel(str, Enum):
block = "block"
high_ = "high+"
high = "high"
middle_ = "middle+"
middle = "middle"
class UpdateState(Enum):
false = "false"
true = "true"
class ManagerPack(ManagerPackInfo):
author: Optional[str] = Field(
None, description="Pack author name or 'Unclaimed' if added via GitHub crawl"
)
files: Optional[List[str]] = Field(None, description='Files included in the pack')
reference: Optional[str] = Field(
None, description='The type of installation reference'
files: Optional[List[str]] = Field(
None,
description="Repository URLs for installation (typically contains one GitHub URL)",
)
title: Optional[str] = Field(None, description='The display name of the pack')
reference: Optional[str] = Field(
None, description="The type of installation reference"
)
title: Optional[str] = Field(None, description="The display name of the pack")
cnr_latest: Optional[SelectedVersion] = None
repository: Optional[str] = Field(None, description='GitHub repository URL')
repository: Optional[str] = Field(None, description="GitHub repository URL")
state: Optional[ManagerPackState] = None
update_state: Optional[UpdateState] = Field(
None, alias='update-state', description='Update availability status'
None, alias="update-state", description="Update availability status"
)
stars: Optional[int] = Field(None, description='GitHub stars count')
last_update: Optional[datetime] = Field(None, description='Last update timestamp')
health: Optional[str] = Field(None, description='Health status of the pack')
description: Optional[str] = Field(None, description='Pack description')
trust: Optional[bool] = Field(None, description='Whether the pack is trusted')
stars: Optional[int] = Field(None, description="GitHub stars count")
last_update: Optional[datetime] = Field(None, description="Last update timestamp")
health: Optional[str] = Field(None, description="Health status of the pack")
description: Optional[str] = Field(None, description="Pack description")
trust: Optional[bool] = Field(None, description="Whether the pack is trusted")
install_type: Optional[ManagerPackInstallType] = None
class InstallPackParams(ManagerPackInfo):
selected_version: Union[str, SelectedVersion] = Field(
..., description='Semantic version, Git commit hash, latest, or nightly'
..., description="Semantic version, Git commit hash, latest, or nightly"
)
repository: Optional[str] = Field(
None,
description='GitHub repository URL (required if selected_version is nightly)',
description="GitHub repository URL (required if selected_version is nightly)",
)
pip: Optional[List[str]] = Field(None, description='PyPi dependency names')
pip: Optional[List[str]] = Field(None, description="PyPi dependency names")
mode: ManagerDatabaseSource
channel: ManagerChannel
skip_post_install: Optional[bool] = Field(
None, description='Whether to skip post-installation steps'
None, description="Whether to skip post-installation steps"
)
class UpdateAllPacksParams(BaseModel):
mode: Optional[ManagerDatabaseSource] = None
ui_id: Optional[str] = Field(None, description='Task ID - generated internally')
ui_id: Optional[str] = Field(None, description="Task ID - generated internally")
class UpdatePackParams(BaseModel):
node_name: str = Field(..., description="Name of the node package to update")
node_ver: Optional[str] = Field(
None, description="Current version of the node package"
)
class UpdateComfyUIParams(BaseModel):
is_stable: Optional[bool] = Field(
True,
description="Whether to update to stable version (true) or nightly (false)",
)
target_version: Optional[str] = Field(
None,
description="Specific version to switch to (for version switching operations)",
)
class FixPackParams(BaseModel):
node_name: str = Field(..., description="Name of the node package to fix")
node_ver: str = Field(..., description="Version of the node package")
class UninstallPackParams(BaseModel):
node_name: str = Field(..., description="Name of the node package to uninstall")
is_unknown: Optional[bool] = Field(
False, description="Whether this is an unknown/unregistered package"
)
class DisablePackParams(BaseModel):
node_name: str = Field(..., description="Name of the node package to disable")
is_unknown: Optional[bool] = Field(
False, description="Whether this is an unknown/unregistered package"
)
class EnablePackParams(BaseModel):
cnr_id: str = Field(
..., description="ComfyUI Node Registry ID of the package to enable"
)
class UpdateAllQueryParams(BaseModel):
client_id: str = Field(
..., description="Client identifier that initiated the request"
)
ui_id: str = Field(..., description="Base UI identifier for task tracking")
mode: Optional[ManagerDatabaseSource] = None
class UpdateComfyUIQueryParams(BaseModel):
client_id: str = Field(
..., description="Client identifier that initiated the request"
)
ui_id: str = Field(..., description="UI identifier for task tracking")
stable: Optional[bool] = Field(
True,
description="Whether to update to stable version (true) or nightly (false)",
)
class ComfyUISwitchVersionQueryParams(BaseModel):
ver: str = Field(..., description="Version to switch to")
client_id: str = Field(
..., description="Client identifier that initiated the request"
)
ui_id: str = Field(..., description="UI identifier for task tracking")
class QueueStatus(BaseModel):
total_count: int = Field(
..., description='Total number of tasks (pending + running)'
..., description="Total number of tasks (pending + running)"
)
done_count: int = Field(..., description='Number of completed tasks')
in_progress_count: int = Field(..., description='Number of tasks currently running')
done_count: int = Field(..., description="Number of completed tasks")
in_progress_count: int = Field(..., description="Number of tasks currently running")
pending_count: Optional[int] = Field(
None, description='Number of tasks waiting to be executed'
None, description="Number of tasks waiting to be executed"
)
is_processing: bool = Field(..., description='Whether the task worker is active')
is_processing: bool = Field(..., description="Whether the task worker is active")
client_id: Optional[str] = Field(
None, description='Client ID (when filtered by client)'
None, description="Client ID (when filtered by client)"
)
class ManagerMapping(BaseModel):
title_aux: Optional[str] = Field(None, description='The display name of the pack')
class ManagerMappings1(BaseModel):
title_aux: Optional[str] = Field(None, description="The display name of the pack")
class ManagerMappings(
RootModel[Optional[Dict[str, List[Union[List[str], ManagerMapping]]]]]
RootModel[Optional[Dict[str, List[Union[List[str], ManagerMappings1]]]]]
):
root: Optional[Dict[str, List[Union[List[str], ManagerMapping]]]] = None
root: Optional[Dict[str, List[Union[List[str], ManagerMappings1]]]] = Field(
None, description="Tuple of [node_names, metadata]"
)
class ModelMetadata(BaseModel):
name: str = Field(..., description='Name of the model')
type: str = Field(..., description='Type of model')
base: Optional[str] = Field(None, description='Base model type')
save_path: Optional[str] = Field(None, description='Path for saving the model')
url: str = Field(..., description='Download URL')
filename: str = Field(..., description='Target filename')
ui_id: Optional[str] = Field(None, description='ID for UI reference')
name: str = Field(..., description="Name of the model")
type: str = Field(..., description="Type of model")
base: Optional[str] = Field(None, description="Base model type")
save_path: Optional[str] = Field(None, description="Path for saving the model")
url: str = Field(..., description="Download URL")
filename: str = Field(..., description="Target filename")
ui_id: Optional[str] = Field(None, description="ID for UI reference")
class InstallType(str, Enum):
git = 'git'
copy = 'copy'
pip = 'pip'
git = "git"
copy = "copy"
pip = "pip"
class NodePackageMetadata(BaseModel):
title: Optional[str] = Field(None, description='Display name of the node package')
name: Optional[str] = Field(None, description='Repository/package name')
files: Optional[List[str]] = Field(None, description='Source URLs for the package')
title: Optional[str] = Field(None, description="Display name of the node package")
name: Optional[str] = Field(None, description="Repository/package name")
files: Optional[List[str]] = Field(None, description="Source URLs for the package")
description: Optional[str] = Field(
None, description='Description of the node package functionality'
None, description="Description of the node package functionality"
)
install_type: Optional[InstallType] = Field(None, description='Installation method')
version: Optional[str] = Field(None, description='Version identifier')
install_type: Optional[InstallType] = Field(None, description="Installation method")
version: Optional[str] = Field(None, description="Version identifier")
id: Optional[str] = Field(
None, description='Unique identifier for the node package'
None, description="Unique identifier for the node package"
)
ui_id: Optional[str] = Field(None, description='ID for UI reference')
channel: Optional[str] = Field(None, description='Source channel')
mode: Optional[str] = Field(None, description='Source mode')
ui_id: Optional[str] = Field(None, description="ID for UI reference")
channel: Optional[str] = Field(None, description="Source channel")
mode: Optional[str] = Field(None, description="Source mode")
class SnapshotItem(RootModel[str]):
root: str = Field(..., description='Name of the snapshot')
root: str = Field(..., description="Name of the snapshot")
class Error(BaseModel):
error: str = Field(..., description='Error message')
error: str = Field(..., description="Error message")
class InstalledPacksResponse(RootModel[Optional[Dict[str, ManagerPackInstalled]]]):
@@ -226,180 +311,235 @@ class InstalledPacksResponse(RootModel[Optional[Dict[str, ManagerPackInstalled]]
class HistoryListResponse(BaseModel):
ids: Optional[List[str]] = Field(
None, description='List of available batch history IDs'
None, description="List of available batch history IDs"
)
class InstalledNodeInfo(BaseModel):
name: str = Field(..., description='Node package name')
version: str = Field(..., description='Installed version')
repository_url: Optional[str] = Field(None, description='Git repository URL')
name: str = Field(..., description="Node package name")
version: str = Field(..., description="Installed version")
repository_url: Optional[str] = Field(None, description="Git repository URL")
install_method: str = Field(
..., description='Installation method (cnr, git, pip, etc.)'
..., description="Installation method (cnr, git, pip, etc.)"
)
enabled: Optional[bool] = Field(
True, description='Whether the node is currently enabled'
True, description="Whether the node is currently enabled"
)
install_date: Optional[datetime] = Field(
None, description='ISO timestamp of installation'
None, description="ISO timestamp of installation"
)
class InstalledModelInfo(BaseModel):
name: str = Field(..., description='Model filename')
path: str = Field(..., description='Full path to model file')
type: str = Field(..., description='Model type (checkpoint, lora, vae, etc.)')
size_bytes: Optional[int] = Field(None, description='File size in bytes', ge=0)
hash: Optional[str] = Field(None, description='Model file hash for verification')
name: str = Field(..., description="Model filename")
path: str = Field(..., description="Full path to model file")
type: str = Field(..., description="Model type (checkpoint, lora, vae, etc.)")
size_bytes: Optional[int] = Field(None, description="File size in bytes", ge=0)
hash: Optional[str] = Field(None, description="Model file hash for verification")
install_date: Optional[datetime] = Field(
None, description='ISO timestamp when added'
None, description="ISO timestamp when added"
)
class ComfyUIVersionInfo(BaseModel):
version: str = Field(..., description='ComfyUI version string')
commit_hash: Optional[str] = Field(None, description='Git commit hash')
branch: Optional[str] = Field(None, description='Git branch name')
version: str = Field(..., description="ComfyUI version string")
commit_hash: Optional[str] = Field(None, description="Git commit hash")
branch: Optional[str] = Field(None, description="Git branch name")
is_stable: Optional[bool] = Field(
False, description='Whether this is a stable release'
False, description="Whether this is a stable release"
)
last_updated: Optional[datetime] = Field(
None, description='ISO timestamp of last update'
None, description="ISO timestamp of last update"
)
class OperationType(str, Enum):
install = 'install'
update = 'update'
uninstall = 'uninstall'
fix = 'fix'
disable = 'disable'
enable = 'enable'
install_model = 'install-model'
class Result(str, Enum):
success = 'success'
failed = 'failed'
skipped = 'skipped'
class BatchOperation(BaseModel):
operation_id: str = Field(..., description='Unique operation identifier')
operation_type: OperationType = Field(..., description='Type of operation')
operation_id: str = Field(..., description="Unique operation identifier")
operation_type: OperationType
target: str = Field(
..., description='Target of the operation (node name, model name, etc.)'
..., description="Target of the operation (node name, model name, etc.)"
)
target_version: Optional[str] = Field(
None, description='Target version for the operation'
None, description="Target version for the operation"
)
result: Result = Field(..., description='Operation result')
result: OperationResult
error_message: Optional[str] = Field(
None, description='Error message if operation failed'
None, description="Error message if operation failed"
)
start_time: datetime = Field(
..., description='ISO timestamp when operation started'
..., description="ISO timestamp when operation started"
)
end_time: Optional[datetime] = Field(
None, description='ISO timestamp when operation completed'
None, description="ISO timestamp when operation completed"
)
client_id: Optional[str] = Field(
None, description='Client that initiated the operation'
None, description="Client that initiated the operation"
)
class ComfyUISystemState(BaseModel):
snapshot_time: datetime = Field(
..., description='ISO timestamp when snapshot was taken'
..., description="ISO timestamp when snapshot was taken"
)
comfyui_version: ComfyUIVersionInfo
frontend_version: Optional[str] = Field(
None, description='ComfyUI frontend version if available'
None, description="ComfyUI frontend version if available"
)
python_version: str = Field(..., description='Python interpreter version')
python_version: str = Field(..., description="Python interpreter version")
platform_info: str = Field(
..., description='Operating system and platform information'
..., description="Operating system and platform information"
)
installed_nodes: Optional[Dict[str, InstalledNodeInfo]] = Field(
None, description='Map of installed node packages by name'
None, description="Map of installed node packages by name"
)
installed_models: Optional[Dict[str, InstalledModelInfo]] = Field(
None, description='Map of installed models by name'
None, description="Map of installed models by name"
)
manager_config: Optional[Dict[str, Any]] = Field(
None, description='ComfyUI Manager configuration settings'
None, description="ComfyUI Manager configuration settings"
)
comfyui_root_path: Optional[str] = Field(
None, description="ComfyUI root installation directory"
)
model_paths: Optional[Dict[str, List[str]]] = Field(
None, description="Map of model types to their configured paths"
)
manager_version: Optional[str] = Field(None, description="ComfyUI Manager version")
security_level: Optional[SecurityLevel] = None
network_mode: Optional[str] = Field(
None, description="Network mode (online, offline, private)"
)
cli_args: Optional[Dict[str, Any]] = Field(
None, description="Selected ComfyUI CLI arguments"
)
custom_nodes_count: Optional[int] = Field(
None, description="Total number of custom node packages", ge=0
)
failed_imports: Optional[List[str]] = Field(
None, description="List of custom nodes that failed to import"
)
pip_packages: Optional[Dict[str, str]] = Field(
None, description="Map of installed pip packages to their versions"
)
embedded_python: Optional[bool] = Field(
None,
description="Whether ComfyUI is running from an embedded Python distribution",
)
class BatchExecutionRecord(BaseModel):
batch_id: str = Field(..., description='Unique batch identifier')
start_time: datetime = Field(..., description='ISO timestamp when batch started')
batch_id: str = Field(..., description="Unique batch identifier")
start_time: datetime = Field(..., description="ISO timestamp when batch started")
end_time: Optional[datetime] = Field(
None, description='ISO timestamp when batch completed'
None, description="ISO timestamp when batch completed"
)
state_before: ComfyUISystemState
state_after: Optional[ComfyUISystemState] = Field(
None, description='System state after batch execution'
None, description="System state after batch execution"
)
operations: Optional[List[BatchOperation]] = Field(
None, description='List of operations performed in this batch'
None, description="List of operations performed in this batch"
)
total_operations: Optional[int] = Field(
0, description='Total number of operations in batch', ge=0
0, description="Total number of operations in batch", ge=0
)
successful_operations: Optional[int] = Field(
0, description='Number of successful operations', ge=0
0, description="Number of successful operations", ge=0
)
failed_operations: Optional[int] = Field(
0, description='Number of failed operations', ge=0
0, description="Number of failed operations", ge=0
)
skipped_operations: Optional[int] = Field(
0, description='Number of skipped operations', ge=0
0, description="Number of skipped operations", ge=0
)
class ImportFailInfoBulkRequest(BaseModel):
cnr_ids: Optional[List[str]] = Field(
None, description="A list of CNR IDs to check."
)
urls: Optional[List[str]] = Field(
None, description="A list of repository URLs to check."
)
class ImportFailInfoItem1(BaseModel):
error: Optional[str] = None
traceback: Optional[str] = None
class ImportFailInfoItem(RootModel[Optional[ImportFailInfoItem1]]):
root: Optional[ImportFailInfoItem1]
class QueueTaskItem(BaseModel):
ui_id: str = Field(..., description="Unique identifier for the task")
client_id: str = Field(..., description="Client identifier that initiated the task")
kind: OperationType
params: Union[
InstallPackParams,
UpdatePackParams,
UpdateAllPacksParams,
UpdateComfyUIParams,
FixPackParams,
UninstallPackParams,
DisablePackParams,
EnablePackParams,
ModelMetadata,
]
class TaskHistoryItem(BaseModel):
ui_id: str = Field(..., description='Unique identifier for the task')
client_id: str = Field(..., description='Client identifier that initiated the task')
kind: str = Field(..., description='Type of task that was performed')
timestamp: datetime = Field(..., description='ISO timestamp when task completed')
result: str = Field(..., description='Task result message or details')
ui_id: str = Field(..., description="Unique identifier for the task")
client_id: str = Field(..., description="Client identifier that initiated the task")
kind: str = Field(..., description="Type of task that was performed")
timestamp: datetime = Field(..., description="ISO timestamp when task completed")
result: str = Field(..., description="Task result message or details")
status: Optional[TaskExecutionStatus] = None
batch_id: Optional[str] = Field(
None, description="ID of the batch this task belongs to"
)
end_time: Optional[datetime] = Field(
None, description="ISO timestamp when task execution ended"
)
class TaskStateMessage(BaseModel):
history: Dict[str, TaskHistoryItem] = Field(
..., description='Map of task IDs to their history items'
..., description="Map of task IDs to their history items"
)
running_queue: List[QueueTaskItem] = Field(
..., description='Currently executing tasks'
..., description="Currently executing tasks"
)
pending_queue: List[QueueTaskItem] = Field(
..., description='Tasks waiting to be executed'
..., description="Tasks waiting to be executed"
)
installed_packs: Dict[str, ManagerPackInstalled] = Field(
..., description="Map of currently installed node packages by name"
)
class MessageTaskDone(BaseModel):
ui_id: str = Field(..., description='Task identifier')
result: str = Field(..., description='Task result message')
kind: str = Field(..., description='Type of task')
ui_id: str = Field(..., description="Task identifier")
result: str = Field(..., description="Task result message")
kind: str = Field(..., description="Type of task")
status: Optional[TaskExecutionStatus] = None
timestamp: datetime = Field(..., description='ISO timestamp when task completed')
timestamp: datetime = Field(..., description="ISO timestamp when task completed")
state: TaskStateMessage
class MessageTaskStarted(BaseModel):
ui_id: str = Field(..., description='Task identifier')
kind: str = Field(..., description='Type of task')
timestamp: datetime = Field(..., description='ISO timestamp when task started')
ui_id: str = Field(..., description="Task identifier")
kind: str = Field(..., description="Type of task")
timestamp: datetime = Field(..., description="ISO timestamp when task started")
state: TaskStateMessage
class MessageTaskFailed(BaseModel):
ui_id: str = Field(..., description='Task identifier')
error: str = Field(..., description='Error message')
kind: str = Field(..., description='Type of task')
timestamp: datetime = Field(..., description='ISO timestamp when task failed')
ui_id: str = Field(..., description="Task identifier")
error: str = Field(..., description="Error message")
kind: str = Field(..., description="Type of task")
timestamp: datetime = Field(..., description="ISO timestamp when task failed")
state: TaskStateMessage
@@ -407,11 +547,15 @@ class MessageUpdate(
RootModel[Union[MessageTaskDone, MessageTaskStarted, MessageTaskFailed]]
):
root: Union[MessageTaskDone, MessageTaskStarted, MessageTaskFailed] = Field(
..., description='Union type for all possible WebSocket message updates'
..., description="Union type for all possible WebSocket message updates"
)
class HistoryResponse(BaseModel):
history: Optional[Dict[str, TaskHistoryItem]] = Field(
None, description='Map of task IDs to their history items'
None, description="Map of task IDs to their history items"
)
class ImportFailInfoBulkResponse(RootModel[Optional[Dict[str, ImportFailInfoItem]]]):
root: Optional[Dict[str, ImportFailInfoItem]] = None

View File

File diff suppressed because it is too large Load Diff

View File

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
- Anytime you make a change to the data being sent or received, you should follow this process:
1. Adjust the openapi.yaml file first
2. Verify the syntax of the openapi.yaml file using `yaml.safe_load`
3. Regenerate the types following the instructions in the `data_models/README.md` file
4. Verify the new data model is generated
5. Verify the syntax of the generated types files
6. Run formatting and linting on the generated types files
7. Adjust the `__init__.py` files in the `data_models` directory to match/export the new data model
8. Only then, make the changes to the rest of the codebase
9. Run the CI tests to verify that the changes are working
- The comfyui_manager is a python package that is used to manage the comfyui server. There are two sub-packages `glob` and `legacy`. These represent the current version (`glob`) and the previous version (`legacy`), not including common utilities and data models. When developing, we work in the `glob` package. You can ignore the `legacy` package entirely, unless you have a very good reason to research how things were done in the legacy or prior major versions of the package. But in those cases, you should just look for the sake of knowledge or reflection, not for changing code (unless explicitly asked to do so).

View File

@@ -1,6 +1,6 @@
from comfy.cli_args import args
SECURITY_MESSAGE_MIDDLE_OR_BELOW = "ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_MIDDLE = "ERROR: To use this action, a security_level of `normal or below` is required. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_MIDDLE_P = "ERROR: To use this action, security_level must be `normal or below`, and network_mode must be set to `personal_cloud`. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_NORMAL_MINUS = "ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_GENERAL = "ERROR: This installation is not allowed in this security_level. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_NORMAL_MINUS_MODEL = "ERROR: Downloading models that are not in '.safetensors' format is only allowed for models registered in the 'default' channel at this security level. If you want to download this model, set the security level to 'normal-' or lower."
@@ -15,9 +15,6 @@ def is_loopback(address):
return False
is_local_mode = is_loopback(args.listen)
model_dir_name_map = {
"checkpoints": "checkpoints",
"checkpoint": "checkpoints",
@@ -37,3 +34,22 @@ model_dir_name_map = {
"unet": "diffusion_models",
"diffusion_model": "diffusion_models",
}
# List of all model directory names used for checking installed models
MODEL_DIR_NAMES = [
"checkpoints",
"loras",
"vae",
"text_encoders",
"diffusion_models",
"clip_vision",
"embeddings",
"diffusers",
"vae_approx",
"controlnet",
"gligen",
"upscale_models",
"hypernetworks",
"photomaker",
"classifiers",
]

View File

@@ -41,11 +41,12 @@ from ..common.enums import NetworkMode, SecurityLevel, DBMode
from ..common import context
version_code = [4, 0]
version_code = [4, 0, 1]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
DEFAULT_CHANNEL = "https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main"
DEFAULT_CHANNEL_LEGACY = "https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main"
default_custom_nodes_path = None
@@ -150,93 +151,11 @@ def check_invalid_nodes():
print("\n---------------------------------------------------------------------------\n")
# read env vars
comfy_path: str = os.environ.get('COMFYUI_PATH')
comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH')
if comfy_path is None:
try:
comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__))
os.environ['COMFYUI_PATH'] = comfy_path
except:
logging.error("[ComfyUI-Manager] environment variable 'COMFYUI_PATH' is not specified.")
exit(-1)
if comfy_base_path is None:
comfy_base_path = comfy_path
channel_list_template_path = os.path.join(manager_util.comfyui_manager_path, 'channels.list.template')
git_script_path = os.path.join(manager_util.comfyui_manager_path, "git_helper.py")
manager_files_path = None
manager_config_path = None
manager_channel_list_path = None
manager_startup_script_path:str = None
manager_snapshot_path = None
manager_pip_overrides_path = None
manager_pip_blacklist_path = None
manager_components_path = None
manager_batch_history_path = None
def update_user_directory(user_dir):
global manager_files_path
global manager_config_path
global manager_channel_list_path
global manager_startup_script_path
global manager_snapshot_path
global manager_pip_overrides_path
global manager_pip_blacklist_path
global manager_components_path
global manager_batch_history_path
manager_files_path = os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
if not os.path.exists(manager_files_path):
os.makedirs(manager_files_path)
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
if not os.path.exists(manager_snapshot_path):
os.makedirs(manager_snapshot_path)
manager_startup_script_path = os.path.join(manager_files_path, "startup-scripts")
if not os.path.exists(manager_startup_script_path):
os.makedirs(manager_startup_script_path)
manager_config_path = os.path.join(manager_files_path, 'config.ini')
manager_channel_list_path = os.path.join(manager_files_path, 'channels.list')
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_components_path = os.path.join(manager_files_path, "components")
manager_util.cache_dir = os.path.join(manager_files_path, "cache")
manager_batch_history_path = os.path.join(manager_files_path, "batch_history")
if not os.path.exists(manager_util.cache_dir):
os.makedirs(manager_util.cache_dir)
if not os.path.exists(manager_batch_history_path):
os.makedirs(manager_batch_history_path)
try:
import folder_paths
update_user_directory(folder_paths.get_user_directory())
except Exception:
# fallback:
# This case is only possible when running with cm-cli, and in practice, this case is not actually used.
update_user_directory(os.path.abspath(manager_util.comfyui_manager_path))
cached_config = None
js_path = None
comfy_ui_required_revision = 1930
comfy_ui_required_commit_datetime = datetime(2024, 1, 24, 0, 0, 0)
comfy_ui_revision = "Unknown"
comfy_ui_commit_datetime = datetime(1900, 1, 1, 0, 0, 0)
channel_dict = None
valid_channels = {'default', 'local'}
valid_channels = {'default', 'local', DEFAULT_CHANNEL, DEFAULT_CHANNEL_LEGACY}
channel_list = None
@@ -380,18 +299,86 @@ class ManagedResult:
return self
class NormalizedKeyDict:
def __init__(self):
self._store = {}
self._key_map = {}
def _normalize_key(self, key):
if isinstance(key, str):
return key.strip().lower()
return key
def __setitem__(self, key, value):
norm_key = self._normalize_key(key)
self._key_map[norm_key] = key
self._store[key] = value
def __getitem__(self, key):
norm_key = self._normalize_key(key)
original_key = self._key_map[norm_key]
return self._store[original_key]
def __delitem__(self, key):
norm_key = self._normalize_key(key)
original_key = self._key_map.pop(norm_key)
del self._store[original_key]
def __contains__(self, key):
return self._normalize_key(key) in self._key_map
def get(self, key, default=None):
return self[key] if key in self else default
def setdefault(self, key, default=None):
if key in self:
return self[key]
self[key] = default
return default
def pop(self, key, default=None):
if key in self:
val = self[key]
del self[key]
return val
if default is not None:
return default
raise KeyError(key)
def keys(self):
return self._store.keys()
def values(self):
return self._store.values()
def items(self):
return self._store.items()
def __iter__(self):
return iter(self._store)
def __len__(self):
return len(self._store)
def __repr__(self):
return repr(self._store)
def to_dict(self):
return dict(self._store)
class UnifiedManager:
def __init__(self):
self.installed_node_packages: dict[str, InstalledNodePackage] = {}
self.cnr_inactive_nodes = {} # node_id -> node_version -> fullpath
self.nightly_inactive_nodes = {} # node_id -> fullpath
self.unknown_inactive_nodes = {} # node_id -> repo url * fullpath
self.active_nodes = {} # node_id -> node_version * fullpath
self.unknown_active_nodes = {} # node_id -> repo url * fullpath
self.cnr_map = {} # node_id -> cnr info
self.repo_cnr_map = {} # repo_url -> cnr info
self.custom_node_map_cache = {} # (channel, mode) -> augmented custom node list json
self.cnr_inactive_nodes = NormalizedKeyDict() # node_id -> node_version -> fullpath
self.nightly_inactive_nodes = NormalizedKeyDict() # node_id -> fullpath
self.unknown_inactive_nodes = {} # node_id -> repo url * fullpath
self.active_nodes = NormalizedKeyDict() # node_id -> node_version * fullpath
self.unknown_active_nodes = {} # node_id -> repo url * fullpath
self.cnr_map = NormalizedKeyDict() # node_id -> cnr info
self.repo_cnr_map = {} # repo_url -> cnr info
self.custom_node_map_cache = {} # (channel, mode) -> augmented custom node list json
self.processed_install = set()
def get_module_name(self, x):
@@ -797,7 +784,7 @@ class UnifiedManager:
channel = normalize_channel(channel)
nodes = await self.load_nightly(channel, mode)
res = {}
res = NormalizedKeyDict()
added_cnr = set()
for v in nodes.values():
v = v[0]
@@ -1487,7 +1474,7 @@ def identify_node_pack_from_path(fullpath):
# cnr
cnr = cnr_utils.read_cnr_info(fullpath)
if cnr is not None:
return module_name, cnr['version'], cnr['id'], None
return module_name, cnr['version'], cnr['original_name'], None
return None
else:
@@ -1537,7 +1524,10 @@ def get_installed_node_packs():
if info is None:
continue
res[info[0]] = { 'ver': info[1], 'cnr_id': info[2], 'aux_id': info[3], 'enabled': False }
# NOTE: don't add disabled nodepack if there is enabled nodepack
original_name = info[0].split('@')[0]
if original_name not in res:
res[info[0]] = { 'ver': info[1], 'cnr_id': info[2], 'aux_id': info[3], 'enabled': False }
return res
@@ -1634,16 +1624,18 @@ def read_config():
config = configparser.ConfigParser(strict=False)
config.read(context.manager_config_path)
default_conf = config['default']
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
def get_bool(key, default_value):
return default_conf[key].lower() == 'true' if key 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)
return {
'http_channel_enabled': get_bool('http_channel_enabled', False),
'preview_method': default_conf.get('preview_method', manager_funcs.get_current_preview_method()).lower(),
'git_exe': default_conf.get('git_exe', ''),
'use_uv': get_bool('use_uv', False),
'use_uv': get_bool('use_uv', True),
'channel_url': default_conf.get('channel_url', DEFAULT_CHANNEL),
'default_cache_as_channel_url': get_bool('default_cache_as_channel_url', False),
'share_option': default_conf.get('share_option', 'all').lower(),
@@ -1661,16 +1653,20 @@ def read_config():
}
except Exception:
manager_util.use_uv = False
import importlib.util
# temporary disable `uv` on Windows by default (https://github.com/Comfy-Org/ComfyUI-Manager/issues/1969)
manager_util.use_uv = importlib.util.find_spec("uv") is not None and platform.system() != "Windows"
manager_util.bypass_ssl = False
return {
'http_channel_enabled': False,
'preview_method': manager_funcs.get_current_preview_method(),
'git_exe': '',
'use_uv': False,
'use_uv': manager_util.use_uv,
'channel_url': DEFAULT_CHANNEL,
'default_cache_as_channel_url': False,
'share_option': 'all',
'bypass_ssl': False,
'bypass_ssl': manager_util.bypass_ssl,
'file_logging': True,
'component_policy': 'workflow',
'update_policy': 'stable-comfyui',
@@ -1788,16 +1784,6 @@ def try_install_script(url, repo_path, install_cmd, instant_execution=False):
print(f"\n## ComfyUI-Manager: EXECUTE => {install_cmd}")
code = manager_funcs.run_script(install_cmd, cwd=repo_path)
if platform.system() != "Windows":
try:
if not os.environ.get('__COMFYUI_DESKTOP_VERSION__') and comfy_ui_commit_datetime.date() < comfy_ui_required_commit_datetime.date():
print("\n\n###################################################################")
print(f"[WARN] ComfyUI-Manager: Your ComfyUI version ({comfy_ui_revision})[{comfy_ui_commit_datetime.date()}] is too old. Please update to the latest version.")
print("[WARN] The extension installation feature may not work properly in the current installed ComfyUI version on Windows environment.")
print("###################################################################\n\n")
except Exception:
pass
if code != 0:
if url is None:
url = os.path.dirname(repo_path)
@@ -2435,14 +2421,17 @@ def update_to_stable_comfyui(repo_path):
versions, current_tag, _ = get_comfyui_versions(repo)
if len(versions) == 0 or (len(versions) == 1 and versions[0] == 'nightly'):
def pick_latest_semver(tags):
for tag in tags:
if re.match(r'^v\d+\.\d+\.\d+$', tag):
return tag
return None
latest_tag = pick_latest_semver(versions)
if latest_tag is None:
logging.info("[ComfyUI-Manager] Unable to update to the stable ComfyUI version.")
return "fail", None
if versions[0] == 'nightly':
latest_tag = versions[1]
else:
latest_tag = versions[0]
if current_tag == latest_tag:
return "skip", None
@@ -2867,7 +2856,7 @@ async def get_unified_total_nodes(channel, mode, regsitry_cache_mode='cache'):
if cnr_id is not None:
# cnr or nightly version
cnr_ids.remove(cnr_id)
cnr_ids.discard(cnr_id)
updatable = False
cnr = unified_manager.cnr_map[cnr_id]
@@ -3031,6 +3020,11 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
info = yaml.load(snapshot_file, Loader=yaml.SafeLoader)
info = info['custom_nodes']
if 'pips' in info and info['pips']:
pips = info['pips']
else:
pips = {}
# for cnr restore
cnr_info = info.get('cnr_custom_nodes')
if cnr_info is not None:
@@ -3237,6 +3231,8 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
unified_manager.repo_install(repo_url, to_path, instant_execution=True, no_deps=False, return_postinstall=False)
cloned_repos.append(repo_name)
manager_util.restore_pip_snapshot(pips, git_helper_extras)
# print summary
for x in cloned_repos:
print(f"[ INSTALLED ] {x}")
@@ -3260,35 +3256,65 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
def get_comfyui_versions(repo=None):
if repo is None:
repo = git.Repo(context.comfy_path)
repo = repo or git.Repo(context.comfy_path)
try:
remote = get_remote_name(repo)
repo.remotes[remote].fetch()
remote = get_remote_name(repo)
repo.remotes[remote].fetch()
except Exception:
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
versions = sorted(versions, key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
versions = versions[:4]
def normalize_describe(tag_name):
if not tag_name:
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]
semver_tag_set = set(semver_tags)
if current_tag not in versions:
versions = sorted(versions + [current_tag], key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
versions = versions[:4]
try:
raw_current_tag = repo.git.describe('--tags')
except Exception:
raw_current_tag = ''
main_branch = repo.heads.master
latest_commit = main_branch.commit
latest_tag = repo.git.describe('--tags', latest_commit.hexsha)
normalized_current = normalize_describe(raw_current_tag)
has_normalized_tag = normalized_current in semver_tag_set
current_tag = normalized_current if has_normalized_tag else raw_current_tag
if latest_tag != versions[0]:
versions.insert(0, 'nightly')
else:
versions[0] = 'nightly'
if has_normalized_tag and normalized_current not in semver_tags:
semver_tags.append(normalized_current)
semver_tags.sort(key=lambda t: parse_semver(t) or (0, 0, 0), reverse=True)
semver_tags = semver_tags[:4]
non_semver_current = None
if current_tag and not has_normalized_tag and current_tag not in semver_tags:
non_semver_current = current_tag
try:
latest_tag = repo.git.describe('--tags', repo.heads.master.commit.hexsha)
except Exception:
latest_tag = None
versions = ['nightly']
if non_semver_current:
versions.append(non_semver_current)
versions.extend(semver_tags)
versions = versions[:5]
if not current_tag:
current_tag = 'nightly'
return versions, current_tag, latest_tag

View File

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,15 @@ import hashlib
import folder_paths
from server import PromptServer
import logging
import sys
try:
from nio import AsyncClient, LoginResponse, UploadResponse
matrix_nio_is_available = True
except Exception:
logging.warning(f"[ComfyUI-Manager] The matrix sharing feature has been disabled because the `matrix-nio` dependency is not installed.\n\tTo use this feature, please run the following command:\n\t{sys.executable} -m pip install matrix-nio\n")
matrix_nio_is_available = False
def extract_model_file_names(json_data):
@@ -193,6 +202,14 @@ async def get_esheep_workflow_and_images(request):
return web.Response(status=200, text=json.dumps(data))
@PromptServer.instance.routes.get("/v2/manager/get_matrix_dep_status")
async def get_matrix_dep_status(request):
if matrix_nio_is_available:
return web.Response(status=200, text='available')
else:
return web.Response(status=200, text='unavailable')
def set_matrix_auth(json_data):
homeserver = json_data['homeserver']
username = json_data['username']
@@ -332,15 +349,12 @@ async def share_art(request):
workflowId = upload_workflow_json["workflowId"]
# check if the user has provided Matrix credentials
if "matrix" in share_destinations:
if matrix_nio_is_available and "matrix" in share_destinations:
comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org'
filename = os.path.basename(asset_filepath)
content_type = assetFileType
try:
from matrix_client.api import MatrixHttpApi
from matrix_client.client import MatrixClient
homeserver = 'matrix.org'
if matrix_auth:
homeserver = matrix_auth.get('homeserver', 'matrix.org')
@@ -348,20 +362,35 @@ async def share_art(request):
if not homeserver.startswith("https://"):
homeserver = "https://" + homeserver
client = MatrixClient(homeserver)
try:
token = client.login(username=matrix_auth['username'], password=matrix_auth['password'])
if not token:
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
except Exception:
client = AsyncClient(homeserver, matrix_auth['username'])
# Login
login_resp = await client.login(matrix_auth['password'])
if not isinstance(login_resp, LoginResponse) or not login_resp.access_token:
await client.close()
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
matrix = MatrixHttpApi(homeserver, token=token)
# Upload asset
with open(asset_filepath, 'rb') as f:
mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri']
upload_resp, _maybe_keys = await client.upload(f, content_type=content_type, filename=filename)
asset_data = f.seek(0) or f.read() # get size for info below
if not isinstance(upload_resp, UploadResponse) or not upload_resp.content_uri:
await client.close()
return web.json_response({"error": "Failed to upload asset to Matrix."}, content_type='application/json', status=500)
mxc_url = upload_resp.content_uri
workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri']
# Upload workflow JSON
import io
workflow_json_bytes = json.dumps(prompt['workflow']).encode('utf-8')
workflow_io = io.BytesIO(workflow_json_bytes)
upload_workflow_resp, _maybe_keys = await client.upload(workflow_io, content_type='application/json', filename='workflow.json')
workflow_io.seek(0)
if not isinstance(upload_workflow_resp, UploadResponse) or not upload_workflow_resp.content_uri:
await client.close()
return web.json_response({"error": "Failed to upload workflow to Matrix."}, content_type='application/json', status=500)
workflow_json_mxc_url = upload_workflow_resp.content_uri
# Send text message
text_content = ""
if title:
text_content += f"{title}\n"
@@ -369,11 +398,47 @@ async def share_art(request):
text_content += f"{description}\n"
if credits:
text_content += f"\ncredits: {credits}\n"
matrix.send_message(comfyui_share_room_id, text_content)
matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image')
matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file')
except Exception:
logging.exception("An error occurred")
await client.room_send(
room_id=comfyui_share_room_id,
message_type="m.room.message",
content={"msgtype": "m.text", "body": text_content}
)
# Send image
await client.room_send(
room_id=comfyui_share_room_id,
message_type="m.room.message",
content={
"msgtype": "m.image",
"body": filename,
"url": mxc_url,
"info": {
"mimetype": content_type,
"size": len(asset_data)
}
}
)
# Send workflow JSON file
await client.room_send(
room_id=comfyui_share_room_id,
message_type="m.room.message",
content={
"msgtype": "m.file",
"body": "workflow.json",
"url": workflow_json_mxc_url,
"info": {
"mimetype": "application/json",
"size": len(workflow_json_bytes)
}
}
)
await client.close()
except:
import traceback
traceback.print_exc()
return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500)
return web.json_response({

View File

@@ -3,7 +3,7 @@ import git
import logging
import traceback
from comfyui_manager.common import context, manager_util
from comfyui_manager.common import context
import folder_paths
from comfy.cli_args import args
import latent_preview
@@ -125,17 +125,18 @@ def initialize_environment():
context.comfy_path = os.path.dirname(folder_paths.__file__)
core.js_path = os.path.join(context.comfy_path, "web", "extensions")
local_db_model = os.path.join(manager_util.comfyui_manager_path, "model-list.json")
local_db_alter = os.path.join(manager_util.comfyui_manager_path, "alter-list.json")
local_db_custom_node_list = os.path.join(
manager_util.comfyui_manager_path, "custom-node-list.json"
)
local_db_extension_node_mappings = os.path.join(
manager_util.comfyui_manager_path, "extension-node-map.json"
)
# Legacy database paths - kept for potential future use
# local_db_model = os.path.join(manager_util.comfyui_manager_path, "model-list.json")
# local_db_alter = os.path.join(manager_util.comfyui_manager_path, "alter-list.json")
# local_db_custom_node_list = os.path.join(
# manager_util.comfyui_manager_path, "custom-node-list.json"
# )
# local_db_extension_node_mappings = os.path.join(
# manager_util.comfyui_manager_path, "extension-node-map.json"
# )
set_preview_method(core.get_config()["preview_method"])
environment_utils.print_comfyui_version()
print_comfyui_version()
setup_environment()
core.check_invalid_nodes()

View File

@@ -1,5 +1,6 @@
import locale
import sys
import re
def handle_stream(stream, prefix):
@@ -19,3 +20,41 @@ def handle_stream(stream, prefix):
print(prefix, msg, end="", file=sys.stderr)
else:
print(prefix, msg, end="")
def convert_markdown_to_html(input_text):
pattern_a = re.compile(r"\[a/([^]]+)]\(([^)]+)\)")
pattern_w = re.compile(r"\[w/([^]]+)]")
pattern_i = re.compile(r"\[i/([^]]+)]")
pattern_bold = re.compile(r"\*\*([^*]+)\*\*")
pattern_white = re.compile(r"%%([^*]+)%%")
def replace_a(match):
return f"<a href='{match.group(2)}' target='blank'>{match.group(1)}</a>"
def replace_w(match):
return f"<p class='cm-warn-note'>{match.group(1)}</p>"
def replace_i(match):
return f"<p class='cm-info-note'>{match.group(1)}</p>"
def replace_bold(match):
return f"<B>{match.group(1)}</B>"
def replace_white(match):
return f"<font color='white'>{match.group(1)}</font>"
input_text = (
input_text.replace("\\[", "&#91;")
.replace("\\]", "&#93;")
.replace("<", "&lt;")
.replace(">", "&gt;")
)
result_text = re.sub(pattern_a, replace_a, input_text)
result_text = re.sub(pattern_w, replace_w, result_text)
result_text = re.sub(pattern_i, replace_i, result_text)
result_text = re.sub(pattern_bold, replace_bold, result_text)
result_text = re.sub(pattern_white, replace_white, result_text)
return result_text.replace("\n", "<BR>")

View File

@@ -1,8 +1,10 @@
import os
import logging
import concurrent.futures
import folder_paths
from comfyui_manager.glob import manager_core as core
from comfyui_manager.glob.constants import model_dir_name_map, MODEL_DIR_NAMES
def get_model_dir(data, show_log=False):
@@ -71,3 +73,89 @@ def get_model_path(data, show_log=False):
return os.path.join(base_model, os.path.basename(data["url"]))
else:
return os.path.join(base_model, data["filename"])
def check_model_installed(json_obj):
def is_exists(model_dir_name, filename, url):
if filename == "<huggingface>":
filename = os.path.basename(url)
dirs = folder_paths.get_folder_paths(model_dir_name)
for x in dirs:
if os.path.exists(os.path.join(x, filename)):
return True
return False
total_models_files = set()
for x in MODEL_DIR_NAMES:
for y in folder_paths.get_filename_list(x):
total_models_files.add(y)
def process_model_phase(item):
if (
"diffusion" not in item["filename"]
and "pytorch" not in item["filename"]
and "model" not in item["filename"]
):
# non-general name case
if item["filename"] in total_models_files:
item["installed"] = "True"
return
if item["save_path"] == "default":
model_dir_name = model_dir_name_map.get(item["type"].lower())
if model_dir_name is not None:
item["installed"] = str(
is_exists(model_dir_name, item["filename"], item["url"])
)
else:
item["installed"] = "False"
else:
model_dir_name = item["save_path"].split("/")[0]
if model_dir_name in folder_paths.folder_names_and_paths:
if is_exists(model_dir_name, item["filename"], item["url"]):
item["installed"] = "True"
if "installed" not in item:
if item["filename"] == "<huggingface>":
filename = os.path.basename(item["url"])
else:
filename = item["filename"]
fullpath = os.path.join(
folder_paths.models_dir, item["save_path"], filename
)
item["installed"] = "True" if os.path.exists(fullpath) else "False"
with concurrent.futures.ThreadPoolExecutor(8) as executor:
for item in json_obj["models"]:
executor.submit(process_model_phase, item)
async def check_whitelist_for_model(item):
from comfyui_manager.data_models import ManagerDatabaseSource
json_obj = await core.get_data_by_mode(ManagerDatabaseSource.cache.value, "model-list.json")
for x in json_obj.get("models", []):
if (
x["save_path"] == item["save_path"]
and x["base"] == item["base"]
and x["filename"] == item["filename"]
):
return True
json_obj = await core.get_data_by_mode(ManagerDatabaseSource.local.value, "model-list.json")
for x in json_obj.get("models", []):
if (
x["save_path"] == item["save_path"]
and x["base"] == item["base"]
and x["filename"] == item["filename"]
):
return True
return False

View File

@@ -1,24 +1,49 @@
from comfyui_manager.glob import manager_core as core
from comfy.cli_args import args
from comfyui_manager.data_models import SecurityLevel, RiskLevel, ManagerDatabaseSource
def is_loopback(address):
import ipaddress
try:
return ipaddress.ip_address(address).is_loopback
except ValueError:
return False
def is_allowed_security_level(level):
if level == "block":
is_local_mode = is_loopback(args.listen)
is_personal_cloud = core.get_config()['network_mode'].lower() == 'personal_cloud'
if level == RiskLevel.block.value:
return False
elif level == "high":
elif level == RiskLevel.high_.value:
if is_local_mode:
return core.get_config()["security_level"] in ["weak", "normal-"]
return core.get_config()['security_level'] in [SecurityLevel.weak.value, SecurityLevel.normal_.value]
elif is_personal_cloud:
return core.get_config()['security_level'] == SecurityLevel.weak.value
else:
return core.get_config()["security_level"] == "weak"
elif level == "middle":
return core.get_config()["security_level"] in ["weak", "normal", "normal-"]
return False
elif level == RiskLevel.high.value:
if is_local_mode:
return core.get_config()['security_level'] in [SecurityLevel.weak.value, SecurityLevel.normal_.value]
else:
return core.get_config()['security_level'] == SecurityLevel.weak.value
elif level == RiskLevel.middle_.value:
if is_local_mode or is_personal_cloud:
return core.get_config()['security_level'] in [SecurityLevel.weak.value, SecurityLevel.normal.value, SecurityLevel.normal_.value]
else:
return False
elif level == RiskLevel.middle.value:
return core.get_config()['security_level'] in [SecurityLevel.weak.value, SecurityLevel.normal.value, SecurityLevel.normal_.value]
else:
return True
async def get_risky_level(files, pip_packages):
json_data1 = await core.get_data_by_mode("local", "custom-node-list.json")
json_data1 = await core.get_data_by_mode(ManagerDatabaseSource.local.value, "custom-node-list.json")
json_data2 = await core.get_data_by_mode(
"cache",
ManagerDatabaseSource.cache.value,
"custom-node-list.json",
channel_url="https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main",
)
@@ -29,7 +54,7 @@ async def get_risky_level(files, pip_packages):
for x in files:
if x not in all_urls:
return "high"
return RiskLevel.high_.value
all_pip_packages = set()
for x in json_data1["custom_nodes"] + json_data2["custom_nodes"]:
@@ -37,6 +62,6 @@ async def get_risky_level(files, pip_packages):
for p in pip_packages:
if p not in all_pip_packages:
return "block"
return RiskLevel.block.value
return "middle"
return RiskLevel.middle_.value

View File

@@ -222,9 +222,6 @@ function isBeforeFrontendVersion(compareVersion) {
}
}
const is_legacy_front = () => isBeforeFrontendVersion('1.2.49');
const isNewManagerUI = () => isBeforeFrontendVersion('1.16.4');
document.head.appendChild(docStyle);
var update_comfyui_button = null;
@@ -478,9 +475,9 @@ async function updateComfyUI() {
// set_inprogress_mode();
showTerminal();
batch_id = generateUUID();
let batch = {};
batch['batch_id'] = batch_id;
batch['update_comfyui'] = true;
@@ -667,13 +664,13 @@ async function onQueueStatus(event) {
update_all_button.innerText = `in progress.. (${event.detail.done_count}/${event.detail.total_count})`;
}
else if(event.detail.status == 'all-done') {
// reset_action_buttons();
reset_action_buttons();
}
else if(event.detail.status == 'batch-done') {
if(batch_id != event.detail.batch_id) {
return;
}
let success_list = [];
let failed_list = [];
let comfyui_state = null;
@@ -780,7 +777,7 @@ async function updateAll(update_comfyui) {
showTerminal();
batch_id = generateUUID();
let batch = {};
if(update_comfyui) {
update_all_button.innerText = "Updating ComfyUI...";
@@ -1517,11 +1514,6 @@ app.registerExtension({
tooltip: "Share"
}).element
);
const shouldShowLegacyMenuItems = !isNewManagerUI();
if (shouldShowLegacyMenuItems) {
app.menu?.settingsGroup.element.before(cmGroup.element);
}
}
catch(exception) {
console.log('ComfyUI is outdated. New style menu based features are disabled.');

View File

@@ -552,6 +552,20 @@ export class ShareDialog extends ComfyDialog {
this.matrix_destination_checkbox.style.color = "var(--fg-color)";
this.matrix_destination_checkbox.checked = this.share_option === 'matrix'; //true;
try {
api.fetchApi(`/v2/manager/get_matrix_dep_status`)
.then(response => response.text())
.then(data => {
if(data == 'unavailable') {
matrix_destination_checkbox_text.style.textDecoration = "line-through";
this.matrix_destination_checkbox.disabled = true;
this.matrix_destination_checkbox.title = "It has been disabled because the 'matrix-nio' dependency is not installed. Please install this dependency to use the matrix sharing feature.";
matrix_destination_checkbox_text.title = "It has been disabled because the 'matrix-nio' dependency is not installed. Please install this dependency to use the matrix sharing feature.";
}
})
.catch(error => {});
} catch (error) {}
this.comfyworkflows_destination_checkbox = $el("input", { type: 'checkbox', id: "comfyworkflows_destination" }, [])
const comfyworkflows_destination_checkbox_text = $el("label", {}, [" ComfyWorkflows.com"])
this.comfyworkflows_destination_checkbox.style.color = "var(--fg-color)";

View File

@@ -71,7 +71,7 @@ export class CopusShareDialog extends ComfyDialog {
this.allFiles = [];
this.titleNum = 0;
}
createButtons() {
const inputStyle = {
display: "block",
@@ -201,13 +201,15 @@ export class CopusShareDialog extends ComfyDialog {
});
this.LockInput = $el("input", {
type: "text",
placeholder: "",
style: {
placeholder: "0",
style: {
width: "100px",
padding: "7px",
paddingLeft: "30px",
borderRadius: "4px",
border: "1px solid #ddd",
boxSizing: "border-box",
position: "relative",
},
oninput: (event) => {
let input = event.target.value;
@@ -301,7 +303,7 @@ export class CopusShareDialog extends ComfyDialog {
},
[]
);
const titleNumDom = $el(
"label",
{
@@ -342,15 +344,11 @@ export class CopusShareDialog extends ComfyDialog {
["0/70"]
);
// Additional Inputs Section
const additionalInputsSection = $el(
"div",
{ style: { ...sectionStyle, } },
[
$el("label", { style: labelStyle }, ["3⃣ Title "]),
this.TitleInput,
titleNumDom,
]
);
const additionalInputsSection = $el("div", { style: { ...sectionStyle } }, [
$el("label", { style: labelStyle }, ["3⃣ Title "]),
this.TitleInput,
titleNumDom,
]);
const SubtitleSection = $el("div", { style: sectionStyle }, [
$el("label", { style: labelStyle }, ["4⃣ Subtitle "]),
this.SubTitleInput,
@@ -379,7 +377,7 @@ export class CopusShareDialog extends ComfyDialog {
});
const blockChainSection_lock = $el("div", { style: sectionStyle }, [
$el("label", { style: labelStyle }, ["6Pay to download"]),
$el("label", { style: labelStyle }, ["6Download threshold"]),
$el(
"label",
{
@@ -392,11 +390,42 @@ export class CopusShareDialog extends ComfyDialog {
},
[
this.radioButtonsCheck_lock,
$el("div", { style: { marginLeft: "5px" ,display:'flex',alignItems:'center'} }, [
$el("span", { style: { marginLeft: "5px" } }, ["ON"]),
$el("span", { style: { marginLeft: "20px",marginRight:'10px' ,color:'#fff'} }, ["Price US$"]),
this.LockInput
]),
$el(
"div",
{
style: {
marginLeft: "5px",
display: "flex",
alignItems: "center",
position: "relative",
},
},
[
$el("span", { style: { marginLeft: "5px" } }, ["ON"]),
$el(
"span",
{
style: {
marginLeft: "20px",
marginRight: "10px",
color: "#fff",
},
},
["Unlock with"]
),
$el("img", {
style: {
width: "16px",
height: "16px",
position: "absolute",
right: "75px",
zIndex: "100",
},
src: "https://static.copus.io/images/admin/202507/prod/e2919a1d8f3c2d99d3b8fe27ff94b841.png",
}),
this.LockInput,
]
),
]
),
$el(
@@ -404,14 +433,25 @@ export class CopusShareDialog extends ComfyDialog {
{ style: { display: "flex", alignItems: "center", cursor: "pointer" } },
[
this.radioButtonsCheckOff_lock,
$el("span", { style: { marginLeft: "5px" } }, ["OFF"]),
$el(
"div",
{
style: {
marginLeft: "5px",
display: "flex",
alignItems: "center",
},
},
[$el("span", { style: { marginLeft: "5px" } }, ["OFF"])]
),
]
),
$el(
"p",
{ style: { fontSize: "16px", color: "#fff", margin: "10px 0 0 0" } },
["Get paid from your workflow. You can change the price and withdraw your earnings on Copus."]
[
]
),
]);
@@ -432,7 +472,7 @@ export class CopusShareDialog extends ComfyDialog {
});
const blockChainSection = $el("div", { style: sectionStyle }, [
$el("label", { style: labelStyle }, ["7️⃣ Store on blockchain "]),
$el("label", { style: labelStyle }, ["8️⃣ Store on blockchain "]),
$el(
"label",
{
@@ -463,6 +503,139 @@ export class CopusShareDialog extends ComfyDialog {
),
]);
this.ratingRadioButtonsCheck0 = $el("input", {
type: "radio",
name: "content_rating",
value: "0",
id: "content_rating0",
});
this.ratingRadioButtonsCheck1 = $el("input", {
type: "radio",
name: "content_rating",
value: "1",
id: "content_rating1",
});
this.ratingRadioButtonsCheck2 = $el("input", {
type: "radio",
name: "content_rating",
value: "2",
id: "content_rating2",
});
this.ratingRadioButtonsCheck_1 = $el("input", {
type: "radio",
name: "content_rating",
value: "-1",
id: "content_rating_1",
checked: true,
});
// content rating
const contentRatingSection = $el("div", { style: sectionStyle }, [
$el("label", { style: labelStyle }, ["7⃣ Content rating "]),
$el(
"label",
{
style: {
marginTop: "10px",
display: "flex",
alignItems: "center",
cursor: "pointer",
},
},
[
this.ratingRadioButtonsCheck0,
$el("img", {
style: {
width: "12px",
height: "12px",
marginLeft: "5px",
},
src: "https://static.copus.io/images/client/202507/test/b9f17da83b054d53cd0cb4508c2c30dc.png",
}),
$el("span", { style: { marginLeft: "5px", color: "#fff" } }, [
"All ages",
]),
]
),
$el(
"p",
{ style: { fontSize: "10px", color: "#fff", marginLeft: "20px" } },
["Safe for all viewers; no profanity, violence, or mature themes."]
),
$el(
"label",
{ style: { display: "flex", alignItems: "center", cursor: "pointer" } },
[
this.ratingRadioButtonsCheck1,
$el("img", {
style: {
width: "12px",
height: "12px",
marginLeft: "5px",
},
src: "https://static.copus.io/images/client/202507/test/7848bc0d3690671df21c7cf00c4cfc81.png",
}),
$el("span", { style: { marginLeft: "5px", color: "#fff" } }, [
"13+ (Teen)",
]),
]
),
$el(
"p",
{ style: { fontSize: "10px", color: "#fff", marginLeft: "20px" } },
[
"Mild language, light themes, or cartoon violence; no explicit content. ",
]
),
$el(
"label",
{ style: { display: "flex", alignItems: "center", cursor: "pointer" } },
[
this.ratingRadioButtonsCheck2,
$el("img", {
style: {
width: "12px",
height: "12px",
marginLeft: "5px",
},
src: "https://static.copus.io/images/client/202507/test/bc51839c208d68d91173e43c23bff039.png",
}),
$el("span", { style: { marginLeft: "5px", color: "#fff" } }, [
"18+ (Explicit)",
]),
]
),
$el(
"p",
{ style: { fontSize: "10px", color: "#fff", marginLeft: "20px" } },
[
"Explicit content, including sexual content, strong violence, or intense themes. ",
]
),
$el(
"label",
{ style: { display: "flex", alignItems: "center", cursor: "pointer" } },
[
this.ratingRadioButtonsCheck_1,
$el("img", {
style: {
width: "12px",
height: "12px",
marginLeft: "5px",
},
src: "https://static.copus.io/images/client/202507/test/5c802fdcaaea4e7bbed37393eec0d5ba.png",
}),
$el("span", { style: { marginLeft: "5px", color: "#fff" } }, [
"Not Rated",
]),
]
),
$el(
"p",
{ style: { fontSize: "10px", color: "#fff", marginLeft: "20px" } },
["No age rating provided."]
),
]);
// Message Section
this.message = $el(
@@ -526,6 +699,7 @@ export class CopusShareDialog extends ComfyDialog {
DescriptionSection,
// contestSection,
blockChainSection_lock,
contentRatingSection,
blockChainSection,
this.message,
buttonsSection,
@@ -534,7 +708,7 @@ export class CopusShareDialog extends ComfyDialog {
return layout;
}
/**
* api
* api
* @param {url} path
* @param {params} options
* @param {statusText} statusText
@@ -587,7 +761,9 @@ export class CopusShareDialog extends ComfyDialog {
url: data,
});
} else {
throw new Error("make sure your API key is correct and try again later");
throw new Error(
"make sure your API key is correct and try again later"
);
}
} catch (e) {
if (e?.response?.status === 413) {
@@ -628,8 +804,15 @@ export class CopusShareDialog extends ComfyDialog {
subTitle: this.SubTitleInput.value,
content: this.descriptionInput.value,
storeOnChain: this.radioButtonsCheck.checked ? true : false,
lockState:this.radioButtonsCheck_lock.checked ? 2 : 0,
unlockPrice:this.LockInput.value,
lockState: this.radioButtonsCheck_lock.checked ? 2 : 0,
unlockPrice: this.LockInput.value,
rating: this.ratingRadioButtonsCheck0.checked
? 0
: this.ratingRadioButtonsCheck1.checked
? 1
: this.ratingRadioButtonsCheck2.checked
? 2
: -1,
};
if (!this.keyInput.value) {
@@ -644,8 +827,8 @@ export class CopusShareDialog extends ComfyDialog {
throw new Error("Title is required");
}
if(this.radioButtonsCheck_lock.checked){
if (!this.LockInput.value){
if (this.radioButtonsCheck_lock.checked) {
if (!this.LockInput.value) {
throw new Error("Price is required");
}
}
@@ -695,23 +878,23 @@ export class CopusShareDialog extends ComfyDialog {
"Uploading workflow..."
);
if (res.status && res.data.status && res.data) {
localStorage.setItem("copus_token",this.keyInput.value);
const { data } = res.data;
if (data) {
const url = `${DEFAULT_HOMEPAGE_URL}/work/${data}`;
this.message.innerHTML = `Workflow has been shared successfully. <a href="${url}" target="_blank">Click here to view it.</a>`;
this.previewImage.src = "";
this.previewImage.style.display = "none";
this.uploadedImages = [];
this.allFilesImages = [];
this.allFiles = [];
this.TitleInput.value = "";
this.SubTitleInput.value = "";
this.descriptionInput.value = "";
this.selectedFile = null;
}
}
if (res.status && res.data.status && res.data) {
localStorage.setItem("copus_token", this.keyInput.value);
const { data } = res.data;
if (data) {
const url = `${DEFAULT_HOMEPAGE_URL}/work/${data}`;
this.message.innerHTML = `Workflow has been shared successfully. <a href="${url}" target="_blank">Click here to view it.</a>`;
this.previewImage.src = "";
this.previewImage.style.display = "none";
this.uploadedImages = [];
this.allFilesImages = [];
this.allFiles = [];
this.TitleInput.value = "";
this.SubTitleInput.value = "";
this.descriptionInput.value = "";
this.selectedFile = null;
}
}
} catch (e) {
throw new Error("Error sharing workflow: " + e.message);
}
@@ -757,7 +940,7 @@ export class CopusShareDialog extends ComfyDialog {
this.element.style.display = "block";
this.previewImage.src = "";
this.previewImage.style.display = "none";
this.keyInput.value = apiToken!=null?apiToken:"";
this.keyInput.value = apiToken != null ? apiToken : "";
this.uploadedImages = [];
this.allFilesImages = [];
this.allFiles = [];

View File

@@ -714,6 +714,7 @@ export class CustomNodesManager {
link.href = rowItem.reference;
link.target = '_blank';
link.innerHTML = `<b>${title}</b>`;
link.title = rowItem.originalData.id;
container.appendChild(link);
return container;
@@ -1534,7 +1535,7 @@ export class CustomNodesManager {
else {
this.batch_id = generateUUID();
batch['batch_id'] = this.batch_id;
const res = await api.fetchApi(`/v2/manager/queue/batch`, {
method: 'POST',
body: JSON.stringify(batch)
@@ -1549,7 +1550,7 @@ export class CustomNodesManager {
errorMsg = `[FAIL] ${item.title}`;
}
}
this.showStop();
showTerminal();
}
@@ -1625,17 +1626,35 @@ export class CustomNodesManager {
getNodesInWorkflow() {
let usedGroupNodes = new Set();
let allUsedNodes = {};
const visitedGraphs = new Set();
for(let k in app.graph._nodes) {
let node = app.graph._nodes[k];
const visitGraph = (graph) => {
if (!graph || visitedGraphs.has(graph)) return;
visitedGraphs.add(graph);
if(node.type.startsWith('workflow>')) {
usedGroupNodes.add(node.type.slice(9));
continue;
const nodes = graph._nodes || graph.nodes || [];
for(let k in nodes) {
let node = nodes[k];
if (!node) continue;
// If it's a SubgraphNode, recurse into its graph and continue searching
if (node.isSubgraphNode?.() && node.subgraph) {
visitGraph(node.subgraph);
}
if (!node.type) continue;
// Group nodes / components
if(typeof node.type === 'string' && node.type.startsWith('workflow>')) {
usedGroupNodes.add(node.type.slice(9));
continue;
}
allUsedNodes[node.type] = node;
}
};
allUsedNodes[node.type] = node;
}
visitGraph(app.graph);
for(let k of usedGroupNodes) {
let subnodes = app.graph.extra.groupNodes[k]?.nodes;

View File

@@ -46,6 +46,7 @@ version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' i
DEFAULT_CHANNEL = "https://raw.githubusercontent.com/Comfy-Org/ComfyUI-Manager/main"
DEFAULT_CHANNEL_LEGACY = "https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main"
default_custom_nodes_path = None
@@ -160,7 +161,7 @@ comfy_ui_revision = "Unknown"
comfy_ui_commit_datetime = datetime(1900, 1, 1, 0, 0, 0)
channel_dict = None
valid_channels = {'default', 'local'}
valid_channels = {'default', 'local', DEFAULT_CHANNEL, DEFAULT_CHANNEL_LEGACY}
channel_list = None
@@ -304,18 +305,86 @@ class ManagedResult:
return self
class NormalizedKeyDict:
def __init__(self):
self._store = {}
self._key_map = {}
def _normalize_key(self, key):
if isinstance(key, str):
return key.strip().lower()
return key
def __setitem__(self, key, value):
norm_key = self._normalize_key(key)
self._key_map[norm_key] = key
self._store[key] = value
def __getitem__(self, key):
norm_key = self._normalize_key(key)
original_key = self._key_map[norm_key]
return self._store[original_key]
def __delitem__(self, key):
norm_key = self._normalize_key(key)
original_key = self._key_map.pop(norm_key)
del self._store[original_key]
def __contains__(self, key):
return self._normalize_key(key) in self._key_map
def get(self, key, default=None):
return self[key] if key in self else default
def setdefault(self, key, default=None):
if key in self:
return self[key]
self[key] = default
return default
def pop(self, key, default=None):
if key in self:
val = self[key]
del self[key]
return val
if default is not None:
return default
raise KeyError(key)
def keys(self):
return self._store.keys()
def values(self):
return self._store.values()
def items(self):
return self._store.items()
def __iter__(self):
return iter(self._store)
def __len__(self):
return len(self._store)
def __repr__(self):
return repr(self._store)
def to_dict(self):
return dict(self._store)
class UnifiedManager:
def __init__(self):
self.installed_node_packages: dict[str, InstalledNodePackage] = {}
self.cnr_inactive_nodes = {} # node_id -> node_version -> fullpath
self.nightly_inactive_nodes = {} # node_id -> fullpath
self.unknown_inactive_nodes = {} # node_id -> repo url * fullpath
self.active_nodes = {} # node_id -> node_version * fullpath
self.unknown_active_nodes = {} # node_id -> repo url * fullpath
self.cnr_map = {} # node_id -> cnr info
self.repo_cnr_map = {} # repo_url -> cnr info
self.custom_node_map_cache = {} # (channel, mode) -> augmented custom node list json
self.cnr_inactive_nodes = NormalizedKeyDict() # node_id -> node_version -> fullpath
self.nightly_inactive_nodes = NormalizedKeyDict() # node_id -> fullpath
self.unknown_inactive_nodes = {} # node_id -> repo url * fullpath
self.active_nodes = NormalizedKeyDict() # node_id -> node_version * fullpath
self.unknown_active_nodes = {} # node_id -> repo url * fullpath
self.cnr_map = NormalizedKeyDict() # node_id -> cnr info
self.repo_cnr_map = {} # repo_url -> cnr info
self.custom_node_map_cache = {} # (channel, mode) -> augmented custom node list json
self.processed_install = set()
def get_module_name(self, x):
@@ -721,7 +790,7 @@ class UnifiedManager:
channel = normalize_channel(channel)
nodes = await self.load_nightly(channel, mode)
res = {}
res = NormalizedKeyDict()
added_cnr = set()
for v in nodes.values():
v = v[0]
@@ -1557,16 +1626,18 @@ def read_config():
config = configparser.ConfigParser(strict=False)
config.read(context.manager_config_path)
default_conf = config['default']
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
def get_bool(key, default_value):
return default_conf[key].lower() == 'true' if key 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)
return {
'http_channel_enabled': get_bool('http_channel_enabled', False),
'preview_method': default_conf.get('preview_method', manager_funcs.get_current_preview_method()).lower(),
'git_exe': default_conf.get('git_exe', ''),
'use_uv': get_bool('use_uv', False),
'use_uv': get_bool('use_uv', True),
'channel_url': default_conf.get('channel_url', DEFAULT_CHANNEL),
'default_cache_as_channel_url': get_bool('default_cache_as_channel_url', False),
'share_option': default_conf.get('share_option', 'all').lower(),
@@ -1585,15 +1656,17 @@ def read_config():
except Exception:
manager_util.use_uv = False
manager_util.bypass_ssl = False
return {
'http_channel_enabled': False,
'preview_method': manager_funcs.get_current_preview_method(),
'git_exe': '',
'use_uv': False,
'use_uv': True,
'channel_url': DEFAULT_CHANNEL,
'default_cache_as_channel_url': False,
'share_option': 'all',
'bypass_ssl': False,
'bypass_ssl': manager_util.bypass_ssl,
'file_logging': True,
'component_policy': 'workflow',
'update_policy': 'stable-comfyui',
@@ -2776,7 +2849,7 @@ async def get_unified_total_nodes(channel, mode, regsitry_cache_mode='cache'):
if cnr_id is not None:
# cnr or nightly version
cnr_ids.remove(cnr_id)
cnr_ids.discard(cnr_id)
updatable = False
cnr = unified_manager.cnr_map[cnr_id]
@@ -2940,6 +3013,11 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
info = yaml.load(snapshot_file, Loader=yaml.SafeLoader)
info = info['custom_nodes']
if 'pips' in info and info['pips']:
pips = info['pips']
else:
pips = {}
# for cnr restore
cnr_info = info.get('cnr_custom_nodes')
if cnr_info is not None:
@@ -3146,6 +3224,8 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
unified_manager.repo_install(repo_url, to_path, instant_execution=True, no_deps=False, return_postinstall=False)
cloned_repos.append(repo_name)
manager_util.restore_pip_snapshot(pips, git_helper_extras)
# print summary
for x in cloned_repos:
print(f"[ INSTALLED ] {x}")

View File

@@ -23,6 +23,7 @@ from ..common import manager_util
from ..common import cm_global
from ..common import manager_downloader
from ..common import context
from ..common import manager_security
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
@@ -36,7 +37,8 @@ logging.info("[ComfyUI-Manager] network_mode: " + network_mode_description)
comfy_ui_hash = "-"
comfyui_tag = None
SECURITY_MESSAGE_MIDDLE_OR_BELOW = "ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.\nReference: https://github.com/Comfy-Org/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_MIDDLE = "ERROR: To use this action, a security_level of `normal or below` is required. Please contact the administrator.\nReference: https://github.com/Comfy-Org/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_MIDDLE_P = "ERROR: To use this action, security_level must be `normal or below`, and network_mode must be set to `personal_cloud`. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_NORMAL_MINUS = "ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.\nReference: https://github.com/Comfy-Org/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_GENERAL = "ERROR: This installation is not allowed in this security_level. Please contact the administrator.\nReference: https://github.com/Comfy-Org/ComfyUI-Manager#security-policy"
SECURITY_MESSAGE_NORMAL_MINUS_MODEL = "ERROR: Downloading models that are not in '.safetensors' format is only allowed for models registered in the 'default' channel at this security level. If you want to download this model, set the security level to 'normal-' or lower."
@@ -93,13 +95,27 @@ model_dir_name_map = {
def is_allowed_security_level(level):
is_personal_cloud = core.get_config()['network_mode'].lower() == 'personal_cloud'
if level == 'block':
return False
elif level == 'high+':
if is_local_mode:
return core.get_config()['security_level'] in ['weak', 'normal-']
elif is_personal_cloud:
return core.get_config()['security_level'] == 'weak'
else:
return False
elif level == 'high':
if is_local_mode:
return core.get_config()['security_level'] in ['weak', 'normal-']
else:
return core.get_config()['security_level'] == 'weak'
elif level == 'middle+':
if is_local_mode or is_personal_cloud:
return core.get_config()['security_level'] in ['weak', 'normal', 'normal-']
else:
return False
elif level == 'middle':
return core.get_config()['security_level'] in ['weak', 'normal', 'normal-']
else:
@@ -116,7 +132,7 @@ async def get_risky_level(files, pip_packages):
for x in files:
if x not in all_urls:
return "high"
return "high+"
all_pip_packages = set()
for x in json_data1['custom_nodes'] + json_data2['custom_nodes']:
@@ -126,7 +142,7 @@ async def get_risky_level(files, pip_packages):
if p not in all_pip_packages:
return "block"
return "middle"
return "middle+"
class ManagerFuncsInComfyUI(core.ManagerFuncs):
@@ -650,7 +666,7 @@ async def task_worker():
return 'success'
except Exception as e:
logging.error(f"[ComfyUI-Manager] ERROR: {e}", file=sys.stderr)
logging.error(f"[ComfyUI-Manager] ERROR: {e}")
return f"Model installation error: {model_url}"
@@ -758,29 +774,29 @@ async def queue_batch(request):
for x in v:
res = await _uninstall_custom_node(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
else:
res = await _install_custom_node(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
elif k == 'install':
for x in v:
res = await _install_custom_node(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
elif k == 'uninstall':
for x in v:
res = await _uninstall_custom_node(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
elif k == 'update':
for x in v:
res = await _update_custom_node(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
elif k == 'update_comfyui':
await update_comfyui(None)
@@ -793,13 +809,13 @@ async def queue_batch(request):
for x in v:
res = await _install_model(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
elif k == 'fix':
for x in v:
res = await _fix_custom_node(x)
if res.status != 200:
failed.add(x[0])
failed.add(x['id'])
with task_worker_lock:
finalize_temp_queue_batch(json_data, failed)
@@ -910,8 +926,8 @@ async def update_all(request):
async def _update_all(json_data):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
if not is_allowed_security_level('middle+'):
logging.error(SECURITY_MESSAGE_MIDDLE_P)
return web.Response(status=403)
with task_worker_lock:
@@ -1056,14 +1072,17 @@ async def fetch_customnode_list(request):
if channel != 'local':
found = 'custom'
for name, url in core.get_channel_dict().items():
if url == channel:
found = name
break
if channel == core.DEFAULT_CHANNEL or channel == core.DEFAULT_CHANNEL_LEGACY:
channel = 'default'
else:
for name, url in core.get_channel_dict().items():
if url == channel:
found = name
break
channel = found
channel = found
result = dict(channel=channel, node_packs=node_packs)
result = dict(channel=channel, node_packs=node_packs.to_dict())
return web.json_response(result, content_type='application/json')
@@ -1162,7 +1181,7 @@ async def get_snapshot_list(request):
@routes.get("/v2/snapshot/remove")
async def remove_snapshot(request):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
logging.error(SECURITY_MESSAGE_MIDDLE)
return web.Response(status=403)
try:
@@ -1179,8 +1198,8 @@ async def remove_snapshot(request):
@routes.get("/v2/snapshot/restore")
async def restore_snapshot(request):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
if not is_allowed_security_level('middle+'):
logging.error(SECURITY_MESSAGE_MIDDLE_P)
return web.Response(status=403)
try:
@@ -1292,6 +1311,65 @@ async def import_fail_info(request):
return web.Response(status=400)
@routes.post("/v2/customnode/import_fail_info_bulk")
async def import_fail_info_bulk(request):
try:
json_data = await request.json()
# Basic validation - ensure we have either cnr_ids or urls
if not isinstance(json_data, dict):
return web.Response(status=400, text="Request body must be a JSON object")
if "cnr_ids" not in json_data and "urls" not in json_data:
return web.Response(
status=400, text="Either 'cnr_ids' or 'urls' field is required"
)
await core.unified_manager.reload('cache')
await core.unified_manager.get_custom_nodes('default', 'cache')
results = {}
if "cnr_ids" in json_data:
if not isinstance(json_data["cnr_ids"], list):
return web.Response(status=400, text="'cnr_ids' must be an array")
for cnr_id in json_data["cnr_ids"]:
if not isinstance(cnr_id, str):
results[cnr_id] = {"error": "cnr_id must be a string"}
continue
module_name = core.unified_manager.get_module_name(cnr_id)
if module_name is not None:
info = cm_global.error_dict.get(module_name)
if info is not None:
results[cnr_id] = info
else:
results[cnr_id] = None
else:
results[cnr_id] = None
if "urls" in json_data:
if not isinstance(json_data["urls"], list):
return web.Response(status=400, text="'urls' must be an array")
for url in json_data["urls"]:
if not isinstance(url, str):
results[url] = {"error": "url must be a string"}
continue
module_name = core.unified_manager.get_module_name(url)
if module_name is not None:
info = cm_global.error_dict.get(module_name)
if info is not None:
results[url] = info
else:
results[url] = None
else:
results[url] = None
return web.json_response(results)
except Exception as e:
logging.error(f"[ComfyUI-Manager] Error processing bulk import fail info: {e}")
return web.Response(status=500, text="Internal server error")
@routes.post("/v2/manager/queue/reinstall")
async def reinstall_custom_node(request):
await uninstall_custom_node(request)
@@ -1356,8 +1434,8 @@ async def install_custom_node(request):
async def _install_custom_node(json_data):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
if not is_allowed_security_level('middle+'):
logging.error(SECURITY_MESSAGE_MIDDLE_P)
return web.Response(status=403, text="A security error has occurred. Please check the terminal logs")
# non-nightly cnr is safe
@@ -1462,7 +1540,7 @@ async def _fix_custom_node(json_data):
@routes.post("/v2/customnode/install/git_url")
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)
return web.Response(status=403)
@@ -1482,7 +1560,7 @@ async def install_custom_node_git_url(request):
@routes.post("/v2/customnode/install/pip")
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)
return web.Response(status=403)
@@ -1500,7 +1578,7 @@ async def uninstall_custom_node(request):
async def _uninstall_custom_node(json_data):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
logging.error(SECURITY_MESSAGE_MIDDLE)
return web.Response(status=403, text="A security error has occurred. Please check the terminal logs")
node_id = json_data.get('id')
@@ -1526,7 +1604,7 @@ async def update_custom_node(request):
async def _update_custom_node(json_data):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
logging.error(SECURITY_MESSAGE_MIDDLE)
return web.Response(status=403, text="A security error has occurred. Please check the terminal logs")
node_id = json_data.get('id')
@@ -1617,8 +1695,8 @@ async def install_model(request):
async def _install_model(json_data):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
if not is_allowed_security_level('middle+'):
logging.error(SECURITY_MESSAGE_MIDDLE_P)
return web.Response(status=403, text="A security error has occurred. Please check the terminal logs")
# validate request
@@ -1626,7 +1704,7 @@ async def _install_model(json_data):
logging.error(f"[ComfyUI-Manager] Invalid model install request is detected: {json_data}")
return web.Response(status=400, text="Invalid model install request is detected")
if not json_data['filename'].endswith('.safetensors') and not is_allowed_security_level('high'):
if not json_data['filename'].endswith('.safetensors') and not is_allowed_security_level('high+'):
models_json = await core.get_data_by_mode('cache', 'model-list.json', 'default')
is_belongs_to_whitelist = False
@@ -1783,7 +1861,7 @@ async def get_notice_legacy(request):
@routes.get("/v2/manager/reboot")
def restart(self):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
logging.error(SECURITY_MESSAGE_MIDDLE)
return web.Response(status=403)
try:
@@ -1949,9 +2027,10 @@ if not os.path.exists(context.manager_config_path):
core.write_config()
cm_global.register_extension('ComfyUI-Manager',
{'version': core.version,
'name': 'ComfyUI Manager',
'nodes': {},
'description': 'This extension provides the ability to manage custom nodes in ComfyUI.', })
# policy setup
manager_security.add_handler_policy(reinstall_custom_node, manager_security.HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD)
manager_security.add_handler_policy(install_custom_node, manager_security.HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD)
manager_security.add_handler_policy(fix_custom_node, manager_security.HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD)
manager_security.add_handler_policy(install_custom_node_git_url, manager_security.HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD)
manager_security.add_handler_policy(install_custom_node_pip, manager_security.HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD)
manager_security.add_handler_policy(install_model, manager_security.HANDLER_POLICY.MULTIPLE_REMOTE_BAN_NOT_PERSONAL_CLOUD)

View File

@@ -10,6 +10,16 @@ import hashlib
import folder_paths
from server import PromptServer
import logging
import sys
try:
from nio import AsyncClient, LoginResponse, UploadResponse
matrix_nio_is_available = True
except Exception:
logging.warning(f"[ComfyUI-Manager] The matrix sharing feature has been disabled because the `matrix-nio` dependency is not installed.\n\tTo use this feature, please run the following command:\n\t{sys.executable} -m pip install matrix-nio\n")
matrix_nio_is_available = False
def extract_model_file_names(json_data):
@@ -192,6 +202,14 @@ async def get_esheep_workflow_and_images(request):
return web.Response(status=200, text=json.dumps(data))
@PromptServer.instance.routes.get("/v2/manager/get_matrix_dep_status")
async def get_matrix_dep_status(request):
if matrix_nio_is_available:
return web.Response(status=200, text='available')
else:
return web.Response(status=200, text='unavailable')
def set_matrix_auth(json_data):
homeserver = json_data['homeserver']
username = json_data['username']
@@ -331,15 +349,12 @@ async def share_art(request):
workflowId = upload_workflow_json["workflowId"]
# check if the user has provided Matrix credentials
if "matrix" in share_destinations:
if matrix_nio_is_available and "matrix" in share_destinations:
comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org'
filename = os.path.basename(asset_filepath)
content_type = assetFileType
try:
from matrix_client.api import MatrixHttpApi
from matrix_client.client import MatrixClient
homeserver = 'matrix.org'
if matrix_auth:
homeserver = matrix_auth.get('homeserver', 'matrix.org')
@@ -347,20 +362,35 @@ async def share_art(request):
if not homeserver.startswith("https://"):
homeserver = "https://" + homeserver
client = MatrixClient(homeserver)
try:
token = client.login(username=matrix_auth['username'], password=matrix_auth['password'])
if not token:
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
except Exception:
client = AsyncClient(homeserver, matrix_auth['username'])
# Login
login_resp = await client.login(matrix_auth['password'])
if not isinstance(login_resp, LoginResponse) or not login_resp.access_token:
await client.close()
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
matrix = MatrixHttpApi(homeserver, token=token)
# Upload asset
with open(asset_filepath, 'rb') as f:
mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri']
upload_resp, _maybe_keys = await client.upload(f, content_type=content_type, filename=filename)
asset_data = f.seek(0) or f.read() # get size for info below
if not isinstance(upload_resp, UploadResponse) or not upload_resp.content_uri:
await client.close()
return web.json_response({"error": "Failed to upload asset to Matrix."}, content_type='application/json', status=500)
mxc_url = upload_resp.content_uri
workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri']
# Upload workflow JSON
import io
workflow_json_bytes = json.dumps(prompt['workflow']).encode('utf-8')
workflow_io = io.BytesIO(workflow_json_bytes)
upload_workflow_resp, _maybe_keys = await client.upload(workflow_io, content_type='application/json', filename='workflow.json')
workflow_io.seek(0)
if not isinstance(upload_workflow_resp, UploadResponse) or not upload_workflow_resp.content_uri:
await client.close()
return web.json_response({"error": "Failed to upload workflow to Matrix."}, content_type='application/json', status=500)
workflow_json_mxc_url = upload_workflow_resp.content_uri
# Send text message
text_content = ""
if title:
text_content += f"{title}\n"
@@ -368,10 +398,45 @@ async def share_art(request):
text_content += f"{description}\n"
if credits:
text_content += f"\ncredits: {credits}\n"
matrix.send_message(comfyui_share_room_id, text_content)
matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image')
matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file')
except Exception:
await client.room_send(
room_id=comfyui_share_room_id,
message_type="m.room.message",
content={"msgtype": "m.text", "body": text_content}
)
# Send image
await client.room_send(
room_id=comfyui_share_room_id,
message_type="m.room.message",
content={
"msgtype": "m.image",
"body": filename,
"url": mxc_url,
"info": {
"mimetype": content_type,
"size": len(asset_data)
}
}
)
# Send workflow JSON file
await client.room_send(
room_id=comfyui_share_room_id,
message_type="m.room.message",
content={
"msgtype": "m.file",
"body": "workflow.json",
"url": workflow_json_mxc_url,
"info": {
"mimetype": "application/json",
"size": len(workflow_json_bytes)
}
}
)
await client.close()
except:
import traceback
traceback.print_exc()
return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500)

View File

@@ -1973,6 +1973,97 @@
"url": "https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth",
"size": "375.0MB"
},
{
"name": "sam2.1_hiera_tiny.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (tiny)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_tiny.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_tiny.pt",
"size": "149.0MB"
},
{
"name": "sam2.1_hiera_small.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (small)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_small.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_small.pt",
"size": "176.0MB"
},
{
"name": "sam2.1_hiera_base_plus.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (base+)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_base_plus.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_base_plus.pt",
"size": "309.0MB"
},
{
"name": "sam2.1_hiera_large.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (large)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_large.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt",
"size": "857.0MB"
},
{
"name": "sam2_hiera_tiny.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (tiny)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_tiny.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_tiny.pt",
"size": "149.0MB"
},
{
"name": "sam2_hiera_small.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (small)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_small.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_small.pt",
"size": "176.0MB"
},
{
"name": "sam2_hiera_base_plus.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (base+)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_base_plus.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_base_plus.pt",
"size": "309.0MB"
},
{
"name": "sam2_hiera_large.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (large)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_large.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_large.pt",
"size": "857.0MB"
},
{
"name": "seecoder v1.0",
"type": "seecoder",
@@ -4006,6 +4097,29 @@
"size": "649MB"
},
{
"name": "Comfy-Org/omnigen2_fp16.safetensors",
"type": "diffusion_model",
"base": "OmniGen2",
"save_path": "default",
"description": "OmniGen2 diffusion model. This is required for using OmniGen2.",
"reference": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged",
"filename": "omnigen2_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/omnigen2_fp16.safetensors",
"size": "7.93GB"
},
{
"name": "Comfy-Org/qwen_2.5_vl_fp16.safetensors",
"type": "clip",
"base": "qwen-2.5",
"save_path": "default",
"description": "text encoder for OmniGen2",
"reference": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged",
"filename": "qwen_2.5_vl_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged/resolve/main/split_files/text_encoders/qwen_2.5_vl_fp16.safetensors",
"size": "7.51GB"
},
{
"name": "FLUX.1 [Schnell] Diffusion model",
"type": "diffusion_model",
@@ -4023,7 +4137,7 @@
"type": "VAE",
"base": "FLUX.1",
"save_path": "vae/FLUX1",
"description": "FLUX.1 VAE model",
"description": "FLUX.1 VAE model\nNOTE: This VAE model can also be used for image generation with OmniGen2.",
"reference": "https://huggingface.co/black-forest-labs/FLUX.1-schnell",
"filename": "ae.safetensors",
"url": "https://huggingface.co/black-forest-labs/FLUX.1-schnell/resolve/main/ae.safetensors",
@@ -4931,6 +5045,105 @@
"size": "1.26GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v high noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v high noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_high_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_high_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v high noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v high noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v low noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v low noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_low_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_low_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v low noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v low noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v high noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v high noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_high_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_high_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v high noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v high noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v low noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v low noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_low_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_low_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v low noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v low noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 ti2v 5B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for ti2v 5B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_ti2v_5B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_ti2v_5B_fp16.safetensors",
"size": "10.0GB"
},
{
"name": "Comfy-Org/umt5_xxl_fp16.safetensors",
@@ -5033,6 +5246,50 @@
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltxv-13b-0.9.7-distilled-fp8.safetensors",
"size": "15.7GB"
},
{
"name": "LTX-Video 2B Distilled v0.9.8",
"type": "checkpoint",
"base": "LTX-Video",
"save_path": "checkpoints/LTXV",
"description": "LTX-Video 2B distilled model v0.9.8 with improved prompt understanding and detail generation.",
"reference": "https://huggingface.co/Lightricks/LTX-Video",
"filename": "ltxv-2b-0.9.8-distilled.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltxv-2b-0.9.8-distilled.safetensors",
"size": "6.34GB"
},
{
"name": "LTX-Video 2B Distilled FP8 v0.9.8",
"type": "checkpoint",
"base": "LTX-Video",
"save_path": "checkpoints/LTXV",
"description": "Quantized LTX-Video 2B distilled model v0.9.8 with improved prompt understanding and detail generation, optimized for lower VRAM usage.",
"reference": "https://huggingface.co/Lightricks/LTX-Video",
"filename": "ltxv-2b-0.9.8-distilled-fp8.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltxv-2b-0.9.8-distilled-fp8.safetensors",
"size": "4.46GB"
},
{
"name": "LTX-Video 13B Distilled v0.9.8",
"type": "checkpoint",
"base": "LTX-Video",
"save_path": "checkpoints/LTXV",
"description": "LTX-Video 13B distilled model v0.9.8 with improved prompt understanding and detail generation.",
"reference": "https://huggingface.co/Lightricks/LTX-Video",
"filename": "ltxv-13b-0.9.8-distilled.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltxv-13b-0.9.8-distilled.safetensors",
"size": "28.6GB"
},
{
"name": "LTX-Video 13B Distilled FP8 v0.9.8",
"type": "checkpoint",
"base": "LTX-Video",
"save_path": "checkpoints/LTXV",
"description": "Quantized LTX-Video 13B distilled model v0.9.8 with improved prompt understanding and detail generation, optimized for lower VRAM usage.",
"reference": "https://huggingface.co/Lightricks/LTX-Video",
"filename": "ltxv-13b-0.9.8-distilled-fp8.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltxv-13b-0.9.8-distilled-fp8.safetensors",
"size": "15.7GB"
},
{
"name": "LTX-Video 13B Distilled LoRA v0.9.7",
"type": "lora",
@@ -5044,6 +5301,50 @@
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltxv-13b-0.9.7-distilled-lora128.safetensors",
"size": "1.33GB"
},
{
"name": "LTX-Video ICLoRA Depth 13B v0.9.7",
"type": "lora",
"base": "LTX-Video",
"save_path": "loras",
"description": "In-Context LoRA (IC LoRA) for depth-controlled video-to-video generation with precise depth conditioning.",
"reference": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-depth-13b-0.9.7",
"filename": "ltxv-097-ic-lora-depth-control-comfyui.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-depth-13b-0.9.7/resolve/main/ltxv-097-ic-lora-depth-control-comfyui.safetensors",
"size": "81.9MB"
},
{
"name": "LTX-Video ICLoRA Pose 13B v0.9.7",
"type": "lora",
"base": "LTX-Video",
"save_path": "loras",
"description": "In-Context LoRA (IC LoRA) for pose-controlled video-to-video generation with precise pose conditioning.",
"reference": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-pose-13b-0.9.7",
"filename": "ltxv-097-ic-lora-pose-control-comfyui.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-pose-13b-0.9.7/resolve/main/ltxv-097-ic-lora-pose-control-comfyui.safetensors",
"size": "151MB"
},
{
"name": "LTX-Video ICLoRA Canny 13B v0.9.7",
"type": "lora",
"base": "LTX-Video",
"save_path": "loras",
"description": "In-Context LoRA (IC LoRA) for canny edge-controlled video-to-video generation with precise edge conditioning.",
"reference": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-canny-13b-0.9.7",
"filename": "ltxv-097-ic-lora-canny-control-comfyui.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-canny-13b-0.9.7/resolve/main/ltxv-097-ic-lora-canny-control-comfyui.safetensors",
"size": "81.9MB"
},
{
"name": "LTX-Video ICLoRA Detailer 13B v0.9.8",
"type": "lora",
"base": "LTX-Video",
"save_path": "loras",
"description": "A video detailer model on top of LTXV_13B_098_DEV trained on custom data using In-Context LoRA (IC LoRA) method.",
"reference": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-detailer-13b-0.9.8",
"filename": "ltxv-098-ic-lora-detailer-comfyui.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video-ICLoRA-detailer-13b-0.9.8/resolve/main/ltxv-098-ic-lora-detailer-comfyui.safetensors",
"size": "1.31GB"
},
{
"name": "Latent Bridge Matching for Image Relighting",
"type": "diffusion_model",

View File

@@ -35,7 +35,6 @@ else:
def current_timestamp():
return str(time.time()).split('.')[0]
security_check.security_check()
cm_global.pip_blacklist = {'torch', 'torchaudio', 'torchsde', 'torchvision'}
cm_global.pip_downgrade_blacklist = ['torch', 'torchaudio', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']
@@ -111,13 +110,14 @@ def check_file_logging():
read_config()
read_uv_mode()
security_check.security_check()
check_file_logging()
cm_global.pip_overrides = {'numpy': 'numpy<2'}
cm_global.pip_overrides = {}
if os.path.exists(manager_pip_overrides_path):
with open(manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
cm_global.pip_overrides = json.load(json_file)
cm_global.pip_overrides['numpy'] = 'numpy<2'
if os.path.exists(manager_pip_blacklist_path):
@@ -330,7 +330,12 @@ try:
log_file.write(message)
else:
log_file.write(f"[{timestamp}] {message}")
log_file.flush()
try:
log_file.flush()
except Exception:
pass
self.last_char = message if message == '' else message[-1]
if not file_only:
@@ -343,7 +348,10 @@ try:
original_stderr.flush()
def flush(self):
log_file.flush()
try:
log_file.flush()
except Exception:
pass
with std_log_lock:
if self.is_stdout:

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
#!/bin/bash
rm ~/.tmp/dev/*.py > /dev/null 2>&1
python ../../scanner.py ~/.tmp/dev
python ../../scanner.py ~/.tmp/dev $*

View File

@@ -1,5 +1,25 @@
{
"custom_nodes": [
{
"author": "synchronicity-labs",
"title": "ComfyUI Sync Lipsync Node",
"reference": "https://github.com/synchronicity-labs/sync-comfyui",
"files": [
"https://github.com/synchronicity-labs/sync-comfyui"
],
"install_type": "git-clone",
"description": "This custom node allows you to perform audio-video lip synchronization inside ComfyUI using a simple interface."
},
{
"author": "joaomede",
"title": "ComfyUI-Unload-Model-Fork",
"reference": "https://github.com/joaomede/ComfyUI-Unload-Model-Fork",
"files": [
"https://github.com/joaomede/ComfyUI-Unload-Model-Fork"
],
"install_type": "git-clone",
"description": "For unloading a model or all models, using the memory management that is already present in ComfyUI. Copied from [a/https://github.com/willblaschko/ComfyUI-Unload-Models](https://github.com/willblaschko/ComfyUI-Unload-Models) but without the unnecessary extra stuff."
},
{
"author": "SanDiegoDude",
"title": "ComfyUI-HiDream-Sampler [WIP]",

View File

@@ -1,16 +1,678 @@
{
"custom_nodes": [
{
"author": "#NOTICE_1.13",
"title": "NOTICE: This channel is not the default channel.",
"reference": "https://github.com/ltdrdata/ComfyUI-Manager",
"files": [],
"author": "perilli",
"title": "apw_nodes [REMOVED]",
"reference": "https://github.com/alessandroperilli/APW_Nodes",
"files": [
"https://github.com/alessandroperilli/APW_Nodes"
],
"install_type": "git-clone",
"description": "If you see this message, your ComfyUI-Manager is outdated.\nLegacy channel provides only the list of the deprecated nodes. If you want to find the complete node list, please go to the Default channel."
"description": "A custom node suite to augment the capabilities of the [a/AP Workflows for ComfyUI](https://perilli.com/ai/comfyui/)\nNOTE: See [a/Open Creative Studio Nodes](https://github.com/alessandroperilli/OCS_Nodes)"
},
{
"author": "greengerong",
"title": "ComfyUI-Lumina-Video [REMOVED]",
"reference": "https://github.com/greengerong/ComfyUI-Lumina-Video",
"files": [
"https://github.com/greengerong/ComfyUI-Lumina-Video"
],
"install_type": "git-clone",
"description": "This is a video generation plugin implementation for ComfyUI based on the Lumina Video model."
},
{
"author": "SatadalAI",
"title": "Combined Upscale Node for ComfyUI [REMOVED]",
"reference": "https://github.com/SatadalAI/SATA_UtilityNode",
"files": [
"https://github.com/SatadalAI/SATA_UtilityNode"
],
"install_type": "git-clone",
"description": "Combined_Upscale is a custom ComfyUI node designed for high-quality image enhancement workflows. It intelligently combines model-based upscaling with efficient CPU-based resizing, offering granular control over output dimensions and quality. Ideal for asset pipelines, UI prototyping, and generative workflows.\nNOTE: The files in the repo are not organized."
},
{
"author": "netroxin",
"title": "Netro_wildcards [REMOVED]",
"reference": "https://github.com/netroxin/comfyui_netro_wildcards",
"files": [
"https://github.com/netroxin/comfyui_netro_wildcards"
],
"install_type": "git-clone",
"description": "Since I used 'simple wildcards' from Vanilla and it no longer works with the new Comfy UI version for me, I created an alternative. This CustomNode takes the entire contents of your wildcards-folder(comfyui wildcards) and creates a node for each one."
},
{
"author": "takoyaki1118",
"title": "ComfyUI-MangaTools [REMOVED]",
"reference": "https://github.com/takoyaki1118/ComfyUI-MangaTools",
"files": [
"https://github.com/takoyaki1118/ComfyUI-MangaTools"
],
"install_type": "git-clone",
"description": "NODES: Manga Panel Detector, Manga Panel Dispatcher, GateImage, MangaPageAssembler"
},
{
"author": "lucasgattas",
"title": "comfyui-egregora-regional [REMOVED]",
"reference": "https://github.com/lucasgattas/comfyui-egregora-regional",
"files": [
"https://github.com/lucasgattas/comfyui-egregora-regional"
],
"install_type": "git-clone",
"description": "Image Tile Split with Region-Aware Prompting for ComfyUI"
},
{
"author": "lucasgattas",
"title": "comfyui-egregora-tiled [REMOVED]",
"reference": "https://github.com/lucasgattas/comfyui-egregora-tiled",
"files": [
"https://github.com/lucasgattas/comfyui-egregora-tiled"
],
"install_type": "git-clone",
"description": "Tiled regional prompting + tiled VAE decode with seam-free blending for ComfyUI"
},
{
"author": "Seedsa",
"title": "ComfyUI Fooocus Nodes [REMOVED]",
"id": "fooocus-nodes",
"reference": "https://github.com/Seedsa/Fooocus_Nodes",
"files": [
"https://github.com/Seedsa/Fooocus_Nodes"
],
"install_type": "git-clone",
"description": "This extension provides image generation features based on Fooocus."
},
{
"author": "zhilemann",
"title": "ComfyUI-moondream2 [REMOVED]",
"reference": "https://github.com/zhilemann/ComfyUI-moondream2",
"files": [
"https://github.com/zhilemann/ComfyUI-moondream2"
],
"install_type": "git-clone",
"description": "nodes for nightly moondream2 VLM inference\nsupports only captioning and visual queries at the moment"
},
{
"author": "shinich39",
"title": "comfyui-textarea-is-shit [REMOVED]",
"reference": "https://github.com/shinich39/comfyui-textarea-is-shit",
"files": [
"https://github.com/shinich39/comfyui-textarea-is-shit"
],
"description": "HTML gives me a textarea like piece of shit.",
"install_type": "git-clone"
},
{
"author": "shinich39",
"title": "comfyui-poor-textarea [REMOVED]",
"reference": "https://github.com/shinich39/comfyui-poor-textarea",
"files": [
"https://github.com/shinich39/comfyui-poor-textarea"
],
"install_type": "git-clone",
"description": "Add commentify, indentation, auto-close brackets in textarea."
},
{
"author": "InfiniNode",
"title": "Comfyui-InfiniNode-Model-Suite [UNSAFE/REMOVED]",
"reference": "https://github.com/InfiniNode/Comfyui-InfiniNode-Model-Suite",
"files": [
"https://github.com/InfiniNode/Comfyui-InfiniNode-Model-Suite"
],
"install_type": "git-clone",
"description": "Welcome to the InfiniNode Model Suite, a custom node pack for ComfyUI that transforms the process of manipulating generative AI models. Our suite is a direct implementation of the 'GUI-Based Key Converter Development Plan,' designed to remove technical barriers for advanced AI practitioners and integrate seamlessly with existing image generation pipelines.[w/This node pack contains a node that has a vulnerability allowing write to arbitrary file paths.]"
},
{
"author": "Avalre",
"title": "ComfyUI-avaNodes [REMOVED]",
"reference": "https://github.com/Avalre/ComfyUI-avaNodes",
"files": [
"https://github.com/Avalre/ComfyUI-avaNodes"
],
"install_type": "git-clone",
"description": "These nodes were created to personalize/optimize several ComfyUI nodes for my own use. You can replicate the functionality of most of my nodes by some combination of default ComfyUI nodes and custom nodes from other developers."
},
{
"author": "Alectriciti",
"title": "comfyui-creativeprompts [REMOVED]",
"reference": "https://github.com/Alectriciti/comfyui-creativeprompts",
"files": [
"https://github.com/Alectriciti/comfyui-creativeprompts"
],
"install_type": "git-clone",
"description": "A creative alternative to dynamicprompts"
},
{
"author": "flybirdxx",
"title": "ComfyUI Sliding Window [REMOVED]",
"reference": "https://github.com/PixWizardry/ComfyUI_Sliding_Window",
"files": [
"https://github.com/PixWizardry/ComfyUI_Sliding_Window"
],
"install_type": "git-clone",
"description": "This set of nodes provides a powerful sliding window or 'tiling' technique for processing long videos and animations in ComfyUI. It allows you to work on animations that are longer than your VRAM would typically allow by breaking the job into smaller, overlapping chunks and seamlessly blending them back together."
},
{
"author": "SykkoAtHome",
"title": "Sykko Tools for ComfyUI [REMOVED]",
"reference": "https://github.com/SykkoAtHome/ComfyUI_SykkoTools",
"files": [
"https://github.com/SykkoAtHome/ComfyUI_SykkoTools"
],
"install_type": "git-clone",
"description": "Utilities for working with camera animations inside ComfyUI. The repository currently provides a node for loading camera motion from ASCII FBX files and a corresponding command line helper for debugging."
},
{
"author": "hananbeer",
"title": "node_dev - ComfyUI Node Development Helper [REMOVED]",
"reference": "https://github.com/hananbeer/node_dev",
"files": [
"https://github.com/hananbeer/node_dev"
],
"install_type": "git-clone",
"description": "Browse to this endpoint to reload custom nodes for more streamlined development:\nhttp://127.0.0.1:8188/node_dev/reload/<module_name>"
},
{
"author": "Charonartist",
"title": "Comfyui_gemini_tts_node [REMOVED]",
"reference": "https://github.com/Charonartist/Comfyui_gemini_tts_node",
"files": [
"https://github.com/Charonartist/Comfyui_gemini_tts_node"
],
"install_type": "git-clone",
"description": "This custom node is a ComfyUI node for generating speech from text using the Gemini 2.5 Flash Preview TTS API."
},
{
"author": "squirrel765",
"title": "lorasubdirectory [REMOVED]",
"reference": "https://github.com/andrewsthomasj/lorasubdirectory",
"files": [
"https://github.com/andrewsthomasj/lorasubdirectory"
],
"install_type": "git-clone",
"description": "only show dropdown of loras ina a given subdirectory"
},
{
"author": "shingo1228",
"title": "ComfyUI-send-Eagle(slim) [REVMOED]",
"id": "send-eagle",
"reference": "https://github.com/shingo1228/ComfyUI-send-eagle-slim",
"files": [
"https://github.com/shingo1228/ComfyUI-send-eagle-slim"
],
"install_type": "git-clone",
"description": "Nodes:Send Webp Image to Eagle. This is an extension node for ComfyUI that allows you to send generated images in webp format to Eagle. This extension node is a re-implementation of the Eagle linkage functions of the previous ComfyUI-send-Eagle node, focusing on the functions required for this node."
},
{
"author": "shingo1228",
"title": "ComfyUI-SDXL-EmptyLatentImage [REVMOED]",
"id": "sdxl-emptylatent",
"reference": "https://github.com/shingo1228/ComfyUI-SDXL-EmptyLatentImage",
"files": [
"https://github.com/shingo1228/ComfyUI-SDXL-EmptyLatentImage"
],
"install_type": "git-clone",
"description": "Nodes:SDXL Empty Latent Image. An extension node for ComfyUI that allows you to select a resolution from the pre-defined json files and output a Latent Image."
},
{
"author": "chaunceyyann",
"title": "ComfyUI Image Processing Nodes [REMOVED]",
"reference": "https://github.com/chaunceyyann/comfyui-image-processing-nodes",
"files": [
"https://github.com/chaunceyyann/comfyui-image-processing-nodes"
],
"install_type": "git-clone",
"description": "A collection of custom nodes for ComfyUI focused on image processing operations."
},
{
"author": "OgreLemonSoup",
"title": "Gallery&Tabs [DEPRECATED]",
"id": "LoadImageGallery",
"reference": "https://github.com/OgreLemonSoup/ComfyUI-Load-Image-Gallery",
"files": [
"https://github.com/OgreLemonSoup/ComfyUI-Load-Image-Gallery"
],
"install_type": "git-clone",
"description": "Adds a gallery to the Load Image node and tabs for Load Checkpoint/Lora/etc nodes"
},
{
"author": "11dogzi",
"title": "Qwen-Image ComfyUI [REMOVED]",
"reference": "https://github.com/11dogzi/Comfyui-Qwen-Image",
"files": [
"https://github.com/11dogzi/Comfyui-Qwen-Image"
],
"install_type": "git-clone",
"description": "This is a custom node package that integrates the Qwen-Image model into ComfyUI."
},
{
"author": "BAIS1C",
"title": "ComfyUI-AudioDuration [REMOVED]",
"reference": "https://github.com/BAIS1C/ComfyUI_BASICDancePoser",
"files": [
"https://github.com/BAIS1C/ComfyUI_BASICDancePoser"
],
"install_type": "git-clone",
"description": "Node to extract Dance poses from Music to control Video Generations.\nNOTE: The files in the repo are not organized."
},
{
"author": "BAIS1C",
"title": "ComfyUI_BASICSAdvancedDancePoser [REMOVED]",
"reference": "https://github.com/BAIS1C/ComfyUI_BASICSAdvancedDancePoser",
"files": [
"https://github.com/BAIS1C/ComfyUI_BASICSAdvancedDancePoser"
],
"install_type": "git-clone",
"description": "Professional COCO-WholeBody 133-keypoint dance animation system for ComfyUI"
},
{
"author": "fablestudio",
"title": "ComfyUI-Showrunner-Utils [REMOVED]",
"reference": "https://github.com/fablestudio/ComfyUI-Showrunner-Utils",
"files": [
"https://github.com/fablestudio/ComfyUI-Showrunner-Utils"
],
"install_type": "git-clone",
"description": "NODES: Align Face, Generate Timestamp, GetMostCommonColors, Alpha Crop and Position Image, Shrink Image"
},
{
"author": "skayka",
"title": "ComfyUI-DreamFit [REMOVED]",
"reference": "https://github.com/skayka/ComfyUI-DreamFit",
"files": [
"https://github.com/skayka/ComfyUI-DreamFit"
],
"install_type": "git-clone",
"description": "Garment-centric human generation nodes for ComfyUI using DreamFit with Flux.\nDreamFit is a powerful adapter system that enhances Flux models with garment-aware generation capabilities, enabling high-quality fashion and clothing generation."
},
{
"author": "domenecmiralles",
"title": "obobo_nodes [REMOVED]",
"reference": "https://github.com/domenecmiralles/obobo_nodes",
"files": [
"https://github.com/domenecmiralles/obobo_nodes"
],
"install_type": "git-clone",
"description": "A collection of custom nodes for ComfyUI that provide various input and output capabilities."
},
{
"author": "NicholasKao1029",
"title": "comfyui-pixxio [REMOVED]",
"reference": "https://github.com/NicholasKao1029/comfyui-pixxio",
"files": [
"https://github.com/NicholasKao1029/comfyui-pixxio"
],
"install_type": "git-clone",
"description": "NODES: Auto-Upload Image to Pixxio Collection, Load Image from Pixx.io"
},
{
"author": "ComfyUI-Workflow",
"title": "ComfyUI OpenAI Nodes [REMOVED]",
"reference": "https://github.com/ComfyUI-Workflow/ComfyUI-OpenAI",
"files": [
"https://github.com/ComfyUI-Workflow/ComfyUI-OpenAI"
],
"install_type": "git-clone",
"description": "By utilizing OpenAI's powerful vision models, this node enables you to incorporate state-of-the-art image understanding into your ComfyUI projects with minimal setup."
},
{
"author": "dionren",
"title": "Export Workflow With Cyuai Api Available Nodes [REMOVED]",
"id": "comfyUI-Pro-Export-Tool",
"reference": "https://github.com/dionren/ComfyUI-Pro-Export-Tool",
"files": [
"https://github.com/dionren/ComfyUI-Pro-Export-Tool"
],
"install_type": "git-clone",
"description": "This is a node to convert workflows to cyuai api available nodes."
},
{
"author": "1H-hobit",
"title": "ComfyUI_InternVL3 [REMOVED]",
"reference": "https://github.com/1H-hobit/ComfyUI_InternVL3",
"files": [
"https://github.com/1H-hobit/ComfyUI_InternVL3"
],
"install_type": "git-clone",
"description": "ComfyUI for [a/InternVL](https://github.com/OpenGVLab/InternVL)"
},
{
"author": "spacepxl",
"title": "ComfyUI-Florence-2 [DEPRECATED]",
"id": "florence2-spacepxl",
"reference": "https://github.com/spacepxl/ComfyUI-Florence-2",
"files": [
"https://github.com/spacepxl/ComfyUI-Florence-2"
],
"install_type": "git-clone",
"description": "[a/https://huggingface.co/microsoft/Florence-2-large-ft](https://huggingface.co/microsoft/Florence-2-large-ft)\nLarge or base model, support for captioning and bbox task modes, more coming soon."
},
{
"author": "xxxxxxxxxxxc",
"title": "flux-kontext-diff-merge [REMOVED]",
"reference": "https://github.com/xxxxxxxxxxxc/flux-kontext-diff-merge",
"files": [
"https://github.com/xxxxxxxxxxxc/flux-kontext-diff-merge"
],
"install_type": "git-clone",
"description": "Preserve image quality with flux-kontext-diff-merge. This ComfyUI node merges only changed areas from AI edits, ensuring clarity and detail."
},
{
"author": "TechnoByteJS",
"title": "TechNodes [REMOVED]",
"id": "technodes",
"reference": "https://github.com/TechnoByteJS/ComfyUI-TechNodes",
"files": [
"https://github.com/TechnoByteJS/ComfyUI-TechNodes"
],
"install_type": "git-clone",
"description": "ComfyUI nodes for merging, testing and more.\nNOTE: SDNext Merge, VAE Merge, MBW Layers, Repeat VAE, Quantization."
},
{
"author": "DDDDEEP",
"title": "ComfyUI-DDDDEEP [REMOVED]",
"reference": "https://github.com/DDDDEEP/ComfyUI-DDDDEEP",
"files": [
"https://github.com/DDDDEEP/ComfyUI-DDDDEEP"
],
"install_type": "git-clone",
"description": "NODES: AutoWidthHeight, ReturnIntSeed, OppositeBool, PromptItemCollection"
},
{
"author": "manifestations",
"title": "ComfyUI Ethnic Outfits Custom Nodes [REMOVED]",
"reference": "https://github.com/manifestations/comfyui-outfits",
"files": [
"https://github.com/manifestations/comfyui-outfits"
],
"install_type": "git-clone",
"description": "Custom ComfyUI nodes for generating outfit prompts representing diverse ethnicities, cultures, and regions. Uses extensible JSON data for clothing, accessories, and poses, with “random/disabled” dropdowns for flexibility. Advanced prompt engineering is supported via Ollama LLM integration. Easily add new regions, ethnicities, or cultures by updating data files and creating lightweight node wrappers. Designed for artists, researchers, and developers seeking culturally rich, customizable prompt generation in ComfyUI workflows."
},
{
"author": "MitoshiroPJ",
"title": "ComfyUI Slothful Attention [REMOVED]",
"reference": "https://github.com/MitoshiroPJ/comfyui_slothful_attention",
"files": [
"https://github.com/MitoshiroPJ/comfyui_slothful_attention"
],
"install_type": "git-clone",
"description": "This custom node allow controlling output without training. The reducing method is similar to [a/Spatial-Reduction Attention](https://paperswithcode.com/method/spatial-reduction-attention)."
},
{
"author": "MitoshiroPJ",
"title": "comfyui_focal_sampler [REMOVED]",
"reference": "https://github.com/MitoshiroPJ/comfyui_focal_sampler",
"files": [
"https://github.com/MitoshiroPJ/comfyui_focal_sampler"
],
"install_type": "git-clone",
"description": "Apply additional sampling to specific area"
},
{
"author": "manifestations",
"title": "ComfyUI Ethnic Outfit & Prompt Enhancer Nodes [REMOVED]",
"reference": "https://github.com/manifestations/comfyui-indian-outfit",
"files": [
"https://github.com/manifestations/comfyui-indian-outfit"
],
"install_type": "git-clone",
"description": "Features:\n* Extensive options for Indian, Indonesian, and international clothing, jewelry, accessories, and styles\n* Multiple jewelry and accessory fields (with material support: gold, diamond, silver, leather, beads, etc.)\n* Support for tattoos, henna, hair styles, poses, shot types, lighting, and photography genres\n* Seamless prompt expansion using your own Ollama LLM instance\n* Modular, extensible JSON data files for easy customization"
},
{
"author": "coVISIONSld",
"title": "ComfyUI-OmniGen2 [REMOVED]",
"reference": "https://github.com/coVISIONSld/ComfyUI-OmniGen2",
"files": [
"https://github.com/coVISIONSld/ComfyUI-OmniGen2"
],
"install_type": "git-clone",
"description": "ComfyUI-OmniGen2 is a custom node package for the OmniGen2 model, enabling advanced text-to-image generation and visual understanding."
},
{
"author": "S4MUEL-404",
"title": "ComfyUI-S4Tool-Image-Overlay [REMOVED]",
"reference": "https://github.com/S4MUEL-404/ComfyUI-S4Tool-Image-Overlay",
"files": [
"https://github.com/S4MUEL-404/ComfyUI-S4Tool-Image-Overlay"
],
"install_type": "git-clone",
"description": "Quickly set up image overlay effects"
},
{
"author": "akspa0",
"title": "ComfyUI-FapMixPlus [REMOVED]",
"reference": "https://github.com/akspa0/ComfyUI-FapMixPlus",
"files": [
"https://github.com/akspa0/ComfyUI-FapMixPlus"
],
"install_type": "git-clone",
"description": "This is an audio processing script that applies soft limiting, optional loudness normalization, and optional slicing for transcription. It can also produce stereo-mixed outputs with optional audio appended to the end. The script organizes processed files into structured folders with sanitized filenames and retains original timestamps for continuity."
},
{
"author": "RedmondAI",
"title": "comfyui-tools [UNSAFE]",
"reference": "https://github.com/RedmondAI/comfyui-tools",
"files": [
"https://github.com/RedmondAI/comfyui-tools"
],
"install_type": "git-clone",
"description": "Custom extensions for ComfyUI used by the Redmond3D VFX team.[w/This node pack has a vulnerability that allows it to create files at arbitrary paths.]"
},
{
"author": "S4MUEL-404",
"title": "Image Position Blend [REMOVED]",
"id": "ComfyUI-Image-Position-Blend",
"version": "1.1",
"reference": "https://github.com/S4MUEL-404/ComfyUI-Image-Position-Blend",
"files": [
"https://github.com/S4MUEL-404/ComfyUI-Image-Position-Blend"
],
"install_type": "git-clone",
"description": "A custom node for conveniently adjusting the overlay position of two images."
},
{
"author": "S4MUEL-404",
"title": "ComfyUI-Text-On-Image [REMOVED]",
"id": "ComfyUI-Text-On-Image",
"reference": "https://github.com/S4MUEL-404/ComfyUI-Text-On-Image",
"files": [
"https://github.com/S4MUEL-404/ComfyUI-Text-On-Image"
],
"install_type": "git-clone",
"description": "A custom node for ComfyUI that allows users to add text overlays to images with customizable size, font, position, and shadow."
},
{
"author": "S4MUEL-404",
"title": "ComfyUI-Prompts-Selector [REMOVED]",
"reference": "https://github.com/S4MUEL-404/ComfyUI-Prompts-Selector",
"files": [
"https://github.com/S4MUEL-404/ComfyUI-Prompts-Selector"
],
"install_type": "git-clone",
"description": "Quickly select preset prompts and merge them"
},
{
"author": "juntaosun",
"title": "ComfyUI_open_nodes [REMOVED]",
"reference": "https://github.com/juntaosun/ComfyUI_open_nodes",
"files": [
"https://github.com/juntaosun/ComfyUI_open_nodes"
],
"install_type": "git-clone",
"description": "ComfyUI open nodes by juntaosun."
},
{
"author": "perilli",
"title": "apw_nodes [DEPRECATED]",
"reference": "https://github.com/alessandroperilli/apw_nodes",
"files": [
"https://github.com/alessandroperilli/apw_nodes"
],
"install_type": "git-clone",
"description": "A custom node suite to augment the capabilities of the [a/AP Workflows for ComfyUI](https://perilli.com/ai/comfyui/)[w/'APW_Nodes' has been newly added in place of 'apw_nodes'.]"
},
{
"author": "markuryy",
"title": "ComfyUI Spiritparticle Nodes [REMOVED]",
"reference": "https://github.com/markuryy/comfyui-spiritparticle",
"files": [
"https://github.com/markuryy/comfyui-spiritparticle"
],
"install_type": "git-clone",
"description": "A node pack by spiritparticle."
},
{
"author": "SpaceKendo",
"title": "Text to video for Stable Video Diffusion in ComfyUI [REMOVED]",
"id": "svd-txt2vid",
"reference": "https://github.com/SpaceKendo/ComfyUI-svd_txt2vid",
"files": [
"https://github.com/SpaceKendo/ComfyUI-svd_txt2vid"
],
"install_type": "git-clone",
"description": "This is node replaces the init_image conditioning for the [a/Stable Video Diffusion](https://github.com/Stability-AI/generative-models) image to video model with text embeds, together with a conditioning frame. The conditioning frame is a set of latents."
},
{
"author": "vovler",
"title": "ComfyUI Civitai Helper Extension [REMOVED]",
"reference": "https://github.com/vovler/comfyui-civitaihelper",
"files": [
"https://github.com/vovler/comfyui-civitaihelper"
],
"install_type": "git-clone",
"description": "ComfyUI extension for parsing Civitai PNG workflows and automatically downloading missing models"
},
{
"author": "DriftJohnson",
"title": "DJZ-Nodes [REMOVED]",
"id": "DJZ-Nodes",
"reference": "https://github.com/MushroomFleet/DJZ-Nodes",
"files": [
"https://github.com/MushroomFleet/DJZ-Nodes"
],
"install_type": "git-clone",
"description": "AspectSize and other nodes"
},
{
"author": "DriftJohnson",
"title": "KokoroTTS Node [REMOVED]",
"reference": "https://github.com/MushroomFleet/DJZ-KokoroTTS",
"files": [
"https://github.com/MushroomFleet/DJZ-KokoroTTS"
],
"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."
},
{
"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",
"title": "SVG Suite for ComfyUI [REMOVED]",
"reference": "https://github.com/MushroomFleet/svg-suite",
"files": [
"https://github.com/MushroomFleet/svg-suite"
],
"install_type": "git-clone",
"description": "SVG Suite is an advanced set of nodes for converting images to SVG in ComfyUI, expanding upon the functionality of ComfyUI-ToSVG."
},
{
"author": "joeriben",
"title": "AI4ArtsEd Ollama Prompt Node [DEPRECATED]",
"reference": "https://github.com/joeriben/ai4artsed_comfyui",
"files": [
"https://github.com/joeriben/ai4artsed_comfyui"
],
"install_type": "git-clone",
"description": "Experimental nodes for ComfyUI. For more, see [a/https://kubi-meta.de/ai4artsed](https://kubi-meta.de/ai4artsed) A custom ComfyUI node for stylistic and cultural transformation of input text using local LLMs served via Ollama. This node allows you to combine a free-form prompt (e.g. translation, poetic recoding, genre shift) with externally supplied text in the ComfyUI graph. The result is processed via an Ollama-hosted model and returned as plain text."
},
{
"author": "bento234",
"title": "ComfyUI-bento-toolbox [REMOVED]",
"reference": "https://github.com/bento234/ComfyUI-bento-toolbox",
"files": [
"https://github.com/bento234/ComfyUI-bento-toolbox"
],
"install_type": "git-clone",
"description": "NODES: Tile Prompt Distributor"
},
{
"author": "yichengup",
"title": "ComfyUI-VideoBlender [REMOVED]",
"reference": "https://github.com/yichengup/ComfyUI-VideoBlender",
"files": [
"https://github.com/yichengup/ComfyUI-VideoBlender"
],
"install_type": "git-clone",
"description": "Video clip mixing"
},
{
"author": "xl0",
"title": "latent-tools [REMOVED]",
"reference": "https://github.com/xl0/latent-tools",
"files": [
"https://github.com/xl0/latent-tools"
],
"install_type": "git-clone",
"description": "Visualize and manipulate the latent space in ComfyUI"
},
{
"author": "Conor-Collins",
"title": "ComfyUI-CoCoTools [REMOVED]",
"reference": "https://github.com/Conor-Collins/coco_tools",
"files": [
"https://github.com/Conor-Collins/coco_tools"
],
"install_type": "git-clone",
"description": "A set of custom nodes for ComfyUI providing advanced image processing, file handling, and utility functions."
},
{
"author": "theUpsider",
"title": "ComfyUI-Logic [DEPRECATED]",
"id": "comfy-logic",
"reference": "https://github.com/theUpsider/ComfyUI-Logic",
"files": [
"https://github.com/theUpsider/ComfyUI-Logic"
],
"install_type": "git-clone",
"description": "An extension to ComfyUI that introduces logic nodes and conditional rendering capabilities."
},
{
"author": "Malloc-pix",
"title": "comfyui_qwen2.4_vl_node [REMOVED]",
"reference": "https://github.com/Malloc-pix/comfyui_qwen2.4_vl_node",
"files": [
"https://github.com/Malloc-pix/comfyui_qwen2.4_vl_node"
],
"install_type": "git-clone",
"description": "NODES: CogVLM2 Captioner, CLIP Dynamic Text Encode(cy)"
},
{
"author": "inyourdreams-studio",
"title": "ComfyUI-RBLM [REMOVED]",
"reference": "https://github.com/inyourdreams-studio/comfyui-rblm",
"files": [
"https://github.com/inyourdreams-studio/comfyui-rblm"
],
"install_type": "git-clone",
"description": "A custom node pack for ComfyUI that provides text manipulation nodes."
},
{
"author": "dream-computing",
"title": "SyntaxNodes - Image Processing Effects for ComfyUI [REMOVED]",
"reference": "https://github.com/dream-computing/syntax-nodes",
"files": [
"https://github.com/dream-computing/syntax-nodes"
],
"install_type": "git-clone",
"description": "A collection of custom nodes for ComfyUI designed to apply various image processing effects, stylizations, and analyses."
},
{
"author": "UD1sto",
"title": "plugin-utils-nodes [DEPRECATED]",

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,219 @@
{
"models": [
{
"name": "Comfy-Org/Wan2.2 i2v high noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v high noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_high_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_high_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v high noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v high noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v low noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v low noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_low_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_low_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 i2v low noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for i2v low noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v high noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v high noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_high_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_high_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v high noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v high noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v low noise 14B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v low noise 14B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_low_noise_14B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_low_noise_14B_fp16.safetensors",
"size": "28.6GB"
},
{
"name": "Comfy-Org/Wan2.2 t2v low noise 14B (fp8_scaled)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for t2v low noise 14B (fp8_scaled)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors",
"size": "14.3GB"
},
{
"name": "Comfy-Org/Wan2.2 ti2v 5B (fp16)",
"type": "diffusion_model",
"base": "Wan2.2",
"save_path": "diffusion_models/Wan2.2",
"description": "Wan2.2 diffusion model for ti2v 5B (fp16)",
"reference": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged",
"filename": "wan2.2_ti2v_5B_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_ti2v_5B_fp16.safetensors",
"size": "10.0GB"
},
{
"name": "sam2.1_hiera_tiny.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (tiny)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_tiny.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_tiny.pt",
"size": "149.0MB"
},
{
"name": "sam2.1_hiera_small.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (small)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_small.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_small.pt",
"size": "176.0MB"
},
{
"name": "sam2.1_hiera_base_plus.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (base+)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_base_plus.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_base_plus.pt",
"size": "309.0MB"
},
{
"name": "sam2.1_hiera_large.pt",
"type": "sam2.1",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2.1 hiera model (large)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2.1_hiera_large.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt",
"size": "857.0MB"
},
{
"name": "sam2_hiera_tiny.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (tiny)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_tiny.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_tiny.pt",
"size": "149.0MB"
},
{
"name": "sam2_hiera_small.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (small)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_small.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_small.pt",
"size": "176.0MB"
},
{
"name": "sam2_hiera_base_plus.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (base+)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_base_plus.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_base_plus.pt",
"size": "309.0MB"
},
{
"name": "sam2_hiera_large.pt",
"type": "sam2",
"base": "SAM",
"save_path": "sams",
"description": "Segmenty Anything SAM 2 hiera model (large)",
"reference": "https://github.com/facebookresearch/sam2#model-description",
"filename": "sam2_hiera_large.pt",
"url": "https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_large.pt",
"size": "857.0MB"
},
{
"name": "Comfy-Org/omnigen2_fp16.safetensors",
"type": "diffusion_model",
"base": "OmniGen2",
"save_path": "default",
"description": "OmniGen2 diffusion model. This is required for using OmniGen2.",
"reference": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged",
"filename": "omnigen2_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/omnigen2_fp16.safetensors",
"size": "7.93GB"
},
{
"name": "Comfy-Org/qwen_2.5_vl_fp16.safetensors",
"type": "clip",
"base": "qwen-2.5",
"save_path": "default",
"description": "text encoder for OmniGen2",
"reference": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged",
"filename": "qwen_2.5_vl_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged/resolve/main/split_files/text_encoders/qwen_2.5_vl_fp16.safetensors",
"size": "7.51GB"
},
{
"name": "Latent Bridge Matching for Image Relighting",
"type": "diffusion_model",
@@ -473,224 +687,6 @@
"filename": "llava_llama3_fp16.safetensors",
"url": "https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged/resolve/main/split_files/text_encoders/llava_llama3_fp16.safetensors",
"size": "16.1GB"
},
{
"name": "PixArt-Sigma-XL-2-512-MS.safetensors (diffusion)",
"type": "diffusion_model",
"base": "pixart-sigma",
"save_path": "diffusion_models/PixArt-Sigma",
"description": "PixArt-Sigma Diffusion model",
"reference": "https://huggingface.co/PixArt-alpha/PixArt-Sigma-XL-2-512-MS",
"filename": "PixArt-Sigma-XL-2-512-MS.safetensors",
"url": "https://huggingface.co/PixArt-alpha/PixArt-Sigma-XL-2-512-MS/resolve/main/transformer/diffusion_pytorch_model.safetensors",
"size": "2.44GB"
},
{
"name": "PixArt-Sigma-XL-2-1024-MS.safetensors (diffusion)",
"type": "diffusion_model",
"base": "pixart-sigma",
"save_path": "diffusion_models/PixArt-Sigma",
"description": "PixArt-Sigma Diffusion model",
"reference": "https://huggingface.co/PixArt-alpha/PixArt-Sigma-XL-2-1024-MS",
"filename": "PixArt-Sigma-XL-2-1024-MS.safetensors",
"url": "https://huggingface.co/PixArt-alpha/PixArt-Sigma-XL-2-1024-MS/resolve/main/transformer/diffusion_pytorch_model.safetensors",
"size": "2.44GB"
},
{
"name": "PixArt-XL-2-1024-MS.safetensors (diffusion)",
"type": "diffusion_model",
"base": "pixart-alpha",
"save_path": "diffusion_models/PixArt-Alpha",
"description": "PixArt-Alpha Diffusion model",
"reference": "https://huggingface.co/PixArt-alpha/PixArt-XL-2-1024-MS",
"filename": "PixArt-XL-2-1024-MS.safetensors",
"url": "https://huggingface.co/PixArt-alpha/PixArt-XL-2-1024-MS/resolve/main/transformer/diffusion_pytorch_model.safetensors",
"size": "2.45GB"
},
{
"name": "Comfy-Org/hunyuan_video_t2v_720p_bf16.safetensors",
"type": "diffusion_model",
"base": "Hunyuan Video",
"save_path": "diffusion_models/hunyuan_video",
"description": "Huyuan Video diffusion model. repackaged version.",
"reference": "https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged",
"filename": "hunyuan_video_t2v_720p_bf16.safetensors",
"url": "https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged/resolve/main/split_files/diffusion_models/hunyuan_video_t2v_720p_bf16.safetensors",
"size": "25.6GB"
},
{
"name": "Comfy-Org/hunyuan_video_vae_bf16.safetensors",
"type": "VAE",
"base": "Hunyuan Video",
"save_path": "VAE",
"description": "Huyuan Video VAE model. repackaged version.",
"reference": "https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged",
"filename": "hunyuan_video_vae_bf16.safetensors",
"url": "https://huggingface.co/Comfy-Org/HunyuanVideo_repackaged/resolve/main/split_files/vae/hunyuan_video_vae_bf16.safetensors",
"size": "493MB"
},
{
"name": "LTX-Video 2B v0.9.1 Checkpoint",
"type": "checkpoint",
"base": "LTX-Video",
"save_path": "checkpoints/LTXV",
"description": "LTX-Video is the first DiT-based video generation model capable of generating high-quality videos in real-time. It produces 24 FPS videos at a 768x512 resolution faster than they can be watched. Trained on a large-scale dataset of diverse videos, the model generates high-resolution videos with realistic and varied content.",
"reference": "https://huggingface.co/Lightricks/LTX-Video",
"filename": "ltx-video-2b-v0.9.1.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltx-video-2b-v0.9.1.safetensors",
"size": "5.72GB"
},
{
"name": "XLabs-AI/flux-canny-controlnet-v3.safetensors",
"type": "controlnet",
"base": "FLUX.1",
"save_path": "xlabs/controlnets",
"description": "ControlNet checkpoints for FLUX.1-dev model by Black Forest Labs.",
"reference": "https://huggingface.co/XLabs-AI/flux-controlnet-collections",
"filename": "flux-canny-controlnet-v3.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-controlnet-collections/resolve/main/flux-canny-controlnet-v3.safetensors",
"size": "1.49GB"
},
{
"name": "XLabs-AI/flux-depth-controlnet-v3.safetensors",
"type": "controlnet",
"base": "FLUX.1",
"save_path": "xlabs/controlnets",
"description": "ControlNet checkpoints for FLUX.1-dev model by Black Forest Labs.",
"reference": "https://huggingface.co/XLabs-AI/flux-controlnet-collections",
"filename": "flux-depth-controlnet-v3.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-controlnet-collections/resolve/main/flux-depth-controlnet-v3.safetensors",
"size": "1.49GB"
},
{
"name": "XLabs-AI/flux-hed-controlnet-v3.safetensors",
"type": "controlnet",
"base": "FLUX.1",
"save_path": "xlabs/controlnets",
"description": "ControlNet checkpoints for FLUX.1-dev model by Black Forest Labs.",
"reference": "https://huggingface.co/XLabs-AI/flux-controlnet-collections",
"filename": "flux-hed-controlnet-v3.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-controlnet-collections/resolve/main/flux-hed-controlnet-v3.safetensors",
"size": "1.49GB"
},
{
"name": "XLabs-AI/realism_lora.safetensors",
"type": "lora",
"base": "FLUX.1",
"save_path": "xlabs/loras",
"description": "A checkpoint with trained LoRAs for FLUX.1-dev model by Black Forest Labs",
"reference": "https://huggingface.co/XLabs-AI/flux-lora-collection",
"filename": "realism_lora.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/realism_lora.safetensors",
"size": "44.8MB"
},
{
"name": "XLabs-AI/art_lora.safetensors",
"type": "lora",
"base": "FLUX.1",
"save_path": "xlabs/loras",
"description": "A checkpoint with trained LoRAs for FLUX.1-dev model by Black Forest Labs",
"reference": "https://huggingface.co/XLabs-AI/flux-lora-collection",
"filename": "art_lora.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/scenery_lora.safetensors",
"size": "44.8MB"
},
{
"name": "XLabs-AI/mjv6_lora.safetensors",
"type": "lora",
"base": "FLUX.1",
"save_path": "xlabs/loras",
"description": "A checkpoint with trained LoRAs for FLUX.1-dev model by Black Forest Labs",
"reference": "https://huggingface.co/XLabs-AI/flux-lora-collection",
"filename": "mjv6_lora.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-lora-collection/resolve/main/mjv6_lora.safetensors",
"size": "44.8MB"
},
{
"name": "XLabs-AI/flux-ip-adapter",
"type": "lora",
"base": "FLUX.1",
"save_path": "xlabs/ipadapters",
"description": "A checkpoint with trained LoRAs for FLUX.1-dev model by Black Forest Labs",
"reference": "https://huggingface.co/XLabs-AI/flux-ip-adapter",
"filename": "ip_adapter.safetensors",
"url": "https://huggingface.co/XLabs-AI/flux-ip-adapter/resolve/main/ip_adapter.safetensors",
"size": "982MB"
},
{
"name": "stabilityai/SD3.5-Large-Controlnet-Blur",
"type": "controlnet",
"base": "SD3.5",
"save_path": "controlnet/SD3.5",
"description": "Blur Controlnet model for SD3.5 Large",
"reference": "https://huggingface.co/stabilityai/stable-diffusion-3.5-controlnets",
"filename": "sd3.5_large_controlnet_blur.safetensors",
"url": "https://huggingface.co/stabilityai/stable-diffusion-3.5-controlnets/resolve/main/sd3.5_large_controlnet_blur.safetensors",
"size": "8.65GB"
},
{
"name": "stabilityai/SD3.5-Large-Controlnet-Canny",
"type": "controlnet",
"base": "SD3.5",
"save_path": "controlnet/SD3.5",
"description": "Canny Controlnet model for SD3.5 Large",
"reference": "https://huggingface.co/stabilityai/stable-diffusion-3.5-controlnets",
"filename": "sd3.5_large_controlnet_canny.safetensors",
"url": "https://huggingface.co/stabilityai/stable-diffusion-3.5-controlnets/resolve/main/sd3.5_large_controlnet_canny.safetensors",
"size": "8.65GB"
},
{
"name": "stabilityai/SD3.5-Large-Controlnet-Depth",
"type": "controlnet",
"base": "SD3.5",
"save_path": "controlnet/SD3.5",
"description": "Depth Controlnet model for SD3.5 Large",
"reference": "https://huggingface.co/stabilityai/stable-diffusion-3.5-controlnets",
"filename": "sd3.5_large_controlnet_depth.safetensors",
"url": "https://huggingface.co/stabilityai/stable-diffusion-3.5-controlnets/resolve/main/sd3.5_large_controlnet_depth.safetensors",
"size": "8.65GB"
},
{
"name": "LTX-Video 2B v0.9 Checkpoint",
"type": "checkpoint",
"base": "LTX-Video",
"save_path": "checkpoints/LTXV",
"description": "LTX-Video is the first DiT-based video generation model capable of generating high-quality videos in real-time. It produces 24 FPS videos at a 768x512 resolution faster than they can be watched. Trained on a large-scale dataset of diverse videos, the model generates high-resolution videos with realistic and varied content.",
"reference": "https://huggingface.co/Lightricks/LTX-Video",
"filename": "ltx-video-2b-v0.9.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltx-video-2b-v0.9.safetensors",
"size": "9.37GB"
},
{
"name": "InstantX/FLUX.1-dev-IP-Adapter",
"type": "IP-Adapter",
"base": "FLUX.1",
"save_path": "ipadapter-flux",
"description": "FLUX.1-dev-IP-Adapter",
"reference": "https://huggingface.co/InstantX/FLUX.1-dev-IP-Adapter",
"filename": "ip-adapter.bin",
"url": "https://huggingface.co/InstantX/FLUX.1-dev-IP-Adapter/resolve/main/ip-adapter.bin",
"size": "5.29GB"
},
{
"name": "Comfy-Org/sigclip_vision_384 (patch14_384)",
"type": "clip_vision",
"base": "sigclip",
"save_path": "clip_vision",
"description": "This clip vision model is required for FLUX.1 Redux.",
"reference": "https://huggingface.co/Comfy-Org/sigclip_vision_384/tree/main",
"filename": "sigclip_vision_patch14_384.safetensors",
"url": "https://huggingface.co/Comfy-Org/sigclip_vision_384/resolve/main/sigclip_vision_patch14_384.safetensors",
"size": "857MB"
}
]
}

View File

@@ -331,6 +331,26 @@
],
"description": "Dynamic Node examples for ComfyUI",
"install_type": "git-clone"
},
{
"author": "Jonathon-Doran",
"title": "remote-combo-demo",
"reference": "https://github.com/Jonathon-Doran/remote-combo-demo",
"files": [
"https://github.com/Jonathon-Doran/remote-combo-demo"
],
"install_type": "git-clone",
"description": "A minimal test suite demonstrating how remote COMBO inputs behave in ComfyUI, with and without force_input"
},
{
"author": "J1mB091",
"title": "ComfyUI-J1mB091 Custom Nodes",
"reference": "https://github.com/J1mB091/ComfyUI-J1mB091",
"files": [
"https://github.com/J1mB091/ComfyUI-J1mB091"
],
"install_type": "git-clone",
"description": "Vibe Coded ComfyUI Custom Nodes"
}
]
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "comfyui-manager"
license = { text = "GPL-3.0-only" }
version = "4.0.0-beta.4"
version = "4.0.1-beta.5"
requires-python = ">= 3.9"
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
readme = "README.md"
@@ -13,9 +13,9 @@ keywords = ["comfyui", "comfyui-manager"]
maintainers = [
{ name = "Dr.Lt.Data", email = "dr.lt.data@gmail.com" },
{ name = "Yoland Yan", email = "yoland@drip.art" },
{ name = "Yoland Yan", email = "yoland@comfy.org" },
{ name = "James Kwon", email = "hongilkwon316@gmail.com" },
{ name = "Robin Huang", email = "robin@drip.art" },
{ name = "Robin Huang", email = "robin@comfy.org" },
]
classifiers = [
@@ -25,16 +25,16 @@ classifiers = [
]
dependencies = [
"GitPython",
"PyGithub",
"matrix-client==0.4.0",
"transformers",
"huggingface-hub>0.20",
"typer",
"rich",
"typing-extensions",
"toml",
"uv",
"GitPython",
"PyGithub",
# "matrix-nio",
"transformers",
"huggingface-hub>0.20",
"typer",
"rich",
"typing-extensions",
"toml",
"uv",
"chardet"
]

View File

@@ -1,6 +1,6 @@
GitPython
PyGithub
matrix-client==0.4.0
# matrix-nio
transformers
huggingface-hub>0.20
typer

View File

@@ -255,13 +255,13 @@ def clone_or_pull_git_repository(git_url):
repo.git.submodule('update', '--init', '--recursive')
print(f"Pulling {repo_name}...")
except Exception as e:
print(f"Pulling {repo_name} failed: {e}")
print(f"Failed to pull '{repo_name}': {e}")
else:
try:
Repo.clone_from(git_url, repo_dir, recursive=True)
print(f"Cloning {repo_name}...")
except Exception as e:
print(f"Cloning {repo_name} failed: {e}")
print(f"Failed to clone '{repo_name}': {e}")
def update_custom_nodes():
@@ -496,8 +496,15 @@ def gen_json(node_info):
nodes_in_url, metadata_in_url = data[git_url]
nodes = set(nodes_in_url)
for x, desc in node_list_json.items():
nodes.add(x.strip())
try:
for x, desc in node_list_json.items():
nodes.add(x.strip())
except Exception as e:
print(f"\nERROR: Invalid json format '{node_list_json_path}'")
print("------------------------------------------------------")
print(e)
print("------------------------------------------------------")
node_list_json = {}
metadata_in_url['title_aux'] = title