diff --git a/glob/cnr_utils.py b/glob/cnr_utils.py index b56b900b..3c6431e8 100644 --- a/glob/cnr_utils.py +++ b/glob/cnr_utils.py @@ -129,3 +129,26 @@ def read_cnr_info(fullpath): return None except Exception: return None # not valid CNR node pack + + +def generate_cnr_id(fullpath, cnr_id): + cnr_id_path = os.path.join(fullpath, '.git', '.cnr-id') + try: + if not os.path.exists(cnr_id_path): + with open(cnr_id_path, "w") as f: + return f.write(cnr_id) + except: + print(f"[ComfyUI Manager] unable to create file: {cnr_id_path}") + + +def read_cnr_id(fullpath): + cnr_id_path = os.path.join(fullpath, '.git', '.cnr-id') + try: + if os.path.exists(cnr_id_path): + with open(cnr_id_path) as f: + return f.read().strip() + except: + pass + + return None + diff --git a/glob/manager_core.py b/glob/manager_core.py index 8f4557e0..d157a93c 100644 --- a/glob/manager_core.py +++ b/glob/manager_core.py @@ -41,7 +41,7 @@ import manager_downloader from node_package import InstalledNodePackage -version_code = [3, 3, 13] +version_code = [3, 4] version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') @@ -466,6 +466,7 @@ class UnifiedManager: cnr = self.get_cnr_by_repo(url) commit_hash = git_utils.get_commit_hash(fullpath) if cnr: + cnr_utils.generate_cnr_id(fullpath, cnr['id']) return {'id': cnr['id'], 'cnr': cnr, 'ver': 'nightly', 'hash': commit_hash} else: url = os.path.basename(url) @@ -1327,6 +1328,7 @@ class UnifiedManager: if version_spec == 'unknown': self.unknown_active_nodes[node_id] = to_path elif version_spec == 'nightly': + cnr_utils.generate_cnr_id(to_path, node_id) self.active_nodes[node_id] = 'nightly', to_path return res.with_target(version_spec) @@ -1379,6 +1381,63 @@ class UnifiedManager: unified_manager = UnifiedManager() +def identify_node_pack_from_path(fullpath): + module_name = os.path.basename(fullpath) + if module_name.endswith('.git'): + module_name = module_name[:-4] + + repo_url = git_utils.git_url(fullpath) + if repo_url is None: + # cnr + cnr = cnr_utils.read_cnr_info(fullpath) + if cnr is not None: + return module_name, cnr['version'], cnr['id'] + + return None + else: + # nightly or unknown + cnr_id = cnr_utils.read_cnr_id(fullpath) + commit_hash = git_utils.get_commit_hash(fullpath) + + if cnr_id is not None: + return module_name, commit_hash, cnr_id + else: + return module_name, commit_hash, '' + + +def get_installed_node_packs(): + res = {} + + for x in get_custom_nodes_paths(): + for y in os.listdir(x): + if y == '__pycache__' or y == '.disabled': + continue + + fullpath = os.path.join(x, y) + info = identify_node_pack_from_path(fullpath) + if info is None: + continue + + is_disabled = not y.endswith('.disabled') + + res[info[0]] = { 'ver': info[1], 'cnr_id': info[2], 'enabled': is_disabled } + + disabled_dirs = os.path.join(x, '.disabled') + if os.path.exists(disabled_dirs): + for y in os.listdir(disabled_dirs): + if y == '__pycache__': + continue + + fullpath = os.path.join(disabled_dirs, y) + info = identify_node_pack_from_path(fullpath) + if info is None: + continue + + res[info[0]] = { 'ver': info[1], 'cnr_id': info[2], 'enabled': False } + + return res + + def get_channel_dict(): global channel_dict diff --git a/glob/manager_server.py b/glob/manager_server.py index 6ac7020c..89639594 100644 --- a/glob/manager_server.py +++ b/glob/manager_server.py @@ -537,17 +537,18 @@ def populate_markdown(x): x['title'] = manager_util.sanitize_tag(x['title']) +# freeze imported version +startup_time_installed_node_packs = core.get_installed_node_packs() @routes.get("/customnode/installed") async def installed_list(request): - unified_manager = core.unified_manager + mode = request.query.get('mode', 'default') - await unified_manager.reload('cache') - await unified_manager.get_custom_nodes('default', 'cache') + if mode == 'imported': + res = startup_time_installed_node_packs + else: + res = core.get_installed_node_packs() - return web.json_response({ - node_id: package.version if package.is_from_cnr else package.get_commit_hash() - for node_id, package in unified_manager.installed_node_packages.items() if not package.disabled - }, content_type='application/json') + return web.json_response(res, content_type='application/json') @routes.get("/customnode/getlist") diff --git a/js/workflow-metadata.js b/js/workflow-metadata.js index 7ebd2e53..c9935f9c 100644 --- a/js/workflow-metadata.js +++ b/js/workflow-metadata.js @@ -17,16 +17,18 @@ import { api } from "../../scripts/api.js"; class WorkflowMetadataExtension { constructor() { this.name = "Comfy.CustomNodesManager.WorkflowMetadata"; - this.installedNodeVersions = {}; + this.installedNodes = {}; this.comfyCoreVersion = null; } /** - * Get the installed node versions - * @returns {Promise>} The mapping from node name to version - * version can either be a git commit hash or a semantic version such as "1.0.0" + * Get the installed nodes info + * @returns {Promise>} The mapping from node name to its info. + * ver can either be a git commit hash or a semantic version such as "1.0.0" + * cnr_id is the id of the node in the ComfyRegistry + * enabled is true if the node is enabled, false if it is disabled */ - async getInstalledNodeVersions() { + async getInstalledNodes() { const res = await api.fetchApi("/customnode/installed"); return await res.json(); } @@ -48,8 +50,10 @@ class WorkflowMetadataExtension { if (modules[0] === "custom_nodes") { const nodePackageName = modules[1]; - const nodeVersion = this.installedNodeVersions[nodePackageName]; - nodeVersions[nodePackageName] = nodeVersion; + const nodeInfo = + this.installedNodes[nodePackageName] ?? + this.installedNodes[nodePackageName.toLowerCase()]; + nodeVersions[nodePackageName] = nodeInfo.ver; } else if (["nodes", "comfy_extras"].includes(modules[0])) { nodeVersions["comfy-core"] = this.comfyCoreVersion; } else { @@ -61,7 +65,7 @@ class WorkflowMetadataExtension { async init() { const extension = this; - this.installedNodeVersions = await this.getInstalledNodeVersions(); + this.installedNodes = await this.getInstalledNodes(); this.comfyCoreVersion = (await api.getSystemStats()).system.comfyui_version; // Attach metadata when app.graphToPrompt is called. diff --git a/pyproject.toml b/pyproject.toml index 623224f9..a668c2a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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.3.13" +version = "3.4" license = { file = "LICENSE.txt" } dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]