Compare commits

..

2 Commits

Author SHA1 Message Date
Dr.Lt.Data
24ca0ab538 fix: Issue where the ComfyUI hash difference was not appearing in v2/snapshot/diff. 2025-07-29 23:22:19 +09:00
Dr.Lt.Data
62da330182 added: /v2/snapshot/diff
modified: use 'packaging.version` instead custom StrictVersion
2025-07-29 23:15:11 +09:00
35 changed files with 8431 additions and 20080 deletions

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch:
push:
branches:
- draft-v4
- main
paths:
- "pyproject.toml"
@@ -21,7 +21,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
python-version: '3.9'
- 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: ${{ 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: ${{ secrets.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@76f52bc884231f62b9a034ebfe128415bbaabdfc
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_TOKEN }}
skip-existing: true
verbose: true
verbose: true

25
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
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 }}

View File

@@ -211,7 +211,6 @@ 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
@@ -223,7 +222,6 @@ 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

@@ -15,7 +15,7 @@ import re
import logging
import platform
import shlex
from packaging import version
cache_lock = threading.Lock()
session_lock = threading.Lock()
@@ -58,62 +58,32 @@ def make_pip_cmd(cmd):
# print(f"[ComfyUI-Manager] 'distutils' package not found. Activating fallback mode for compatibility.")
class StrictVersion:
def __init__(self, version_string):
self.obj = version.parse(version_string)
self.version_string = version_string
self.major = 0
self.minor = 0
self.patch = 0
self.pre_release = None
self.parse_version_string()
def parse_version_string(self):
parts = self.version_string.split('.')
if not parts:
raise ValueError("Version string must not be empty")
self.major = int(parts[0])
self.minor = int(parts[1]) if len(parts) > 1 else 0
self.patch = int(parts[2]) if len(parts) > 2 else 0
# Handling pre-release versions if present
if len(parts) > 3:
self.pre_release = parts[3]
self.major = self.obj.major
self.minor = self.obj.minor
self.patch = self.obj.micro
def __str__(self):
version = f"{self.major}.{self.minor}.{self.patch}"
if self.pre_release:
version += f"-{self.pre_release}"
return version
return self.version_string
def __eq__(self, other):
return (self.major, self.minor, self.patch, self.pre_release) == \
(other.major, other.minor, other.patch, other.pre_release)
return self.obj == other.obj
def __lt__(self, other):
if (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch):
return self.pre_release_compare(self.pre_release, other.pre_release) < 0
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
@staticmethod
def pre_release_compare(pre1, pre2):
if pre1 == pre2:
return 0
if pre1 is None:
return 1
if pre2 is None:
return -1
return -1 if pre1 < pre2 else 1
return self.obj < other.obj
def __le__(self, other):
return self == other or self < other
return self.obj == other.obj or self.obj < other.obj
def __gt__(self, other):
return not self <= other
return not self.obj <= other.obj
def __ge__(self, other):
return not self < other
return not self.obj < other.obj
def __ne__(self, other):
return not self == other
return not self.obj == other.obj
def simple_hash(input_string):

View File

@@ -0,0 +1,136 @@
from . import manager_util
from . import git_utils
import json
import yaml
import logging
def read_snapshot(snapshot_path):
try:
with open(snapshot_path, 'r', encoding="UTF-8") as snapshot_file:
if snapshot_path.endswith('.json'):
info = json.load(snapshot_file)
elif snapshot_path.endswith('.yaml'):
info = yaml.load(snapshot_file, Loader=yaml.SafeLoader)
info = info['custom_nodes']
return info
except Exception as e:
logging.warning(f"Failed to read snapshot file: {snapshot_path}\nError: {e}")
return None
def diff_snapshot(a, b):
if not a or not b:
return None
nodepack_diff = {
'added': {},
'removed': [],
'upgraded': {},
'downgraded': {},
'changed': []
}
pip_diff = {
'added': {},
'upgraded': {},
'downgraded': {}
}
# check: comfyui
if a.get('comfyui') != b.get('comfyui'):
nodepack_diff['changed'].append('comfyui')
# check: cnr nodes
a_cnrs = a.get('cnr_custom_nodes', {})
b_cnrs = b.get('cnr_custom_nodes', {})
if 'comfyui-manager' in a_cnrs:
del a_cnrs['comfyui-manager']
if 'comfyui-manager' in b_cnrs:
del b_cnrs['comfyui-manager']
for k, v in a_cnrs.items():
if k not in b_cnrs.keys():
nodepack_diff['removed'].append(k)
elif a_cnrs[k] != b_cnrs[k]:
a_ver = manager_util.StrictVersion(a_cnrs[k])
b_ver = manager_util.StrictVersion(b_cnrs[k])
if a_ver < b_ver:
nodepack_diff['upgraded'][k] = {'from': a_cnrs[k], 'to': b_cnrs[k]}
elif a_ver > b_ver:
nodepack_diff['downgraded'][k] = {'from': a_cnrs[k], 'to': b_cnrs[k]}
added_cnrs = set(b_cnrs.keys()) - set(a_cnrs.keys())
for k in added_cnrs:
nodepack_diff['added'][k] = b_cnrs[k]
# check: git custom nodes
a_gits = a.get('git_custom_nodes', {})
b_gits = b.get('git_custom_nodes', {})
a_gits = {git_utils.normalize_url(k): v for k, v in a_gits.items() if k.lower() != 'comfyui-manager'}
b_gits = {git_utils.normalize_url(k): v for k, v in b_gits.items() if k.lower() != 'comfyui-manager'}
for k, v in a_gits.items():
if k not in b_gits.keys():
nodepack_diff['removed'].append(k)
elif not v['disabled'] and b_gits[k]['disabled']:
nodepack_diff['removed'].append(k)
elif v['disabled'] and not b_gits[k]['disabled']:
nodepack_diff['added'].append(k)
elif v['hash'] != b_gits[k]['hash']:
a_date = v.get('commit_timestamp')
b_date = b_gits[k].get('commit_timestamp')
if a_date is not None and b_date is not None:
if a_date < b_date:
nodepack_diff['upgraded'].append(k)
elif a_date > b_date:
nodepack_diff['downgraded'].append(k)
else:
nodepack_diff['changed'].append(k)
# check: pip packages
a_pip = a.get('pips', {})
b_pip = b.get('pips', {})
for k, v in a_pip.items():
if '==' in k:
package_name, version = k.split('==', 1)
else:
package_name, version = k, None
for k2, v2 in b_pip.items():
if '==' in k2:
package_name2, version2 = k2.split('==', 1)
else:
package_name2, version2 = k2, None
if package_name.lower() == package_name2.lower():
if version != version2:
a_ver = manager_util.StrictVersion(version) if version else None
b_ver = manager_util.StrictVersion(version2) if version2 else None
if a_ver and b_ver:
if a_ver < b_ver:
pip_diff['upgraded'][package_name] = {'from': version, 'to': version2}
elif a_ver > b_ver:
pip_diff['downgraded'][package_name] = {'from': version, 'to': version2}
elif not a_ver and b_ver:
pip_diff['added'][package_name] = version2
a_pip_names = {k.split('==', 1)[0].lower() for k in a_pip.keys()}
for k in b_pip.keys():
if '==' in k:
package_name = k.split('==', 1)[0]
package_version = k.split('==', 1)[1]
else:
package_name = k
package_version = None
if package_name.lower() not in a_pip_names:
if package_version:
pip_diff['added'][package_name] = package_version
return {'nodepack_diff': nodepack_diff, 'pip_diff': pip_diff}

View File

@@ -30,12 +30,6 @@ from .generated_models import (
InstalledModelInfo,
ComfyUIVersionInfo,
# Import Fail Info Models
ImportFailInfoBulkRequest,
ImportFailInfoBulkResponse,
ImportFailInfoItem,
ImportFailInfoItem1,
# Other models
OperationType,
OperationResult,
@@ -94,12 +88,6 @@ __all__ = [
"InstalledModelInfo",
"ComfyUIVersionInfo",
# Import Fail Info Models
"ImportFailInfoBulkRequest",
"ImportFailInfoBulkResponse",
"ImportFailInfoItem",
"ImportFailInfoItem1",
# Other models
"OperationType",
"OperationResult",

View File

@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: openapi.yaml
# timestamp: 2025-07-31T04:52:26+00:00
# timestamp: 2025-06-27T04:01:45+00:00
from __future__ import annotations
@@ -454,24 +454,6 @@ class BatchExecutionRecord(BaseModel):
)
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")
@@ -555,7 +537,3 @@ class HistoryResponse(BaseModel):
history: Optional[Dict[str, TaskHistoryItem]] = Field(
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

@@ -41,12 +41,11 @@ from ..common.enums import NetworkMode, SecurityLevel, DBMode
from ..common import context
version_code = [4, 0, 1]
version_code = [4, 0]
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
@@ -154,8 +153,14 @@ def check_invalid_nodes():
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', DEFAULT_CHANNEL, DEFAULT_CHANNEL_LEGACY}
valid_channels = {'default', 'local'}
channel_list = None
@@ -1474,7 +1479,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['original_name'], None
return module_name, cnr['version'], cnr['id'], None
return None
else:
@@ -1524,10 +1529,7 @@ def get_installed_node_packs():
if info is None:
continue
# 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 }
res[info[0]] = { 'ver': info[1], 'cnr_id': info[2], 'aux_id': info[3], 'enabled': False }
return res
@@ -1784,6 +1786,16 @@ 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)
@@ -2421,17 +2433,14 @@ def update_to_stable_comfyui(repo_path):
versions, current_tag, _ = get_comfyui_versions(repo)
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:
if len(versions) == 0 or (len(versions) == 1 and versions[0] == 'nightly'):
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
@@ -2637,8 +2646,8 @@ async def get_current_snapshot(custom_nodes_only = False):
commit_hash = git_utils.get_commit_hash(fullpath)
url = git_utils.git_url(fullpath)
git_custom_nodes[url] = dict(hash=commit_hash, disabled=is_disabled)
except Exception:
print(f"Failed to extract snapshots for the custom node '{path}'.")
except Exception as e:
print(f"Failed to extract snapshots for the custom node '{path}'. / {e}")
elif path.endswith('.py'):
is_disabled = path.endswith(".py.disabled")
@@ -3256,65 +3265,35 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
def get_comfyui_versions(repo=None):
repo = repo or git.Repo(context.comfy_path)
if repo is None:
repo = 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")
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
versions = [x.name for x in repo.tags if x.name.startswith('v')]
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
# nearest tag
versions = sorted(versions, key=lambda v: repo.git.log('-1', '--format=%ct', v), reverse=True)
versions = versions[:4]
# 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)
current_tag = repo.git.describe('--tags')
try:
raw_current_tag = repo.git.describe('--tags')
except Exception:
raw_current_tag = ''
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]
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
main_branch = repo.heads.master
latest_commit = main_branch.commit
latest_tag = repo.git.describe('--tags', latest_commit.hexsha)
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:
if latest_tag != versions[0]:
versions.insert(0, 'nightly')
else:
versions[0] = 'nightly'
current_tag = 'nightly'
return versions, current_tag, latest_tag

View File

@@ -47,7 +47,7 @@ from ..common import manager_util
from ..common import cm_global
from ..common import manager_downloader
from ..common import context
from ..common import snapshot_util
from ..data_models import (
@@ -61,7 +61,6 @@ from ..data_models import (
ManagerMessageName,
BatchExecutionRecord,
ComfyUISystemState,
ImportFailInfoBulkRequest,
BatchOperation,
InstalledNodeInfo,
ComfyUIVersionInfo,
@@ -1594,6 +1593,46 @@ async def save_snapshot(request):
return web.Response(status=400)
@routes.get("/v2/snapshot/diff")
async def get_snapshot_diff(request):
try:
from_id = request.rel_url.query.get("from")
to_id = request.rel_url.query.get("to")
if (from_id is not None and '..' in from_id) or (to_id is not None and '..' in to_id):
logging.error("/v2/snapshot/diff: invalid 'from' or 'to' parameter.")
return web.Response(status=400)
if from_id is None:
from_json = await core.get_current_snapshot()
else:
from_path = os.path.join(context.manager_snapshot_path, f"{from_id}.json")
if not os.path.exists(from_path):
logging.error(f"/v2/snapshot/diff: 'from' parameter file not found: {from_path}")
return web.Response(status=400)
from_json = snapshot_util.read_snapshot(from_path)
if to_id is None:
logging.error("/v2/snapshot/diff: 'to' parameter is required.")
return web.Response(status=401)
else:
to_path = os.path.join(context.manager_snapshot_path, f"{to_id}.json")
if not os.path.exists(to_path):
logging.error(f"/v2/snapshot/diff: 'to' parameter file not found: {to_path}")
return web.Response(status=400)
to_json = snapshot_util.read_snapshot(to_path)
return web.json_response(snapshot_util.diff_snapshot(from_json, to_json), content_type='application/json')
except Exception as e:
logging.error(f"[ComfyUI-Manager] Error in /v2/snapshot/diff: {e}")
traceback.print_exc()
# Return a generic error response
return web.Response(status=400)
def unzip_install(files):
temp_filename = "manager-temp.zip"
for url in files:
@@ -1657,67 +1696,6 @@ async def import_fail_info(request):
return web.Response(status=500, text="Internal server error")
@routes.post("/v2/customnode/import_fail_info_bulk")
async def import_fail_info_bulk(request):
try:
json_data = await request.json()
# Validate input using Pydantic model
request_data = ImportFailInfoBulkRequest.model_validate(json_data)
# Ensure we have either cnr_ids or urls
if not request_data.cnr_ids and not request_data.urls:
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 request_data.cnr_ids:
for cnr_id in request_data.cnr_ids:
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:
# Convert error_dict format to API spec format
results[cnr_id] = {
'error': info.get('msg', ''),
'traceback': info.get('traceback', '')
}
else:
results[cnr_id] = None
else:
results[cnr_id] = None
if request_data.urls:
for url in request_data.urls:
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:
# Convert error_dict format to API spec format
results[url] = {
'error': info.get('msg', ''),
'traceback': info.get('traceback', '')
}
else:
results[url] = None
else:
results[url] = None
# Return results directly as JSON
return web.json_response(results, content_type="application/json")
except ValidationError as e:
logging.error(f"[ComfyUI-Manager] Invalid request data: {e}")
return web.Response(status=400, text=f"Invalid request data: {e}")
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.get("/v2/manager/queue/reset")
async def reset_queue(request):
logging.debug("[ComfyUI-Manager] Queue reset requested")

View File

@@ -11,15 +11,6 @@ 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):
@@ -202,14 +193,6 @@ 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']
@@ -349,12 +332,15 @@ async def share_art(request):
workflowId = upload_workflow_json["workflowId"]
# check if the user has provided Matrix credentials
if matrix_nio_is_available and "matrix" in share_destinations:
if "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')
@@ -362,35 +348,20 @@ async def share_art(request):
if not homeserver.startswith("https://"):
homeserver = "https://" + homeserver
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()
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:
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
# Upload asset
matrix = MatrixHttpApi(homeserver, token=token)
with open(asset_filepath, 'rb') as f:
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
mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['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
workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri']
# Send text message
text_content = ""
if title:
text_content += f"{title}\n"
@@ -398,47 +369,11 @@ async def share_art(request):
text_content += f"{description}\n"
if credits:
text_content += f"\ncredits: {credits}\n"
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()
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")
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

@@ -1514,6 +1514,8 @@ app.registerExtension({
tooltip: "Share"
}).element
);
app.menu?.settingsGroup.element.before(cmGroup.element);
}
catch(exception) {
console.log('ComfyUI is outdated. New style menu based features are disabled.');

View File

@@ -552,20 +552,6 @@ 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

@@ -201,15 +201,13 @@ export class CopusShareDialog extends ComfyDialog {
});
this.LockInput = $el("input", {
type: "text",
placeholder: "0",
placeholder: "",
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;
@@ -377,7 +375,7 @@ export class CopusShareDialog extends ComfyDialog {
});
const blockChainSection_lock = $el("div", { style: sectionStyle }, [
$el("label", { style: labelStyle }, ["6Download threshold"]),
$el("label", { style: labelStyle }, ["6Pay to download"]),
$el(
"label",
{
@@ -397,7 +395,6 @@ export class CopusShareDialog extends ComfyDialog {
marginLeft: "5px",
display: "flex",
alignItems: "center",
position: "relative",
},
},
[
@@ -411,18 +408,8 @@ export class CopusShareDialog extends ComfyDialog {
color: "#fff",
},
},
["Unlock with"]
["Price US$"]
),
$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,
]
),
@@ -433,7 +420,7 @@ export class CopusShareDialog extends ComfyDialog {
{ style: { display: "flex", alignItems: "center", cursor: "pointer" } },
[
this.radioButtonsCheckOff_lock,
$el(
$el(
"div",
{
style: {
@@ -442,7 +429,9 @@ export class CopusShareDialog extends ComfyDialog {
alignItems: "center",
},
},
[$el("span", { style: { marginLeft: "5px" } }, ["OFF"])]
[
$el("span", { style: { marginLeft: "5px" } }, ["OFF"]),
]
),
]
),
@@ -451,6 +440,7 @@ export class CopusShareDialog extends ComfyDialog {
"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.",
]
),
]);

View File

@@ -1626,35 +1626,17 @@ export class CustomNodesManager {
getNodesInWorkflow() {
let usedGroupNodes = new Set();
let allUsedNodes = {};
const visitedGraphs = new Set();
const visitGraph = (graph) => {
if (!graph || visitedGraphs.has(graph)) return;
visitedGraphs.add(graph);
for(let k in app.graph._nodes) {
let node = app.graph._nodes[k];
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;
if(node.type.startsWith('workflow>')) {
usedGroupNodes.add(node.type.slice(9));
continue;
}
};
visitGraph(app.graph);
allUsedNodes[node.type] = node;
}
for(let k of usedGroupNodes) {
let subnodes = app.graph.extra.groupNodes[k]?.nodes;

View File

@@ -46,7 +46,6 @@ 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
@@ -161,7 +160,7 @@ comfy_ui_revision = "Unknown"
comfy_ui_commit_datetime = datetime(1900, 1, 1, 0, 0, 0)
channel_dict = None
valid_channels = {'default', 'local', DEFAULT_CHANNEL, DEFAULT_CHANNEL_LEGACY}
valid_channels = {'default', 'local'}
channel_list = None

View File

@@ -24,6 +24,7 @@ from ..common import cm_global
from ..common import manager_downloader
from ..common import context
from ..common import manager_security
from ..common import snapshot_util
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
@@ -1072,15 +1073,12 @@ async def fetch_customnode_list(request):
if channel != 'local':
found = 'custom'
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
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.to_dict())
@@ -1171,7 +1169,7 @@ async def fetch_externalmodel_list(request):
return web.json_response(json_obj, content_type='application/json')
@PromptServer.instance.routes.get("/v2/snapshot/getlist")
@routes.get("/v2/snapshot/getlist")
async def get_snapshot_list(request):
items = [f[:-5] for f in os.listdir(context.manager_snapshot_path) if f.endswith('.json')]
items.sort(reverse=True)
@@ -1239,6 +1237,46 @@ async def save_snapshot(request):
return web.Response(status=400)
@routes.get("/v2/snapshot/diff")
async def get_snapshot_diff(request):
try:
from_id = request.rel_url.query.get("from")
to_id = request.rel_url.query.get("to")
if (from_id is not None and '..' in from_id) or (to_id is not None and '..' in to_id):
logging.error("/v2/snapshot/diff: invalid 'from' or 'to' parameter.")
return web.Response(status=400)
if from_id is None:
from_json = await core.get_current_snapshot()
else:
from_path = os.path.join(context.manager_snapshot_path, f"{from_id}.json")
if not os.path.exists(from_path):
logging.error(f"/v2/snapshot/diff: 'from' parameter file not found: {from_path}")
return web.Response(status=400)
from_json = snapshot_util.read_snapshot(from_path)
if to_id is None:
logging.error("/v2/snapshot/diff: 'to' parameter is required.")
return web.Response(status=401)
else:
to_path = os.path.join(context.manager_snapshot_path, f"{to_id}.json")
if not os.path.exists(to_path):
logging.error(f"/v2/snapshot/diff: 'to' parameter file not found: {to_path}")
return web.Response(status=400)
to_json = snapshot_util.read_snapshot(to_path)
return web.json_response(snapshot_util.diff_snapshot(from_json, to_json), content_type='application/json')
except Exception as e:
logging.error(f"[ComfyUI-Manager] Error in /v2/snapshot/diff: {e}")
traceback.print_exc()
# Return a generic error response
return web.Response(status=400)
def unzip_install(files):
temp_filename = 'manager-temp.zip'
for url in files:
@@ -1311,65 +1349,6 @@ 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)

View File

@@ -10,16 +10,6 @@ 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):
@@ -202,14 +192,6 @@ 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']
@@ -349,12 +331,14 @@ async def share_art(request):
workflowId = upload_workflow_json["workflowId"]
# check if the user has provided Matrix credentials
if matrix_nio_is_available and "matrix" in share_destinations:
if "matrix" in share_destinations:
comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org'
filename = os.path.basename(asset_filepath)
content_type = assetFileType
try:
from nio import AsyncClient, LoginResponse, UploadResponse
homeserver = 'matrix.org'
if matrix_auth:
homeserver = matrix_auth.get('homeserver', 'matrix.org')

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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -5045,105 +5045,6 @@
"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",

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,15 +1,5 @@
{
"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",

View File

@@ -1,282 +1,8 @@
{
"custom_nodes": [
{
"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": "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]",
"title": "ComfyUI-DreamFit []REMOVED]",
"reference": "https://github.com/skayka/ComfyUI-DreamFit",
"files": [
"https://github.com/skayka/ComfyUI-DreamFit"

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,106 +1,5 @@
{
"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",
@@ -687,6 +586,109 @@
"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"
}
]
}

View File

@@ -341,16 +341,6 @@
],
"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

@@ -782,39 +782,6 @@ components:
minimum: 0
default: 0
required: [batch_id, start_time, state_before]
ImportFailInfoBulkRequest:
type: object
properties:
cnr_ids:
type: array
items:
type: string
description: A list of CNR IDs to check.
urls:
type: array
items:
type: string
description: A list of repository URLs to check.
ImportFailInfoBulkResponse:
type: object
additionalProperties:
$ref: '#/components/schemas/ImportFailInfoItem'
description: >-
A dictionary where each key is a cnr_id or url from the request,
and the value is the corresponding error info.
ImportFailInfoItem:
oneOf:
- type: object
properties:
error:
type: string
traceback:
type: string
- type: "null"
securitySchemes:
securityLevel:
type: apiKey
@@ -1050,32 +1017,6 @@ paths:
description: Processing started
'201':
description: Processing already in progress
/v2/customnode/import_fail_info_bulk:
post:
summary: Get import failure info for multiple nodes
description: Retrieves recorded import failure information for a list of custom nodes.
tags:
- customnode
requestBody:
description: A list of CNR IDs or repository URLs to check.
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ImportFailInfoBulkRequest'
responses:
'200':
description: A dictionary containing the import failure information.
content:
application/json:
schema:
$ref: '#/components/schemas/ImportFailInfoBulkResponse'
'400':
description: Bad Request. The request body is invalid.
'500':
description: Internal Server Error.
/v2/manager/queue/reset:
get:
summary: Reset queue
@@ -1268,6 +1209,89 @@ paths:
description: Snapshot saved successfully
'400':
description: Error saving snapshot
/v2/snapshot/diff:
get:
summary: Get snapshot diff
description: Returns the changes that would occur when restoring from the 'from' snapshot to the 'to' snapshot.
parameters:
- name: from
in: query
required: false
description: This parameter refers to the existing snapshot; if omitted, it defaults to the current snapshot.
schema:
type: string
- name: to
in: query
required: true
description: This parameter is the snapshot to compare against the existing snapshot.
schema:
type: string
responses:
'200':
description: Successful operation
content:
application/json:
schema:
type: object
properties:
nodepack_diff:
type: object
properties:
added:
type: object
additionalProperties:
type: string
removed:
type: array
items:
type: string
upgraded:
type: object
additionalProperties:
type: object
properties:
from:
type: string
to:
type: string
downgraded:
type: object
additionalProperties:
type: object
properties:
from:
type: string
to:
type: string
changed:
type: array
items:
type: string
pip_diff:
type: object
properties:
added:
type: object
additionalProperties:
type: string
upgraded:
type: object
additionalProperties:
type: object
properties:
from:
type: string
to:
type: string
downgraded:
type: object
additionalProperties:
type: object
properties:
from:
type: string
to:
type: string
# ComfyUI Management Endpoints (v2)
/v2/comfyui_manager/comfyui_versions:
get:

View File

@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "comfyui-manager"
license = { text = "GPL-3.0-only" }
version = "4.0.1-beta.5"
version = "4.0.0-beta.10"
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"
@@ -27,7 +27,7 @@ classifiers = [
dependencies = [
"GitPython",
"PyGithub",
# "matrix-nio",
"matrix-client==0.4.0",
"transformers",
"huggingface-hub>0.20",
"typer",

View File

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