From 60386b569e7b9914bb98e2fe559f71f40f5a1aa2 Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Sat, 23 Dec 2023 16:16:11 +0900 Subject: [PATCH] feat: custom node install api --- __init__.py | 45 ++++++++++++++++++++++++++++++- js/cm-api.js | 54 ++++++++++++++++++++++++++++++++++++++ js/comfyui-share-common.js | 2 +- js/common.js | 4 +++ prestartup_script.py | 3 +++ 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 js/cm-api.js diff --git a/__init__.py b/__init__.py index b628ea56..06130200 100644 --- a/__init__.py +++ b/__init__.py @@ -20,7 +20,7 @@ import nodes import torch -version = [1, 15, 1] +version = [1, 16] version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '') print(f"### Loading: ComfyUI-Manager ({version_str})") @@ -1968,6 +1968,49 @@ async def share_art(request): }, content_type='application/json', status=200) + +def register_api(k, f): + sys.CM_api[k] = f + + +def sanitize(data): + return data.replace("<", "<").replace(">", ">") + + +def lookup_customnode_by_url(data, target): + for x in data['custom_nodes']: + if target in x['files']: + dir_name = os.path.splitext(os.path.basename(target))[0].replace(".git", "") + dir_path = os.path.join(custom_nodes_path, dir_name) + if os.path.exists(dir_path): + x['installed'] = 'True' + elif os.path.exists(dir_path + ".disabled"): + x['installed'] = 'Disabled' + return x + + return None + + +async def _confirm_try_install(sender, custom_node_url, msg): + json_obj = await get_data_by_mode('default', 'custom-node-list.json') + + sender = sanitize(sender) + msg = sanitize(msg) + target = lookup_customnode_by_url(json_obj, custom_node_url) + + if target is not None: + server.PromptServer.instance.send_sync("cm-api-try-install-customnode", + {"sender": sender, "target": target, "msg": msg}) + else: + print(f"[ComfyUI Manager API] Failed to try install - Unknown custom node url '{custom_node_url}'") + + +def confirm_try_install(sender, custom_node_url, msg): + asyncio.run(_confirm_try_install(sender, custom_node_url, msg)) + +register_api('cm.try-install-custom-node', confirm_try_install) + + import asyncio async def default_cache_update(): async def get_cache(filename): diff --git a/js/cm-api.js b/js/cm-api.js new file mode 100644 index 00000000..e65cb348 --- /dev/null +++ b/js/cm-api.js @@ -0,0 +1,54 @@ +import { api } from "../../scripts/api.js"; +import { app } from "../../scripts/app.js"; +import { sleep } from "./common.js"; + +async function tryInstallCustomNode(event) { + let msg = '-= [ComfyUI Manager] extension installation request =-\n\n'; + msg += `The '${event.detail.sender}' extension requires the installation of the '${event.detail.title}' extension. `; + + if(event.detail.target.installed == 'Disabled') { + msg += 'However, the extension is currently disabled. Would you like to enable it and reboot?' + } + else if(event.detail.target.installed == 'True') { + msg += 'However, it seems that the extension is in an import-fail state or is not compatible with the current version. Please address this issue.'; + } + else { + msg += `Would you like to install it and reboot?`; + } + + msg += `\n\nRequest message:\n${event.detail.msg}`; + + if(event.detail.target.installed == 'True') { + alert(msg); + return; + } + + let res = confirm(msg); + if(res) { + if(event.detail.target.installed == 'Disabled') { + const response = await api.fetchApi(`/customnode/toggle_active`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(event.detail.target) + }); + } + else { + await sleep(300); + app.ui.dialog.show(`Installing... '${event.detail.target.title}'`); + + const response = await api.fetchApi(`/customnode/install`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(event.detail.target) + }); + } + + api.fetchApi("/manager/reboot"); + + await sleep(300); + + app.ui.dialog.show(`Rebooting...`); + } +} + +api.addEventListener("cm-api-try-install-customnode", tryInstallCustomNode); diff --git a/js/comfyui-share-common.js b/js/comfyui-share-common.js index 451a7197..e7506665 100644 --- a/js/comfyui-share-common.js +++ b/js/comfyui-share-common.js @@ -1,5 +1,5 @@ import { app } from "../../scripts/app.js"; -import { api } from "../../scripts/api.js" +import { api } from "../../scripts/api.js"; import { ComfyDialog, $el } from "../../scripts/ui.js"; import { OpenArtShareDialog } from "./comfyui-share-openart.js"; diff --git a/js/common.js b/js/common.js index 5550eca5..c507dddd 100644 --- a/js/common.js +++ b/js/common.js @@ -1,6 +1,10 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js" +export async function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + export function rebootAPI() { if (confirm("Are you sure you'd like to reboot the server?")) { try { diff --git a/prestartup_script.py b/prestartup_script.py index 721cf85d..8d472cbc 100644 --- a/prestartup_script.py +++ b/prestartup_script.py @@ -9,6 +9,9 @@ import locale import platform +sys.CM_api = {} + + message_collapses = [] import_failed_extensions = set()