mirror of
https://github.com/Comfy-Org/ComfyUI-Manager.git
synced 2026-05-14 19:07:28 +08:00
Compare commits
54 Commits
e9fa427f40
...
6b524eb238
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b524eb238 | ||
|
|
8d5c12037f | ||
|
|
d370403e2d | ||
|
|
e67e35795e | ||
|
|
ccf6d98457 | ||
|
|
113324728e | ||
|
|
f2a3d39e26 | ||
|
|
ec72d983ad | ||
|
|
a3aabfd72c | ||
|
|
03272b1f70 | ||
|
|
66108ccdbc | ||
|
|
abf9c654b3 | ||
|
|
491f847bbc | ||
|
|
d57c142019 | ||
|
|
6a26409bcb | ||
|
|
bbc223a76c | ||
|
|
aba857a350 | ||
|
|
74c2518894 | ||
|
|
98e0098ddd | ||
|
|
ed56212fa0 | ||
|
|
22fc850853 | ||
|
|
15fd6dbe37 | ||
|
|
f1863994f4 | ||
|
|
7c0fa1c581 | ||
|
|
dcb15d4dc9 | ||
|
|
6be5491d9e | ||
|
|
1e8956f42e | ||
|
|
d7adab215b | ||
|
|
15ec9a901b | ||
|
|
e9fd8a3078 | ||
|
|
980f8f58af | ||
|
|
9b37dcfe42 | ||
|
|
2f1d02b688 | ||
|
|
685dca9749 | ||
|
|
03b54019ff | ||
|
|
92a47f59cf | ||
|
|
bae0ac11c5 | ||
|
|
f016eadd64 | ||
|
|
0f13355b08 | ||
|
|
bf5efd72ff | ||
|
|
0fc4649d23 | ||
|
|
3842e70fd9 | ||
|
|
0952dd1686 | ||
|
|
a7fb42be01 | ||
|
|
ee0f446ad0 | ||
|
|
b220733094 | ||
|
|
5079365034 | ||
|
|
454f24145e | ||
|
|
9d838d302f | ||
|
|
928cc80088 | ||
|
|
a54ab14c37 | ||
|
|
ba5aca7122 | ||
|
|
715c6c2426 | ||
|
|
e51a83fc8c |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
12146
github-stats.json
12146
github-stats.json
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,7 @@ import manager_migration
|
||||
from node_package import InstalledNodePackage
|
||||
|
||||
|
||||
version_code = [3, 39, 2]
|
||||
version_code = [3, 40]
|
||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||
|
||||
|
||||
|
||||
@ -312,6 +312,57 @@ def security_403_response():
|
||||
return web.json_response({"error": "security_level"}, status=403)
|
||||
|
||||
|
||||
# CORS "simple request" Content-Type set per Fetch spec §3.2.3. Browsers send
|
||||
# <form method=POST> submissions with one of these three MIME types and do NOT
|
||||
# trigger a CORS preflight, so a malicious cross-origin page can silently POST
|
||||
# into state-changing endpoints if we only gate on HTTP method. Blocking these
|
||||
# three Content-Types on no-body mutation endpoints forces any non-same-origin
|
||||
# POST to use a non-simple Content-Type (e.g. application/json), which triggers
|
||||
# a preflight that this server rejects by not advertising an Access-Control-
|
||||
# Allow-Origin response.
|
||||
_SIMPLE_FORM_CONTENT_TYPES = frozenset({
|
||||
'application/x-www-form-urlencoded',
|
||||
'multipart/form-data',
|
||||
'text/plain',
|
||||
})
|
||||
|
||||
|
||||
def _reject_simple_form_content_type(request):
|
||||
"""Reject Content-Types that enable preflight-less <form method=POST> CSRF.
|
||||
|
||||
Applied ONLY to POST handlers that do not consume a request body (e.g.,
|
||||
/snapshot/save, /manager/queue/{reset,start,update_comfyui},
|
||||
/manager/reboot). These are vulnerable to cross-origin <form method=POST>
|
||||
attacks because the handler accepts the request without parsing any body —
|
||||
the attacker needs no ability to forge a valid payload, only to point a
|
||||
hidden form at the URL.
|
||||
|
||||
Handlers that already read a body via ``await request.json()`` are NOT
|
||||
gated here: a cross-origin <form method=POST> cannot forge a valid JSON
|
||||
body because the browser refuses to send ``application/json`` without a
|
||||
CORS preflight, which this server does not answer.
|
||||
|
||||
DO NOT add this gate to body-reading handlers — redundant and UX-breaking.
|
||||
DO NOT remove this gate from no-body handlers — this is the bypass vector.
|
||||
|
||||
aiohttp's ``request.content_type`` normalizes the header (lower-cases,
|
||||
strips parameters), so ``multipart/form-data; boundary=----X`` is compared
|
||||
as ``multipart/form-data``.
|
||||
|
||||
Returns:
|
||||
web.Response(status=400) when the request has a simple-form
|
||||
Content-Type that must be rejected. None when the request is allowed
|
||||
to proceed (no Content-Type, application/json, or any non-simple
|
||||
Content-Type).
|
||||
"""
|
||||
if request.content_type in _SIMPLE_FORM_CONTENT_TYPES:
|
||||
return web.Response(
|
||||
status=400,
|
||||
text='Invalid Content-Type for this endpoint. Use application/json or omit body.',
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def get_model_dir(data, show_log=False):
|
||||
if 'download_model_base' in folder_paths.folder_names_and_paths:
|
||||
models_base = folder_paths.folder_names_and_paths['download_model_base'][0][0]
|
||||
@ -737,16 +788,19 @@ async def fetch_customnode_mappings(request):
|
||||
return web.json_response(json_obj, content_type='application/json')
|
||||
|
||||
|
||||
@routes.get("/customnode/fetch_updates")
|
||||
@routes.post("/customnode/fetch_updates")
|
||||
async def fetch_updates(request):
|
||||
try:
|
||||
if request.rel_url.query["mode"] == "local":
|
||||
json_data = await request.json()
|
||||
mode = json_data.get("mode", "default")
|
||||
|
||||
if mode == "local":
|
||||
channel = 'local'
|
||||
else:
|
||||
channel = core.get_config()['channel_url']
|
||||
|
||||
await core.unified_manager.reload(request.rel_url.query["mode"])
|
||||
await core.unified_manager.get_custom_nodes(channel, request.rel_url.query["mode"])
|
||||
await core.unified_manager.reload(mode)
|
||||
await core.unified_manager.get_custom_nodes(channel, mode)
|
||||
|
||||
res = core.unified_manager.fetch_or_pull_git_repo(is_pull=False)
|
||||
|
||||
@ -764,7 +818,7 @@ async def fetch_updates(request):
|
||||
return web.Response(status=400)
|
||||
|
||||
|
||||
@routes.get("/manager/queue/update_all")
|
||||
@routes.post("/manager/queue/update_all")
|
||||
async def update_all(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
@ -774,16 +828,19 @@ async def update_all(request):
|
||||
is_processing = task_worker_thread is not None and task_worker_thread.is_alive()
|
||||
if is_processing:
|
||||
return web.Response(status=401)
|
||||
|
||||
|
||||
await core.save_snapshot_with_postfix('autosave')
|
||||
|
||||
if request.rel_url.query["mode"] == "local":
|
||||
json_data = await request.json()
|
||||
mode = json_data.get("mode", "default")
|
||||
|
||||
if mode == "local":
|
||||
channel = 'local'
|
||||
else:
|
||||
channel = core.get_config()['channel_url']
|
||||
|
||||
await core.unified_manager.reload(request.rel_url.query["mode"])
|
||||
await core.unified_manager.get_custom_nodes(channel, request.rel_url.query["mode"])
|
||||
await core.unified_manager.reload(mode)
|
||||
await core.unified_manager.get_custom_nodes(channel, mode)
|
||||
|
||||
for k, v in core.unified_manager.active_nodes.items():
|
||||
if k == 'comfyui-manager':
|
||||
@ -1006,14 +1063,15 @@ def get_safe_snapshot_path(target):
|
||||
return os.path.join(core.manager_snapshot_path, f"{target}.json")
|
||||
|
||||
|
||||
@routes.get("/snapshot/remove")
|
||||
@routes.post("/snapshot/remove")
|
||||
async def remove_snapshot(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return security_403_response()
|
||||
|
||||
try:
|
||||
target = request.rel_url.query["target"]
|
||||
json_data = await request.json()
|
||||
target = json_data["target"]
|
||||
path = get_safe_snapshot_path(target)
|
||||
|
||||
if path is None:
|
||||
@ -1028,14 +1086,15 @@ async def remove_snapshot(request):
|
||||
return web.Response(status=400)
|
||||
|
||||
|
||||
@routes.get("/snapshot/restore")
|
||||
@routes.post("/snapshot/restore")
|
||||
async def restore_snapshot(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return security_403_response()
|
||||
|
||||
try:
|
||||
target = request.rel_url.query["target"]
|
||||
json_data = await request.json()
|
||||
target = json_data["target"]
|
||||
path = get_safe_snapshot_path(target)
|
||||
|
||||
if path is None:
|
||||
@ -1066,8 +1125,11 @@ async def get_current_snapshot_api(request):
|
||||
return web.Response(status=400)
|
||||
|
||||
|
||||
@routes.get("/snapshot/save")
|
||||
@routes.post("/snapshot/save")
|
||||
async def save_snapshot(request):
|
||||
resp = _reject_simple_form_content_type(request)
|
||||
if resp is not None:
|
||||
return resp
|
||||
try:
|
||||
await core.save_snapshot_with_postfix('snapshot')
|
||||
return web.Response(status=200)
|
||||
@ -1228,8 +1290,11 @@ async def reinstall_custom_node(request):
|
||||
await install_custom_node(request)
|
||||
|
||||
|
||||
@routes.get("/manager/queue/reset")
|
||||
@routes.post("/manager/queue/reset")
|
||||
async def reset_queue(request):
|
||||
resp = _reject_simple_form_content_type(request)
|
||||
if resp is not None:
|
||||
return resp
|
||||
global task_queue
|
||||
task_queue = queue.Queue()
|
||||
return web.Response(status=200)
|
||||
@ -1270,6 +1335,26 @@ async def install_custom_node(request):
|
||||
if skip_post_install:
|
||||
if cnr_id in core.unified_manager.nightly_inactive_nodes or cnr_id in core.unified_manager.cnr_inactive_nodes:
|
||||
core.unified_manager.unified_enable(cnr_id)
|
||||
# Mirror the pair of events (in_progress then done) that the async
|
||||
# task_worker normally emits for queued operations. The in_progress
|
||||
# event is what sets item.restart=true on the client row so the
|
||||
# action cell re-renders as "Restart Required"; without it, the
|
||||
# "Enable" button remains visible after successful enable. The done
|
||||
# event drives the completion UI (toast, restart indicator, button
|
||||
# loading clear).
|
||||
ui_id = json_data.get('ui_id', cnr_id)
|
||||
PromptServer.instance.send_sync(
|
||||
"cm-queue-status",
|
||||
{'status': 'in_progress',
|
||||
'target': ui_id,
|
||||
'ui_target': 'nodepack_manager',
|
||||
'total_count': 1, 'done_count': 0})
|
||||
PromptServer.instance.send_sync(
|
||||
"cm-queue-status",
|
||||
{'status': 'done',
|
||||
'nodepack_result': {ui_id: 'success'},
|
||||
'model_result': {},
|
||||
'total_count': 1, 'done_count': 1})
|
||||
return web.Response(status=200)
|
||||
elif selected_version is None:
|
||||
selected_version = 'latest'
|
||||
@ -1311,8 +1396,11 @@ async def install_custom_node(request):
|
||||
|
||||
task_worker_thread:threading.Thread = None
|
||||
|
||||
@routes.get("/manager/queue/start")
|
||||
@routes.post("/manager/queue/start")
|
||||
async def queue_start(request):
|
||||
resp = _reject_simple_form_content_type(request)
|
||||
if resp is not None:
|
||||
return resp
|
||||
global nodepack_result
|
||||
global model_result
|
||||
global task_worker_thread
|
||||
@ -1427,8 +1515,11 @@ async def update_custom_node(request):
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.get("/manager/queue/update_comfyui")
|
||||
@routes.post("/manager/queue/update_comfyui")
|
||||
async def update_comfyui(request):
|
||||
resp = _reject_simple_form_content_type(request)
|
||||
if resp is not None:
|
||||
return resp
|
||||
is_stable = core.get_config()['update_policy'] != 'nightly-comfyui'
|
||||
task_queue.put(("update-comfyui", ('comfyui', is_stable)))
|
||||
return web.Response(status=200)
|
||||
@ -1445,11 +1536,12 @@ async def comfyui_versions(request):
|
||||
return web.Response(status=400)
|
||||
|
||||
|
||||
@routes.get("/comfyui_manager/comfyui_switch_version")
|
||||
@routes.post("/comfyui_manager/comfyui_switch_version")
|
||||
async def comfyui_switch_version(request):
|
||||
try:
|
||||
if "ver" in request.rel_url.query:
|
||||
core.switch_comfyui(request.rel_url.query['ver'])
|
||||
json_data = await request.json()
|
||||
if "ver" in json_data:
|
||||
core.switch_comfyui(json_data['ver'])
|
||||
|
||||
return web.Response(status=200)
|
||||
except Exception as e:
|
||||
@ -1526,83 +1618,87 @@ async def install_model(request):
|
||||
|
||||
|
||||
@routes.get("/manager/preview_method")
|
||||
async def preview_method(request):
|
||||
# Setting change request
|
||||
if "value" in request.rel_url.query:
|
||||
# Reject setting change if per-queue preview feature is available
|
||||
if COMFYUI_HAS_PER_QUEUE_PREVIEW:
|
||||
return web.Response(text="DISABLED", status=403)
|
||||
async def get_preview_method(request):
|
||||
if COMFYUI_HAS_PER_QUEUE_PREVIEW:
|
||||
return web.Response(text="DISABLED", status=200)
|
||||
return web.Response(text=core.manager_funcs.get_current_preview_method(), status=200)
|
||||
|
||||
# Process normally if not available
|
||||
set_preview_method(request.rel_url.query['value'])
|
||||
core.write_config()
|
||||
return web.Response(status=200)
|
||||
|
||||
# Status query request
|
||||
else:
|
||||
# Return DISABLED if per-queue preview feature is available
|
||||
if COMFYUI_HAS_PER_QUEUE_PREVIEW:
|
||||
return web.Response(text="DISABLED", status=200)
|
||||
@routes.post("/manager/preview_method")
|
||||
async def set_preview_method_handler(request):
|
||||
if COMFYUI_HAS_PER_QUEUE_PREVIEW:
|
||||
return web.Response(text="DISABLED", status=403)
|
||||
|
||||
# Return current value if not available
|
||||
return web.Response(text=core.manager_funcs.get_current_preview_method(), status=200)
|
||||
json_data = await request.json()
|
||||
set_preview_method(json_data['value'])
|
||||
core.write_config()
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.get("/manager/db_mode")
|
||||
async def db_mode(request):
|
||||
if "value" in request.rel_url.query:
|
||||
set_db_mode(request.rel_url.query['value'])
|
||||
core.write_config()
|
||||
else:
|
||||
return web.Response(text=core.get_config()['db_mode'], status=200)
|
||||
async def get_db_mode(request):
|
||||
return web.Response(text=core.get_config()['db_mode'], status=200)
|
||||
|
||||
|
||||
@routes.post("/manager/db_mode")
|
||||
async def set_db_mode_handler(request):
|
||||
json_data = await request.json()
|
||||
set_db_mode(json_data['value'])
|
||||
core.write_config()
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
|
||||
@routes.get("/manager/policy/component")
|
||||
async def component_policy(request):
|
||||
if "value" in request.rel_url.query:
|
||||
set_component_policy(request.rel_url.query['value'])
|
||||
core.write_config()
|
||||
else:
|
||||
return web.Response(text=core.get_config()['component_policy'], status=200)
|
||||
async def get_component_policy(request):
|
||||
return web.Response(text=core.get_config()['component_policy'], status=200)
|
||||
|
||||
|
||||
@routes.post("/manager/policy/component")
|
||||
async def set_component_policy_handler(request):
|
||||
json_data = await request.json()
|
||||
set_component_policy(json_data['value'])
|
||||
core.write_config()
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.get("/manager/policy/update")
|
||||
async def update_policy(request):
|
||||
if "value" in request.rel_url.query:
|
||||
set_update_policy(request.rel_url.query['value'])
|
||||
core.write_config()
|
||||
else:
|
||||
return web.Response(text=core.get_config()['update_policy'], status=200)
|
||||
async def get_update_policy(request):
|
||||
return web.Response(text=core.get_config()['update_policy'], status=200)
|
||||
|
||||
|
||||
@routes.post("/manager/policy/update")
|
||||
async def set_update_policy_handler(request):
|
||||
json_data = await request.json()
|
||||
set_update_policy(json_data['value'])
|
||||
core.write_config()
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@routes.get("/manager/channel_url_list")
|
||||
async def channel_url_list(request):
|
||||
async def get_channel_url_list(request):
|
||||
channels = core.get_channel_dict()
|
||||
if "value" in request.rel_url.query:
|
||||
channel_url = channels.get(request.rel_url.query['value'])
|
||||
if channel_url is not None:
|
||||
core.get_config()['channel_url'] = channel_url
|
||||
core.write_config()
|
||||
else:
|
||||
selected = 'custom'
|
||||
selected_url = core.get_config()['channel_url']
|
||||
selected = 'custom'
|
||||
selected_url = core.get_config()['channel_url']
|
||||
|
||||
for name, url in channels.items():
|
||||
if url == selected_url:
|
||||
selected = name
|
||||
break
|
||||
for name, url in channels.items():
|
||||
if url == selected_url:
|
||||
selected = name
|
||||
break
|
||||
|
||||
res = {'selected': selected,
|
||||
'list': core.get_channel_list()}
|
||||
return web.json_response(res, status=200)
|
||||
res = {'selected': selected,
|
||||
'list': core.get_channel_list()}
|
||||
return web.json_response(res, status=200)
|
||||
|
||||
|
||||
@routes.post("/manager/channel_url_list")
|
||||
async def set_channel_url_list(request):
|
||||
json_data = await request.json()
|
||||
channels = core.get_channel_dict()
|
||||
channel_url = channels.get(json_data['value'])
|
||||
if channel_url is not None:
|
||||
core.get_config()['channel_url'] = channel_url
|
||||
core.write_config()
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@ -1700,8 +1796,11 @@ async def get_startup_alerts(request):
|
||||
return web.json_response(alerts)
|
||||
|
||||
|
||||
@routes.get("/manager/reboot")
|
||||
@routes.post("/manager/reboot")
|
||||
def restart(self):
|
||||
resp = _reject_simple_form_content_type(self)
|
||||
if resp is not None:
|
||||
return resp
|
||||
if not is_allowed_security_level('middle'):
|
||||
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return security_403_response()
|
||||
|
||||
@ -52,7 +52,7 @@ async function tryInstallCustomNode(event) {
|
||||
}
|
||||
}
|
||||
|
||||
let response = await api.fetchApi("/manager/reboot");
|
||||
let response = await api.fetchApi("/manager/reboot", { method: 'POST' });
|
||||
if(response.status == 403) {
|
||||
await handle403Response(response);
|
||||
return false;
|
||||
|
||||
@ -470,12 +470,12 @@ async function updateComfyUI() {
|
||||
|
||||
set_inprogress_mode();
|
||||
|
||||
const response = await api.fetchApi('/manager/queue/update_comfyui');
|
||||
const response = await api.fetchApi('/manager/queue/update_comfyui', { method: 'POST' });
|
||||
|
||||
showTerminal();
|
||||
|
||||
is_updating = true;
|
||||
await api.fetchApi('/manager/queue/start');
|
||||
await api.fetchApi('/manager/queue/start', { method: 'POST' });
|
||||
}
|
||||
|
||||
function showVersionSelectorDialog(versions, current, onSelect) {
|
||||
@ -625,14 +625,14 @@ async function switchComfyUI() {
|
||||
showVersionSelectorDialog(versions, obj.current, async (selected_version) => {
|
||||
if(selected_version == 'nightly') {
|
||||
update_policy_combo.value = 'nightly-comfyui';
|
||||
api.fetchApi('/manager/policy/update?value=nightly-comfyui');
|
||||
api.fetchApi('/manager/policy/update', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: 'nightly-comfyui' }) });
|
||||
}
|
||||
else {
|
||||
update_policy_combo.value = 'stable-comfyui';
|
||||
api.fetchApi('/manager/policy/update?value=stable-comfyui');
|
||||
api.fetchApi('/manager/policy/update', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: 'stable-comfyui' }) });
|
||||
}
|
||||
|
||||
let response = await api.fetchApi(`/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" });
|
||||
let response = await api.fetchApi('/comfyui_manager/comfyui_switch_version', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ver: selected_version }), cache: "no-store" });
|
||||
if (response.status == 200) {
|
||||
infoToast(`ComfyUI version is switched to ${selected_version}`);
|
||||
}
|
||||
@ -769,10 +769,10 @@ async function updateAll(update_comfyui) {
|
||||
|
||||
if(update_comfyui) {
|
||||
update_all_button.innerText = "Updating ComfyUI...";
|
||||
await api.fetchApi('/manager/queue/update_comfyui');
|
||||
await api.fetchApi('/manager/queue/update_comfyui', { method: 'POST' });
|
||||
}
|
||||
|
||||
const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`);
|
||||
const response = await api.fetchApi('/manager/queue/update_all', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ mode: mode }) });
|
||||
|
||||
if (response.status == 403) {
|
||||
await handle403Response(response);
|
||||
@ -784,7 +784,7 @@ async function updateAll(update_comfyui) {
|
||||
}
|
||||
else if(response.status == 200) {
|
||||
is_updating = true;
|
||||
await api.fetchApi('/manager/queue/start');
|
||||
await api.fetchApi('/manager/queue/start', { method: 'POST' });
|
||||
}
|
||||
}
|
||||
|
||||
@ -813,7 +813,7 @@ function restartOrStop() {
|
||||
rebootAPI();
|
||||
}
|
||||
else {
|
||||
api.fetchApi('/manager/queue/reset');
|
||||
api.fetchApi('/manager/queue/reset', { method: 'POST' });
|
||||
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
||||
}
|
||||
}
|
||||
@ -967,7 +967,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
.then(data => { this.datasrc_combo.value = data; });
|
||||
|
||||
this.datasrc_combo.addEventListener('change', function (event) {
|
||||
api.fetchApi(`/manager/db_mode?value=${event.target.value}`);
|
||||
api.fetchApi('/manager/db_mode', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: event.target.value }) });
|
||||
});
|
||||
|
||||
const dbRetrievalSetttingItem = createSettingsCombo("DB", this.datasrc_combo);
|
||||
@ -1043,7 +1043,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
}
|
||||
|
||||
// Normal operation
|
||||
api.fetchApi(`/manager/preview_method?value=${event.target.value}`)
|
||||
api.fetchApi('/manager/preview_method', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: event.target.value }) })
|
||||
.then(response => {
|
||||
if (response.status === 403) {
|
||||
// Feature transitioned to native
|
||||
@ -1087,7 +1087,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
}
|
||||
|
||||
channel_combo.addEventListener('change', function (event) {
|
||||
api.fetchApi(`/manager/channel_url_list?value=${event.target.value}`);
|
||||
api.fetchApi('/manager/channel_url_list', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: event.target.value }) });
|
||||
});
|
||||
|
||||
channel_combo.value = data.selected;
|
||||
@ -1152,7 +1152,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
});
|
||||
|
||||
component_policy_combo.addEventListener('change', function (event) {
|
||||
api.fetchApi(`/manager/policy/component?value=${event.target.value}`);
|
||||
api.fetchApi('/manager/policy/component', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: event.target.value }) });
|
||||
set_component_policy(event.target.value);
|
||||
});
|
||||
|
||||
@ -1171,7 +1171,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
||||
});
|
||||
|
||||
update_policy_combo.addEventListener('change', function (event) {
|
||||
api.fetchApi(`/manager/policy/update?value=${event.target.value}`);
|
||||
api.fetchApi('/manager/policy/update', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: event.target.value }) });
|
||||
});
|
||||
|
||||
const updateSetttingItem = createSettingsCombo("Update", update_policy_combo);
|
||||
|
||||
@ -185,7 +185,7 @@ export async function rebootAPI() {
|
||||
const isConfirmed = await customConfirm("Are you sure you'd like to reboot the server?");
|
||||
if (isConfirmed) {
|
||||
try {
|
||||
const response = await api.fetchApi("/manager/reboot");
|
||||
const response = await api.fetchApi("/manager/reboot", { method: 'POST' });
|
||||
if (response.status == 403) {
|
||||
await handle403Response(response);
|
||||
return false;
|
||||
|
||||
@ -462,7 +462,7 @@ export class CustomNodesManager {
|
||||
|
||||
".cn-manager-stop": {
|
||||
click: () => {
|
||||
api.fetchApi('/manager/queue/reset');
|
||||
api.fetchApi('/manager/queue/reset', { method: 'POST' });
|
||||
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
||||
}
|
||||
},
|
||||
@ -1476,9 +1476,15 @@ export class CustomNodesManager {
|
||||
let needRestart = false;
|
||||
let errorMsg = "";
|
||||
|
||||
await api.fetchApi('/manager/queue/reset');
|
||||
await api.fetchApi('/manager/queue/reset', { method: 'POST' });
|
||||
|
||||
// Set install_context BEFORE per-item queue enqueue calls so that any
|
||||
// server-side synchronous completion (e.g., sync enable of an inactive
|
||||
// node) that emits cm-queue-status before we return here still finds
|
||||
// install_context populated in onQueueCompleted. target_items is shared
|
||||
// by reference so further pushes below remain visible.
|
||||
let target_items = [];
|
||||
this.install_context = {btn: btn, targets: target_items};
|
||||
|
||||
for (const hash of list) {
|
||||
const item = this.grid.getRowItemBy("hash", hash);
|
||||
@ -1550,8 +1556,6 @@ export class CustomNodesManager {
|
||||
}
|
||||
}
|
||||
|
||||
this.install_context = {btn: btn, targets: target_items};
|
||||
|
||||
if(errorMsg) {
|
||||
this.showError(errorMsg);
|
||||
show_message("[Installation Errors]\n"+errorMsg);
|
||||
@ -1563,7 +1567,7 @@ export class CustomNodesManager {
|
||||
}
|
||||
}
|
||||
else {
|
||||
await api.fetchApi('/manager/queue/start');
|
||||
await api.fetchApi('/manager/queue/start', { method: 'POST' });
|
||||
this.showStop();
|
||||
showTerminal();
|
||||
}
|
||||
@ -1576,6 +1580,10 @@ export class CustomNodesManager {
|
||||
|
||||
const item = self.grid.getRowItemBy("hash", hash);
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.restart = true;
|
||||
self.restartMap[item.hash] = true;
|
||||
self.grid.updateCell(item, "action");
|
||||
@ -1583,45 +1591,81 @@ export class CustomNodesManager {
|
||||
}
|
||||
else if(event.detail.status == 'done') {
|
||||
self.hideStop();
|
||||
self.onQueueCompleted(event.detail);
|
||||
// Await + error logging so any unhandled rejection surfaces to the
|
||||
// console instead of silently swallowing completion finalization
|
||||
// (root cause of disable/enable button staying loading with no toast).
|
||||
try {
|
||||
await self.onQueueCompleted(event.detail);
|
||||
} catch (e) {
|
||||
console.error("[ComfyUI-Manager] onQueueCompleted failed:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onQueueCompleted(info) {
|
||||
// `nodepack_result` is a dict serialized from a Python dict, not an array.
|
||||
// `dict.length` is `undefined` and `undefined == 0` is `false`, so the
|
||||
// previous `result.length == 0` guard was a no-op; switch to a correct
|
||||
// empty-check that also tolerates null/undefined.
|
||||
let result = info.nodepack_result;
|
||||
|
||||
if(result.length == 0) {
|
||||
if (!result || Object.keys(result).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self = CustomNodesManager.instance;
|
||||
|
||||
if(!self.install_context) {
|
||||
if (!self || !self.install_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { target, label, mode } = self.install_context.btn;
|
||||
target.classList.remove("cn-btn-loading");
|
||||
const targets = self.install_context.targets || [];
|
||||
|
||||
// Compute errorMsg upfront so the downstream user-visible finalization
|
||||
// (showRestart / showMessage / infoToast) fires regardless of whether
|
||||
// any DOM-touching step below throws.
|
||||
let errorMsg = "";
|
||||
|
||||
for(let hash in result){
|
||||
for (let hash in result) {
|
||||
let v = result[hash];
|
||||
|
||||
if(v != 'success' && v != 'skip')
|
||||
errorMsg += v+'\n';
|
||||
if (v != 'success' && v != 'skip') {
|
||||
errorMsg += v + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
for(let k in self.install_context.targets) {
|
||||
let item = self.install_context.targets[k];
|
||||
self.grid.updateCell(item, "action");
|
||||
// Defensive: `target` may be a detached DOM node (the in_progress
|
||||
// handler's updateCell can re-render the row and replace the button
|
||||
// element). classList.remove on a detached node is a no-op, but we
|
||||
// still guard in case target was torn down entirely.
|
||||
try {
|
||||
if (target && target.classList) {
|
||||
target.classList.remove("cn-btn-loading");
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("[ComfyUI-Manager] Failed to clear button loading state:", e);
|
||||
}
|
||||
|
||||
// Defensive: grid.updateCell can throw if the item was removed or the
|
||||
// grid was re-rendered between in_progress and done. Do NOT let this
|
||||
// loop abort the completion finalization below — that was the observed
|
||||
// failure mode for disable/enable (no toast, no "restart required"
|
||||
// message).
|
||||
try {
|
||||
for (let k in targets) {
|
||||
let item = targets[k];
|
||||
if (item) {
|
||||
self.grid.updateCell(item, "action");
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("[ComfyUI-Manager] Failed to refresh target cells after queue completion:", e);
|
||||
}
|
||||
|
||||
if (errorMsg) {
|
||||
self.showError(errorMsg);
|
||||
show_message("Installation Error:\n"+errorMsg);
|
||||
show_message("Installation Error:\n" + errorMsg);
|
||||
} else {
|
||||
self.showStatus(`${label} ${result.length} custom node(s) successfully`);
|
||||
self.showStatus(`${label} ${Object.keys(result).length} custom node(s) successfully`);
|
||||
}
|
||||
|
||||
self.showRestart();
|
||||
|
||||
@ -170,7 +170,7 @@ export class ModelManager {
|
||||
|
||||
".cmm-manager-stop": {
|
||||
click: () => {
|
||||
api.fetchApi('/manager/queue/reset');
|
||||
api.fetchApi('/manager/queue/reset', { method: 'POST' });
|
||||
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
||||
}
|
||||
},
|
||||
@ -444,7 +444,7 @@ export class ModelManager {
|
||||
let needRefresh = false;
|
||||
let errorMsg = "";
|
||||
|
||||
await api.fetchApi('/manager/queue/reset');
|
||||
await api.fetchApi('/manager/queue/reset', { method: 'POST' });
|
||||
|
||||
let target_items = [];
|
||||
|
||||
@ -503,7 +503,7 @@ export class ModelManager {
|
||||
}
|
||||
}
|
||||
else {
|
||||
await api.fetchApi('/manager/queue/start');
|
||||
await api.fetchApi('/manager/queue/start', { method: 'POST' });
|
||||
this.showStop();
|
||||
showTerminal();
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ loadCss("./snapshot.css");
|
||||
async function restore_snapshot(target) {
|
||||
if(SnapshotManager.instance) {
|
||||
try {
|
||||
const response = await api.fetchApi(`/snapshot/restore?target=${target}`, { cache: "no-store" });
|
||||
const response = await api.fetchApi('/snapshot/restore', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ target: target }), cache: "no-store" });
|
||||
|
||||
if(response.status == 403) {
|
||||
await handle403Response(response);
|
||||
@ -37,7 +37,7 @@ async function restore_snapshot(target) {
|
||||
async function remove_snapshot(target) {
|
||||
if(SnapshotManager.instance) {
|
||||
try {
|
||||
const response = await api.fetchApi(`/snapshot/remove?target=${target}`, { cache: "no-store" });
|
||||
const response = await api.fetchApi('/snapshot/remove', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ target: target }), cache: "no-store" });
|
||||
|
||||
if(response.status == 403) {
|
||||
await handle403Response(response);
|
||||
@ -63,7 +63,7 @@ async function remove_snapshot(target) {
|
||||
|
||||
async function save_current_snapshot() {
|
||||
try {
|
||||
const response = await api.fetchApi('/snapshot/save', { cache: "no-store" });
|
||||
const response = await api.fetchApi('/snapshot/save', { method: 'POST', cache: "no-store" });
|
||||
app.ui.dialog.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,5 +1,155 @@
|
||||
{
|
||||
"custom_nodes": [
|
||||
{
|
||||
"author": "andreszs",
|
||||
"title": "ComfyUI-Lora-Pipeline",
|
||||
"reference": "https://github.com/andreszs/ComfyUI-Lora-Pipeline",
|
||||
"files": [
|
||||
"https://github.com/andreszs/ComfyUI-Lora-Pipeline"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Area-based LoRA and conditioning workflow tools for ComfyUI with multi-region control."
|
||||
},
|
||||
{
|
||||
"author": "Zinigo",
|
||||
"title": "Prompt Builder [NAME CONFLICT]",
|
||||
"reference": "https://github.com/zinigo-creations/comfyui-prompt-builder",
|
||||
"files": [
|
||||
"https://github.com/zinigo-creations/comfyui-prompt-builder"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Dropdown-based prompt builder for ComfyUI. Create characters, scenes, and styles without writing prompts. Designed for beginners and fast iteration."
|
||||
},
|
||||
{
|
||||
"author": "ethanfel",
|
||||
"title": "Comfyui-Return-Run-Logic",
|
||||
"reference": "https://github.com/ethanfel/Comfyui-Return-Run-Logic",
|
||||
"files": [
|
||||
"https://github.com/ethanfel/Comfyui-Return-Run-Logic"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Adds a toggle button to quickly switch between Run and Run (Instant) modes without opening the queue button dropdown menu."
|
||||
},
|
||||
{
|
||||
"author": "outrun32",
|
||||
"title": "[WIP] comfyui-chat-assistant",
|
||||
"reference": "https://github.com/outrun32/comfyui-chat-assistant",
|
||||
"files": [
|
||||
"https://github.com/outrun32/comfyui-chat-assistant"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A streamlined ComfyUI extension that adds an AI-powered chat interface to the sidebar for converting complex briefs/specs into generation-ready prompts. (Description by CC)\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "ComfyuiGY",
|
||||
"title": "Comfyui-Memory-Clear",
|
||||
"reference": "https://github.com/ComfyuiGY/Comfyui-Memory-Clear",
|
||||
"files": [
|
||||
"https://github.com/ComfyuiGY/Comfyui-Memory-Clear"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node for clearing memory. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "lying1324a-glitch",
|
||||
"title": "comfyuiautofirelaod",
|
||||
"reference": "https://github.com/lying1324a-glitch/comfyuiautofirelaod",
|
||||
"files": [
|
||||
"https://github.com/lying1324a-glitch/comfyuiautofirelaod"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI auto-fire loader extension. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "skkut",
|
||||
"title": "[WIP] ComfyUI-detailed-jobstatus",
|
||||
"reference": "https://github.com/skkut/ComfyUI-detailed-jobstatus",
|
||||
"files": [
|
||||
"https://github.com/skkut/ComfyUI-detailed-jobstatus"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A simple ComfyUI extension to show a execution timer.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "bob-bar-b-que",
|
||||
"title": "ComfyUI CLIP Token Counter [WIP]",
|
||||
"reference": "https://github.com/Bob-Bar-B-Que/ComfyUI_clip_token_counter",
|
||||
"files": [
|
||||
"https://github.com/Bob-Bar-B-Que/ComfyUI_clip_token_counter"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Shows real-time token count and adds a copy button to CLIPTextEncode nodes in ComfyUI.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "Lisa-Mays",
|
||||
"title": "wan-model-downloader",
|
||||
"reference": "https://github.com/Lisa-Mays/wan-model-downloader",
|
||||
"files": [
|
||||
"https://github.com/Lisa-Mays/wan-model-downloader"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Auto-downloads required models on startup."
|
||||
},
|
||||
{
|
||||
"author": "fya16838",
|
||||
"title": "Comfyui-Xiufu",
|
||||
"reference": "https://github.com/fya16838/Comfyui-Xiufu",
|
||||
"files": [
|
||||
"https://github.com/fya16838/Comfyui-Xiufu"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Fix ComfyUI models and nodes after importing workflows from others. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "fengye12",
|
||||
"title": "ComfyUI_XL_OpenAPI",
|
||||
"reference": "https://github.com/fengye12/ComfyUI_XL_OpenAPI",
|
||||
"files": [
|
||||
"https://github.com/fengye12/ComfyUI_XL_OpenAPI"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "OpenAPI wrapper for ComfyUI XL, providing standardized API access. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "scruffynerf",
|
||||
"title": "_0_comfyui_transformers_fix",
|
||||
"reference": "https://github.com/scruffynerf/_0_comfyui_transformers_fix",
|
||||
"files": [
|
||||
"https://github.com/scruffynerf/_0_comfyui_transformers_fix"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Quick patch that solves compatibility problems caused by MeshGraphormer-DepthMapPreprocessor by injecting missing functions into transformers."
|
||||
},
|
||||
{
|
||||
"author": "pixelmavenai",
|
||||
"title": "comfyui-custom-branding",
|
||||
"reference": "https://github.com/pixelmavenai/comfyui-custom-branding",
|
||||
"files": [
|
||||
"https://github.com/pixelmavenai/comfyui-custom-branding"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom branding for ComfyUI tab title and favicon"
|
||||
},
|
||||
{
|
||||
"author": "ka4ok424",
|
||||
"title": "ComfyUI-NodeLibrary",
|
||||
"reference": "https://github.com/ka4ok424/ComfyUI-NodeLibrary",
|
||||
"files": [
|
||||
"https://github.com/ka4ok424/ComfyUI-NodeLibrary"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "No ComfyUI nodes detected. May not be a ComfyUI custom node repository."
|
||||
},
|
||||
{
|
||||
"author": "skkut",
|
||||
"title": "ComfyUI-Auto-DarkMode [WIP]",
|
||||
"reference": "https://github.com/skkut/ComfyUI-Auto-DarkMode",
|
||||
"files": [
|
||||
"https://github.com/skkut/ComfyUI-Auto-DarkMode"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Lightweight ComfyUI extension that automatically detects and matches your system's Light/Dark theme in real-time.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "xWris3",
|
||||
"title": "jus_multifruit_comfyui",
|
||||
@ -230,16 +380,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI node implementing SMC-CFG (Sliding Mode Control CFG) that replaces standard linear CFG with a nonlinear sliding mode controller for stable guidance at any CFG scale. NOT WORKING - Work in progress. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "AiSatan",
|
||||
"title": "ComfyUI_CSM [NAME CONFLICT]",
|
||||
"reference": "https://github.com/AiSatan/ComfyUI_CSM",
|
||||
"files": [
|
||||
"https://github.com/AiSatan/ComfyUI_CSM"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI node for the CSM model featuring text-to-speech, voice cloning, and automatic model downloading from Hugging Face."
|
||||
},
|
||||
{
|
||||
"author": "unobtuse",
|
||||
"title": "comfyui-topaz-ai-upscale",
|
||||
@ -583,16 +723,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI nodes for GLM image generation, image-to-image translation, and flexible input handling. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "DailyMok",
|
||||
"title": "ComfyUI-PromptMixerNode",
|
||||
"reference": "https://github.com/DailyMok/ComfyUI-PromptMixerNode",
|
||||
"files": [
|
||||
"https://github.com/DailyMok/ComfyUI-PromptMixerNode"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node for prompt mixing with PromptMixerDaily node. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "shin131002",
|
||||
"title": "[WIP] ComfyUI-Prompt-Preset-Selector",
|
||||
@ -1684,16 +1814,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node that splits multi-line prompts by line, enabling batch image generation with each line triggering one execution and supporting custom prompt boxes. (Description by CC)\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "rookiestar28",
|
||||
"title": "ComfyUI_Security_Audit",
|
||||
"reference": "https://github.com/rookiestar28/ComfyUI_Security_Audit",
|
||||
"files": [
|
||||
"https://github.com/rookiestar28/ComfyUI_Security_Audit"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A lightweight, dual-layer security extension for ComfyUI using AST-based static analysis and runtime monitoring to detect malicious code in custom nodes."
|
||||
},
|
||||
{
|
||||
"author": "c1660181647-hash",
|
||||
"title": "ComfyUI-MM-Visual-Encryption",
|
||||
@ -1995,16 +2115,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom ComfyUI nodes for preset latent image generation including EmptyLatentImagePresetsAIO, FLUX, QWEN, and SD1.5 variants. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "silveroxides",
|
||||
"title": "ComfyUI_LoHalo",
|
||||
"reference": "https://github.com/silveroxides/ComfyUI_LoHalo",
|
||||
"files": [
|
||||
"https://github.com/silveroxides/ComfyUI_LoHalo"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI upscaling node package with Lohalo high-fidelity scaling and kernel-based image enhancement capabilities. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "jorin91",
|
||||
"title": "ComfyUI-JSG-Utils [UNSAFE]",
|
||||
@ -2528,16 +2638,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Amor's Image WebpSaver, Amor's Image Resizer, Amor's Text Translator, Amor's CogView Image Generator, ..."
|
||||
},
|
||||
{
|
||||
"author": "Solarish",
|
||||
"title": "fyUI-MidnightLook [WIP]",
|
||||
"reference": "https://github.com/Solarish/ComfyUI-MidnightLook",
|
||||
"files": [
|
||||
"https://github.com/Solarish/ComfyUI-MidnightLook"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom node for MidnightLook.com\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "hujuying",
|
||||
"title": "ComfyUI-QwenVL3-image-Plus [WIP]",
|
||||
@ -2558,16 +2658,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom nodes and utilities for workflow building, type conversions, checkpoint/pipe loaders and file utilities.[w/This nodepack includes an endpoint that access files from arbitrary paths.]"
|
||||
},
|
||||
{
|
||||
"author": "silveroxides",
|
||||
"title": "ComfyUI_LogicMath",
|
||||
"reference": "https://github.com/silveroxides/ComfyUI_LogicMath",
|
||||
"files": [
|
||||
"https://github.com/silveroxides/ComfyUI_LogicMath"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom node for with some basic logic and math nodes based on pull request [a/comfyanonymous/ComfyUI#8024](https://github.com/comfyanonymous/ComfyUI/pull/8024)"
|
||||
},
|
||||
{
|
||||
"author": "lyra-ai",
|
||||
"title": "lyra-nodes",
|
||||
@ -2808,16 +2898,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Morpheus · Batch Images + crop image, Morpheus · NanoBanana Mask, Morpheus · Image Editing Prompt, ...\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "silveroxides",
|
||||
"title": "ComfyUI_PromptAttention [WIP]",
|
||||
"reference": "https://github.com/silveroxides/ComfyUI_PromptAttention",
|
||||
"files": [
|
||||
"https://github.com/silveroxides/ComfyUI_PromptAttention"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Text Encode with Attention Bias"
|
||||
},
|
||||
{
|
||||
"author": "cedarconnor",
|
||||
"title": "ComfyUI Motion Transfer Pack [WIP]",
|
||||
@ -2908,16 +2988,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: ImageScaleToTotalPixelsRound64, ImageBlendLighter, ImageOffset, RGBtoRYGCBM, RYGCBMtoRGB, ExtractImageChannel, MatchRYGCBMColors, TextCommaToWeighted, TextCommaToRandomWeighted, RGBtoLAB, LABtoRGB, ImageMirrorPad, ImageCropBorders, ImageStitcher, ImageScaleToQwen, ..."
|
||||
},
|
||||
{
|
||||
"author": "silveroxides",
|
||||
"title": "Sampling Utility Toolkit",
|
||||
"reference": "https://github.com/silveroxides/ComfyUI_SamplingUtils",
|
||||
"files": [
|
||||
"https://github.com/silveroxides/ComfyUI_SamplingUtils"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Utilities making it easy to set up inference parameters."
|
||||
},
|
||||
{
|
||||
"author": "henjicc",
|
||||
"title": "ComfyUI-CC-ImageLoader [UNSAFE]",
|
||||
@ -3058,16 +3128,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Concatenate Sigmas Node, Splice Sigmas At %"
|
||||
},
|
||||
{
|
||||
"author": "silveroxides",
|
||||
"title": "WIP Conditioning Toolkit [UNSAFE]",
|
||||
"reference": "https://github.com/silveroxides/ComfyUI_CondsUtils",
|
||||
"files": [
|
||||
"https://github.com/silveroxides/ComfyUI_CondsUtils"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom nodes for modifying, saving and loading of various conditionings.[w/This nodepack contains a node that has a vulnerability allowing write to arbitrary file paths.]"
|
||||
},
|
||||
{
|
||||
"author": "ThuckMaBaws",
|
||||
"title": "TMB Camera Modifier for ComfyUI [WIP]",
|
||||
@ -4840,16 +4900,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Package that adds nodes to retrieve the system date and time.\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "rodpl",
|
||||
"title": "comfyui-asset-manager",
|
||||
"reference": "https://github.com/rodpl/comfyui-asset-manager",
|
||||
"files": [
|
||||
"https://github.com/rodpl/comfyui-asset-manager"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI Asset Manager for managing assets in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "blepping",
|
||||
"title": "ComfyUI 'dum' samplers [WIP]",
|
||||
@ -6172,16 +6222,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: TelegramSend, TelegramReply"
|
||||
},
|
||||
{
|
||||
"author": "qlikpetersen",
|
||||
"title": "ComfyUI-AI_Tools [UNSAFE]",
|
||||
"reference": "https://github.com/qlikpetersen/ComfyUI-AI_Tools",
|
||||
"files": [
|
||||
"https://github.com/qlikpetersen/ComfyUI-AI_Tools"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: DoLogin, HttpRequest, Json2String, String2Json, CreateListString, CreateListJSON, Query_OpenAI, Image_Attachment, JSON_Attachment, String_Attachment, RunPython\n[w/This nodepack contains a node with a vulnerability that allows arbitrary code execution.]"
|
||||
},
|
||||
{
|
||||
"author": "MuAIGC",
|
||||
"title": "DMXAPI Nodes [WIP]",
|
||||
@ -6532,16 +6572,6 @@
|
||||
"description": "NODES: Properties, Apply SVG to Image",
|
||||
"install_type": "git-clone"
|
||||
},
|
||||
{
|
||||
"author": "Kur0butiMegane",
|
||||
"title": "Comfyui-StringUtils",
|
||||
"reference": "https://github.com/Kur0butiMegane/Comfyui-StringUtils2",
|
||||
"files": [
|
||||
"https://github.com/Kur0butiMegane/Comfyui-StringUtils2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Normalizer, Splitter, Selector, XML Parser, XML Parser, Make Property, Add XML Tag, Is String Empty, Cond Passthrough, CLIP Passthrough, ClipRegion Passthrough, Scheduler Selector (Impact), Scheduler Selector (Inspire), Save Text, XML to Cutoff"
|
||||
},
|
||||
{
|
||||
"author": "ronaldstg",
|
||||
"title": "comfyui-plus-integrations [WIP]",
|
||||
@ -6582,16 +6612,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI implementation of the partfield nvidea segmentation models\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "silveroxides",
|
||||
"title": "ComfyUI_ReduxEmbedToolkit",
|
||||
"reference": "https://github.com/silveroxides/ComfyUI_ReduxEmbedToolkit",
|
||||
"files": [
|
||||
"https://github.com/silveroxides/ComfyUI_ReduxEmbedToolkit"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom nodes for managing, saving and loading of Redux/Style based embeddings."
|
||||
},
|
||||
{
|
||||
"author": "StaffsGull",
|
||||
"title": "comfyui_scene_builder [WIP]",
|
||||
@ -11253,16 +11273,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes: Node Jumper. Various quality of life testing nodes"
|
||||
},
|
||||
{
|
||||
"author": "IvanZhd",
|
||||
"title": "comfyui-codeformer [WIP]",
|
||||
"reference": "https://github.com/IvanZhd/comfyui-codeformer",
|
||||
"files": [
|
||||
"https://github.com/IvanZhd/comfyui-codeformer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes:Image Inverter"
|
||||
},
|
||||
{
|
||||
"author": "romeobuilderotti",
|
||||
"title": "ComfyUI-EZ-Pipes",
|
||||
|
||||
@ -385,6 +385,7 @@
|
||||
"PD_Mask Selector By Area Left",
|
||||
"PD_MaskFillHoles",
|
||||
"PD_MaskRemoveSmallObjects",
|
||||
"PD_Maskfenkai",
|
||||
"PD_ModelLoraLoader",
|
||||
"PD_RemoveBlackBackground",
|
||||
"PD_RemoveColorWords",
|
||||
@ -833,6 +834,8 @@
|
||||
"TSRestoreFromCrop",
|
||||
"TSWhisper",
|
||||
"TS_Animation_Preview",
|
||||
"TS_AudioLoader",
|
||||
"TS_AudioPreview",
|
||||
"TS_BGRM_BiRefNet",
|
||||
"TS_BatchPromptLoader",
|
||||
"TS_Color_Grade",
|
||||
@ -869,6 +872,7 @@
|
||||
"TS_QwenSafeResize",
|
||||
"TS_RTX_Upscaler",
|
||||
"TS_ResolutionSelector",
|
||||
"TS_SileroStress",
|
||||
"TS_SileroTTS",
|
||||
"TS_Smart_Switch",
|
||||
"TS_StylePromptSelector",
|
||||
@ -1482,12 +1486,91 @@
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/CondsUtils": [
|
||||
[
|
||||
"InsertAttnConds",
|
||||
"InsertTEConds",
|
||||
"LoadReduxEmb",
|
||||
"LoadTEConds",
|
||||
"SaveCondsEmb",
|
||||
"SaveReduxEmb"
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/DiffsynthPause": [
|
||||
[
|
||||
"nynxz.Patch.ZImageDiffsynthControlnetPause"
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/LoHalo": [
|
||||
[
|
||||
"LohaloHighFidelityScaler",
|
||||
"LohaloKernelScalingNode"
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/PromptAttention": [
|
||||
[
|
||||
"CLIPTextEncodeAttentionBias"
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/ReduxEmbedToolkit": [
|
||||
[
|
||||
"InsertAttnConds",
|
||||
"InsertTEConds",
|
||||
"LoadReduxEmb",
|
||||
"LoadTEConds",
|
||||
"SaveCondsEmb",
|
||||
"SaveReduxEmb"
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/SamplingUtils": [
|
||||
[
|
||||
"AdjustedResolutionParameters",
|
||||
"BonusPromptPresets",
|
||||
"CameraShotPresets",
|
||||
"EditOpPresets",
|
||||
"EditTargetPresets",
|
||||
"Frakturpad",
|
||||
"GetJsonKeyValue",
|
||||
"IdeographicLinePad",
|
||||
"IdeographicSentencePad",
|
||||
"IdeographicTagPad",
|
||||
"ImageBlendByMask",
|
||||
"ImageMatchProperties",
|
||||
"Image_Color_Noise",
|
||||
"InstructPromptPresets",
|
||||
"IntegerRangeRandom",
|
||||
"JoinerPadding",
|
||||
"LlTokenizerOptions",
|
||||
"ModifyMask",
|
||||
"OpticalFlowComposite",
|
||||
"PrimitiveRandomInt",
|
||||
"PrimitiveRandomIntRange",
|
||||
"PrimitiveStaticInt",
|
||||
"SU_LoadImageDirectory",
|
||||
"SU_LoadImagePath",
|
||||
"SamplingParameters",
|
||||
"SystemMessagePresets",
|
||||
"TagNormalizeCombine",
|
||||
"TextEncodeFlux2SystemPrompt",
|
||||
"TextEncodeKleinSystemPrompt",
|
||||
"TextEncodeSystemPrompt",
|
||||
"TextEncodeZITSystemPrompt",
|
||||
"TextEncodeZImageThinkPrompt",
|
||||
"TextOverlayNode",
|
||||
"UNETLoaderAsync",
|
||||
"UnFrakturPad",
|
||||
"UnifiedPresets",
|
||||
"VLMSysInstrAdvPresets",
|
||||
"VLMSysInstrPresets",
|
||||
"VLMSysQueryAddPresets"
|
||||
],
|
||||
{}
|
||||
],
|
||||
"https://github.com/ComfyUI/Text_Processor": [
|
||||
[
|
||||
"AddTextToImage",
|
||||
@ -1524,14 +1607,6 @@
|
||||
"title_aux": "ComfyUI-VideoStream"
|
||||
}
|
||||
],
|
||||
"https://github.com/DailyMok/ComfyUI-PromptMixerNode": [
|
||||
[
|
||||
"PromptMixerDaily"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-PromptMixerNode"
|
||||
}
|
||||
],
|
||||
"https://github.com/DataCTE/ComfyUI-DataVoid-nodes": [
|
||||
[
|
||||
"IPAAdapterFaceIDBatch",
|
||||
@ -1896,6 +1971,7 @@
|
||||
[
|
||||
"Base64ToImageNode by IAT",
|
||||
"FloatInputNode by IAT",
|
||||
"GPTReversePrompt by IAT",
|
||||
"ImageMatchSize by IAT",
|
||||
"ImageResizeLongestSide by IAT",
|
||||
"ImageResizeToSDXL by IAT",
|
||||
@ -2400,14 +2476,6 @@
|
||||
"title_aux": "ComfyUI_DeleteModelPassthrough_ExecutionFlowControl [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/IvanZhd/comfyui-codeformer": [
|
||||
[
|
||||
"RedBeanie_CustomImageInverter"
|
||||
],
|
||||
{
|
||||
"title_aux": "comfyui-codeformer [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/JBKing514/map_comfyui": [
|
||||
[
|
||||
"MAP_Pro_Suite"
|
||||
@ -2712,30 +2780,6 @@
|
||||
"title_aux": "RK_Comfyui"
|
||||
}
|
||||
],
|
||||
"https://github.com/Kur0butiMegane/Comfyui-StringUtils2": [
|
||||
[
|
||||
"AddXMLTag",
|
||||
"CLIPPassThrough",
|
||||
"ClipRegionPassThrough",
|
||||
"CondPassThrough",
|
||||
"ElapsedTime",
|
||||
"GetBeginTime",
|
||||
"GetEndTime",
|
||||
"IsStringEmpty",
|
||||
"MakeProperty",
|
||||
"Normalize",
|
||||
"SaveText",
|
||||
"SchedulerSelectorImpact",
|
||||
"SchedulerSelectorInspire",
|
||||
"Selector",
|
||||
"Split",
|
||||
"XMLParser",
|
||||
"XMLtoCutoff"
|
||||
],
|
||||
{
|
||||
"title_aux": "Comfyui-StringUtils"
|
||||
}
|
||||
],
|
||||
"https://github.com/KurtHokke/ComfyUI_KurtHokke_Nodes": [
|
||||
[
|
||||
"AIO_Tuner_Pipe",
|
||||
@ -3131,6 +3175,7 @@
|
||||
"MpiBoolean",
|
||||
"MpiBooleanCompare",
|
||||
"MpiChoiceSelector",
|
||||
"MpiClearVram",
|
||||
"MpiCombo",
|
||||
"MpiCombo1",
|
||||
"MpiCombo10",
|
||||
@ -3147,6 +3192,7 @@
|
||||
"MpiConvert",
|
||||
"MpiDisplayPrompt",
|
||||
"MpiDoubleLora",
|
||||
"MpiExpoFloat",
|
||||
"MpiFloat",
|
||||
"MpiFromCheckpoint",
|
||||
"MpiGetImageAtIndex",
|
||||
@ -3159,6 +3205,7 @@
|
||||
"MpiInt",
|
||||
"MpiJsonLoad",
|
||||
"MpiJsonSave",
|
||||
"MpiLogger",
|
||||
"MpiLoraModel",
|
||||
"MpiLoraModelClip",
|
||||
"MpiLoraSwitch",
|
||||
@ -4689,6 +4736,7 @@
|
||||
],
|
||||
"https://github.com/SlackinJack/multigpu_diffusion_comfyui": [
|
||||
[
|
||||
"AdvancedFlowMatchScheduler",
|
||||
"AdvancedSchedulerSelector",
|
||||
"ApplyPipeline",
|
||||
"AsyncDiffConfig",
|
||||
@ -4699,7 +4747,7 @@
|
||||
"CompileConfig",
|
||||
"CreateHost",
|
||||
"EncodePromptWithCompel",
|
||||
"FMEulerScheduler",
|
||||
"FlowMatchScheduler",
|
||||
"FluxSampler",
|
||||
"GroupOffloadConfig",
|
||||
"LoraSelector",
|
||||
@ -4716,10 +4764,10 @@
|
||||
"SVDSampler",
|
||||
"SchedulerSelector",
|
||||
"SingleConfig",
|
||||
"SleepHost",
|
||||
"TorchAOQuantizationConfig",
|
||||
"TorchConfig",
|
||||
"UnsafeModelSelector",
|
||||
"WanSampler",
|
||||
"ZImageSampler"
|
||||
],
|
||||
{
|
||||
@ -4772,8 +4820,6 @@
|
||||
"CombineWanPipeline",
|
||||
"CombineZImagePipeline",
|
||||
"CreateTrajectoryBasedOnKJNodes",
|
||||
"DeepFace_FaceCrop",
|
||||
"DeepFace_Verify",
|
||||
"Flux2ControlSampler",
|
||||
"Flux2T2ISampler",
|
||||
"FunAttention",
|
||||
@ -4785,7 +4831,6 @@
|
||||
"ImageToCanny",
|
||||
"ImageToDepth",
|
||||
"ImageToPose",
|
||||
"IterativeUpscaleNode",
|
||||
"LoadCogVideoXFunLora",
|
||||
"LoadCogVideoXFunModel",
|
||||
"LoadFlux2ControlNetInModel",
|
||||
@ -4825,39 +4870,48 @@
|
||||
"LoadZImageTextEncoderModel",
|
||||
"LoadZImageTransformerModel",
|
||||
"LoadZImageVAEModel",
|
||||
"MediaPipe_FaceCrop",
|
||||
"MidnightDetailerNode",
|
||||
"MidnightLook_AnyToString",
|
||||
"MidnightLook_CropDATAToBBOX",
|
||||
"MidnightLook_CropForInpaint",
|
||||
"MidnightLook_DisplayAny",
|
||||
"MidnightLook_LatentSizePresets",
|
||||
"MidnightLook_LoadImageByURL",
|
||||
"MidnightLook_LoopEnd",
|
||||
"MidnightLook_LoopStart",
|
||||
"MidnightLook_PasteAfterInpaint",
|
||||
"MidnightLook_PreFill",
|
||||
"MidnightLook_QwenGuidance",
|
||||
"MidnightLook_QwenSmartCropPad",
|
||||
"MidnightLook_StringToBBOX",
|
||||
"MidnightLook_URLLoRALoader",
|
||||
"MidnightLook_UploadToR2",
|
||||
"MidnightLook_VRAMClear",
|
||||
"MidnightLook_ZImageCNLoader",
|
||||
"MidnightLook_ZImageCNSampler",
|
||||
"MidnightLook_ZImageInpaintSampler",
|
||||
"MidnightLook_ZImageLoader",
|
||||
"MidnightLook_ZImageOutpaintSampler",
|
||||
"MidnightLook_ZImagePrompt",
|
||||
"MidnightQwen25Load",
|
||||
"MidnightQwen25Run",
|
||||
"MidnightLook-AnyToString",
|
||||
"MidnightLook-CanvasExpand",
|
||||
"MidnightLook-CropDataToBBox",
|
||||
"MidnightLook-CropForInpaint",
|
||||
"MidnightLook-DeepFaceCrop",
|
||||
"MidnightLook-DeepFaceVerify",
|
||||
"MidnightLook-Detailer",
|
||||
"MidnightLook-DisplayAny",
|
||||
"MidnightLook-ExpandCropMask",
|
||||
"MidnightLook-GrowMaskWithBlur",
|
||||
"MidnightLook-ImageCompare",
|
||||
"MidnightLook-IterativeUpscale",
|
||||
"MidnightLook-LatentSizePresets",
|
||||
"MidnightLook-LoadImageByURL",
|
||||
"MidnightLook-LoopEnd",
|
||||
"MidnightLook-LoopStart",
|
||||
"MidnightLook-MediaPipeFaceCrop",
|
||||
"MidnightLook-PasteAfterInpaint",
|
||||
"MidnightLook-PreFill",
|
||||
"MidnightLook-PresetPrompt",
|
||||
"MidnightLook-Qwen25Load",
|
||||
"MidnightLook-Qwen25Run",
|
||||
"MidnightLook-QwenGuidance",
|
||||
"MidnightLook-QwenSmartCropPad",
|
||||
"MidnightLook-SAM2Loader",
|
||||
"MidnightLook-StringToBBox",
|
||||
"MidnightLook-TextBox",
|
||||
"MidnightLook-URLLoRALoader",
|
||||
"MidnightLook-UploadToR2",
|
||||
"MidnightLook-UpscalerProvider",
|
||||
"MidnightLook-VRAMClear",
|
||||
"MidnightLook-ZImageCNLoader",
|
||||
"MidnightLook-ZImageCNSampler",
|
||||
"MidnightLook-ZImageInpaintSampler",
|
||||
"MidnightLook-ZImageLoader",
|
||||
"MidnightLook-ZImageOutpaintSampler",
|
||||
"MidnightLook-ZImagePrompt",
|
||||
"PassThroughImage",
|
||||
"QwenImageControlSampler",
|
||||
"QwenImageEditPlusSampler",
|
||||
"QwenImageEditSampler",
|
||||
"QwenImageT2VSampler",
|
||||
"SAM2LoaderNode",
|
||||
"SampleUpscalerProviderNode",
|
||||
"VideoToCanny",
|
||||
"VideoToDepth",
|
||||
"VideoToOpenpose",
|
||||
@ -4982,6 +5036,7 @@
|
||||
"SDVN Gemini 3.1 Flash Image",
|
||||
"SDVN Gemini Flash 2 Image",
|
||||
"SDVN Get Mask Size",
|
||||
"SDVN Google Colab Disconnect",
|
||||
"SDVN Google Imagen",
|
||||
"SDVN IC Lora Layout",
|
||||
"SDVN IC Lora Layout Crop",
|
||||
@ -7132,6 +7187,9 @@
|
||||
"BriaImageEditNode",
|
||||
"BriaRemoveImageBackground",
|
||||
"BriaRemoveVideoBackground",
|
||||
"ByteDance2FirstLastFrameNode",
|
||||
"ByteDance2ReferenceNode",
|
||||
"ByteDance2TextToVideoNode",
|
||||
"ByteDanceFirstLastFrameNode",
|
||||
"ByteDanceImageNode",
|
||||
"ByteDanceImageReferenceNode",
|
||||
@ -7168,6 +7226,7 @@
|
||||
"CheckpointSave",
|
||||
"ChromaRadianceOptions",
|
||||
"ColorToRGBInt",
|
||||
"ColorTransfer",
|
||||
"ComboOptionTestNode",
|
||||
"ComfyMathExpression",
|
||||
"ComfyNumberConvert",
|
||||
@ -7295,6 +7354,7 @@
|
||||
"ImageCropV2",
|
||||
"ImageFlip",
|
||||
"ImageFromBatch",
|
||||
"ImageHistogram",
|
||||
"ImageInvert",
|
||||
"ImageMergeTileList",
|
||||
"ImageOnlyCheckpointLoader",
|
||||
@ -7319,6 +7379,7 @@
|
||||
"InvertMask",
|
||||
"JoinAudioChannels",
|
||||
"JoinImageWithAlpha",
|
||||
"JsonExtractString",
|
||||
"KSampler",
|
||||
"KSamplerAdvanced",
|
||||
"KSamplerSelect",
|
||||
@ -7560,6 +7621,7 @@
|
||||
"SDPoseKeypointExtractor",
|
||||
"SDTurboScheduler",
|
||||
"SD_4XUpscale_Conditioning",
|
||||
"SUPIRApply",
|
||||
"SV3D_Conditioning",
|
||||
"SVD_img2vid_Conditioning",
|
||||
"SamplerCustom",
|
||||
@ -7604,6 +7666,8 @@
|
||||
"SkipLayerGuidanceDiTSimple",
|
||||
"SkipLayerGuidanceSD3",
|
||||
"SolidMask",
|
||||
"SoniloTextToMusic",
|
||||
"SoniloVideoToMusic",
|
||||
"SplitAudioChannels",
|
||||
"SplitImageToTileList",
|
||||
"SplitImageWithAlpha",
|
||||
@ -8524,9 +8588,12 @@
|
||||
],
|
||||
"https://github.com/fangg2000/comfyui_fgtools": [
|
||||
[
|
||||
"DeepSeekChat",
|
||||
"DoubaoChat",
|
||||
"InpaintConcat",
|
||||
"InpaintCut",
|
||||
"IsEmptyString",
|
||||
"PriorityLLMNode",
|
||||
"SwitchString"
|
||||
],
|
||||
{
|
||||
@ -10705,6 +10772,7 @@
|
||||
"AnyToAny",
|
||||
"BlockifyMask_lhy",
|
||||
"CLIPName",
|
||||
"CLIPNameGGUF",
|
||||
"CLIPVisionName",
|
||||
"CSVRandomPicker",
|
||||
"CSVRandomPickerAdv",
|
||||
@ -10726,11 +10794,13 @@
|
||||
"MorseCode",
|
||||
"PoseReformer",
|
||||
"QueueHandler",
|
||||
"RequestURL",
|
||||
"SaveImageAsZip",
|
||||
"SaveTextAsZip",
|
||||
"StrFormat",
|
||||
"StrFormatAdv",
|
||||
"UNETName",
|
||||
"UNETNameGGUF",
|
||||
"UpscaleModelName",
|
||||
"VAEName",
|
||||
"WanAnimateBestFrameWindow",
|
||||
@ -11803,6 +11873,7 @@
|
||||
"https://github.com/nobinBB/comfyui-samenodes": [
|
||||
[
|
||||
"A1111PromptSplitter",
|
||||
"BatchImageCompressor",
|
||||
"BatchImageProcessor",
|
||||
"CivitaiLoraSearcher",
|
||||
"EmbeddingPathResolver",
|
||||
@ -11811,11 +11882,16 @@
|
||||
"FloatToString",
|
||||
"FloatToStringWithPrefix",
|
||||
"GetComfyInputPath",
|
||||
"ImageFormatConverter",
|
||||
"ImagesToPdf",
|
||||
"ImpactWildcardProcessorSeed",
|
||||
"LoRATagPowerLoaderExtended",
|
||||
"LoRATextDualInput",
|
||||
"LoraToCivitaiUrl",
|
||||
"LoraWildcardGenerator",
|
||||
"RepeatTextLines",
|
||||
"SDPromptSaverOptimized",
|
||||
"SeedStepN",
|
||||
"TextSplit3"
|
||||
],
|
||||
{
|
||||
@ -12396,29 +12472,38 @@
|
||||
"Any Multi-Switch [Eclipse]",
|
||||
"Any Passer Purge [Eclipse]",
|
||||
"Any Passer [Eclipse]",
|
||||
"Audio Passer [Eclipse]",
|
||||
"Basic Pipe Passer [Eclipse]",
|
||||
"Boolean [Eclipse]",
|
||||
"CLIP Loader [Eclipse]",
|
||||
"CLIP Text Encode [Eclipse]",
|
||||
"CLIPLoaderGGUF",
|
||||
"Checkpoint Loader Small (Pipe) [Eclipse]",
|
||||
"Checkpoint Loader Small [Eclipse]",
|
||||
"Clip Passer [Eclipse]",
|
||||
"Color Match [Eclipse]",
|
||||
"Combine Video Clips [Eclipse]",
|
||||
"Concat Pipe Multi [Eclipse]",
|
||||
"Conditioning Passer [Eclipse]",
|
||||
"Conditioning Zero Out [Eclipse]",
|
||||
"Context Image [Eclipse]",
|
||||
"Context Video (WVW) [Eclipse]",
|
||||
"Context Video [Eclipse]",
|
||||
"ControlNet Passer [Eclipse]",
|
||||
"ControlNet Set Union Types (Flux) [Eclipse]",
|
||||
"Convert Primitive [Eclipse]",
|
||||
"Convert To Batch [Eclipse]",
|
||||
"Convert to List [Eclipse]",
|
||||
"Custom Size [Eclipse]",
|
||||
"Detailer Pipe Passer [Eclipse]",
|
||||
"Detection to Bboxes [Eclipse]",
|
||||
"DualCLIPLoaderGGUF",
|
||||
"Fast Bypasser [Eclipse]",
|
||||
"Fast Groups Bypasser [Eclipse]",
|
||||
"Fast Groups Muter [Eclipse]",
|
||||
"Fast Mode Switcher [Eclipse]",
|
||||
"Fast Muter [Eclipse]",
|
||||
"Float Passer [Eclipse]",
|
||||
"Float [Eclipse]",
|
||||
"Generation Data (Gated) [Eclipse]",
|
||||
"Generation Data [Eclipse]",
|
||||
@ -12426,13 +12511,21 @@
|
||||
"IF A Else B [Eclipse]",
|
||||
"IO Checkpoint Loader [Eclipse]",
|
||||
"IO Load Image [Eclipse]",
|
||||
"Image Align Size [Eclipse]",
|
||||
"Image Comparer [Eclipse]",
|
||||
"Image Convert [Eclipse]",
|
||||
"Image Crop by Mask [Eclipse]",
|
||||
"Image Passer [Eclipse]",
|
||||
"Image Resize [Eclipse]",
|
||||
"Image Resolution [Eclipse]",
|
||||
"Image Soften [Eclipse]",
|
||||
"Image with FX [Eclipse]",
|
||||
"Int Passer [Eclipse]",
|
||||
"Integer Generate [Eclipse]",
|
||||
"Integer [Eclipse]",
|
||||
"Join [Eclipse]",
|
||||
"Keep Calculator [Eclipse]",
|
||||
"Latent Passer [Eclipse]",
|
||||
"Load Directory Settings [Eclipse]",
|
||||
"Load Image (Metadata Pipe) [Eclipse]",
|
||||
"Load Image (Pipe) [Eclipse]",
|
||||
@ -12444,9 +12537,15 @@
|
||||
"Lora Stack [Eclipse]",
|
||||
"Lora Stack apply [Eclipse]",
|
||||
"Lora Stack to String [Eclipse]",
|
||||
"Mask Passer [Eclipse]",
|
||||
"Merge Strings [Eclipse]",
|
||||
"Mode Bridge Get [Eclipse]",
|
||||
"Mode Bridge Set [Eclipse]",
|
||||
"Mode Bridge [Eclipse]",
|
||||
"Mode Relay [Eclipse]",
|
||||
"Model Loader Pipe [Eclipse]",
|
||||
"Model Loader [Eclipse]",
|
||||
"Model Passer [Eclipse]",
|
||||
"Mute / Bypass Repeater [Eclipse]",
|
||||
"Node Collector [Eclipse]",
|
||||
"None [Eclipse]",
|
||||
@ -12460,12 +12559,15 @@
|
||||
"Pipe IO Sampler Settings v2.1 [Eclipse]",
|
||||
"Pipe IO Sampler Settings v2.2 [Eclipse]",
|
||||
"Pipe Out Checkpoint Loader [Eclipse]",
|
||||
"Pipe Out LM Advanced Options [Eclipse]",
|
||||
"Pipe Out LM Advanced Options [SmartLML]",
|
||||
"Pipe Out Load Directory Settings [Eclipse]",
|
||||
"Pipe Out Load Image (Metadata Pipe) [Eclipse]",
|
||||
"Pipe Out Sampler Settings [Eclipse]",
|
||||
"Pipe Out Smart Folder [Eclipse]",
|
||||
"Pipe Out VC Name Generator [Eclipse]",
|
||||
"Pipe Out WanVideo Setup [Eclipse]",
|
||||
"Pipe Passer [Eclipse]",
|
||||
"Preview Image (DOM) [Eclipse]",
|
||||
"Preview Image [Eclipse]",
|
||||
"Preview Mask [Eclipse]",
|
||||
@ -12476,6 +12578,8 @@
|
||||
"Replace String [Eclipse]",
|
||||
"Replace String v2 [Eclipse]",
|
||||
"Replace String v3 [Eclipse]",
|
||||
"Resolution Scale [Eclipse]",
|
||||
"SEGS Passer [Eclipse]",
|
||||
"SEGS Preview [Eclipse]",
|
||||
"Sampler Selection [Eclipse]",
|
||||
"Sampler Settings NI [Eclipse]",
|
||||
@ -12495,8 +12599,14 @@
|
||||
"Seed 32-bit [Eclipse]",
|
||||
"Seed [Eclipse]",
|
||||
"Show Any [Eclipse]",
|
||||
"Smart Detection [Eclipse]",
|
||||
"Smart Detection [SML]",
|
||||
"Smart Folder [Eclipse]",
|
||||
"Smart Folder v2 [Eclipse]",
|
||||
"Smart LM Loader [Eclipse]",
|
||||
"Smart Language Model Loader v2 [Eclipse]",
|
||||
"Smart Language Model Loader v2 [SmartLML]",
|
||||
"Smart Language Model Loader v3 [SmartLML]",
|
||||
"Smart Loader Basic [Eclipse]",
|
||||
"Smart Loader Basic v2 [Eclipse]",
|
||||
"Smart Loader Plus [Eclipse]",
|
||||
@ -12504,6 +12614,7 @@
|
||||
"Smart Loader [Eclipse]",
|
||||
"Smart Loader v2 [Eclipse]",
|
||||
"Smart Model Loader [Eclipse]",
|
||||
"Smart Model Loader [SML]",
|
||||
"Smart Prompt [Eclipse]",
|
||||
"Smart Prompt v2 [Eclipse]",
|
||||
"Smart Sampler Settings [Eclipse]",
|
||||
@ -12513,17 +12624,24 @@
|
||||
"String Dual [Eclipse]",
|
||||
"String Multiline List [Eclipse]",
|
||||
"String Multiline [Eclipse]",
|
||||
"String Passer [Eclipse]",
|
||||
"String [Eclipse]",
|
||||
"String from List [Eclipse]",
|
||||
"Text Image with FX [Eclipse]",
|
||||
"Tile Assembly [Eclipse]",
|
||||
"Tile Decode & Assembly [Eclipse]",
|
||||
"Tile Split [Eclipse]",
|
||||
"TripleCLIPLoaderGGUF",
|
||||
"UnetLoaderGGUF",
|
||||
"UnetLoaderGGUFAdvanced",
|
||||
"Universal Block Swap [Eclipse]",
|
||||
"VAE Loader [Eclipse]",
|
||||
"VAE Passer [Eclipse]",
|
||||
"VC-Filename Generator I [Eclipse]",
|
||||
"VC-Filename Generator II [Eclipse]",
|
||||
"VRAM Cleanup [Eclipse]",
|
||||
"Video Resolution [Eclipse]",
|
||||
"WAN Model Passer [Eclipse]",
|
||||
"WanVideo Setup [Eclipse]",
|
||||
"Widget to String [Eclipse]",
|
||||
"Wildcard Processor [Eclipse]"
|
||||
@ -12815,14 +12933,6 @@
|
||||
"title_aux": "comfyui-plus-integrations [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/rookiestar28/ComfyUI_Security_Audit": [
|
||||
[
|
||||
"ComfyUI_Security_Audit"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_Security_Audit"
|
||||
}
|
||||
],
|
||||
"https://github.com/rossturk/comfyui-primitive-mesh": [
|
||||
[
|
||||
"PrimitiveMeshNode"
|
||||
@ -13040,6 +13150,8 @@
|
||||
"ImageListConverter",
|
||||
"ImageResizer",
|
||||
"ImageSelector",
|
||||
"KeywordFilter",
|
||||
"KeywordFilterLoRA",
|
||||
"MaskApplierAndCombiner",
|
||||
"MaskBlackener",
|
||||
"MaskMerger",
|
||||
@ -13162,126 +13274,6 @@
|
||||
"title_aux": "ComfyUI-SilentRain"
|
||||
}
|
||||
],
|
||||
"https://github.com/silveroxides/ComfyUI_CondsUtils": [
|
||||
[
|
||||
"InsertAttnConds",
|
||||
"InsertTEConds",
|
||||
"LoadReduxEmb",
|
||||
"LoadTEConds",
|
||||
"SaveCondsEmb",
|
||||
"SaveReduxEmb"
|
||||
],
|
||||
{
|
||||
"title_aux": "WIP Conditioning Toolkit [UNSAFE]"
|
||||
}
|
||||
],
|
||||
"https://github.com/silveroxides/ComfyUI_LoHalo": [
|
||||
[
|
||||
"LohaloHighFidelityScaler",
|
||||
"LohaloKernelScalingNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_LoHalo"
|
||||
}
|
||||
],
|
||||
"https://github.com/silveroxides/ComfyUI_LogicMath": [
|
||||
[
|
||||
"LogicAND",
|
||||
"LogicIF",
|
||||
"LogicNOT",
|
||||
"LogicOR",
|
||||
"LogicXOR",
|
||||
"MathAbs",
|
||||
"MathAdd",
|
||||
"MathCeil",
|
||||
"MathClamp",
|
||||
"MathCompare",
|
||||
"MathCos",
|
||||
"MathDivide",
|
||||
"MathFloor",
|
||||
"MathMax",
|
||||
"MathMin",
|
||||
"MathModulo",
|
||||
"MathMultiply",
|
||||
"MathNumberConvert",
|
||||
"MathOperation",
|
||||
"MathPower",
|
||||
"MathRound",
|
||||
"MathSin",
|
||||
"MathSqrt",
|
||||
"MathSubtract",
|
||||
"MathTan",
|
||||
"NumberToString",
|
||||
"StringToNumber"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_LogicMath"
|
||||
}
|
||||
],
|
||||
"https://github.com/silveroxides/ComfyUI_PromptAttention": [
|
||||
[
|
||||
"CLIPTextEncodeAttentionBias"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_PromptAttention [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/silveroxides/ComfyUI_ReduxEmbedToolkit": [
|
||||
[
|
||||
"InsertAttnConds",
|
||||
"InsertTEConds",
|
||||
"LoadReduxEmb",
|
||||
"LoadTEConds",
|
||||
"SaveCondsEmb",
|
||||
"SaveReduxEmb"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_ReduxEmbedToolkit"
|
||||
}
|
||||
],
|
||||
"https://github.com/silveroxides/ComfyUI_SamplingUtils": [
|
||||
[
|
||||
"AdjustedResolutionParameters",
|
||||
"BonusPromptPresets",
|
||||
"CameraShotPresets",
|
||||
"EditOpPresets",
|
||||
"EditTargetPresets",
|
||||
"Frakturpad",
|
||||
"GetJsonKeyValue",
|
||||
"IdeographicLinePad",
|
||||
"IdeographicSentencePad",
|
||||
"IdeographicTagPad",
|
||||
"ImageBlendByMask",
|
||||
"ImageMatchProperties",
|
||||
"Image_Color_Noise",
|
||||
"InstructPromptPresets",
|
||||
"IntegerRangeRandom",
|
||||
"JoinerPadding",
|
||||
"LlTokenizerOptions",
|
||||
"ModifyMask",
|
||||
"OpticalFlowComposite",
|
||||
"PrimitiveRandomInt",
|
||||
"PrimitiveStaticInt",
|
||||
"SU_LoadImageDirectory",
|
||||
"SU_LoadImagePath",
|
||||
"SamplingParameters",
|
||||
"SystemMessagePresets",
|
||||
"TagNormalizeCombine",
|
||||
"TextEncodeFlux2SystemPrompt",
|
||||
"TextEncodeKleinSystemPrompt",
|
||||
"TextEncodeSystemPrompt",
|
||||
"TextEncodeZITSystemPrompt",
|
||||
"TextEncodeZImageThinkPrompt",
|
||||
"TextOverlayNode",
|
||||
"UnFrakturPad",
|
||||
"UnifiedPresets",
|
||||
"VLMSysInstrAdvPresets",
|
||||
"VLMSysInstrPresets"
|
||||
],
|
||||
{
|
||||
"title_aux": "Sampling Utility Toolkit"
|
||||
}
|
||||
],
|
||||
"https://github.com/simonjaq/ComfyUI-sjnodes": [
|
||||
[
|
||||
"CrossFadeVideo",
|
||||
@ -13456,6 +13448,9 @@
|
||||
[
|
||||
"AddNumbers",
|
||||
"Character",
|
||||
"CharacterPrompt",
|
||||
"CharacterPromptWithLora",
|
||||
"CharacterPromptWithLoraWithDualModel",
|
||||
"CombineStrings",
|
||||
"Connector",
|
||||
"FloatToStr",
|
||||
@ -13466,6 +13461,7 @@
|
||||
"ResFinder",
|
||||
"SSchlTextEncoder",
|
||||
"ShowText",
|
||||
"Switch",
|
||||
"TextAppender"
|
||||
],
|
||||
{
|
||||
@ -14339,8 +14335,6 @@
|
||||
],
|
||||
"https://github.com/usrname0/ComfyUI-AllergicPack": [
|
||||
[
|
||||
"AudioAnalyzerNode",
|
||||
"AudioAnalyzerUploadNode",
|
||||
"FolderFileCounter",
|
||||
"IncrementorPlus",
|
||||
"MasterBatcher",
|
||||
@ -15261,6 +15255,21 @@
|
||||
"title_aux": "ComfyUI-prompt-library"
|
||||
}
|
||||
],
|
||||
"https://github.com/zinigo-creations/comfyui-prompt-builder": [
|
||||
[
|
||||
"ActionNode",
|
||||
"CharacterNode",
|
||||
"CombinePromptNode",
|
||||
"CompositionNode",
|
||||
"EnvironmentNode",
|
||||
"NSFWNode",
|
||||
"PresetCharacterNode",
|
||||
"StylePresetNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "Prompt Builder [NAME CONFLICT]"
|
||||
}
|
||||
],
|
||||
"https://github.com/zjkhurry/comfyui_MetalFX": [
|
||||
[
|
||||
"metalFXImg"
|
||||
@ -15280,7 +15289,8 @@
|
||||
"https://github.com/zopieux/ComfyUI-zopi": [
|
||||
[
|
||||
"EvalPython",
|
||||
"LoadTensortRTAndCheckpoint"
|
||||
"LoadTensortRTAndCheckpoint",
|
||||
"SizeSelector"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-zopi [UNSAFE]"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,175 @@
|
||||
{
|
||||
"custom_nodes": [
|
||||
{
|
||||
"author": "qlikpetersen",
|
||||
"title": "ComfyUI-AI_Tools [UNSAFE] [REMOVED]",
|
||||
"reference": "https://github.com/qlikpetersen/ComfyUI-AI_Tools",
|
||||
"files": [
|
||||
"https://github.com/qlikpetersen/ComfyUI-AI_Tools"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: DoLogin, HttpRequest, Json2String, String2Json, CreateListString, CreateListJSON, Query_OpenAI, Image_Attachment, JSON_Attachment, String_Attachment, RunPython\n[w/This nodepack contains a node with a vulnerability that allows arbitrary code execution.]"
|
||||
},
|
||||
{
|
||||
"author": "AiSatan",
|
||||
"title": "ComfyUI_CSM [NAME CONFLICT] [REMOVED]",
|
||||
"reference": "https://github.com/AiSatan/ComfyUI_CSM",
|
||||
"files": [
|
||||
"https://github.com/AiSatan/ComfyUI_CSM"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A ComfyUI node for the CSM model featuring text-to-speech, voice cloning, and automatic model downloading from Hugging Face."
|
||||
},
|
||||
{
|
||||
"author": "shiertier",
|
||||
"title": "ComfyUI-TeaCache-Lumina [REMOVED]",
|
||||
"reference": "https://github.com/shiertier/ComfyUI-TeaCache-lumina2",
|
||||
"files": [
|
||||
"https://github.com/shiertier/ComfyUI-TeaCache-lumina2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI Node Implementation: TeaCache Acceleration Specifically Designed for the Lumina Model"
|
||||
},
|
||||
{
|
||||
"author": "Daniel Lewis",
|
||||
"title": "ComfyUI-TTS [REMOVED]",
|
||||
"reference": "https://github.com/daniel-lewis-ab/ComfyUI-TTS",
|
||||
"files": [
|
||||
"https://github.com/daniel-lewis-ab/ComfyUI-TTS"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Text To Speech (TTS) for ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "Daniel Lewis",
|
||||
"title": "ComfyUI-Llama [REMOVED]",
|
||||
"reference": "https://github.com/daniel-lewis-ab/ComfyUI-Llama",
|
||||
"files": [
|
||||
"https://github.com/daniel-lewis-ab/ComfyUI-Llama"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is a set of nodes to interact with llama-cpp-python"
|
||||
},
|
||||
{
|
||||
"author": "Solarish",
|
||||
"title": "fyUI-MidnightLook [REMOVED]",
|
||||
"reference": "https://github.com/Solarish/ComfyUI-MidnightLook",
|
||||
"files": [
|
||||
"https://github.com/Solarish/ComfyUI-MidnightLook"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Custom node for MidnightLook.com\nNOTE: The files in the repo are not organized."
|
||||
},
|
||||
{
|
||||
"author": "pdale-boop",
|
||||
"title": "Network Guardian [REMOVED]",
|
||||
"reference": "https://github.com/pdale-boop/Comfyui-Network-Guardian",
|
||||
"files": [
|
||||
"https://github.com/pdale-boop/Comfyui-Network-Guardian"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Protects ComfyUI workflows from network interruptions with automatic retry and fallback"
|
||||
},
|
||||
{
|
||||
"author": "rodpl",
|
||||
"title": "comfyui-asset-manager [INCOMPLETE]",
|
||||
"reference": "https://github.com/rodpl/comfyui-asset-manager",
|
||||
"files": [
|
||||
"https://github.com/rodpl/comfyui-asset-manager"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI Asset Manager for managing assets in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "DailyMok",
|
||||
"title": "ComfyUI-PromptMixerNode [REMOVED]",
|
||||
"reference": "https://github.com/DailyMok/ComfyUI-PromptMixerNode",
|
||||
"files": [
|
||||
"https://github.com/DailyMok/ComfyUI-PromptMixerNode"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI custom node for prompt mixing with PromptMixerDaily node. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "IvanZhd",
|
||||
"title": "comfyui-codeformer [REMOVED]",
|
||||
"reference": "https://github.com/IvanZhd/comfyui-codeformer",
|
||||
"files": [
|
||||
"https://github.com/IvanZhd/comfyui-codeformer"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes:Image Inverter"
|
||||
},
|
||||
{
|
||||
"author": "Kur0butiMegane",
|
||||
"title": "Comfyui-StringUtils [REMOVED]",
|
||||
"reference": "https://github.com/Kur0butiMegane/Comfyui-StringUtils2",
|
||||
"files": [
|
||||
"https://github.com/Kur0butiMegane/Comfyui-StringUtils2"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "NODES: Normalizer, Splitter, Selector, XML Parser, XML Parser, Make Property, Add XML Tag, Is String Empty, Cond Passthrough, CLIP Passthrough, ClipRegion Passthrough, Scheduler Selector (Impact), Scheduler Selector (Inspire), Save Text, XML to Cutoff"
|
||||
},
|
||||
{
|
||||
"author": "rookiestar28",
|
||||
"title": "ComfyUI_Security_Audit [REMOVED]",
|
||||
"reference": "https://github.com/rookiestar28/ComfyUI_Security_Audit",
|
||||
"files": [
|
||||
"https://github.com/rookiestar28/ComfyUI_Security_Audit"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A lightweight, dual-layer security extension for ComfyUI using AST-based static analysis and runtime monitoring to detect malicious code in custom nodes."
|
||||
},
|
||||
{
|
||||
"author": "hw5511",
|
||||
"title": "Woohee HF Upscaler Loader [REMOVED]",
|
||||
"reference": "https://github.com/hw5511/comfyui_hf_upscaler_loader",
|
||||
"files": [
|
||||
"https://github.com/hw5511/comfyui_hf_upscaler_loader"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Load upscale models directly from Hugging Face Hub in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "arthur",
|
||||
"title": "Video Output Bridge [REMOVED]",
|
||||
"reference": "https://github.com/arthurtravers/ComfyUI-VideoOutputBridge",
|
||||
"files": [
|
||||
"https://github.com/arthurtravers/ComfyUI-VideoOutputBridge"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Bridge VHS_VideoCombine video outputs to standard image payloads for serverless runners (RunPod, Modal). Enables automatic S3 uploads of MP4/WebP files in worker-comfyui deployments."
|
||||
},
|
||||
{
|
||||
"author": "UmeAiRT",
|
||||
"title": "ComfyUI-UmeAiRT-Sync [REMOVED]",
|
||||
"reference": "https://github.com/UmeAiRT/ComfyUI-UmeAiRT-Sync",
|
||||
"files": [
|
||||
"https://github.com/UmeAiRT/ComfyUI-UmeAiRT-Sync"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Automatic workflow synchronizer/loader for UmeAiRT Workflows (Flux, SDXL, WAN, etc.)."
|
||||
},
|
||||
{
|
||||
"author": "UmeAiRT",
|
||||
"title": "UmeAiRT-Toolkit [REMOVED]",
|
||||
"reference": "https://github.com/UmeAiRT/ComfyUI-UmeAiRT-Toolkit",
|
||||
"files": [
|
||||
"https://github.com/UmeAiRT/ComfyUI-UmeAiRT-Toolkit"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A Wireless, Nodes 2.0 Ready, and Aesthetic Toolkit for ComfyUI."
|
||||
},
|
||||
{
|
||||
"author": "sln77",
|
||||
"title": "ComfyUI-Camie-Tagger [REMOVED]",
|
||||
"reference": "https://github.com/sln77/ComfyUI-Camie-Tagger",
|
||||
"files": [
|
||||
"https://github.com/sln77/ComfyUI-Camie-Tagger"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI node integration for the Camie tagger v2 model from Hugging Face for image tagging. (Description by CC)"
|
||||
},
|
||||
{
|
||||
"author": "vegaflowltd",
|
||||
"title": "Vega Flow V8.9 — Temporal Stabilisation [REMOVED]",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
217
openapi.yaml
217
openapi.yaml
@ -191,11 +191,20 @@ paths:
|
||||
description: Mapping of node packages to node classes
|
||||
|
||||
/customnode/fetch_updates:
|
||||
get:
|
||||
post:
|
||||
summary: Check for updates
|
||||
description: Fetches updates for custom nodes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/modeParam'
|
||||
requestBody:
|
||||
required: false
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
enum: [local, remote, default]
|
||||
description: Source mode (e.g., "local", "remote")
|
||||
responses:
|
||||
'200':
|
||||
description: No updates available
|
||||
@ -423,13 +432,22 @@ paths:
|
||||
|
||||
# Queue Management Endpoints
|
||||
/manager/queue/update_all:
|
||||
get:
|
||||
post:
|
||||
summary: Update all custom nodes
|
||||
description: Queues update operations for all installed custom nodes
|
||||
security:
|
||||
- securityLevel: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/modeParam'
|
||||
requestBody:
|
||||
required: false
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
enum: [local, remote, default]
|
||||
description: Source mode (e.g., "local", "remote")
|
||||
responses:
|
||||
'200':
|
||||
description: Update queued successfully
|
||||
@ -439,7 +457,7 @@ paths:
|
||||
description: Security policy violation
|
||||
|
||||
/manager/queue/reset:
|
||||
get:
|
||||
post:
|
||||
summary: Reset queue
|
||||
description: Resets the operation queue
|
||||
responses:
|
||||
@ -479,7 +497,7 @@ paths:
|
||||
description: Target node not found or security issue
|
||||
|
||||
/manager/queue/start:
|
||||
get:
|
||||
post:
|
||||
summary: Start queue processing
|
||||
description: Starts processing the operation queue
|
||||
responses:
|
||||
@ -575,7 +593,7 @@ paths:
|
||||
description: Disable operation queued successfully
|
||||
|
||||
/manager/queue/update_comfyui:
|
||||
get:
|
||||
post:
|
||||
summary: Update ComfyUI
|
||||
description: Queues an update operation for ComfyUI itself
|
||||
responses:
|
||||
@ -621,13 +639,22 @@ paths:
|
||||
$ref: '#/components/schemas/SnapshotItem'
|
||||
|
||||
/snapshot/remove:
|
||||
get:
|
||||
post:
|
||||
summary: Remove snapshot
|
||||
description: Removes a specified snapshot
|
||||
security:
|
||||
- securityLevel: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/targetParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [target]
|
||||
properties:
|
||||
target:
|
||||
type: string
|
||||
description: Target identifier
|
||||
responses:
|
||||
'200':
|
||||
description: Snapshot removed successfully
|
||||
@ -637,13 +664,22 @@ paths:
|
||||
description: Security policy violation
|
||||
|
||||
/snapshot/restore:
|
||||
get:
|
||||
post:
|
||||
summary: Restore snapshot
|
||||
description: Restores a specified snapshot
|
||||
security:
|
||||
- securityLevel: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/targetParam'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [target]
|
||||
properties:
|
||||
target:
|
||||
type: string
|
||||
description: Target identifier
|
||||
responses:
|
||||
'200':
|
||||
description: Snapshot restoration scheduled
|
||||
@ -667,7 +703,7 @@ paths:
|
||||
description: Error creating snapshot
|
||||
|
||||
/snapshot/save:
|
||||
get:
|
||||
post:
|
||||
summary: Save snapshot
|
||||
description: Saves the current system state as a new snapshot
|
||||
responses:
|
||||
@ -699,15 +735,19 @@ paths:
|
||||
description: Error retrieving versions
|
||||
|
||||
/comfyui_manager/comfyui_switch_version:
|
||||
get:
|
||||
post:
|
||||
summary: Switch ComfyUI version
|
||||
description: Switches to a specified ComfyUI version
|
||||
parameters:
|
||||
- name: ver
|
||||
in: query
|
||||
description: Target version
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: false
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
ver:
|
||||
type: string
|
||||
description: Target version
|
||||
responses:
|
||||
'200':
|
||||
description: Version switch successful
|
||||
@ -715,7 +755,7 @@ paths:
|
||||
description: Error switching version
|
||||
|
||||
/manager/reboot:
|
||||
get:
|
||||
post:
|
||||
summary: Reboot ComfyUI
|
||||
description: Restarts the ComfyUI server
|
||||
security:
|
||||
@ -746,7 +786,32 @@ paths:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
post:
|
||||
summary: Set preview method
|
||||
description: Sets the latent preview method (write-only; use GET to read)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [value]
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
enum: [auto, latent2rgb, taesd, none]
|
||||
description: New preview method
|
||||
responses:
|
||||
'200':
|
||||
description: Setting updated
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Invalid value
|
||||
|
||||
|
||||
/manager/db_mode:
|
||||
get:
|
||||
summary: Get or set database mode
|
||||
@ -766,7 +831,32 @@ paths:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
post:
|
||||
summary: Set database mode
|
||||
description: Sets the database mode (write-only; use GET to read)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [value]
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
enum: [channel, local, remote]
|
||||
description: New database mode
|
||||
responses:
|
||||
'200':
|
||||
description: Setting updated
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Invalid value
|
||||
|
||||
|
||||
/manager/policy/component:
|
||||
get:
|
||||
summary: Get or set component policy
|
||||
@ -785,7 +875,29 @@ paths:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
post:
|
||||
summary: Set component policy
|
||||
description: Sets the component policy (write-only; use GET to read)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [value]
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
description: New component policy
|
||||
responses:
|
||||
'200':
|
||||
description: Setting updated
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
|
||||
/manager/policy/update:
|
||||
get:
|
||||
summary: Get or set update policy
|
||||
@ -805,7 +917,32 @@ paths:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
post:
|
||||
summary: Set update policy
|
||||
description: Sets the update policy (write-only; use GET to read)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [value]
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
enum: [stable, nightly, nightly-comfyui]
|
||||
description: New update policy
|
||||
responses:
|
||||
'200':
|
||||
description: Setting updated
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Invalid value
|
||||
|
||||
|
||||
/manager/channel_url_list:
|
||||
get:
|
||||
summary: Get or set channel URL
|
||||
@ -836,7 +973,29 @@ paths:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
|
||||
post:
|
||||
summary: Set channel URL
|
||||
description: Sets the channel URL for custom node sources (write-only; use GET to read current + list)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [value]
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
description: New channel name
|
||||
responses:
|
||||
'200':
|
||||
description: Setting updated
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
|
||||
# Component Management Endpoints
|
||||
/manager/component/save:
|
||||
post:
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-manager"
|
||||
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
||||
version = "3.39.3"
|
||||
version = "3.40"
|
||||
license = { file = "LICENSE.txt" }
|
||||
dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]
|
||||
|
||||
|
||||
121
tests/test_csrf_content_type_helper.py
Normal file
121
tests/test_csrf_content_type_helper.py
Normal file
@ -0,0 +1,121 @@
|
||||
"""AC verification for wi-001 (B2): Content-Type rejection helper.
|
||||
|
||||
Validates _reject_simple_form_content_type against the 5-item curl matrix
|
||||
from the WI's acceptance criteria using aiohttp test client. The test
|
||||
builds a minimal aiohttp app that mirrors the helper's wiring into a
|
||||
no-body POST handler, so we exercise the real request.content_type
|
||||
parsing path rather than a mock.
|
||||
|
||||
AC matrix:
|
||||
form-url → 400
|
||||
multipart → 400
|
||||
text/plain → 400
|
||||
no-CT → 200
|
||||
application/json → 200
|
||||
"""
|
||||
import asyncio
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from aiohttp import web
|
||||
from aiohttp.test_utils import TestClient, TestServer
|
||||
|
||||
|
||||
# Parse the helper from manager_server.py without importing it, to avoid
|
||||
# pulling in the full ComfyUI/PromptServer stack. Note: we intentionally do
|
||||
# NOT add the `glob/` directory to sys.path — the dir name would shadow
|
||||
# Python's stdlib `glob` module and break pytest collection.
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def _load_helper():
|
||||
"""Parse manager_server.py and execute only the helper definition."""
|
||||
import ast
|
||||
|
||||
source = (REPO_ROOT / "glob" / "manager_server.py").read_text()
|
||||
tree = ast.parse(source)
|
||||
wanted = {"_SIMPLE_FORM_CONTENT_TYPES", "_reject_simple_form_content_type"}
|
||||
nodes = []
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and target.id in wanted:
|
||||
nodes.append(node)
|
||||
elif isinstance(node, ast.FunctionDef) and node.name in wanted:
|
||||
nodes.append(node)
|
||||
module = ast.Module(body=nodes, type_ignores=[])
|
||||
ns = {"web": web, "frozenset": frozenset}
|
||||
exec(compile(module, "manager_server_helpers", "exec"), ns)
|
||||
return ns["_reject_simple_form_content_type"]
|
||||
|
||||
|
||||
_reject_simple_form_content_type = _load_helper()
|
||||
|
||||
|
||||
async def _handler(request):
|
||||
resp = _reject_simple_form_content_type(request)
|
||||
if resp is not None:
|
||||
return resp
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
class ContentTypeRejectionTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(cls.loop)
|
||||
app = web.Application()
|
||||
app.router.add_post("/noop", _handler)
|
||||
cls.server = TestServer(app, loop=cls.loop)
|
||||
cls.client = TestClient(cls.server, loop=cls.loop)
|
||||
cls.loop.run_until_complete(cls.client.start_server())
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.loop.run_until_complete(cls.client.close())
|
||||
cls.loop.close()
|
||||
|
||||
def _post(self, headers):
|
||||
async def go():
|
||||
return await self.client.post("/noop", headers=headers, data=b"")
|
||||
|
||||
return self.loop.run_until_complete(go())
|
||||
|
||||
def test_form_urlencoded_rejected(self):
|
||||
r = self._post({"Content-Type": "application/x-www-form-urlencoded"})
|
||||
self.assertEqual(r.status, 400)
|
||||
|
||||
def test_multipart_form_data_rejected(self):
|
||||
# aiohttp requires a boundary for multipart; helper should still reject
|
||||
# based on the primary mimetype.
|
||||
r = self._post({"Content-Type": "multipart/form-data; boundary=xyz"})
|
||||
self.assertEqual(r.status, 400)
|
||||
|
||||
def test_text_plain_rejected(self):
|
||||
r = self._post({"Content-Type": "text/plain"})
|
||||
self.assertEqual(r.status, 400)
|
||||
|
||||
def test_no_content_type_allowed(self):
|
||||
# Explicitly strip Content-Type: aiohttp client may add a default,
|
||||
# so we use a raw request to ensure absence is tested.
|
||||
async def go():
|
||||
import aiohttp
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(
|
||||
self.client.make_url("/noop"),
|
||||
data=None,
|
||||
skip_auto_headers=["Content-Type"],
|
||||
) as resp:
|
||||
return resp.status
|
||||
|
||||
status = self.loop.run_until_complete(go())
|
||||
self.assertEqual(status, 200)
|
||||
|
||||
def test_application_json_allowed(self):
|
||||
r = self._post({"Content-Type": "application/json"})
|
||||
self.assertEqual(r.status, 200)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Loading…
Reference in New Issue
Block a user