diff --git a/.gitignore b/.gitignore index e774ed6b..94d789b6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ matrix_auth channels.list comfyworkflows_sharekey github-stats-cache.json +pip_overrides.json \ No newline at end of file diff --git a/README.md b/README.md index 4f7616fb..37791381 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,9 @@ ![menu](misc/menu.jpg) ## NOTICE -* 🏆 Join us for the [ComfyUI Workflow Contest](https://contest.openart.ai/), hosted by OpenArt AI (11.27.2023 - 12.15.2023). Our esteemed judge panel includes Scott E. Detweiler, Olivio Sarikas, MERJIC麦橘, among others. We're also thrilled to have the authors of ComfyUI Manager and AnimateDiff as our special guests! -* If you wish to hide the "Share" button, click "Manager" and choose "Share: None" option. +* V2.21 [cm-cli](docs/en/cm-cli.md) tool is added. +* V2.18 to V2.18.3 is not functioning due to a severe bug. Users on these versions are advised to promptly update to V2.18.4. Please navigate to the `ComfyUI/custom_nodes/ComfyUI-Manager` directory and execute `git pull` to update. * You can see whole nodes info on [ComfyUI Nodes Info](https://ltdrdata.github.io/) page. -* Versions prior to V0.22.2 will no longer detect missing nodes unless using a local database. Please update ComfyUI-Manager to the latest version. ## Installation @@ -35,7 +34,7 @@ To install ComfyUI-Manager in addition to an existing installation of ComfyUI, y ### Installation[method3] (Installation for linux+venv: ComfyUI + ComfyUI-Manager) To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps: -prerequisite: python-is-python3, python3-venv +* **prerequisite: python-is-python3, python3-venv** 1. Download [scripts/install-comfyui-venv-linux.sh](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-comfyui-venv-linux.sh) into empty install directory - ComfyUI will be installed in the subdirectory of the specified directory, and the directory will contain the generated executable script. @@ -63,6 +62,7 @@ This repository provides Colab notebooks that allow you to install and use Comfy * Support for automatically installing dependencies of custom nodes upon restarting Colab notebooks. ## Changes +* **2.21** [cm-cli](docs/en/cm-cli.md) tool is added. * **2.4** Copy the connections of the nearest node by double-clicking. * **2.2.3** Support Components System * **0.29** Add `Update all` feature @@ -157,6 +157,12 @@ This repository provides Colab notebooks that allow you to install and use Comfy ![model-install-dialog](misc/snapshot.jpg) + +## cm-cli: command line tools for power user +* A tool is provided that allows you to use the features of ComfyUI-Manager without running ComfyUI. +* For more details, please refer to the [cm-cli documentation](docs/en/cm-cli.md). + + ## How to register your custom node into ComfyUI-Manager * Add an entry to `custom-node-list.json` located in the root of ComfyUI-Manager and submit a Pull Request. @@ -279,6 +285,26 @@ NODE_CLASS_MAPPINGS.update({ downgrade_blacklist = diffusers, kornia ``` +* Custom pip mapping + * When you create the `pip_overrides.json` file, it changes the installation of specific pip packages to installations defined by the user. + * Please refer to the `pip_overrides.json.template` file. + + +## Scanner +When you run the `scan.sh` script: + +* It updates the `extension-node-map.json`. + * To do this, it pulls or clones the custom nodes listed in `custom-node-list.json` into `~/.tmp/default`. + * To skip this step, add the `--skip-update` option. + * If you want to specify a different path instead of `~/.tmp/default`, run `python scanner.py [path]` directly instead of `scan.sh`. + +* It updates the `github-stats.json`. + * This uses the GitHub API, so set your token with `export GITHUB_TOKEN=your_token_here` to avoid quickly reaching the rate limit and malfunctioning. + * To skip this step, add the `--skip-update-stat` option. + +* The `--skip-all` option applies both `--skip-update` and `--skip-stat-update`. + + ## Troubleshooting * If your `git.exe` is installed in a specific location other than system git, please install ComfyUI-Manager and run ComfyUI. Then, specify the path including the file name in `git_exe = ` in the ComfyUI-Manager/config.ini file that is generated. * If updating ComfyUI-Manager itself fails, please go to the **ComfyUI-Manager** directory and execute the command `git update-ref refs/remotes/origin/main a361cc1 && git fetch --all && git pull`. diff --git a/__init__.py b/__init__.py index 9361c885..ab85975c 100644 --- a/__init__.py +++ b/__init__.py @@ -1,2531 +1,15 @@ -import configparser -import mimetypes -import shutil -import traceback - -import folder_paths import os -import sys -import threading -import locale -import subprocess # don't remove this -from tqdm.auto import tqdm -import concurrent -from urllib.parse import urlparse -import http.client -import re -import nodes -import hashlib -from datetime import datetime -from .glob.manager_util import * +cli_mode_flag = os.path.join(os.path.dirname(__file__), '.enable-cli-only-mode') -try: - import cm_global -except: - glob_path = os.path.join(os.path.dirname(__file__), "glob") - sys.path.append(glob_path) - import cm_global +if not os.path.exists(cli_mode_flag): + from .glob import manager_server + WEB_DIRECTORY = "js" +else: + print(f"\n[ComfyUI-Manager] !! cli-only-mode is enabled !!\n") - print(f"[WARN] ComfyUI-Manager: Your ComfyUI version is outdated. Please update to the latest version.") - - -version = [2, 16] -version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '') -print(f"### Loading: ComfyUI-Manager ({version_str})") - - -comfy_ui_hash = "-" - -cache_lock = threading.Lock() - -pip_map = None - - -def get_installed_packages(): - global pip_map - - if pip_map is None: - try: - result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True) - - pip_map = {} - for line in result.split('\n'): - x = line.strip() - if x: - y = line.split() - if y[0] == 'Package' or y[0].startswith('-'): - continue - - pip_map[y[0]] = y[1] - except subprocess.CalledProcessError as e: - print(f"[ComfyUI-Manager] Failed to retrieve the information of installed pip packages.") - return set() - - return pip_map - - -def clear_pip_cache(): - global pip_map - pip_map = None - - -def is_blacklisted(name): - name = name.strip() - - pattern = r'([^<>!=]+)([<>!=]=?)(.*)' - match = re.search(pattern, name) - - if match: - name = match.group(1) - - if name in cm_global.pip_downgrade_blacklist: - pips = get_installed_packages() - - if match is None: - if name in pips: - return True - elif match.group(2) in ['<=', '==', '<']: - if name in pips: - if StrictVersion(pips[name]) >= StrictVersion(match.group(3)): - return True - - return False - - -def handle_stream(stream, prefix): - stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace') - for msg in stream: - if prefix == '[!]' and ('it/s]' in msg or 's/it]' in msg) and ('%|' in msg or 'it [' in msg): - if msg.startswith('100%'): - print('\r' + msg, end="", file=sys.stderr), - else: - print('\r' + msg[:-1], end="", file=sys.stderr), - else: - if prefix == '[!]': - print(prefix, msg, end="", file=sys.stderr) - else: - print(prefix, msg, end="") - - -def run_script(cmd, cwd='.'): - if len(cmd) > 0 and cmd[0].startswith("#"): - print(f"[ComfyUI-Manager] Unexpected behavior: `{cmd}`") - return 0 - - process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1) - - stdout_thread = threading.Thread(target=handle_stream, args=(process.stdout, "")) - stderr_thread = threading.Thread(target=handle_stream, args=(process.stderr, "[!]")) - - stdout_thread.start() - stderr_thread.start() - - stdout_thread.join() - stderr_thread.join() - - return process.wait() - - -try: - import git -except: - my_path = os.path.dirname(__file__) - requirements_path = os.path.join(my_path, "requirements.txt") - - print(f"## ComfyUI-Manager: installing dependencies") - - run_script([sys.executable, '-s', '-m', 'pip', 'install', '-r', requirements_path]) - - try: - import git - except: - print(f"## [ERROR] ComfyUI-Manager: Attempting to reinstall dependencies using an alternative method.") - run_script([sys.executable, '-s', '-m', 'pip', 'install', '--user', '-r', requirements_path]) - - try: - import git - except: - print(f"## [ERROR] ComfyUI-Manager: Failed to install the GitPython package in the correct Python environment. Please install it manually in the appropriate environment. (You can seek help at https://app.element.io/#/room/%23comfyui_space%3Amatrix.org)") - - print(f"## ComfyUI-Manager: installing dependencies done.") - - -from git.remote import RemoteProgress - -sys.path.append('../..') - -from torchvision.datasets.utils import download_url - -comfy_ui_required_revision = 1930 -comfy_ui_required_commit_datetime = datetime(2024, 1, 24, 0, 0, 0) - -comfy_ui_revision = "Unknown" -comfy_ui_commit_datetime = datetime(1900, 1, 1, 0, 0, 0) - -comfy_path = os.path.dirname(folder_paths.__file__) -custom_nodes_path = os.path.join(comfy_path, 'custom_nodes') -js_path = os.path.join(comfy_path, "web", "extensions") - -comfyui_manager_path = os.path.dirname(__file__) -cache_dir = os.path.join(comfyui_manager_path, '.cache') -local_db_model = os.path.join(comfyui_manager_path, "model-list.json") -local_db_alter = os.path.join(comfyui_manager_path, "alter-list.json") -local_db_custom_node_list = os.path.join(comfyui_manager_path, "custom-node-list.json") -local_db_extension_node_mappings = os.path.join(comfyui_manager_path, "extension-node-map.json") -git_script_path = os.path.join(os.path.dirname(__file__), "git_helper.py") -components_path = os.path.join(comfyui_manager_path, 'components') - -startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts") -config_path = os.path.join(os.path.dirname(__file__), "config.ini") -cached_config = None - -channel_list_path = os.path.join(comfyui_manager_path, 'channels.list') -channel_dict = None -channel_list = None - -from comfy.cli_args import args -import latent_preview - - -def get_channel_dict(): - global channel_dict - - if channel_dict is None: - channel_dict = {} - - if not os.path.exists(channel_list_path): - shutil.copy(channel_list_path+'.template', channel_list_path) - - with open(os.path.join(comfyui_manager_path, 'channels.list'), 'r') as file: - channels = file.read() - for x in channels.split('\n'): - channel_info = x.split("::") - if len(channel_info) == 2: - channel_dict[channel_info[0]] = channel_info[1] - - return channel_dict - - -def get_channel_list(): - global channel_list - - if channel_list is None: - channel_list = [] - for k, v in get_channel_dict().items(): - channel_list.append(f"{k}::{v}") - - return channel_list - - -def write_config(): - config = configparser.ConfigParser() - config['default'] = { - 'preview_method': get_current_preview_method(), - 'badge_mode': get_config()['badge_mode'], - 'git_exe': get_config()['git_exe'], - 'channel_url': get_config()['channel_url'], - 'share_option': get_config()['share_option'], - 'bypass_ssl': get_config()['bypass_ssl'], - "file_logging": get_config()['file_logging'], - 'default_ui': get_config()['default_ui'], - 'component_policy': get_config()['component_policy'], - 'double_click_policy': get_config()['double_click_policy'], - 'windows_selector_event_loop_policy': get_config()['windows_selector_event_loop_policy'], - 'model_download_by_agent': get_config()['model_download_by_agent'], - 'downgrade_blacklist': get_config()['downgrade_blacklist'] - } - with open(config_path, 'w') as configfile: - config.write(configfile) - - -def read_config(): - try: - config = configparser.ConfigParser() - config.read(config_path) - default_conf = config['default'] - - return { - 'preview_method': default_conf['preview_method'] if 'preview_method' in default_conf else get_current_preview_method(), - 'badge_mode': default_conf['badge_mode'] if 'badge_mode' in default_conf else 'none', - 'git_exe': default_conf['git_exe'] if 'git_exe' in default_conf else '', - 'channel_url': default_conf['channel_url'] if 'channel_url' in default_conf else 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main', - 'share_option': default_conf['share_option'] if 'share_option' in default_conf else 'all', - 'bypass_ssl': default_conf['bypass_ssl'] if 'bypass_ssl' in default_conf else False, - 'file_logging': default_conf['file_logging'] if 'file_logging' in default_conf else True, - 'default_ui': default_conf['default_ui'] if 'default_ui' in default_conf else 'none', - 'component_policy': default_conf['component_policy'] if 'component_policy' in default_conf else 'workflow', - 'double_click_policy': default_conf['double_click_policy'] if 'double_click_policy' in default_conf else 'copy-all', - 'windows_selector_event_loop_policy': default_conf['windows_selector_event_loop_policy'] if 'windows_selector_event_loop_policy' in default_conf else False, - 'model_download_by_agent': default_conf['model_download_by_agent'] if 'model_download_by_agent' in default_conf else False, - 'downgrade_blacklist': default_conf['downgrade_blacklist'] if 'downgrade_blacklist' in default_conf else '', - } - - except Exception: - return { - 'preview_method': get_current_preview_method(), - 'badge_mode': 'none', - 'git_exe': '', - 'channel_url': 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main', - 'share_option': 'all', - 'bypass_ssl': False, - 'file_logging': True, - 'default_ui': 'none', - 'component_policy': 'workflow', - 'double_click_policy': 'copy-all', - 'windows_selector_event_loop_policy': False, - 'model_download_by_agent': False, - 'downgrade_blacklist': '' - } - - -def get_config(): - global cached_config - - if cached_config is None: - cached_config = read_config() - - return cached_config - - -def get_current_preview_method(): - if args.preview_method == latent_preview.LatentPreviewMethod.Auto: - return "auto" - elif args.preview_method == latent_preview.LatentPreviewMethod.Latent2RGB: - return "latent2rgb" - elif args.preview_method == latent_preview.LatentPreviewMethod.TAESD: - return "taesd" - else: - return "none" - - -def set_preview_method(method): - if method == 'auto': - args.preview_method = latent_preview.LatentPreviewMethod.Auto - elif method == 'latent2rgb': - args.preview_method = latent_preview.LatentPreviewMethod.Latent2RGB - elif method == 'taesd': - args.preview_method = latent_preview.LatentPreviewMethod.TAESD - else: - args.preview_method = latent_preview.LatentPreviewMethod.NoPreviews - - get_config()['preview_method'] = args.preview_method - - -set_preview_method(get_config()['preview_method']) - - -def set_badge_mode(mode): - get_config()['badge_mode'] = mode - - -def set_default_ui_mode(mode): - get_config()['default_ui'] = mode - - -def set_component_policy(mode): - get_config()['component_policy'] = mode - - -def set_double_click_policy(mode): - get_config()['double_click_policy'] = mode - - -def try_install_script(url, repo_path, install_cmd): - if (len(install_cmd) > 0 and install_cmd[0].startswith('#')) or (platform.system() == "Windows" and comfy_ui_commit_datetime.date() >= comfy_ui_required_commit_datetime.date()): - if not os.path.exists(startup_script_path): - os.makedirs(startup_script_path) - - script_path = os.path.join(startup_script_path, "install-scripts.txt") - with open(script_path, "a") as file: - obj = [repo_path] + install_cmd - file.write(f"{obj}\n") - - return True - else: - if len(install_cmd) == 5 and install_cmd[2:4] == ['pip', 'install']: - if is_blacklisted(install_cmd[4]): - print(f"[ComfyUI-Manager] skip black listed pip installation: '{install_cmd[4]}'") - return True - - print(f"\n## ComfyUI-Manager: EXECUTE => {install_cmd}") - code = run_script(install_cmd, cwd=repo_path) - - if platform.system() == "Windows": - try: - if comfy_ui_commit_datetime.date() < comfy_ui_required_commit_datetime.date(): - print("\n\n###################################################################") - print(f"[WARN] ComfyUI-Manager: Your ComfyUI version ({comfy_ui_revision})[{comfy_ui_commit_datetime.date()}] is too old. Please update to the latest version.") - print(f"[WARN] The extension installation feature may not work properly in the current installed ComfyUI version on Windows environment.") - print("###################################################################\n\n") - except: - pass - - if code != 0: - if url is None: - url = os.path.dirname(repo_path) - print(f"install script failed: {url}") - return False - -def print_comfyui_version(): - global comfy_ui_revision - global comfy_ui_commit_datetime - global comfy_ui_hash - - is_detached = False - try: - repo = git.Repo(os.path.dirname(folder_paths.__file__)) - comfy_ui_revision = len(list(repo.iter_commits('HEAD'))) - - comfy_ui_hash = repo.head.commit.hexsha - cm_global.variables['comfyui.revision'] = comfy_ui_revision - - comfy_ui_commit_datetime = repo.head.commit.committed_datetime - cm_global.variables['comfyui.commit_datetime'] = comfy_ui_commit_datetime - - is_detached = repo.head.is_detached - current_branch = repo.active_branch.name - - try: - if comfy_ui_commit_datetime.date() < comfy_ui_required_commit_datetime.date(): - print(f"\n\n## [WARN] ComfyUI-Manager: Your ComfyUI version ({comfy_ui_revision})[{comfy_ui_commit_datetime.date()}] is too old. Please update to the latest version. ##\n\n") - except: - pass - - # process on_revision_detected --> - if 'cm.on_revision_detected_handler' in cm_global.variables: - for k, f in cm_global.variables['cm.on_revision_detected_handler']: - try: - f(comfy_ui_revision) - except Exception: - print(f"[ERROR] '{k}' on_revision_detected_handler") - traceback.print_exc() - - del cm_global.variables['cm.on_revision_detected_handler'] - else: - print(f"[ComfyUI-Manager] Some features are restricted due to your ComfyUI being outdated.") - # <-- - - if current_branch == "master": - print(f"### ComfyUI Revision: {comfy_ui_revision} [{comfy_ui_hash[:8]}] | Released on '{comfy_ui_commit_datetime.date()}'") - else: - print(f"### ComfyUI Revision: {comfy_ui_revision} on '{current_branch}' [{comfy_ui_hash[:8]}] | Released on '{comfy_ui_commit_datetime.date()}'") - except: - if is_detached: - print(f"### ComfyUI Revision: {comfy_ui_revision} [{comfy_ui_hash[:8]}] *DETACHED | Released on '{comfy_ui_commit_datetime.date()}'") - else: - print("### ComfyUI Revision: UNKNOWN (The currently installed ComfyUI is not a Git repository)") - - -print_comfyui_version() - - -# use subprocess to avoid file system lock by git (Windows) -def __win_check_git_update(path, do_fetch=False, do_update=False): - if do_fetch: - command = [sys.executable, git_script_path, "--fetch", path] - elif do_update: - command = [sys.executable, git_script_path, "--pull", path] - else: - command = [sys.executable, git_script_path, "--check", path] - - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output, _ = process.communicate() - output = output.decode('utf-8').strip() - - if 'detected dubious' in output: - # fix and try again - safedir_path = path.replace('\\', '/') - try: - print(f"[ComfyUI-Manager] Try fixing 'dubious repository' error on '{safedir_path}' repo") - process = subprocess.Popen(['git', 'config', '--global', '--add', 'safe.directory', safedir_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output, _ = process.communicate() - - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output, _ = process.communicate() - output = output.decode('utf-8').strip() - except Exception: - print(f'[ComfyUI-Manager] failed to fixing') - - if 'detected dubious' in output: - print(f'\n[ComfyUI-Manager] Failed to fixing repository setup. Please execute this command on cmd: \n' - f'-----------------------------------------------------------------------------------------\n' - f'git config --global --add safe.directory "{safedir_path}"\n' - f'-----------------------------------------------------------------------------------------\n') - - if do_update: - if "CUSTOM NODE PULL: Success" in output: - process.wait() - print(f"\rUpdated: {path}") - return True, True # updated - elif "CUSTOM NODE PULL: None" in output: - process.wait() - return False, True # there is no update - else: - print(f"\rUpdate error: {path}") - process.wait() - return False, False # update failed - else: - if "CUSTOM NODE CHECK: True" in output: - process.wait() - return True, True - elif "CUSTOM NODE CHECK: False" in output: - process.wait() - return False, True - else: - print(f"\rFetch error: {path}") - print(f"\n{output}\n") - process.wait() - return False, True - - -def __win_check_git_pull(path): - command = [sys.executable, git_script_path, "--pull", path] - process = subprocess.Popen(command) - process.wait() - - -def switch_to_default_branch(repo): - show_result = repo.git.remote("show", "origin") - matches = re.search(r"\s*HEAD branch:\s*(.*)", show_result) - if matches: - default_branch = matches.group(1) - repo.git.checkout(default_branch) - - -def git_repo_has_updates(path, do_fetch=False, do_update=False): - if do_fetch: - print(f"\x1b[2K\rFetching: {path}", end='') - elif do_update: - print(f"\x1b[2K\rUpdating: {path}", end='') - - # Check if the path is a git repository - if not os.path.exists(os.path.join(path, '.git')): - raise ValueError('Not a git repository') - - if platform.system() == "Windows": - updated, success = __win_check_git_update(path, do_fetch, do_update) - if updated and success: - execute_install_script(None, path, lazy_mode=True) - return updated, success - else: - # Fetch the latest commits from the remote repository - repo = git.Repo(path) - - current_branch = repo.active_branch - branch_name = current_branch.name - - remote_name = 'origin' - remote = repo.remote(name=remote_name) - - # Get the current commit hash - commit_hash = repo.head.commit.hexsha - - if do_fetch or do_update: - remote.fetch() - - if do_update: - if repo.head.is_detached: - switch_to_default_branch(repo) - - remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha - - if commit_hash == remote_commit_hash: - repo.close() - return False, True - - try: - remote.pull() - repo.git.submodule('update', '--init', '--recursive') - new_commit_hash = repo.head.commit.hexsha - - if commit_hash != new_commit_hash: - execute_install_script(None, path) - print(f"\x1b[2K\rUpdated: {path}") - return True, True - else: - return False, False - - except Exception as e: - print(f"\nUpdating failed: {path}\n{e}", file=sys.stderr) - return False, False - - if repo.head.is_detached: - repo.close() - return True, True - - # Get commit hash of the remote branch - current_branch = repo.active_branch - branch_name = current_branch.name - - remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha - - # Compare the commit hashes to determine if the local repository is behind the remote repository - if commit_hash != remote_commit_hash: - # Get the commit dates - commit_date = repo.head.commit.committed_datetime - remote_commit_date = repo.refs[f'{remote_name}/{branch_name}'].object.committed_datetime - - # Compare the commit dates to determine if the local repository is behind the remote repository - if commit_date < remote_commit_date: - repo.close() - return True, True - - repo.close() - - return False, True - - -def git_pull(path): - # Check if the path is a git repository - if not os.path.exists(os.path.join(path, '.git')): - raise ValueError('Not a git repository') - - # Pull the latest changes from the remote repository - if platform.system() == "Windows": - return __win_check_git_pull(path) - else: - repo = git.Repo(path) - - if repo.is_dirty(): - repo.git.stash() - - if repo.head.is_detached: - switch_to_default_branch(repo) - - current_branch = repo.active_branch - remote_name = current_branch.tracking_branch().remote_name - remote = repo.remote(name=remote_name) - - remote.pull() - repo.git.submodule('update', '--init', '--recursive') - - repo.close() - - return True - - -async def get_data(uri, silent=False): - if not silent: - print(f"FETCH DATA from: {uri}") - - if uri.startswith("http"): - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - async with session.get(uri) as resp: - json_text = await resp.text() - else: - with cache_lock: - with open(uri, "r", encoding="utf-8") as f: - json_text = f.read() - - json_obj = json.loads(json_text) - return json_obj - -async def populate_github_stats(json_obj, filename, silent=False): - uri = os.path.join(comfyui_manager_path, filename) - with open(uri, "r", encoding='utf-8') as f: - github_stats = json.load(f) - if 'custom_nodes' in json_obj: - for i, node in enumerate(json_obj['custom_nodes']): - url = node['reference'] - if url in github_stats: - json_obj['custom_nodes'][i]['stars'] = github_stats[url]['stars'] - json_obj['custom_nodes'][i]['last_update'] = github_stats[url]['last_update'] - else: - json_obj['custom_nodes'][i]['stars'] = -1 - json_obj['custom_nodes'][i]['last_update'] = -1 - return json_obj - -def setup_js(): - import nodes - js_dest_path = os.path.join(js_path, "comfyui-manager") - - if hasattr(nodes, "EXTENSION_WEB_DIRS"): - if os.path.exists(js_dest_path): - shutil.rmtree(js_dest_path) - else: - print(f"[WARN] ComfyUI-Manager: Your ComfyUI version is outdated. Please update to the latest version.") - # setup js - if not os.path.exists(js_dest_path): - os.makedirs(js_dest_path) - js_src_path = os.path.join(comfyui_manager_path, "js", "comfyui-manager.js") - - print(f"### ComfyUI-Manager: Copy .js from '{js_src_path}' to '{js_dest_path}'") - shutil.copy(js_src_path, js_dest_path) - - -setup_js() - - -def setup_environment(): - git_exe = get_config()['git_exe'] - - if git_exe != '': - git.Git().update_environment(GIT_PYTHON_GIT_EXECUTABLE=git_exe) - - -setup_environment() - - -# Expand Server api - -import server -from aiohttp import web -import aiohttp -import json -import zipfile -import urllib.request - - -def simple_hash(input_string): - hash_value = 0 - for char in input_string: - hash_value = (hash_value * 31 + ord(char)) % (2**32) - - return hash_value - - -def is_file_created_within_one_day(file_path): - if not os.path.exists(file_path): - return False - - file_creation_time = os.path.getctime(file_path) - current_time = datetime.now().timestamp() - time_difference = current_time - file_creation_time - - return time_difference <= 86400 - - -async def get_data_by_mode(mode, filename): - try: - if mode == "local": - uri = os.path.join(comfyui_manager_path, filename) - json_obj = await get_data(uri) - else: - uri = get_config()['channel_url'] + '/' + filename - cache_uri = str(simple_hash(uri))+'_'+filename - cache_uri = os.path.join(cache_dir, cache_uri) - - if mode == "cache": - if is_file_created_within_one_day(cache_uri): - json_obj = await get_data(cache_uri) - else: - json_obj = await get_data(uri) - with cache_lock: - with open(cache_uri, "w", encoding='utf-8') as file: - json.dump(json_obj, file, indent=4, sort_keys=True) - else: - uri = get_config()['channel_url'] + '/' + filename - json_obj = await get_data(uri) - with cache_lock: - with open(cache_uri, "w", encoding='utf-8') as file: - json.dump(json_obj, file, indent=4, sort_keys=True) - except Exception as e: - print(f"[ComfyUI-Manager] Due to a network error, switching to local mode.\n=> {filename}\n=> {e}") - uri = os.path.join(comfyui_manager_path, filename) - json_obj = await get_data(uri) - - return json_obj - - -def get_model_dir(data): - if data['save_path'] != 'default': - if '..' in data['save_path'] or data['save_path'].startswith('/'): - print(f"[WARN] '{data['save_path']}' is not allowed path. So it will be saved into 'models/etc'.") - base_model = "etc" - else: - if data['save_path'].startswith("custom_nodes"): - base_model = os.path.join(comfy_path, data['save_path']) - else: - base_model = os.path.join(folder_paths.models_dir, data['save_path']) - else: - model_type = data['type'] - if model_type == "checkpoints": - base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0] - elif model_type == "unclip": - base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0] - elif model_type == "VAE": - base_model = folder_paths.folder_names_and_paths["vae"][0][0] - elif model_type == "lora": - base_model = folder_paths.folder_names_and_paths["loras"][0][0] - elif model_type == "T2I-Adapter": - base_model = folder_paths.folder_names_and_paths["controlnet"][0][0] - elif model_type == "T2I-Style": - base_model = folder_paths.folder_names_and_paths["controlnet"][0][0] - elif model_type == "controlnet": - base_model = folder_paths.folder_names_and_paths["controlnet"][0][0] - elif model_type == "clip_vision": - base_model = folder_paths.folder_names_and_paths["clip_vision"][0][0] - elif model_type == "gligen": - base_model = folder_paths.folder_names_and_paths["gligen"][0][0] - elif model_type == "upscale": - base_model = folder_paths.folder_names_and_paths["upscale_models"][0][0] - elif model_type == "embeddings": - base_model = folder_paths.folder_names_and_paths["embeddings"][0][0] - else: - base_model = "etc" - - return base_model - - -def get_model_path(data): - base_model = get_model_dir(data) - return os.path.join(base_model, data['filename']) - - -def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do_update=False): - item['installed'] = 'None' - - if item['install_type'] == 'git-clone' and len(item['files']) == 1: - url = item['files'][0] - - if url.endswith("/"): - url = url[:-1] - - dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") - dir_path = os.path.join(custom_nodes_path, dir_name) - if os.path.exists(dir_path): - try: - item['installed'] = 'True' # default - - if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name): - item['installed'] = 'Fail' - - if do_update_check: - update_state, success = git_repo_has_updates(dir_path, do_fetch, do_update) - if (do_update_check or do_update) and update_state: - item['installed'] = 'Update' - elif do_update and not success: - item['installed'] = 'Fail' - except: - if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name): - item['installed'] = 'Fail' - else: - item['installed'] = 'True' - - elif os.path.exists(dir_path + ".disabled"): - item['installed'] = 'Disabled' - - else: - item['installed'] = 'False' - - elif item['install_type'] == 'copy' and len(item['files']) == 1: - dir_name = os.path.basename(item['files'][0]) - - if item['files'][0].endswith('.py'): - base_path = custom_nodes_path - elif 'js_path' in item: - base_path = os.path.join(js_path, item['js_path']) - else: - base_path = js_path - - file_path = os.path.join(base_path, dir_name) - if os.path.exists(file_path): - if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name): - item['installed'] = 'Fail' - else: - item['installed'] = 'True' - elif os.path.exists(file_path + ".disabled"): - item['installed'] = 'Disabled' - else: - item['installed'] = 'False' - - -def check_custom_nodes_installed(json_obj, do_fetch=False, do_update_check=True, do_update=False): - if do_fetch: - print("Start fetching...", end="") - elif do_update: - print("Start updating...", end="") - elif do_update_check: - print("Start update check...", end="") - - def process_custom_node(item): - check_a_custom_node_installed(item, do_fetch, do_update_check, do_update) - - with concurrent.futures.ThreadPoolExecutor(4) as executor: - for item in json_obj['custom_nodes']: - executor.submit(process_custom_node, item) - - if do_fetch: - print(f"\x1b[2K\rFetching done.") - elif do_update: - update_exists = any(item['installed'] == 'Update' for item in json_obj['custom_nodes']) - if update_exists: - print(f"\x1b[2K\rUpdate done.") - else: - print(f"\x1b[2K\rAll extensions are already up-to-date.") - elif do_update_check: - print(f"\x1b[2K\rUpdate check done.") - - -def nickname_filter(json_obj): - preemptions_map = {} - - for k, x in json_obj.items(): - if 'preemptions' in x[1]: - for y in x[1]['preemptions']: - preemptions_map[y] = k - elif k.endswith("/ComfyUI"): - for y in x[0]: - preemptions_map[y] = k - - updates = {} - for k, x in json_obj.items(): - removes = set() - for y in x[0]: - k2 = preemptions_map.get(y) - if k2 is not None and k != k2: - removes.add(y) - - if len(removes) > 0: - updates[k] = [y for y in x[0] if y not in removes] - - for k, v in updates.items(): - json_obj[k][0] = v - - return json_obj - - -@server.PromptServer.instance.routes.get("/customnode/getmappings") -async def fetch_customnode_mappings(request): - mode = request.rel_url.query["mode"] - - nickname_mode = False - if mode == "nickname": - mode = "local" - nickname_mode = True - - json_obj = await get_data_by_mode(mode, 'extension-node-map.json') - - if nickname_mode: - json_obj = nickname_filter(json_obj) - - all_nodes = set() - patterns = [] - for k, x in json_obj.items(): - all_nodes.update(set(x[0])) - - if 'nodename_pattern' in x[1]: - patterns.append((x[1]['nodename_pattern'], x[0])) - - missing_nodes = set(nodes.NODE_CLASS_MAPPINGS.keys()) - all_nodes - - for x in missing_nodes: - for pat, item in patterns: - if re.match(pat, x): - item.append(x) - - return web.json_response(json_obj, content_type='application/json') - - -@server.PromptServer.instance.routes.get("/customnode/fetch_updates") -async def fetch_updates(request): - try: - json_obj = await get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') - - check_custom_nodes_installed(json_obj, True) - - update_exists = any('custom_nodes' in json_obj and 'installed' in node and node['installed'] == 'Update' for node in - json_obj['custom_nodes']) - - if update_exists: - return web.Response(status=201) - - return web.Response(status=200) - except: - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/customnode/update_all") -async def update_all(request): - try: - save_snapshot_with_postfix('autosave') - - json_obj = await get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') - - check_custom_nodes_installed(json_obj, do_update=True) - - updated = [item['title'] for item in json_obj['custom_nodes'] if item['installed'] == 'Update'] - failed = [item['title'] for item in json_obj['custom_nodes'] if item['installed'] == 'Fail'] - - res = {'updated': updated, 'failed': failed} - - if len(updated) == 0 and len(failed) == 0: - status = 200 - else: - status = 201 - - return web.json_response(res, status=status, content_type='application/json') - except: - return web.Response(status=400) - finally: - clear_pip_cache() - - -def convert_markdown_to_html(input_text): - pattern_a = re.compile(r'\[a/([^]]+)\]\(([^)]+)\)') - pattern_w = re.compile(r'\[w/([^]]+)\]') - pattern_i = re.compile(r'\[i/([^]]+)\]') - pattern_bold = re.compile(r'\*\*([^*]+)\*\*') - pattern_white = re.compile(r'%%([^*]+)%%') - - def replace_a(match): - return f"{match.group(1)}" - - def replace_w(match): - return f"

{match.group(1)}

" - - def replace_i(match): - return f"

{match.group(1)}

" - - def replace_bold(match): - return f"{match.group(1)}" - - def replace_white(match): - return f"{match.group(1)}" - - input_text = input_text.replace('\\[', '[').replace('\\]', ']').replace('<', '<').replace('>', '>') - - result_text = re.sub(pattern_a, replace_a, input_text) - result_text = re.sub(pattern_w, replace_w, result_text) - result_text = re.sub(pattern_i, replace_i, result_text) - result_text = re.sub(pattern_bold, replace_bold, result_text) - result_text = re.sub(pattern_white, replace_white, result_text) - - return result_text.replace("\n", "
") - - -def populate_markdown(x): - if 'description' in x: - x['description'] = convert_markdown_to_html(x['description']) - - if 'name' in x: - x['name'] = x['name'].replace('<', '<').replace('>', '>') - - if 'title' in x: - x['title'] = x['title'].replace('<', '<').replace('>', '>') - - -@server.PromptServer.instance.routes.get("/customnode/getlist") -async def fetch_customnode_list(request): - if "skip_update" in request.rel_url.query and request.rel_url.query["skip_update"] == "true": - skip_update = True - else: - skip_update = False - - if request.rel_url.query["mode"] == "local": - channel = 'local' - else: - channel = get_config()['channel_url'] - - json_obj = await get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') - json_obj = await populate_github_stats(json_obj, "github-stats.json") - - def is_ignored_notice(code): - global version - - if code is not None and code.startswith('#NOTICE_'): - try: - notice_version = [int(x) for x in code[8:].split('.')] - return notice_version[0] < version[0] or (notice_version[0] == version[0] and notice_version[1] <= version[1]) - except Exception: - return False - else: - return False - - - json_obj['custom_nodes'] = [record for record in json_obj['custom_nodes'] if not is_ignored_notice(record.get('author'))] - - check_custom_nodes_installed(json_obj, False, not skip_update) - - for x in json_obj['custom_nodes']: - populate_markdown(x) - - if channel != 'local': - found = 'custom' - - for name, url in get_channel_dict().items(): - if url == channel: - found = name - break - - channel = found - - json_obj['channel'] = channel - - return web.json_response(json_obj, content_type='application/json') - - -@server.PromptServer.instance.routes.get("/alternatives/getlist") -async def fetch_alternatives_list(request): - if "skip_update" in request.rel_url.query and request.rel_url.query["skip_update"] == "true": - skip_update = True - else: - skip_update = False - - alter_json = await get_data_by_mode(request.rel_url.query["mode"], 'alter-list.json') - custom_node_json = await get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') - - fileurl_to_custom_node = {} - - for item in custom_node_json['custom_nodes']: - for fileurl in item['files']: - fileurl_to_custom_node[fileurl] = item - - for item in alter_json['items']: - fileurl = item['id'] - if fileurl in fileurl_to_custom_node: - custom_node = fileurl_to_custom_node[fileurl] - check_a_custom_node_installed(custom_node, not skip_update) - - populate_markdown(item) - populate_markdown(custom_node) - item['custom_node'] = custom_node - - return web.json_response(alter_json, content_type='application/json') - - -def check_model_installed(json_obj): - def process_model(item): - model_path = get_model_path(item) - item['installed'] = 'None' - - if model_path is not None: - if os.path.exists(model_path): - item['installed'] = 'True' - else: - item['installed'] = 'False' - - with concurrent.futures.ThreadPoolExecutor(8) as executor: - for item in json_obj['models']: - executor.submit(process_model, item) - - -@server.PromptServer.instance.routes.get("/externalmodel/getlist") -async def fetch_externalmodel_list(request): - json_obj = await get_data_by_mode(request.rel_url.query["mode"], 'model-list.json') - - check_model_installed(json_obj) - - for x in json_obj['models']: - populate_markdown(x) - - return web.json_response(json_obj, content_type='application/json') - - -@server.PromptServer.instance.routes.get("/snapshot/getlist") -async def get_snapshot_list(request): - snapshots_directory = os.path.join(os.path.dirname(__file__), 'snapshots') - items = [f[:-5] for f in os.listdir(snapshots_directory) if f.endswith('.json')] - items.sort(reverse=True) - return web.json_response({'items': items}, content_type='application/json') - - -@server.PromptServer.instance.routes.get("/snapshot/remove") -async def remove_snapshot(request): - try: - target = request.rel_url.query["target"] - - path = os.path.join(os.path.dirname(__file__), 'snapshots', f"{target}.json") - if os.path.exists(path): - os.remove(path) - - return web.Response(status=200) - except: - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/snapshot/restore") -async def remove_snapshot(request): - try: - target = request.rel_url.query["target"] - - path = os.path.join(os.path.dirname(__file__), 'snapshots', f"{target}.json") - if os.path.exists(path): - if not os.path.exists(startup_script_path): - os.makedirs(startup_script_path) - - target_path = os.path.join(startup_script_path, "restore-snapshot.json") - shutil.copy(path, target_path) - - print(f"Snapshot restore scheduled: `{target}`") - return web.Response(status=200) - - print(f"Snapshot file not found: `{path}`") - return web.Response(status=400) - except: - return web.Response(status=400) - - -def get_current_snapshot(): - # Get ComfyUI hash - repo_path = os.path.dirname(folder_paths.__file__) - - if not os.path.exists(os.path.join(repo_path, '.git')): - print(f"ComfyUI update fail: The installed ComfyUI does not have a Git repository.") - return web.Response(status=400) - - repo = git.Repo(repo_path) - comfyui_commit_hash = repo.head.commit.hexsha - - git_custom_nodes = {} - file_custom_nodes = [] - - # Get custom nodes hash - for path in os.listdir(custom_nodes_path): - fullpath = os.path.join(custom_nodes_path, path) - - if os.path.isdir(fullpath): - is_disabled = path.endswith(".disabled") - - try: - git_dir = os.path.join(fullpath, '.git') - - if not os.path.exists(git_dir): - continue - - repo = git.Repo(fullpath) - commit_hash = repo.head.commit.hexsha - url = repo.remotes.origin.url - git_custom_nodes[url] = { - 'hash': commit_hash, - 'disabled': is_disabled - } - - except: - print(f"Failed to extract snapshots for the custom node '{path}'.") - - elif path.endswith('.py'): - is_disabled = path.endswith(".py.disabled") - filename = os.path.basename(path) - item = { - 'filename': filename, - 'disabled': is_disabled - } - - file_custom_nodes.append(item) - - return { - 'comfyui': comfyui_commit_hash, - 'git_custom_nodes': git_custom_nodes, - 'file_custom_nodes': file_custom_nodes, - } - - -def save_snapshot_with_postfix(postfix): - now = datetime.now() - - date_time_format = now.strftime("%Y-%m-%d_%H-%M-%S") - file_name = f"{date_time_format}_{postfix}" - - path = os.path.join(os.path.dirname(__file__), 'snapshots', f"{file_name}.json") - with open(path, "w") as json_file: - json.dump(get_current_snapshot(), json_file, indent=4) - - -@server.PromptServer.instance.routes.get("/snapshot/get_current") -async def get_current_snapshot_api(request): - try: - return web.json_response(get_current_snapshot(), content_type='application/json') - except: - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/snapshot/save") -async def save_snapshot(request): - try: - save_snapshot_with_postfix('snapshot') - return web.Response(status=200) - except: - return web.Response(status=400) - - -def unzip_install(files): - temp_filename = 'manager-temp.zip' - for url in files: - if url.endswith("/"): - url = url[:-1] - try: - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} - - req = urllib.request.Request(url, headers=headers) - response = urllib.request.urlopen(req) - data = response.read() - - with open(temp_filename, 'wb') as f: - f.write(data) - - with zipfile.ZipFile(temp_filename, 'r') as zip_ref: - zip_ref.extractall(custom_nodes_path) - - os.remove(temp_filename) - except Exception as e: - print(f"Install(unzip) error: {url} / {e}", file=sys.stderr) - return False - - print("Installation was successful.") - return True - - -def download_url_with_agent(url, save_path): - try: - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} - - req = urllib.request.Request(url, headers=headers) - response = urllib.request.urlopen(req) - data = response.read() - - if not os.path.exists(os.path.dirname(save_path)): - os.makedirs(os.path.dirname(save_path)) - - with open(save_path, 'wb') as f: - f.write(data) - - except Exception as e: - print(f"Download error: {url} / {e}", file=sys.stderr) - return False - - print("Installation was successful.") - return True - - -def copy_install(files, js_path_name=None): - for url in files: - if url.endswith("/"): - url = url[:-1] - try: - if url.endswith(".py"): - download_url(url, custom_nodes_path) - else: - path = os.path.join(js_path, js_path_name) if js_path_name is not None else js_path - if not os.path.exists(path): - os.makedirs(path) - download_url(url, path) - - except Exception as e: - print(f"Install(copy) error: {url} / {e}", file=sys.stderr) - return False - - print("Installation was successful.") - return True - - -def copy_uninstall(files, js_path_name='.'): - for url in files: - if url.endswith("/"): - url = url[:-1] - dir_name = os.path.basename(url) - base_path = custom_nodes_path if url.endswith('.py') else os.path.join(js_path, js_path_name) - file_path = os.path.join(base_path, dir_name) - - try: - if os.path.exists(file_path): - os.remove(file_path) - elif os.path.exists(file_path + ".disabled"): - os.remove(file_path + ".disabled") - except Exception as e: - print(f"Uninstall(copy) error: {url} / {e}", file=sys.stderr) - return False - - print("Uninstallation was successful.") - return True - - -def copy_set_active(files, is_disable, js_path_name='.'): - if is_disable: - action_name = "Disable" - else: - action_name = "Enable" - - for url in files: - if url.endswith("/"): - url = url[:-1] - dir_name = os.path.basename(url) - base_path = custom_nodes_path if url.endswith('.py') else os.path.join(js_path, js_path_name) - file_path = os.path.join(base_path, dir_name) - - try: - if is_disable: - current_name = file_path - new_name = file_path + ".disabled" - else: - current_name = file_path + ".disabled" - new_name = file_path - - os.rename(current_name, new_name) - - except Exception as e: - print(f"{action_name}(copy) error: {url} / {e}", file=sys.stderr) - - return False - - print(f"{action_name} was successful.") - return True - - -def execute_install_script(url, repo_path, lazy_mode=False): - install_script_path = os.path.join(repo_path, "install.py") - requirements_path = os.path.join(repo_path, "requirements.txt") - - if lazy_mode: - install_cmd = ["#LAZY-INSTALL-SCRIPT", sys.executable] - try_install_script(url, repo_path, install_cmd) - else: - if os.path.exists(requirements_path): - print("Install: pip packages") - with open(requirements_path, "r") as requirements_file: - for line in requirements_file: - package_name = line.strip() - if package_name: - install_cmd = [sys.executable, "-m", "pip", "install", package_name] - if package_name.strip() != "": - try_install_script(url, repo_path, install_cmd) - - if os.path.exists(install_script_path): - print(f"Install: install script") - install_cmd = [sys.executable, "install.py"] - try_install_script(url, repo_path, install_cmd) - - return True - - -class GitProgress(RemoteProgress): - def __init__(self): - super().__init__() - self.pbar = tqdm() - - def update(self, op_code, cur_count, max_count=None, message=''): - self.pbar.total = max_count - self.pbar.n = cur_count - self.pbar.pos = 0 - self.pbar.refresh() - - -def is_valid_url(url): - try: - result = urlparse(url) - return all([result.scheme, result.netloc]) - except ValueError: - return False - - -def gitclone_install(files): - print(f"install: {files}") - for url in files: - if not is_valid_url(url): - print(f"Invalid git url: '{url}'") - return False - - if url.endswith("/"): - url = url[:-1] - try: - print(f"Download: git clone '{url}'") - repo_name = os.path.splitext(os.path.basename(url))[0] - repo_path = os.path.join(custom_nodes_path, repo_name) - - # Clone the repository from the remote URL - if platform.system() == 'Windows': - res = run_script([sys.executable, git_script_path, "--clone", custom_nodes_path, url]) - if res != 0: - return False - else: - repo = git.Repo.clone_from(url, repo_path, recursive=True, progress=GitProgress()) - repo.git.clear_cache() - repo.close() - - if not execute_install_script(url, repo_path): - return False - - except Exception as e: - print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr) - return False - - print("Installation was successful.") - return True - - -def gitclone_fix(files): - print(f"Try fixing: {files}") - for url in files: - if not is_valid_url(url): - print(f"Invalid git url: '{url}'") - return False - - if url.endswith("/"): - url = url[:-1] - try: - repo_name = os.path.splitext(os.path.basename(url))[0] - repo_path = os.path.join(custom_nodes_path, repo_name) - - if not execute_install_script(url, repo_path): - return False - - except Exception as e: - print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr) - return False - - print(f"Attempt to fixing '{files}' is done.") - return True - - -def pip_install(packages): - install_cmd = ['#FORCE', sys.executable, "-m", "pip", "install", '-U'] + packages - try_install_script('pip install via manager', '.', install_cmd) - - -import platform -import subprocess -import time - - -def rmtree(path): - retry_count = 3 - - while True: - try: - retry_count -= 1 - - if platform.system() == "Windows": - run_script(['attrib', '-R', path + '\\*', '/S']) - shutil.rmtree(path) - - return True - - except Exception as ex: - print(f"ex: {ex}") - time.sleep(3) - - if retry_count < 0: - raise ex - - print(f"Uninstall retry({retry_count})") - - -def gitclone_uninstall(files): - import shutil - import os - - print(f"uninstall: {files}") - for url in files: - if url.endswith("/"): - url = url[:-1] - try: - dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") - dir_path = os.path.join(custom_nodes_path, dir_name) - - # safety check - if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '': - print(f"Uninstall(git-clone) error: invalid path '{dir_path}' for '{url}'") - return False - - install_script_path = os.path.join(dir_path, "uninstall.py") - disable_script_path = os.path.join(dir_path, "disable.py") - if os.path.exists(install_script_path): - uninstall_cmd = [sys.executable, "uninstall.py"] - code = run_script(uninstall_cmd, cwd=dir_path) - - if code != 0: - print(f"An error occurred during the execution of the uninstall.py script. Only the '{dir_path}' will be deleted.") - elif os.path.exists(disable_script_path): - disable_script = [sys.executable, "disable.py"] - code = run_script(disable_script, cwd=dir_path) - if code != 0: - print(f"An error occurred during the execution of the disable.py script. Only the '{dir_path}' will be deleted.") - - if os.path.exists(dir_path): - rmtree(dir_path) - elif os.path.exists(dir_path + ".disabled"): - rmtree(dir_path + ".disabled") - except Exception as e: - print(f"Uninstall(git-clone) error: {url} / {e}", file=sys.stderr) - return False - - print("Uninstallation was successful.") - return True - - -def gitclone_set_active(files, is_disable): - import os - - if is_disable: - action_name = "Disable" - else: - action_name = "Enable" - - print(f"{action_name}: {files}") - for url in files: - if url.endswith("/"): - url = url[:-1] - try: - dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") - dir_path = os.path.join(custom_nodes_path, dir_name) - - # safey check - if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '': - print(f"{action_name}(git-clone) error: invalid path '{dir_path}' for '{url}'") - return False - - if is_disable: - current_path = dir_path - new_path = dir_path + ".disabled" - else: - current_path = dir_path + ".disabled" - new_path = dir_path - - os.rename(current_path, new_path) - - if is_disable: - if os.path.exists(os.path.join(new_path, "disable.py")): - disable_script = [sys.executable, "disable.py"] - try_install_script(url, new_path, disable_script) - else: - if os.path.exists(os.path.join(new_path, "enable.py")): - enable_script = [sys.executable, "enable.py"] - try_install_script(url, new_path, enable_script) - - except Exception as e: - print(f"{action_name}(git-clone) error: {url} / {e}", file=sys.stderr) - return False - - print(f"{action_name} was successful.") - return True - - -def gitclone_update(files): - import os - - print(f"Update: {files}") - for url in files: - if url.endswith("/"): - url = url[:-1] - try: - repo_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") - repo_path = os.path.join(custom_nodes_path, repo_name) - git_pull(repo_path) - - if not execute_install_script(url, repo_path, lazy_mode=True): - return False - - except Exception as e: - print(f"Update(git-clone) error: {url} / {e}", file=sys.stderr) - return False - - print("Update was successful.") - return True - - -@server.PromptServer.instance.routes.post("/customnode/install") -async def install_custom_node(request): - json_data = await request.json() - - install_type = json_data['install_type'] - - print(f"Install custom node '{json_data['title']}'") - - res = False - - if len(json_data['files']) == 0: - return web.Response(status=400) - - if install_type == "unzip": - res = unzip_install(json_data['files']) - - if install_type == "copy": - js_path_name = json_data['js_path'] if 'js_path' in json_data else '.' - res = copy_install(json_data['files'], js_path_name) - - elif install_type == "git-clone": - res = gitclone_install(json_data['files']) - - if 'pip' in json_data: - for pname in json_data['pip']: - install_cmd = [sys.executable, "-m", "pip", "install", pname] - try_install_script(json_data['files'][0], ".", install_cmd) - - clear_pip_cache() - - if res: - print(f"After restarting ComfyUI, please refresh the browser.") - return web.json_response({}, content_type='application/json') - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.post("/customnode/fix") -async def fix_custom_node(request): - json_data = await request.json() - - install_type = json_data['install_type'] - - print(f"Install custom node '{json_data['title']}'") - - res = False - - if len(json_data['files']) == 0: - return web.Response(status=400) - - if install_type == "git-clone": - res = gitclone_fix(json_data['files']) - else: - return web.Response(status=400) - - if 'pip' in json_data: - for pname in json_data['pip']: - install_cmd = [sys.executable, "-m", "pip", "install", '-U', pname] - try_install_script(json_data['files'][0], ".", install_cmd) - - if res: - print(f"After restarting ComfyUI, please refresh the browser.") - return web.json_response({}, content_type='application/json') - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/customnode/install/git_url") -async def install_custom_node_git_url(request): - res = False - if "url" in request.rel_url.query: - url = request.rel_url.query['url'] - res = gitclone_install([url]) - - if res: - print(f"After restarting ComfyUI, please refresh the browser.") - return web.Response(status=200) - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/customnode/install/pip") -async def install_custom_node_git_url(request): - res = False - if "packages" in request.rel_url.query: - packages = request.rel_url.query['packages'] - pip_install(packages.split(' ')) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.post("/customnode/uninstall") -async def uninstall_custom_node(request): - json_data = await request.json() - - install_type = json_data['install_type'] - - print(f"Uninstall custom node '{json_data['title']}'") - - res = False - - if install_type == "copy": - js_path_name = json_data['js_path'] if 'js_path' in json_data else '.' - res = copy_uninstall(json_data['files'], js_path_name) - - elif install_type == "git-clone": - res = gitclone_uninstall(json_data['files']) - - if res: - print(f"After restarting ComfyUI, please refresh the browser.") - return web.json_response({}, content_type='application/json') - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.post("/customnode/update") -async def update_custom_node(request): - json_data = await request.json() - - install_type = json_data['install_type'] - - print(f"Update custom node '{json_data['title']}'") - - res = False - - if install_type == "git-clone": - res = gitclone_update(json_data['files']) - - clear_pip_cache() - - if res: - print(f"After restarting ComfyUI, please refresh the browser.") - return web.json_response({}, content_type='application/json') - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/comfyui_manager/update_comfyui") -async def update_comfyui(request): - print(f"Update ComfyUI") - - try: - repo_path = os.path.dirname(folder_paths.__file__) - - if not os.path.exists(os.path.join(repo_path, '.git')): - print(f"ComfyUI update fail: The installed ComfyUI does not have a Git repository.") - return web.Response(status=400) - - # version check - repo = git.Repo(repo_path) - - if repo.head.is_detached: - switch_to_default_branch(repo) - - current_branch = repo.active_branch - branch_name = current_branch.name - - if current_branch.tracking_branch() is None: - print(f"[ComfyUI-Manager] There is no tracking branch ({current_branch})") - remote_name = 'origin' - else: - remote_name = current_branch.tracking_branch().remote_name - remote = repo.remote(name=remote_name) - - try: - remote.fetch() - except Exception as e: - if 'detected dubious' in str(e): - print(f"[ComfyUI-Manager] Try fixing 'dubious repository' error on 'ComfyUI' repository") - safedir_path = comfy_path.replace('\\', '/') - subprocess.run(['git', 'config', '--global', '--add', 'safe.directory', safedir_path]) - try: - remote.fetch() - except Exception: - print(f"\n[ComfyUI-Manager] Failed to fixing repository setup. Please execute this command on cmd: \n" - f"-----------------------------------------------------------------------------------------\n" - f'git config --global --add safe.directory "{safedir_path}"\n' - f"-----------------------------------------------------------------------------------------\n") - - commit_hash = repo.head.commit.hexsha - remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha - - if commit_hash != remote_commit_hash: - git_pull(repo_path) - execute_install_script("ComfyUI", repo_path) - return web.Response(status=201) - else: - return web.Response(status=200) - except Exception as e: - print(f"ComfyUI update fail: {e}", file=sys.stderr) - pass - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.post("/customnode/toggle_active") -async def toggle_active(request): - json_data = await request.json() - - install_type = json_data['install_type'] - is_disabled = json_data['installed'] == "Disabled" - - print(f"Update custom node '{json_data['title']}'") - - res = False - - if install_type == "git-clone": - res = gitclone_set_active(json_data['files'], not is_disabled) - elif install_type == "copy": - res = copy_set_active(json_data['files'], not is_disabled, json_data.get('js_path', None)) - - if res: - return web.json_response({}, content_type='application/json') - - return web.Response(status=400) - - -@server.PromptServer.instance.routes.post("/model/install") -async def install_model(request): - json_data = await request.json() - - model_path = get_model_path(json_data) - - res = False - - try: - if model_path is not None: - print(f"Install model '{json_data['name']}' into '{model_path}'") - - model_url = json_data['url'] - if not get_config()['model_download_by_agent'] and (model_url.startswith('https://github.com') or model_url.startswith('https://huggingface.co') or model_url.startswith('https://heibox.uni-heidelberg.de')): - model_dir = get_model_dir(json_data) - download_url(model_url, model_dir, filename=json_data['filename']) - - return web.json_response({}, content_type='application/json') - else: - res = download_url_with_agent(model_url, model_path) - else: - print(f"Model installation error: invalid model type - {json_data['type']}") - - if res: - return web.json_response({}, content_type='application/json') - except Exception as e: - print(f"[ERROR] {e}", file=sys.stderr) - pass - - return web.Response(status=400) - - -class ManagerTerminalHook: - def write_stderr(self, msg): - server.PromptServer.instance.send_sync("manager-terminal-feedback", {"data": msg}) - - def write_stdout(self, msg): - server.PromptServer.instance.send_sync("manager-terminal-feedback", {"data": msg}) - - -manager_terminal_hook = ManagerTerminalHook() - - -@server.PromptServer.instance.routes.get("/manager/terminal") -async def terminal_mode(request): - if "mode" in request.rel_url.query: - if request.rel_url.query['mode'] == 'true': - sys.__comfyui_manager_terminal_hook.add_hook('cm', manager_terminal_hook) - else: - sys.__comfyui_manager_terminal_hook.remove_hook('cm') - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/preview_method") -async def preview_method(request): - if "value" in request.rel_url.query: - set_preview_method(request.rel_url.query['value']) - write_config() - else: - return web.Response(text=get_current_preview_method(), status=200) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/badge_mode") -async def badge_mode(request): - if "value" in request.rel_url.query: - set_badge_mode(request.rel_url.query['value']) - write_config() - else: - return web.Response(text=get_config()['badge_mode'], status=200) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/default_ui") -async def default_ui_mode(request): - if "value" in request.rel_url.query: - set_default_ui_mode(request.rel_url.query['value']) - write_config() - else: - return web.Response(text=get_config()['default_ui'], status=200) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/component/policy") -async def component_policy(request): - if "value" in request.rel_url.query: - set_component_policy(request.rel_url.query['value']) - write_config() - else: - return web.Response(text=get_config()['component_policy'], status=200) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/dbl_click/policy") -async def dbl_click_policy(request): - if "value" in request.rel_url.query: - set_double_click_policy(request.rel_url.query['value']) - write_config() - else: - return web.Response(text=get_config()['double_click_policy'], status=200) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/channel_url_list") -async def channel_url_list(request): - channels = 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: - get_config()['channel_url'] = channel_url - write_config() - else: - selected = 'custom' - selected_url = get_config()['channel_url'] - - for name, url in channels.items(): - if url == selected_url: - selected = name - break - - res = {'selected': selected, - 'list': get_channel_list()} - return web.json_response(res, status=200) - - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/notice") -async def get_notice(request): - url = "github.com" - path = "/ltdrdata/ltdrdata.github.io/wiki/News" - - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - async with session.get(f"https://{url}{path}") as response: - if response.status == 200: - # html_content = response.read().decode('utf-8') - html_content = await response.text() - - pattern = re.compile(r'
([\s\S]*?)
') - match = pattern.search(html_content) - - if match: - markdown_content = match.group(1) - markdown_content += f"
ComfyUI: {comfy_ui_revision}[{comfy_ui_hash[:6]}]({comfy_ui_commit_datetime.date()})" - # markdown_content += f"
         ()" - markdown_content += f"
Manager: {version_str}" - - try: - if comfy_ui_required_commit_datetime.date() > comfy_ui_commit_datetime.date(): - markdown_content = f'

Your ComfyUI is too OUTDATED!!!

' + markdown_content - except: - pass - - return web.Response(text=markdown_content, status=200) - else: - return web.Response(text="Unable to retrieve Notice", status=200) - else: - return web.Response(text="Unable to retrieve Notice", status=200) - - -@server.PromptServer.instance.routes.get("/manager/reboot") -def restart(self): - try: - sys.stdout.close_log() - except Exception as e: - pass - - return os.execv(sys.executable, [sys.executable] + sys.argv) - - -def sanitize_filename(input_string): - # 알파벳, 숫자, 및 밑줄 이외의 문자를 밑줄로 대체 - result_string = re.sub(r'[^a-zA-Z0-9_]', '_', input_string) - return result_string - - -@server.PromptServer.instance.routes.post("/manager/component/save") -async def save_component(request): - try: - data = await request.json() - name = data['name'] - workflow = data['workflow'] - - if not os.path.exists(components_path): - os.mkdir(components_path) - - if 'packname' in workflow and workflow['packname'] != '': - sanitized_name = sanitize_filename(workflow['packname'])+'.pack' - else: - sanitized_name = sanitize_filename(name)+'.json' - - filepath = os.path.join(components_path, sanitized_name) - components = {} - if os.path.exists(filepath): - with open(filepath) as f: - components = json.load(f) - - components[name] = workflow - - with open(filepath, 'w') as f: - json.dump(components, f, indent=4, sort_keys=True) - return web.Response(text=filepath, status=200) - except: - return web.Response(status=400) - - -@server.PromptServer.instance.routes.post("/manager/component/loads") -async def load_components(request): - try: - json_files = [f for f in os.listdir(components_path) if f.endswith('.json')] - pack_files = [f for f in os.listdir(components_path) if f.endswith('.pack')] - - components = {} - for json_file in json_files + pack_files: - file_path = os.path.join(components_path, json_file) - with open(file_path, 'r') as file: - try: - # When there is a conflict between the .pack and the .json, the pack takes precedence and overrides. - components.update(json.load(file)) - except json.JSONDecodeError as e: - print(f"[ComfyUI-Manager] Error decoding component file in file {json_file}: {e}") - - return web.json_response(components) - except Exception as e: - print(f"[ComfyUI-Manager] failed to load components\n{e}") - return web.Response(status=400) - - -@server.PromptServer.instance.routes.get("/manager/share_option") -async def share_option(request): - if "value" in request.rel_url.query: - get_config()['share_option'] = request.rel_url.query['value'] - write_config() - else: - return web.Response(text=get_config()['share_option'], status=200) - - return web.Response(status=200) - - -def get_openart_auth(): - if not os.path.exists(os.path.join(comfyui_manager_path, ".openart_key")): - return None - try: - with open(os.path.join(comfyui_manager_path, ".openart_key"), "r") as f: - openart_key = f.read().strip() - return openart_key if openart_key else None - except: - return None - - -def get_matrix_auth(): - if not os.path.exists(os.path.join(comfyui_manager_path, "matrix_auth")): - return None - try: - with open(os.path.join(comfyui_manager_path, "matrix_auth"), "r") as f: - matrix_auth = f.read() - homeserver, username, password = matrix_auth.strip().split("\n") - if not homeserver or not username or not password: - return None - return { - "homeserver": homeserver, - "username": username, - "password": password, - } - except: - return None - - -def get_comfyworkflows_auth(): - if not os.path.exists(os.path.join(comfyui_manager_path, "comfyworkflows_sharekey")): - return None - try: - with open(os.path.join(comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f: - share_key = f.read() - if not share_key.strip(): - return None - return share_key - except: - return None - - -def get_youml_settings(): - if not os.path.exists(os.path.join(comfyui_manager_path, ".youml")): - return None - try: - with open(os.path.join(comfyui_manager_path, ".youml"), "r") as f: - youml_settings = f.read().strip() - return youml_settings if youml_settings else None - except: - return None - - -def set_youml_settings(settings): - with open(os.path.join(comfyui_manager_path, ".youml"), "w") as f: - f.write(settings) - - -@server.PromptServer.instance.routes.get("/manager/get_openart_auth") -async def api_get_openart_auth(request): - # print("Getting stored Matrix credentials...") - openart_key = get_openart_auth() - if not openart_key: - return web.Response(status=404) - return web.json_response({"openart_key": openart_key}) - - -@server.PromptServer.instance.routes.post("/manager/set_openart_auth") -async def api_set_openart_auth(request): - json_data = await request.json() - openart_key = json_data['openart_key'] - with open(os.path.join(comfyui_manager_path, ".openart_key"), "w") as f: - f.write(openart_key) - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/get_matrix_auth") -async def api_get_matrix_auth(request): - # print("Getting stored Matrix credentials...") - matrix_auth = get_matrix_auth() - if not matrix_auth: - return web.Response(status=404) - return web.json_response(matrix_auth) - - -@server.PromptServer.instance.routes.get("/manager/youml/settings") -async def api_get_youml_settings(request): - youml_settings = get_youml_settings() - if not youml_settings: - return web.Response(status=404) - return web.json_response(json.loads(youml_settings)) - - -@server.PromptServer.instance.routes.post("/manager/youml/settings") -async def api_set_youml_settings(request): - json_data = await request.json() - set_youml_settings(json.dumps(json_data)) - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/get_comfyworkflows_auth") -async def api_get_comfyworkflows_auth(request): - # Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken' - # in the same directory as the ComfyUI base folder - # print("Getting stored Comfyworkflows.com auth...") - comfyworkflows_auth = get_comfyworkflows_auth() - if not comfyworkflows_auth: - return web.Response(status=404) - return web.json_response({"comfyworkflows_sharekey" : comfyworkflows_auth}) - -args.enable_cors_header = "*" -if hasattr(server.PromptServer.instance, "app"): - app = server.PromptServer.instance.app - cors_middleware = server.create_cors_middleware(args.enable_cors_header) - app.middlewares.append(cors_middleware) - - -@server.PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images") -async def set_esheep_workflow_and_images(request): - json_data = await request.json() - current_workflow = json_data['workflow'] - images = json_data['images'] - with open(os.path.join(comfyui_manager_path, "esheep_share_message.json"), "w", encoding='utf-8') as file: - json.dump(json_data, file, indent=4) - return web.Response(status=200) - - -@server.PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images") -async def get_esheep_workflow_and_images(request): - with open(os.path.join(comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file: - data = json.load(file) - return web.Response(status=200, text=json.dumps(data)) - - -def set_matrix_auth(json_data): - homeserver = json_data['homeserver'] - username = json_data['username'] - password = json_data['password'] - with open(os.path.join(comfyui_manager_path, "matrix_auth"), "w") as f: - f.write("\n".join([homeserver, username, password])) - - -def set_comfyworkflows_auth(comfyworkflows_sharekey): - with open(os.path.join(comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f: - f.write(comfyworkflows_sharekey) - - -def has_provided_matrix_auth(matrix_auth): - return matrix_auth['homeserver'].strip() and matrix_auth['username'].strip() and matrix_auth['password'].strip() - - -def has_provided_comfyworkflows_auth(comfyworkflows_sharekey): - return comfyworkflows_sharekey.strip() - - - -def extract_model_file_names(json_data): - """Extract unique file names from the input JSON data.""" - file_names = set() - model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'} - - # Recursively search for file names in the JSON data - def recursive_search(data): - if isinstance(data, dict): - for value in data.values(): - recursive_search(value) - elif isinstance(data, list): - for item in data: - recursive_search(item) - elif isinstance(data, str) and '.' in data: - file_names.add(os.path.basename(data)) # file_names.add(data) - - recursive_search(json_data) - return [f for f in list(file_names) if os.path.splitext(f)[1] in model_filename_extensions] - - -def find_file_paths(base_dir, file_names): - """Find the paths of the files in the base directory.""" - file_paths = {} - - for root, dirs, files in os.walk(base_dir): - # Exclude certain directories - dirs[:] = [d for d in dirs if d not in ['.git']] - - for file in files: - if file in file_names: - file_paths[file] = os.path.join(root, file) - return file_paths - - -def compute_sha256_checksum(filepath): - """Compute the SHA256 checksum of a file, in chunks""" - sha256 = hashlib.sha256() - with open(filepath, 'rb') as f: - for chunk in iter(lambda: f.read(4096), b''): - sha256.update(chunk) - return sha256.hexdigest() - - -@server.PromptServer.instance.routes.post("/manager/share") -async def share_art(request): - # get json data - json_data = await request.json() - - matrix_auth = json_data['matrix_auth'] - comfyworkflows_sharekey = json_data['cw_auth']['cw_sharekey'] - - set_matrix_auth(matrix_auth) - set_comfyworkflows_auth(comfyworkflows_sharekey) - - share_destinations = json_data['share_destinations'] - credits = json_data['credits'] - title = json_data['title'] - description = json_data['description'] - is_nsfw = json_data['is_nsfw'] - prompt = json_data['prompt'] - potential_outputs = json_data['potential_outputs'] - selected_output_index = json_data['selected_output_index'] - - try: - output_to_share = potential_outputs[int(selected_output_index)] - except: - # for now, pick the first output - output_to_share = potential_outputs[0] - - assert output_to_share['type'] in ('image', 'output') - output_dir = folder_paths.get_output_directory() - - if output_to_share['type'] == 'image': - asset_filename = output_to_share['image']['filename'] - asset_subfolder = output_to_share['image']['subfolder'] - - if output_to_share['image']['type'] == 'temp': - output_dir = folder_paths.get_temp_directory() - else: - asset_filename = output_to_share['output']['filename'] - asset_subfolder = output_to_share['output']['subfolder'] - - if asset_subfolder: - asset_filepath = os.path.join(output_dir, asset_subfolder, asset_filename) - else: - asset_filepath = os.path.join(output_dir, asset_filename) - - # get the mime type of the asset - assetFileType = mimetypes.guess_type(asset_filepath)[0] - - share_website_host = "UNKNOWN" - if "comfyworkflows" in share_destinations: - share_website_host = "https://comfyworkflows.com" - share_endpoint = f"{share_website_host}/api" - - # get presigned urls - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - async with session.post( - f"{share_endpoint}/get_presigned_urls", - json={ - "assetFileName": asset_filename, - "assetFileType": assetFileType, - "workflowJsonFileName" : 'workflow.json', - "workflowJsonFileType" : 'application/json', - }, - ) as resp: - assert resp.status == 200 - presigned_urls_json = await resp.json() - assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"] - assetFileKey = presigned_urls_json["assetFileKey"] - workflowJsonFilePresignedUrl = presigned_urls_json["workflowJsonFilePresignedUrl"] - workflowJsonFileKey = presigned_urls_json["workflowJsonFileKey"] - - # upload asset - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - async with session.put(assetFilePresignedUrl, data=open(asset_filepath, "rb")) as resp: - assert resp.status == 200 - - # upload workflow json - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - async with session.put(workflowJsonFilePresignedUrl, data=json.dumps(prompt['workflow']).encode('utf-8')) as resp: - assert resp.status == 200 - - model_filenames = extract_model_file_names(prompt['workflow']) - model_file_paths = find_file_paths(folder_paths.base_path, model_filenames) - - models_info = {} - for filename, filepath in model_file_paths.items(): - models_info[filename] = { - "filename": filename, - "sha256_checksum": compute_sha256_checksum(filepath), - "relative_path": os.path.relpath(filepath, folder_paths.base_path), - } - - # make a POST request to /api/upload_workflow with form data key values - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - form = aiohttp.FormData() - if comfyworkflows_sharekey: - form.add_field("shareKey", comfyworkflows_sharekey) - form.add_field("source", "comfyui_manager") - form.add_field("assetFileKey", assetFileKey) - form.add_field("assetFileType", assetFileType) - form.add_field("workflowJsonFileKey", workflowJsonFileKey) - form.add_field("sharedWorkflowWorkflowJsonString", json.dumps(prompt['workflow'])) - form.add_field("sharedWorkflowPromptJsonString", json.dumps(prompt['output'])) - form.add_field("shareWorkflowCredits", credits) - form.add_field("shareWorkflowTitle", title) - form.add_field("shareWorkflowDescription", description) - form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower()) - form.add_field("currentSnapshot", json.dumps(get_current_snapshot())) - form.add_field("modelsInfo", json.dumps(models_info)) - - async with session.post( - f"{share_endpoint}/upload_workflow", - data=form, - ) as resp: - assert resp.status == 200 - upload_workflow_json = await resp.json() - workflowId = upload_workflow_json["workflowId"] - - # check if the user has provided Matrix credentials - if "matrix" in share_destinations: - comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org' - filename = os.path.basename(asset_filepath) - content_type = assetFileType - - try: - from matrix_client.api import MatrixHttpApi - from matrix_client.client import MatrixClient - - homeserver = 'matrix.org' - if matrix_auth: - homeserver = matrix_auth.get('homeserver', 'matrix.org') - homeserver = homeserver.replace("http://", "https://") - if not homeserver.startswith("https://"): - homeserver = "https://" + homeserver - - client = MatrixClient(homeserver) - try: - token = client.login(username=matrix_auth['username'], password=matrix_auth['password']) - if not token: - return web.json_response({"error" : "Invalid Matrix credentials."}, content_type='application/json', status=400) - except: - return web.json_response({"error" : "Invalid Matrix credentials."}, content_type='application/json', status=400) - - matrix = MatrixHttpApi(homeserver, token=token) - with open(asset_filepath, 'rb') as f: - mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri'] - - workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri'] - - text_content = "" - if title: - text_content += f"{title}\n" - if description: - text_content += f"{description}\n" - if credits: - text_content += f"\ncredits: {credits}\n" - response = matrix.send_message(comfyui_share_room_id, text_content) - response = matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image') - response = matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file') - except: - import traceback - traceback.print_exc() - return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500) - - return web.json_response({ - "comfyworkflows": { - "url": None if "comfyworkflows" not in share_destinations else f"{share_website_host}/workflows/{workflowId}", - }, - "matrix": { - "success": None if "matrix" not in share_destinations else True - } - }, content_type='application/json', status=200) - - -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)) - - -cm_global.register_api('cm.try-install-custom-node', confirm_try_install) - - -import asyncio -async def default_cache_update(): - async def get_cache(filename): - uri = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/' + filename - cache_uri = str(simple_hash(uri)) + '_' + filename - cache_uri = os.path.join(cache_dir, cache_uri) - - json_obj = await get_data(uri, True) - - with cache_lock: - with open(cache_uri, "w", encoding='utf-8') as file: - json.dump(json_obj, file, indent=4, sort_keys=True) - print(f"[ComfyUI-Manager] default cache updated: {uri}") - - a = get_cache("custom-node-list.json") - b = get_cache("extension-node-map.json") - c = get_cache("model-list.json") - d = get_cache("alter-list.json") - - await asyncio.gather(a, b, c, d) - - -threading.Thread(target=lambda: asyncio.run(default_cache_update())).start() - - -if not os.path.exists(config_path): - get_config() - write_config() - - -WEB_DIRECTORY = "js" NODE_CLASS_MAPPINGS = {} __all__ = ['NODE_CLASS_MAPPINGS'] -cm_global.register_extension('ComfyUI-Manager', - {'version': version, - 'name': 'ComfyUI Manager', - 'nodes': {'Terminal Log //CM'}, - 'description': 'It provides the ability to manage custom nodes in ComfyUI.', }) + diff --git a/cm-cli.py b/cm-cli.py new file mode 100644 index 00000000..30a256b0 --- /dev/null +++ b/cm-cli.py @@ -0,0 +1,508 @@ + +import os +import sys +import traceback +import json +import asyncio +import subprocess +import shutil + +sys.path.append(os.path.dirname(__file__)) +sys.path.append(os.path.join(os.path.dirname(__file__), "glob")) +import manager_core as core +import cm_global +import git + + +print(f"\n-= ComfyUI-Manager CLI ({core.version_str}) =-\n") + + +if not (len(sys.argv) == 2 and sys.argv[1] in ['save-snapshot', 'restore-dependencies', 'clear']) and len(sys.argv) < 3: + print(f"\npython cm-cli.py [OPTIONS]\n\n" + f"OPTIONS:\n" + f" [install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel ] ?[--mode [remote|local|cache]]\n" + f" [update|disable|enable|fix] all ?[--channel ] ?[--mode [remote|local|cache]]\n" + f" [simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel ] ?[--mode [remote|local|cache]]\n" + f" save-snapshot\n" + f" restore-snapshot \n" + f" cli-only-mode [enable|disable]\n" + f" restore-dependencies\n" + f" clear\n") + exit(-1) + + +comfyui_manager_path = os.path.dirname(__file__) +comfy_path = os.environ.get('COMFYUI_PATH') + +if comfy_path is None: + print(f"WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.\n", file=sys.stderr) + comfy_path = os.path.abspath(os.path.join(comfyui_manager_path, '..', '..')) + +startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts") +custom_nodes_path = os.path.join(comfy_path, 'custom_nodes') + +script_path = os.path.join(startup_script_path, "install-scripts.txt") +restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json") +pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json") +git_script_path = os.path.join(comfyui_manager_path, "git_helper.py") + +cm_global.pip_downgrade_blacklist = ['torch', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia'] +cm_global.pip_overrides = {} +if os.path.exists(pip_overrides_path): + with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file: + cm_global.pip_overrides = json.load(json_file) + + +processed_install = set() + + +def post_install(url): + try: + repository_name = url.split("/")[-1].strip() + repo_path = os.path.join(custom_nodes_path, repository_name) + repo_path = os.path.abspath(repo_path) + + requirements_path = os.path.join(repo_path, 'requirements.txt') + install_script_path = os.path.join(repo_path, 'install.py') + + if os.path.exists(requirements_path): + with (open(requirements_path, 'r', encoding="UTF-8", errors="ignore") as file): + for line in file: + package_name = core.remap_pip_package(line.strip()) + if package_name and not core.is_installed(package_name): + install_cmd = [sys.executable, "-m", "pip", "install", package_name] + output = subprocess.check_output(install_cmd, cwd=repo_path, text=True) + for msg_line in output.split('\n'): + if 'Requirement already satisfied:' in msg_line: + print('.', end='') + else: + print(msg_line) + + if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install: + processed_install.add(f'{repo_path}/install.py') + install_cmd = [sys.executable, install_script_path] + output = subprocess.check_output(install_cmd, cwd=repo_path, text=True) + for msg_line in output.split('\n'): + if 'Requirement already satisfied:' in msg_line: + print('.', end='') + else: + print(msg_line) + + except Exception: + print(f"ERROR: Restoring '{url}' is failed.") + + +def restore_dependencies(): + node_paths = [os.path.join(custom_nodes_path, name) for name in os.listdir(custom_nodes_path) + if os.path.isdir(os.path.join(custom_nodes_path, name)) and not name.endswith('.disabled')] + + total = len(node_paths) + i = 1 + for x in node_paths: + print(f"----------------------------------------------------------------------------------------------------") + print(f"Restoring [{i}/{total}]: {x}") + post_install(x) + i += 1 + + +def restore_snapshot(snapshot_name): + global processed_install + + snapshot_path = os.path.join(core.comfyui_manager_path, 'snapshots', snapshot_name) + if not os.path.exists(snapshot_path): + print(f"ERROR: `{snapshot_path}` is not exists.") + exit(-1) + + try: + cloned_repos = [] + checkout_repos = [] + skipped_repos = [] + enabled_repos = [] + disabled_repos = [] + is_failed = False + + def extract_infos(msg_lines): + nonlocal is_failed + + for x in msg_lines: + if x.startswith("CLONE: "): + cloned_repos.append(x[7:]) + elif x.startswith("CHECKOUT: "): + checkout_repos.append(x[10:]) + elif x.startswith("SKIPPED: "): + skipped_repos.append(x[9:]) + elif x.startswith("ENABLE: "): + enabled_repos.append(x[8:]) + elif x.startswith("DISABLE: "): + disabled_repos.append(x[9:]) + elif 'APPLY SNAPSHOT: False' in x: + is_failed = True + + print(f"Restore snapshot.") + cmd_str = [sys.executable, git_script_path, '--apply-snapshot', snapshot_path] + output = subprocess.check_output(cmd_str, cwd=custom_nodes_path, text=True) + msg_lines = output.split('\n') + extract_infos(msg_lines) + + for url in cloned_repos: + post_install(url) + + # print summary + for x in cloned_repos: + print(f"[ INSTALLED ] {x}") + for x in checkout_repos: + print(f"[ CHECKOUT ] {x}") + for x in enabled_repos: + print(f"[ ENABLED ] {x}") + for x in disabled_repos: + print(f"[ DISABLED ] {x}") + + if is_failed: + print("ERROR: Failed to restore snapshot.") + + except Exception: + print("ERROR: Failed to restore snapshot.") + traceback.print_exc() + exit(-1) + + +def check_comfyui_hash(): + repo = git.Repo(comfy_path) + core.comfy_ui_revision = len(list(repo.iter_commits('HEAD'))) + + comfy_ui_hash = repo.head.commit.hexsha + cm_global.variables['comfyui.revision'] = core.comfy_ui_revision + + core.comfy_ui_commit_datetime = repo.head.commit.committed_datetime + + +check_comfyui_hash() + + +def read_downgrade_blacklist(): + try: + import configparser + config_path = os.path.join(os.path.dirname(__file__), "config.ini") + config = configparser.ConfigParser() + config.read(config_path) + default_conf = config['default'] + + if 'downgrade_blacklist' in default_conf: + items = default_conf['downgrade_blacklist'].split(',') + items = [x.strip() for x in items if x != ''] + cm_global.pip_downgrade_blacklist += items + cm_global.pip_downgrade_blacklist = list(set(cm_global.pip_downgrade_blacklist)) + except: + pass + + +read_downgrade_blacklist() + +channel = 'default' +mode = 'remote' +nodes = set() + + +def load_custom_nodes(): + channel_dict = core.get_channel_dict() + if channel not in channel_dict: + print(f"ERROR: Invalid channel is specified `--channel {channel}`", file=sys.stderr) + exit(-1) + + if mode not in ['remote', 'local', 'cache']: + print(f"ERROR: Invalid mode is specified `--mode {mode}`", file=sys.stderr) + exit(-1) + + channel_url = channel_dict[channel] + + res = {} + json_obj = asyncio.run(core.get_data_by_mode(mode, 'custom-node-list.json', channel_url=channel_url)) + for x in json_obj['custom_nodes']: + for y in x['files']: + if 'github.com' in y and not (y.endswith('.py') or y.endswith('.js')): + repo_name = y.split('/')[-1] + res[repo_name] = x + + return res + + +def process_args(): + global channel + global mode + + i = 2 + while i < len(sys.argv): + if sys.argv[i] == '--channel': + if i+1 < len(sys.argv): + channel = sys.argv[i+1] + i += 1 + elif sys.argv[i] == '--mode': + if i+1 < len(sys.argv): + mode = sys.argv[i+1] + i += 1 + else: + nodes.add(sys.argv[i]) + + i += 1 + + +process_args() +custom_node_map = load_custom_nodes() + + +def lookup_node_path(node_name): + # Currently, the node_name is used directly as the node_path, but in the future, I plan to allow nicknames. + + if '..' in node_name: + print(f"ERROR: invalid node name '{node_name}'") + exit(-1) + + if node_name in custom_node_map: + node_path = os.path.join(custom_nodes_path, node_name) + return node_path, custom_node_map[node_name] + + print(f"ERROR: invalid node name '{node_name}'") + exit(-1) + + +def install_node(node_name, is_all=False, cnt_msg=''): + node_path, node_item = lookup_node_path(node_name) + + if os.path.exists(node_path): + if not is_all: + print(f"{cnt_msg} [ SKIPPED ] {node_name:50} => Already installed") + elif os.path.exists(node_path+'.disabled'): + enable_node(node_name) + else: + res = core.gitclone_install(node_item['files'], instant_execution=True, msg_prefix=f"[{cnt_msg}] ") + if not res: + print(f"ERROR: An error occurred while installing '{node_name}'.") + else: + print(f"{cnt_msg} [INSTALLED] {node_name:50}") + + +def reinstall_node(node_name, is_all=False, cnt_msg=''): + node_path, node_item = lookup_node_path(node_name) + + if os.path.exists(node_path): + shutil.rmtree(node_path) + if os.path.exists(node_path+'.disabled'): + shutil.rmtree(node_path+'.disabled') + + install_node(node_name, is_all=is_all, cnt_msg=cnt_msg) + + +def fix_node(node_name, is_all=False, cnt_msg=''): + node_path, node_item = lookup_node_path(node_name) + if os.path.exists(node_path): + print(f"{cnt_msg} [ FIXING ]: {node_name:50} => Disabled") + res = core.gitclone_fix(node_item['files'], instant_execution=True) + if not res: + print(f"ERROR: An error occurred while fixing '{node_name}'.") + elif not is_all and os.path.exists(node_path+'.disabled'): + print(f"{cnt_msg} [ SKIPPED ]: {node_name:50} => Disabled") + elif not is_all: + print(f"{cnt_msg} [ SKIPPED ]: {node_name:50} => Not installed") + + +def uninstall_node(node_name, is_all=False, cnt_msg=''): + node_path, node_item = lookup_node_path(node_name) + if os.path.exists(node_path) or os.path.exists(node_path+'.disabled'): + res = core.gitclone_uninstall(node_item['files']) + if not res: + print(f"ERROR: An error occurred while uninstalling '{node_name}'.") + else: + print(f"{cnt_msg} [UNINSTALLED] {node_name:50}") + else: + print(f"{cnt_msg} [ SKIPPED ]: {node_name:50} => Not installed") + + +def update_node(node_name, is_all=False, cnt_msg=''): + node_path, node_item = lookup_node_path(node_name) + res = core.gitclone_update(node_item['files'], skip_script=True, msg_prefix=f"[{cnt_msg}] ") + post_install(node_path) + if not res: + print(f"ERROR: An error occurred while uninstalling '{node_name}'.") + + +def enable_node(node_name, is_all=False, cnt_msg=''): + if node_name == 'ComfyUI-Manager': + return + + node_path, _ = lookup_node_path(node_name) + + if os.path.exists(node_path+'.disabled'): + current_name = node_path+'.disabled' + os.rename(current_name, node_path) + print(f"{cnt_msg} [ENABLED] {node_name:50}") + elif os.path.exists(node_path): + print(f"{cnt_msg} [SKIPPED] {node_name:50} => Already enabled") + elif not is_all: + print(f"{cnt_msg} [SKIPPED] {node_name:50} => Not installed") + + +def disable_node(node_name, is_all=False, cnt_msg=''): + if node_name == 'ComfyUI-Manager': + return + + node_path, _ = lookup_node_path(node_name) + + if os.path.exists(node_path): + current_name = node_path + new_name = node_path+'.disabled' + os.rename(current_name, new_name) + print(f"{cnt_msg} [DISABLED] {node_name:50}") + elif os.path.exists(node_path+'.disabled'): + print(f"{cnt_msg} [ SKIPPED] {node_name:50} => Already disabled") + elif not is_all: + print(f"{cnt_msg} [ SKIPPED] {node_name:50} => Not installed") + + +def show_list(kind, simple=False): + for k, v in custom_node_map.items(): + node_path = os.path.join(custom_nodes_path, k) + + states = set() + if os.path.exists(node_path): + prefix = '[ ENABLED ] ' + states.add('installed') + states.add('enabled') + states.add('all') + elif os.path.exists(node_path+'.disabled'): + prefix = '[ DISABLED ] ' + states.add('installed') + states.add('disabled') + states.add('all') + else: + prefix = '[ NOT INSTALLED ] ' + states.add('not-installed') + states.add('all') + + if kind in states: + if simple: + print(f"{k:50}") + else: + print(f"{prefix} {k:50}(author: {v['author']})") + + +def show_snapshot(simple_mode=False): + json_obj = core.get_current_snapshot() + + if simple_mode: + print(f"[{json_obj['comfyui']}] comfyui") + for k, v in json_obj['git_custom_nodes'].items(): + print(f"[{v['hash']}] {k}") + for v in json_obj['file_custom_nodes']: + print(f"[ N/A ] {v['filename']}") + + else: + formatted_json = json.dumps(json_obj, ensure_ascii=False, indent=4) + print(formatted_json) + + +def show_snapshot_list(simple_mode=False): + path = os.path.join(comfyui_manager_path, 'snapshots') + + files = os.listdir(path) + json_files = [x for x in files if x.endswith('.json')] + for x in sorted(json_files): + print(x) + + +def cancel(): + if os.path.exists(script_path): + os.remove(script_path) + + if os.path.exists(restore_snapshot_path): + os.remove(restore_snapshot_path) + + +def for_each_nodes(act, allow_all=True): + global nodes + + is_all = False + if allow_all and 'all' in nodes: + is_all = True + nodes = [x for x in custom_node_map.keys() if os.path.exists(os.path.join(custom_nodes_path, x)) or os.path.exists(os.path.join(custom_nodes_path, x)+'.disabled')] + + total = len(nodes) + i = 1 + for x in nodes: + try: + act(x, is_all=is_all, cnt_msg=f'{i}/{total}') + except Exception as e: + print(f"ERROR: {e}") + traceback.print_exc() + i+=1 + + +op = sys.argv[1] + + +if op == 'install': + for_each_nodes(install_node) + +elif op == 'reinstall': + for_each_nodes(reinstall_node) + +elif op == 'uninstall': + for_each_nodes(uninstall_node) + +elif op == 'update': + for_each_nodes(update_node, allow_all=True) + +elif op == 'disable': + for_each_nodes(disable_node, allow_all=True) + +elif op == 'enable': + for_each_nodes(enable_node, allow_all=True) + +elif op == 'fix': + for_each_nodes(fix_node, allow_all=True) + +elif op == 'show': + if sys.argv[2] == 'snapshot': + show_snapshot() + elif sys.argv[2] == 'snapshot-list': + show_snapshot_list() + else: + show_list(sys.argv[2]) + +elif op == 'simple-show': + if sys.argv[2] == 'snapshot': + show_snapshot(True) + elif sys.argv[2] == 'snapshot-list': + show_snapshot_list(True) + else: + show_list(sys.argv[2], True) + +elif op == 'cli-only-mode': + cli_mode_flag = os.path.join(os.path.dirname(__file__), '.enable-cli-only-mode') + if sys.argv[2] == 'enable': + with open(cli_mode_flag, 'w') as file: + pass + print(f"\ncli-only-mode: enabled\n") + elif sys.argv[2] == 'disable': + if os.path.exists(cli_mode_flag): + os.remove(cli_mode_flag) + print(f"\ncli-only-mode: disabled\n") + else: + print(f"\ninvalid value for cli-only-mode: {sys.argv[2]}\n") + +elif op == 'save-snapshot': + path = core.save_snapshot_with_postfix('snapshot') + print(f"Current snapshot is saved as `{path}`") + +elif op == 'restore-snapshot': + restore_snapshot(sys.argv[2]) + +elif op == 'restore-dependencies': + restore_dependencies() + +elif op == 'clear': + cancel() + +else: + print(f"\nInvalid command `{op}`") + +print(f"") diff --git a/custom-node-list.json b/custom-node-list.json index 1465fb90..e01a6b11 100644 --- a/custom-node-list.json +++ b/custom-node-list.json @@ -42,6 +42,16 @@ "install_type": "git-clone", "description": "Nodes: ModelSamplerTonemapNoiseTest, TonemapNoiseWithRescaleCFG, ReferenceOnlySimple, RescaleClassifierFreeGuidanceTest, ModelMergeBlockNumber, ModelMergeSDXL, ModelMergeSDXLTransformers, ModelMergeSDXLDetailedTransformers.[w/NOTE: This is a consolidation of the previously separate custom nodes. Please delete the sampler_tonemap.py, sampler_rescalecfg.py, advanced_model_merging.py, sdxl_model_merging.py, and reference_only.py files installed in custom_nodes before.]" }, + { + "author": "Stability-AI", + "title": "Stability API nodes for ComfyUI", + "reference": "https://github.com/Stability-AI/ComfyUI-SAI_API", + "files": [ + "https://github.com/Stability-AI/ComfyUI-SAI_API" + ], + "install_type": "git-clone", + "description": "Nodes:Stability SD3, Stability Outpainting, Stability Search and Replace, Stability Image Core, Stability Inpainting, Stability Remove Background, Stability Creative Upscale.\nAdd API key to environment variable 'SAI_API_KEY'\nAlternatively you can write your API key to file 'sai_platform_key.txt'\nYou can also use and/or override the above by entering your API key in the 'api_key_override' field of each node." + }, { "author": "Stability-AI", "title": "stability-ComfyUI-nodes", @@ -152,6 +162,16 @@ "install_type": "git-clone", "description": "A minimalistic implementation of [a/Robust Video Matting (RVM)](https://github.com/PeterL1n/RobustVideoMatting/) in ComfyUI" }, + { + "author": "Fannovel16", + "title": "ComfyUI-MagickWand", + "reference": "https://github.com/Fannovel16/ComfyUI-MagickWand", + "files": [ + "https://github.com/Fannovel16/ComfyUI-MagickWand" + ], + "install_type": "git-clone", + "description": "Proper implementation of ImageMagick - the famous software suite for editing and manipulating digital images to ComfyUI using [a/wandpy](https://github.com/emcconville/wand).\nNOTE: You need to install ImageMagick, manually." + }, { "author": "biegert", "title": "CLIPSeg", @@ -224,7 +244,7 @@ }, { "author": "jags111", - "title": "ComfyUI_Jags_VectorMagic", + "title": "Jags_VectorMagic", "reference": "https://github.com/jags111/ComfyUI_Jags_VectorMagic", "files": [ "https://github.com/jags111/ComfyUI_Jags_VectorMagic" @@ -234,7 +254,7 @@ }, { "author": "jags111", - "title": "ComfyUI_Jags_Audiotools", + "title": "Jags_Audiotools", "reference": "https://github.com/jags111/ComfyUI_Jags_Audiotools", "files": [ "https://github.com/jags111/ComfyUI_Jags_Audiotools" @@ -836,7 +856,7 @@ }, { "author": "Suzie1", - "title": "ComfyUI_Comfyroll_CustomNodes", + "title": "Comfyroll Studio", "reference": "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes", "files": [ "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes" @@ -2260,7 +2280,7 @@ }, { "author": "receyuki", - "title": "comfyui-prompt-reader-node", + "title": "SD Prompt Reader", "reference": "https://github.com/receyuki/comfyui-prompt-reader-node", "files": [ "https://github.com/receyuki/comfyui-prompt-reader-node" @@ -2399,16 +2419,6 @@ "install_type": "git-clone", "description": "Custom AI prompt generator node for ComfyUI." }, - { - "author": "mlinmg", - "title": "LaMa Preprocessor [WIP]", - "reference": "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor", - "files": [ - "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor" - ], - "install_type": "git-clone", - "description": "A LaMa prerocessor for ComfyUI. This preprocessor finally enable users to generate coherent inpaint and outpaint prompt-free. The best results are given on landscapes, not so much in drawings/animation." - }, { "author": "kijai", "title": "KJNodes for ComfyUI", @@ -2522,12 +2532,12 @@ { "author": "kijai", "title": "ComfyUI-APISR", - "reference": "https://github.com/kijai/ComfyUI-APISR", + "reference": "https://github.com/kijai/ComfyUI-APISR-KJ", "files": [ - "https://github.com/kijai/ComfyUI-APISR" + "https://github.com/kijai/ComfyUI-APISR-KJ" ], "install_type": "git-clone", - "description": "Node to use [a/APISR](https://github.com/Kiteretsu77/APISR) upscale models in ComfyUI" + "description": "Node to use [a/APISR](https://github.com/Kiteretsu77/APISR) upscale models in ComfyUI.[w/NOTE: repo name is changed from ComfyUI-APISR -> ComfyUI-APISR-KJ]" }, { "author": "kijai", @@ -2539,6 +2549,36 @@ "install_type": "git-clone", "description": "This is simplified implementation of the [a/DiffusionLight](https://github.com/DiffusionLight/DiffusionLight) method of creating light probes. You will need the included LoRA, place it in ComfyUI/loras folder like usual, it's converted from the original diffusers one." }, + { + "author": "kijai", + "title": "ComfyUI-ELLA-wrapper", + "reference": "https://github.com/kijai/ComfyUI-ELLA-wrapper", + "files": [ + "https://github.com/kijai/ComfyUI-ELLA-wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI wrapper nodes to use the Diffusers implementation of ELLA" + }, + { + "author": "kijai", + "title": "ComfyUI-LaVi-Bridge-Wrapper", + "reference": "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper", + "files": [ + "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI wrapper node to test LaVi-Bridge using Diffusers" + }, + { + "author": "kijai", + "title": "ComfyUI-BrushNet-Wrapper", + "reference": "https://github.com/kijai/ComfyUI-BrushNet-Wrapper", + "files": [ + "https://github.com/kijai/ComfyUI-BrushNet-Wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI wrapper nodes to use the Diffusers implementation of BrushNet" + }, { "author": "hhhzzyang", "title": "Comfyui-Lama", @@ -2581,7 +2621,7 @@ }, { "author": "avatechai", - "title": "avatar-graph-comfyui", + "title": "Avatar Graph", "reference": "https://github.com/avatechai/avatar-graph-comfyui", "files": [ "https://github.com/avatechai/avatar-graph-comfyui" @@ -3304,7 +3344,7 @@ }, { "author": "Danand", - "title": "ComfyUI-ComfyCouple", + "title": "Comfy Couple", "reference": "https://github.com/Danand/ComfyUI-ComfyCouple", "files": [ "https://github.com/Danand/ComfyUI-ComfyCouple" @@ -4114,6 +4154,16 @@ "install_type": "git-clone", "description": "A suite of tools for prompt management. Combining nodes helps the user sequence strings for prompts, also creating logical groupings if necessary. Individual nodes can be chained together in any order." }, + { + "author": "florestefano1975", + "title": "ComfyUI StabilityAI Suite", + "reference": "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite", + "files": [ + "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite" + ], + "install_type": "git-clone", + "description": "This fork of the official StabilityAI repository contains a number of enhancements and implementations." + }, { "author": "mozman", "title": "ComfyUI_mozman_nodes", @@ -4266,7 +4316,7 @@ }, { "author": "HarroweD and quadmoon", - "title": "Harronode", + "title": "Harrlogos Prompt Builder Node", "reference": "https://github.com/NotHarroweD/Harronode", "nodename_pattern": "Harronode", "files": [ @@ -4557,6 +4607,26 @@ "install_type": "git-clone", "description": "Nodes:3D Pose Editor" }, + { + "author": "chaojie", + "title": "ComfyUI-CameraCtrl-Wrapper", + "reference": "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper", + "files": [ + "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI-CameraCtrl-Wrapper" + }, + { + "author": "chaojie", + "title": "ComfyUI-EasyAnimate", + "reference": "https://github.com/chaojie/ComfyUI-EasyAnimate", + "files": [ + "https://github.com/chaojie/ComfyUI-EasyAnimate" + ], + "install_type": "git-clone", + "description": "ComfyUI-EasyAnimate" + }, { "author": "chaojie", "title": "ComfyUI_StreamingT2V", @@ -4787,6 +4857,16 @@ "install_type": "git-clone", "description": "This is an ComfyUI implementation of RAFT to generate motion brush" }, + { + "author": "chaojie", + "title": "ComfyUI-LaVIT", + "reference": "https://github.com/chaojie/ComfyUI-LaVIT", + "files": [ + "https://github.com/chaojie/ComfyUI-LaVIT" + ], + "install_type": "git-clone", + "description": "Nodes:VideoLaVITLoader, VideoLaVITT2V, VideoLaVITI2V, VideoLaVITI2VLong, VideoLaVITT2VLong, VideoLaVITI2I" + }, { "author": "alexopus", "title": "ComfyUI Image Saver", @@ -5321,7 +5401,7 @@ }, { "author": "Hiero207", - "title": "ComfyUI-Hiero-Nodes", + "title": "Hiero-Nodes", "reference": "https://github.com/Hiero207/ComfyUI-Hiero-Nodes", "files": [ "https://github.com/Hiero207/ComfyUI-Hiero-Nodes" @@ -5411,7 +5491,7 @@ }, { "author": "JerryOrbachJr", - "title": "ComfyUI-RandomSize", + "title": "Random Size", "reference": "https://github.com/JerryOrbachJr/ComfyUI-RandomSize", "files": [ "https://github.com/JerryOrbachJr/ComfyUI-RandomSize" @@ -5431,7 +5511,7 @@ }, { "author": "mape", - "title": "mape's ComfyUI Helpers", + "title": "mape's helpers", "reference": "https://github.com/mape/ComfyUI-mape-Helpers", "files": [ "https://github.com/mape/ComfyUI-mape-Helpers" @@ -5621,7 +5701,7 @@ }, { "author": "dfl", - "title": "comfyui-clip-with-break", + "title": "CLIP with BREAK syntax", "reference": "https://github.com/dfl/comfyui-clip-with-break", "files": [ "https://github.com/dfl/comfyui-clip-with-break" @@ -5639,16 +5719,6 @@ "install_type": "git-clone", "description": "ComfyUI Custom Sampler nodes that implement Zheng et al.'s Trajectory Consistency Distillation based on [a/https://mhh0318.github.io/tcd](https://mhh0318.github.io/tcd)" }, - { - "author": "MarkoCa1", - "title": "ComfyUI_Segment_Mask", - "reference": "https://github.com/MarkoCa1/ComfyUI_Segment_Mask", - "files": [ - "https://github.com/MarkoCa1/ComfyUI_Segment_Mask" - ], - "install_type": "git-clone", - "description": "Mask cutout based on Segment Anything." - }, { "author": "antrobot", "title": "antrobots ComfyUI Nodepack", @@ -5920,14 +5990,24 @@ "description": "ComfyUI nodes to use [a/FLATTEN: optical FLow-guided ATTENtion for consistent text-to-video editing](https://github.com/yrcong/flatten)." }, { - "author": "Big-Idea-Technology", - "title": "ImageTextOverlay Node for ComfyUI", - "reference": "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay", + "author": "logtd", + "title": "ComfyUI-RAVE Attention", + "reference": "https://github.com/logtd/ComfyUI-RAVE_ATTN", "files": [ - "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay" + "https://github.com/logtd/ComfyUI-RAVE_ATTN" ], "install_type": "git-clone", - "description": "ImageTextOverlay is a customizable Node for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding." + "description": "ComfyUI nodes to use RAVE attention as a temporal attention mechanism.\nThis differs from other implementations in that it does not concatenate the images together, but within the UNet's Self-Attention mechanism performs the RAVE technique. By not altering the images/latents throughout the UNet, this method does not affect other temporal techniques, style mechanisms, or other UNet modifications.\nFor example, it can be combined with AnimateDiff, ModelScope/ZeroScope, or FLATTEN." + }, + { + "author": "Big-Idea-Technology", + "title": "ComfyUI-Book-Tools Nodes for ComfyUI", + "reference": "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools", + "files": [ + "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools" + ], + "install_type": "git-clone", + "description": "ComfyUI-Book-Tools is a set o new nodes for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding. Loop with any parameters (*), prompt batch schedule with prompt selector, end queue for automatic ending current queue." }, { "author": "Big Idea Technology", @@ -5939,16 +6019,6 @@ "install_type": "git-clone", "description": "The LLM_Node enhances ComfyUI by integrating advanced language model capabilities, enabling a wide range of NLP tasks such as text generation, content summarization, question answering, and more. This flexibility is powered by various transformer model architectures from the transformers library, allowing for the deployment of models like T5, GPT-2, and others based on your project's needs." }, - { - "author": "Big Idea Technology", - "title": "Image Text Overlay Node for ComfyUI", - "reference": "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay", - "files": [ - "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay" - ], - "install_type": "git-clone", - "description": "ImageTextOverlay is a customizable Node for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding." - }, { "author": "Guillaume-Fgt", "title": "ComfyUI-ScenarioPrompt", @@ -5981,7 +6051,7 @@ }, { "author": "czcz1024", - "title": "Comfyui-FaceCompare", + "title": "Face Compare", "reference": "https://github.com/czcz1024/Comfyui-FaceCompare", "files": [ "https://github.com/czcz1024/Comfyui-FaceCompare" @@ -6399,6 +6469,16 @@ "install_type": "git-clone", "description": "ComfyUI Version of '[a/Visual Style Prompting with Swapping Self-Attention](https://github.com/naver-ai/Visual-Style-Prompting)'" }, + { + "author": "ExponentialML", + "title": "ComfyUI_ELLA", + "reference": "https://github.com/ExponentialML/ComfyUI_ELLA", + "files": [ + "https://github.com/ExponentialML/ComfyUI_ELLA" + ], + "install_type": "git-clone", + "description": "ComfyUI Implementaion of ELLA: Equip Diffusion Models with LLM for Enhanced Semantic Alignment" + }, { "author": "angeloshredder", "title": "StableCascadeResizer", @@ -6489,6 +6569,16 @@ "install_type": "git-clone", "description": "Various AI tools to use in Comfy UI. Starting with VL and prompt making tools using Ollma as backend will evolve as I find time." }, + { + "author": "if-ai", + "title": "ComfyUI-IF_AI_WishperSpeechNode", + "reference": "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode", + "files": [ + "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode" + ], + "install_type": "git-clone", + "description": "This repository hosts a Text-to-Speech (TTS) application that leverages Whisper Speech for voice synthesis, allowing users to train a voice model on-the-fly. It is built on ComfyUI and supports rapid training and inference processes." + }, { "author": "dmMaze", "title": "Sketch2Manga", @@ -6549,6 +6639,16 @@ "install_type": "git-clone", "description": "Text." }, + { + "author": "MarkoCa1", + "title": "ComfyUI_Segment_Mask", + "reference": "https://github.com/MarkoCa1/ComfyUI_Segment_Mask", + "files": [ + "https://github.com/MarkoCa1/ComfyUI_Segment_Mask" + ], + "install_type": "git-clone", + "description": "Mask cutout based on Segment Anything." + }, { "author": "Shadetail", "title": "Eagleshadow Custom Nodes", @@ -6647,7 +6747,7 @@ "https://github.com/chaosaiart/Chaosaiart-Nodes" ], "install_type": "git-clone", - "description": "This extension provides various custom nodes to assist in configuring the workflow structure." + "description": "LowVRAM Animation : txt2video - img2video - video2video , Frame by Frame, compatible with LowVRAM GPUs\nIncluded : Prompt Switch, Checkpoint Switch, Cache, Number Count by Frame, Ksampler txt2img & img2img ..." }, { "author": "viperyl", @@ -6691,13 +6791,43 @@ }, { "author": "hay86", - "title": "ComfyUI_AceNodes", + "title": "ComfyUI OpenVoice", + "reference": "https://github.com/hay86/ComfyUI_OpenVoice", + "files": [ + "https://github.com/hay86/ComfyUI_OpenVoice" + ], + "install_type": "git-clone", + "description": "Unofficial implementation of [a/OpenVoice](https://github.com/myshell-ai/OpenVoice) for ComfyUI" + }, + { + "author": "hay86", + "title": "ComfyUI DDColor", + "reference": "https://github.com/hay86/ComfyUI_DDColor", + "files": [ + "https://github.com/hay86/ComfyUI_DDColor" + ], + "install_type": "git-clone", + "description": "Unofficial implementation of [a/DDColor](https://github.com/piddnad/DDColor) for ComfyUI" + }, + { + "author": "hay86", + "title": "ComfyUI MiniCPM-V", + "reference": "https://github.com/hay86/ComfyUI_MiniCPM-V", + "files": [ + "https://github.com/hay86/ComfyUI_MiniCPM-V" + ], + "install_type": "git-clone", + "description": "Unofficial implementation of [a/MiniCPM-V](https://github.com/OpenBMB/MiniCPM-V) for ComfyUI" + }, + { + "author": "hay86", + "title": "ComfyUI AceNodes", "reference": "https://github.com/hay86/ComfyUI_AceNodes", "files": [ "https://github.com/hay86/ComfyUI_AceNodes" ], "install_type": "git-clone", - "description": "Nodes:Integer, Float, Text, Seed, Text Concatenate, Text Input Switch (2/4/8 way), Text List, Text Preview, Text Selector, Text To Resolution. Some useful custom nodes that are not included in ComfyUI core yet." + "description": "Some useful custom nodes that are not included in ComfyUI core yet." }, { "author": "shinich39", @@ -6830,7 +6960,7 @@ "description": "Several utility nodes for use with ComfyUI." }, { - "author": "frankchieng", + "author": "FrankChieng", "title": "ComfyUI_Aniportrait", "reference": "https://github.com/frankchieng/ComfyUI_Aniportrait", "files": [ @@ -6839,6 +6969,16 @@ "install_type": "git-clone", "description": "implementation of [a/AniPortrait](https://github.com/Zejun-Yang/AniPortrait) generating of videos, includes self driven, face reenacment and audio driven with a reference image" }, + { + "author": "FrankChieng", + "title": "ComfyUI_MagicClothing", + "reference": "https://github.com/frankchieng/ComfyUI_MagicClothing", + "files": [ + "https://github.com/frankchieng/ComfyUI_MagicClothing" + ], + "install_type": "git-clone", + "description": "implementation of MagicClothing with garment and prompt in ComfyUI" + }, { "author": "BlakeOne", "title": "ComfyUI SchedulerMixer", @@ -6859,6 +6999,26 @@ "install_type": "git-clone", "description": "Simple node for setting the sigma values directly. Note, for a full denoise the last sigma should be zero." }, + { + "author": "BlakeOne", + "title": "ComfyUI NodePresets", + "reference": "https://github.com/BlakeOne/ComfyUI-NodePresets", + "files": [ + "https://github.com/BlakeOne/ComfyUI-NodePresets" + ], + "install_type": "git-clone", + "description": "An extension for ComyUI that enables saving and loading node presets using the node's context menu.\nRight click a node and choose 'Presets' from its context menu to access the node's presets." + }, + { + "author": "BlakeOne", + "title": "ComfyUI NodeReset", + "reference": "https://github.com/BlakeOne/ComfyUI-NodeReset", + "files": [ + "https://github.com/BlakeOne/ComfyUI-NodeReset" + ], + "install_type": "git-clone", + "description": "An extension for ComyUI to allow resetting a node's inputs to their default values.\nNOTE:Right click any node and choose 'Reset' from the context menu." + }, { "author": "kale4eat", "title": "ComfyUI_demucus", @@ -6889,6 +7049,16 @@ "install_type": "git-clone", "description": "Text file utility for ComfyUI" }, + { + "author": "kale4eat", + "title": "ComfyUI-speech-dataset-toolkit", + "reference": "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit", + "files": [ + "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit" + ], + "install_type": "git-clone", + "description": "Basic audio tools using torchaudio for ComfyUI. It is assumed to assist in the speech dataset creation for ASR, TTS, etc." + }, { "author": "DrMWeigand", "title": "ComfyUI Color Detection Nodes", @@ -6959,6 +7129,16 @@ "install_type": "git-clone", "description": "Attach a debug node to an output to obtain more detailed information. Uncover the details of your models in ComfyUI with ease." }, + { + "author": "Sida Liu", + "title": "ComfyUI-Login", + "reference": "https://github.com/liusida/ComfyUI-Login", + "files": [ + "https://github.com/liusida/ComfyUI-Login" + ], + "install_type": "git-clone", + "description": "A simple password to protect ComfyUI." + }, { "author": "jtydhr88", "title": "ComfyUI-Workflow-Encrypt", @@ -6999,16 +7179,6 @@ "install_type": "git-clone", "description": "This repository simply caches the CLIP embeddings and subtly accelerates the inference process by bypassing unnecessary computations." }, - { - "author": "abdozmantar", - "title": "InstaSwap Face Swap Node for ComfyUI", - "reference": "https://github.com/abdozmantar/ComfyUI-InstaSwap", - "files": [ - "https://github.com/abdozmantar/ComfyUI-InstaSwap" - ], - "install_type": "git-clone", - "description": "Fastest Face Swap Extension Node for ComfyUI, Single node and FastTrack: Lightning-Speed Facial Transformation for your projects." - }, { "author": "AIFSH", "title": "ComfyUI-UVR5", @@ -7020,14 +7190,54 @@ "description": "the custom code for [a/UVR5](https://github.com/Anjok07/ultimatevocalremovergui) to separate vocals and background music" }, { - "author": "CapsAdmin", - "title": "ComfyUI-Euler-Smea-Dyn-Sampler", - "reference": "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler", + "author": "AIFSH", + "title": "ComfyUI-IP_LAP", + "reference": "https://github.com/AIFSH/ComfyUI-IP_LAP", "files": [ - "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler" + "https://github.com/AIFSH/ComfyUI-IP_LAP" ], "install_type": "git-clone", - "description": "Just a comfyui version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds the sampler directly to existing samplers." + "description": "Nodes:IP_LAP Node, Video Loader, PreView Video, Combine Audio Video. the comfyui custom node of [a/IP_LAP](https://github.com/Weizhi-Zhong/IP_LAP) to make audio driven videos!" + }, + { + "author": "AIFSH", + "title": "ComfyUI-GPT_SoVITS", + "reference": "https://github.com/AIFSH/ComfyUI-GPT_SoVITS", + "files": [ + "https://github.com/AIFSH/ComfyUI-GPT_SoVITS" + ], + "install_type": "git-clone", + "description": "a comfyui custom node for [a/GPT-SoVITS](https://github.com/RVC-Boss/GPT-SoVITS)! you can voice cloning and tts in comfyui now\n[w/NOTE:make sure ffmpeg is worked in your commandline]" + }, + { + "author": "AIFSH", + "title": "ComfyUI-MuseTalk_FSH", + "reference": "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH", + "files": [ + "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH" + ], + "install_type": "git-clone", + "description": "the comfyui custom node of [a/MuseTalk](https://github.com/TMElyralab/MuseTalk) to make audio driven videos!" + }, + { + "author": "AIFSH", + "title": "ComfyUI-WhisperX", + "reference": "https://github.com/AIFSH/ComfyUI-WhisperX", + "files": [ + "https://github.com/AIFSH/ComfyUI-WhisperX" + ], + "install_type": "git-clone", + "description": "a comfyui cuatom node for audio subtitling based on [a/whisperX](https://github.com/m-bain/whisperX.git) and [a/translators](https://github.com/UlionTse/translators)" + }, + { + "author": "Koishi-Star", + "title": "Euler-Smea-Dyn-Sampler", + "reference": "https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler", + "files": [ + "https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler" + ], + "install_type": "git-clone", + "description": "СomfyUI version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds samplers directly to KSampler nodes." }, { "author": "sdfxai", @@ -7039,7 +7249,376 @@ "install_type": "git-clone", "description": "SDFXBridgeForComfyUI is a custom node designed for seamless integration between ComfyUI and SDFX. This custom node allows users to make ComfyUI compatible with SDFX when running the ComfyUI instance on their local machines." }, - + { + "author": "smthemex", + "title": "ComfyUI_ChatGLM_API", + "reference": "https://github.com/smthemex/ComfyUI_ChatGLM_API", + "files": [ + "https://github.com/smthemex/ComfyUI_ChatGLM_API" + ], + "install_type": "git-clone", + "description": "You can call Chatglm's API in comfyUI to translate and describe pictures, and the API similar to OpenAI." + }, + { + "author": "smthemex", + "title": "ComfyUI_ParlerTTS", + "reference": "https://github.com/smthemex/ComfyUI_ParlerTTS", + "files": [ + "https://github.com/smthemex/ComfyUI_ParlerTTS" + ], + "install_type": "git-clone", + "description": "This is a simple ComfyUI custom TTS node based on [a/Parler_tts](https://huggingface.co/parler-tts)." + }, + { + "author": "smthemex", + "title": "ComfyUI_Pic2Story", + "reference": "https://github.com/smthemex/ComfyUI_Pic2Story", + "files": [ + "https://github.com/smthemex/ComfyUI_Pic2Story" + ], + "install_type": "git-clone", + "description": "ComfyUI simple node based on BLIP method, with the function of 'Image to Txt'." + }, + { + "author": "smthemex", + "title": "ComfyUI_Pic2Story", + "reference": "https://github.com/smthemex/ComfyUI_Pic2Story", + "files": [ + "https://github.com/smthemex/ComfyUI_Pic2Story" + ], + "install_type": "git-clone", + "description": "ComfyUI simple node based on BLIP method, with the function of 'Image to Txt'." + }, + { + "author": "smthemex", + "title": "ComfyUI_Pipeline_Tool", + "reference": "https://github.com/smthemex/ComfyUI_Pipeline_Tool", + "files": [ + "https://github.com/smthemex/ComfyUI_Pipeline_Tool" + ], + "install_type": "git-clone", + "description": "Nodes:Pipeline_Tool" + }, + { + "author": "choey", + "title": "Comfy-Topaz", + "reference": "https://github.com/choey/Comfy-Topaz", + "files": [ + "https://github.com/choey/Comfy-Topaz" + ], + "install_type": "git-clone", + "description": "Comfy-Topaz is a custom node for ComfyUI, which integrates with Topaz Photo AI to enhance (upscale, sharpen, denoise, etc.) images, allowing this traditionally asynchronous step to become a part of ComfyUI workflows.\nNOTE:Licensed installation of Topaz Photo AI" + }, + { + "author": "ALatentPlace", + "title": "ComfyUI_yanc", + "reference": "https://github.com/ALatentPlace/ComfyUI_yanc", + "files": [ + "https://github.com/ALatentPlace/ComfyUI_yanc" + ], + "install_type": "git-clone", + "description": "Yet Another Node Collection. Adds some useful nodes, check out the GitHub page for more details." + }, + { + "author": "Wicloz", + "title": "ComfyUI-Simply-Nodes", + "reference": "https://github.com/Wicloz/ComfyUI-Simply-Nodes", + "files": [ + "https://github.com/Wicloz/ComfyUI-Simply-Nodes" + ], + "install_type": "git-clone", + "description": "Nodes:Conditional LoRA Loader, Multiline Text, Text Flow Controller, Select SDXL Resolution, Random Style Prompt." + }, + { + "author": "wandbrandon", + "title": "comfyui-pixel", + "reference": "https://github.com/wandbrandon/comfyui-pixel", + "files": [ + "https://github.com/wandbrandon/comfyui-pixel" + ], + "install_type": "git-clone", + "description": "pixel art workshop nodes for comfyui." + }, + { + "author": "nullquant", + "title": "BrushNet", + "reference": "https://github.com/nullquant/ComfyUI-BrushNet", + "files": [ + "https://github.com/nullquant/ComfyUI-BrushNet" + ], + "install_type": "git-clone", + "description": "Custom nodes for ComfyUI allow to inpaint using Brushnet: '[a/BrushNet: A Plug-and-Play Image Inpainting Model with Decomposed Dual-Branch Diffusion](https://arxiv.org/abs/2403.06976)'." + }, + { + "author": "pamparamm", + "title": "Perturbed-Attention Guidance", + "reference": "https://github.com/pamparamm/sd-perturbed-attention", + "files": [ + "https://github.com/pamparamm/sd-perturbed-attention" + ], + "install_type": "git-clone", + "description": "Perturbed-Attention Guidance node for ComfyUI." + }, + { + "author": "unwdef", + "title": "unwdef-nodes", + "reference": "https://github.com/unwdef/unwdef-nodes-comfyui", + "files": [ + "https://github.com/unwdef/unwdef-nodes-comfyui" + ], + "install_type": "git-clone", + "description": "Custom nodes for ComfyUI by unwdef." + }, + { + "author": "fevre27", + "title": "Self-Guidance nodes", + "reference": "https://github.com/forever22777/comfyui-self-guidance", + "files": [ + "https://github.com/forever22777/comfyui-self-guidance" + ], + "install_type": "git-clone", + "description": "Unofficial ComfyUI implementation of Self-Guidance." + }, + { + "author": "aburahamu", + "title": "ComfyUI-RequestsPoster", + "reference": "https://github.com/aburahamu/ComfyUI-RequestsPoster", + "files": [ + "https://github.com/aburahamu/ComfyUI-RequestsPoster" + ], + "install_type": "git-clone", + "description": "This custom node is that simply posts HttpRequest from ComfyUI." + }, + { + "author": "Sorcerio", + "title": "MBM's Music Visualizer", + "reference": "https://github.com/Sorcerio/MBM-Music-Visualizer", + "files": [ + "https://github.com/Sorcerio/MBM-Music-Visualizer" + ], + "install_type": "git-clone", + "description": "An image generation based music visualizer integrated into comfyanonymous/ComfyUI as custom nodes." + }, + { + "author": "quadmoon", + "title": "quadmoon's ComfyUI nodes", + "reference": "https://github.com/traugdor/ComfyUI-quadMoons-nodes", + "files": [ + "https://github.com/traugdor/ComfyUI-quadMoons-nodes" + ], + "install_type": "git-clone", + "description": "These are just some nodes I wanted and couldn't find where anyone else had made them yet." + }, + { + "author": "quadme7macoon", + "title": "ComfyUI-ShadertoyGL", + "reference": "https://github.com/e7mac/ComfyUI-ShadertoyGL", + "files": [ + "https://github.com/e7mac/ComfyUI-ShadertoyGL" + ], + "install_type": "git-clone", + "description": "Nodes:Shadertoy, Shader, ColorChannelOffset." + }, + { + "author": "turkyden", + "title": "ComfyUI-Sticker", + "reference": "https://github.com/turkyden/ComfyUI-Sticker", + "files": [ + "https://github.com/turkyden/ComfyUI-Sticker" + ], + "install_type": "git-clone", + "description": "image to sticker" + }, + { + "author": "turkyden", + "title": "ComfyUI-Comic", + "reference": "https://github.com/turkyden/ComfyUI-Comic", + "files": [ + "https://github.com/turkyden/ComfyUI-Comic" + ], + "install_type": "git-clone", + "description": "a comfyui plugin for image to comic" + }, + { + "author": "royceschultz", + "title": "ComfyUI-TranscriptionTools", + "reference": "https://github.com/royceschultz/ComfyUI-TranscriptionTools", + "files": [ + "https://github.com/royceschultz/ComfyUI-TranscriptionTools" + ], + "install_type": "git-clone", + "description": "Transcribe audio and video files in ComfyUI." + }, + { + "author": "kunieone", + "title": "ComfyUI_alkaid", + "reference": "https://github.com/kunieone/ComfyUI_alkaid", + "files": [ + "https://github.com/kunieone/ComfyUI_alkaid" + ], + "install_type": "git-clone", + "description": "Nodes:A_Face3DSwapper, A_FaceCrop, A_FacePaste, A_OpenPosePreprocessor, A_EmptyLatentImageLongside, A_GetImageSize, AlkaidLoader, AdapterFaceLoader, AdapterStyleLoader, ..." + }, + { + "author": "jtydhr88", + "title": "ComfyUI-InstantMesh", + "reference": "https://github.com/jtydhr88/ComfyUI-InstantMesh", + "files": [ + "https://github.com/jtydhr88/ComfyUI-InstantMesh" + ], + "install_type": "git-clone", + "description": "ComfyUI InstantMesh is custom nodes that running TencentARC/InstantMesh into ComfyUI, this extension depends on ComfyUI-3D-Pack. Please refer to Readme carefully to install." + }, + { + "author": "txt2any", + "title": "ComfyUI-PromptOrganizer", + "reference": "https://github.com/txt2any/ComfyUI-PromptOrganizer", + "files": [ + "https://github.com/txt2any/ComfyUI-PromptOrganizer" + ], + "install_type": "git-clone", + "description": "This is a custom node for ComfyUI that automatically saves your AI-generated images specifically to [a/www.txt2any.com](http://www.txt2any.com/)." + }, + { + "author": "kealiu", + "title": "ComfyUI Load and Save file to S3", + "reference": "https://github.com/kealiu/ComfyUI-S3-Tools", + "files": [ + "https://github.com/kealiu/ComfyUI-S3-Tools" + ], + "install_type": "git-clone", + "description": "Nodes:Load From S3, Save To S3." + }, + { + "author": "TashaSkyUp", + "title": "ComfyUI_LiteLLM", + "reference": "https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM", + "files": [ + "https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM" + ], + "install_type": "git-clone", + "description": "Nodes for interfacing with LiteLLM" + }, + { + "author": "AonekoSS", + "title": "ComfyUI-SimpleCounter", + "reference": "https://github.com/AonekoSS/ComfyUI-SimpleCounter", + "files": [ + "https://github.com/AonekoSS/ComfyUI-SimpleCounter" + ], + "install_type": "git-clone", + "description": "Nodes:Simple Counter" + }, + { + "author": "heshengtao", + "title": "comfyui_LLM_party", + "reference": "https://github.com/heshengtao/comfyui_LLM_party", + "files": [ + "https://github.com/heshengtao/comfyui_LLM_party" + ], + "install_type": "git-clone", + "description": "A set of block-based LLM agent node libraries designed for ComfyUI.This project aims to develop a complete set of nodes for LLM workflow construction based on comfyui. It allows users to quickly and conveniently build their own LLM workflows and easily integrate them into their existing SD workflows." + }, + { + "author": "VAST-AI-Research", + "title": "Tripo for ComfyUI", + "reference": "https://github.com/VAST-AI-Research/ComfyUI-Tripo", + "files": [ + "https://github.com/VAST-AI-Research/ComfyUI-Tripo" + ], + "install_type": "git-clone", + "description": "Custom nodes for using [a/Tripo](https://www.tripo3d.ai/) in ComfyUI to create 3D from text and image prompts." + }, + { + "author": "JettHu", + "title": "ComfyUI_TGate", + "reference": "https://github.com/JettHu/ComfyUI_TGate", + "files": [ + "https://github.com/JettHu/ComfyUI_TGate" + ], + "install_type": "git-clone", + "description": "ComfyUI reference implementation for [a/T-GATE](https://github.com/HaozheLiu-ST/T-GATE)." + }, + { + "author": "sugarkwork", + "title": "comfyui_tag_filter", + "reference": "https://github.com/sugarkwork/comfyui_tag_fillter", + "files": [ + "https://github.com/sugarkwork/comfyui_tag_fillter" + ], + "install_type": "git-clone", + "description": "This is a custom node of ComfyUI that categorizes tags outputted by tools like WD14Tagger, filters them by each category, and returns the filtered results." + }, + { + "author": "Intersection98", + "title": "ComfyUI-MX-post-processing-nodes", + "reference": "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes", + "files": [ + "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes" + ], + "install_type": "git-clone", + "description": "A collection of post processing nodes for ComfyUI, dds image post-processing adjustment capabilities to the ComfyUI." + }, + { + "author": "TencentQQGYLab", + "title": "ComfyUI-ELLA", + "reference": "https://github.com/TencentQQGYLab/ComfyUI-ELLA", + "files": [ + "https://github.com/TencentQQGYLab/ComfyUI-ELLA" + ], + "install_type": "git-clone", + "description": "ComfyUI implementation for [a/ELLA](https://github.com/TencentQQGYLab/ELLA)." + }, + { + "author": "DarKDinDoN", + "title": "ComfyUI Checkpoint Automatic Config", + "reference": "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config", + "files": [ + "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config" + ], + "install_type": "git-clone", + "description": "This node was designed to help with checkpoint configuration." + }, + { + "author": "aburahamu", + "title": "ComfyUI-RequestPoster", + "reference": "https://github.com/aburahamu/ComfyUI-RequestsPoster", + "files": [ + "https://github.com/aburahamu/ComfyUI-RequestsPoster" + ], + "install_type": "git-clone", + "description": "This extension can send HTTP Requests. You can request image generation to StableDiffusion3 and post images to X (Twitter) and Discord." + }, + { + "author": "MinusZoneAI", + "title": "ComfyUI-Prompt-MZ", + "reference": "https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ", + "files": [ + "https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ" + ], + "install_type": "git-clone", + "description": "Use llama.cpp to help generate some nodes for prompt word related work" + }, + { + "author": "blueraincoatli", + "title": "comfyUI_SillyNodes", + "reference": "https://github.com/blueraincoatli/comfyUI_SillyNodes", + "files": [ + "https://github.com/blueraincoatli/comfyUI_SillyNodes" + ], + "install_type": "git-clone", + "description": "Using rgthree's fast_group_muter and bookmark nodes, introduce the pyautogui library to simulate clicks and hotkeys, and run groups in sequence. screen manipulation is involved" + }, + { + "author": "ty0x2333", + "title": "ComfyUI-Dev-Utils", + "reference": "https://github.com/ty0x2333/ComfyUI-Dev-Utils", + "files": [ + "https://github.com/ty0x2333/ComfyUI-Dev-Utils" + ], + "install_type": "git-clone", + "description": "Execution Time Analysis, Reroute Enhancement, Node collection for developers." + }, @@ -7352,7 +7931,19 @@ ], "install_type": "copy", "description": "Extension to show random cat GIFs while queueing prompt." - }, + }, + { + "author": "xliry", + "title": "ComfyUI_SendDiscord", + "reference": "https://github.com/xliry/ComfyUI_SendDiscord", + "files": [ + "https://github.com/xliry/ComfyUI_SendDiscord/raw/main/SendDiscord.py" + ], + "install_type": "copy", + "description": "Nodes:Send Video to Discord" + }, + + { "author": "theally", "title": "TheAlly's Custom Nodes", diff --git a/docs/en/cm-cli.md b/docs/en/cm-cli.md new file mode 100644 index 00000000..8599b496 --- /dev/null +++ b/docs/en/cm-cli.md @@ -0,0 +1,140 @@ +# `cm-cli`: ComfyUI-Manager CLI + +`cm-cli` is a tool that allows you to use various functions of ComfyUI-Manager from the command line without launching ComfyUI. + + +``` +-= ComfyUI-Manager CLI (V2.22) =- + +python cm-cli.py [OPTIONS] + +OPTIONS: + [install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel ] ?[--mode [remote|local|cache]] + [update|disable|enable|fix] all ?[--channel ] ?[--mode [remote|local|cache]] + [simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel ] ?[--mode [remote|local|cache]] + save-snapshot + restore-snapshot + cli-only-mode [enable|disable] + restore-dependencies + clear + +``` + +## How To Use? +* You can execute it via `python cm-cli.py`. +* For example, if you want to update all custom nodes: + * In the ComfyUI-Manager directory, you can execute the command `python cm-cli.py update all`. + * If running from the ComfyUI directory, you can specify the path to cm-cli.py like this: `python custom_nodes/ComfyUI-Manager/cm-cli.py update all`. + +## Prerequisite +* It must be run in the same Python environment as the one running ComfyUI. + * If using a venv, you must run it with the venv activated. + * If using a portable version, and you are in the directory with the run_nvidia_gpu.bat file, you should execute the command as follows: + `.\python_embeded\python.exe ComfyUI\custom_nodes\ComfyUI-Manager\cm-cli.py update all` +* The path for ComfyUI can be set with the COMFYUI_PATH environment variable. If omitted, a warning message will appear, and the path will be set relative to the installed location of ComfyUI-Manager: + ``` + WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path. + ``` + +## Features + +### 1. --channel, --mode +* For viewing information and managing custom nodes, you can set the information database through --channel and --mode. +* For instance, executing the command `python cm-cli.py update all --channel recent --mode remote` will operate based on the latest information from remote rather than local data embedded in the current ComfyUI-Manager repo and will only target the list in the recent channel. +* --channel, --mode are only available with the commands `simple-show, show, install, uninstall, update, disable, enable, fix`. + +### 2. Viewing Management Information + +`[simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel ] ?[--mode [remote|local|cache]]` + +* `[show|simple-show]` - `show` provides detailed information, while `simple-show` displays information more simply. + +Executing a command like `python cm-cli.py show installed` will display detailed information about the installed custom nodes. + +``` +-= ComfyUI-Manager CLI (V2.21.1) =- + +FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json +[ ENABLED ] ComfyUI-Manager (author: Dr.Lt.Data) +[ ENABLED ] ComfyUI-Impact-Pack (author: Dr.Lt.Data) +[ ENABLED ] ComfyUI-Inspire-Pack (author: Dr.Lt.Data) +[ ENABLED ] ComfyUI_experiments (author: comfyanonymous) +[ ENABLED ] ComfyUI-SAI_API (author: Stability-AI) +[ ENABLED ] stability-ComfyUI-nodes (author: Stability-AI) +[ ENABLED ] comfyui_controlnet_aux (author: Fannovel16) +[ ENABLED ] ComfyUI-Frame-Interpolation (author: Fannovel16) +[ DISABLED ] ComfyUI-Loopchain (author: Fannovel16) +``` + +Using a command like `python cm-cli.py simple-show installed` will simply display information about the installed custom nodes. + +``` +-= ComfyUI-Manager CLI (V2.21.1) =- + +FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json +ComfyUI-Manager +ComfyUI-Impact-Pack +ComfyUI-Inspire-Pack +ComfyUI_experiments +ComfyUI-SAI_API +stability-ComfyUI-nodes +comfyui_controlnet_aux +ComfyUI-Frame-Interpolation +ComfyUI-Loopchain +``` + +`[installed|enabled|not-installed|disabled|all|snapshot|snapshot-list]` + * `enabled`, `disabled`: Shows nodes that have been enabled or disabled among the installed custom nodes. + * `installed`: Shows all nodes that have been installed, regardless of whether they are enabled or disabled. + * `not-installed`: Shows a list of custom nodes that have not been installed. + * `all`: Shows a list of all custom nodes. + * `snapshot`: Displays snapshot information of the currently installed custom nodes. When viewed with `show`, it is displayed in JSON format, and with `simple-show`, it is displayed simply, along with the commit hash. + * `snapshot-list`: Shows a list of snapshot files stored in ComfyUI-Manager/snapshots. + +### 3. Managing Custom Nodes + +`[install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel ] ?[--mode [remote|local|cache]]` + +* You can apply management functions by listing the names of custom nodes, such as `python cm-cli.py install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack ComfyUI_experiments`. +* The names of the custom nodes are as shown by `show` and are the names of the git repositories. +(Plans are to update the use of nicknames in the future.) + +`[update|disable|enable|fix] all ?[--channel ] ?[--mode [remote|local|cache]]` + +* The `update, disable, enable, fix` functions can be specified for all. + +* Detailed Operations + * `install`: Installs the specified custom nodes. + * `reinstall`: Removes and then reinstalls the specified custom nodes. + * `uninstall`: Uninstalls the specified custom nodes. + * `update`: Updates the specified custom nodes. + * `disable`: Disables the specified custom nodes. + * `enable`: Enables the specified custom nodes. + * `fix`: Attempts to fix dependencies for the specified custom nodes. + +### 4. Snapshot Management +* `python cm-cli.py save-snapshot`: Saves the current snapshot. +* `python cm-cli.py restore-snapshot `: Restores to the specified snapshot. + * It is assumed that the snapshot files are located in ComfyUI-Manager/snapshots. + (An update is planned to allow files from other paths in the future.) + +### 5. CLI Only Mode + +You can set whether to use ComfyUI-Manager solely via CLI. + +`cli-only-mode [enable|disable]` + +* This mode can be used if you want to restrict the use of ComfyUI-Manager through the GUI for security or policy reasons. + * When CLI only mode is enabled, ComfyUI-Manager is loaded in a very restricted state, the internal web API is disabled, and the Manager button is not displayed in the main menu. + +### 6. Dependency Restoration + +`restore-dependencies` + +* This command can be used if custom nodes are installed under the `ComfyUI/custom_nodes` path but their dependencies are not installed. +* It is useful when starting a new cloud instance, like colab, where dependencies need to be reinstalled and installation scripts re-executed. +* It can also be utilized if ComfyUI is reinstalled and only the custom_nodes path has been backed up and restored. + +### 7. Clear + +In the GUI, installations, updates, or snapshot restorations are scheduled to execute the next time ComfyUI is launched. The `clear` command clears this scheduled state, ensuring no pre-execution actions are applied. \ No newline at end of file diff --git a/docs/ko/cm-cli.md b/docs/ko/cm-cli.md new file mode 100644 index 00000000..71f4404d --- /dev/null +++ b/docs/ko/cm-cli.md @@ -0,0 +1,145 @@ +# `cm-cli`: ComfyUI-Manager CLI + +`cm-cli` 는 ComfyUI를 실행시키지 않고 command line에서 ComfyUI-Manager의 여러가지 기능을 사용할 수 있도록 도와주는 도구입니다. + + +``` +-= ComfyUI-Manager CLI (V2.21.1) =- + +python cm-cli.py [OPTIONS] + +OPTIONS: + [install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel ] ?[--mode [remote|local|cache]] + [update|disable|enable|fix] all ?[--channel ] ?[--mode [remote|local|cache]] + [simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel ] ?[--mode [remote|local|cache]] + save-snapshot + restore-snapshot + cli-only-mode [enable|disable] + restore-dependencies + clear + +``` + +## How To Use? +* `python cm-cli.py` 를 통해서 실행 시킬 수 있습니다. +* 예를 들어 custom node를 모두 업데이트 하고 싶다면 + * ComfyUI-Manager경로 에서 `python cm-cli.py update all` 를 command를 실행할 수 있습니다. + * ComfyUI 경로에서 실행한다면, `python custom_nodes/ComfyUI-Manager/cm-cli.py update all` 와 같이 cm-cli.py 의 경로를 지정할 수도 있습니다. + +## Prerequisite +* ComfyUI 를 실행하는 python과 동일한 python 환경에서 실행해야 합니다. + * venv를 사용할 경우 해당 venv를 activate 한 상태에서 실행해야 합니다. + * portable 버전을 사용할 경우 run_nvidia_gpu.bat 파일이 있는 경로인 경우, 다음과 같은 방식으로 코맨드를 실행해야 합니다. + `.\python_embeded\python.exe ComfyUI\custom_nodes\ComfyUI-Manager\cm-cli.py update all` +* ComfyUI 의 경로는 COMFYUI_PATH 환경 변수로 설정할 수 있습니다. 만약 생략할 경우 다음과 같은 경고 메시지가 나타나며, ComfyUI-Manager가 설치된 경로를 기준으로 상대 경로로 설정됩니다. + ``` + WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path. + ``` + +## Features + +### 1. --channel, --mode +* 정보 보기 기능과 커스텀 노드 관리 기능의 경우는 --channel과 --mode를 통해 정보 DB를 설정할 수 있습니다. +* 예들 들어 `python cm-cli.py update all --channel recent --mode remote`와 같은 command를 실행할 경우, 현재 ComfyUI-Manager repo에 내장된 로컬의 정보가 아닌 remote의 최신 정보를 기준으로 동작하며, recent channel에 있는 목록을 대상으로만 동작합니다. +* --channel, --mode 는 `simple-show, show, install, uninstall, update, disable, enable, fix` command에서만 사용 가능합니다. + +### 2. 관리 정보 보기 + +`[simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel ] ?[--mode [remote|local|cache]]` + + +* `[show|simple-show]` - `show`는 상세하게 정보를 보여주며, `simple-show`는 간단하게 정보를 보여줍니다. + + +`python cm-cli.py show installed` 와 같은 코맨드를 실행하면 설치된 커스텀 노드의 정보를 상세하게 보여줍니다. +``` +-= ComfyUI-Manager CLI (V2.21.1) =- + +FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json +[ ENABLED ] ComfyUI-Manager (author: Dr.Lt.Data) +[ ENABLED ] ComfyUI-Impact-Pack (author: Dr.Lt.Data) +[ ENABLED ] ComfyUI-Inspire-Pack (author: Dr.Lt.Data) +[ ENABLED ] ComfyUI_experiments (author: comfyanonymous) +[ ENABLED ] ComfyUI-SAI_API (author: Stability-AI) +[ ENABLED ] stability-ComfyUI-nodes (author: Stability-AI) +[ ENABLED ] comfyui_controlnet_aux (author: Fannovel16) +[ ENABLED ] ComfyUI-Frame-Interpolation (author: Fannovel16) +[ DISABLED ] ComfyUI-Loopchain (author: Fannovel16) +``` + +`python cm-cli.py simple-show installed` 와 같은 코맨드를 이용해서 설치된 커스텀 노드의 정보를 간단하게 보여줍니다. + +``` +-= ComfyUI-Manager CLI (V2.21.1) =- + +FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json +ComfyUI-Manager +ComfyUI-Impact-Pack +ComfyUI-Inspire-Pack +ComfyUI_experiments +ComfyUI-SAI_API +stability-ComfyUI-nodes +comfyui_controlnet_aux +ComfyUI-Frame-Interpolation +ComfyUI-Loopchain +``` + +* `[installed|enabled|not-installed|disabled|all|snapshot|snapshot-list]` + * `enabled`, `disabled`: 설치된 커스텀 노드들 중 enable 되었거나, disable된 노드들을 보여줍니다. + * `installed`: enable, disable 여부와 상관없이 설치된 모든 노드를 보여줍니다 + * `not-installed`: 설치되지 않은 커스텀 노드의 목록을 보여줍니다. + * `all`: 모든 커스텀 노드의 목록을 보여줍니다. + * `snapshot`: 현재 설치된 커스텀 노드의 snapshot 정보를 보여줍니다. `show`롤 통해서 볼 경우는 json 출력 형태로 보여주며, `simple-show`를 통해서 볼 경우는 간단하게, 커밋 해시와 함께 보여줍니다. + * `snapshot-list`: ComfyUI-Manager/snapshots 에 저장된 snapshot 파일의 목록을 보여줍니다. + +### 3. 커스텀 노드 관리 하기 + +`[install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel ] ?[--mode [remote|local|cache]]` + +* `python cm-cli.py install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack ComfyUI_experiments` 와 같이 커스텀 노드의 이름을 나열해서 관리 기능을 적용할 수 있습니다. +* 커스텀 노드의 이름은 `show`를 했을 때 보여주는 이름이며, git repository의 이름입니다. +(추후 nickname 을 사용가능하돌고 업데이트 할 예정입니다.) + +`[update|disable|enable|fix] all ?[--channel ] ?[--mode [remote|local|cache]]` + +* `update, disable, enable, fix` 기능은 all 로 지정 가능합니다. + +* 세부 동작 + * `install`: 지정된 커스텀 노드들을 설치합니다 + * `reinstall`: 지정된 커스텀 노드를 삭제하고 재설치 합니다. + * `uninstall`: 지정된 커스텀 노드들을 삭제합니다. + * `update`: 지정된 커스텀 노드들을 업데이트합니다. + * `disable`: 지정된 커스텀 노드들을 비활성화합니다. + * `enable`: 지정된 커스텀 노드들을 활성화합니다. + * `fix`: 지정된 커스텀 노드의 의존성을 고치기 위한 시도를 합니다. + + +### 4. 스냅샷 관리 기능 +* `python cm-cli.py save-snapshot`: 현재의 snapshot을 저장합니다. +* `python cm-cli.py restore-snapshot `: 지정된 snapshot으로 복구합니다. + * snapshot 파일은 ComfyUI-Manager/snapshots 에 있다고 가정합니다. + (추후 다른 경로에 있는 파일을 허용 가능하도록 업데이트 예정입니다.) + + +### 5. CLI only mode + +ComfyUI-Manager를 CLI로만 사용할 것인지를 설정할 수 있습니다. + +`cli-only-mode [enable|disable]` + +* security 혹은 policy 의 이유로 GUI 를 통한 ComfyUI-Manager 사용을 제한하고 싶은 경우 이 모드를 사용할 수 있습니다. + * CLI only mode를 적용할 경우 ComfyUI-Manager 가 매우 제한된 상태로 로드되어, 내부적으로 제공하는 web API가 비활성화 되며, 메인 메뉴에서도 Manager 버튼이 표시되지 않습니다. + + +### 6. 의존성 설치 + +`restore-dependencies` + +* `ComfyUI/custom_nodes` 하위 경로에 커스텀 노드들이 설치되어 있긴 하지만, 의존성이 설치되지 않은 경우 사용할 수 있습니다. +* colab 과 같이 cloud instance를 새로 시작하는 경우 의존성 재설치 및 설치 스크립트가 재실행 되어야 하는 경우 사용합니다. +* ComfyUI을 재설치할 경우, custom_nodes 경로만 백업했다가 재설치 할 경우 활용 가능합니다. + + +### 7. clear + +GUI에서 install, update를 하거나 snapshot 을 restore하는 경우 예약을 통해서 다음번 ComfyUI를 실행할 경우 실행되는 구조입니다. `clear` 는 이런 예약 상태를 clear해서, 아무런 사전 실행이 적용되지 않도록 합니다. \ No newline at end of file diff --git a/extension-node-map.json b/extension-node-map.json index 5de49b21..459c2ded 100644 --- a/extension-node-map.json +++ b/extension-node-map.json @@ -126,7 +126,11 @@ "GPT4VCaptioner", "Image Load with Metadata", "SAMIN String Attribute Selector", + "SANMIN ChineseToCharacter", "SANMIN ClothingWildcards", + "SANMIN ConvertToEnglish", + "SANMIN LoadPathImagesPreview", + "SANMIN SanmiSaveImageToLocal", "SANMIN SimpleWildcards", "Samin Counter", "Samin Load Image Batch" @@ -186,16 +190,61 @@ "title_aux": "ComfyUI-PixelOE" } ], + "https://github.com/AIFSH/ComfyUI-GPT_SoVITS": [ + [ + "GPT_SOVITS_FT", + "GPT_SOVITS_INFER", + "GPT_SOVITS_TTS", + "LoadAudio", + "LoadSRT", + "PreViewAudio" + ], + { + "title_aux": "ComfyUI-GPT_SoVITS" + } + ], + "https://github.com/AIFSH/ComfyUI-IP_LAP": [ + [ + "CombineAudioVideo", + "IP_LAP", + "LoadVideo", + "PreViewVideo" + ], + { + "title_aux": "ComfyUI-IP_LAP" + } + ], + "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH": [ + [ + "CombineAudioVideo", + "LoadVideo", + "MuseTalk", + "PreViewVideo" + ], + { + "title_aux": "ComfyUI-MuseTalk_FSH" + } + ], "https://github.com/AIFSH/ComfyUI-UVR5": [ [ "LoadAudio", - "PlayAudio", + "PreViewAudio", "UVR5_Node" ], { "title_aux": "ComfyUI-UVR5" } ], + "https://github.com/AIFSH/ComfyUI-WhisperX": [ + [ + "LoadAudio", + "PreViewSRT", + "WhisperX" + ], + { + "title_aux": "ComfyUI-WhisperX" + } + ], "https://github.com/AIGCTeam/ComfyUI_kkTranslator_nodes": [ [ "LoadMarianMTCheckPoint", @@ -260,6 +309,28 @@ "title_aux": "One Button Prompt" } ], + "https://github.com/ALatentPlace/ComfyUI_yanc": [ + [ + "> Clear Text", + "> Float to Int", + "> Int", + "> Int to Text", + "> Load Image", + "> Load Image From Folder", + "> Resolution by Aspect Ratio", + "> Rotate Image", + "> Save Image", + "> Scale Image to Side", + "> Text", + "> Text Combine", + "> Text Pick Random Line", + "> Text Random Weights", + "> Text Replace" + ], + { + "title_aux": "ComfyUI_yanc" + } + ], "https://github.com/AbdullahAlfaraj/Comfy-Photoshop-SD": [ [ "APS_LatentBatch", @@ -297,6 +368,8 @@ "ImageOverlap-badger", "ImageScaleToSide-badger", "IntToString-badger", + "IntToStringAdvanced-badger", + "LoadImageAdvanced-badger", "SegmentToMaskByPoint-badger", "SimpleBoolean-badger", "StringToFizz-badger", @@ -377,6 +450,14 @@ "title_aux": "Jovimetrix Composition Nodes" } ], + "https://github.com/AonekoSS/ComfyUI-SimpleCounter": [ + [ + "Simple Counter" + ], + { + "title_aux": "ComfyUI-SimpleCounter" + } + ], "https://github.com/AppleBotzz/ComfyUI_LLMVISION": [ [ "CLAUDE_CHAT", @@ -539,17 +620,24 @@ "title_aux": "ComfyUI Deploy" } ], - "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay": [ + "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools": [ [ - "Image Text Overlay" + "EndQueue", + "ImageTextOverlay", + "Loop", + "LoopEnd", + "LoopStart", + "PromptSchedule", + "PromptSelector" ], { - "title_aux": "Image Text Overlay Node for ComfyUI" + "title_aux": "ComfyUI-Book-Tools Nodes for ComfyUI" } ], "https://github.com/Big-Idea-Technology/ComfyUI_LLM_Node": [ [ "AdvOptions_Node", + "CodingOptionsNode", "LLM_Node", "Output_Node", "QuantizationConfig_Node" @@ -742,6 +830,7 @@ [ "GeometricCFGGuider", "ImageAssistedCFGGuider", + "MegaCFGGuider", "SamplerCLYB_4M_SDE_Momentumized", "SamplerCustomModelMixtureDuo", "SamplerCustomNoise", @@ -754,7 +843,8 @@ "SamplerSupreme", "SamplerTTM", "ScaledCFGGuider", - "SimpleExponentialScheduler" + "SimpleExponentialScheduler", + "WarmupDecayCFGGuider" ], { "title_aux": "ComfyUI Extra Samplers" @@ -770,6 +860,7 @@ ], "https://github.com/CosmicLaca/ComfyUI_Primere_Nodes": [ [ + "PrimereAestheticCKPTScorer", "PrimereAnyDetailer", "PrimereAnyOutput", "PrimereCKPT", @@ -843,7 +934,15 @@ "description": "If you want to draw two different characters together without blending their features, so you could try to check out this custom node.", "nickname": "Danand", "title": "Comfy Couple", - "title_aux": "ComfyUI-ComfyCouple" + "title_aux": "Comfy Couple" + } + ], + "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config": [ + [ + "CheckpointAutomaticConfig" + ], + { + "title_aux": "ComfyUI Checkpoint Automatic Config" } ], "https://github.com/Derfuu/Derfuu_ComfyUI_ModdedNodes": [ @@ -851,42 +950,32 @@ "Absolute value", "Ceil", "Conditioning area scale by ratio", - "ConditioningSetArea with tuples", "Cosines", "Divide", "Float", - "Float debug print", "Floor", "Get image size", "Get latent size", "Image scale by ratio", "Image scale to side", - "Int debug print", "Int to float", - "Int to tuple", "Integer", "Latent Scale by ratio", "Latent Scale to side", - "LatentComposite with tuples", "Logic node", "Multiply", "Power", "Random", "Sinus", "Square root", - "String debug print", + "String Concatenate", + "String Replace", "Subtract", "Sum", "Tangent", "Text", "Text box", - "To text (Debug)", - "Tuple", - "Tuple debug print", - "Tuple multiply", - "Tuple swap", - "Tuple to floats", - "Tuple to ints" + "To text (Debug)" ], { "title_aux": "Derfuu_ComfyUI_ModdedNodes" @@ -955,6 +1044,16 @@ "title_aux": "ComfyUI-post-processing-nodes" } ], + "https://github.com/ExponentialML/ComfyUI_ELLA": [ + [ + "ELLATextEncode", + "GetSigma", + "LoadElla" + ], + { + "title_aux": "ComfyUI_ELLA" + } + ], "https://github.com/ExponentialML/ComfyUI_ModelScopeT2V": [ [ "ModelScopeT2VLoader" @@ -983,8 +1082,11 @@ "https://github.com/Extraltodeus/ComfyUI-AutomaticCFG": [ [ "Automatic CFG", - "Automatic CFG - Advanced settings", - "Automatic CFG - Negative" + "Automatic CFG - Advanced", + "Automatic CFG - Fastest", + "Automatic CFG - Negative", + "Automatic CFG - Post rescale only", + "SAG delayed activation" ], { "title_aux": "ComfyUI-AutomaticCFG" @@ -1026,6 +1128,7 @@ "Merge sigmas by average", "Merge sigmas gradually", "Multiply sigmas", + "Output min/max sigmas", "Split and concatenate sigmas", "The Golden Scheduler" ], @@ -1069,6 +1172,112 @@ "title_aux": "ComfyUI Loopchain" } ], + "https://github.com/Fannovel16/ComfyUI-MagickWand": [ + [ + "ImageMagick Adaptive Blur", + "ImageMagick Adaptive Resize", + "ImageMagick Adaptive Sharpen", + "ImageMagick Adaptive Threshold", + "ImageMagick Auto Gamma", + "ImageMagick Auto Level", + "ImageMagick Auto Orient", + "ImageMagick Auto Threshold", + "ImageMagick Blue Shift", + "ImageMagick Blur", + "ImageMagick Brightness Contrast", + "ImageMagick Canny", + "ImageMagick Charcoal", + "ImageMagick Chop", + "ImageMagick Clahe", + "ImageMagick Clamp", + "ImageMagick Coalesce", + "ImageMagick Color Decision List", + "ImageMagick Color Matrix", + "ImageMagick Combine", + "ImageMagick Concat", + "ImageMagick Contrast", + "ImageMagick Contrast Stretch", + "ImageMagick Crop", + "ImageMagick Cycle Color Map", + "ImageMagick Decipher", + "ImageMagick Despeckle", + "ImageMagick Distort", + "ImageMagick Edge", + "ImageMagick Emboss", + "ImageMagick Encipher", + "ImageMagick Enhance", + "ImageMagick Equalize", + "ImageMagick Evaluate", + "ImageMagick Extent", + "ImageMagick Flip", + "ImageMagick Flop", + "ImageMagick Forward Fourier Transform", + "ImageMagick Function", + "ImageMagick Gamma", + "ImageMagick Gaussian Blur", + "ImageMagick Hough Lines", + "ImageMagick Implode", + "ImageMagick Kmeans", + "ImageMagick Kuwahara", + "ImageMagick Level", + "ImageMagick Levelize", + "ImageMagick Linear Stretch", + "ImageMagick Liquid Rescale", + "ImageMagick Local Contrast", + "ImageMagick Magnify", + "ImageMagick Mean Shift", + "ImageMagick Merge Layers", + "ImageMagick Mode", + "ImageMagick Modulate", + "ImageMagick Morphology", + "ImageMagick Motion Blur", + "ImageMagick Negate", + "ImageMagick Noise", + "ImageMagick Normalize", + "ImageMagick Oil Paint", + "ImageMagick Ordered Dither", + "ImageMagick Polynomial", + "ImageMagick Posterize", + "ImageMagick Quantize", + "ImageMagick Random Threshold", + "ImageMagick Range Threshold", + "ImageMagick Resample", + "ImageMagick Resize", + "ImageMagick Roll", + "ImageMagick Rotational Blur", + "ImageMagick Sample", + "ImageMagick Scale", + "ImageMagick Selective Blur", + "ImageMagick Sepia Tone", + "ImageMagick Shade", + "ImageMagick Shadow", + "ImageMagick Sharpen", + "ImageMagick Shave", + "ImageMagick Sigmoidal Contrast", + "ImageMagick Sketch", + "ImageMagick Smush", + "ImageMagick Solarize", + "ImageMagick Splice", + "ImageMagick Spread", + "ImageMagick Statistic", + "ImageMagick Swirl", + "ImageMagick Threshold", + "ImageMagick Thumbnail", + "ImageMagick Transform", + "ImageMagick Transform Colorspace", + "ImageMagick Transparentize", + "ImageMagick Transpose", + "ImageMagick Transverse", + "ImageMagick Unsharp Mask", + "ImageMagick Vignette", + "ImageMagick Wave", + "ImageMagick Wavelet Denoise", + "ImageMagick White Balance" + ], + { + "title_aux": "ComfyUI-MagickWand" + } + ], "https://github.com/Fannovel16/ComfyUI-MotionDiff": [ [ "EmptyMotionData", @@ -1087,6 +1296,8 @@ "SMPLShapeParameters", "SaveSMPL", "SmplifyMotionData", + "SpectreFaceReconLoader", + "SpectreImg2SMPL", "mgpt_model_loader", "mgpt_t2m" ], @@ -1350,7 +1561,11 @@ [ "ReActorBuildFaceModel", "ReActorFaceSwap", + "ReActorFaceSwapOpt", + "ReActorImageDublicator", "ReActorLoadFaceModel", + "ReActorMaskHelper", + "ReActorOptions", "ReActorRestoreFace", "ReActorSaveFaceModel" ], @@ -1459,7 +1674,7 @@ "description": "Just some nodes that I wanted/needed, so I made them.", "nickname": "HNodes", "title": "Hiero-Nodes", - "title_aux": "ComfyUI-Hiero-Nodes" + "title_aux": "Hiero-Nodes" } ], "https://github.com/IDGallagher/ComfyUI-IG-Nodes": [ @@ -1496,6 +1711,34 @@ "title_aux": "ikhor-nodes" } ], + "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes": [ + [ + "MX_AlphaBlend", + "MX_Blend", + "MX_Blur", + "MX_Canny", + "MX_ChromaticAberration", + "MX_ColorCorrect", + "MX_ColorMatch", + "MX_ColorTint", + "MX_Glow", + "MX_HSVThresholdMask", + "MX_KuwaharaBlur(Cartoon)", + "MX_LUT", + "MX_LensBokeh", + "MX_LensOpticAxis", + "MX_LensZoomBurst", + "MX_Mosaic", + "MX_Noise", + "MX_Posterize", + "MX_SineWave", + "MX_Solarize", + "MX_Vignette" + ], + { + "title_aux": "ComfyUI-MX-post-processing-nodes" + } + ], "https://github.com/Inzaniak/comfyui-ranbooru": [ [ "LockSeed", @@ -1524,6 +1767,7 @@ ], "https://github.com/JPS-GER/ComfyUI_JPS-Nodes": [ [ + "CLIPTextEncode SDXL Plus (JPS)", "Conditioning Switch (JPS)", "ControlNet Switch (JPS)", "Crop Image Pipe (JPS)", @@ -1545,13 +1789,23 @@ "Get Image Size (JPS)", "IP Adapter Settings (JPS)", "IP Adapter Settings Pipe (JPS)", - "IP Adapter Single Settings (JPS)", - "IP Adapter Single Settings Pipe (JPS)", + "IP Adapter Tiled Settings (JPS)", + "IP Adapter Tiled Settings Pipe (JPS)", "IPA Switch (JPS)", + "Image Prepare Pipe (JPS)", + "Image Prepare Settings (JPS)", "Image Switch (JPS)", "ImageToImage Pipe (JPS)", "ImageToImage Settings (JPS)", "Images Masks MultiPipe (JPS)", + "InstantID Mask Prepare Pipe (JPS)", + "InstantID Mask Prepare Settings (JPS)", + "InstantID Pipe (JPS)", + "InstantID Pose Prepare Pipe (JPS)", + "InstantID Pose Prepare Settings (JPS)", + "InstantID Settings (JPS)", + "InstantID Source Prepare Pipe (JPS)", + "InstantID Source Prepare Settings (JPS)", "Integer Switch (JPS)", "Largest Int (JPS)", "Latent Switch (JPS)", @@ -1561,6 +1815,9 @@ "Multiply Float Float (JPS)", "Multiply Int Float (JPS)", "Multiply Int Int (JPS)", + "Prepare Image (JPS)", + "Prepare Image Plus (JPS)", + "Prepare Image Tiled IPA (JPS)", "Resolution Multiply (JPS)", "Revision Settings (JPS)", "Revision Settings Pipe (JPS)", @@ -1572,11 +1829,15 @@ "SDXL Prompt Styler (JPS)", "SDXL Recommended Resolution Calc (JPS)", "SDXL Resolutions (JPS)", + "SDXL Settings (JPS)", + "SDXL Settings Pipe (JPS)", "Sampler Scheduler Settings (JPS)", "Save Images Plus (JPS)", "Substract Int Int (JPS)", "Text Concatenate (JPS)", "Text Prompt (JPS)", + "Text Prompt Combo (JPS)", + "Time Seed (JPS)", "VAE Switch (JPS)" ], { @@ -1598,6 +1859,7 @@ "DiffusersPipeline", "DiffusersPrepareLatents", "DiffusersTextureInversionLoader", + "DiffusersXLPipeline", "GetAverageColorFromImage", "GetFilledColorImage" ], @@ -1611,6 +1873,7 @@ "JNodes_AnyToString", "JNodes_AppendReversedFrames", "JNodes_BooleanSelectorWithString", + "JNodes_BreakMediaInfo", "JNodes_CheckpointSelectorWithString", "JNodes_GetOutputDirectory", "JNodes_GetParameterFromList", @@ -1619,7 +1882,9 @@ "JNodes_ImageFormatSelector", "JNodes_ImageSizeSelector", "JNodes_LoadVideo", + "JNodes_LoadVisualMediaFromPath", "JNodes_LoraExtractor", + "JNodes_MediaInfoToString", "JNodes_OutVideoInfo", "JNodes_ParseDynamicPrompts", "JNodes_ParseParametersToGlobalList", @@ -1643,6 +1908,7 @@ "JNodes_TokenCounter", "JNodes_TrimAndStrip", "JNodes_UploadVideo", + "JNodes_UploadVisualMedia", "JNodes_VaeSelectorWithString" ], { @@ -1676,7 +1942,15 @@ "description": "A ComfyUI custom node that randomly selects a height and width pair from a list in a config file", "nickname": "Random Size", "title": "Random Size", - "title_aux": "ComfyUI-RandomSize" + "title_aux": "Random Size" + } + ], + "https://github.com/JettHu/ComfyUI_TGate": [ + [ + "TGateApply" + ], + { + "title_aux": "ComfyUI_TGate" } ], "https://github.com/Jordach/comfy-plasma": [ @@ -1778,8 +2052,14 @@ "ADE_AnimateDiffUnload", "ADE_ApplyAnimateDiffModel", "ADE_ApplyAnimateDiffModelSimple", + "ADE_ApplyAnimateDiffModelWithCameraCtrl", "ADE_ApplyAnimateLCMI2VModel", "ADE_BatchedContextOptions", + "ADE_CameraCtrlAnimateDiffKeyframe", + "ADE_CameraManualPoseAppend", + "ADE_CameraPoseAdvanced", + "ADE_CameraPoseBasic", + "ADE_CameraPoseCombo", "ADE_CustomCFG", "ADE_CustomCFGKeyframe", "ADE_EmptyLatentImageLarge", @@ -1787,7 +2067,9 @@ "ADE_IterationOptsDefault", "ADE_IterationOptsFreeInit", "ADE_LoadAnimateDiffModel", + "ADE_LoadAnimateDiffModelWithCameraCtrl", "ADE_LoadAnimateLCMI2VModel", + "ADE_LoadCameraPoses", "ADE_LoopedUniformContextOptions", "ADE_LoopedUniformViewOptions", "ADE_MaskedLoadLora", @@ -1797,6 +2079,8 @@ "ADE_NoiseLayerAddWeighted", "ADE_NoiseLayerReplace", "ADE_RawSigmaSchedule", + "ADE_ReplaceCameraParameters", + "ADE_ReplaceOriginalPoseAspectRatio", "ADE_SigmaSchedule", "ADE_SigmaScheduleSplitAndCombine", "ADE_SigmaScheduleWeightedAverage", @@ -1825,6 +2109,7 @@ "VHS_GetLatentCount", "VHS_GetMaskCount", "VHS_LoadAudio", + "VHS_LoadAudioUpload", "VHS_LoadImages", "VHS_LoadImagesPath", "VHS_LoadVideo", @@ -2146,8 +2431,10 @@ ], "https://github.com/MNeMoNiCuZ/ComfyUI-mnemic-nodes": [ [ - "Generate Negative Prompt_mne", - "Save Text File_mne" + "\u26d4 Generate Negative Prompt", + "\u2728 Groq LLM API", + "\ud83d\udcbe Save Text File With Path", + "\ud83d\uddbc\ufe0f Download Image from URL" ], { "title_aux": "ComfyUI-mnemic-nodes" @@ -2214,28 +2501,43 @@ ], "https://github.com/MokkaBoss1/ComfyUI_Mokkaboss1": [ [ + "AnimeCosplayDir", "AspectRatioCondition", + "Colors", "ConnectFloat", "ConnectImage", "ConnectInteger", + "ConnectLatent", "ConnectString", + "DirSelector", "DoubleClipTextEncode", + "EmbeddingLoader", + "FilmCharDir", "HashText", + "HueSatLum", + "ImageDimensions", + "ImageResizeLong", "IndoorBackgrounds", + "IndoorDir", + "IntEvaluate", "IntFloatDict", "IntStringDict", "LandscapeBackgrounds", - "NatureColours", + "LandscapeDir", + "MakeupStylesDir", "OptimalCrop", - "SDXLAspectRatioDec", - "UrbanColours", + "SDXLEmptyLatent", + "SaveWithMetaData", + "SimplePrompts", + "SpecificStylesDir", + "TimeStamp", + "TricolorComposition", "WorkflowSettings", "WrapText", "X_In_a_Dress", "X_In_a_Suit", "X_In_a_Suit)", - "ZoomCrop", - "seveninabox" + "ZoomCrop" ], { "title_aux": "Node Pack mostly for manipulating strings and integers" @@ -2328,7 +2630,7 @@ "nickname": "Harronode", "nodename_pattern": "Harronode", "title": "Harrlogos Prompt Builder Node", - "title_aux": "Harronode" + "title_aux": "Harrlogos Prompt Builder Node" } ], "https://github.com/Nourepide/ComfyUI-Allor": [ @@ -2551,6 +2853,7 @@ "CyclistTimerStop", "CyclistTypeCast", "Interrupt", + "LoopManager", "MemorizeConditioning", "MemorizeFloat", "MemorizeInt", @@ -3083,6 +3386,22 @@ "title_aux": "ComfyUI_Mexx_Styler" } ], + "https://github.com/Sorcerio/MBM-Music-Visualizer": [ + [ + "id", + "mbmAudioFeatureCalculator", + "mbmAudioLoader", + "mbmImageConcat", + "mbmPromptSequenceBuilder", + "mbmPromptSequenceBuilderAdv", + "mbmPromptSequenceInterpolator", + "mbmPromptSequenceLoader", + "mbmPromptSequenceRenderer" + ], + { + "title_aux": "MBM's Music Visualizer" + } + ], "https://github.com/SpaceKendo/ComfyUI-svd_txt2vid": [ [ "SVD_txt2vid_ConditioningwithLatent" @@ -3091,6 +3410,20 @@ "title_aux": "Text to video for Stable Video Diffusion in ComfyUI" } ], + "https://github.com/Stability-AI/ComfyUI-SAI_API": [ + [ + "Stability Creative Upscale", + "Stability Image Core", + "Stability Inpainting", + "Stability Outpainting", + "Stability Remove Background", + "Stability SD3", + "Stability Search and Replace" + ], + { + "title_aux": "Stability API nodes for ComfyUI" + } + ], "https://github.com/Stability-AI/stability-ComfyUI-nodes": [ [ "ColorBlend", @@ -3364,7 +3697,7 @@ "description": "175 custom nodes for artists, designers and animators.", "nickname": "Comfyroll Studio", "title": "Comfyroll Studio", - "title_aux": "ComfyUI_Comfyroll_CustomNodes" + "title_aux": "Comfyroll Studio" } ], "https://github.com/Sxela/ComfyWarp": [ @@ -3451,8 +3784,12 @@ ], "https://github.com/TRI3D-LC/tri3d-comfyui-nodes": [ [ + "get_histogram_limits", "main_scaled_paste", + "simple_rescale_histogram", "tri3d-HistogramEqualization", + "tri3d-LAB_2_RGB", + "tri3d-RGB_2_LAB", "tri3d-adjust-neck", "tri3d-atr-parse", "tri3d-atr-parse-batch", @@ -3466,6 +3803,9 @@ "tri3d-face-recognise", "tri3d-float-to-image", "tri3d-fuzzification", + "tri3d-get_histogram_limits", + "tri3d-get_mean_and_standard_deviation", + "tri3d-get_threshold_for_bg_swap", "tri3d-image-mask-2-box", "tri3d-image-mask-box-2-image", "tri3d-interaction-canny", @@ -3480,7 +3820,10 @@ "tri3d-recolor-mask-LAB_space", "tri3d-recolor-mask-LAB_space_manual", "tri3d-recolor-mask-RGB_space", + "tri3d-renormalize_array", "tri3d-scaled-paste", + "tri3d-simple_bg_swap", + "tri3d-simple_rescale_histogram", "tri3d-skin-feathered-padded-mask", "tri3d-swap-pixels" ], @@ -3533,6 +3876,21 @@ "title_aux": "ComfyS3" } ], + "https://github.com/TencentQQGYLab/ComfyUI-ELLA": [ + [ + "ConcatConditionEllaEmbeds", + "ConditionToEllaEmbeds", + "ELLALoader", + "EllaAdvancedApply", + "EllaApply", + "EllaCombineEmbeds", + "T5TextEncode #ELLA", + "T5TextEncoderLoader #ELLA" + ], + { + "title_aux": "ComfyUI-ELLA" + } + ], "https://github.com/TheBarret/ZSuite": [ [ "ZSuite: Prompter", @@ -3676,6 +4034,16 @@ "title_aux": "select_folder_path_easy" } ], + "https://github.com/VAST-AI-Research/ComfyUI-Tripo": [ + [ + "TripoAPIImageToMeshNode", + "TripoAPITextToMeshNode", + "TripoGLBViewer" + ], + { + "title_aux": "Tripo for ComfyUI" + } + ], "https://github.com/WASasquatch/ASTERR": [ [ "ASTERR", @@ -3975,6 +4343,18 @@ "title_aux": "WebDev9000-Nodes" } ], + "https://github.com/Wicloz/ComfyUI-Simply-Nodes": [ + [ + "WF_ConditionalLoraLoader", + "WF_MultilineText", + "WF_RandomStyle", + "WF_ResolutionSDXL", + "WF_TextFlow" + ], + { + "title_aux": "ComfyUI-Simply-Nodes" + } + ], "https://github.com/XmYx/deforum-comfy-nodes": [ [ "DeforumAddNoiseNode", @@ -4137,12 +4517,16 @@ [ "ConcatText_Zho", "DisplayText_Zho", + "Gemini_15P_API_S_Advance_Zho", + "Gemini_15P_API_S_Chat_Advance_Zho", "Gemini_API_Chat_Zho", "Gemini_API_S_Chat_Zho", "Gemini_API_S_Vsion_ImgURL_Zho", "Gemini_API_S_Zho", "Gemini_API_Vsion_ImgURL_Zho", - "Gemini_API_Zho" + "Gemini_API_Zho", + "Gemini_FileUpload_API_S_Zho", + "Gemini_File_API_S_Zho" ], { "title_aux": "ComfyUI-Gemini" @@ -4289,14 +4673,16 @@ "title_aux": "ComfyUI-AudioScheduler" } ], - "https://github.com/abdozmantar/ComfyUI-InstaSwap": [ + "https://github.com/aburahamu/ComfyUI-RequestsPoster": [ [ - "InstaSwapFaceSwap", - "InstaSwapLoadFaceModel", - "InstaSwapSaveFaceModel" + "GetImageFromSD3byI2I", + "GetImageFromSD3byT2I", + "PostImage2Discord", + "PostImage2X", + "PostText" ], { - "title_aux": "InstaSwap Face Swap Node for ComfyUI" + "title_aux": "ComfyUI-RequestPoster" } ], "https://github.com/abyz22/image_control": [ @@ -4630,6 +5016,7 @@ "PCPromptFromSchedule", "PCScheduleSettings", "PCSplitSampling", + "PCWrapGuider", "PromptControlSimple", "PromptToSchedule", "ScheduleToCond", @@ -4688,7 +5075,7 @@ "description": "Include nodes for sam + bpy operation, that allows workflow creations for generative 2d character rig.", "nickname": "Avatar Graph", "title": "Avatar Graph", - "title_aux": "avatar-graph-comfyui" + "title_aux": "Avatar Graph" } ], "https://github.com/azure-dragon-ai/ComfyUI-ClipScore-Nodes": [ @@ -4832,11 +5219,14 @@ ], "https://github.com/blepping/ComfyUI-bleh": [ [ + "BlehBlockOps", "BlehDeepShrink", "BlehDiscardPenultimateSigma", "BlehForceSeedSampler", "BlehHyperTile", "BlehInsaneChainSampler", + "BlehLatentOps", + "BlehLatentScaleBy", "BlehModelPatchConditional", "BlehRefinerAfter" ], @@ -4859,6 +5249,18 @@ "title_aux": "ComfyUI-sonar" } ], + "https://github.com/blueraincoatli/comfyUI_SillyNodes": [ + [ + "BooleanJumper|SillyNode", + "QueueSequence|SillyNode", + "Screenshots|SillyNode", + "dummyInput|SillyNode", + "dummyInput|blueraincoat" + ], + { + "title_aux": "comfyUI_SillyNodes" + } + ], "https://github.com/bmad4ever/comfyui_ab_samplercustom": [ [ "AB SamplerCustom (experimental)" @@ -5152,7 +5554,9 @@ "SamplerDPMPP_2M_SDE_SUN", "SamplerDPMPP_3M_SDE_SUN", "SamplerDPMPP_SDE_SUN", - "SamplerEulerAncestral_SUN" + "SamplerEulerAncestral_SUN", + "SamplersSUNoise", + "SamplersSUNoiseAdvanced" ], { "title_aux": "ComfyUI_SUNoise" @@ -5233,6 +5637,19 @@ "title_aux": "ComfyUI-AniPortrait" } ], + "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper": [ + [ + "CameraBasic", + "CameraCombine", + "CameraCtrlLoader", + "CameraCtrlRun", + "CameraJoin", + "CameraTrajectory" + ], + { + "title_aux": "ComfyUI-CameraCtrl-Wrapper" + } + ], "https://github.com/chaojie/ComfyUI-Champ": [ [ "ChampLoader", @@ -5297,6 +5714,15 @@ "title_aux": "ComfyUI-DynamiCrafter" } ], + "https://github.com/chaojie/ComfyUI-EasyAnimate": [ + [ + "EasyAnimateLoader", + "EasyAnimateRun" + ], + { + "title_aux": "ComfyUI-EasyAnimate" + } + ], "https://github.com/chaojie/ComfyUI-Gemma": [ [ "GemmaLoader", @@ -5326,6 +5752,19 @@ "title_aux": "ComfyUI-Img2Img-Turbo" } ], + "https://github.com/chaojie/ComfyUI-LaVIT": [ + [ + "VideoLaVITI2I", + "VideoLaVITI2V", + "VideoLaVITI2VLong", + "VideoLaVITLoader", + "VideoLaVITT2V", + "VideoLaVITT2VLong" + ], + { + "title_aux": "ComfyUI-LaVIT" + } + ], "https://github.com/chaojie/ComfyUI-LightGlue": [ [ "LightGlue Loader", @@ -5482,6 +5921,7 @@ ], "https://github.com/chaojie/ComfyUI-dust3r": [ [ + "CameraPoseVideo", "Dust3rLoader", "Dust3rRun" ], @@ -5491,6 +5931,9 @@ ], "https://github.com/chaojie/ComfyUI_StreamingT2V": [ [ + "LoadText_StreamingT2V", + "PromptTravelIndex", + "SaveText_StreamingT2V", "StreamingT2VLoaderAnimateDiff", "StreamingT2VLoaderAnimateDiffModel", "StreamingT2VLoaderEnhanceModel", @@ -5504,10 +5947,14 @@ "StreamingT2VRunI2V", "StreamingT2VRunLongStep", "StreamingT2VRunLongStepVidXTendPipeline", + "StreamingT2VRunLongStepVidXTendPipelineCustomRef", + "StreamingT2VRunLongStepVidXTendPipelineCustomRefOutExtendOnly", + "StreamingT2VRunLongStepVidXTendPipelinePromptTravel", "StreamingT2VRunShortStepAnimateDiff", "StreamingT2VRunShortStepModelscopeT2V", "StreamingT2VRunShortStepSVD", - "StreamingT2VRunT2V" + "StreamingT2VRunT2V", + "VHS_FILENAMES_STRING_StreamingT2V" ], { "title_aux": "ComfyUI_StreamingT2V" @@ -5515,11 +5962,9 @@ ], "https://github.com/chaosaiart/Chaosaiart-Nodes": [ [ - "chaosaiart_ADD_Prompt", - "chaosaiart_Any_Display", "chaosaiart_Any_Switch", "chaosaiart_Any_Switch_Big_Number", - "chaosaiart_Batch_Loader_Number_Override", + "chaosaiart_Any_Switch_small", "chaosaiart_CheckpointLoader", "chaosaiart_CheckpointPrompt", "chaosaiart_CheckpointPrompt2", @@ -5531,13 +5976,19 @@ "chaosaiart_Denoising_Switch", "chaosaiart_EmptyLatentImage", "chaosaiart_FramePromptCLIPEncode", - "chaosaiart_ImageHolder_loop", - "chaosaiart_KSampler", + "chaosaiart_Frame_Switch", "chaosaiart_KSampler1", "chaosaiart_KSampler2", "chaosaiart_KSampler3", "chaosaiart_KSampler4", "chaosaiart_KSampler5", + "chaosaiart_KSampler7", + "chaosaiart_KSampler_a1", + "chaosaiart_KSampler_a1a", + "chaosaiart_KSampler_a2", + "chaosaiart_KSampler_expert_0", + "chaosaiart_KSampler_expert_1", + "chaosaiart_Ksampler_attribut", "chaosaiart_Load_Image_Batch", "chaosaiart_Load_Image_Batch_2img", "chaosaiart_MainPromptCLIPEncode", @@ -5547,48 +5998,40 @@ "chaosaiart_Number_Switch", "chaosaiart_Prompt", "chaosaiart_Prompt_Frame", - "chaosaiart_Prompt_mixer", "chaosaiart_Prompt_mixer_byFrame", "chaosaiart_SaveImage", - "chaosaiart_ShowInput", - "chaosaiart_Show_Any", "chaosaiart_Show_Info", "chaosaiart_Simple_Prompt", "chaosaiart_Style_Node", "chaosaiart_TextCLIPEncode", "chaosaiart_TextCLIPEncode_lora", - "chaosaiart_TextCLIPEncode_simple", "chaosaiart_adjust_color", "chaosaiart_any_array2input_1Input", "chaosaiart_any_array2input_all_big", "chaosaiart_any_array2input_all_small", "chaosaiart_any_input2array_big", "chaosaiart_any_input2array_small", - "chaosaiart_cn_math", "chaosaiart_controlnet_weidgth", "chaosaiart_convert", + "chaosaiart_convert_Prompt", + "chaosaiart_forPreview", "chaosaiart_image_loop", + "chaosaiart_img2gif", "chaosaiart_img2video", - "chaosaiart_imgHolder", "chaosaiart_lora", "chaosaiart_lora_advanced", - "chaosaiart_main_Prompt", + "chaosaiart_merge_Folders", "chaosaiart_oneNode", "chaosaiart_reloadAny_Load", "chaosaiart_reloadAny_Save", "chaosaiart_reloadIMG_Load", - "chaosaiart_reloadIMG_Load2", "chaosaiart_reloadIMG_Save", "chaosaiart_reloadLatent_Load", - "chaosaiart_reloadLatent_Load2", "chaosaiart_reloadLatent_Save", "chaosaiart_restarter", "chaosaiart_restarter_advanced", - "chaosaiart_saveImagePrefix", - "chaosaiart_test", - "chaosaiart_test2", "chaosaiart_video2img1", - "chaosaiart_video2img2" + "chaosaiart_zoom_frame" ], { "title_aux": "Chaosaiart-Nodes" @@ -5745,6 +6188,16 @@ "title_aux": "ComfyUI-Chibi-Nodes" } ], + "https://github.com/choey/Comfy-Topaz": [ + [ + "TopazPhotoAI", + "TopazSharpenSettings", + "TopazUpscaleSettings" + ], + { + "title_aux": "Comfy-Topaz" + } + ], "https://github.com/chrisgoringe/cg-image-picker": [ [ "Preview Chooser", @@ -5889,6 +6342,8 @@ ], "https://github.com/comfyanonymous/ComfyUI": [ [ + "AddNoise", + "AlignYourStepsScheduler", "BasicGuider", "BasicScheduler", "CFGGuider", @@ -6000,6 +6455,8 @@ "Morphology", "PatchModelAddDownscale", "PerpNeg", + "PerpNegGuider", + "PerturbedAttentionGuidance", "PhotoMakerEncode", "PhotoMakerLoader", "PolyexponentialScheduler", @@ -6162,20 +6619,26 @@ "IPAdapterAdvanced", "IPAdapterBatch", "IPAdapterCombineEmbeds", + "IPAdapterCombineParams", "IPAdapterEmbeds", "IPAdapterEncoder", "IPAdapterFaceID", + "IPAdapterFromParams", "IPAdapterInsightFaceLoader", "IPAdapterLoadEmbeds", + "IPAdapterMS", "IPAdapterModelLoader", "IPAdapterNoise", + "IPAdapterRegionalConditioning", "IPAdapterSaveEmbeds", "IPAdapterStyleComposition", + "IPAdapterStyleCompositionBatch", "IPAdapterTiled", "IPAdapterTiledBatch", "IPAdapterUnifiedLoader", "IPAdapterUnifiedLoaderCommunity", "IPAdapterUnifiedLoaderFaceID", + "IPAdapterWeights", "PrepImageForClipVision" ], { @@ -6209,12 +6672,14 @@ [ "BatchCount+", "CLIPTextEncodeSDXL+", + "ConditioningCombineMultiple+", "ConsoleDebug+", "DebugTensorShape+", "DrawText+", "ExtractKeyframes+", "GetImageSize+", "ImageApplyLUT+", + "ImageBatchMultiple+", "ImageCASharpening+", "ImageCompositeFromMaskBatch+", "ImageCrop+", @@ -6237,7 +6702,10 @@ "MaskFlip+", "MaskFromBatch+", "MaskFromColor+", + "MaskFromRGBCMYBW+", + "MaskFromSegmentation+", "MaskPreview+", + "MaskSmooth+", "ModelCompile+", "NoiseFromImage~", "PixelOEPixelize+", @@ -6260,7 +6728,7 @@ "description": "Face Compare", "nickname": "Face Compare", "title": "Face Compare", - "title_aux": "Comfyui-FaceCompare" + "title_aux": "Face Compare" } ], "https://github.com/dagthomas/comfyui_dagthomas": [ @@ -6348,9 +6816,11 @@ [ "JDCN_AnyFileList", "JDCN_AnyFileListHelper", + "JDCN_AnyFileListRandom", "JDCN_AnyFileSelector", "JDCN_BatchImageLoadFromList", "JDCN_BatchLatentLoadFromDir", + "JDCN_BatchLatentLoadFromList", "JDCN_BatchSaveLatent", "JDCN_FileMover", "JDCN_ImageSaver", @@ -6359,6 +6829,7 @@ "JDCN_SeamlessExperience", "JDCN_SplitString", "JDCN_StringToList", + "JDCN_TXTFileSaver", "JDCN_VHSFileMover" ], { @@ -6423,7 +6894,7 @@ "description": "CLIP text encoder that does BREAK prompting like A1111", "nickname": "CLIP with BREAK", "title": "CLIP with BREAK syntax", - "title_aux": "comfyui-clip-with-break" + "title_aux": "CLIP with BREAK syntax" } ], "https://github.com/dfl/comfyui-tcd-scheduler": [ @@ -6638,6 +7109,16 @@ "title_aux": "primitive-types" } ], + "https://github.com/e7mac/ComfyUI-ShadertoyGL": [ + [ + "ColorChannelOffset", + "Shader", + "Shadertoy" + ], + { + "title_aux": "ComfyUI-ShadertoyGL" + } + ], "https://github.com/ealkanat/comfyui_easy_padding": [ [ "comfyui-easy-padding" @@ -6656,8 +7137,10 @@ "Eden_Float", "Eden_Int", "Eden_String", + "HistogramMatching", "IMG_blender", "IMG_padder", + "IMG_resolution_multiple_of", "IMG_scaler", "IMG_unpadder", "If ANY execute A else B", @@ -6785,6 +7268,7 @@ ], "https://github.com/filliptm/ComfyUI_Fill-Nodes": [ [ + "FL_Ascii", "FL_AudioConverter", "FL_AudioFrameCalculator", "FL_AudioPreview", @@ -6811,6 +7295,21 @@ "title_aux": "fcSuite" } ], + "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite": [ + [ + "StabilityAI Suite - Creative Upscale", + "StabilityAI Suite - Creative Upscale Recover File", + "StabilityAI Suite - Image Core + Style Preset", + "StabilityAI Suite - Inpainting", + "StabilityAI Suite - Outpainting", + "StabilityAI Suite - Remove Background", + "StabilityAI Suite - SD3", + "StabilityAI Suite - Search and Replace" + ], + { + "title_aux": "ComfyUI StabilityAI Suite" + } + ], "https://github.com/florestefano1975/comfyui-portrait-master": [ [ "PortraitMaster" @@ -6897,6 +7396,16 @@ "title_aux": "As_ComfyUI_CustomNodes" } ], + "https://github.com/forever22777/comfyui-self-guidance": [ + [ + "CLIPConditioning", + "CheckpointLoaderMixWithDiffusers", + "SelfGuidanceSampler" + ], + { + "title_aux": "Self-Guidance nodes" + } + ], "https://github.com/foxtrot-roger/comfyui-rf-nodes": [ [ "LogBool", @@ -6946,6 +7455,14 @@ "title_aux": "ComfyUI_Aniportrait" } ], + "https://github.com/frankchieng/ComfyUI_MagicClothing": [ + [ + "MagicClothing_Generate" + ], + { + "title_aux": "ComfyUI_MagicClothing" + } + ], "https://github.com/gemell1/ComfyUI_GMIC": [ [ "GmicCliWrapper", @@ -7045,6 +7562,7 @@ [ "GlifConsistencyDecoder", "GlifPatchConsistencyDecoderTiled", + "HFHubLoraLoader", "ImageToMultipleOf", "SDXLAspectRatio" ], @@ -7156,9 +7674,16 @@ ], "https://github.com/hay86/ComfyUI_AceNodes": [ [ + "ACE_AudioLoad", + "ACE_AudioPlay", + "ACE_AudioSave", "ACE_Float", + "ACE_ImageColorFix", "ACE_ImageConstrain", + "ACE_ImageLoadFromCloud", + "ACE_ImageQA", "ACE_ImageRemoveBackground", + "ACE_ImageSaveToCloud", "ACE_Integer", "ACE_Seed", "ACE_Text", @@ -7174,18 +7699,68 @@ "ACE_TextTranslate" ], { - "title_aux": "ComfyUI_AceNodes" + "title_aux": "ComfyUI AceNodes" + } + ], + "https://github.com/hay86/ComfyUI_DDColor": [ + [ + "D_DDColor" + ], + { + "title_aux": "ComfyUI DDColor" } ], "https://github.com/hay86/ComfyUI_Dreamtalk": [ [ - "D_DreamTalk", - "D_LoadAudio" + "D_DreamTalk" ], { "title_aux": "ComfyUI Dreamtalk" } ], + "https://github.com/hay86/ComfyUI_MiniCPM-V": [ + [ + "D_MiniCPM_VQA" + ], + { + "title_aux": "ComfyUI MiniCPM-V" + } + ], + "https://github.com/hay86/ComfyUI_OpenVoice": [ + [ + "D_OpenVoice_STS", + "D_OpenVoice_TTS" + ], + { + "title_aux": "ComfyUI OpenVoice" + } + ], + "https://github.com/heshengtao/comfyui_LLM_party": [ + [ + "LLM", + "LLM_local", + "check_web_tool", + "classify_function", + "classify_persona", + "custom_persona", + "ebd_tool", + "end_dialog", + "file_combine", + "file_combine_plus", + "google_tool", + "interpreter_tool", + "load_file", + "load_persona", + "start_dialog", + "time_tool", + "tool_combine", + "tool_combine_plus", + "weather_tool" + ], + { + "title_aux": "comfyui_LLM_party" + } + ], "https://github.com/hhhzzyang/Comfyui_Lama": [ [ "LamaApply", @@ -7319,11 +7894,18 @@ "title_aux": "ComfyUI-Lora-Auto-Trigger-Words" } ], + "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode": [ + [ + "IF_WhisperSpeech" + ], + { + "title_aux": "ComfyUI-IF_AI_WishperSpeechNode" + } + ], "https://github.com/if-ai/ComfyUI-IF_AI_tools": [ [ + "IF_ChatPrompt", "IF_DisplayText", - "IF_HFDownload", - "IF_HFDownloadNode", "IF_ImagePrompt", "IF_PromptMkr", "IF_SaveText", @@ -7401,7 +7983,7 @@ "description": "This extension offers various audio generation tools", "nickname": "Audiotools", "title": "Jags_Audiotools", - "title_aux": "ComfyUI_Jags_Audiotools" + "title_aux": "Jags_Audiotools" } ], "https://github.com/jags111/ComfyUI_Jags_VectorMagic": [ @@ -7422,7 +8004,7 @@ "description": "This extension offers various vector manipulation and generation tools", "nickname": "Jags_VectorMagic", "title": "Jags_VectorMagic", - "title_aux": "ComfyUI_Jags_VectorMagic" + "title_aux": "Jags_VectorMagic" } ], "https://github.com/jags111/efficiency-nodes-comfyui": [ @@ -7562,6 +8144,15 @@ "title_aux": "ComfyUI-JaRue" } ], + "https://github.com/jtydhr88/ComfyUI-InstantMesh": [ + [ + "InstantMeshLoader", + "InstantMeshRun" + ], + { + "title_aux": "ComfyUI-InstantMesh" + } + ], "https://github.com/ka-puna/comfyui-yanc": [ [ "YANC.ConcatStrings", @@ -7602,6 +8193,60 @@ "title_aux": "ComfyUI_demucus" } ], + "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit": [ + [ + "SDT_AudioProperty", + "SDT_ConcatAudio", + "SDT_CutAudio", + "SDT_DemucsApply", + "SDT_DemucsLoader", + "SDT_FasterWhisperListSegments", + "SDT_FasterWhisperLoader", + "SDT_FasterWhisperSegmentProperty", + "SDT_FasterWhisperTextFromSegments", + "SDT_FasterWhisperTranscribe", + "SDT_GriffinLim", + "SDT_JoinAudio", + "SDT_LFCC", + "SDT_LoadAudio", + "SDT_LoadAudios", + "SDT_MFCC", + "SDT_MakeSilenceAudio", + "SDT_MelSpectrogram", + "SDT_NemoAsrListSegments", + "SDT_NemoAsrListSubwords", + "SDT_NemoAsrLoader", + "SDT_NemoAsrSegmentProperty", + "SDT_NemoAsrSubwordProperty", + "SDT_NemoAsrTranscribe", + "SDT_NueAsrLoader", + "SDT_NueAsrTranscribe", + "SDT_PlayAudio", + "SDT_PlotMelFilterBank", + "SDT_PlotPitch", + "SDT_PlotSpecgram", + "SDT_PlotSpectrogram", + "SDT_PlotWaveForm", + "SDT_ResampleAudio", + "SDT_SaveAudio", + "SDT_SaveAudioWithSequentialNumbering", + "SDT_SilenceAudio", + "SDT_SileroVADApply", + "SDT_SileroVADCollectChunks", + "SDT_SileroVADListTimestamps", + "SDT_SileroVADLoader", + "SDT_SileroVADTimestampProperty", + "SDT_Spectrogram", + "SDT_SpeechMOSLoader", + "SDT_SpeechMOSScore", + "SDT_SplitAudio", + "SDT_TrimAudio", + "SDT_TrimAudioBySample" + ], + { + "title_aux": "ComfyUI-speech-dataset-toolkit" + } + ], "https://github.com/kale4eat/ComfyUI-string-util": [ [ "string_util_Str", @@ -7640,6 +8285,15 @@ "title_aux": "ComfyUI-text-file-util" } ], + "https://github.com/kealiu/ComfyUI-S3-Tools": [ + [ + "Load Image From S3", + "Save Image To S3" + ], + { + "title_aux": "ComfyUI Load and Save file to S3" + } + ], "https://github.com/kenjiqq/qq-nodes-comfyui": [ [ "Any List", @@ -7688,6 +8342,27 @@ "title_aux": "Animatediff MotionLoRA Trainer" } ], + "https://github.com/kijai/ComfyUI-APISR-KJ": [ + [ + "APISR_upscale" + ], + { + "title_aux": "ComfyUI-APISR" + } + ], + "https://github.com/kijai/ComfyUI-BrushNet-Wrapper": [ + [ + "brushnet_ella_loader", + "brushnet_ipadapter_matteo", + "brushnet_model_loader", + "brushnet_sampler", + "brushnet_sampler_ella", + "powerpaint_brushnet_sampler" + ], + { + "title_aux": "ComfyUI-BrushNet-Wrapper" + } + ], "https://github.com/kijai/ComfyUI-CCSR": [ [ "CCSR_Model_Select", @@ -7724,6 +8399,16 @@ "title_aux": "ComfyUI-DynamiCrafterWrapper" } ], + "https://github.com/kijai/ComfyUI-ELLA-wrapper": [ + [ + "ella_model_loader", + "ella_sampler", + "ella_t5_embeds" + ], + { + "title_aux": "ComfyUI-ELLA-wrapper" + } + ], "https://github.com/kijai/ComfyUI-Geowizard": [ [ "geowizard_model_loader", @@ -7762,11 +8447,13 @@ "CreateTextMask", "CreateVoronoiMask", "CrossFadeImages", + "CustomSigmas", "DummyLatentOut", "EmptyLatentImagePresets", "FilterZeroMasksAndCorrespondingImages", "FlipSigmasAdjusted", "FloatConstant", + "FloatToMask", "GLIGENTextBoxApplyBatch", "GenerateNoise", "GetImageRangeFromBatch", @@ -7774,6 +8461,7 @@ "GetLatentsFromBatchIndexed", "GrowMaskWithBlur", "INTConstant", + "ImageAndMaskPreview", "ImageBatchRepeatInterleaving", "ImageBatchTestPattern", "ImageConcanate", @@ -7781,13 +8469,16 @@ "ImageGridComposite2x2", "ImageGridComposite3x3", "ImageNormalize_Neg1_To_1", + "ImagePadForOutpaintMasked", "ImageTransformByNormalizedAmplitude", "ImageUpscaleWithModelBatched", "InjectNoiseToLatent", "InsertImageBatchByIndexes", + "InsertImagesToBatchIndexed", "Intrinsic_lora_sampling", "JoinStrings", "LoadResAdapterNormalization", + "MaskOrImageToWeight", "NormalizedAmplitudeToMask", "OffsetMask", "OffsetMaskByNormalizedAmplitude", @@ -7803,18 +8494,32 @@ "Sleep", "SomethingToString", "SoundReactive", + "SplineEditor", "SplitBboxes", + "StabilityAPI_SD3", "StableZero123_BatchSchedule", "StringConstant", "StringConstantMultiline", "Superprompt", "VRAM_Debug", + "WeightScheduleConvert", "WidgetToString" ], { "title_aux": "KJNodes for ComfyUI" } ], + "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper": [ + [ + "lavi_bridge_llama_encoder", + "lavi_bridge_t5_encoder", + "lavibridge_model_loader", + "lavibridge_sampler" + ], + { + "title_aux": "ComfyUI-LaVi-Bridge-Wrapper" + } + ], "https://github.com/kijai/ComfyUI-Marigold": [ [ "ColorizeDepthmap", @@ -7900,12 +8605,12 @@ "https://github.com/klinter007/klinter_nodes": [ [ "Filter", + "ListStringToFloatNode", "PresentString", + "PrintFloats", "SingleString", "SizeSelector", - "concat", - "concat_klinter", - "whitelist" + "concat" ], { "title_aux": "Klinter_nodes" @@ -7973,6 +8678,28 @@ "title_aux": "komojini-comfyui-nodes" } ], + "https://github.com/kunieone/ComfyUI_alkaid": [ + [ + "A_EmptyLatentImageLongside", + "A_Face3DSwapper", + "A_FaceCrop", + "A_FacePaste", + "A_GetImageSize", + "A_OpenPosePreprocessor", + "AdapterFace", + "AdapterFaceLoader", + "AdapterStyle", + "AdapterStyleLoader", + "AlkaidLoader", + "ApplyAdapter", + "ApplyControlNet_KPS", + "CombineAdapterPatch", + "KSamplerHires" + ], + { + "title_aux": "ComfyUI_alkaid" + } + ], "https://github.com/kwaroran/abg-comfyui": [ [ "Remove Image Background (abg)" @@ -8144,6 +8871,16 @@ "title_aux": "ComfyUI-InversedNoise" } ], + "https://github.com/logtd/ComfyUI-RAVE_ATTN": [ + [ + "ApplyRaveAttentionNode", + "AttentionOverrideSD15Node", + "AttentionOverrideSDXLNode" + ], + { + "title_aux": "ComfyUI-RAVE Attention" + } + ], "https://github.com/logtd/ComfyUI-RefSampling": [ [ "ApplyRefContentNode", @@ -8176,6 +8913,7 @@ "https://github.com/longgui0318/comfyui-mask-util": [ [ "Image Adaptive Crop M&R", + "Image Adaptive Crop With Mask", "Image Change Device", "Image Resolution Adaptive With X", "Image Resolution Limit With 8K", @@ -8189,7 +8927,13 @@ ], "https://github.com/longgui0318/comfyui-oms-diffusion": [ [ - "Additional Features With Attention" + "Add Magic Clothing Attention", + "Change Pixel Value Normalization", + "InjectTensorHashLog", + "LOAD OMS", + "Load Magic Clothing Model", + "RUN OMS", + "VAE Mode Choose" ], { "title_aux": "comfyui-oms-diffusion" @@ -8524,7 +9268,7 @@ "description": "Various QoL improvements like prompt tweaking, variable assignment, image preview, fuzzy search, error reporting, organizing and node navigation.", "nickname": "\ud83d\udfe1 mape's helpers", "title": "mape's helpers", - "title_aux": "mape's ComfyUI Helpers" + "title_aux": "mape's helpers" } ], "https://github.com/maracman/ComfyUI-SubjectStyle-CSV": [ @@ -8766,6 +9510,7 @@ "IntToFloatMultiplication", "LogicNot", "NumeralToString", + "OneFloat", "PngColorMasksToMaskList", "PngColorMasksToRGB", "PngColorMasksToString", @@ -8791,15 +9536,6 @@ "title_aux": "ComfyUI_Mira" } ], - "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor": [ - [ - "LaMaPreprocessor", - "lamaPreprocessor" - ], - { - "title_aux": "LaMa Preprocessor [WIP]" - } - ], "https://github.com/modusCell/ComfyUI-dimension-node-modusCell": [ [ "DimensionProviderFree modusCell", @@ -9000,6 +9736,21 @@ "title_aux": "ntdviet/comfyui-ext" } ], + "https://github.com/nullquant/ComfyUI-BrushNet": [ + [ + "BlendInpaint", + "BrushNetInpaint", + "BrushNetLoader", + "BrushNetPipeline" + ], + { + "author": "nullquant", + "description": "This repository contains an custom nodes for inpaint using BrushNet and PowerPaint models", + "nickname": "BrushName nodes", + "title": "BrushNet", + "title_aux": "BrushNet" + } + ], "https://github.com/olduvai-jp/ComfyUI-HfLoader": [ [ "Lora Loader From HF" @@ -9115,6 +9866,14 @@ "title_aux": "Image Resize for ComfyUI" } ], + "https://github.com/pamparamm/sd-perturbed-attention": [ + [ + "PerturbedAttention" + ], + { + "title_aux": "Perturbed-Attention Guidance" + } + ], "https://github.com/pants007/comfy-pants": [ [ "CLIPTextEncodeAIO", @@ -9282,7 +10041,7 @@ "description": "ComfyUI node version of the SD Prompt Reader", "nickname": "SD Prompt Reader", "title": "SD Prompt Reader", - "title_aux": "comfyui-prompt-reader-node" + "title_aux": "SD Prompt Reader" } ], "https://github.com/redhottensors/ComfyUI-Prediction": [ @@ -9385,6 +10144,21 @@ "title_aux": "ComfyUI-Tara-LLM-Integration" } ], + "https://github.com/royceschultz/ComfyUI-TranscriptionTools": [ + [ + "TT-AudioSink", + "TT-ConvertVhsAudioToAudio", + "TT-LoadAudio", + "TT-LoadBatch", + "TT-LoadVideoAudio", + "TT-LoadWhisperModel", + "TT-WhisperTranscription", + "TT-WhisperTranscriptionBatch" + ], + { + "title_aux": "ComfyUI-TranscriptionTools" + } + ], "https://github.com/rui40000/RUI-Nodes": [ [ "ABCondition", @@ -9511,6 +10285,7 @@ "NewLayer", "NoiseImage", "OutlineMask", + "PreviewMask_", "PromptImage", "PromptSimplification", "PromptSlide", @@ -9751,6 +10526,40 @@ "title_aux": "kb-comfyui-nodes" } ], + "https://github.com/smthemex/ComfyUI_ChatGLM_API": [ + [ + "ZhipuaiApi_Txt", + "ZhipuaiApi_img" + ], + { + "title_aux": "ComfyUI_ChatGLM_API" + } + ], + "https://github.com/smthemex/ComfyUI_ParlerTTS": [ + [ + "ModelDownload", + "PromptToAudio" + ], + { + "title_aux": "ComfyUI_ParlerTTS" + } + ], + "https://github.com/smthemex/ComfyUI_Pic2Story": [ + [ + "Pic2Story" + ], + { + "title_aux": "ComfyUI_Pic2Story" + } + ], + "https://github.com/smthemex/ComfyUI_Pipeline_Tool": [ + [ + "Pipeline_Tool" + ], + { + "title_aux": "ComfyUI_Pipeline_Tool" + } + ], "https://github.com/space-nuko/ComfyUI-Disco-Diffusion": [ [ "DiscoDiffusion_DiscoDiffusion", @@ -9816,8 +10625,10 @@ "GuidedFilterAlpha", "ImageConstant", "ImageConstantHSV", + "InstructPixToPixConditioningAdvanced", "JitterImage", "Keyer", + "LatentNormalizeShuffle", "LatentStats", "NormalMapSimple", "OffsetLatentImage", @@ -9962,6 +10773,14 @@ "title_aux": "ComfyUI-sudo-latent-upscale" } ], + "https://github.com/sugarkwork/comfyui_tag_fillter": [ + [ + "TagFilter" + ], + { + "title_aux": "comfyui_tag_filter" + } + ], "https://github.com/syllebra/bilbox-comfyui": [ [ "BilboXLut", @@ -10148,6 +10967,27 @@ "title_aux": "ComfyUI_toyxyz_test_nodes" } ], + "https://github.com/traugdor/ComfyUI-quadMoons-nodes": [ + [ + "quadmoonCLIPTextEncode", + "quadmoonConvertBoolToString", + "quadmoonConvertFloatToString", + "quadmoonConvertIntToString", + "quadmoonConvertNormalizeHW", + "quadmoonConvertNumberToString", + "quadmoonINTConditionalOperation", + "quadmoonKSampler", + "quadmoonKSamplerAdvanced", + "quadmoonThebutton" + ], + { + "author": "quadmoon (https://github.com/traugdor)", + "description": "These are just some nodes I wanted and couldn't find where anyone else had made them yet.", + "nickname": "quadmoon's Nodes", + "title": "quadmoon's ComfyUI nodes", + "title_aux": "quadmoon's ComfyUI nodes" + } + ], "https://github.com/trojblue/trNodes": [ [ "JpgConvertNode", @@ -10219,6 +11059,22 @@ "title_aux": "Hakkun-ComfyUI-nodes" } ], + "https://github.com/turkyden/ComfyUI-Comic": [ + [ + "Image To Comic" + ], + { + "title_aux": "ComfyUI-Comic" + } + ], + "https://github.com/turkyden/ComfyUI-Sticker": [ + [ + "Image To Sticker" + ], + { + "title_aux": "ComfyUI-Sticker" + } + ], "https://github.com/tusharbhutt/Endless-Nodes": [ [ "ESS Aesthetic Scoring", @@ -10292,6 +11148,17 @@ "title_aux": "comfyui-webcam-node" } ], + "https://github.com/unwdef/unwdef-nodes-comfyui": [ + [ + "RandomTextFromMultiline", + "RandomizeLoras", + "RandomizeLorasStack", + "TextMultilineWithVariables" + ], + { + "title_aux": "unwdef-nodes" + } + ], "https://github.com/vanillacode314/SimpleWildcardsComfyUI": [ [ "SimpleConcat", @@ -10588,6 +11455,14 @@ "title_aux": "hd-nodes-comfyui" } ], + "https://github.com/xliry/ComfyUI_SendDiscord/raw/main/SendDiscord.py": [ + [ + "SendDiscord" + ], + { + "title_aux": "ComfyUI_SendDiscord" + } + ], "https://github.com/yffyhk/comfyui_auto_danbooru": [ [ "GetDanbooru", @@ -10622,6 +11497,8 @@ "easy cascadeKSampler", "easy cascadeLoader", "easy cleanGpuUsed", + "easy clearCacheAll", + "easy clearCacheKey", "easy comfyLoader", "easy compare", "easy controlnetLoader", @@ -10636,12 +11513,14 @@ "easy fullkSampler", "easy globalSeed", "easy hiresFix", + "easy humanParsing", "easy if", + "easy imageChooser", "easy imageInsetCrop", + "easy imageInterrogator", "easy imagePixelPerfect", "easy imageRatio", "easy imageRemBg", - "easy imageRemoveBG", "easy imageSave", "easy imageScaleDown", "easy imageScaleDownBy", @@ -10652,6 +11531,7 @@ "easy imageSplitList", "easy imageSwitch", "easy imageToMask", + "easy injectNoiseToLatent", "easy instantIDApply", "easy instantIDApplyADV", "easy int", @@ -10659,6 +11539,9 @@ "easy ipadapterApplyADV", "easy ipadapterApplyEmbeds", "easy ipadapterApplyEncoder", + "easy ipadapterApplyFromParams", + "easy ipadapterApplyRegional", + "easy ipadapterStyleComposition", "easy isSDXL", "easy joinImageBatch", "easy kSampler", @@ -10684,6 +11567,7 @@ "easy preSampling", "easy preSamplingAdvanced", "easy preSamplingCascade", + "easy preSamplingCustom", "easy preSamplingDynamicCFG", "easy preSamplingLayerDiffusion", "easy preSamplingLayerDiffusionADDTL", @@ -10701,6 +11585,7 @@ "easy showLoaderSettingsNames", "easy showSpentTime", "easy showTensorShape", + "easy stableDiffusion3API", "easy string", "easy stylesSelector", "easy sv3dLoader", @@ -10924,6 +11809,7 @@ [ "ConcatText", "ImageBatchOneOrMore", + "IntAndIntAddOffsetLiteral", "LoadImageWithSwitch", "ModifyTextGender" ], diff --git a/git_helper.py b/git_helper.py index dbe3271a..37d6dcc7 100644 --- a/git_helper.py +++ b/git_helper.py @@ -176,24 +176,32 @@ def checkout_custom_node_hash(git_custom_node_infos): if repo_name.endswith('.disabled'): repo_name = repo_name[:-9] - item = git_custom_node_infos[repo_name_to_url[repo_name]] - if item['disabled'] and is_disabled: - pass - elif item['disabled'] and not is_disabled: - # disable - print(f"DISABLE: {repo_name}") - new_path = fullpath + ".disabled" - os.rename(fullpath, new_path) - pass - elif not item['disabled'] and is_disabled: - # enable - print(f"ENABLE: {repo_name}") - new_path = fullpath[:-9] - os.rename(fullpath, new_path) - fullpath = new_path - need_checkout = True + if repo_name not in repo_name_to_url: + if not is_disabled: + # should be disabled + print(f"DISABLE: {repo_name}") + new_path = fullpath + ".disabled" + os.rename(fullpath, new_path) + need_checkout = False else: - need_checkout = True + item = git_custom_node_infos[repo_name_to_url[repo_name]] + if item['disabled'] and is_disabled: + pass + elif item['disabled'] and not is_disabled: + # disable + print(f"DISABLE: {repo_name}") + new_path = fullpath + ".disabled" + os.rename(fullpath, new_path) + + elif not item['disabled'] and is_disabled: + # enable + print(f"ENABLE: {repo_name}") + new_path = fullpath[:-9] + os.rename(fullpath, new_path) + fullpath = new_path + need_checkout = True + else: + need_checkout = True if need_checkout: repo = git.Repo(fullpath) @@ -202,6 +210,7 @@ def checkout_custom_node_hash(git_custom_node_infos): if commit_hash != item['hash']: print(f"CHECKOUT: {repo_name} [{item['hash']}]") repo.git.checkout(item['hash']) + except Exception: print(f"Failed to restore snapshots for the custom node '{path}'") diff --git a/github-stats.json b/github-stats.json index cd57e25c..93813c02 100644 --- a/github-stats.json +++ b/github-stats.json @@ -1,30 +1,30 @@ { "https://github.com/ltdrdata/ComfyUI-Manager": { - "stars": 3285, - "last_update": "2024-04-09 02:15:28" + "stars": 3506, + "last_update": "2024-04-22 14:21:42" }, "https://github.com/ltdrdata/ComfyUI-Impact-Pack": { - "stars": 1094, - "last_update": "2024-04-09 02:10:21" + "stars": 1153, + "last_update": "2024-04-22 15:59:47" }, "https://github.com/ltdrdata/ComfyUI-Inspire-Pack": { - "stars": 211, - "last_update": "2024-04-04 14:29:26" + "stars": 225, + "last_update": "2024-04-13 11:04:17" }, "https://github.com/comfyanonymous/ComfyUI_experiments": { - "stars": 119, + "stars": 121, "last_update": "2023-09-13 06:28:20" }, "https://github.com/Stability-AI/stability-ComfyUI-nodes": { - "stars": 162, + "stars": 166, "last_update": "2023-08-18 19:03:06" }, "https://github.com/Fannovel16/comfyui_controlnet_aux": { - "stars": 1150, + "stars": 1236, "last_update": "2024-04-05 13:07:00" }, "https://github.com/Fannovel16/ComfyUI-Frame-Interpolation": { - "stars": 253, + "stars": 273, "last_update": "2024-02-17 06:26:44" }, "https://github.com/Fannovel16/ComfyUI-Loopchain": { @@ -32,55 +32,55 @@ "last_update": "2023-12-15 14:25:35" }, "https://github.com/Fannovel16/ComfyUI-MotionDiff": { - "stars": 124, - "last_update": "2024-04-06 14:42:16" + "stars": 130, + "last_update": "2024-04-23 09:56:48" }, "https://github.com/Fannovel16/ComfyUI-Video-Matting": { - "stars": 109, + "stars": 114, "last_update": "2024-02-12 13:57:45" }, "https://github.com/BlenderNeko/ComfyUI_Cutoff": { - "stars": 288, + "stars": 298, "last_update": "2024-04-08 22:34:21" }, "https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb": { - "stars": 219, + "stars": 235, "last_update": "2024-04-08 22:18:59" }, "https://github.com/BlenderNeko/ComfyUI_Noise": { - "stars": 171, - "last_update": "2024-04-08 22:33:03" + "stars": 182, + "last_update": "2024-04-19 13:09:18" }, "https://github.com/BlenderNeko/ComfyUI_TiledKSampler": { - "stars": 242, + "stars": 249, "last_update": "2024-04-08 22:15:55" }, "https://github.com/BlenderNeko/ComfyUI_SeeCoder": { - "stars": 33, + "stars": 34, "last_update": "2023-09-11 10:09:22" }, "https://github.com/jags111/efficiency-nodes-comfyui": { - "stars": 506, - "last_update": "2024-04-05 19:13:30" + "stars": 559, + "last_update": "2024-04-11 15:08:50" }, "https://github.com/jags111/ComfyUI_Jags_VectorMagic": { "stars": 38, "last_update": "2024-02-03 04:00:30" }, "https://github.com/jags111/ComfyUI_Jags_Audiotools": { - "stars": 16, + "stars": 19, "last_update": "2023-12-27 16:47:20" }, "https://github.com/Derfuu/Derfuu_ComfyUI_ModdedNodes": { - "stars": 234, - "last_update": "2024-04-03 19:30:15" + "stars": 239, + "last_update": "2024-04-15 03:11:36" }, "https://github.com/paulo-coronado/comfy_clip_blip_node": { "stars": 25, "last_update": "2023-09-27 00:33:21" }, "https://github.com/WASasquatch/was-node-suite-comfyui": { - "stars": 774, + "stars": 796, "last_update": "2024-04-08 17:54:15" }, "https://github.com/WASasquatch/ComfyUI_Preset_Merger": { @@ -92,15 +92,15 @@ "last_update": "2023-10-01 03:36:57" }, "https://github.com/WASasquatch/PowerNoiseSuite": { - "stars": 45, + "stars": 46, "last_update": "2023-09-19 17:04:01" }, "https://github.com/WASasquatch/FreeU_Advanced": { - "stars": 87, + "stars": 88, "last_update": "2024-03-05 15:36:38" }, "https://github.com/WASasquatch/ASTERR": { - "stars": 7, + "stars": 8, "last_update": "2023-09-30 01:11:46" }, "https://github.com/WASasquatch/WAS_Extras": { @@ -108,11 +108,11 @@ "last_update": "2023-11-20 17:14:58" }, "https://github.com/get-salt-AI/SaltAI": { - "stars": 37, - "last_update": "2024-04-04 19:28:01" + "stars": 40, + "last_update": "2024-04-16 18:54:06" }, "https://github.com/omar92/ComfyUI-QualityOfLifeSuit_Omar92": { - "stars": 97, + "stars": 100, "last_update": "2024-02-13 05:05:31" }, "https://github.com/lilly1987/ComfyUI_node_Lilly": { @@ -124,15 +124,15 @@ "last_update": "2023-08-29 08:07:35" }, "https://github.com/EllangoK/ComfyUI-post-processing-nodes": { - "stars": 135, + "stars": 138, "last_update": "2024-02-07 01:59:01" }, "https://github.com/LEv145/images-grid-comfy-plugin": { - "stars": 108, + "stars": 110, "last_update": "2024-02-23 08:22:13" }, "https://github.com/diontimmer/ComfyUI-Vextra-Nodes": { - "stars": 54, + "stars": 56, "last_update": "2024-02-14 18:07:29" }, "https://github.com/CYBERLOOM-INC/ComfyUI-nodes-hnmr": { @@ -140,7 +140,7 @@ "last_update": "2024-01-01 20:01:25" }, "https://github.com/BadCafeCode/masquerade-nodes-comfyui": { - "stars": 250, + "stars": 258, "last_update": "2024-02-26 04:23:37" }, "https://github.com/guoyk93/yk-node-suite-comfyui": { @@ -148,7 +148,7 @@ "last_update": "2023-03-28 16:19:46" }, "https://github.com/Jcd1230/rembg-comfyui-node": { - "stars": 96, + "stars": 101, "last_update": "2023-04-03 00:12:22" }, "https://github.com/YinBailiang/MergeBlockWeighted_fo_ComfyUI": { @@ -164,19 +164,19 @@ "last_update": "2024-01-09 14:14:18" }, "https://github.com/city96/ComfyUI_NetDist": { - "stars": 175, + "stars": 181, "last_update": "2024-02-15 17:34:51" }, "https://github.com/city96/SD-Latent-Interposer": { - "stars": 140, + "stars": 145, "last_update": "2024-03-20 21:55:09" }, "https://github.com/city96/SD-Advanced-Noise": { - "stars": 15, + "stars": 16, "last_update": "2023-08-14 15:17:54" }, "https://github.com/city96/SD-Latent-Upscaler": { - "stars": 96, + "stars": 97, "last_update": "2023-11-27 00:26:14" }, "https://github.com/city96/ComfyUI_DiT": { @@ -184,19 +184,19 @@ "last_update": "2023-09-06 17:15:54" }, "https://github.com/city96/ComfyUI_ColorMod": { - "stars": 17, + "stars": 23, "last_update": "2024-04-09 03:35:11" }, "https://github.com/city96/ComfyUI_ExtraModels": { - "stars": 80, - "last_update": "2024-04-07 15:58:09" + "stars": 104, + "last_update": "2024-04-21 19:12:23" }, "https://github.com/Kaharos94/ComfyUI-Saveaswebp": { "stars": 27, "last_update": "2023-11-11 19:53:48" }, "https://github.com/SLAPaper/ComfyUI-Image-Selector": { - "stars": 44, + "stars": 46, "last_update": "2024-01-10 10:02:25" }, "https://github.com/flyingshutter/As_ComfyUI_CustomNodes": { @@ -208,35 +208,35 @@ "last_update": "2023-09-19 12:11:26" }, "https://github.com/Zuellni/ComfyUI-ExLlama": { - "stars": 79, - "last_update": "2024-04-08 01:03:56" + "stars": 83, + "last_update": "2024-04-22 16:30:33" }, "https://github.com/Zuellni/ComfyUI-PickScore-Nodes": { - "stars": 16, - "last_update": "2024-04-08 01:10:43" + "stars": 18, + "last_update": "2024-04-22 13:30:47" }, "https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet": { - "stars": 517, - "last_update": "2024-02-29 09:53:46" + "stars": 554, + "last_update": "2024-04-17 09:44:09" }, "https://github.com/pythongosssss/ComfyUI-WD14-Tagger": { - "stars": 281, + "stars": 310, "last_update": "2024-04-04 01:15:12" }, "https://github.com/pythongosssss/ComfyUI-Custom-Scripts": { - "stars": 1035, + "stars": 1096, "last_update": "2024-04-09 03:04:04" }, "https://github.com/strimmlarn/ComfyUI_Strimmlarns_aesthetic_score": { - "stars": 20, + "stars": 22, "last_update": "2024-03-01 23:00:05" }, "https://github.com/TinyTerra/ComfyUI_tinyterraNodes": { - "stars": 241, + "stars": 257, "last_update": "2024-03-10 07:42:00" }, "https://github.com/Jordach/comfy-plasma": { - "stars": 39, + "stars": 42, "last_update": "2023-07-31 00:57:50" }, "https://github.com/bvhari/ComfyUI_ImageProcessing": { @@ -252,15 +252,15 @@ "last_update": "2024-03-25 07:05:23" }, "https://github.com/ssitu/ComfyUI_UltimateSDUpscale": { - "stars": 502, + "stars": 527, "last_update": "2024-03-30 17:18:43" }, "https://github.com/ssitu/ComfyUI_restart_sampling": { - "stars": 54, - "last_update": "2024-04-08 03:08:27" + "stars": 62, + "last_update": "2024-04-21 22:30:37" }, "https://github.com/ssitu/ComfyUI_roop": { - "stars": 57, + "stars": 58, "last_update": "2023-09-05 16:18:48" }, "https://github.com/ssitu/ComfyUI_fabric": { @@ -272,7 +272,7 @@ "last_update": "2023-09-12 07:35:52" }, "https://github.com/space-nuko/ComfyUI-OpenPose-Editor": { - "stars": 129, + "stars": 131, "last_update": "2024-01-05 17:45:55" }, "https://github.com/space-nuko/nui-suite": { @@ -280,27 +280,27 @@ "last_update": "2023-06-04 22:08:46" }, "https://github.com/Nourepide/ComfyUI-Allor": { - "stars": 146, + "stars": 150, "last_update": "2024-03-21 07:40:20" }, "https://github.com/melMass/comfy_mtb": { - "stars": 267, - "last_update": "2024-04-09 00:31:53" + "stars": 277, + "last_update": "2024-04-19 19:52:07" }, "https://github.com/xXAdonesXx/NodeGPT": { - "stars": 301, + "stars": 302, "last_update": "2024-02-01 23:20:08" }, "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes": { - "stars": 368, - "last_update": "2024-03-22 16:13:20" + "stars": 383, + "last_update": "2024-04-19 21:02:12" }, "https://github.com/bmad4ever/ComfyUI-Bmad-DirtyUndoRedo": { - "stars": 47, + "stars": 48, "last_update": "2023-11-29 14:41:23" }, "https://github.com/bmad4ever/comfyui_bmad_nodes": { - "stars": 36, + "stars": 38, "last_update": "2024-04-07 19:57:43" }, "https://github.com/bmad4ever/comfyui_ab_samplercustom": { @@ -320,55 +320,55 @@ "last_update": "2024-03-04 22:48:03" }, "https://github.com/FizzleDorf/ComfyUI_FizzNodes": { - "stars": 258, - "last_update": "2024-03-24 14:52:58" + "stars": 270, + "last_update": "2024-04-22 09:38:42" }, "https://github.com/FizzleDorf/ComfyUI-AIT": { "stars": 42, "last_update": "2023-11-08 14:03:03" }, "https://github.com/filipemeneses/comfy_pixelization": { - "stars": 21, + "stars": 23, "last_update": "2024-02-01 04:09:13" }, "https://github.com/shiimizu/ComfyUI_smZNodes": { - "stars": 109, - "last_update": "2024-04-08 21:15:59" + "stars": 118, + "last_update": "2024-04-17 23:10:37" }, "https://github.com/shiimizu/ComfyUI-TiledDiffusion": { - "stars": 132, - "last_update": "2024-04-03 21:25:42" + "stars": 152, + "last_update": "2024-04-11 21:32:24" }, "https://github.com/ZaneA/ComfyUI-ImageReward": { "stars": 22, "last_update": "2024-02-04 23:38:10" }, "https://github.com/SeargeDP/SeargeSDXL": { - "stars": 686, - "last_update": "2024-04-06 23:50:53" + "stars": 702, + "last_update": "2024-04-10 14:29:50" }, "https://github.com/cubiq/ComfyUI_SimpleMath": { - "stars": 7, + "stars": 8, "last_update": "2023-09-26 06:31:44" }, "https://github.com/cubiq/ComfyUI_IPAdapter_plus": { - "stars": 2067, - "last_update": "2024-04-07 12:54:02" + "stars": 2343, + "last_update": "2024-04-23 07:18:06" }, "https://github.com/cubiq/ComfyUI_InstantID": { - "stars": 642, - "last_update": "2024-04-08 19:00:08" + "stars": 706, + "last_update": "2024-04-13 09:44:58" }, "https://github.com/cubiq/ComfyUI_FaceAnalysis": { - "stars": 106, - "last_update": "2024-03-16 17:13:27" + "stars": 120, + "last_update": "2024-04-21 18:18:59" }, "https://github.com/shockz0rz/ComfyUI_InterpolateEverything": { "stars": 21, "last_update": "2023-12-23 04:13:06" }, "https://github.com/shockz0rz/comfy-easy-grids": { - "stars": 9, + "stars": 10, "last_update": "2024-01-01 02:40:59" }, "https://github.com/yolanother/DTAIComfyPromptAgent": { @@ -392,12 +392,12 @@ "last_update": "2023-12-25 04:38:00" }, "https://github.com/yolanother/DTAIComfyVariables": { - "stars": 6, + "stars": 7, "last_update": "2023-12-25 04:37:03" }, "https://github.com/sipherxyz/comfyui-art-venture": { - "stars": 53, - "last_update": "2024-03-03 12:21:56" + "stars": 56, + "last_update": "2024-04-18 15:09:49" }, "https://github.com/SOELexicon/ComfyUI-LexMSDBNodes": { "stars": 4, @@ -408,11 +408,11 @@ "last_update": "2023-08-13 12:02:23" }, "https://github.com/evanspearman/ComfyMath": { - "stars": 35, + "stars": 36, "last_update": "2023-08-27 03:29:04" }, "https://github.com/civitai/comfy-nodes": { - "stars": 74, + "stars": 76, "last_update": "2024-02-29 12:23:11" }, "https://github.com/andersxa/comfyui-PromptAttention": { @@ -420,15 +420,15 @@ "last_update": "2023-09-22 22:48:52" }, "https://github.com/ArtVentureX/comfyui-animatediff": { - "stars": 581, + "stars": 590, "last_update": "2024-01-06 09:18:52" }, "https://github.com/twri/sdxl_prompt_styler": { - "stars": 505, + "stars": 531, "last_update": "2024-03-24 18:55:24" }, "https://github.com/wolfden/ComfyUi_PromptStylers": { - "stars": 51, + "stars": 54, "last_update": "2023-10-22 21:34:59" }, "https://github.com/wolfden/ComfyUi_String_Function_Tree": { @@ -436,15 +436,15 @@ "last_update": "2023-10-22 22:12:55" }, "https://github.com/daxthin/DZ-FaceDetailer": { - "stars": 86, + "stars": 89, "last_update": "2023-12-16 17:31:44" }, "https://github.com/asagi4/comfyui-prompt-control": { - "stars": 128, - "last_update": "2024-04-08 18:19:18" + "stars": 133, + "last_update": "2024-04-17 18:01:52" }, "https://github.com/asagi4/ComfyUI-CADS": { - "stars": 26, + "stars": 27, "last_update": "2024-04-08 15:52:29" }, "https://github.com/asagi4/comfyui-utility-nodes": { @@ -456,11 +456,11 @@ "last_update": "2023-08-11 20:15:26" }, "https://github.com/jamesWalker55/comfyui-various": { - "stars": 22, + "stars": 23, "last_update": "2024-03-10 06:45:45" }, "https://github.com/adieyal/comfyui-dynamicprompts": { - "stars": 152, + "stars": 158, "last_update": "2024-02-05 06:55:50" }, "https://github.com/mihaiiancu/ComfyUI_Inpaint": { @@ -468,55 +468,55 @@ "last_update": "2023-07-30 22:32:41" }, "https://github.com/kwaroran/abg-comfyui": { - "stars": 19, + "stars": 20, "last_update": "2023-08-03 08:57:52" }, "https://github.com/bash-j/mikey_nodes": { - "stars": 61, + "stars": 64, "last_update": "2024-03-10 09:09:50" }, "https://github.com/failfa-st/failfast-comfyui-extensions": { - "stars": 103, + "stars": 109, "last_update": "2024-02-25 09:56:19" }, "https://github.com/Pfaeff/pfaeff-comfyui": { - "stars": 17, + "stars": 18, "last_update": "2023-08-19 19:28:36" }, "https://github.com/wallish77/wlsh_nodes": { - "stars": 70, + "stars": 71, "last_update": "2024-03-28 23:02:54" }, "https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet": { - "stars": 315, + "stars": 337, "last_update": "2024-04-04 19:49:52" }, "https://github.com/Kosinkadink/ComfyUI-AnimateDiff-Evolved": { - "stars": 1912, - "last_update": "2024-04-09 00:01:21" + "stars": 1988, + "last_update": "2024-04-23 08:21:10" }, "https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite": { - "stars": 288, - "last_update": "2024-04-09 04:17:58" + "stars": 304, + "last_update": "2024-04-20 18:24:00" }, "https://github.com/Gourieff/comfyui-reactor-node": { - "stars": 820, - "last_update": "2024-04-07 08:47:57" + "stars": 868, + "last_update": "2024-04-16 12:22:21" }, "https://github.com/imb101/ComfyUI-FaceSwap": { "stars": 28, "last_update": "2023-08-04 23:54:24" }, "https://github.com/Chaoses-Ib/ComfyUI_Ib_CustomNodes": { - "stars": 7, + "stars": 9, "last_update": "2024-04-05 11:14:24" }, "https://github.com/AIrjen/OneButtonPrompt": { - "stars": 618, - "last_update": "2024-04-05 14:40:04" + "stars": 651, + "last_update": "2024-04-16 19:24:12" }, "https://github.com/coreyryanhanson/ComfyQR": { - "stars": 36, + "stars": 37, "last_update": "2024-03-20 20:10:27" }, "https://github.com/coreyryanhanson/ComfyQR-scanning-nodes": { @@ -524,7 +524,7 @@ "last_update": "2023-10-15 03:19:16" }, "https://github.com/dimtoneff/ComfyUI-PixelArt-Detector": { - "stars": 146, + "stars": 151, "last_update": "2024-01-07 03:29:57" }, "https://github.com/hylarucoder/ComfyUI-Eagle-PNGInfo": { @@ -532,7 +532,7 @@ "last_update": "2023-12-10 13:57:48" }, "https://github.com/theUpsider/ComfyUI-Styles_CSV_Loader": { - "stars": 24, + "stars": 25, "last_update": "2023-10-23 14:55:53" }, "https://github.com/M1kep/Comfy_KepListStuff": { @@ -560,11 +560,11 @@ "last_update": "2023-10-29 03:21:34" }, "https://github.com/M1kep/ComfyUI-KepOpenAI": { - "stars": 21, + "stars": 23, "last_update": "2023-11-08 22:43:37" }, "https://github.com/uarefans/ComfyUI-Fans": { - "stars": 11, + "stars": 12, "last_update": "2023-08-15 18:42:40" }, "https://github.com/NicholasMcCarthy/ComfyUI_TravelSuite": { @@ -576,11 +576,11 @@ "last_update": "2023-11-03 11:09:53" }, "https://github.com/theUpsider/ComfyUI-Logic": { - "stars": 73, + "stars": 76, "last_update": "2023-12-12 20:29:49" }, "https://github.com/mpiquero7164/ComfyUI-SaveImgPrompt": { - "stars": 12, + "stars": 13, "last_update": "2023-08-14 11:27:09" }, "https://github.com/m-sokes/ComfyUI-Sokes-Nodes": { @@ -592,31 +592,31 @@ "last_update": "2023-08-21 22:04:31" }, "https://github.com/Extraltodeus/LoadLoraWithTags": { - "stars": 28, + "stars": 29, "last_update": "2023-10-28 15:51:44" }, "https://github.com/Extraltodeus/sigmas_tools_and_the_golden_scheduler": { - "stars": 27, - "last_update": "2024-01-25 16:30:20" + "stars": 32, + "last_update": "2024-04-20 11:46:46" }, "https://github.com/Extraltodeus/ComfyUI-AutomaticCFG": { - "stars": 123, - "last_update": "2024-04-05 02:00:30" + "stars": 141, + "last_update": "2024-04-21 19:05:31" }, "https://github.com/Extraltodeus/Vector_Sculptor_ComfyUI": { - "stars": 57, + "stars": 63, "last_update": "2024-04-04 20:20:54" }, "https://github.com/JPS-GER/ComfyUI_JPS-Nodes": { "stars": 26, - "last_update": "2024-02-02 13:05:11" + "last_update": "2024-04-21 09:44:11" }, "https://github.com/hustille/ComfyUI_hus_utils": { "stars": 4, "last_update": "2023-08-16 15:44:24" }, "https://github.com/hustille/ComfyUI_Fooocus_KSampler": { - "stars": 54, + "stars": 56, "last_update": "2023-09-10 01:51:24" }, "https://github.com/badjeff/comfyui_lora_tag_loader": { @@ -624,15 +624,15 @@ "last_update": "2024-02-12 07:46:02" }, "https://github.com/rgthree/rgthree-comfy": { - "stars": 453, - "last_update": "2024-04-07 04:42:44" + "stars": 511, + "last_update": "2024-04-21 23:46:18" }, "https://github.com/AIGODLIKE/AIGODLIKE-COMFYUI-TRANSLATION": { - "stars": 656, - "last_update": "2024-04-09 07:45:56" + "stars": 715, + "last_update": "2024-04-23 07:47:40" }, "https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Studio": { - "stars": 176, + "stars": 182, "last_update": "2024-04-03 03:59:31" }, "https://github.com/AIGODLIKE/ComfyUI-CUP": { @@ -640,19 +640,19 @@ "last_update": "2024-03-22 07:26:43" }, "https://github.com/syllebra/bilbox-comfyui": { - "stars": 66, + "stars": 68, "last_update": "2024-04-03 22:58:07" }, "https://github.com/giriss/comfy-image-saver": { - "stars": 106, + "stars": 112, "last_update": "2023-11-16 10:39:05" }, "https://github.com/shingo1228/ComfyUI-send-eagle-slim": { - "stars": 18, - "last_update": "2024-01-27 01:44:58" + "stars": 19, + "last_update": "2024-04-11 17:41:50" }, "https://github.com/shingo1228/ComfyUI-SDXL-EmptyLatentImage": { - "stars": 21, + "stars": 22, "last_update": "2023-08-17 07:51:02" }, "https://github.com/laksjdjf/pfg-ComfyUI": { @@ -692,7 +692,7 @@ "last_update": "2023-09-17 00:00:31" }, "https://github.com/meap158/ComfyUI-Background-Replacement": { - "stars": 28, + "stars": 30, "last_update": "2023-12-17 14:05:08" }, "https://github.com/TeaCrab/ComfyUI-TeaNodes": { @@ -708,7 +708,7 @@ "last_update": "2023-08-19 06:52:19" }, "https://github.com/kohya-ss/ControlNet-LLLite-ComfyUI": { - "stars": 121, + "stars": 126, "last_update": "2024-03-15 19:05:53" }, "https://github.com/jjkramhoeft/ComfyUI-Jjk-Nodes": { @@ -716,20 +716,20 @@ "last_update": "2023-08-19 19:17:07" }, "https://github.com/dagthomas/comfyui_dagthomas": { - "stars": 40, - "last_update": "2024-01-03 09:59:57" + "stars": 47, + "last_update": "2024-04-11 22:05:09" }, "https://github.com/marhensa/sdxl-recommended-res-calc": { - "stars": 46, + "stars": 49, "last_update": "2024-03-15 05:43:38" }, "https://github.com/Nuked88/ComfyUI-N-Nodes": { - "stars": 140, + "stars": 147, "last_update": "2024-03-16 11:27:55" }, "https://github.com/Nuked88/ComfyUI-N-Sidebar": { - "stars": 265, - "last_update": "2024-03-31 20:26:53" + "stars": 284, + "last_update": "2024-04-22 21:58:04" }, "https://github.com/richinsley/Comfy-LFO": { "stars": 4, @@ -744,7 +744,7 @@ "last_update": "2023-09-21 08:40:50" }, "https://github.com/Sxela/ComfyWarp": { - "stars": 19, + "stars": 20, "last_update": "2023-11-04 10:45:11" }, "https://github.com/skfoo/ComfyUI-Coziness": { @@ -756,11 +756,11 @@ "last_update": "2023-08-30 16:06:45" }, "https://github.com/Lerc/canvas_tab": { - "stars": 114, + "stars": 115, "last_update": "2024-01-25 22:09:37" }, "https://github.com/Ttl/ComfyUi_NNLatentUpscale": { - "stars": 125, + "stars": 136, "last_update": "2023-08-28 13:56:20" }, "https://github.com/spro/comfyui-mirror": { @@ -768,27 +768,27 @@ "last_update": "2023-08-28 02:37:52" }, "https://github.com/Tropfchen/ComfyUI-Embedding_Picker": { - "stars": 19, + "stars": 20, "last_update": "2024-01-06 14:15:12" }, "https://github.com/Acly/comfyui-tooling-nodes": { - "stars": 163, + "stars": 170, "last_update": "2024-03-04 08:52:39" }, "https://github.com/Acly/comfyui-inpaint-nodes": { - "stars": 252, - "last_update": "2024-04-09 07:53:12" + "stars": 277, + "last_update": "2024-04-18 08:46:41" }, "https://github.com/picturesonpictures/comfy_PoP": { - "stars": 9, + "stars": 10, "last_update": "2024-02-01 03:04:42" }, "https://github.com/alt-key-project/comfyui-dream-project": { - "stars": 60, + "stars": 62, "last_update": "2023-12-21 19:36:51" }, "https://github.com/alt-key-project/comfyui-dream-video-batches": { - "stars": 39, + "stars": 44, "last_update": "2023-12-03 10:31:55" }, "https://github.com/seanlynch/comfyui-optical-flow": { @@ -800,11 +800,11 @@ "last_update": "2023-09-26 14:56:04" }, "https://github.com/ArtBot2023/CharacterFaceSwap": { - "stars": 48, + "stars": 49, "last_update": "2023-10-25 04:29:40" }, "https://github.com/mav-rik/facerestore_cf": { - "stars": 119, + "stars": 130, "last_update": "2024-03-19 21:36:31" }, "https://github.com/braintacles/braintacles-comfyui-nodes": { @@ -812,15 +812,15 @@ "last_update": "2023-09-06 12:12:32" }, "https://github.com/hayden-fr/ComfyUI-Model-Manager": { - "stars": 15, - "last_update": "2024-04-08 06:10:39" + "stars": 17, + "last_update": "2024-04-21 07:42:28" }, "https://github.com/hayden-fr/ComfyUI-Image-Browsing": { "stars": 2, "last_update": "2023-09-07 14:06:12" }, "https://github.com/ali1234/comfyui-job-iterator": { - "stars": 42, + "stars": 45, "last_update": "2023-09-10 23:42:15" }, "https://github.com/jmkl/ComfyUI-ricing": { @@ -836,7 +836,7 @@ "last_update": "2023-09-13 02:56:53" }, "https://github.com/spinagon/ComfyUI-seamless-tiling": { - "stars": 55, + "stars": 60, "last_update": "2024-01-29 03:45:40" }, "https://github.com/tusharbhutt/Endless-Nodes": { @@ -844,15 +844,15 @@ "last_update": "2023-10-21 23:02:19" }, "https://github.com/spacepxl/ComfyUI-HQ-Image-Save": { - "stars": 17, + "stars": 20, "last_update": "2024-03-30 05:10:42" }, "https://github.com/spacepxl/ComfyUI-Image-Filters": { - "stars": 41, - "last_update": "2024-03-15 06:09:56" + "stars": 45, + "last_update": "2024-04-15 20:28:20" }, "https://github.com/spacepxl/ComfyUI-RAVE": { - "stars": 69, + "stars": 75, "last_update": "2024-01-28 09:08:08" }, "https://github.com/phineas-pta/comfyui-auto-nodes-layout": { @@ -860,7 +860,7 @@ "last_update": "2023-09-21 14:49:12" }, "https://github.com/receyuki/comfyui-prompt-reader-node": { - "stars": 146, + "stars": 155, "last_update": "2024-04-08 18:19:54" }, "https://github.com/rklaffehn/rk-comfy-nodes": { @@ -868,40 +868,40 @@ "last_update": "2024-01-23 17:12:45" }, "https://github.com/cubiq/ComfyUI_essentials": { - "stars": 169, - "last_update": "2024-04-07 13:42:40" + "stars": 201, + "last_update": "2024-04-21 09:40:23" }, "https://github.com/Clybius/ComfyUI-Latent-Modifiers": { - "stars": 37, + "stars": 39, "last_update": "2024-01-02 21:57:58" }, "https://github.com/Clybius/ComfyUI-Extra-Samplers": { - "stars": 28, - "last_update": "2024-04-06 21:03:11" + "stars": 35, + "last_update": "2024-04-18 04:28:09" }, "https://github.com/mcmonkeyprojects/sd-dynamic-thresholding": { - "stars": 990, - "last_update": "2024-03-21 09:27:41" + "stars": 1003, + "last_update": "2024-04-21 14:51:14" }, "https://github.com/Tropfchen/ComfyUI-yaResolutionSelector": { "stars": 5, "last_update": "2024-01-20 14:15:58" }, "https://github.com/chrisgoringe/cg-noise": { - "stars": 20, + "stars": 22, "last_update": "2024-02-02 23:38:25" }, "https://github.com/chrisgoringe/cg-image-picker": { - "stars": 116, - "last_update": "2024-04-03 22:31:49" + "stars": 129, + "last_update": "2024-04-22 14:41:30" }, "https://github.com/chrisgoringe/cg-use-everywhere": { - "stars": 253, - "last_update": "2024-04-08 22:33:13" + "stars": 271, + "last_update": "2024-04-17 23:03:28" }, "https://github.com/chrisgoringe/cg-prompt-info": { "stars": 23, - "last_update": "2023-10-20 05:21:26" + "last_update": "2024-04-10 01:08:34" }, "https://github.com/TGu-97/ComfyUI-TGu-utils": { "stars": 1, @@ -912,63 +912,63 @@ "last_update": "2023-10-22 22:35:41" }, "https://github.com/alpertunga-bile/prompt-generator-comfyui": { - "stars": 51, + "stars": 54, "last_update": "2024-04-07 16:02:06" }, "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor": { - "stars": 62, - "last_update": "2023-12-21 04:31:58" + "stars": 63, + "last_update": "2024-04-12 12:59:58" }, "https://github.com/kijai/ComfyUI-KJNodes": { - "stars": 167, - "last_update": "2024-04-08 20:40:40" + "stars": 192, + "last_update": "2024-04-22 21:53:19" }, "https://github.com/kijai/ComfyUI-CCSR": { - "stars": 97, + "stars": 103, "last_update": "2024-03-18 10:10:20" }, "https://github.com/kijai/ComfyUI-SVD": { - "stars": 149, + "stars": 151, "last_update": "2023-11-25 10:16:57" }, "https://github.com/kijai/ComfyUI-Marigold": { - "stars": 307, + "stars": 328, "last_update": "2024-04-08 08:33:04" }, "https://github.com/kijai/ComfyUI-Geowizard": { - "stars": 64, + "stars": 68, "last_update": "2024-04-07 12:46:47" }, "https://github.com/kijai/ComfyUI-depth-fm": { - "stars": 38, + "stars": 41, "last_update": "2024-03-23 23:45:51" }, "https://github.com/kijai/ComfyUI-DDColor": { - "stars": 57, + "stars": 65, "last_update": "2024-01-18 08:05:17" }, "https://github.com/kijai/ComfyUI-ADMotionDirector": { - "stars": 88, + "stars": 90, "last_update": "2024-03-27 19:38:20" }, "https://github.com/kijai/ComfyUI-moondream": { - "stars": 55, + "stars": 58, "last_update": "2024-03-11 00:50:24" }, "https://github.com/kijai/ComfyUI-SUPIR": { - "stars": 817, - "last_update": "2024-04-08 18:11:09" + "stars": 898, + "last_update": "2024-04-23 10:04:12" }, "https://github.com/kijai/ComfyUI-DynamiCrafterWrapper": { - "stars": 170, - "last_update": "2024-03-26 13:31:13" + "stars": 190, + "last_update": "2024-04-18 11:22:03" }, "https://github.com/hhhzzyang/Comfyui_Lama": { - "stars": 30, - "last_update": "2023-10-01 17:33:29" + "stars": 31, + "last_update": "2024-04-15 09:44:58" }, "https://github.com/thedyze/save-image-extended-comfyui": { - "stars": 58, + "stars": 59, "last_update": "2023-11-09 17:48:44" }, "https://github.com/SOELexicon/ComfyUI-LexTools": { @@ -976,24 +976,24 @@ "last_update": "2024-03-15 17:45:41" }, "https://github.com/mikkel/ComfyUI-text-overlay": { - "stars": 22, + "stars": 23, "last_update": "2023-10-05 03:05:03" }, "https://github.com/avatechai/avatar-graph-comfyui": { - "stars": 184, + "stars": 190, "last_update": "2024-02-06 08:56:30" }, "https://github.com/TRI3D-LC/tri3d-comfyui-nodes": { - "stars": 8, - "last_update": "2024-04-08 17:45:48" + "stars": 10, + "last_update": "2024-04-10 15:22:50" }, "https://github.com/storyicon/comfyui_segment_anything": { - "stars": 346, + "stars": 385, "last_update": "2024-04-03 15:43:25" }, "https://github.com/a1lazydog/ComfyUI-AudioScheduler": { - "stars": 57, - "last_update": "2024-04-01 05:46:51" + "stars": 76, + "last_update": "2024-04-14 23:50:26" }, "https://github.com/whatbirdisthat/cyberdolphin": { "stars": 14, @@ -1001,10 +1001,10 @@ }, "https://github.com/chrish-slingshot/CrasHUtils": { "stars": 11, - "last_update": "2023-11-02 23:00:35" + "last_update": "2024-04-19 22:22:24" }, "https://github.com/spinagon/ComfyUI-seam-carving": { - "stars": 11, + "stars": 12, "last_update": "2023-10-13 07:24:05" }, "https://github.com/YMC-GitHub/ymc-node-suite-comfyui": { @@ -1012,7 +1012,7 @@ "last_update": "2023-12-27 14:18:04" }, "https://github.com/chibiace/ComfyUI-Chibi-Nodes": { - "stars": 19, + "stars": 23, "last_update": "2024-04-09 09:23:35" }, "https://github.com/DigitalIO/ComfyUI-stable-wildcards": { @@ -1020,31 +1020,31 @@ "last_update": "2023-12-18 23:42:52" }, "https://github.com/THtianhao/ComfyUI-Portrait-Maker": { - "stars": 150, + "stars": 152, "last_update": "2024-03-07 06:45:14" }, "https://github.com/THtianhao/ComfyUI-FaceChain": { - "stars": 62, - "last_update": "2024-01-15 07:18:31" + "stars": 68, + "last_update": "2024-04-12 03:48:33" }, "https://github.com/zer0TF/cute-comfy": { "stars": 27, "last_update": "2024-01-04 04:20:46" }, "https://github.com/chflame163/ComfyUI_MSSpeech_TTS": { - "stars": 12, + "stars": 16, "last_update": "2024-02-20 01:27:38" }, "https://github.com/chflame163/ComfyUI_WordCloud": { - "stars": 45, + "stars": 49, "last_update": "2024-02-27 12:47:52" }, "https://github.com/chflame163/ComfyUI_LayerStyle": { - "stars": 358, - "last_update": "2024-04-08 14:38:52" + "stars": 410, + "last_update": "2024-04-22 09:24:35" }, "https://github.com/chflame163/ComfyUI_FaceSimilarity": { - "stars": 2, + "stars": 3, "last_update": "2024-03-22 05:35:23" }, "https://github.com/drustan-hawk/primitive-types": { @@ -1052,12 +1052,12 @@ "last_update": "2023-10-20 16:33:23" }, "https://github.com/shadowcz007/comfyui-mixlab-nodes": { - "stars": 626, - "last_update": "2024-04-08 09:14:33" + "stars": 674, + "last_update": "2024-04-23 04:14:55" }, "https://github.com/shadowcz007/comfyui-ultralytics-yolo": { - "stars": 9, - "last_update": "2024-03-29 08:35:02" + "stars": 12, + "last_update": "2024-04-23 02:35:25" }, "https://github.com/shadowcz007/comfyui-consistency-decoder": { "stars": 1, @@ -1068,19 +1068,19 @@ "last_update": "2024-03-25 05:41:04" }, "https://github.com/ostris/ostris_nodes_comfyui": { - "stars": 18, + "stars": 19, "last_update": "2023-11-26 21:41:27" }, "https://github.com/0xbitches/ComfyUI-LCM": { - "stars": 240, + "stars": 241, "last_update": "2023-11-11 21:24:33" }, "https://github.com/aszc-dev/ComfyUI-CoreMLSuite": { - "stars": 70, + "stars": 72, "last_update": "2023-12-01 00:09:15" }, "https://github.com/taabata/LCM_Inpaint-Outpaint_Comfy": { - "stars": 209, + "stars": 214, "last_update": "2024-04-07 21:32:38" }, "https://github.com/noxinias/ComfyUI_NoxinNodes": { @@ -1088,7 +1088,7 @@ "last_update": "2023-11-01 00:11:28" }, "https://github.com/GMapeSplat/ComfyUI_ezXY": { - "stars": 16, + "stars": 17, "last_update": "2023-11-30 00:32:24" }, "https://github.com/kinfolk0117/ComfyUI_SimpleTiles": { @@ -1096,7 +1096,7 @@ "last_update": "2024-01-29 19:27:12" }, "https://github.com/kinfolk0117/ComfyUI_GradientDeepShrink": { - "stars": 20, + "stars": 21, "last_update": "2023-12-01 20:13:00" }, "https://github.com/kinfolk0117/ComfyUI_Pilgram": { @@ -1108,8 +1108,8 @@ "last_update": "2023-11-29 12:58:14" }, "https://github.com/idrirap/ComfyUI-Lora-Auto-Trigger-Words": { - "stars": 59, - "last_update": "2024-03-14 22:26:17" + "stars": 66, + "last_update": "2024-04-09 20:35:52" }, "https://github.com/aianimation55/ComfyUI-FatLabels": { "stars": 4, @@ -1120,7 +1120,7 @@ "last_update": "2024-03-22 17:52:32" }, "https://github.com/mikkel/comfyui-mask-boundingbox": { - "stars": 20, + "stars": 22, "last_update": "2024-03-07 08:11:06" }, "https://github.com/ParmanBabra/ComfyUI-Malefish-Custom-Scripts": { @@ -1128,15 +1128,15 @@ "last_update": "2023-11-03 04:16:28" }, "https://github.com/matan1905/ComfyUI-Serving-Toolkit": { - "stars": 30, + "stars": 31, "last_update": "2024-02-28 18:30:35" }, "https://github.com/PCMonsterx/ComfyUI-CSV-Loader": { - "stars": 9, + "stars": 10, "last_update": "2023-11-06 06:34:25" }, "https://github.com/Trung0246/ComfyUI-0246": { - "stars": 84, + "stars": 83, "last_update": "2024-04-04 02:30:39" }, "https://github.com/fexli/fexli-util-node-comfyui": { @@ -1144,11 +1144,11 @@ "last_update": "2024-02-20 09:14:55" }, "https://github.com/AbyssYuan0/ComfyUI_BadgerTools": { - "stars": 5, - "last_update": "2024-04-07 05:00:05" + "stars": 6, + "last_update": "2024-04-16 07:26:43" }, "https://github.com/palant/image-resize-comfyui": { - "stars": 40, + "stars": 42, "last_update": "2024-01-18 20:59:55" }, "https://github.com/palant/integrated-nodes-comfyui": { @@ -1160,7 +1160,7 @@ "last_update": "2024-03-27 14:08:21" }, "https://github.com/whmc76/ComfyUI-Openpose-Editor-Plus": { - "stars": 12, + "stars": 13, "last_update": "2024-01-06 18:32:07" }, "https://github.com/martijnat/comfyui-previewlatent": { @@ -1168,8 +1168,8 @@ "last_update": "2024-02-15 05:52:28" }, "https://github.com/banodoco/steerable-motion": { - "stars": 432, - "last_update": "2024-04-08 17:56:08" + "stars": 499, + "last_update": "2024-04-17 19:27:29" }, "https://github.com/gemell1/ComfyUI_GMIC": { "stars": 5, @@ -1184,7 +1184,7 @@ "last_update": "2023-12-06 12:47:18" }, "https://github.com/romeobuilderotti/ComfyUI-PNG-Metadata": { - "stars": 1, + "stars": 2, "last_update": "2024-01-04 17:52:44" }, "https://github.com/ka-puna/comfyui-yanc": { @@ -1192,7 +1192,7 @@ "last_update": "2023-12-10 21:29:12" }, "https://github.com/Amorano/Jovimetrix": { - "stars": 96, + "stars": 111, "last_update": "2024-03-31 04:36:03" }, "https://github.com/Umikaze-job/select_folder_path_easy": { @@ -1212,7 +1212,7 @@ "last_update": "2023-11-20 21:32:07" }, "https://github.com/natto-maki/ComfyUI-NegiTools": { - "stars": 20, + "stars": 21, "last_update": "2024-02-02 07:50:01" }, "https://github.com/LonicaMewinsky/ComfyUI-RawSaver": { @@ -1220,7 +1220,7 @@ "last_update": "2023-11-21 14:34:54" }, "https://github.com/jojkaart/ComfyUI-sampler-lcm-alternative": { - "stars": 74, + "stars": 79, "last_update": "2024-04-07 00:30:45" }, "https://github.com/GTSuya-Studio/ComfyUI-Gtsuya-Nodes": { @@ -1244,19 +1244,19 @@ "last_update": "2023-12-03 12:32:49" }, "https://github.com/toyxyz/ComfyUI_toyxyz_test_nodes": { - "stars": 390, + "stars": 400, "last_update": "2024-03-31 15:10:51" }, "https://github.com/thecooltechguy/ComfyUI-Stable-Video-Diffusion": { - "stars": 255, + "stars": 262, "last_update": "2023-11-24 06:14:27" }, "https://github.com/thecooltechguy/ComfyUI-ComfyRun": { - "stars": 72, + "stars": 74, "last_update": "2023-12-27 18:16:34" }, "https://github.com/thecooltechguy/ComfyUI-MagicAnimate": { - "stars": 180, + "stars": 184, "last_update": "2024-01-09 19:24:47" }, "https://github.com/thecooltechguy/ComfyUI-ComfyWorkflows": { @@ -1268,11 +1268,11 @@ "last_update": "2024-04-06 21:05:24" }, "https://github.com/42lux/ComfyUI-safety-checker": { - "stars": 12, + "stars": 13, "last_update": "2024-03-15 18:39:38" }, "https://github.com/sergekatzmann/ComfyUI_Nimbus-Pack": { - "stars": 1, + "stars": 2, "last_update": "2024-04-06 15:42:48" }, "https://github.com/komojini/ComfyUI_SDXL_DreamBooth_LoRA_CustomNodes": { @@ -1284,67 +1284,67 @@ "last_update": "2024-02-10 14:58:22" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-APISR": { - "stars": 240, - "last_update": "2024-03-24 14:20:44" + "stars": 266, + "last_update": "2024-04-17 19:59:18" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-Text_Image-Composite": { - "stars": 54, - "last_update": "2023-12-22 08:22:45" + "stars": 59, + "last_update": "2024-04-17 20:02:42" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-Gemini": { - "stars": 303, - "last_update": "2024-04-04 00:10:12" + "stars": 507, + "last_update": "2024-04-17 19:57:55" }, "https://github.com/ZHO-ZHO-ZHO/comfyui-portrait-master-zh-cn": { - "stars": 1332, - "last_update": "2023-12-23 07:08:46" + "stars": 1362, + "last_update": "2024-04-17 19:57:18" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-Q-Align": { "stars": 2, "last_update": "2024-01-03 15:22:13" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-InstantID": { - "stars": 1049, - "last_update": "2024-03-23 06:33:03" + "stars": 1081, + "last_update": "2024-04-17 20:02:02" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-PhotoMaker-ZHO": { - "stars": 696, - "last_update": "2024-01-25 13:13:33" + "stars": 713, + "last_update": "2024-04-17 20:01:40" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-Qwen-VL-API": { - "stars": 161, - "last_update": "2024-03-12 10:32:47" + "stars": 166, + "last_update": "2024-04-17 19:58:21" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-SVD-ZHO": { - "stars": 74, - "last_update": "2024-02-06 09:16:21" + "stars": 78, + "last_update": "2024-04-17 20:04:09" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-SegMoE": { - "stars": 67, - "last_update": "2024-02-04 20:03:35" + "stars": 70, + "last_update": "2024-04-17 20:03:27" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-YoloWorld-EfficientSAM": { - "stars": 295, - "last_update": "2024-04-06 04:04:12" + "stars": 341, + "last_update": "2024-04-17 20:00:25" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-PixArt-alpha-Diffusers": { - "stars": 28, - "last_update": "2024-04-02 02:55:59" + "stars": 35, + "last_update": "2024-04-17 20:03:46" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-BRIA_AI-RMBG": { - "stars": 402, - "last_update": "2024-02-07 13:22:16" + "stars": 456, + "last_update": "2024-04-17 20:00:02" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-DepthFM": { - "stars": 50, - "last_update": "2024-03-25 02:09:04" + "stars": 57, + "last_update": "2024-04-17 20:00:46" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-BiRefNet-ZHO": { - "stars": 66, - "last_update": "2024-04-01 13:35:54" + "stars": 92, + "last_update": "2024-04-17 19:59:42" }, "https://github.com/kenjiqq/qq-nodes-comfyui": { - "stars": 16, + "stars": 18, "last_update": "2024-02-23 01:57:06" }, "https://github.com/80sVectorz/ComfyUI-Static-Primitives": { @@ -1352,7 +1352,7 @@ "last_update": "2023-12-11 11:06:16" }, "https://github.com/AbdullahAlfaraj/Comfy-Photoshop-SD": { - "stars": 137, + "stars": 146, "last_update": "2023-12-12 12:23:04" }, "https://github.com/zhuanqianfish/ComfyUI-EasyNode": { @@ -1368,7 +1368,7 @@ "last_update": "2024-02-25 06:28:49" }, "https://github.com/SoftMeng/ComfyUI_Mexx_Styler": { - "stars": 12, + "stars": 13, "last_update": "2024-04-06 06:49:01" }, "https://github.com/SoftMeng/ComfyUI_Mexx_Poster": { @@ -1392,11 +1392,11 @@ "last_update": "2023-12-01 02:23:18" }, "https://github.com/Scholar01/ComfyUI-Keyframe": { - "stars": 7, + "stars": 8, "last_update": "2024-02-01 16:57:40" }, "https://github.com/Haoming02/comfyui-diffusion-cg": { - "stars": 35, + "stars": 37, "last_update": "2024-03-22 19:10:11" }, "https://github.com/Haoming02/comfyui-prompt-format": { @@ -1416,7 +1416,7 @@ "last_update": "2023-12-14 08:24:49" }, "https://github.com/Haoming02/comfyui-floodgate": { - "stars": 21, + "stars": 22, "last_update": "2024-01-31 09:08:14" }, "https://github.com/bedovyy/ComfyUI_NAIDGenerator": { @@ -1425,14 +1425,14 @@ }, "https://github.com/Off-Live/ComfyUI-off-suite": { "stars": 0, - "last_update": "2024-03-22 06:35:18" + "last_update": "2024-04-19 07:13:08" }, "https://github.com/ningxiaoxiao/comfyui-NDI": { - "stars": 29, + "stars": 31, "last_update": "2024-03-07 02:08:05" }, "https://github.com/subtleGradient/TinkerBot-tech-for-ComfyUI-Touchpad": { - "stars": 11, + "stars": 13, "last_update": "2024-01-14 20:01:01" }, "https://github.com/zcfrank1st/comfyui_visual_anagrams": { @@ -1440,16 +1440,16 @@ "last_update": "2023-12-05 12:31:26" }, "https://github.com/Electrofried/ComfyUI-OpenAINode": { - "stars": 15, + "stars": 16, "last_update": "2023-12-05 21:34:23" }, "https://github.com/AustinMroz/ComfyUI-SpliceTools": { - "stars": 1, - "last_update": "2024-02-09 23:16:25" + "stars": 6, + "last_update": "2024-04-21 07:59:14" }, "https://github.com/11cafe/comfyui-workspace-manager": { - "stars": 586, - "last_update": "2024-04-08 08:11:17" + "stars": 620, + "last_update": "2024-04-18 10:03:50" }, "https://github.com/knuknX/ComfyUI-Image-Tools": { "stars": 1, @@ -1460,8 +1460,8 @@ "last_update": "2023-12-25 17:55:50" }, "https://github.com/filliptm/ComfyUI_Fill-Nodes": { - "stars": 12, - "last_update": "2024-04-08 11:46:49" + "stars": 26, + "last_update": "2024-04-14 01:54:33" }, "https://github.com/zfkun/ComfyUI_zfkun": { "stars": 11, @@ -1472,12 +1472,12 @@ "last_update": "2023-12-13 11:36:14" }, "https://github.com/talesofai/comfyui-browser": { - "stars": 347, - "last_update": "2024-04-07 07:38:51" + "stars": 362, + "last_update": "2024-04-23 06:21:36" }, "https://github.com/yolain/ComfyUI-Easy-Use": { - "stars": 295, - "last_update": "2024-04-08 04:33:32" + "stars": 334, + "last_update": "2024-04-23 06:41:07" }, "https://github.com/bruefire/ComfyUI-SeqImageLoader": { "stars": 25, @@ -1488,7 +1488,7 @@ "last_update": "2023-12-13 21:01:18" }, "https://github.com/aria1th/ComfyUI-LogicUtils": { - "stars": 12, + "stars": 14, "last_update": "2023-12-24 09:07:07" }, "https://github.com/MitoshiroPJ/comfyui_slothful_attention": { @@ -1496,59 +1496,59 @@ "last_update": "2023-12-16 09:10:38" }, "https://github.com/brianfitzgerald/style_aligned_comfy": { - "stars": 218, + "stars": 227, "last_update": "2024-03-12 03:42:07" }, "https://github.com/deroberon/demofusion-comfyui": { - "stars": 79, + "stars": 80, "last_update": "2023-12-19 22:54:02" }, "https://github.com/deroberon/StableZero123-comfyui": { - "stars": 117, + "stars": 122, "last_update": "2024-01-15 10:38:27" }, "https://github.com/glifxyz/ComfyUI-GlifNodes": { - "stars": 5, - "last_update": "2024-03-15 14:30:29" + "stars": 6, + "last_update": "2024-04-16 16:27:56" }, "https://github.com/concarne000/ConCarneNode": { "stars": 4, "last_update": "2024-04-02 23:10:42" }, "https://github.com/aegis72/aegisflow_utility_nodes": { - "stars": 20, + "stars": 21, "last_update": "2024-03-06 14:04:56" }, "https://github.com/aegis72/comfyui-styles-all": { - "stars": 20, - "last_update": "2024-03-21 02:58:24" + "stars": 22, + "last_update": "2024-04-18 04:30:06" }, "https://github.com/glibsonoran/Plush-for-ComfyUI": { - "stars": 86, - "last_update": "2024-03-27 15:00:07" + "stars": 92, + "last_update": "2024-04-17 17:12:37" }, "https://github.com/vienteck/ComfyUI-Chat-GPT-Integration": { "stars": 24, - "last_update": "2024-02-24 21:32:58" + "last_update": "2024-04-10 23:47:22" }, "https://github.com/MNeMoNiCuZ/ComfyUI-mnemic-nodes": { - "stars": 10, - "last_update": "2024-04-01 10:37:35" + "stars": 12, + "last_update": "2024-04-21 12:44:41" }, "https://github.com/AI2lab/comfyUI-tool-2lab": { "stars": 0, - "last_update": "2024-03-24 16:59:45" + "last_update": "2024-04-15 16:37:12" }, "https://github.com/SpaceKendo/ComfyUI-svd_txt2vid": { - "stars": 4, + "stars": 6, "last_update": "2023-12-15 21:07:36" }, "https://github.com/NimaNzrii/comfyui-popup_preview": { - "stars": 24, + "stars": 25, "last_update": "2024-01-07 12:21:43" }, "https://github.com/NimaNzrii/comfyui-photoshop": { - "stars": 48, + "stars": 49, "last_update": "2023-12-20 13:03:59" }, "https://github.com/rui40000/RUI-Nodes": { @@ -1560,24 +1560,24 @@ "last_update": "2023-12-30 00:37:20" }, "https://github.com/dmarx/ComfyUI-AudioReactive": { - "stars": 4, + "stars": 7, "last_update": "2024-01-03 08:27:32" }, "https://github.com/TripleHeadedMonkey/ComfyUI_MileHighStyler": { - "stars": 12, + "stars": 13, "last_update": "2023-12-16 19:21:57" }, "https://github.com/BennyKok/comfyui-deploy": { - "stars": 541, - "last_update": "2024-03-28 15:15:47" + "stars": 560, + "last_update": "2024-04-23 06:11:15" }, "https://github.com/florestefano1975/comfyui-portrait-master": { - "stars": 653, - "last_update": "2024-03-04 11:08:24" + "stars": 671, + "last_update": "2024-04-18 16:19:47" }, "https://github.com/florestefano1975/comfyui-prompt-composer": { - "stars": 185, - "last_update": "2024-03-08 11:46:57" + "stars": 192, + "last_update": "2024-04-18 16:19:36" }, "https://github.com/mozman/ComfyUI_mozman_nodes": { "stars": 0, @@ -1593,19 +1593,19 @@ }, "https://github.com/IDGallagher/ComfyUI-IG-Nodes": { "stars": 0, - "last_update": "2024-02-04 03:37:05" + "last_update": "2024-04-15 15:09:48" }, "https://github.com/violet-chen/comfyui-psd2png": { - "stars": 4, + "stars": 5, "last_update": "2024-01-18 05:00:49" }, "https://github.com/lldacing/comfyui-easyapi-nodes": { "stars": 16, - "last_update": "2024-03-26 08:41:20" + "last_update": "2024-04-16 07:51:03" }, "https://github.com/CosmicLaca/ComfyUI_Primere_Nodes": { - "stars": 51, - "last_update": "2024-04-06 18:07:34" + "stars": 56, + "last_update": "2024-04-21 09:51:55" }, "https://github.com/RenderRift/ComfyUI-RenderRiftNodes": { "stars": 6, @@ -1616,23 +1616,23 @@ "last_update": "2024-01-24 21:44:12" }, "https://github.com/ttulttul/ComfyUI-Iterative-Mixer": { - "stars": 89, + "stars": 93, "last_update": "2024-04-09 00:15:26" }, "https://github.com/ttulttul/ComfyUI-Tensor-Operations": { - "stars": 3, + "stars": 4, "last_update": "2024-02-07 21:22:45" }, "https://github.com/jitcoder/lora-info": { - "stars": 20, - "last_update": "2024-01-28 15:09:51" + "stars": 24, + "last_update": "2024-04-18 09:16:05" }, "https://github.com/ceruleandeep/ComfyUI-LLaVA-Captioner": { - "stars": 54, + "stars": 60, "last_update": "2024-03-04 10:07:53" }, "https://github.com/styler00dollar/ComfyUI-sudo-latent-upscale": { - "stars": 18, + "stars": 19, "last_update": "2024-04-04 17:29:40" }, "https://github.com/styler00dollar/ComfyUI-deepcache": { @@ -1640,7 +1640,7 @@ "last_update": "2023-12-26 17:53:44" }, "https://github.com/NotHarroweD/Harronode": { - "stars": 4, + "stars": 5, "last_update": "2023-12-31 06:00:14" }, "https://github.com/Limitex/ComfyUI-Calculation": { @@ -1648,12 +1648,12 @@ "last_update": "2023-12-27 17:50:16" }, "https://github.com/Limitex/ComfyUI-Diffusers": { - "stars": 90, + "stars": 92, "last_update": "2024-03-08 11:07:01" }, "https://github.com/edenartlab/eden_comfy_pipelines": { - "stars": 23, - "last_update": "2024-03-18 05:40:42" + "stars": 26, + "last_update": "2024-04-17 01:06:53" }, "https://github.com/pkpkTech/ComfyUI-SaveAVIF": { "stars": 1, @@ -1672,19 +1672,19 @@ "last_update": "2024-02-17 14:26:26" }, "https://github.com/crystian/ComfyUI-Crystools": { - "stars": 323, - "last_update": "2024-03-27 16:59:44" + "stars": 351, + "last_update": "2024-04-20 03:03:23" }, "https://github.com/crystian/ComfyUI-Crystools-save": { "stars": 21, "last_update": "2024-01-28 14:37:54" }, "https://github.com/Kangkang625/ComfyUI-paint-by-example": { - "stars": 11, + "stars": 12, "last_update": "2024-01-29 02:37:38" }, "https://github.com/54rt1n/ComfyUI-DareMerge": { - "stars": 23, + "stars": 25, "last_update": "2024-01-29 23:23:01" }, "https://github.com/an90ray/ComfyUI_RErouter_CustomNodes": { @@ -1692,7 +1692,7 @@ "last_update": "2023-12-30 01:42:04" }, "https://github.com/jesenzhang/ComfyUI_StreamDiffusion": { - "stars": 89, + "stars": 90, "last_update": "2023-12-29 09:41:48" }, "https://github.com/ai-liam/comfyui_liam_util": { @@ -1700,15 +1700,15 @@ "last_update": "2023-12-29 04:44:00" }, "https://github.com/Ryuukeisyou/comfyui_face_parsing": { - "stars": 25, + "stars": 26, "last_update": "2024-02-17 11:00:34" }, "https://github.com/tocubed/ComfyUI-AudioReactor": { - "stars": 5, + "stars": 6, "last_update": "2024-01-02 07:51:03" }, "https://github.com/ntc-ai/ComfyUI-DARE-LoRA-Merge": { - "stars": 17, + "stars": 18, "last_update": "2024-01-05 03:38:18" }, "https://github.com/wwwins/ComfyUI-Simple-Aspect-Ratio": { @@ -1728,15 +1728,15 @@ "last_update": "2024-03-04 13:20:38" }, "https://github.com/flowtyone/ComfyUI-Flowty-LDSR": { - "stars": 135, + "stars": 142, "last_update": "2024-03-24 19:03:45" }, "https://github.com/flowtyone/ComfyUI-Flowty-TripoSR": { - "stars": 287, + "stars": 307, "last_update": "2024-03-19 10:49:59" }, "https://github.com/flowtyone/ComfyUI-Flowty-CRM": { - "stars": 95, + "stars": 102, "last_update": "2024-04-03 23:47:03" }, "https://github.com/massao000/ComfyUI_aspect_ratios": { @@ -1744,31 +1744,31 @@ "last_update": "2024-01-05 09:36:52" }, "https://github.com/siliconflow/onediff_comfy_nodes": { - "stars": 7, + "stars": 8, "last_update": "2024-04-08 04:23:57" }, "https://github.com/ZHO-ZHO-ZHO/ComfyUI-ArtGallery": { - "stars": 185, - "last_update": "2024-02-12 01:56:02" + "stars": 275, + "last_update": "2024-04-17 19:58:54" }, "https://github.com/hinablue/ComfyUI_3dPoseEditor": { - "stars": 89, + "stars": 91, "last_update": "2024-01-04 14:41:18" }, "https://github.com/chaojie/ComfyUI-AniPortrait": { - "stars": 184, + "stars": 211, "last_update": "2024-04-02 03:06:43" }, "https://github.com/chaojie/ComfyUI-Img2Img-Turbo": { - "stars": 32, + "stars": 33, "last_update": "2024-03-27 01:10:14" }, "https://github.com/chaojie/ComfyUI-Champ": { - "stars": 14, + "stars": 16, "last_update": "2024-04-02 02:46:02" }, "https://github.com/chaojie/ComfyUI-Open-Sora": { - "stars": 68, + "stars": 75, "last_update": "2024-03-26 05:54:18" }, "https://github.com/chaojie/ComfyUI-Trajectory": { @@ -1776,19 +1776,19 @@ "last_update": "2024-03-14 14:41:18" }, "https://github.com/chaojie/ComfyUI-dust3r": { - "stars": 10, - "last_update": "2024-03-31 00:30:51" + "stars": 12, + "last_update": "2024-04-23 01:47:18" }, "https://github.com/chaojie/ComfyUI-Gemma": { "stars": 5, "last_update": "2024-02-24 10:02:51" }, "https://github.com/chaojie/ComfyUI-DynamiCrafter": { - "stars": 73, + "stars": 84, "last_update": "2024-03-16 19:08:28" }, "https://github.com/chaojie/ComfyUI-Panda3d": { - "stars": 10, + "stars": 11, "last_update": "2024-03-05 06:37:32" }, "https://github.com/chaojie/ComfyUI-Pymunk": { @@ -1796,7 +1796,7 @@ "last_update": "2024-01-31 15:36:36" }, "https://github.com/chaojie/ComfyUI-MotionCtrl": { - "stars": 115, + "stars": 116, "last_update": "2024-01-08 14:18:40" }, "https://github.com/chaojie/ComfyUI-Motion-Vector-Extractor": { @@ -1804,23 +1804,23 @@ "last_update": "2024-01-20 16:51:06" }, "https://github.com/chaojie/ComfyUI-MotionCtrl-SVD": { - "stars": 69, + "stars": 72, "last_update": "2024-01-16 09:41:07" }, "https://github.com/chaojie/ComfyUI-DragAnything": { - "stars": 56, + "stars": 57, "last_update": "2024-03-19 03:37:48" }, "https://github.com/chaojie/ComfyUI-DragNUWA": { - "stars": 328, + "stars": 340, "last_update": "2024-03-14 06:56:41" }, "https://github.com/chaojie/ComfyUI-Moore-AnimateAnyone": { - "stars": 192, + "stars": 193, "last_update": "2024-02-24 13:48:57" }, "https://github.com/chaojie/ComfyUI-I2VGEN-XL": { - "stars": 22, + "stars": 27, "last_update": "2024-01-19 09:02:08" }, "https://github.com/chaojie/ComfyUI-LightGlue": { @@ -1828,43 +1828,43 @@ "last_update": "2024-01-20 16:53:51" }, "https://github.com/chaojie/ComfyUI-RAFT": { - "stars": 24, + "stars": 23, "last_update": "2024-01-29 08:08:13" }, "https://github.com/alexopus/ComfyUI-Image-Saver": { - "stars": 15, - "last_update": "2024-04-01 20:42:20" + "stars": 17, + "last_update": "2024-04-19 23:26:02" }, "https://github.com/kft334/Knodes": { - "stars": 0, + "stars": 1, "last_update": "2024-01-14 04:23:09" }, "https://github.com/MrForExample/ComfyUI-3D-Pack": { - "stars": 1288, - "last_update": "2024-04-01 13:51:02" + "stars": 1400, + "last_update": "2024-04-13 17:45:06" }, "https://github.com/MrForExample/ComfyUI-AnimateAnyone-Evolved": { - "stars": 384, + "stars": 391, "last_update": "2024-02-02 14:19:37" }, "https://github.com/Hangover3832/ComfyUI-Hangover-Nodes": { - "stars": 19, + "stars": 21, "last_update": "2024-04-06 11:02:44" }, "https://github.com/Hangover3832/ComfyUI-Hangover-Moondream": { - "stars": 22, - "last_update": "2024-04-02 13:24:56" + "stars": 26, + "last_update": "2024-04-21 13:02:21" }, "https://github.com/Hangover3832/ComfyUI-Hangover-Recognize_Anything": { - "stars": 6, + "stars": 8, "last_update": "2024-04-04 11:58:20" }, "https://github.com/tzwm/comfyui-profiler": { - "stars": 27, + "stars": 29, "last_update": "2024-01-12 07:38:40" }, "https://github.com/daniel-lewis-ab/ComfyUI-Llama": { - "stars": 19, + "stars": 21, "last_update": "2024-04-02 06:33:08" }, "https://github.com/daniel-lewis-ab/ComfyUI-TTS": { @@ -1872,7 +1872,7 @@ "last_update": "2024-04-02 06:32:21" }, "https://github.com/djbielejeski/a-person-mask-generator": { - "stars": 182, + "stars": 189, "last_update": "2024-02-16 16:26:02" }, "https://github.com/smagnetize/kb-comfyui-nodes": { @@ -1888,7 +1888,7 @@ "last_update": "2024-01-09 08:33:02" }, "https://github.com/AInseven/ComfyUI-fastblend": { - "stars": 79, + "stars": 83, "last_update": "2024-04-03 11:50:44" }, "https://github.com/HebelHuber/comfyui-enhanced-save-node": { @@ -1896,15 +1896,15 @@ "last_update": "2024-01-12 14:34:55" }, "https://github.com/LarryJane491/Lora-Training-in-Comfy": { - "stars": 164, + "stars": 180, "last_update": "2024-03-03 17:16:51" }, "https://github.com/LarryJane491/Image-Captioning-in-ComfyUI": { - "stars": 19, + "stars": 20, "last_update": "2024-03-08 19:59:00" }, "https://github.com/Layer-norm/comfyui-lama-remover": { - "stars": 36, + "stars": 40, "last_update": "2024-01-13 04:58:58" }, "https://github.com/Taremin/comfyui-prompt-extranetworks": { @@ -1928,7 +1928,7 @@ "last_update": "2024-02-18 23:17:53" }, "https://github.com/HAL41/ComfyUI-aichemy-nodes": { - "stars": 3, + "stars": 4, "last_update": "2024-01-15 22:25:46" }, "https://github.com/nkchocoai/ComfyUI-SizeFromPresets": { @@ -1944,16 +1944,16 @@ "last_update": "2024-02-12 06:05:47" }, "https://github.com/nkchocoai/ComfyUI-SaveImageWithMetaData": { - "stars": 1, - "last_update": "2024-03-30 04:12:19" + "stars": 2, + "last_update": "2024-04-16 13:28:45" }, "https://github.com/nkchocoai/ComfyUI-Dart": { - "stars": 10, + "stars": 15, "last_update": "2024-03-24 07:26:03" }, "https://github.com/JaredTherriault/ComfyUI-JNodes": { - "stars": 4, - "last_update": "2024-03-29 21:14:13" + "stars": 5, + "last_update": "2024-04-23 01:03:13" }, "https://github.com/prozacgod/comfyui-pzc-multiworkspace": { "stars": 6, @@ -1976,39 +1976,39 @@ "last_update": "2024-01-19 21:30:27" }, "https://github.com/JcandZero/ComfyUI_GLM4Node": { - "stars": 21, + "stars": 22, "last_update": "2024-02-21 01:48:08" }, "https://github.com/darkpixel/darkprompts": { "stars": 3, - "last_update": "2024-03-25 15:42:28" + "last_update": "2024-04-15 16:40:05" }, "https://github.com/shiimizu/ComfyUI-PhotoMaker-Plus": { - "stars": 128, - "last_update": "2024-02-16 01:18:34" + "stars": 133, + "last_update": "2024-04-17 09:02:51" }, "https://github.com/QaisMalkawi/ComfyUI-QaisHelper": { "stars": 0, "last_update": "2024-01-22 10:39:27" }, "https://github.com/longgui0318/comfyui-mask-util": { - "stars": 1, - "last_update": "2024-02-29 14:34:55" + "stars": 4, + "last_update": "2024-04-15 08:07:13" }, "https://github.com/longgui0318/comfyui-llm-assistant": { "stars": 4, "last_update": "2024-03-01 02:57:07" }, "https://github.com/longgui0318/comfyui-oms-diffusion": { - "stars": 4, - "last_update": "2024-04-09 08:35:53" + "stars": 7, + "last_update": "2024-04-23 10:02:21" }, "https://github.com/DimaChaichan/LAizypainter-Exporter-ComfyUI": { "stars": 7, "last_update": "2024-02-08 13:57:21" }, "https://github.com/adriflex/ComfyUI_Blender_Texdiff": { - "stars": 0, + "stars": 1, "last_update": "2024-01-26 10:25:05" }, "https://github.com/Shraknard/ComfyUI-Remover": { @@ -2016,11 +2016,11 @@ "last_update": "2024-01-23 23:14:23" }, "https://github.com/FlyingFireCo/tiled_ksampler": { - "stars": 52, + "stars": 54, "last_update": "2023-08-13 23:05:26" }, "https://github.com/Nlar/ComfyUI_CartoonSegmentation": { - "stars": 7, + "stars": 8, "last_update": "2024-01-25 23:17:51" }, "https://github.com/godspede/ComfyUI_Substring": { @@ -2028,19 +2028,19 @@ "last_update": "2024-01-26 06:28:40" }, "https://github.com/gokayfem/ComfyUI_VLM_nodes": { - "stars": 165, - "last_update": "2024-03-26 11:46:29" + "stars": 186, + "last_update": "2024-04-20 18:42:31" }, "https://github.com/gokayfem/ComfyUI-Dream-Interpreter": { - "stars": 50, + "stars": 57, "last_update": "2024-04-03 23:51:44" }, "https://github.com/gokayfem/ComfyUI-Depth-Visualization": { - "stars": 41, + "stars": 42, "last_update": "2024-03-24 04:03:08" }, "https://github.com/gokayfem/ComfyUI-Texture-Simple": { - "stars": 26, + "stars": 27, "last_update": "2024-03-24 22:20:21" }, "https://github.com/Hiero207/ComfyUI-Hiero-Nodes": { @@ -2052,15 +2052,15 @@ "last_update": "2024-01-26 08:38:39" }, "https://github.com/yuvraj108c/ComfyUI-Whisper": { - "stars": 20, + "stars": 24, "last_update": "2024-02-05 08:32:57" }, "https://github.com/blepping/ComfyUI-bleh": { - "stars": 17, - "last_update": "2024-04-06 20:40:50" + "stars": 21, + "last_update": "2024-04-15 22:33:44" }, "https://github.com/blepping/ComfyUI-sonar": { - "stars": 24, + "stars": 25, "last_update": "2024-04-05 18:57:04" }, "https://github.com/JerryOrbachJr/ComfyUI-RandomSize": { @@ -2072,19 +2072,19 @@ "last_update": "2024-01-27 15:25:00" }, "https://github.com/mape/ComfyUI-mape-Helpers": { - "stars": 81, + "stars": 92, "last_update": "2024-02-07 16:58:47" }, "https://github.com/zhongpei/Comfyui_image2prompt": { - "stars": 154, - "last_update": "2024-03-27 03:29:23" + "stars": 169, + "last_update": "2024-04-12 09:50:19" }, "https://github.com/zhongpei/ComfyUI-InstructIR": { "stars": 53, "last_update": "2024-02-01 06:40:40" }, "https://github.com/Loewen-Hob/rembg-comfyui-node-better": { - "stars": 21, + "stars": 25, "last_update": "2024-01-29 16:03:36" }, "https://github.com/HaydenReeve/ComfyUI-Better-Strings": { @@ -2092,7 +2092,7 @@ "last_update": "2024-04-04 17:27:11" }, "https://github.com/StartHua/ComfyUI_Seg_VITON": { - "stars": 141, + "stars": 146, "last_update": "2024-02-07 05:33:39" }, "https://github.com/StartHua/Comfyui_joytag": { @@ -2100,11 +2100,11 @@ "last_update": "2024-02-12 04:13:41" }, "https://github.com/StartHua/Comfyui_segformer_b2_clothes": { - "stars": 17, - "last_update": "2024-02-19 16:02:10" + "stars": 23, + "last_update": "2024-04-18 08:04:23" }, "https://github.com/StartHua/ComfyUI_OOTDiffusion_CXH": { - "stars": 72, + "stars": 81, "last_update": "2024-03-04 09:33:57" }, "https://github.com/ricklove/comfyui-ricklove": { @@ -2112,15 +2112,15 @@ "last_update": "2024-02-01 02:50:59" }, "https://github.com/nosiu/comfyui-instantId-faceswap": { - "stars": 137, + "stars": 146, "last_update": "2024-02-25 13:58:50" }, "https://github.com/LyazS/comfyui-anime-seg": { - "stars": 3, - "last_update": "2024-02-03 16:45:06" + "stars": 4, + "last_update": "2024-04-16 08:27:12" }, "https://github.com/Chan-0312/ComfyUI-IPAnimate": { - "stars": 52, + "stars": 55, "last_update": "2024-02-01 09:17:58" }, "https://github.com/Chan-0312/ComfyUI-EasyDeforum": { @@ -2136,8 +2136,8 @@ "last_update": "2024-02-08 16:59:15" }, "https://github.com/davask/ComfyUI-MarasIT-Nodes": { - "stars": 15, - "last_update": "2024-04-01 08:48:30" + "stars": 18, + "last_update": "2024-04-15 10:15:37" }, "https://github.com/yffyhk/comfyui_auto_danbooru": { "stars": 0, @@ -2148,12 +2148,12 @@ "last_update": "2024-02-05 17:48:33" }, "https://github.com/dfl/comfyui-tcd-scheduler": { - "stars": 56, + "stars": 66, "last_update": "2024-04-08 20:15:29" }, "https://github.com/MarkoCa1/ComfyUI_Segment_Mask": { - "stars": 7, - "last_update": "2024-03-16 06:37:47" + "stars": 9, + "last_update": "2024-04-20 07:29:00" }, "https://github.com/antrobot1234/antrobots-comfyUI-nodepack": { "stars": 8, @@ -2168,7 +2168,7 @@ "last_update": "2024-02-06 15:43:43" }, "https://github.com/digitaljohn/comfyui-propost": { - "stars": 86, + "stars": 94, "last_update": "2024-02-11 10:08:19" }, "https://github.com/DonBaronFactory/ComfyUI-Cre8it-Nodes": { @@ -2176,15 +2176,15 @@ "last_update": "2024-02-25 12:35:13" }, "https://github.com/XmYx/deforum-comfy-nodes": { - "stars": 66, - "last_update": "2024-03-21 11:08:54" + "stars": 80, + "last_update": "2024-04-11 00:45:00" }, "https://github.com/adbrasi/ComfyUI-TrashNodes-DownloadHuggingface": { "stars": 4, "last_update": "2024-02-08 21:25:17" }, "https://github.com/mbrostami/ComfyUI-HF": { - "stars": 7, + "stars": 8, "last_update": "2024-02-11 00:03:26" }, "https://github.com/Billius-AI/ComfyUI-Path-Helper": { @@ -2196,7 +2196,7 @@ "last_update": "2024-02-19 10:14:56" }, "https://github.com/xiaoxiaodesha/hd_node": { - "stars": 3, + "stars": 6, "last_update": "2024-02-18 05:23:57" }, "https://github.com/ShmuelRonen/ComfyUI-SVDResizer": { @@ -2204,15 +2204,15 @@ "last_update": "2024-03-08 15:16:10" }, "https://github.com/redhottensors/ComfyUI-Prediction": { - "stars": 7, + "stars": 8, "last_update": "2024-04-06 02:11:59" }, "https://github.com/Mamaaaamooooo/batchImg-rembg-ComfyUI-nodes": { - "stars": 9, + "stars": 11, "last_update": "2024-04-02 12:00:48" }, "https://github.com/jordoh/ComfyUI-Deepface": { - "stars": 8, + "stars": 9, "last_update": "2024-03-23 14:37:34" }, "https://github.com/yuvraj108c/ComfyUI-Pronodes": { @@ -2228,8 +2228,8 @@ "last_update": "2024-04-02 09:26:29" }, "https://github.com/mirabarukaso/ComfyUI_Mira": { - "stars": 5, - "last_update": "2024-04-06 14:54:11" + "stars": 6, + "last_update": "2024-04-10 12:24:38" }, "https://github.com/1038lab/ComfyUI-GPT2P": { "stars": 3, @@ -2241,14 +2241,14 @@ }, "https://github.com/klinter007/klinter_nodes": { "stars": 2, - "last_update": "2024-03-26 02:58:49" + "last_update": "2024-04-22 06:04:25" }, "https://github.com/Ludobico/ComfyUI-ScenarioPrompt": { "stars": 12, "last_update": "2024-03-26 01:28:07" }, "https://github.com/logtd/ComfyUI-InstanceDiffusion": { - "stars": 20, + "stars": 22, "last_update": "2024-03-31 19:06:57" }, "https://github.com/logtd/ComfyUI-TrackingNodes": { @@ -2264,27 +2264,27 @@ "last_update": "2024-03-31 02:11:14" }, "https://github.com/logtd/ComfyUI-FLATTEN": { - "stars": 48, - "last_update": "2024-04-01 01:14:36" + "stars": 52, + "last_update": "2024-04-10 01:46:26" }, "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay": { "stars": 4, - "last_update": "2024-02-26 15:43:54" + "last_update": "2024-04-19 14:21:28" }, "https://github.com/Big-Idea-Technology/ComfyUI_LLM_Node": { - "stars": 28, - "last_update": "2024-03-29 07:06:45" + "stars": 37, + "last_update": "2024-04-22 22:56:16" }, "https://github.com/Guillaume-Fgt/ComfyUI_StableCascadeLatentRatio": { "stars": 3, "last_update": "2024-02-26 09:37:16" }, "https://github.com/AuroBit/ComfyUI-OOTDiffusion": { - "stars": 236, + "stars": 273, "last_update": "2024-03-26 02:44:57" }, "https://github.com/AuroBit/ComfyUI-AnimateAnyone-reproduction": { - "stars": 32, + "stars": 34, "last_update": "2024-02-29 10:19:36" }, "https://github.com/czcz1024/Comfyui-FaceCompare": { @@ -2304,7 +2304,7 @@ "last_update": "2024-02-24 21:41:24" }, "https://github.com/jkrauss82/ultools-comfyui": { - "stars": 1, + "stars": 4, "last_update": "2024-03-31 08:27:34" }, "https://github.com/hiforce/comfyui-hiforce-plugin": { @@ -2320,7 +2320,7 @@ "last_update": "2024-02-26 04:25:21" }, "https://github.com/cerspense/ComfyUI_cspnodes": { - "stars": 17, + "stars": 21, "last_update": "2024-03-23 14:40:21" }, "https://github.com/qwixiwp/queuetools": { @@ -2328,7 +2328,7 @@ "last_update": "2024-02-26 19:21:00" }, "https://github.com/Chan-0312/ComfyUI-Prompt-Preview": { - "stars": 11, + "stars": 12, "last_update": "2024-02-27 11:30:38" }, "https://github.com/Munkyfoot/ComfyUI-TextOverlay": { @@ -2340,11 +2340,11 @@ "last_update": "2024-03-02 05:43:41" }, "https://github.com/Alysondao/Comfyui-Yolov8-JSON": { - "stars": 8, - "last_update": "2024-03-04 07:34:39" + "stars": 9, + "last_update": "2024-04-16 08:29:55" }, "https://github.com/CC-BryanOttho/ComfyUI_API_Manager": { - "stars": 4, + "stars": 5, "last_update": "2024-02-27 23:31:45" }, "https://github.com/maracman/ComfyUI-SubjectStyle-CSV": { @@ -2352,31 +2352,31 @@ "last_update": "2024-02-29 19:40:01" }, "https://github.com/438443467/ComfyUI-GPT4V-Image-Captioner": { - "stars": 11, - "last_update": "2024-04-03 15:54:14" + "stars": 13, + "last_update": "2024-04-21 10:05:37" }, "https://github.com/uetuluk/comfyui-webcam-node": { "stars": 0, "last_update": "2024-03-01 07:25:27" }, "https://github.com/huchenlei/ComfyUI-layerdiffuse": { - "stars": 995, + "stars": 1075, "last_update": "2024-03-09 21:16:31" }, "https://github.com/huchenlei/ComfyUI_DanTagGen": { - "stars": 34, + "stars": 39, "last_update": "2024-03-23 19:40:34" }, "https://github.com/nathannlu/ComfyUI-Pets": { - "stars": 31, + "stars": 34, "last_update": "2024-03-31 23:55:42" }, "https://github.com/nathannlu/ComfyUI-Cloud": { - "stars": 108, + "stars": 112, "last_update": "2024-04-03 00:59:21" }, "https://github.com/11dogzi/Comfyui-ergouzi-Nodes": { - "stars": 4, + "stars": 6, "last_update": "2024-03-12 02:03:09" }, "https://github.com/BXYMartin/ComfyUI-InstantIDUtils": { @@ -2388,11 +2388,11 @@ "last_update": "2024-03-07 07:35:43" }, "https://github.com/cdb-boop/ComfyUI-Bringing-Old-Photos-Back-to-Life": { - "stars": 4, - "last_update": "2024-03-27 21:37:34" + "stars": 8, + "last_update": "2024-04-18 18:49:15" }, "https://github.com/atmaranto/ComfyUI-SaveAsScript": { - "stars": 6, + "stars": 10, "last_update": "2024-03-20 08:47:51" }, "https://github.com/meshmesh-io/mm-comfyui-megamask": { @@ -2408,11 +2408,11 @@ "last_update": "2024-03-12 17:19:32" }, "https://github.com/cozymantis/human-parser-comfyui-node": { - "stars": 24, + "stars": 31, "last_update": "2024-04-02 20:04:32" }, "https://github.com/cozymantis/pose-generator-comfyui-node": { - "stars": 10, + "stars": 13, "last_update": "2024-03-13 14:59:23" }, "https://github.com/cozymantis/cozy-utils-comfyui-nodes": { @@ -2432,7 +2432,7 @@ "last_update": "2024-03-24 21:52:17" }, "https://github.com/diStyApps/ComfyUI_FrameMaker": { - "stars": 8, + "stars": 9, "last_update": "2024-03-08 09:19:43" }, "https://github.com/hackkhai/ComfyUI-Image-Matting": { @@ -2440,31 +2440,31 @@ "last_update": "2024-03-09 06:30:39" }, "https://github.com/Pos13/comfyui-cyclist": { - "stars": 8, - "last_update": "2024-03-23 17:33:44" + "stars": 13, + "last_update": "2024-04-20 04:13:22" }, "https://github.com/ExponentialML/ComfyUI_ModelScopeT2V": { - "stars": 17, + "stars": 25, "last_update": "2024-03-09 00:02:47" }, "https://github.com/ExponentialML/ComfyUI_Native_DynamiCrafter": { - "stars": 63, + "stars": 76, "last_update": "2024-04-02 23:29:14" }, "https://github.com/ExponentialML/ComfyUI_VisualStylePrompting": { - "stars": 204, - "last_update": "2024-04-07 21:29:06" + "stars": 216, + "last_update": "2024-04-17 22:30:10" }, "https://github.com/angeloshredder/StableCascadeResizer": { "stars": 0, "last_update": "2024-03-08 22:53:27" }, "https://github.com/stavsap/comfyui-ollama": { - "stars": 18, + "stars": 40, "last_update": "2024-04-07 20:49:11" }, "https://github.com/dchatel/comfyui_facetools": { - "stars": 13, + "stars": 33, "last_update": "2024-04-06 11:45:55" }, "https://github.com/prodogape/ComfyUI-Minio": { @@ -2488,11 +2488,11 @@ "last_update": "2024-03-13 08:26:09" }, "https://github.com/if-ai/ComfyUI-IF_AI_tools": { - "stars": 91, - "last_update": "2024-04-07 08:43:30" + "stars": 148, + "last_update": "2024-04-21 02:21:23" }, "https://github.com/dmMaze/sketch2manga": { - "stars": 11, + "stars": 21, "last_update": "2024-03-14 05:44:16" }, "https://github.com/olduvai-jp/ComfyUI-HfLoader": { @@ -2504,8 +2504,8 @@ "last_update": "2024-03-31 14:14:24" }, "https://github.com/ForeignGods/ComfyUI-Mana-Nodes": { - "stars": 137, - "last_update": "2024-04-02 19:58:05" + "stars": 144, + "last_update": "2024-04-22 11:26:32" }, "https://github.com/madtunebk/ComfyUI-ControlnetAux": { "stars": 7, @@ -2524,23 +2524,23 @@ "last_update": "2024-03-28 02:21:05" }, "https://github.com/Jannchie/ComfyUI-J": { - "stars": 50, - "last_update": "2024-03-24 06:35:19" + "stars": 52, + "last_update": "2024-04-21 17:21:53" }, "https://github.com/daxcay/ComfyUI-JDCN": { - "stars": 3, - "last_update": "2024-03-30 19:14:48" + "stars": 7, + "last_update": "2024-04-19 18:37:18" }, "https://github.com/Seedsa/Fooocus_Nodes": { - "stars": 17, - "last_update": "2024-03-28 07:37:38" + "stars": 21, + "last_update": "2024-04-13 12:38:56" }, "https://github.com/zhangp365/ComfyUI-utils-nodes": { - "stars": 1, - "last_update": "2024-04-07 09:53:27" + "stars": 2, + "last_update": "2024-04-16 02:02:15" }, "https://github.com/ratulrafsan/Comfyui-SAL-VTON": { - "stars": 18, + "stars": 25, "last_update": "2024-03-22 04:31:59" }, "https://github.com/Nevysha/ComfyUI-nevysha-top-menu": { @@ -2548,19 +2548,19 @@ "last_update": "2024-03-23 10:48:36" }, "https://github.com/alisson-anjos/ComfyUI-LLaVA-Describer": { - "stars": 9, + "stars": 13, "last_update": "2024-03-31 15:13:33" }, "https://github.com/chaosaiart/Chaosaiart-Nodes": { - "stars": 10, - "last_update": "2024-03-31 12:41:40" + "stars": 29, + "last_update": "2024-04-22 00:50:39" }, "https://github.com/viperyl/ComfyUI-BiRefNet": { - "stars": 112, + "stars": 127, "last_update": "2024-03-25 11:02:49" }, "https://github.com/SuperBeastsAI/ComfyUI-SuperBeasts": { - "stars": 65, + "stars": 73, "last_update": "2024-04-07 23:49:52" }, "https://github.com/IKHOR/ComfyUI-IKHOR-Jam-Nodes": { @@ -2568,64 +2568,64 @@ "last_update": "2024-03-26 16:55:10" }, "https://github.com/yuvraj108c/ComfyUI-Depth-Anything-Tensorrt": { - "stars": 25, + "stars": 30, "last_update": "2024-04-07 10:43:50" }, "https://github.com/hay86/ComfyUI_Dreamtalk": { - "stars": 1, - "last_update": "2024-04-02 04:15:50" + "stars": 3, + "last_update": "2024-04-12 09:13:05" }, "https://github.com/shinich39/comfyui-load-image-39": { - "stars": 1, + "stars": 2, "last_update": "2024-04-07 14:38:17" }, "https://github.com/shinich39/comfyui-ramdom-node-39": { "stars": 2, - "last_update": "2024-04-03 00:23:18" + "last_update": "2024-04-23 06:09:43" }, "https://github.com/wei30172/comfygen": { "stars": 3, "last_update": "2024-04-06 16:22:09" }, "https://github.com/zombieyang/sd-ppp": { - "stars": 3, - "last_update": "2024-03-30 03:24:34" + "stars": 5, + "last_update": "2024-04-23 10:36:59" }, "https://github.com/KytraScript/ComfyUI_KytraWebhookHTTP": { "stars": 3, "last_update": "2024-03-29 06:08:53" }, "https://github.com/1mckw/Comfyui-Gelbooru": { - "stars": 1, + "stars": 2, "last_update": "2024-03-29 04:22:07" }, "https://github.com/NeuralSamurAI/Comfyui-Superprompt-Unofficial": { - "stars": 31, + "stars": 44, "last_update": "2024-03-30 22:07:58" }, "https://github.com/MokkaBoss1/ComfyUI_Mokkaboss1": { - "stars": 3, - "last_update": "2024-04-07 21:57:16" + "stars": 5, + "last_update": "2024-04-22 15:52:18" }, "https://github.com/jiaxiangc/ComfyUI-ResAdapter": { - "stars": 228, + "stars": 243, "last_update": "2024-04-06 09:25:46" }, "https://github.com/ParisNeo/lollms_nodes_suite": { - "stars": 6, - "last_update": "2024-04-07 02:26:00" + "stars": 9, + "last_update": "2024-04-15 00:17:38" }, "https://github.com/IsItDanOrAi/ComfyUI-Stereopsis": { "stars": 2, "last_update": "2024-03-20 21:56:10" }, "https://github.com/frankchieng/ComfyUI_Aniportrait": { - "stars": 14, - "last_update": "2024-04-09 07:21:34" + "stars": 23, + "last_update": "2024-04-22 05:53:26" }, "https://github.com/BlakeOne/ComfyUI-SchedulerMixer": { - "stars": 6, - "last_update": "2024-04-03 01:52:00" + "stars": 7, + "last_update": "2024-04-21 17:12:56" }, "https://github.com/kale4eat/ComfyUI-path-util": { "stars": 0, @@ -2640,131 +2640,383 @@ "last_update": "2024-04-01 01:32:04" }, "https://github.com/kijai/ComfyUI-APISR": { - "stars": 43, - "last_update": "2024-04-01 21:37:50" + "stars": 49, + "last_update": "2024-04-19 16:38:57" }, "https://github.com/DrMWeigand/ComfyUI_ColorImageDetection": { "stars": 0, "last_update": "2024-04-01 10:47:39" }, "https://github.com/comfyanonymous/ComfyUI": { - "stars": 31197, - "last_update": "2024-04-09 10:11:08" + "stars": 32897, + "last_update": "2024-04-22 22:52:47" }, "https://github.com/chaojie/ComfyUI-MuseV": { - "stars": 45, + "stars": 78, "last_update": "2024-04-04 02:07:29" }, "https://github.com/kijai/ComfyUI-DiffusionLight": { - "stars": 40, + "stars": 43, "last_update": "2024-04-02 19:18:34" }, "https://github.com/BlakeOne/ComfyUI-CustomScheduler": { - "stars": 5, - "last_update": "2024-04-03 03:55:59" + "stars": 7, + "last_update": "2024-04-21 17:11:38" }, "https://github.com/bobmagicii/comfykit-custom-nodes": { "stars": 0, "last_update": "2024-04-04 16:39:56" }, "https://github.com/chaojie/ComfyUI-MuseTalk": { - "stars": 39, + "stars": 59, "last_update": "2024-04-05 15:26:14" }, "https://github.com/bvhari/ComfyUI_SUNoise": { - "stars": 1, - "last_update": "2024-04-05 06:07:22" + "stars": 3, + "last_update": "2024-04-16 17:44:31" }, "https://github.com/TJ16th/comfyUI_TJ_NormalLighting": { - "stars": 87, + "stars": 108, "last_update": "2024-04-07 12:46:36" }, "https://github.com/SoftMeng/ComfyUI_ImageToText": { - "stars": 2, + "stars": 3, "last_update": "2024-04-07 07:27:14" }, "https://github.com/AppleBotzz/ComfyUI_LLMVISION": { - "stars": 32, + "stars": 39, "last_update": "2024-04-05 23:55:41" }, "https://github.com/A4P7J1N7M05OT/ComfyUI-PixelOE": { - "stars": 3, - "last_update": "2024-04-07 09:02:36" + "stars": 5, + "last_update": "2024-04-20 18:40:33" }, "https://github.com/SLAPaper/ComfyUI-dpmpp_2m_alt-Sampler": { "stars": 0, - "last_update": "2024-04-06 06:20:14" + "last_update": "2024-04-21 15:57:28" }, "https://github.com/yuvraj108c/ComfyUI-PiperTTS": { - "stars": 14, + "stars": 15, "last_update": "2024-04-06 17:16:28" }, "https://github.com/nickve28/ComfyUI-Nich-Utils": { - "stars": 2, - "last_update": "2024-04-09 05:19:37" + "stars": 5, + "last_update": "2024-04-21 09:13:50" }, "https://github.com/al-swaiti/ComfyUI-CascadeResolutions": { - "stars": 0, + "stars": 1, "last_update": "2024-04-06 16:48:55" }, "https://github.com/ronniebasak/ComfyUI-Tara-LLM-Integration": { - "stars": 33, - "last_update": "2024-04-09 08:16:38" + "stars": 51, + "last_update": "2024-04-20 05:00:41" }, "https://github.com/hay86/ComfyUI_AceNodes": { - "stars": 0, - "last_update": "2024-04-09 10:16:43" + "stars": 3, + "last_update": "2024-04-22 06:06:50" }, "https://github.com/shinich39/comfyui-text-pipe-39": { - "stars": 1, + "stars": 2, "last_update": "2024-04-07 15:11:16" }, "https://github.com/liusida/ComfyUI-Debug": { - "stars": 4, + "stars": 5, "last_update": "2024-04-07 11:33:02" }, "https://github.com/jtydhr88/ComfyUI-Workflow-Encrypt": { - "stars": 4, + "stars": 7, "last_update": "2024-04-07 02:47:17" }, "https://github.com/Zuellni/ComfyUI-ExLlama-Nodes": { - "stars": 79, - "last_update": "2024-04-08 01:03:56" + "stars": 83, + "last_update": "2024-04-22 16:30:33" }, "https://github.com/chaojie/ComfyUI-Open-Sora-Plan": { - "stars": 16, - "last_update": "2024-04-09 00:51:04" + "stars": 42, + "last_update": "2024-04-23 08:01:58" }, "https://github.com/SeaArtLab/ComfyUI-Long-CLIP": { - "stars": 6, + "stars": 22, "last_update": "2024-04-08 11:29:40" }, "https://github.com/tsogzark/ComfyUI-load-image-from-url": { - "stars": 0, - "last_update": "2024-04-08 10:01:40" + "stars": 1, + "last_update": "2024-04-16 09:07:22" }, "https://github.com/discus0434/comfyui-caching-embeddings": { - "stars": 0, + "stars": 1, "last_update": "2024-04-09 03:52:05" }, "https://github.com/abdozmantar/ComfyUI-InstaSwap": { - "stars": 28, - "last_update": "2024-04-07 22:43:03" + "stars": 33, + "last_update": "2024-04-22 11:02:28" }, "https://github.com/chaojie/ComfyUI_StreamingT2V": { - "stars": 6, - "last_update": "2024-04-09 09:39:05" + "stars": 17, + "last_update": "2024-04-16 01:07:14" }, "https://github.com/AIFSH/ComfyUI-UVR5": { - "stars": 8, - "last_update": "2024-04-09 02:13:10" + "stars": 30, + "last_update": "2024-04-17 08:51:51" }, "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler": { - "stars": 5, - "last_update": "2024-04-09 01:41:48" + "stars": 10, + "last_update": "2024-04-11 06:02:15" }, "https://github.com/sdfxai/SDFXBridgeForComfyUI": { + "stars": 2, + "last_update": "2024-04-12 14:09:45" + }, + "https://github.com/smthemex/ComfyUI_ChatGLM_API": { + "stars": 7, + "last_update": "2024-04-11 07:38:35" + }, + "https://github.com/kijai/ComfyUI-ELLA-wrapper": { + "stars": 84, + "last_update": "2024-04-19 16:36:43" + }, + "https://github.com/ExponentialML/ComfyUI_ELLA": { + "stars": 140, + "last_update": "2024-04-17 17:18:08" + }, + "https://github.com/choey/Comfy-Topaz": { + "stars": 10, + "last_update": "2024-04-10 09:05:18" + }, + "https://github.com/ALatentPlace/ComfyUI_yanc": { + "stars": 3, + "last_update": "2024-04-16 19:03:34" + }, + "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper": { + "stars": 13, + "last_update": "2024-04-11 15:56:49" + }, + "https://github.com/logtd/ComfyUI-RAVE_ATTN": { + "stars": 7, + "last_update": "2024-04-10 22:20:21" + }, + "https://github.com/BlakeOne/ComfyUI-NodePresets": { + "stars": 5, + "last_update": "2024-04-21 17:11:04" + }, + "https://github.com/AIFSH/ComfyUI-IP_LAP": { + "stars": 12, + "last_update": "2024-04-21 00:05:43" + }, + "https://github.com/Wicloz/ComfyUI-Simply-Nodes": { "stars": 1, - "last_update": "2024-04-09 11:11:06" + "last_update": "2024-04-11 01:32:57" + }, + "https://github.com/wandbrandon/comfyui-pixel": { + "stars": 3, + "last_update": "2024-04-10 22:23:36" + }, + "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit": { + "stars": 2, + "last_update": "2024-04-11 06:20:34" + }, + "https://github.com/nullquant/ComfyUI-BrushNet": { + "stars": 95, + "last_update": "2024-04-18 18:01:47" + }, + "https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler": { + "stars": 108, + "last_update": "2024-04-19 18:26:41" + }, + "https://github.com/pamparamm/sd-perturbed-attention": { + "stars": 117, + "last_update": "2024-04-21 19:38:43" + }, + "https://github.com/kijai/ComfyUI-BrushNet-Wrapper": { + "stars": 60, + "last_update": "2024-04-21 09:45:44" + }, + "https://github.com/unwdef/unwdef-nodes-comfyui": { + "stars": 1, + "last_update": "2024-04-15 19:32:36" + }, + "https://github.com/smthemex/ComfyUI_ParlerTTS": { + "stars": 10, + "last_update": "2024-04-20 03:29:59" + }, + "https://github.com/aburahamu/ComfyUI-RequestsPoster": { + "stars": 1, + "last_update": "2024-04-21 02:35:06" + }, + "https://github.com/AIFSH/ComfyUI-GPT_SoVITS": { + "stars": 83, + "last_update": "2024-04-22 08:52:17" + }, + "https://github.com/royceschultz/ComfyUI-TranscriptionTools": { + "stars": 6, + "last_update": "2024-04-22 03:51:58" + }, + "https://github.com/BlakeOne/ComfyUI-NodeDefaults": { + "stars": 1, + "last_update": "2024-04-21 17:10:35" + }, + "https://github.com/liusida/ComfyUI-Login": { + "stars": 13, + "last_update": "2024-04-22 08:15:19" + }, + "https://github.com/Sorcerio/MBM-Music-Visualizer": { + "stars": 7, + "last_update": "2024-04-19 23:35:24" + }, + "https://github.com/traugdor/ComfyUI-quadMoons-nodes": { + "stars": 5, + "last_update": "2024-04-20 01:40:50" + }, + "https://github.com/e7mac/ComfyUI-ShadertoyGL": { + "stars": 2, + "last_update": "2024-04-13 22:29:24" + }, + "https://github.com/turkyden/ComfyUI-Sticker": { + "stars": 0, + "last_update": "2024-04-16 10:00:26" + }, + "https://github.com/kunieone/ComfyUI_alkaid": { + "stars": 0, + "last_update": "2024-04-15 07:49:55" + }, + "https://github.com/jtydhr88/ComfyUI-InstantMesh": { + "stars": 88, + "last_update": "2024-04-17 03:15:10" + }, + "https://github.com/txt2any/ComfyUI-PromptOrganizer": { + "stars": 0, + "last_update": "2024-04-15 21:14:54" + }, + "https://github.com/kealiu/ComfyUI-S3-Tools": { + "stars": 0, + "last_update": "2024-04-14 12:45:49" + }, + "https://github.com/chaojie/ComfyUI-EasyAnimate": { + "stars": 35, + "last_update": "2024-04-16 14:45:13" + }, + "https://github.com/hay86/ComfyUI_OpenVoice": { + "stars": 0, + "last_update": "2024-04-18 12:35:11" + }, + "https://github.com/hay86/ComfyUI_DDColor": { + "stars": 0, + "last_update": "2024-04-17 14:38:22" + }, + "https://github.com/forever22777/comfyui-self-guidance": { + "stars": 4, + "last_update": "2024-04-22 06:40:09" + }, + "https://github.com/smthemex/ComfyUI_Pic2Story": { + "stars": 2, + "last_update": "2024-04-21 11:18:29" + }, + "https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM": { + "stars": 0, + "last_update": "2024-04-15 23:04:31" + }, + "https://github.com/AonekoSS/ComfyUI-SimpleCounter": { + "stars": 0, + "last_update": "2024-04-15 16:21:16" + }, + "https://github.com/heshengtao/comfyui_LLM_party": { + "stars": 10, + "last_update": "2024-04-23 09:28:15" + }, + "https://github.com/frankchieng/ComfyUI_MagicClothing": { + "stars": 238, + "last_update": "2024-04-22 20:48:26" + }, + "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH": { + "stars": 1, + "last_update": "2024-04-17 08:45:20" + }, + "https://github.com/JettHu/ComfyUI_TGate": { + "stars": 18, + "last_update": "2024-04-19 07:59:28" + }, + "https://github.com/VAST-AI-Research/ComfyUI-Tripo": { + "stars": 32, + "last_update": "2024-04-18 11:37:22" + }, + "https://github.com/Stability-AI/ComfyUI-SAI_API": { + "stars": 17, + "last_update": "2024-04-21 07:17:27" + }, + "https://github.com/chaojie/ComfyUI-CameraCtrl": { + "stars": 9, + "last_update": "2024-04-19 03:46:18" + }, + "https://github.com/sugarkwork/comfyui_tag_fillter": { + "stars": 1, + "last_update": "2024-04-18 06:37:21" + }, + "https://github.com/hay86/ComfyUI_MiniCPM-V": { + "stars": 0, + "last_update": "2024-04-18 13:11:09" + }, + "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite": { + "stars": 1, + "last_update": "2024-04-21 07:34:21" + }, + "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper": { + "stars": 9, + "last_update": "2024-04-19 03:46:18" + }, + "https://github.com/turkyden/ComfyUI-Comic": { + "stars": 0, + "last_update": "2024-04-23 07:10:04" + }, + "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes": { + "stars": 2, + "last_update": "2024-04-22 06:23:29" + }, + "https://github.com/TencentQQGYLab/ComfyUI-ELLA": { + "stars": 100, + "last_update": "2024-04-22 08:06:55" + }, + "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools": { + "stars": 6, + "last_update": "2024-04-22 15:25:03" + }, + "https://github.com/kijai/ComfyUI-APISR-KJ": { + "stars": 49, + "last_update": "2024-04-19 16:38:57" + }, + "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode": { + "stars": 8, + "last_update": "2024-04-19 10:52:02" + }, + "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config": { + "stars": 1, + "last_update": "2024-04-20 13:27:26" + }, + "https://github.com/BlakeOne/ComfyUI-NodeReset": { + "stars": 1, + "last_update": "2024-04-21 17:10:35" + }, + "https://github.com/Fannovel16/ComfyUI-MagickWand": { + "stars": 30, + "last_update": "2024-04-22 13:33:13" + }, + "https://github.com/AIFSH/ComfyUI-WhisperX": { + "stars": 4, + "last_update": "2024-04-22 08:45:58" + }, + "https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ": { + "stars": 3, + "last_update": "2024-04-22 19:05:01" + }, + "https://github.com/blueraincoatli/comfyUI_SillyNodes": { + "stars": 2, + "last_update": "2024-04-22 14:05:41" + }, + "https://github.com/chaojie/ComfyUI-LaVIT": { + "stars": 2, + "last_update": "2024-04-23 01:30:42" + }, + "https://github.com/smthemex/ComfyUI_Pipeline_Tool": { + "stars": 1, + "last_update": "2024-04-23 10:31:37" } } \ No newline at end of file diff --git a/glob/manager_core.py b/glob/manager_core.py new file mode 100644 index 00000000..2aa189bf --- /dev/null +++ b/glob/manager_core.py @@ -0,0 +1,951 @@ +import os +import sys +import subprocess +import re +import shutil +import configparser +import platform +from datetime import datetime +import git +from git.remote import RemoteProgress +from urllib.parse import urlparse +from tqdm.auto import tqdm +import aiohttp +import threading +import json +import time + +glob_path = os.path.join(os.path.dirname(__file__)) # ComfyUI-Manager/glob +sys.path.append(glob_path) + +import cm_global +from manager_util import * + +version = [2, 22, 1] +version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '') + +comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, '..')) +comfy_path = os.path.abspath(os.path.join(custom_nodes_path, '..')) +channel_list_path = os.path.join(comfyui_manager_path, 'channels.list') +config_path = os.path.join(comfyui_manager_path, "config.ini") +startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts") +git_script_path = os.path.join(comfyui_manager_path, "git_helper.py") +cache_dir = os.path.join(comfyui_manager_path, '.cache') +cached_config = None +js_path = None + +comfy_ui_required_revision = 1930 +comfy_ui_required_commit_datetime = datetime(2024, 1, 24, 0, 0, 0) + +comfy_ui_revision = "Unknown" +comfy_ui_commit_datetime = datetime(1900, 1, 1, 0, 0, 0) + + +cache_lock = threading.Lock() + + +channel_dict = None +channel_list = None +pip_map = None + + +def remap_pip_package(pkg): + if pkg in cm_global.pip_overrides: + res = cm_global.pip_overrides[pkg] + print(f"[ComfyUI-Manager] '{pkg}' is remapped to '{res}'") + return res + else: + return pkg + + +def get_installed_packages(): + global pip_map + + if pip_map is None: + try: + result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True) + + pip_map = {} + for line in result.split('\n'): + x = line.strip() + if x: + y = line.split() + if y[0] == 'Package' or y[0].startswith('-'): + continue + + pip_map[y[0]] = y[1] + except subprocess.CalledProcessError as e: + print(f"[ComfyUI-Manager] Failed to retrieve the information of installed pip packages.") + return set() + + return pip_map + + +def clear_pip_cache(): + global pip_map + pip_map = None + + +def is_blacklisted(name): + name = name.strip() + + pattern = r'([^<>!=]+)([<>!=]=?)(.*)' + match = re.search(pattern, name) + + if match: + name = match.group(1) + + if name in cm_global.pip_downgrade_blacklist: + pips = get_installed_packages() + + if match is None: + if name in pips: + return True + elif match.group(2) in ['<=', '==', '<']: + if name in pips: + if StrictVersion(pips[name]) >= StrictVersion(match.group(3)): + return True + + return False + + +def is_installed(name): + name = name.strip() + + if name.startswith('#'): + return True + + pattern = r'([^<>!=]+)([<>!=]=?)(.*)' + match = re.search(pattern, name) + + if match: + name = match.group(1) + + if name in cm_global.pip_downgrade_blacklist: + pips = get_installed_packages() + + if match is None: + if name in pips: + return True + elif match.group(2) in ['<=', '==', '<']: + if name in pips: + if StrictVersion(pips[name]) >= StrictVersion(match.group(3)): + print(f"[ComfyUI-Manager] skip black listed pip installation: '{name}'") + return True + + return name.lower() in get_installed_packages() + + +def get_channel_dict(): + global channel_dict + + if channel_dict is None: + channel_dict = {} + + if not os.path.exists(channel_list_path): + shutil.copy(channel_list_path+'.template', channel_list_path) + + with open(os.path.join(comfyui_manager_path, 'channels.list'), 'r') as file: + channels = file.read() + for x in channels.split('\n'): + channel_info = x.split("::") + if len(channel_info) == 2: + channel_dict[channel_info[0]] = channel_info[1] + + return channel_dict + + +def get_channel_list(): + global channel_list + + if channel_list is None: + channel_list = [] + for k, v in get_channel_dict().items(): + channel_list.append(f"{k}::{v}") + + return channel_list + + +class ManagerFuncs: + def __init__(self): + pass + + def get_current_preview_method(self): + return "none" + + def run_script(self, cmd, cwd='.'): + if len(cmd) > 0 and cmd[0].startswith("#"): + print(f"[ComfyUI-Manager] Unexpected behavior: `{cmd}`") + return 0 + + out = subprocess.check_call(cmd, cwd=cwd) + print(out) + + return 0 + + +manager_funcs = ManagerFuncs() + + +def write_config(): + config = configparser.ConfigParser() + config['default'] = { + 'preview_method': manager_funcs.get_current_preview_method(), + 'badge_mode': get_config()['badge_mode'], + 'git_exe': get_config()['git_exe'], + 'channel_url': get_config()['channel_url'], + 'share_option': get_config()['share_option'], + 'bypass_ssl': get_config()['bypass_ssl'], + "file_logging": get_config()['file_logging'], + 'default_ui': get_config()['default_ui'], + 'component_policy': get_config()['component_policy'], + 'double_click_policy': get_config()['double_click_policy'], + 'windows_selector_event_loop_policy': get_config()['windows_selector_event_loop_policy'], + 'model_download_by_agent': get_config()['model_download_by_agent'], + 'downgrade_blacklist': get_config()['downgrade_blacklist'] + } + with open(config_path, 'w') as configfile: + config.write(configfile) + + +def read_config(): + try: + config = configparser.ConfigParser() + config.read(config_path) + default_conf = config['default'] + + return { + 'preview_method': default_conf['preview_method'] if 'preview_method' in default_conf else manager_funcs.get_current_preview_method(), + 'badge_mode': default_conf['badge_mode'] if 'badge_mode' in default_conf else 'none', + 'git_exe': default_conf['git_exe'] if 'git_exe' in default_conf else '', + 'channel_url': default_conf['channel_url'] if 'channel_url' in default_conf else 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main', + 'share_option': default_conf['share_option'] if 'share_option' in default_conf else 'all', + 'bypass_ssl': default_conf['bypass_ssl'] if 'bypass_ssl' in default_conf else False, + 'file_logging': default_conf['file_logging'] if 'file_logging' in default_conf else True, + 'default_ui': default_conf['default_ui'] if 'default_ui' in default_conf else 'none', + 'component_policy': default_conf['component_policy'] if 'component_policy' in default_conf else 'workflow', + 'double_click_policy': default_conf['double_click_policy'] if 'double_click_policy' in default_conf else 'copy-all', + 'windows_selector_event_loop_policy': default_conf['windows_selector_event_loop_policy'] if 'windows_selector_event_loop_policy' in default_conf else False, + 'model_download_by_agent': default_conf['model_download_by_agent'] if 'model_download_by_agent' in default_conf else False, + 'downgrade_blacklist': default_conf['downgrade_blacklist'] if 'downgrade_blacklist' in default_conf else '', + } + + except Exception: + return { + 'preview_method': manager_funcs.get_current_preview_method(), + 'badge_mode': 'none', + 'git_exe': '', + 'channel_url': 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main', + 'share_option': 'all', + 'bypass_ssl': False, + 'file_logging': True, + 'default_ui': 'none', + 'component_policy': 'workflow', + 'double_click_policy': 'copy-all', + 'windows_selector_event_loop_policy': False, + 'model_download_by_agent': False, + 'downgrade_blacklist': '' + } + + +def get_config(): + global cached_config + + if cached_config is None: + cached_config = read_config() + + return cached_config + + +def switch_to_default_branch(repo): + show_result = repo.git.remote("show", "origin") + matches = re.search(r"\s*HEAD branch:\s*(.*)", show_result) + if matches: + default_branch = matches.group(1) + repo.git.checkout(default_branch) + + +def try_install_script(url, repo_path, install_cmd, instant_execution=False): + if not instant_execution and ((len(install_cmd) > 0 and install_cmd[0].startswith('#')) or (platform.system() == "Windows" and comfy_ui_commit_datetime.date() >= comfy_ui_required_commit_datetime.date())): + if not os.path.exists(startup_script_path): + os.makedirs(startup_script_path) + + script_path = os.path.join(startup_script_path, "install-scripts.txt") + with open(script_path, "a") as file: + obj = [repo_path] + install_cmd + file.write(f"{obj}\n") + + return True + else: + if len(install_cmd) == 5 and install_cmd[2:4] == ['pip', 'install']: + if is_blacklisted(install_cmd[4]): + print(f"[ComfyUI-Manager] skip black listed pip installation: '{install_cmd[4]}'") + return True + + print(f"\n## ComfyUI-Manager: EXECUTE => {install_cmd}") + code = manager_funcs.run_script(install_cmd, cwd=repo_path) + + if platform.system() != "Windows": + try: + if comfy_ui_commit_datetime.date() < comfy_ui_required_commit_datetime.date(): + print("\n\n###################################################################") + print(f"[WARN] ComfyUI-Manager: Your ComfyUI version ({comfy_ui_revision})[{comfy_ui_commit_datetime.date()}] is too old. Please update to the latest version.") + print(f"[WARN] The extension installation feature may not work properly in the current installed ComfyUI version on Windows environment.") + print("###################################################################\n\n") + except: + pass + + if code != 0: + if url is None: + url = os.path.dirname(repo_path) + print(f"install script failed: {url}") + return False + + +# use subprocess to avoid file system lock by git (Windows) +def __win_check_git_update(path, do_fetch=False, do_update=False): + if do_fetch: + command = [sys.executable, git_script_path, "--fetch", path] + elif do_update: + command = [sys.executable, git_script_path, "--pull", path] + else: + command = [sys.executable, git_script_path, "--check", path] + + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, _ = process.communicate() + output = output.decode('utf-8').strip() + + if 'detected dubious' in output: + # fix and try again + safedir_path = path.replace('\\', '/') + try: + print(f"[ComfyUI-Manager] Try fixing 'dubious repository' error on '{safedir_path}' repo") + process = subprocess.Popen(['git', 'config', '--global', '--add', 'safe.directory', safedir_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, _ = process.communicate() + + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, _ = process.communicate() + output = output.decode('utf-8').strip() + except Exception: + print(f'[ComfyUI-Manager] failed to fixing') + + if 'detected dubious' in output: + print(f'\n[ComfyUI-Manager] Failed to fixing repository setup. Please execute this command on cmd: \n' + f'-----------------------------------------------------------------------------------------\n' + f'git config --global --add safe.directory "{safedir_path}"\n' + f'-----------------------------------------------------------------------------------------\n') + + if do_update: + if "CUSTOM NODE PULL: Success" in output: + process.wait() + print(f"\rUpdated: {path}") + return True, True # updated + elif "CUSTOM NODE PULL: None" in output: + process.wait() + return False, True # there is no update + else: + print(f"\rUpdate error: {path}") + process.wait() + return False, False # update failed + else: + if "CUSTOM NODE CHECK: True" in output: + process.wait() + return True, True + elif "CUSTOM NODE CHECK: False" in output: + process.wait() + return False, True + else: + print(f"\rFetch error: {path}") + print(f"\n{output}\n") + process.wait() + return False, True + + +def __win_check_git_pull(path): + command = [sys.executable, git_script_path, "--pull", path] + process = subprocess.Popen(command) + process.wait() + + +def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=False): + install_script_path = os.path.join(repo_path, "install.py") + requirements_path = os.path.join(repo_path, "requirements.txt") + + if lazy_mode: + install_cmd = ["#LAZY-INSTALL-SCRIPT", sys.executable] + try_install_script(url, repo_path, install_cmd) + else: + if os.path.exists(requirements_path): + print("Install: pip packages") + with open(requirements_path, "r") as requirements_file: + for line in requirements_file: + package_name = remap_pip_package(line.strip()) + if package_name and not package_name.startswith('#'): + install_cmd = [sys.executable, "-m", "pip", "install", package_name] + if package_name.strip() != "": + try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution) + + if os.path.exists(install_script_path): + print(f"Install: install script") + install_cmd = [sys.executable, "install.py"] + try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution) + + return True + + +def git_repo_has_updates(path, do_fetch=False, do_update=False): + if do_fetch: + print(f"\x1b[2K\rFetching: {path}", end='') + elif do_update: + print(f"\x1b[2K\rUpdating: {path}", end='') + + # Check if the path is a git repository + if not os.path.exists(os.path.join(path, '.git')): + raise ValueError('Not a git repository') + + if platform.system() == "Windows": + updated, success = __win_check_git_update(path, do_fetch, do_update) + if updated and success: + execute_install_script(None, path, lazy_mode=True) + return updated, success + else: + # Fetch the latest commits from the remote repository + repo = git.Repo(path) + + current_branch = repo.active_branch + branch_name = current_branch.name + + remote_name = 'origin' + remote = repo.remote(name=remote_name) + + # Get the current commit hash + commit_hash = repo.head.commit.hexsha + + if do_fetch or do_update: + remote.fetch() + + if do_update: + if repo.head.is_detached: + switch_to_default_branch(repo) + + remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha + + if commit_hash == remote_commit_hash: + repo.close() + return False, True + + try: + remote.pull() + repo.git.submodule('update', '--init', '--recursive') + new_commit_hash = repo.head.commit.hexsha + + if commit_hash != new_commit_hash: + execute_install_script(None, path) + print(f"\x1b[2K\rUpdated: {path}") + return True, True + else: + return False, False + + except Exception as e: + print(f"\nUpdating failed: {path}\n{e}", file=sys.stderr) + return False, False + + if repo.head.is_detached: + repo.close() + return True, True + + # Get commit hash of the remote branch + current_branch = repo.active_branch + branch_name = current_branch.name + + remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha + + # Compare the commit hashes to determine if the local repository is behind the remote repository + if commit_hash != remote_commit_hash: + # Get the commit dates + commit_date = repo.head.commit.committed_datetime + remote_commit_date = repo.refs[f'{remote_name}/{branch_name}'].object.committed_datetime + + # Compare the commit dates to determine if the local repository is behind the remote repository + if commit_date < remote_commit_date: + repo.close() + return True, True + + repo.close() + + return False, True + + +class GitProgress(RemoteProgress): + def __init__(self): + super().__init__() + self.pbar = tqdm() + + def update(self, op_code, cur_count, max_count=None, message=''): + self.pbar.total = max_count + self.pbar.n = cur_count + self.pbar.pos = 0 + self.pbar.refresh() + + +def is_valid_url(url): + try: + result = urlparse(url) + return all([result.scheme, result.netloc]) + except ValueError: + return False + + +def gitclone_install(files, instant_execution=False, msg_prefix=''): + print(f"{msg_prefix}Install: {files}") + for url in files: + if not is_valid_url(url): + print(f"Invalid git url: '{url}'") + return False + + if url.endswith("/"): + url = url[:-1] + try: + print(f"Download: git clone '{url}'") + repo_name = os.path.splitext(os.path.basename(url))[0] + repo_path = os.path.join(custom_nodes_path, repo_name) + + # Clone the repository from the remote URL + if not instant_execution and platform.system() == 'Windows': + res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", custom_nodes_path, url]) + if res != 0: + return False + else: + repo = git.Repo.clone_from(url, repo_path, recursive=True, progress=GitProgress()) + repo.git.clear_cache() + repo.close() + + if not execute_install_script(url, repo_path, instant_execution=instant_execution): + return False + + except Exception as e: + print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr) + return False + + print("Installation was successful.") + return True + + +def git_pull(path): + # Check if the path is a git repository + if not os.path.exists(os.path.join(path, '.git')): + raise ValueError('Not a git repository') + + # Pull the latest changes from the remote repository + if platform.system() == "Windows": + return __win_check_git_pull(path) + else: + repo = git.Repo(path) + + if repo.is_dirty(): + repo.git.stash() + + if repo.head.is_detached: + switch_to_default_branch(repo) + + current_branch = repo.active_branch + remote_name = current_branch.tracking_branch().remote_name + remote = repo.remote(name=remote_name) + + remote.pull() + repo.git.submodule('update', '--init', '--recursive') + + repo.close() + + return True + + +async def get_data(uri, silent=False): + if not silent: + print(f"FETCH DATA from: {uri}") + + if uri.startswith("http"): + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + async with session.get(uri) as resp: + json_text = await resp.text() + else: + with cache_lock: + with open(uri, "r", encoding="utf-8") as f: + json_text = f.read() + + json_obj = json.loads(json_text) + return json_obj + + +def simple_hash(input_string): + hash_value = 0 + for char in input_string: + hash_value = (hash_value * 31 + ord(char)) % (2**32) + + return hash_value + + +def is_file_created_within_one_day(file_path): + if not os.path.exists(file_path): + return False + + file_creation_time = os.path.getctime(file_path) + current_time = datetime.now().timestamp() + time_difference = current_time - file_creation_time + + return time_difference <= 86400 + + +async def get_data_by_mode(mode, filename, channel_url=None): + try: + if mode == "local": + uri = os.path.join(comfyui_manager_path, filename) + json_obj = await get_data(uri) + else: + if channel_url is None: + uri = get_config()['channel_url'] + '/' + filename + else: + uri = channel_url + '/' + filename + + cache_uri = str(simple_hash(uri))+'_'+filename + cache_uri = os.path.join(cache_dir, cache_uri) + + if mode == "cache": + if is_file_created_within_one_day(cache_uri): + json_obj = await get_data(cache_uri) + else: + json_obj = await get_data(uri) + with cache_lock: + with open(cache_uri, "w", encoding='utf-8') as file: + json.dump(json_obj, file, indent=4, sort_keys=True) + else: + json_obj = await get_data(uri) + with cache_lock: + with open(cache_uri, "w", encoding='utf-8') as file: + json.dump(json_obj, file, indent=4, sort_keys=True) + except Exception as e: + print(f"[ComfyUI-Manager] Due to a network error, switching to local mode.\n=> {filename}\n=> {e}") + uri = os.path.join(comfyui_manager_path, filename) + json_obj = await get_data(uri) + + return json_obj + + +def gitclone_fix(files, instant_execution=False): + print(f"Try fixing: {files}") + for url in files: + if not is_valid_url(url): + print(f"Invalid git url: '{url}'") + return False + + if url.endswith("/"): + url = url[:-1] + try: + repo_name = os.path.splitext(os.path.basename(url))[0] + repo_path = os.path.join(custom_nodes_path, repo_name) + + if os.path.exists(repo_path+'.disabled'): + repo_path = repo_path+'.disabled' + + if not execute_install_script(url, repo_path, instant_execution=instant_execution): + return False + + except Exception as e: + print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr) + return False + + print(f"Attempt to fixing '{files}' is done.") + return True + + +def pip_install(packages): + install_cmd = ['#FORCE', sys.executable, "-m", "pip", "install", '-U'] + packages + try_install_script('pip install via manager', '..', install_cmd) + + +def rmtree(path): + retry_count = 3 + + while True: + try: + retry_count -= 1 + + if platform.system() == "Windows": + manager_funcs.run_script(['attrib', '-R', path + '\\*', '/S']) + shutil.rmtree(path) + + return True + + except Exception as ex: + print(f"ex: {ex}") + time.sleep(3) + + if retry_count < 0: + raise ex + + print(f"Uninstall retry({retry_count})") + + +def gitclone_uninstall(files): + import os + + print(f"Uninstall: {files}") + for url in files: + if url.endswith("/"): + url = url[:-1] + try: + dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") + dir_path = os.path.join(custom_nodes_path, dir_name) + + # safety check + if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '': + print(f"Uninstall(git-clone) error: invalid path '{dir_path}' for '{url}'") + return False + + install_script_path = os.path.join(dir_path, "uninstall.py") + disable_script_path = os.path.join(dir_path, "disable.py") + if os.path.exists(install_script_path): + uninstall_cmd = [sys.executable, "uninstall.py"] + code = manager_funcs.run_script(uninstall_cmd, cwd=dir_path) + + if code != 0: + print(f"An error occurred during the execution of the uninstall.py script. Only the '{dir_path}' will be deleted.") + elif os.path.exists(disable_script_path): + disable_script = [sys.executable, "disable.py"] + code = manager_funcs.run_script(disable_script, cwd=dir_path) + if code != 0: + print(f"An error occurred during the execution of the disable.py script. Only the '{dir_path}' will be deleted.") + + if os.path.exists(dir_path): + rmtree(dir_path) + elif os.path.exists(dir_path + ".disabled"): + rmtree(dir_path + ".disabled") + except Exception as e: + print(f"Uninstall(git-clone) error: {url} / {e}", file=sys.stderr) + return False + + print("Uninstallation was successful.") + return True + + +def gitclone_set_active(files, is_disable): + import os + + if is_disable: + action_name = "Disable" + else: + action_name = "Enable" + + print(f"{action_name}: {files}") + for url in files: + if url.endswith("/"): + url = url[:-1] + try: + dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") + dir_path = os.path.join(custom_nodes_path, dir_name) + + # safety check + if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '': + print(f"{action_name}(git-clone) error: invalid path '{dir_path}' for '{url}'") + return False + + if is_disable: + current_path = dir_path + new_path = dir_path + ".disabled" + else: + current_path = dir_path + ".disabled" + new_path = dir_path + + os.rename(current_path, new_path) + + if is_disable: + if os.path.exists(os.path.join(new_path, "disable.py")): + disable_script = [sys.executable, "disable.py"] + try_install_script(url, new_path, disable_script) + else: + if os.path.exists(os.path.join(new_path, "enable.py")): + enable_script = [sys.executable, "enable.py"] + try_install_script(url, new_path, enable_script) + + except Exception as e: + print(f"{action_name}(git-clone) error: {url} / {e}", file=sys.stderr) + return False + + print(f"{action_name} was successful.") + return True + + +def gitclone_update(files, instant_execution=False, skip_script=False, msg_prefix=""): + import os + + print(f"{msg_prefix}Update: {files}") + for url in files: + if url.endswith("/"): + url = url[:-1] + try: + repo_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") + repo_path = os.path.join(custom_nodes_path, repo_name) + + if os.path.exists(repo_path+'.disabled'): + repo_path = repo_path+'.disabled' + + git_pull(repo_path) + + if not skip_script: + if instant_execution: + if not execute_install_script(url, repo_path, lazy_mode=False, instant_execution=True): + return False + else: + if not execute_install_script(url, repo_path, lazy_mode=True): + return False + + except Exception as e: + print(f"Update(git-clone) error: {url} / {e}", file=sys.stderr) + return False + + if not skip_script: + print("Update was successful.") + return True + + +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 + + +def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do_update=False): + item['installed'] = 'None' + + if item['install_type'] == 'git-clone' and len(item['files']) == 1: + url = item['files'][0] + + if url.endswith("/"): + url = url[:-1] + + dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "") + dir_path = os.path.join(custom_nodes_path, dir_name) + if os.path.exists(dir_path): + try: + item['installed'] = 'True' # default + + if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name): + item['installed'] = 'Fail' + + if do_update_check: + update_state, success = git_repo_has_updates(dir_path, do_fetch, do_update) + if (do_update_check or do_update) and update_state: + item['installed'] = 'Update' + elif do_update and not success: + item['installed'] = 'Fail' + except: + if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name): + item['installed'] = 'Fail' + else: + item['installed'] = 'True' + + elif os.path.exists(dir_path + ".disabled"): + item['installed'] = 'Disabled' + + else: + item['installed'] = 'False' + + elif item['install_type'] == 'copy' and len(item['files']) == 1: + dir_name = os.path.basename(item['files'][0]) + + if item['files'][0].endswith('.py'): + base_path = custom_nodes_path + elif 'js_path' in item: + base_path = os.path.join(js_path, item['js_path']) + else: + base_path = js_path + + file_path = os.path.join(base_path, dir_name) + if os.path.exists(file_path): + if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name): + item['installed'] = 'Fail' + else: + item['installed'] = 'True' + elif os.path.exists(file_path + ".disabled"): + item['installed'] = 'Disabled' + else: + item['installed'] = 'False' + + +def get_current_snapshot(): + # Get ComfyUI hash + repo_path = comfy_path + + print(f"comfy_path: {comfy_path}") + if not os.path.exists(os.path.join(repo_path, '.git')): + print(f"ComfyUI update fail: The installed ComfyUI does not have a Git repository.") + return {} + + repo = git.Repo(repo_path) + comfyui_commit_hash = repo.head.commit.hexsha + + git_custom_nodes = {} + file_custom_nodes = [] + + # Get custom nodes hash + for path in os.listdir(custom_nodes_path): + fullpath = os.path.join(custom_nodes_path, path) + + if os.path.isdir(fullpath): + is_disabled = path.endswith(".disabled") + + try: + git_dir = os.path.join(fullpath, '.git') + + if not os.path.exists(git_dir): + continue + + repo = git.Repo(fullpath) + commit_hash = repo.head.commit.hexsha + url = repo.remotes.origin.url + git_custom_nodes[url] = { + 'hash': commit_hash, + 'disabled': is_disabled + } + + except: + print(f"Failed to extract snapshots for the custom node '{path}'.") + + elif path.endswith('.py'): + is_disabled = path.endswith(".py.disabled") + filename = os.path.basename(path) + item = { + 'filename': filename, + 'disabled': is_disabled + } + + file_custom_nodes.append(item) + + return { + 'comfyui': comfyui_commit_hash, + 'git_custom_nodes': git_custom_nodes, + 'file_custom_nodes': file_custom_nodes, + } + + +def save_snapshot_with_postfix(postfix): + now = datetime.now() + + date_time_format = now.strftime("%Y-%m-%d_%H-%M-%S") + file_name = f"{date_time_format}_{postfix}" + + path = os.path.join(comfyui_manager_path, 'snapshots', f"{file_name}.json") + with open(path, "w") as json_file: + json.dump(get_current_snapshot(), json_file, indent=4) + + return file_name+'.json' + diff --git a/glob/manager_server.py b/glob/manager_server.py new file mode 100644 index 00000000..3111c3c0 --- /dev/null +++ b/glob/manager_server.py @@ -0,0 +1,1627 @@ +import mimetypes +import traceback + +import folder_paths +import locale +import subprocess # don't remove this +import concurrent +import nodes +import hashlib +import os +import sys +import threading +import re +import shutil +import git + +from server import PromptServer +import manager_core as core +import cm_global + +print(f"### Loading: ComfyUI-Manager ({core.version_str})") + +comfy_ui_hash = "-" + + +def handle_stream(stream, prefix): + stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace') + for msg in stream: + if prefix == '[!]' and ('it/s]' in msg or 's/it]' in msg) and ('%|' in msg or 'it [' in msg): + if msg.startswith('100%'): + print('\r' + msg, end="", file=sys.stderr), + else: + print('\r' + msg[:-1], end="", file=sys.stderr), + else: + if prefix == '[!]': + print(prefix, msg, end="", file=sys.stderr) + else: + print(prefix, msg, end="") + + +from comfy.cli_args import args +import latent_preview + + +class ManagerFuncsInComfyUI(core.ManagerFuncs): + def get_current_preview_method(self): + if args.preview_method == latent_preview.LatentPreviewMethod.Auto: + return "auto" + elif args.preview_method == latent_preview.LatentPreviewMethod.Latent2RGB: + return "latent2rgb" + elif args.preview_method == latent_preview.LatentPreviewMethod.TAESD: + return "taesd" + else: + return "none" + + def run_script(self, cmd, cwd='.'): + if len(cmd) > 0 and cmd[0].startswith("#"): + print(f"[ComfyUI-Manager] Unexpected behavior: `{cmd}`") + return 0 + + process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1) + + stdout_thread = threading.Thread(target=handle_stream, args=(process.stdout, "")) + stderr_thread = threading.Thread(target=handle_stream, args=(process.stderr, "[!]")) + + stdout_thread.start() + stderr_thread.start() + + stdout_thread.join() + stderr_thread.join() + + return process.wait() + + +core.manager_funcs = ManagerFuncsInComfyUI() + +sys.path.append('../..') + +from torchvision.datasets.utils import download_url + +core.comfy_path = os.path.dirname(folder_paths.__file__) +core.js_path = os.path.join(core.comfy_path, "web", "extensions") + +local_db_model = os.path.join(core.comfyui_manager_path, "model-list.json") +local_db_alter = os.path.join(core.comfyui_manager_path, "alter-list.json") +local_db_custom_node_list = os.path.join(core.comfyui_manager_path, "custom-node-list.json") +local_db_extension_node_mappings = os.path.join(core.comfyui_manager_path, "extension-node-map.json") +components_path = os.path.join(core.comfyui_manager_path, 'components') + + +def set_preview_method(method): + if method == 'auto': + args.preview_method = latent_preview.LatentPreviewMethod.Auto + elif method == 'latent2rgb': + args.preview_method = latent_preview.LatentPreviewMethod.Latent2RGB + elif method == 'taesd': + args.preview_method = latent_preview.LatentPreviewMethod.TAESD + else: + args.preview_method = latent_preview.LatentPreviewMethod.NoPreviews + + core.get_config()['preview_method'] = args.preview_method + + +set_preview_method(core.get_config()['preview_method']) + + +def set_badge_mode(mode): + core.get_config()['badge_mode'] = mode + + +def set_default_ui_mode(mode): + core.get_config()['default_ui'] = mode + + +def set_component_policy(mode): + core.get_config()['component_policy'] = mode + + +def set_double_click_policy(mode): + core.get_config()['double_click_policy'] = mode + + +def print_comfyui_version(): + global comfy_ui_hash + + is_detached = False + try: + repo = git.Repo(os.path.dirname(folder_paths.__file__)) + core.comfy_ui_revision = len(list(repo.iter_commits('HEAD'))) + + comfy_ui_hash = repo.head.commit.hexsha + cm_global.variables['comfyui.revision'] = core.comfy_ui_revision + + core.comfy_ui_commit_datetime = repo.head.commit.committed_datetime + cm_global.variables['comfyui.commit_datetime'] = core.comfy_ui_commit_datetime + + is_detached = repo.head.is_detached + current_branch = repo.active_branch.name + + try: + if core.comfy_ui_commit_datetime.date() < core.comfy_ui_required_commit_datetime.date(): + print(f"\n\n## [WARN] ComfyUI-Manager: Your ComfyUI version ({core.comfy_ui_revision})[{core.comfy_ui_commit_datetime.date()}] is too old. Please update to the latest version. ##\n\n") + except: + pass + + # process on_revision_detected --> + if 'cm.on_revision_detected_handler' in cm_global.variables: + for k, f in cm_global.variables['cm.on_revision_detected_handler']: + try: + f(core.comfy_ui_revision) + except Exception: + print(f"[ERROR] '{k}' on_revision_detected_handler") + traceback.print_exc() + + del cm_global.variables['cm.on_revision_detected_handler'] + else: + print(f"[ComfyUI-Manager] Some features are restricted due to your ComfyUI being outdated.") + # <-- + + if current_branch == "master": + print(f"### ComfyUI Revision: {core.comfy_ui_revision} [{comfy_ui_hash[:8]}] | Released on '{core.comfy_ui_commit_datetime.date()}'") + else: + print(f"### ComfyUI Revision: {core.comfy_ui_revision} on '{current_branch}' [{comfy_ui_hash[:8]}] | Released on '{core.comfy_ui_commit_datetime.date()}'") + except: + if is_detached: + print(f"### ComfyUI Revision: {core.comfy_ui_revision} [{comfy_ui_hash[:8]}] *DETACHED | Released on '{core.comfy_ui_commit_datetime.date()}'") + else: + print("### ComfyUI Revision: UNKNOWN (The currently installed ComfyUI is not a Git repository)") + + +print_comfyui_version() + + +async def populate_github_stats(json_obj, filename, silent=False): + uri = os.path.join(core.comfyui_manager_path, filename) + with open(uri, "r", encoding='utf-8') as f: + github_stats = json.load(f) + if 'custom_nodes' in json_obj: + for i, node in enumerate(json_obj['custom_nodes']): + url = node['reference'] + if url in github_stats: + json_obj['custom_nodes'][i]['stars'] = github_stats[url]['stars'] + json_obj['custom_nodes'][i]['last_update'] = github_stats[url]['last_update'] + else: + json_obj['custom_nodes'][i]['stars'] = -1 + json_obj['custom_nodes'][i]['last_update'] = -1 + return json_obj + + +def setup_environment(): + git_exe = core.get_config()['git_exe'] + + if git_exe != '': + git.Git().update_environment(GIT_PYTHON_GIT_EXECUTABLE=git_exe) + + +setup_environment() + +# Expand Server api + +import server +from aiohttp import web +import aiohttp +import json +import zipfile +import urllib.request + + +def get_model_dir(data): + if data['save_path'] != 'default': + if '..' in data['save_path'] or data['save_path'].startswith('/'): + print(f"[WARN] '{data['save_path']}' is not allowed path. So it will be saved into 'models/etc'.") + base_model = "etc" + else: + if data['save_path'].startswith("custom_nodes"): + base_model = os.path.join(core.comfy_path, data['save_path']) + else: + base_model = os.path.join(folder_paths.models_dir, data['save_path']) + else: + model_type = data['type'] + if model_type == "checkpoints": + base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0] + elif model_type == "unclip": + base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0] + elif model_type == "VAE": + base_model = folder_paths.folder_names_and_paths["vae"][0][0] + elif model_type == "lora": + base_model = folder_paths.folder_names_and_paths["loras"][0][0] + elif model_type == "T2I-Adapter": + base_model = folder_paths.folder_names_and_paths["controlnet"][0][0] + elif model_type == "T2I-Style": + base_model = folder_paths.folder_names_and_paths["controlnet"][0][0] + elif model_type == "controlnet": + base_model = folder_paths.folder_names_and_paths["controlnet"][0][0] + elif model_type == "clip_vision": + base_model = folder_paths.folder_names_and_paths["clip_vision"][0][0] + elif model_type == "gligen": + base_model = folder_paths.folder_names_and_paths["gligen"][0][0] + elif model_type == "upscale": + base_model = folder_paths.folder_names_and_paths["upscale_models"][0][0] + elif model_type == "embeddings": + base_model = folder_paths.folder_names_and_paths["embeddings"][0][0] + else: + base_model = "etc" + + return base_model + + +def get_model_path(data): + base_model = get_model_dir(data) + return os.path.join(base_model, data['filename']) + + +def check_custom_nodes_installed(json_obj, do_fetch=False, do_update_check=True, do_update=False): + if do_fetch: + print("Start fetching...", end="") + elif do_update: + print("Start updating...", end="") + elif do_update_check: + print("Start update check...", end="") + + def process_custom_node(item): + core.check_a_custom_node_installed(item, do_fetch, do_update_check, do_update) + + with concurrent.futures.ThreadPoolExecutor(4) as executor: + for item in json_obj['custom_nodes']: + executor.submit(process_custom_node, item) + + if do_fetch: + print(f"\x1b[2K\rFetching done.") + elif do_update: + update_exists = any(item['installed'] == 'Update' for item in json_obj['custom_nodes']) + if update_exists: + print(f"\x1b[2K\rUpdate done.") + else: + print(f"\x1b[2K\rAll extensions are already up-to-date.") + elif do_update_check: + print(f"\x1b[2K\rUpdate check done.") + + +def nickname_filter(json_obj): + preemptions_map = {} + + for k, x in json_obj.items(): + if 'preemptions' in x[1]: + for y in x[1]['preemptions']: + preemptions_map[y] = k + elif k.endswith("/ComfyUI"): + for y in x[0]: + preemptions_map[y] = k + + updates = {} + for k, x in json_obj.items(): + removes = set() + for y in x[0]: + k2 = preemptions_map.get(y) + if k2 is not None and k != k2: + removes.add(y) + + if len(removes) > 0: + updates[k] = [y for y in x[0] if y not in removes] + + for k, v in updates.items(): + json_obj[k][0] = v + + return json_obj + + +@PromptServer.instance.routes.get("/customnode/getmappings") +async def fetch_customnode_mappings(request): + mode = request.rel_url.query["mode"] + + nickname_mode = False + if mode == "nickname": + mode = "local" + nickname_mode = True + + json_obj = await core.get_data_by_mode(mode, 'extension-node-map.json') + + if nickname_mode: + json_obj = nickname_filter(json_obj) + + all_nodes = set() + patterns = [] + for k, x in json_obj.items(): + all_nodes.update(set(x[0])) + + if 'nodename_pattern' in x[1]: + patterns.append((x[1]['nodename_pattern'], x[0])) + + missing_nodes = set(nodes.NODE_CLASS_MAPPINGS.keys()) - all_nodes + + for x in missing_nodes: + for pat, item in patterns: + if re.match(pat, x): + item.append(x) + + return web.json_response(json_obj, content_type='application/json') + + +@PromptServer.instance.routes.get("/customnode/fetch_updates") +async def fetch_updates(request): + try: + json_obj = await core.get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') + + check_custom_nodes_installed(json_obj, True) + + update_exists = any('custom_nodes' in json_obj and 'installed' in node and node['installed'] == 'Update' for node in + json_obj['custom_nodes']) + + if update_exists: + return web.Response(status=201) + + return web.Response(status=200) + except: + return web.Response(status=400) + + +@PromptServer.instance.routes.get("/customnode/update_all") +async def update_all(request): + try: + core.save_snapshot_with_postfix('autosave') + + json_obj = await core.get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') + + check_custom_nodes_installed(json_obj, do_update=True) + + updated = [item['title'] for item in json_obj['custom_nodes'] if item['installed'] == 'Update'] + failed = [item['title'] for item in json_obj['custom_nodes'] if item['installed'] == 'Fail'] + + res = {'updated': updated, 'failed': failed} + + if len(updated) == 0 and len(failed) == 0: + status = 200 + else: + status = 201 + + return web.json_response(res, status=status, content_type='application/json') + except: + return web.Response(status=400) + finally: + core.clear_pip_cache() + + +def convert_markdown_to_html(input_text): + pattern_a = re.compile(r'\[a/([^]]+)\]\(([^)]+)\)') + pattern_w = re.compile(r'\[w/([^]]+)\]') + pattern_i = re.compile(r'\[i/([^]]+)\]') + pattern_bold = re.compile(r'\*\*([^*]+)\*\*') + pattern_white = re.compile(r'%%([^*]+)%%') + + def replace_a(match): + return f"{match.group(1)}" + + def replace_w(match): + return f"

{match.group(1)}

" + + def replace_i(match): + return f"

{match.group(1)}

" + + def replace_bold(match): + return f"{match.group(1)}" + + def replace_white(match): + return f"{match.group(1)}" + + input_text = input_text.replace('\\[', '[').replace('\\]', ']').replace('<', '<').replace('>', '>') + + result_text = re.sub(pattern_a, replace_a, input_text) + result_text = re.sub(pattern_w, replace_w, result_text) + result_text = re.sub(pattern_i, replace_i, result_text) + result_text = re.sub(pattern_bold, replace_bold, result_text) + result_text = re.sub(pattern_white, replace_white, result_text) + + return result_text.replace("\n", "
") + + +def populate_markdown(x): + if 'description' in x: + x['description'] = convert_markdown_to_html(x['description']) + + if 'name' in x: + x['name'] = x['name'].replace('<', '<').replace('>', '>') + + if 'title' in x: + x['title'] = x['title'].replace('<', '<').replace('>', '>') + + +@PromptServer.instance.routes.get("/customnode/getlist") +async def fetch_customnode_list(request): + if "skip_update" in request.rel_url.query and request.rel_url.query["skip_update"] == "true": + skip_update = True + else: + skip_update = False + + if request.rel_url.query["mode"] == "local": + channel = 'local' + else: + channel = core.get_config()['channel_url'] + + json_obj = await core.get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') + json_obj = await populate_github_stats(json_obj, "github-stats.json") + + def is_ignored_notice(code): + global version + + if code is not None and code.startswith('#NOTICE_'): + try: + notice_version = [int(x) for x in code[8:].split('.')] + return notice_version[0] < version[0] or (notice_version[0] == version[0] and notice_version[1] <= version[1]) + except Exception: + return False + else: + return False + + json_obj['custom_nodes'] = [record for record in json_obj['custom_nodes'] if not is_ignored_notice(record.get('author'))] + + check_custom_nodes_installed(json_obj, False, not skip_update) + + for x in json_obj['custom_nodes']: + populate_markdown(x) + + if channel != 'local': + found = 'custom' + + for name, url in core.get_channel_dict().items(): + if url == channel: + found = name + break + + channel = found + + json_obj['channel'] = channel + + return web.json_response(json_obj, content_type='application/json') + + +@PromptServer.instance.routes.get("/alternatives/getlist") +async def fetch_alternatives_list(request): + if "skip_update" in request.rel_url.query and request.rel_url.query["skip_update"] == "true": + skip_update = True + else: + skip_update = False + + alter_json = await core.get_data_by_mode(request.rel_url.query["mode"], 'alter-list.json') + custom_node_json = await core.get_data_by_mode(request.rel_url.query["mode"], 'custom-node-list.json') + + fileurl_to_custom_node = {} + + for item in custom_node_json['custom_nodes']: + for fileurl in item['files']: + fileurl_to_custom_node[fileurl] = item + + for item in alter_json['items']: + fileurl = item['id'] + if fileurl in fileurl_to_custom_node: + custom_node = fileurl_to_custom_node[fileurl] + core.check_a_custom_node_installed(custom_node, not skip_update) + + populate_markdown(item) + populate_markdown(custom_node) + item['custom_node'] = custom_node + + return web.json_response(alter_json, content_type='application/json') + + +def check_model_installed(json_obj): + def process_model(item): + model_path = get_model_path(item) + item['installed'] = 'None' + + if model_path is not None: + if os.path.exists(model_path): + item['installed'] = 'True' + else: + item['installed'] = 'False' + + with concurrent.futures.ThreadPoolExecutor(8) as executor: + for item in json_obj['models']: + executor.submit(process_model, item) + + +@PromptServer.instance.routes.get("/externalmodel/getlist") +async def fetch_externalmodel_list(request): + json_obj = await core.get_data_by_mode(request.rel_url.query["mode"], 'model-list.json') + + check_model_installed(json_obj) + + for x in json_obj['models']: + populate_markdown(x) + + return web.json_response(json_obj, content_type='application/json') + + +@PromptServer.instance.routes.get("/snapshot/get_current") +async def get_snapshot_list(request): + json_obj = core.get_current_snapshot() + return web.json_response(json_obj, content_type='application/json') + + +@PromptServer.instance.routes.get("/snapshot/getlist") +async def get_snapshot_list(request): + snapshots_directory = os.path.join(core.comfyui_manager_path, 'snapshots') + items = [f[:-5] for f in os.listdir(snapshots_directory) if f.endswith('.json')] + items.sort(reverse=True) + return web.json_response({'items': items}, content_type='application/json') + + +@PromptServer.instance.routes.get("/snapshot/remove") +async def remove_snapshot(request): + try: + target = request.rel_url.query["target"] + + path = os.path.join(core.comfyui_manager_path, 'snapshots', f"{target}.json") + if os.path.exists(path): + os.remove(path) + + return web.Response(status=200) + except: + return web.Response(status=400) + + +@PromptServer.instance.routes.get("/snapshot/restore") +async def remove_snapshot(request): + try: + target = request.rel_url.query["target"] + + path = os.path.join(core.comfyui_manager_path, 'snapshots', f"{target}.json") + if os.path.exists(path): + if not os.path.exists(core.startup_script_path): + os.makedirs(core.startup_script_path) + + target_path = os.path.join(core.startup_script_path, "restore-snapshot.json") + shutil.copy(path, target_path) + + print(f"Snapshot restore scheduled: `{target}`") + return web.Response(status=200) + + print(f"Snapshot file not found: `{path}`") + return web.Response(status=400) + except: + return web.Response(status=400) + + +@PromptServer.instance.routes.get("/snapshot/get_current") +async def get_current_snapshot_api(request): + try: + return web.json_response(core.get_current_snapshot(), content_type='application/json') + except: + return web.Response(status=400) + + +@PromptServer.instance.routes.get("/snapshot/save") +async def save_snapshot(request): + try: + core.save_snapshot_with_postfix('snapshot') + return web.Response(status=200) + except: + return web.Response(status=400) + + +def unzip_install(files): + temp_filename = 'manager-temp.zip' + for url in files: + if url.endswith("/"): + url = url[:-1] + try: + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} + + req = urllib.request.Request(url, headers=headers) + response = urllib.request.urlopen(req) + data = response.read() + + with open(temp_filename, 'wb') as f: + f.write(data) + + with zipfile.ZipFile(temp_filename, 'r') as zip_ref: + zip_ref.extractall(core.custom_nodes_path) + + os.remove(temp_filename) + except Exception as e: + print(f"Install(unzip) error: {url} / {e}", file=sys.stderr) + return False + + print("Installation was successful.") + return True + + +def download_url_with_agent(url, save_path): + try: + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} + + req = urllib.request.Request(url, headers=headers) + response = urllib.request.urlopen(req) + data = response.read() + + if not os.path.exists(os.path.dirname(save_path)): + os.makedirs(os.path.dirname(save_path)) + + with open(save_path, 'wb') as f: + f.write(data) + + except Exception as e: + print(f"Download error: {url} / {e}", file=sys.stderr) + return False + + print("Installation was successful.") + return True + + +def copy_install(files, js_path_name=None): + for url in files: + if url.endswith("/"): + url = url[:-1] + try: + if url.endswith(".py"): + download_url(url, core.custom_nodes_path) + else: + path = os.path.join(core.js_path, js_path_name) if js_path_name is not None else core.js_path + if not os.path.exists(path): + os.makedirs(path) + download_url(url, path) + + except Exception as e: + print(f"Install(copy) error: {url} / {e}", file=sys.stderr) + return False + + print("Installation was successful.") + return True + + +def copy_uninstall(files, js_path_name='.'): + for url in files: + if url.endswith("/"): + url = url[:-1] + dir_name = os.path.basename(url) + base_path = core.custom_nodes_path if url.endswith('.py') else os.path.join(core.js_path, js_path_name) + file_path = os.path.join(base_path, dir_name) + + try: + if os.path.exists(file_path): + os.remove(file_path) + elif os.path.exists(file_path + ".disabled"): + os.remove(file_path + ".disabled") + except Exception as e: + print(f"Uninstall(copy) error: {url} / {e}", file=sys.stderr) + return False + + print("Uninstallation was successful.") + return True + + +def copy_set_active(files, is_disable, js_path_name='.'): + if is_disable: + action_name = "Disable" + else: + action_name = "Enable" + + for url in files: + if url.endswith("/"): + url = url[:-1] + dir_name = os.path.basename(url) + base_path = core.custom_nodes_path if url.endswith('.py') else os.path.join(core.js_path, js_path_name) + file_path = os.path.join(base_path, dir_name) + + try: + if is_disable: + current_name = file_path + new_name = file_path + ".disabled" + else: + current_name = file_path + ".disabled" + new_name = file_path + + os.rename(current_name, new_name) + + except Exception as e: + print(f"{action_name}(copy) error: {url} / {e}", file=sys.stderr) + + return False + + print(f"{action_name} was successful.") + return True + + +@PromptServer.instance.routes.post("/customnode/install") +async def install_custom_node(request): + json_data = await request.json() + + install_type = json_data['install_type'] + + print(f"Install custom node '{json_data['title']}'") + + res = False + + if len(json_data['files']) == 0: + return web.Response(status=400) + + if install_type == "unzip": + res = unzip_install(json_data['files']) + + if install_type == "copy": + js_path_name = json_data['js_path'] if 'js_path' in json_data else '.' + res = copy_install(json_data['files'], js_path_name) + + elif install_type == "git-clone": + res = core.gitclone_install(json_data['files']) + + if 'pip' in json_data: + for pname in json_data['pip']: + pkg = core.remap_pip_package(pname) + install_cmd = [sys.executable, "-m", "pip", "install", pkg] + core.try_install_script(json_data['files'][0], ".", install_cmd) + + core.clear_pip_cache() + + if res: + print(f"After restarting ComfyUI, please refresh the browser.") + return web.json_response({}, content_type='application/json') + + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/customnode/fix") +async def fix_custom_node(request): + json_data = await request.json() + + install_type = json_data['install_type'] + + print(f"Install custom node '{json_data['title']}'") + + res = False + + if len(json_data['files']) == 0: + return web.Response(status=400) + + if install_type == "git-clone": + res = core.gitclone_fix(json_data['files']) + else: + return web.Response(status=400) + + if 'pip' in json_data: + for pname in json_data['pip']: + install_cmd = [sys.executable, "-m", "pip", "install", '-U', pname] + core.try_install_script(json_data['files'][0], ".", install_cmd) + + if res: + print(f"After restarting ComfyUI, please refresh the browser.") + return web.json_response({}, content_type='application/json') + + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/customnode/install/git_url") +async def install_custom_node_git_url(request): + url = await request.text() + res = core.gitclone_install([url]) + + if res: + print(f"After restarting ComfyUI, please refresh the browser.") + return web.Response(status=200) + + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/customnode/install/pip") +async def install_custom_node_git_url(request): + packages = await request.text() + core.pip_install(packages.split(' ')) + + return web.Response(status=200) + + +@PromptServer.instance.routes.post("/customnode/uninstall") +async def uninstall_custom_node(request): + json_data = await request.json() + + install_type = json_data['install_type'] + + print(f"Uninstall custom node '{json_data['title']}'") + + res = False + + if install_type == "copy": + js_path_name = json_data['js_path'] if 'js_path' in json_data else '.' + res = copy_uninstall(json_data['files'], js_path_name) + + elif install_type == "git-clone": + res = core.gitclone_uninstall(json_data['files']) + + if res: + print(f"After restarting ComfyUI, please refresh the browser.") + return web.json_response({}, content_type='application/json') + + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/customnode/update") +async def update_custom_node(request): + json_data = await request.json() + + install_type = json_data['install_type'] + + print(f"Update custom node '{json_data['title']}'") + + res = False + + if install_type == "git-clone": + res = core.gitclone_update(json_data['files']) + + core.clear_pip_cache() + + if res: + print(f"After restarting ComfyUI, please refresh the browser.") + return web.json_response({}, content_type='application/json') + + return web.Response(status=400) + + +@PromptServer.instance.routes.get("/comfyui_manager/update_comfyui") +async def update_comfyui(request): + print(f"Update ComfyUI") + + try: + repo_path = os.path.dirname(folder_paths.__file__) + + if not os.path.exists(os.path.join(repo_path, '.git')): + print(f"ComfyUI update fail: The installed ComfyUI does not have a Git repository.") + return web.Response(status=400) + + # version check + repo = git.Repo(repo_path) + + if repo.head.is_detached: + core.switch_to_default_branch(repo) + + current_branch = repo.active_branch + branch_name = current_branch.name + + if current_branch.tracking_branch() is None: + print(f"[ComfyUI-Manager] There is no tracking branch ({current_branch})") + remote_name = 'origin' + else: + remote_name = current_branch.tracking_branch().remote_name + remote = repo.remote(name=remote_name) + + try: + remote.fetch() + except Exception as e: + if 'detected dubious' in str(e): + print(f"[ComfyUI-Manager] Try fixing 'dubious repository' error on 'ComfyUI' repository") + safedir_path = core.comfy_path.replace('\\', '/') + subprocess.run(['git', 'config', '--global', '--add', 'safe.directory', safedir_path]) + try: + remote.fetch() + except Exception: + print(f"\n[ComfyUI-Manager] Failed to fixing repository setup. Please execute this command on cmd: \n" + f"-----------------------------------------------------------------------------------------\n" + f'git config --global --add safe.directory "{safedir_path}"\n' + f"-----------------------------------------------------------------------------------------\n") + + commit_hash = repo.head.commit.hexsha + remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha + + if commit_hash != remote_commit_hash: + core.git_pull(repo_path) + core.execute_install_script("ComfyUI", repo_path) + return web.Response(status=201) + else: + return web.Response(status=200) + except Exception as e: + print(f"ComfyUI update fail: {e}", file=sys.stderr) + pass + + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/customnode/toggle_active") +async def toggle_active(request): + json_data = await request.json() + + install_type = json_data['install_type'] + is_disabled = json_data['installed'] == "Disabled" + + print(f"Update custom node '{json_data['title']}'") + + res = False + + if install_type == "git-clone": + res = core.gitclone_set_active(json_data['files'], not is_disabled) + elif install_type == "copy": + res = copy_set_active(json_data['files'], not is_disabled, json_data.get('js_path', None)) + + if res: + return web.json_response({}, content_type='application/json') + + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/model/install") +async def install_model(request): + json_data = await request.json() + + model_path = get_model_path(json_data) + + res = False + + try: + if model_path is not None: + print(f"Install model '{json_data['name']}' into '{model_path}'") + + model_url = json_data['url'] + if not core.get_config()['model_download_by_agent'] and ( + model_url.startswith('https://github.com') or model_url.startswith('https://huggingface.co') or model_url.startswith('https://heibox.uni-heidelberg.de')): + model_dir = get_model_dir(json_data) + download_url(model_url, model_dir, filename=json_data['filename']) + + return web.json_response({}, content_type='application/json') + else: + res = download_url_with_agent(model_url, model_path) + else: + print(f"Model installation error: invalid model type - {json_data['type']}") + + if res: + return web.json_response({}, content_type='application/json') + except Exception as e: + print(f"[ERROR] {e}", file=sys.stderr) + pass + + return web.Response(status=400) + + +class ManagerTerminalHook: + def write_stderr(self, msg): + PromptServer.instance.send_sync("manager-terminal-feedback", {"data": msg}) + + def write_stdout(self, msg): + PromptServer.instance.send_sync("manager-terminal-feedback", {"data": msg}) + + +manager_terminal_hook = ManagerTerminalHook() + + +@PromptServer.instance.routes.get("/manager/terminal") +async def terminal_mode(request): + if "mode" in request.rel_url.query: + if request.rel_url.query['mode'] == 'true': + sys.__comfyui_manager_terminal_hook.add_hook('cm', manager_terminal_hook) + else: + sys.__comfyui_manager_terminal_hook.remove_hook('cm') + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/preview_method") +async def preview_method(request): + if "value" in request.rel_url.query: + set_preview_method(request.rel_url.query['value']) + core.write_config() + else: + return web.Response(text=core.manager_funcs.get_current_preview_method(), status=200) + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/badge_mode") +async def badge_mode(request): + if "value" in request.rel_url.query: + set_badge_mode(request.rel_url.query['value']) + core.write_config() + else: + return web.Response(text=core.get_config()['badge_mode'], status=200) + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/default_ui") +async def default_ui_mode(request): + if "value" in request.rel_url.query: + set_default_ui_mode(request.rel_url.query['value']) + core.write_config() + else: + return web.Response(text=core.get_config()['default_ui'], status=200) + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/component/policy") +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) + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/dbl_click/policy") +async def dbl_click_policy(request): + if "value" in request.rel_url.query: + set_double_click_policy(request.rel_url.query['value']) + core.write_config() + else: + return web.Response(text=core.get_config()['double_click_policy'], status=200) + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/channel_url_list") +async def 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'] + + 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) + + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/notice") +async def get_notice(request): + url = "github.com" + path = "/ltdrdata/ltdrdata.github.io/wiki/News" + + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + async with session.get(f"https://{url}{path}") as response: + if response.status == 200: + # html_content = response.read().decode('utf-8') + html_content = await response.text() + + pattern = re.compile(r'
([\s\S]*?)
') + match = pattern.search(html_content) + + if match: + markdown_content = match.group(1) + markdown_content += f"
ComfyUI: {core.comfy_ui_revision}[{comfy_ui_hash[:6]}]({core.comfy_ui_commit_datetime.date()})" + # markdown_content += f"
         ()" + markdown_content += f"
Manager: {core.version_str}" + + try: + if core.comfy_ui_required_commit_datetime.date() > core.comfy_ui_commit_datetime.date(): + markdown_content = f'

Your ComfyUI is too OUTDATED!!!

' + markdown_content + except: + pass + + return web.Response(text=markdown_content, status=200) + else: + return web.Response(text="Unable to retrieve Notice", status=200) + else: + return web.Response(text="Unable to retrieve Notice", status=200) + + +@PromptServer.instance.routes.get("/manager/reboot") +def restart(self): + try: + sys.stdout.close_log() + except Exception as e: + pass + + if '__COMFY_CLI_SESSION__' in os.environ: + with open(os.path.join(os.environ['__COMFY_CLI_SESSION__'], '.reboot'), 'w') as file: + pass + + print(f"\nRestarting...\n\n") + exit(0) + + print(f"\nRestarting... [Legacy Mode]\n\n") + return os.execv(sys.executable, [sys.executable] + sys.argv) + + +def sanitize_filename(input_string): + # 알파벳, 숫자, 및 밑줄 이외의 문자를 밑줄로 대체 + result_string = re.sub(r'[^a-zA-Z0-9_]', '_', input_string) + return result_string + + +@PromptServer.instance.routes.post("/manager/component/save") +async def save_component(request): + try: + data = await request.json() + name = data['name'] + workflow = data['workflow'] + + if not os.path.exists(components_path): + os.mkdir(components_path) + + if 'packname' in workflow and workflow['packname'] != '': + sanitized_name = sanitize_filename(workflow['packname']) + '.pack' + else: + sanitized_name = sanitize_filename(name) + '.json' + + filepath = os.path.join(components_path, sanitized_name) + components = {} + if os.path.exists(filepath): + with open(filepath) as f: + components = json.load(f) + + components[name] = workflow + + with open(filepath, 'w') as f: + json.dump(components, f, indent=4, sort_keys=True) + return web.Response(text=filepath, status=200) + except: + return web.Response(status=400) + + +@PromptServer.instance.routes.post("/manager/component/loads") +async def load_components(request): + try: + json_files = [f for f in os.listdir(components_path) if f.endswith('.json')] + pack_files = [f for f in os.listdir(components_path) if f.endswith('.pack')] + + components = {} + for json_file in json_files + pack_files: + file_path = os.path.join(components_path, json_file) + with open(file_path, 'r') as file: + try: + # When there is a conflict between the .pack and the .json, the pack takes precedence and overrides. + components.update(json.load(file)) + except json.JSONDecodeError as e: + print(f"[ComfyUI-Manager] Error decoding component file in file {json_file}: {e}") + + return web.json_response(components) + except Exception as e: + print(f"[ComfyUI-Manager] failed to load components\n{e}") + return web.Response(status=400) + + +@PromptServer.instance.routes.get("/manager/share_option") +async def share_option(request): + if "value" in request.rel_url.query: + core.get_config()['share_option'] = request.rel_url.query['value'] + core.write_config() + else: + return web.Response(text=core.get_config()['share_option'], status=200) + + return web.Response(status=200) + + +def get_openart_auth(): + if not os.path.exists(os.path.join(core.comfyui_manager_path, ".openart_key")): + return None + try: + with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "r") as f: + openart_key = f.read().strip() + return openart_key if openart_key else None + except: + return None + + +def get_matrix_auth(): + if not os.path.exists(os.path.join(core.comfyui_manager_path, "matrix_auth")): + return None + try: + with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "r") as f: + matrix_auth = f.read() + homeserver, username, password = matrix_auth.strip().split("\n") + if not homeserver or not username or not password: + return None + return { + "homeserver": homeserver, + "username": username, + "password": password, + } + except: + return None + + +def get_comfyworkflows_auth(): + if not os.path.exists(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey")): + return None + try: + with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f: + share_key = f.read() + if not share_key.strip(): + return None + return share_key + except: + return None + + +def get_youml_settings(): + if not os.path.exists(os.path.join(core.comfyui_manager_path, ".youml")): + return None + try: + with open(os.path.join(core.comfyui_manager_path, ".youml"), "r") as f: + youml_settings = f.read().strip() + return youml_settings if youml_settings else None + except: + return None + + +def set_youml_settings(settings): + with open(os.path.join(core.comfyui_manager_path, ".youml"), "w") as f: + f.write(settings) + + +@PromptServer.instance.routes.get("/manager/get_openart_auth") +async def api_get_openart_auth(request): + # print("Getting stored Matrix credentials...") + openart_key = get_openart_auth() + if not openart_key: + return web.Response(status=404) + return web.json_response({"openart_key": openart_key}) + + +@PromptServer.instance.routes.post("/manager/set_openart_auth") +async def api_set_openart_auth(request): + json_data = await request.json() + openart_key = json_data['openart_key'] + with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "w") as f: + f.write(openart_key) + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/get_matrix_auth") +async def api_get_matrix_auth(request): + # print("Getting stored Matrix credentials...") + matrix_auth = get_matrix_auth() + if not matrix_auth: + return web.Response(status=404) + return web.json_response(matrix_auth) + + +@PromptServer.instance.routes.get("/manager/youml/settings") +async def api_get_youml_settings(request): + youml_settings = get_youml_settings() + if not youml_settings: + return web.Response(status=404) + return web.json_response(json.loads(youml_settings)) + + +@PromptServer.instance.routes.post("/manager/youml/settings") +async def api_set_youml_settings(request): + json_data = await request.json() + set_youml_settings(json.dumps(json_data)) + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/get_comfyworkflows_auth") +async def api_get_comfyworkflows_auth(request): + # Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken' + # in the same directory as the ComfyUI base folder + # print("Getting stored Comfyworkflows.com auth...") + comfyworkflows_auth = get_comfyworkflows_auth() + if not comfyworkflows_auth: + return web.Response(status=404) + return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth}) + + +args.enable_cors_header = "*" +if hasattr(PromptServer.instance, "app"): + app = PromptServer.instance.app + cors_middleware = server.create_cors_middleware(args.enable_cors_header) + app.middlewares.append(cors_middleware) + + +@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images") +async def set_esheep_workflow_and_images(request): + json_data = await request.json() + current_workflow = json_data['workflow'] + images = json_data['images'] + with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), "w", encoding='utf-8') as file: + json.dump(json_data, file, indent=4) + return web.Response(status=200) + + +@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images") +async def get_esheep_workflow_and_images(request): + with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file: + data = json.load(file) + return web.Response(status=200, text=json.dumps(data)) + + +def set_matrix_auth(json_data): + homeserver = json_data['homeserver'] + username = json_data['username'] + password = json_data['password'] + with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "w") as f: + f.write("\n".join([homeserver, username, password])) + + +def set_comfyworkflows_auth(comfyworkflows_sharekey): + with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f: + f.write(comfyworkflows_sharekey) + + +def has_provided_matrix_auth(matrix_auth): + return matrix_auth['homeserver'].strip() and matrix_auth['username'].strip() and matrix_auth['password'].strip() + + +def has_provided_comfyworkflows_auth(comfyworkflows_sharekey): + return comfyworkflows_sharekey.strip() + + +def extract_model_file_names(json_data): + """Extract unique file names from the input JSON data.""" + file_names = set() + model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'} + + # Recursively search for file names in the JSON data + def recursive_search(data): + if isinstance(data, dict): + for value in data.values(): + recursive_search(value) + elif isinstance(data, list): + for item in data: + recursive_search(item) + elif isinstance(data, str) and '.' in data: + file_names.add(os.path.basename(data)) # file_names.add(data) + + recursive_search(json_data) + return [f for f in list(file_names) if os.path.splitext(f)[1] in model_filename_extensions] + + +def find_file_paths(base_dir, file_names): + """Find the paths of the files in the base directory.""" + file_paths = {} + + for root, dirs, files in os.walk(base_dir): + # Exclude certain directories + dirs[:] = [d for d in dirs if d not in ['.git']] + + for file in files: + if file in file_names: + file_paths[file] = os.path.join(root, file) + return file_paths + + +def compute_sha256_checksum(filepath): + """Compute the SHA256 checksum of a file, in chunks""" + sha256 = hashlib.sha256() + with open(filepath, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b''): + sha256.update(chunk) + return sha256.hexdigest() + + +@PromptServer.instance.routes.post("/manager/share") +async def share_art(request): + # get json data + json_data = await request.json() + + matrix_auth = json_data['matrix_auth'] + comfyworkflows_sharekey = json_data['cw_auth']['cw_sharekey'] + + set_matrix_auth(matrix_auth) + set_comfyworkflows_auth(comfyworkflows_sharekey) + + share_destinations = json_data['share_destinations'] + credits = json_data['credits'] + title = json_data['title'] + description = json_data['description'] + is_nsfw = json_data['is_nsfw'] + prompt = json_data['prompt'] + potential_outputs = json_data['potential_outputs'] + selected_output_index = json_data['selected_output_index'] + + try: + output_to_share = potential_outputs[int(selected_output_index)] + except: + # for now, pick the first output + output_to_share = potential_outputs[0] + + assert output_to_share['type'] in ('image', 'output') + output_dir = folder_paths.get_output_directory() + + if output_to_share['type'] == 'image': + asset_filename = output_to_share['image']['filename'] + asset_subfolder = output_to_share['image']['subfolder'] + + if output_to_share['image']['type'] == 'temp': + output_dir = folder_paths.get_temp_directory() + else: + asset_filename = output_to_share['output']['filename'] + asset_subfolder = output_to_share['output']['subfolder'] + + if asset_subfolder: + asset_filepath = os.path.join(output_dir, asset_subfolder, asset_filename) + else: + asset_filepath = os.path.join(output_dir, asset_filename) + + # get the mime type of the asset + assetFileType = mimetypes.guess_type(asset_filepath)[0] + + share_website_host = "UNKNOWN" + if "comfyworkflows" in share_destinations: + share_website_host = "https://comfyworkflows.com" + share_endpoint = f"{share_website_host}/api" + + # get presigned urls + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + async with session.post( + f"{share_endpoint}/get_presigned_urls", + json={ + "assetFileName": asset_filename, + "assetFileType": assetFileType, + "workflowJsonFileName": 'workflow.json', + "workflowJsonFileType": 'application/json', + }, + ) as resp: + assert resp.status == 200 + presigned_urls_json = await resp.json() + assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"] + assetFileKey = presigned_urls_json["assetFileKey"] + workflowJsonFilePresignedUrl = presigned_urls_json["workflowJsonFilePresignedUrl"] + workflowJsonFileKey = presigned_urls_json["workflowJsonFileKey"] + + # upload asset + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + async with session.put(assetFilePresignedUrl, data=open(asset_filepath, "rb")) as resp: + assert resp.status == 200 + + # upload workflow json + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + async with session.put(workflowJsonFilePresignedUrl, data=json.dumps(prompt['workflow']).encode('utf-8')) as resp: + assert resp.status == 200 + + model_filenames = extract_model_file_names(prompt['workflow']) + model_file_paths = find_file_paths(folder_paths.base_path, model_filenames) + + models_info = {} + for filename, filepath in model_file_paths.items(): + models_info[filename] = { + "filename": filename, + "sha256_checksum": compute_sha256_checksum(filepath), + "relative_path": os.path.relpath(filepath, folder_paths.base_path), + } + + # make a POST request to /api/upload_workflow with form data key values + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + form = aiohttp.FormData() + if comfyworkflows_sharekey: + form.add_field("shareKey", comfyworkflows_sharekey) + form.add_field("source", "comfyui_manager") + form.add_field("assetFileKey", assetFileKey) + form.add_field("assetFileType", assetFileType) + form.add_field("workflowJsonFileKey", workflowJsonFileKey) + form.add_field("sharedWorkflowWorkflowJsonString", json.dumps(prompt['workflow'])) + form.add_field("sharedWorkflowPromptJsonString", json.dumps(prompt['output'])) + form.add_field("shareWorkflowCredits", credits) + form.add_field("shareWorkflowTitle", title) + form.add_field("shareWorkflowDescription", description) + form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower()) + form.add_field("currentSnapshot", json.dumps(core.get_current_snapshot())) + form.add_field("modelsInfo", json.dumps(models_info)) + + async with session.post( + f"{share_endpoint}/upload_workflow", + data=form, + ) as resp: + assert resp.status == 200 + upload_workflow_json = await resp.json() + workflowId = upload_workflow_json["workflowId"] + + # check if the user has provided Matrix credentials + if "matrix" in share_destinations: + comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org' + filename = os.path.basename(asset_filepath) + content_type = assetFileType + + try: + from matrix_client.api import MatrixHttpApi + from matrix_client.client import MatrixClient + + homeserver = 'matrix.org' + if matrix_auth: + homeserver = matrix_auth.get('homeserver', 'matrix.org') + homeserver = homeserver.replace("http://", "https://") + if not homeserver.startswith("https://"): + homeserver = "https://" + homeserver + + client = MatrixClient(homeserver) + try: + token = client.login(username=matrix_auth['username'], password=matrix_auth['password']) + if not token: + return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400) + except: + return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400) + + matrix = MatrixHttpApi(homeserver, token=token) + with open(asset_filepath, 'rb') as f: + mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri'] + + workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri'] + + text_content = "" + if title: + text_content += f"{title}\n" + if description: + text_content += f"{description}\n" + if credits: + text_content += f"\ncredits: {credits}\n" + response = matrix.send_message(comfyui_share_room_id, text_content) + response = matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image') + response = matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file') + except: + import traceback + traceback.print_exc() + return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500) + + return web.json_response({ + "comfyworkflows": { + "url": None if "comfyworkflows" not in share_destinations else f"{share_website_host}/workflows/{workflowId}", + }, + "matrix": { + "success": None if "matrix" not in share_destinations else True + } + }, content_type='application/json', status=200) + + +def sanitize(data): + return data.replace("<", "<").replace(">", ">") + + +async def _confirm_try_install(sender, custom_node_url, msg): + json_obj = await core.get_data_by_mode('default', 'custom-node-list.json') + + sender = sanitize(sender) + msg = sanitize(msg) + target = core.lookup_customnode_by_url(json_obj, custom_node_url) + + if target is not None: + 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)) + + +cm_global.register_api('cm.try-install-custom-node', confirm_try_install) + +import asyncio + + +async def default_cache_update(): + async def get_cache(filename): + uri = 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/' + filename + cache_uri = str(core.simple_hash(uri)) + '_' + filename + cache_uri = os.path.join(core.cache_dir, cache_uri) + + json_obj = await core.get_data(uri, True) + + with core.cache_lock: + with open(cache_uri, "w", encoding='utf-8') as file: + json.dump(json_obj, file, indent=4, sort_keys=True) + print(f"[ComfyUI-Manager] default cache updated: {uri}") + + a = get_cache("custom-node-list.json") + b = get_cache("extension-node-map.json") + c = get_cache("model-list.json") + d = get_cache("alter-list.json") + + await asyncio.gather(a, b, c, d) + + +threading.Thread(target=lambda: asyncio.run(default_cache_update())).start() + +if not os.path.exists(core.config_path): + core.get_config() + core.write_config() + + +cm_global.register_extension('ComfyUI-Manager', + {'version': core.version, + 'name': 'ComfyUI Manager', + 'nodes': {'Terminal Log //CM'}, + 'description': 'It provides the ability to manage custom nodes in ComfyUI.', }) + diff --git a/js/common.js b/js/common.js index 0815c1eb..03615260 100644 --- a/js/common.js +++ b/js/common.js @@ -89,7 +89,10 @@ export async function install_pip(packages) { if(packages.includes('&')) app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`); - const res = await api.fetchApi(`/customnode/install/pip?packages=${packages}`); + const res = await api.fetchApi("/customnode/install/pip", { + method: "POST", + body: packages, + }); if(res.status == 200) { app.ui.dialog.show(`PIP package installation is processed.
To apply the pip packages, please click the button in ComfyUI.`); @@ -121,7 +124,10 @@ export async function install_via_git_url(url, manager_dialog) { app.ui.dialog.show(`Wait...

Installing '${url}'`); app.ui.dialog.element.style.zIndex = 10010; - const res = await api.fetchApi(`/customnode/install/git_url?url=${url}`); + const res = await api.fetchApi("/customnode/install/git_url", { + method: "POST", + body: url, + }); if(res.status == 200) { app.ui.dialog.show(`'${url}' is installed
To apply the installed custom node, please ComfyUI.`); @@ -148,7 +154,7 @@ export async function free_models() { let res = await api.fetchApi(`/free`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: '{}' + body: '{"unload_models": true}' }); if(res.status == 200) { diff --git a/js/snapshot.js b/js/snapshot.js index e2eed3f4..0ca7c76a 100644 --- a/js/snapshot.js +++ b/js/snapshot.js @@ -269,6 +269,7 @@ export class SnapshotManager extends ComfyDialog { save_button.onclick = () => { save_current_snapshot(); } save_button.style.display = "inline-block"; save_button.style.horizontalAlign = "right"; + save_button.style.width = "170px"; this.message_box = $el('div', {id:'custom-download-message'}, [$el('br'), '']); this.message_box.style.height = '60px'; diff --git a/model-list.json b/model-list.json index f636f9d6..5d40ebd7 100644 --- a/model-list.json +++ b/model-list.json @@ -2400,6 +2400,26 @@ "filename": "SUPIR-v0Q.ckpt", "url": "https://huggingface.co/camenduru/SUPIR/resolve/main/SUPIR-v0Q.ckpt" }, + { + "name": "Kijai/SUPIR-v0F_fp16.safetensors (pruned)", + "type": "checkpoints", + "base": "SUPIR", + "save_path": "checkpoints/SUPIR", + "description": "SUPIR checkpoint model", + "reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main", + "filename": "SUPIR-v0F_fp16.safetensors", + "url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0F_fp16.safetensors" + }, + { + "name": "Kijai/SUPIR-v0Q_fp16.safetensors (pruned)", + "type": "checkpoints", + "base": "SUPIR", + "save_path": "checkpoints/SUPIR", + "description": "SUPIR checkpoint model", + "reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main", + "filename": "SUPIR-v0Q_fp16.safetensors", + "url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0Q_fp16.safetensors" + }, { "name": "RAM", "type": "RAM", diff --git a/node_db/dev/custom-node-list.json b/node_db/dev/custom-node-list.json index a411b644..96804b88 100644 --- a/node_db/dev/custom-node-list.json +++ b/node_db/dev/custom-node-list.json @@ -10,6 +10,77 @@ }, + + { + "author": "kijai", + "title": "ComfyUI nodes to use DeepSeek-VL", + "reference": "https://github.com/kijai/ComfyUI-DeepSeek-VL", + "files": [ + "https://github.com/kijai/ComfyUI-DeepSeek-VL" + ], + "install_type": "git-clone", + "description": "[a/https://huggingface.co/deepseek-ai](https://huggingface.co/deepseek-ai)" + }, + { + "author": "GentlemanHu", + "title": "ComfyUI-Notifier", + "reference": "https://github.com/GentlemanHu/ComfyUI-Notifier", + "files": [ + "https://github.com/GentlemanHu/ComfyUI-Notifier" + ], + "install_type": "git-clone", + "description": "Nodes:GentlemanHu_Notifier" + }, + { + "author": "nat-chan", + "title": "comfyui-in-memory-transceiver", + "reference": "https://github.com/nat-chan/comfyui-in-memory-transceiver", + "files": [ + "https://github.com/nat-chan/comfyui-in-memory-transceiver" + ], + "install_type": "git-clone", + "description": "Why? When processing a large number of requests, the SaveImage and LoadImage nodes may be IO-limited, and using shared memory improves performance by passing images only through memory access, not through IO." + }, + { + "author": "DrMWeigand", + "title": "ComfyUI_LineBreakInserter", + "reference": "https://github.com/DrMWeigand/ComfyUI_LineBreakInserter", + "files": [ + "https://github.com/DrMWeigand/ComfyUI_LineBreakInserter" + ], + "install_type": "git-clone", + "description": "Nodes:Line Break Inserter" + }, + { + "author": "WilliamStanford", + "title": "visuallabs_comfyui_nodes", + "reference": "https://github.com/WilliamStanford/visuallabs_comfyui_nodes", + "files": [ + "https://github.com/WilliamStanford/visuallabs_comfyui_nodes" + ], + "install_type": "git-clone", + "description": "Nodes:PointStringFromFloatArray" + }, + { + "author": "bruce007lee", + "title": "comfyui-cleaner", + "reference": "https://github.com/bruce007lee/comfyui-cleaner", + "files": [ + "https://github.com/bruce007lee/comfyui-cleaner" + ], + "install_type": "git-clone", + "description": "Nodes:cleaner" + }, + { + "author": "ExponentialML", + "title": "ComfyUI_LiveDirector (WIP)", + "reference": "https://github.com/ExponentialML/ComfyUI_LiveDirector", + "files": [ + "https://github.com/ExponentialML/ComfyUI_LiveDirector" + ], + "install_type": "git-clone", + "description": "Experimental method to use reference video to drive motion in generations without training in ComfyUI." + }, { "author": "logtd", "title": "ComfyUI-MotionThiefExperiment", @@ -30,16 +101,6 @@ "install_type": "git-clone", "description": "Nodes:sound voice, text concat, latent to list, movie generate, movie batch, hy save image, generate story" }, - { - "author": "liusida", - "title": "ComfyUI-Login", - "reference": "https://github.com/liusida/ComfyUI-Login", - "files": [ - "https://github.com/liusida/ComfyUI-Login" - ], - "install_type": "git-clone", - "description": "This custom node serves as a proof-of-concept to explore the implementation of basic login functionality for ComfyUI.\nNOTE:In the future, if proven useful, this feature might be directly integrated into either ComfyUI or ComfyUI-Manager." - }, { "author": "gameltb", "title": "io_comfyui", diff --git a/node_db/forked/custom-node-list.json b/node_db/forked/custom-node-list.json index 69e5d0c4..76b4f038 100644 --- a/node_db/forked/custom-node-list.json +++ b/node_db/forked/custom-node-list.json @@ -1,5 +1,25 @@ { "custom_nodes": [ + { + "author": "ZHO-ZHO-ZHO", + "title": "Dr.Lt.Data/ComfyUI-YoloWorld-EfficientSAM", + "reference": "https://github.com/ltdrdata/ComfyUI-YoloWorld-EfficientSAM", + "files": [ + "https://github.com/ltdrdata/ComfyUI-YoloWorld-EfficientSAM" + ], + "install_type": "git-clone", + "description": "This fork includes [a/PR32](https://github.com/ZHO-ZHO-ZHO/ComfyUI-YoloWorld-EfficientSAM/pull/32)" + }, + { + "author": "ertu110", + "title": "sdxl_prompt_style", + "reference": "https://github.com/ertu110/sdxl_prompt_style", + "files": [ + "https://github.com/ertu110/sdxl_prompt_style" + ], + "install_type": "git-clone", + "description": "This project is a complete benchmark [a/https://github.com/twri/sdxl_prompt_styler](https://github.com/twri/sdxl_prompt_styler) A large amount of code inside comes from https://github.com/twri/sdxl_prompt_styler Project and [a/https://www.nodecafe.org/package/pythongosssss_ComfyUI-Custom-Scripts](https://www.nodecafe.org/package/pythongosssss_ComfyUI-Custom-Scripts) project\nThe functionality of this project is related to https://github.com/twri/sdxl_prompt_styler Highly overlapping, the only purpose of creating this project is because there are too many styles when selecting, resulting in a long and inconvenient dropdown box. Therefore, To address this issue, this project has added a secondary menu to the style." + }, { "author": "gustproof", "title": "ComfyUI_IPAdapter_plus_Style_Components", @@ -10,16 +30,6 @@ "install_type": "git-clone", "description": "Style Components is an IP-Adapter model conditioned on anime styles. The style embeddings can either be extracted from images or created manually. This repo currently only supports the SDXL model trained on AutismmixPony." }, - { - "author": "BlenderNeko", - "title": "Dr.Lt.Data/Advanced CLIP Text Encode (PR21)", - "reference": "https://github.com/ltdrdata/ComfyUI_ADV_CLIP_emb", - "files": [ - "https://github.com/ltdrdata/ComfyUI_ADV_CLIP_emb" - ], - "install_type": "git-clone", - "description": "[a/PR21](https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb/pull/21) is applied.\nmissing 'clip_layer' method fix." - }, { "author": "gameltb", "title": "comfyui-stablsr", diff --git a/node_db/legacy/custom-node-list.json b/node_db/legacy/custom-node-list.json index ef73cd2a..1c00dd13 100644 --- a/node_db/legacy/custom-node-list.json +++ b/node_db/legacy/custom-node-list.json @@ -8,7 +8,48 @@ "install_type": "git-clone", "description": "If you see this message, your ComfyUI-Manager is outdated.\nLegacy channel provides only the list of the deprecated nodes. If you want to find the complete node list, please go to the Default channel." }, + + { + "author": "Big Idea Technology", + "title": "Image Text Overlay Node for ComfyUI [DEPRECATED]", + "reference": "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay", + "files": [ + "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay" + ], + "install_type": "git-clone", + "description": "Please note that the ImageTextOverlay project is no longer supported and has been moved to a new repository. For ongoing developments, contributions, and issues, please refer to the new repository at: [a/https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools](https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools)" + }, + { + "author": "meimeilook", + "title": "ComfyUI_IPAdapter_plus.old [backward compatbility]", + "reference": "https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old", + "files": [ + "https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old" + ], + "install_type": "git-clone", + "description": "This repo is created to provide backward compatibility for workflows configured with the old IPAdapter." + }, + { + "author": "mlinmg", + "title": "LaMa Preprocessor [DEPRECATED]", + "reference": "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor", + "files": [ + "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor" + ], + "install_type": "git-clone", + "description": "A LaMa prerocessor for ComfyUI. This preprocessor finally enable users to generate coherent inpaint and outpaint prompt-free. The best results are given on landscapes, not so much in drawings/animation." + }, + { + "author": "CapsAdmin", + "title": "ComfyUI-Euler-Smea-Dyn-Sampler [DEPRECATED]", + "reference": "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler", + "files": [ + "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler" + ], + "install_type": "git-clone", + "description": "Just a comfyui version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds the sampler directly to existing samplers." + }, { "author": "BlakeOne", "title": "ComfyUI FastImageListToImageBatch [REMOVED]", @@ -59,16 +100,6 @@ "install_type": "git-clone", "description": "Proof of concent on how to use IPAdapter to control tiled upscaling. NOTE: You need to have 'ComfyUI_IPAdapter_plus' installed." }, - { - "author": "meimeilook", - "title": "ComfyUI_IPAdapter_plus", - "reference": "https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old", - "files": [ - "https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old" - ], - "install_type": "git-clone", - "description": "This repo is created to provide backward compatibility for workflows configured with the old IPAdapter." - }, { "author": "XINZHANG-ops", "title": "comfyui-xin-nodes [REMOVED]", diff --git a/node_db/new/custom-node-list.json b/node_db/new/custom-node-list.json index 2bba2bfa..9cfe83b0 100644 --- a/node_db/new/custom-node-list.json +++ b/node_db/new/custom-node-list.json @@ -10,6 +10,598 @@ }, + + + { + "author": "ty0x2333", + "title": "ComfyUI-Dev-Utils", + "reference": "https://github.com/ty0x2333/ComfyUI-Dev-Utils", + "files": [ + "https://github.com/ty0x2333/ComfyUI-Dev-Utils" + ], + "install_type": "git-clone", + "description": "Execution Time Analysis, Reroute Enhancement, Node collection for developers." + }, + { + "author": "chaojie", + "title": "ComfyUI-LaVIT", + "reference": "https://github.com/chaojie/ComfyUI-LaVIT", + "files": [ + "https://github.com/chaojie/ComfyUI-LaVIT" + ], + "install_type": "git-clone", + "description": "Nodes:VideoLaVITLoader, VideoLaVITT2V, VideoLaVITI2V, VideoLaVITI2VLong, VideoLaVITT2VLong, VideoLaVITI2I" + }, + { + "author": "smthemex", + "title": "ComfyUI_Pipeline_Tool", + "reference": "https://github.com/smthemex/ComfyUI_Pipeline_Tool", + "files": [ + "https://github.com/smthemex/ComfyUI_Pipeline_Tool" + ], + "install_type": "git-clone", + "description": "Nodes:Pipeline_Tool" + }, + { + "author": "blueraincoatli", + "title": "comfyUI_SillyNodes", + "reference": "https://github.com/blueraincoatli/comfyUI_SillyNodes", + "files": [ + "https://github.com/blueraincoatli/comfyUI_SillyNodes" + ], + "install_type": "git-clone", + "description": "Using rgthree's fast_group_muter and bookmark nodes, introduce the pyautogui library to simulate clicks and hotkeys, and run groups in sequence. screen manipulation is involved" + }, + { + "author": "Fannovel16", + "title": "ComfyUI-MagickWand", + "reference": "https://github.com/Fannovel16/ComfyUI-MagickWand", + "files": [ + "https://github.com/Fannovel16/ComfyUI-MagickWand" + ], + "install_type": "git-clone", + "description": "Proper implementation of ImageMagick - the famous software suite for editing and manipulating digital images to ComfyUI using [a/wandpy](https://github.com/emcconville/wand).\nNOTE: You need to install ImageMagick, manually." + }, + { + "author": "MinusZoneAI", + "title": "ComfyUI-Prompt-MZ", + "reference": "https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ", + "files": [ + "https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ" + ], + "install_type": "git-clone", + "description": "Use llama.cpp to help generate some nodes for prompt word related work" + }, + { + "author": "AIFSH", + "title": "ComfyUI-WhisperX", + "reference": "https://github.com/AIFSH/ComfyUI-WhisperX", + "files": [ + "https://github.com/AIFSH/ComfyUI-WhisperX" + ], + "install_type": "git-clone", + "description": "a comfyui cuatom node for audio subtitling based on [a/whisperX](https://github.com/m-bain/whisperX.git) and [a/translators](https://github.com/UlionTse/translators)" + }, + { + "author": "aburahamu", + "title": "ComfyUI-RequestPoster", + "reference": "https://github.com/aburahamu/ComfyUI-RequestsPoster", + "files": [ + "https://github.com/aburahamu/ComfyUI-RequestsPoster" + ], + "install_type": "git-clone", + "description": "This extension can send HTTP Requests. You can request image generation to StableDiffusion3 and post images to X (Twitter) and Discord." + }, + { + "author": "DarKDinDoN", + "title": "ComfyUI Checkpoint Automatic Config", + "reference": "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config", + "files": [ + "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config" + ], + "install_type": "git-clone", + "description": "This node was designed to help with checkpoint configuration." + }, + { + "author": "if-ai", + "title": "ComfyUI-IF_AI_WishperSpeechNode", + "reference": "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode", + "files": [ + "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode" + ], + "install_type": "git-clone", + "description": "This repository hosts a Text-to-Speech (TTS) application that leverages Whisper Speech for voice synthesis, allowing users to train a voice model on-the-fly. It is built on ComfyUI and supports rapid training and inference processes." + }, + { + "author": "Big-Idea-Technology", + "title": "ComfyUI-Book-Tools Nodes for ComfyUI", + "reference": "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools", + "files": [ + "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools" + ], + "install_type": "git-clone", + "description": "ComfyUI-Book-Tools is a set o new nodes for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding. Loop with any parameters (*), prompt batch schedule with prompt selector, end queue for automatic ending current queue." + }, + { + "author": "TencentQQGYLab", + "title": "ComfyUI-ELLA", + "reference": "https://github.com/TencentQQGYLab/ComfyUI-ELLA", + "files": [ + "https://github.com/TencentQQGYLab/ComfyUI-ELLA" + ], + "install_type": "git-clone", + "description": "ComfyUI implementation for [a/ELLA](https://github.com/TencentQQGYLab/ELLA)." + }, + { + "author": "turkyden", + "title": "ComfyUI-Comic", + "reference": "https://github.com/turkyden/ComfyUI-Comic", + "files": [ + "https://github.com/turkyden/ComfyUI-Comic" + ], + "install_type": "git-clone", + "description": "a comfyui plugin for image to comic" + }, + { + "author": "Intersection98", + "title": "ComfyUI-MX-post-processing-nodes", + "reference": "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes", + "files": [ + "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes" + ], + "install_type": "git-clone", + "description": "A collection of post processing nodes for ComfyUI, dds image post-processing adjustment capabilities to the ComfyUI." + }, + { + "author": "florestefano1975", + "title": "ComfyUI StabilityAI Suite", + "reference": "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite", + "files": [ + "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite" + ], + "install_type": "git-clone", + "description": "This fork of the official StabilityAI repository contains a number of enhancements and implementations." + }, + { + "author": "hay86", + "title": "ComfyUI MiniCPM-V", + "reference": "https://github.com/hay86/ComfyUI_MiniCPM-V", + "files": [ + "https://github.com/hay86/ComfyUI_MiniCPM-V" + ], + "install_type": "git-clone", + "description": "Unofficial implementation of [a/MiniCPM-V](https://github.com/OpenBMB/MiniCPM-V) for ComfyUI" + }, + { + "author": "sugarkwork", + "title": "comfyui_tag_filter", + "reference": "https://github.com/sugarkwork/comfyui_tag_fillter", + "files": [ + "https://github.com/sugarkwork/comfyui_tag_fillter" + ], + "install_type": "git-clone", + "description": "This is a custom node of ComfyUI that categorizes tags outputted by tools like WD14Tagger, filters them by each category, and returns the filtered results." + }, + { + "author": "chaojie", + "title": "ComfyUI-CameraCtrl-Wrapper", + "reference": "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper", + "files": [ + "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI-CameraCtrl-Wrapper" + }, + { + "author": "Stability-AI", + "title": "Stability API nodes for ComfyUI", + "reference": "https://github.com/Stability-AI/ComfyUI-SAI_API", + "files": [ + "https://github.com/Stability-AI/ComfyUI-SAI_API" + ], + "install_type": "git-clone", + "description": "Nodes:Stability SD3, Stability Outpainting, Stability Search and Replace, Stability Image Core, Stability Inpainting, Stability Remove Background, Stability Creative Upscale.\nAdd API key to environment variable 'SAI_API_KEY'\nAlternatively you can write your API key to file 'sai_platform_key.txt'\nYou can also use and/or override the above by entering your API key in the 'api_key_override' field of each node." + }, + { + "author": "JettHu", + "title": "ComfyUI_TGate", + "reference": "https://github.com/JettHu/ComfyUI_TGate", + "files": [ + "https://github.com/JettHu/ComfyUI_TGate" + ], + "install_type": "git-clone", + "description": "ComfyUI reference implementation for [a/T-GATE](https://github.com/HaozheLiu-ST/T-GATE)." + }, + { + "author": "AIFSH", + "title": "ComfyUI-MuseTalk_FSH", + "reference": "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH", + "files": [ + "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH" + ], + "install_type": "git-clone", + "description": "the comfyui custom node of [a/MuseTalk](https://github.com/TMElyralab/MuseTalk) to make audio driven videos!" + }, + { + "author": "heshengtao", + "title": "comfyui_LLM_party", + "reference": "https://github.com/heshengtao/comfyui_LLM_party", + "files": [ + "https://github.com/heshengtao/comfyui_LLM_party" + ], + "install_type": "git-clone", + "description": "A set of block-based LLM agent node libraries designed for ComfyUI.This project aims to develop a complete set of nodes for LLM workflow construction based on comfyui. It allows users to quickly and conveniently build their own LLM workflows and easily integrate them into their existing SD workflows." + }, + { + "author": "FrankChieng", + "title": "ComfyUI_MagicClothing", + "reference": "https://github.com/frankchieng/ComfyUI_MagicClothing", + "files": [ + "https://github.com/frankchieng/ComfyUI_MagicClothing" + ], + "install_type": "git-clone", + "description": "implementation of MagicClothing with garment and prompt in ComfyUI" + }, + { + "author": "VAST-AI-Research", + "title": "Tripo for ComfyUI", + "reference": "https://github.com/VAST-AI-Research/ComfyUI-Tripo", + "files": [ + "https://github.com/VAST-AI-Research/ComfyUI-Tripo" + ], + "install_type": "git-clone", + "description": "Custom nodes for using [a/Tripo](https://www.tripo3d.ai/) in ComfyUI to create 3D from text and image prompts." + }, + { + "author": "AonekoSS", + "title": "ComfyUI-SimpleCounter", + "reference": "https://github.com/xliry/ComfyUI_SendDiscord", + "files": [ + "https://github.com/xliry/ComfyUI_SendDiscord/raw/main/SendDiscord.py" + ], + "install_type": "copy", + "description": "Nodes:Send Video to Discor" + }, + { + "author": "AonekoSS", + "title": "ComfyUI-SimpleCounter", + "reference": "https://github.com/AonekoSS/ComfyUI-SimpleCounter", + "files": [ + "https://github.com/AonekoSS/ComfyUI-SimpleCounter" + ], + "install_type": "git-clone", + "description": "Nodes:Simple Counter" + }, + { + "author": "TashaSkyUp", + "title": "ComfyUI_LiteLLM", + "reference": "https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM", + "files": [ + "https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM" + ], + "install_type": "git-clone", + "description": "Nodes for interfacing with LiteLLM" + }, + { + "author": "smthemex", + "title": "ComfyUI_Pic2Story", + "reference": "https://github.com/smthemex/ComfyUI_Pic2Story", + "files": [ + "https://github.com/smthemex/ComfyUI_Pic2Story" + ], + "install_type": "git-clone", + "description": "ComfyUI simple node based on BLIP method, with the function of 'Image to Txt'." + }, + { + "author": "fevre27", + "title": "Self-Guidance nodes", + "reference": "https://github.com/forever22777/comfyui-self-guidance", + "files": [ + "https://github.com/forever22777/comfyui-self-guidance" + ], + "install_type": "git-clone", + "description": "Unofficial ComfyUI implementation of Self-Guidance." + }, + { + "author": "chaojie", + "title": "ComfyUI-EasyAnimate", + "reference": "https://github.com/chaojie/ComfyUI-EasyAnimate", + "files": [ + "https://github.com/chaojie/ComfyUI-EasyAnimate" + ], + "install_type": "git-clone", + "description": "ComfyUI-EasyAnimate" + }, + { + "author": "hay86", + "title": "ComfyUI DDColor", + "reference": "https://github.com/hay86/ComfyUI_DDColor", + "files": [ + "https://github.com/hay86/ComfyUI_DDColor" + ], + "install_type": "git-clone", + "description": "Unofficial implementation of [a/DDColor](https://github.com/piddnad/DDColor) for ComfyUI" + }, + { + "author": "hay86", + "title": "ComfyUI OpenVoice", + "reference": "https://github.com/hay86/ComfyUI_OpenVoice", + "files": [ + "https://github.com/hay86/ComfyUI_OpenVoice" + ], + "install_type": "git-clone", + "description": "Unofficial implementation of [a/OpenVoice](https://github.com/myshell-ai/OpenVoice) for ComfyUI" + }, + { + "author": "kealiu", + "title": "ComfyUI Load and Save file to S3", + "reference": "https://github.com/kealiu/ComfyUI-S3-Tools", + "files": [ + "https://github.com/kealiu/ComfyUI-S3-Tools" + ], + "install_type": "git-clone", + "description": "Nodes:Load From S3, Save To S3." + }, + { + "author": "txt2any", + "title": "ComfyUI-PromptOrganizer", + "reference": "https://github.com/txt2any/ComfyUI-PromptOrganizer", + "files": [ + "https://github.com/txt2any/ComfyUI-PromptOrganizer" + ], + "install_type": "git-clone", + "description": "This is a custom node for ComfyUI that automatically saves your AI-generated images specifically to [a/www.txt2any.com](http://www.txt2any.com/)." + }, + { + "author": "jtydhr88", + "title": "ComfyUI-InstantMesh", + "reference": "https://github.com/jtydhr88/ComfyUI-InstantMesh", + "files": [ + "https://github.com/jtydhr88/ComfyUI-InstantMesh" + ], + "install_type": "git-clone", + "description": "ComfyUI InstantMesh is custom nodes that running TencentARC/InstantMesh into ComfyUI, this extension depends on ComfyUI-3D-Pack. Please refer to Readme carefully to install." + }, + { + "author": "kunieone", + "title": "ComfyUI_alkaid", + "reference": "https://github.com/kunieone/ComfyUI_alkaid", + "files": [ + "https://github.com/kunieone/ComfyUI_alkaid" + ], + "install_type": "git-clone", + "description": "Nodes:A_Face3DSwapper, A_FaceCrop, A_FacePaste, A_OpenPosePreprocessor, A_EmptyLatentImageLongside, A_GetImageSize, AlkaidLoader, AdapterFaceLoader, AdapterStyleLoader, ..." + }, + { + "author": "royceschultz", + "title": "ComfyUI-TranscriptionTools", + "reference": "https://github.com/royceschultz/ComfyUI-TranscriptionTools", + "files": [ + "https://github.com/royceschultz/ComfyUI-TranscriptionTools" + ], + "install_type": "git-clone", + "description": "Transcribe audio and video files in ComfyUI." + }, + { + "author": "turkyden", + "title": "ComfyUI-Sticker", + "reference": "https://github.com/turkyden/ComfyUI-Sticker", + "files": [ + "https://github.com/turkyden/ComfyUI-Sticker" + ], + "install_type": "git-clone", + "description": "image to sticker" + }, + { + "author": "quadme7macoon", + "title": "ComfyUI-ShadertoyGL", + "reference": "https://github.com/e7mac/ComfyUI-ShadertoyGL", + "files": [ + "https://github.com/e7mac/ComfyUI-ShadertoyGL" + ], + "install_type": "git-clone", + "description": "Nodes:Shadertoy, Shader, ColorChannelOffset." + }, + { + "author": "quadmoon", + "title": "quadmoon's ComfyUI nodes", + "reference": "https://github.com/traugdor/ComfyUI-quadMoons-nodes", + "files": [ + "https://github.com/traugdor/ComfyUI-quadMoons-nodes" + ], + "install_type": "git-clone", + "description": "These are just some nodes I wanted and couldn't find where anyone else had made them yet." + }, + { + "author": "Sorcerio", + "title": "MBM's Music Visualizer", + "reference": "https://github.com/Sorcerio/MBM-Music-Visualizer", + "files": [ + "https://github.com/Sorcerio/MBM-Music-Visualizer" + ], + "install_type": "git-clone", + "description": "An image generation based music visualizer integrated into comfyanonymous/ComfyUI as custom nodes." + }, + { + "author": "BlakeOne", + "title": "ComfyUI NodeReset", + "reference": "https://github.com/BlakeOne/ComfyUI-NodeReset", + "files": [ + "https://github.com/BlakeOne/ComfyUI-NodeReset" + ], + "install_type": "git-clone", + "description": "An extension for ComyUI to allow resetting a node's inputs to their default values.\nNOTE:Right click any node and choose 'Restore default values' from the context menu." + }, + { + "author": "AIFSH", + "title": "ComfyUI-GPT_SoVITS", + "reference": "https://github.com/AIFSH/ComfyUI-GPT_SoVITS", + "files": [ + "https://github.com/AIFSH/ComfyUI-GPT_SoVITS" + ], + "install_type": "git-clone", + "description": "a comfyui custom node for [a/GPT-SoVITS](https://github.com/RVC-Boss/GPT-SoVITS)! you can voice cloning and tts in comfyui now\n[w/NOTE:make sure ffmpeg is worked in your commandline]" + }, + { + "author": "aburahamu", + "title": "ComfyUI-RequestsPoster", + "reference": "https://github.com/aburahamu/ComfyUI-RequestsPoster", + "files": [ + "https://github.com/aburahamu/ComfyUI-RequestsPoster" + ], + "install_type": "git-clone", + "description": "This custom node is that simply posts HttpRequest from ComfyUI." + }, + { + "author": "smthemex", + "title": "ComfyUI_ParlerTTS", + "reference": "https://github.com/smthemex/ComfyUI_ParlerTTS", + "files": [ + "https://github.com/smthemex/ComfyUI_ParlerTTS" + ], + "install_type": "git-clone", + "description": "This is a simple ComfyUI custom TTS node based on [a/Parler_tts](https://huggingface.co/parler-tts)." + }, + { + "author": "unwdef", + "title": "unwdef-nodes", + "reference": "https://github.com/unwdef/unwdef-nodes-comfyui", + "files": [ + "https://github.com/unwdef/unwdef-nodes-comfyui" + ], + "install_type": "git-clone", + "description": "Custom nodes for ComfyUI by unwdef." + }, + { + "author": "kijai", + "title": "ComfyUI-BrushNet-Wrapper", + "reference": "https://github.com/kijai/ComfyUI-BrushNet-Wrapper", + "files": [ + "https://github.com/kijai/ComfyUI-BrushNet-Wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI wrapper nodes to use the Diffusers implementation of BrushNet" + }, + { + "author": "pamparamm", + "title": "Perturbed-Attention Guidance", + "reference": "https://github.com/pamparamm/sd-perturbed-attention", + "files": [ + "https://github.com/pamparamm/sd-perturbed-attention" + ], + "install_type": "git-clone", + "description": "Perturbed-Attention Guidance node for ComfyUI." + }, + { + "author": "kale4eat", + "title": "ComfyUI-speech-dataset-toolkit", + "reference": "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit", + "files": [ + "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit" + ], + "install_type": "git-clone", + "description": "Basic audio tools using torchaudio for ComfyUI. It is assumed to assist in the speech dataset creation for ASR, TTS, etc." + }, + { + "author": "nullquant", + "title": "BrushNet", + "reference": "https://github.com/nullquant/ComfyUI-BrushNet", + "files": [ + "https://github.com/nullquant/ComfyUI-BrushNet" + ], + "install_type": "git-clone", + "description": "Custom nodes for ComfyUI allow to inpaint using Brushnet: '[a/BrushNet: A Plug-and-Play Image Inpainting Model with Decomposed Dual-Branch Diffusion](https://arxiv.org/abs/2403.06976)'." + }, + { + "author": "logtd", + "title": "ComfyUI-RAVE Attention", + "reference": "https://github.com/logtd/ComfyUI-RAVE_ATTN", + "files": [ + "https://github.com/logtd/ComfyUI-RAVE_ATTN" + ], + "install_type": "git-clone", + "description": "ComfyUI nodes to use RAVE attention as a temporal attention mechanism.\nThis differs from other implementations in that it does not concatenate the images together, but within the UNet's Self-Attention mechanism performs the RAVE technique. By not altering the images/latents throughout the UNet, this method does not affect other temporal techniques, style mechanisms, or other UNet modifications.\nFor example, it can be combined with AnimateDiff, ModelScope/ZeroScope, or FLATTEN." + }, + { + "author": "BlakeOne", + "title": "ComfyUI NodePresets", + "reference": "https://github.com/BlakeOne/ComfyUI-NodePresets", + "files": [ + "https://github.com/BlakeOne/ComfyUI-NodePresets" + ], + "install_type": "git-clone", + "description": "An extension for ComyUI that enables saving and loading node presets using the node's context menu.\nRight click a node and choose 'Presets' from its context menu to access the node's presets." + }, + { + "author": "Wicloz", + "title": "ComfyUI-Simply-Nodes", + "reference": "https://github.com/Wicloz/ComfyUI-Simply-Nodes", + "files": [ + "https://github.com/Wicloz/ComfyUI-Simply-Nodes" + ], + "install_type": "git-clone", + "description": "Nodes:Conditional LoRA Loader, Multiline Text, Text Flow Controller, Select SDXL Resolution, Random Style Prompt." + }, + { + "author": "AIFSH", + "title": "ComfyUI-IP_LAP", + "reference": "https://github.com/AIFSH/ComfyUI-IP_LAP", + "files": [ + "https://github.com/AIFSH/ComfyUI-IP_LAP" + ], + "install_type": "git-clone", + "description": "Nodes:IP_LAP Node, Video Loader, PreView Video, Combine Audio Video. the comfyui custom node of [a/IP_LAP](https://github.com/Weizhi-Zhong/IP_LAP) to make audio driven videos!" + }, + { + "author": "kijai", + "title": "ComfyUI-LaVi-Bridge-Wrapper", + "reference": "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper", + "files": [ + "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI wrapper node to test LaVi-Bridge using Diffusers" + }, + { + "author": "ALatentPlace", + "title": "ComfyUI_yanc", + "reference": "https://github.com/ALatentPlace/ComfyUI_yanc", + "files": [ + "https://github.com/ALatentPlace/ComfyUI_yanc" + ], + "install_type": "git-clone", + "description": "Yet Another Node Collection. Adds some useful nodes, check out the GitHub page for more details." + }, + { + "author": "choey", + "title": "Comfy-Topaz", + "reference": "https://github.com/choey/Comfy-Topaz", + "files": [ + "https://github.com/choey/Comfy-Topaz" + ], + "install_type": "git-clone", + "description": "Comfy-Topaz is a custom node for ComfyUI, which integrates with Topaz Photo AI to enhance (upscale, sharpen, denoise, etc.) images, allowing this traditionally asynchronous step to become a part of ComfyUI workflows.\nNOTE:Licensed installation of Topaz Photo AI" + }, + { + "author": "ExponentialML", + "title": "ComfyUI_ELLA", + "reference": "https://github.com/ExponentialML/ComfyUI_ELLA", + "files": [ + "https://github.com/ExponentialML/ComfyUI_ELLA" + ], + "install_type": "git-clone", + "description": "ComfyUI Implementaion of ELLA: Equip Diffusion Models with LLM for Enhanced Semantic Alignment" + }, + { + "author": "kijai", + "title": "ComfyUI-ELLA-wrapper", + "reference": "https://github.com/kijai/ComfyUI-ELLA-wrapper", + "files": [ + "https://github.com/kijai/ComfyUI-ELLA-wrapper" + ], + "install_type": "git-clone", + "description": "ComfyUI wrapper nodes to use the Diffusers implementation of ELLA" + }, { "author": "sdfxai", "title": "SDFXBridgeForComfyUI - ComfyUI Custom Node for SDFX Integration", @@ -21,14 +613,24 @@ "description": "SDFXBridgeForComfyUI is a custom node designed for seamless integration between ComfyUI and SDFX. This custom node allows users to make ComfyUI compatible with SDFX when running the ComfyUI instance on their local machines." }, { - "author": "CapsAdmin", - "title": "ComfyUI-Euler-Smea-Dyn-Sampler", - "reference": "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler", + "author": "Koishi-Star", + "title": "Euler-Smea-Dyn-Sampler", + "reference": "https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler", "files": [ - "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler" + "https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler" ], "install_type": "git-clone", - "description": "Just a comfyui version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds the sampler directly to existing samplers." + "description": "СomfyUI version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds samplers directly to KSampler nodes." + }, + { + "author": "smthemex", + "title": "ComfyUI_ChatGLM_API", + "reference": "https://github.com/smthemex/ComfyUI_ChatGLM_API", + "files": [ + "https://github.com/smthemex/ComfyUI_ChatGLM_API" + ], + "install_type": "git-clone", + "description": "You can call Chatglm's API in comfyUI to translate and describe pictures, and the API similar to OpenAI." }, { "author": "AIFSH", @@ -50,16 +652,6 @@ "install_type": "git-clone", "description": "ComfyUI_StreamingT2V" }, - { - "author": "abdozmantar", - "title": "InstaSwap Face Swap Node for ComfyUI", - "reference": "https://github.com/abdozmantar/ComfyUI-InstaSwap", - "files": [ - "https://github.com/abdozmantar/ComfyUI-InstaSwap" - ], - "install_type": "git-clone", - "description": "Fastest Face Swap Extension Node for ComfyUI, Single node and FastTrack: Lightning-Speed Facial Transformation for your projects." - }, { "author": "Zuellni", "title": "ComfyUI ExLlamaV2 Nodes", @@ -109,587 +701,6 @@ ], "install_type": "git-clone", "description": "ComfyUI-Open-Sora-Plan" - }, - { - "author": "shinich39", - "title": "comfyui-text-pipe-39", - "reference": "https://github.com/shinich39/comfyui-text-pipe-39", - "files": [ - "https://github.com/shinich39/comfyui-text-pipe-39" - ], - "install_type": "git-clone", - "description": "Modify text by condition." - }, - { - "author": "Sida Liu", - "title": "ComfyUI-Debug", - "reference": "https://github.com/liusida/ComfyUI-Debug", - "files": [ - "https://github.com/liusida/ComfyUI-Debug" - ], - "install_type": "git-clone", - "description": "Attach a debug node to an output to obtain more detailed information. Uncover the details of your models in ComfyUI with ease." - }, - { - "author": "hay86", - "title": "ComfyUI_AceNodes", - "reference": "https://github.com/hay86/ComfyUI_AceNodes", - "files": [ - "https://github.com/hay86/ComfyUI_AceNodes" - ], - "install_type": "git-clone", - "description": "Nodes:Integer, Float, Text, Seed, Text Concatenate, Text Input Switch (2/4/8 way), Text List, Text Preview, Text Selector, Text To Resolution. Some useful custom nodes that are not included in ComfyUI core yet." - }, - { - "author": "jtydhr88", - "title": "ComfyUI-Workflow-Encrypt", - "reference": "https://github.com/jtydhr88/ComfyUI-Workflow-Encrypt", - "files": [ - "https://github.com/jtydhr88/ComfyUI-Workflow-Encrypt" - ], - "install_type": "git-clone", - "description": "Encrypt your comfyui workflow, and share it with key" - }, - { - "author": "ronniebasak", - "title": "ComfyUI-Tara-LLM-Integration", - "reference": "https://github.com/ronniebasak/ComfyUI-Tara-LLM-Integration", - "files": [ - "https://github.com/ronniebasak/ComfyUI-Tara-LLM-Integration" - ], - "install_type": "git-clone", - "description": "Tara is a powerful node for ComfyUI that integrates Large Language Models (LLMs) to enhance and automate workflow processes. With Tara, you can create complex, intelligent workflows that refine and generate content, manage API keys, and seamlessly integrate various LLMs into your projects." - }, - { - "author": "SLAPaper", - "title": "ComfyUI DPM++ 2M Alt Sampler", - "reference": "https://github.com/SLAPaper/ComfyUI-dpmpp_2m_alt-Sampler", - "files": [ - "https://github.com/SLAPaper/ComfyUI-dpmpp_2m_alt-Sampler" - ], - "install_type": "git-clone", - "description": "the sampler introduced by [a/hallatore](https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions/8457)\ncode extracted from [a/smZNodes](https://github.com/shiimizu/ComfyUI_smZNodes)" - }, - { - "author": "yuvraj108c", - "title": "ComfyUI PiperTTS", - "reference": "https://github.com/yuvraj108c/ComfyUI-PiperTTS", - "files": [ - "https://github.com/yuvraj108c/ComfyUI-PiperTTS" - ], - "install_type": "git-clone", - "description": "Convert Text-to-Speech inside ComfyUI using [a/Piper](https://github.com/rhasspy/piper)" - }, - { - "author": "A4P7J1N7M05OT", - "title": "ComfyUI-PixelOE", - "reference": "https://github.com/A4P7J1N7M05OT/ComfyUI-PixelOE", - "files": [ - "https://github.com/A4P7J1N7M05OT/ComfyUI-PixelOE" - ], - "install_type": "git-clone", - "description": "A barebones ComfyUI wrapper for [a/PixelOE](https://github.com/KohakuBlueleaf/PixelOE).\nI cannot promise any support, if there is someone who wants to make a proper node, please do." - }, - { - "author": "AppleBotzz", - "title": "ComfyUI_LLMVISION", - "reference": "https://github.com/AppleBotzz/ComfyUI_LLMVISION", - "files": [ - "https://github.com/AppleBotzz/ComfyUI_LLMVISION" - ], - "install_type": "git-clone", - "description": "This repository provides integration of GPT-4 and Claude 3 models into ComfyUI, allowing for both image and text-based interactions within the ComfyUI workflow." - }, - { - "author": "SoftMeng", - "title": "ComfyUI_ImageToText", - "reference": "https://github.com/SoftMeng/ComfyUI_ImageToText", - "files": [ - "https://github.com/SoftMeng/ComfyUI_ImageToText" - ], - "install_type": "git-clone", - "description": "Nodes: ComfyUI_ImageToText" - }, - { - "author": "bvhari", - "title": "ComfyUI_SUNoise", - "reference": "https://github.com/bvhari/ComfyUI_SUNoise", - "files": [ - "https://github.com/bvhari/ComfyUI_SUNoise" - ], - "install_type": "git-clone", - "description": "Scaled Uniform Noise for Ancestral and Stochastic samplers" - }, - { - "author": "TJ16th", - "title": "comfyUI_TJ_NormalLighting", - "reference": "https://github.com/TJ16th/comfyUI_TJ_NormalLighting", - "files": [ - "https://github.com/TJ16th/comfyUI_TJ_NormalLighting" - ], - "install_type": "git-clone", - "description": "Custom Node for comfyUI for virtual lighting based on normal map.\nYou can use normal maps to add virtual lighting effects to your images." - }, - { - "author": "chaojie", - "title": "ComfyUI-MuseTalk", - "reference": "https://github.com/chaojie/ComfyUI-MuseTalk", - "files": [ - "https://github.com/chaojie/ComfyUI-MuseTalk" - ], - "install_type": "git-clone", - "description": "ComfyUI MuseTalk" - }, - { - "author": "kijai", - "title": "DiffusionLight implementation for ComfyUI", - "reference": "https://github.com/kijai/ComfyUI-DiffusionLight", - "files": [ - "https://github.com/kijai/ComfyUI-DiffusionLight" - ], - "install_type": "git-clone", - "description": "This is simplified implementation of the [a/DiffusionLight](https://github.com/DiffusionLight/DiffusionLight) method of creating light probes. You will need the included LoRA, place it in ComfyUI/loras folder like usual, it's converted from the original diffusers one." - }, - { - "author": "bobmagicii", - "title": "ComfyKit Custom Nodes", - "reference": "https://github.com/bobmagicii/comfykit-custom-nodes", - "files": [ - "https://github.com/bobmagicii/comfykit-custom-nodes" - ], - "install_type": "git-clone", - "description": "Nodes:LoraWithMetadata, TypecasterImage." - }, - { - "author": "BlakeOne", - "title": "ComfyUI CustomScheduler", - "reference": "https://github.com/BlakeOne/ComfyUI-CustomScheduler", - "files": [ - "https://github.com/BlakeOne/ComfyUI-CustomScheduler" - ], - "install_type": "git-clone", - "description": "Simple node for setting the sigma values directly. Note, for a full denoise the last sigma should be zero." - }, - { - "author": "chaojie", - "title": "ComfyUI-MuseV", - "reference": "https://github.com/chaojie/ComfyUI-MuseV", - "files": [ - "https://github.com/chaojie/ComfyUI-MuseV" - ], - "install_type": "git-clone", - "description": "ComfyUI MuseV" - }, - { - "author": "DrMWeigand", - "title": "ComfyUI Color Detection Nodes", - "reference": "https://github.com/DrMWeigand/ComfyUI_ColorImageDetection", - "files": [ - "https://github.com/DrMWeigand/ComfyUI_ColorImageDetection" - ], - "install_type": "git-clone", - "description": "A collection of nodes for detecting color in images, leveraging RGB and LAB color spaces. These nodes aim to distinguish colored images from black and white, including those with color tints." - }, - { - "author": "kijai", - "title": "ComfyUI-APISR", - "reference": "https://github.com/kijai/ComfyUI-APISR", - "files": [ - "https://github.com/kijai/ComfyUI-APISR" - ], - "install_type": "git-clone", - "description": "Node to use [a/APISR](https://github.com/Kiteretsu77/APISR) upscale models in ComfyUI" - }, - { - "author": "logtd", - "title": "ComfyUI-FLATTEN", - "reference": "https://github.com/logtd/ComfyUI-FLATTEN", - "files": [ - "https://github.com/logtd/ComfyUI-FLATTEN" - ], - "install_type": "git-clone", - "description": "ComfyUI nodes to use [a/FLATTEN: optical FLow-guided ATTENtion for consistent text-to-video editing](https://github.com/yrcong/flatten)." - }, - { - "author": "BlakeOne", - "title": "ComfyUI SchedulerMixer", - "reference": "https://github.com/BlakeOne/ComfyUI-SchedulerMixer", - "files": [ - "https://github.com/BlakeOne/ComfyUI-SchedulerMixer" - ], - "install_type": "git-clone", - "description": "Create a custom scheduler from a weighted average of the built-in schedulers" - }, - { - "author": "BlakeOne", - "title": "ComfyUI FastImageListToImageBatch", - "reference": "https://github.com/BlakeOne/ComfyUI-FastImageListToImageBatch", - "files": [ - "https://github.com/BlakeOne/ComfyUI-FastImageListToImageBatch" - ], - "install_type": "git-clone", - "description": "Quickly convert a list of images to a batch of images. All images must be the same size. Great for long videos." - }, - { - "author": "frankchieng", - "title": "ComfyUI_Aniportrait", - "reference": "https://github.com/frankchieng/ComfyUI_Aniportrait", - "files": [ - "https://github.com/frankchieng/ComfyUI_Aniportrait" - ], - "install_type": "git-clone", - "description": "implementation of [a/AniPortrait](https://github.com/Zejun-Yang/AniPortrait) generating of videos, includes self driven, face reenacment and audio driven with a reference image" - }, - { - "author": "ZHO-ZHO-ZHO", - "title": "ComfyUI-BiRefNet-ZHO", - "reference": "https://github.com/ZHO-ZHO-ZHO/ComfyUI-BiRefNet-ZHO", - "files": [ - "https://github.com/ZHO-ZHO-ZHO/ComfyUI-BiRefNet-ZHO" - ], - "install_type": "git-clone", - "description": "Better version for [a/BiRefNet](https://github.com/zhengpeng7/birefnet) in ComfyUI | Both img and video" - }, - { - "author": "kale4eat", - "title": "ComfyUI_demucus", - "reference": "https://github.com/kale4eat/ComfyUI-path-util", - "files": [ - "https://github.com/kale4eat/ComfyUI-path-util" - ], - "install_type": "git-clone", - "description": "Path utility for ComfyUI" - }, - { - "author": "kale4eat", - "title": "ComfyUI-string-util", - "reference": "https://github.com/kale4eat/ComfyUI-string-util", - "files": [ - "https://github.com/kale4eat/ComfyUI-string-util" - ], - "install_type": "git-clone", - "description": "String utility for ComfyUI" - }, - { - "author": "kale4eat", - "title": "ComfyUI-text-file-util", - "reference": "https://github.com/kale4eat/ComfyUI-text-file-util", - "files": [ - "https://github.com/kale4eat/ComfyUI-text-file-util" - ], - "install_type": "git-clone", - "description": "Text file utility for ComfyUI" - }, - { - "author": "nickve28", - "title": "ComfyUI Nich Utils", - "reference": "https://github.com/nickve28/ComfyUI-Nich-Utils", - "files": [ - "https://github.com/nickve28/ComfyUI-Nich-Utils" - ], - "install_type": "git-clone", - "description": "Several utility nodes for use with ComfyUI." - }, - { - "author": "Hangover3832", - "title": "Recognize Anything Model (RAM) for ComfyUI", - "reference": "https://github.com/Hangover3832/ComfyUI-Hangover-Recognize_Anything", - "files": [ - "https://github.com/Hangover3832/ComfyUI-Hangover-Recognize_Anything" - ], - "install_type": "git-clone", - "description": "This is an image recognition node for ComfyUI based on the RAM++ model from [a/xinyu1205](https://huggingface.co/xinyu1205).\nThis node outputs a string of tags with all the recognized objects and elements in the image in English or Chinese language.\nFor image tagging and captioning." - }, - { - "author": "ParisNeo", - "title": "lollms_nodes_suite", - "reference": "https://github.com/ParisNeo/lollms_nodes_suite", - "files": [ - "https://github.com/ParisNeo/lollms_nodes_suite" - ], - "install_type": "git-clone", - "description": "lollms_nodes_suite is a set of nodes for comfyui that harnesses the power of lollms, a state-of-the-art AI text generation tool, to improve the quality of image generation." - }, - { - "author": "jiaxiangc", - "title": "ResAdapter for ComfyUI", - "reference": "https://github.com/jiaxiangc/ComfyUI-ResAdapter", - "files": [ - "https://github.com/jiaxiangc/ComfyUI-ResAdapter" - ], - "install_type": "git-clone", - "description": "We provide ComfyUI-ResAdapter node to help users to use [a/ResAdapter](https://github.com/bytedance/res-adapter) in ComfyUI." - }, - { - "author": "MokkaBoss1", - "title": "Node Pack mostly for manipulating strings and integers", - "reference": "https://github.com/MokkaBoss1/ComfyUI_Mokkaboss1/wiki/Documentation-for-the-ComfyUI-Nodes-in-this-Node-Pack", - "files": [ - "https://github.com/MokkaBoss1/ComfyUI_Mokkaboss1" - ], - "install_type": "git-clone", - "description": "Node Pack mostly for manipulating strings and integers" - }, - { - "author": "shinich39", - "title": "comfyui-random-node-39", - "reference": "https://github.com/shinich39/comfyui-ramdom-node-39", - "files": [ - "https://github.com/shinich39/comfyui-ramdom-node-39" - ], - "install_type": "git-clone", - "description": "Choose random node." - }, - { - "author": "NeuralSamurAI", - "title": "SuperPrompter Node for ComfyUI", - "reference": "https://github.com/NeuralSamurAI/Comfyui-Superprompt-Unofficial", - "files": [ - "https://github.com/NeuralSamurAI/Comfyui-Superprompt-Unofficial" - ], - "install_type": "git-clone", - "description": "The SuperPrompter node is a ComfyUI node that uses the SuperPrompt-v1 model from Hugging Face to generate text based on a given prompt. It provides various parameters to control the text generation process." - }, - { - "author": "1mckw", - "title": "Comfyui-Gelbooru", - "reference": "https://github.com/1mckw/Comfyui-Gelbooru", - "files": [ - "https://github.com/1mckw/Comfyui-Gelbooru" - ], - "install_type": "git-clone", - "description": "Get random images from gelbooru, support multiple tag searches, exclude tags, etc. user and api key are optional." - }, - { - "author": "zombieyang", - "title": "SD-PPP", - "reference": "https://github.com/zombieyang/sd-ppp", - "files": [ - "https://github.com/zombieyang/sd-ppp" - ], - "install_type": "git-clone", - "description": "!!Another custom node about Photoshop!! PPP means interoP with your PhotoshoP. You can get or send layers from/to your Photoshop. This custom node is easier to use." - }, - { - "author": "KytraScript", - "title": "ComfyUI_KytraWebhookHTTP", - "reference": "https://github.com/KytraScript/ComfyUI_KytraWebhookHTTP", - "files": [ - "https://github.com/KytraScript/ComfyUI_KytraWebhookHTTP" - ], - "install_type": "git-clone", - "description": "A ComfyUI node that utilizes Moviepy to convert and send your images or videos to a webhook endpoint directly from ComfyUI." - }, - { - "author": "MokkaBoss1", - "title": "NatureColours, UrbanColours", - "reference": "https://github.com/MokkaBoss1/NatureColours", - "files": [ - "https://github.com/MokkaBoss1/NatureColours/raw/main/NatureColours.py", - "https://github.com/MokkaBoss1/NatureColours/raw/main/UrbanColours.py" - ], - "install_type": "copy", - "description": "Nodes:NatureColours, UrbanColours. These nodes outputs the color code for the selected color as a string." - }, - { - "author": "logtd", - "title": "ComfyUI-RefSampling", - "reference": "https://github.com/logtd/ComfyUI-RefSampling", - "files": [ - "https://github.com/logtd/ComfyUI-RefSampling" - ], - "install_type": "git-clone", - "description": "Nodes:Apply Ref UNet, Ref Sampler, Ref Sampler Custom" - }, - { - "author": "chaojie", - "title": "ComfyUI-AniPortrait", - "reference": "https://github.com/chaojie/ComfyUI-AniPortrait", - "files": [ - "https://github.com/chaojie/ComfyUI-AniPortrait" - ], - "install_type": "git-clone", - "description": "ComfyUI [a/AniPortrait](https://github.com/Zejun-Yang/AniPortrait)" - }, - { - "author": "wei30172", - "title": "comfygen", - "reference": "https://github.com/wei30172/comfygen", - "files": [ - "https://github.com/wei30172/comfygen" - ], - "install_type": "git-clone", - "description": "Setting Up a Web Interface Using ComfyUI.\nNOTE:When installed, you can access it via http://127.0.0.1:8188/comfygen." - }, - { - "author": "longgui0318", - "title": "comfyui-oms-diffusion", - "reference": "https://github.com/longgui0318/comfyui-oms-diffusion", - "files": [ - "https://github.com/longgui0318/comfyui-oms-diffusion" - ], - "install_type": "git-clone", - "description": "Nodes:Extract Features With Unet, Additional Features With Attention" - }, - { - "author": "shinich39", - "title": "comfyui-load-image-39", - "reference": "https://github.com/shinich39/comfyui-load-image-39", - "files": [ - "https://github.com/shinich39/comfyui-load-image-39" - ], - "install_type": "git-clone", - "description": "This node is load png image sequentially with metadata. Only supported for PNG format that has been created by ComfyUI." - }, - { - "author": "yuvraj108c", - "title": "ComfyUI Depth Anything TensorRT", - "reference": "https://github.com/yuvraj108c/ComfyUI-Depth-Anything-Tensorrt", - "files": [ - "https://github.com/yuvraj108c/ComfyUI-Depth-Anything-Tensorrt" - ], - "install_type": "git-clone", - "description": "This extension provides a ComfyUI Custom Node implementation of the [a/Depth-Anything-Tensorrt](https://github.com/spacewalk01/depth-anything-tensorrt) in Python for ultra fast depth map generation" - }, - { - "author": "Extraltodeus", - "title": "Vector_Sculptor_ComfyUI", - "reference": "https://github.com/Extraltodeus/Vector_Sculptor_ComfyUI", - "files": [ - "https://github.com/Extraltodeus/Vector_Sculptor_ComfyUI" - ], - "install_type": "git-clone", - "description": "The main node makes your conditioning go towards similar concepts so to enrich your composition or further away so to make it more precise. It gathers similar pre-cond vectors for as long as the cosine similarity score diminishes. If it climbs back it stops. This allows to set a relative direction to similar concepts.\nThere are examples at the end but [a/you can also check this imgur album](https://imgur.com/a/WvPd81Y) which demonstrates the capability of improving variety." - }, - { - "author": "chaojie", - "title": "ComfyUI-Img2Img-Turbo", - "reference": "https://github.com/chaojie/ComfyUI-Img2Img-Turbo", - "files": [ - "https://github.com/chaojie/ComfyUI-Img2Img-Turbo" - ], - "install_type": "git-clone", - "description": "ComfyUI Img2Img-Turbo" - }, - { - "author": "kijai", - "title": "Geowizard depth and normal estimation in ComfyUI", - "reference": "https://github.com/kijai/ComfyUI-Geowizard", - "files": [ - "https://github.com/kijai/ComfyUI-Geowizard" - ], - "install_type": "git-clone", - "description": "This is a diffusers (0.27.2) wrapper node for Geowizard: [https://github.com/fuxiao0719/GeoWizard]. The model is autodownloaded from Hugginface to ComfyUI/models/diffusers/geowizard" - }, - { - "author": "SuperBeastsAI", - "title": "ComfyUI-SuperBeasts", - "reference": "https://github.com/SuperBeastsAI/ComfyUI-SuperBeasts", - "files": [ - "https://github.com/SuperBeastsAI/ComfyUI-SuperBeasts" - ], - "install_type": "git-clone", - "description": "Nodes:HDR Effects (SuperBeasts.AI). This repository contains custom nodes for ComfyUI created and used by SuperBeasts.AI (@SuperBeasts.AI on Instagram)" - }, - { - "author": "IKHOR", - "title": "ikhor-nodes", - "reference": "https://github.com/IKHOR/ComfyUI-IKHOR-Jam-Nodes", - "files": [ - "https://github.com/IKHOR/ComfyUI-IKHOR-Jam-Nodes" - ], - "install_type": "git-clone", - "description": "Nodes:LoadFromS3, LoadBatchFromS3, SaveToS3, SaveBatchToS3" - }, - { - "author": "viperyl", - "title": "ComfyUI-BiRefNet", - "reference": "https://github.com/viperyl/ComfyUI-BiRefNet", - "files": [ - "https://github.com/viperyl/ComfyUI-BiRefNet" - ], - "install_type": "git-clone", - "description": "Bilateral Reference Network achieves SOTA result in multi Salient Object Segmentation dataset, this repo pack BiRefNet as ComfyUI nodes, and make this SOTA model easier use for everyone." - }, - { - "author": "alisson-anjos", - "title": "ComfyUI-LLaVA-Describer", - "reference": "https://github.com/alisson-anjos/ComfyUI-LLaVA-Describer", - "files": [ - "https://github.com/alisson-anjos/ComfyUI-LLaVA-Describer" - ], - "install_type": "git-clone", - "description": "This is an extension for ComfyUI to extract descriptions from your images using the multimodal model called LLaVa. The LLaVa model - Large Language and Vision Assistant, although trained on a relatively small dataset, demonstrates exceptional capabilities in understanding images and answering questions about them. This model shows behaviors similar to multimodal models like GPT-4, even when presented with unseen images and instructions." - }, - { - "author": "chaosaiart", - "title": "Chaosaiart-Nodes", - "reference": "https://github.com/chaosaiart/Chaosaiart-Nodes", - "files": [ - "https://github.com/chaosaiart/Chaosaiart-Nodes" - ], - "install_type": "git-clone", - "description": "This extension provides various custom nodes to assist in configuring the workflow structure." - }, - { - "author": "shadowcz007", - "title": "comfyui-Image-reward", - "reference": "https://github.com/shadowcz007/comfyui-Image-reward", - "files": [ - "https://github.com/shadowcz007/comfyui-Image-reward" - ], - "install_type": "git-clone", - "description": "[a/ImageReward](https://github.com/THUDM/ImageReward): Human preference learning in text-to-image generation. This is a [a/paper](https://arxiv.org/abs/2304.05977) from NeurIPS 2023" - }, - { - "author": "Nevysha", - "title": "ComfyUI-nevysha-top-menu", - "reference": "https://github.com/Nevysha/ComfyUI-nevysha-top-menu", - "files": [ - "https://github.com/Nevysha/ComfyUI-nevysha-top-menu" - ], - "install_type": "git-clone", - "description": "A simple sidebar tweak to force fixe the ComfyUI menu to the top of the screen. Reaaally quick and dirty. May break with some ComfyUI setup." - }, - { - "author": "Big Idea Technology", - "title": "LLM Node for ComfyUI", - "reference": "https://github.com/Big-Idea-Technology/ComfyUI_LLM_Node", - "files": [ - "https://github.com/Big-Idea-Technology/ComfyUI_LLM_Node" - ], - "install_type": "git-clone", - "description": "The LLM_Node enhances ComfyUI by integrating advanced language model capabilities, enabling a wide range of NLP tasks such as text generation, content summarization, question answering, and more. This flexibility is powered by various transformer model architectures from the transformers library, allowing for the deployment of models like T5, GPT-2, and others based on your project's needs." - }, - { - "author": "zhangp365", - "title": "zhangp365/Some Utils for ComfyUI", - "reference": "https://github.com/viperyl/ComfyUI-GCoNet-plus", - "files": [ - "https://github.com/viperyl/ComfyUI-GCoNet-plus" - ], - "install_type": "git-clone", - "description": "Group collaborative learning network, termed GCoNet+, which can effectively and efficiently co-salient objects in natural scenes. This repo pack GCoNet-plus as ComfyUI nodes, and make this fast SOTA model easier use for everyone." - }, - { - "author": "ExponentialML", - "title": "ComfyUI - Native DynamiCrafter", - "reference": "https://github.com/ExponentialML/ComfyUI_Native_DynamiCrafter", - "files": [ - "https://github.com/ExponentialML/ComfyUI_Native_DynamiCrafter" - ], - "install_type": "git-clone", - "description": "DynamiCrafter that works natively with ComfyUI's nodes, optimizations, ControlNet, and more." - }, - { - "author": "ExponentialML", - "title": "ComfyUI_VisualStylePrompting", - "reference": "https://github.com/ExponentialML/ComfyUI_VisualStylePrompting", - "files": [ - "https://github.com/ExponentialML/ComfyUI_VisualStylePrompting" - ], - "install_type": "git-clone", - "description": "ComfyUI Version of '[a/Visual Style Prompting with Swapping Self-Attention](https://github.com/naver-ai/Visual-Style-Prompting)'" } ] -} +} \ No newline at end of file diff --git a/node_db/new/extension-node-map.json b/node_db/new/extension-node-map.json index 5de49b21..459c2ded 100644 --- a/node_db/new/extension-node-map.json +++ b/node_db/new/extension-node-map.json @@ -126,7 +126,11 @@ "GPT4VCaptioner", "Image Load with Metadata", "SAMIN String Attribute Selector", + "SANMIN ChineseToCharacter", "SANMIN ClothingWildcards", + "SANMIN ConvertToEnglish", + "SANMIN LoadPathImagesPreview", + "SANMIN SanmiSaveImageToLocal", "SANMIN SimpleWildcards", "Samin Counter", "Samin Load Image Batch" @@ -186,16 +190,61 @@ "title_aux": "ComfyUI-PixelOE" } ], + "https://github.com/AIFSH/ComfyUI-GPT_SoVITS": [ + [ + "GPT_SOVITS_FT", + "GPT_SOVITS_INFER", + "GPT_SOVITS_TTS", + "LoadAudio", + "LoadSRT", + "PreViewAudio" + ], + { + "title_aux": "ComfyUI-GPT_SoVITS" + } + ], + "https://github.com/AIFSH/ComfyUI-IP_LAP": [ + [ + "CombineAudioVideo", + "IP_LAP", + "LoadVideo", + "PreViewVideo" + ], + { + "title_aux": "ComfyUI-IP_LAP" + } + ], + "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH": [ + [ + "CombineAudioVideo", + "LoadVideo", + "MuseTalk", + "PreViewVideo" + ], + { + "title_aux": "ComfyUI-MuseTalk_FSH" + } + ], "https://github.com/AIFSH/ComfyUI-UVR5": [ [ "LoadAudio", - "PlayAudio", + "PreViewAudio", "UVR5_Node" ], { "title_aux": "ComfyUI-UVR5" } ], + "https://github.com/AIFSH/ComfyUI-WhisperX": [ + [ + "LoadAudio", + "PreViewSRT", + "WhisperX" + ], + { + "title_aux": "ComfyUI-WhisperX" + } + ], "https://github.com/AIGCTeam/ComfyUI_kkTranslator_nodes": [ [ "LoadMarianMTCheckPoint", @@ -260,6 +309,28 @@ "title_aux": "One Button Prompt" } ], + "https://github.com/ALatentPlace/ComfyUI_yanc": [ + [ + "> Clear Text", + "> Float to Int", + "> Int", + "> Int to Text", + "> Load Image", + "> Load Image From Folder", + "> Resolution by Aspect Ratio", + "> Rotate Image", + "> Save Image", + "> Scale Image to Side", + "> Text", + "> Text Combine", + "> Text Pick Random Line", + "> Text Random Weights", + "> Text Replace" + ], + { + "title_aux": "ComfyUI_yanc" + } + ], "https://github.com/AbdullahAlfaraj/Comfy-Photoshop-SD": [ [ "APS_LatentBatch", @@ -297,6 +368,8 @@ "ImageOverlap-badger", "ImageScaleToSide-badger", "IntToString-badger", + "IntToStringAdvanced-badger", + "LoadImageAdvanced-badger", "SegmentToMaskByPoint-badger", "SimpleBoolean-badger", "StringToFizz-badger", @@ -377,6 +450,14 @@ "title_aux": "Jovimetrix Composition Nodes" } ], + "https://github.com/AonekoSS/ComfyUI-SimpleCounter": [ + [ + "Simple Counter" + ], + { + "title_aux": "ComfyUI-SimpleCounter" + } + ], "https://github.com/AppleBotzz/ComfyUI_LLMVISION": [ [ "CLAUDE_CHAT", @@ -539,17 +620,24 @@ "title_aux": "ComfyUI Deploy" } ], - "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay": [ + "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools": [ [ - "Image Text Overlay" + "EndQueue", + "ImageTextOverlay", + "Loop", + "LoopEnd", + "LoopStart", + "PromptSchedule", + "PromptSelector" ], { - "title_aux": "Image Text Overlay Node for ComfyUI" + "title_aux": "ComfyUI-Book-Tools Nodes for ComfyUI" } ], "https://github.com/Big-Idea-Technology/ComfyUI_LLM_Node": [ [ "AdvOptions_Node", + "CodingOptionsNode", "LLM_Node", "Output_Node", "QuantizationConfig_Node" @@ -742,6 +830,7 @@ [ "GeometricCFGGuider", "ImageAssistedCFGGuider", + "MegaCFGGuider", "SamplerCLYB_4M_SDE_Momentumized", "SamplerCustomModelMixtureDuo", "SamplerCustomNoise", @@ -754,7 +843,8 @@ "SamplerSupreme", "SamplerTTM", "ScaledCFGGuider", - "SimpleExponentialScheduler" + "SimpleExponentialScheduler", + "WarmupDecayCFGGuider" ], { "title_aux": "ComfyUI Extra Samplers" @@ -770,6 +860,7 @@ ], "https://github.com/CosmicLaca/ComfyUI_Primere_Nodes": [ [ + "PrimereAestheticCKPTScorer", "PrimereAnyDetailer", "PrimereAnyOutput", "PrimereCKPT", @@ -843,7 +934,15 @@ "description": "If you want to draw two different characters together without blending their features, so you could try to check out this custom node.", "nickname": "Danand", "title": "Comfy Couple", - "title_aux": "ComfyUI-ComfyCouple" + "title_aux": "Comfy Couple" + } + ], + "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config": [ + [ + "CheckpointAutomaticConfig" + ], + { + "title_aux": "ComfyUI Checkpoint Automatic Config" } ], "https://github.com/Derfuu/Derfuu_ComfyUI_ModdedNodes": [ @@ -851,42 +950,32 @@ "Absolute value", "Ceil", "Conditioning area scale by ratio", - "ConditioningSetArea with tuples", "Cosines", "Divide", "Float", - "Float debug print", "Floor", "Get image size", "Get latent size", "Image scale by ratio", "Image scale to side", - "Int debug print", "Int to float", - "Int to tuple", "Integer", "Latent Scale by ratio", "Latent Scale to side", - "LatentComposite with tuples", "Logic node", "Multiply", "Power", "Random", "Sinus", "Square root", - "String debug print", + "String Concatenate", + "String Replace", "Subtract", "Sum", "Tangent", "Text", "Text box", - "To text (Debug)", - "Tuple", - "Tuple debug print", - "Tuple multiply", - "Tuple swap", - "Tuple to floats", - "Tuple to ints" + "To text (Debug)" ], { "title_aux": "Derfuu_ComfyUI_ModdedNodes" @@ -955,6 +1044,16 @@ "title_aux": "ComfyUI-post-processing-nodes" } ], + "https://github.com/ExponentialML/ComfyUI_ELLA": [ + [ + "ELLATextEncode", + "GetSigma", + "LoadElla" + ], + { + "title_aux": "ComfyUI_ELLA" + } + ], "https://github.com/ExponentialML/ComfyUI_ModelScopeT2V": [ [ "ModelScopeT2VLoader" @@ -983,8 +1082,11 @@ "https://github.com/Extraltodeus/ComfyUI-AutomaticCFG": [ [ "Automatic CFG", - "Automatic CFG - Advanced settings", - "Automatic CFG - Negative" + "Automatic CFG - Advanced", + "Automatic CFG - Fastest", + "Automatic CFG - Negative", + "Automatic CFG - Post rescale only", + "SAG delayed activation" ], { "title_aux": "ComfyUI-AutomaticCFG" @@ -1026,6 +1128,7 @@ "Merge sigmas by average", "Merge sigmas gradually", "Multiply sigmas", + "Output min/max sigmas", "Split and concatenate sigmas", "The Golden Scheduler" ], @@ -1069,6 +1172,112 @@ "title_aux": "ComfyUI Loopchain" } ], + "https://github.com/Fannovel16/ComfyUI-MagickWand": [ + [ + "ImageMagick Adaptive Blur", + "ImageMagick Adaptive Resize", + "ImageMagick Adaptive Sharpen", + "ImageMagick Adaptive Threshold", + "ImageMagick Auto Gamma", + "ImageMagick Auto Level", + "ImageMagick Auto Orient", + "ImageMagick Auto Threshold", + "ImageMagick Blue Shift", + "ImageMagick Blur", + "ImageMagick Brightness Contrast", + "ImageMagick Canny", + "ImageMagick Charcoal", + "ImageMagick Chop", + "ImageMagick Clahe", + "ImageMagick Clamp", + "ImageMagick Coalesce", + "ImageMagick Color Decision List", + "ImageMagick Color Matrix", + "ImageMagick Combine", + "ImageMagick Concat", + "ImageMagick Contrast", + "ImageMagick Contrast Stretch", + "ImageMagick Crop", + "ImageMagick Cycle Color Map", + "ImageMagick Decipher", + "ImageMagick Despeckle", + "ImageMagick Distort", + "ImageMagick Edge", + "ImageMagick Emboss", + "ImageMagick Encipher", + "ImageMagick Enhance", + "ImageMagick Equalize", + "ImageMagick Evaluate", + "ImageMagick Extent", + "ImageMagick Flip", + "ImageMagick Flop", + "ImageMagick Forward Fourier Transform", + "ImageMagick Function", + "ImageMagick Gamma", + "ImageMagick Gaussian Blur", + "ImageMagick Hough Lines", + "ImageMagick Implode", + "ImageMagick Kmeans", + "ImageMagick Kuwahara", + "ImageMagick Level", + "ImageMagick Levelize", + "ImageMagick Linear Stretch", + "ImageMagick Liquid Rescale", + "ImageMagick Local Contrast", + "ImageMagick Magnify", + "ImageMagick Mean Shift", + "ImageMagick Merge Layers", + "ImageMagick Mode", + "ImageMagick Modulate", + "ImageMagick Morphology", + "ImageMagick Motion Blur", + "ImageMagick Negate", + "ImageMagick Noise", + "ImageMagick Normalize", + "ImageMagick Oil Paint", + "ImageMagick Ordered Dither", + "ImageMagick Polynomial", + "ImageMagick Posterize", + "ImageMagick Quantize", + "ImageMagick Random Threshold", + "ImageMagick Range Threshold", + "ImageMagick Resample", + "ImageMagick Resize", + "ImageMagick Roll", + "ImageMagick Rotational Blur", + "ImageMagick Sample", + "ImageMagick Scale", + "ImageMagick Selective Blur", + "ImageMagick Sepia Tone", + "ImageMagick Shade", + "ImageMagick Shadow", + "ImageMagick Sharpen", + "ImageMagick Shave", + "ImageMagick Sigmoidal Contrast", + "ImageMagick Sketch", + "ImageMagick Smush", + "ImageMagick Solarize", + "ImageMagick Splice", + "ImageMagick Spread", + "ImageMagick Statistic", + "ImageMagick Swirl", + "ImageMagick Threshold", + "ImageMagick Thumbnail", + "ImageMagick Transform", + "ImageMagick Transform Colorspace", + "ImageMagick Transparentize", + "ImageMagick Transpose", + "ImageMagick Transverse", + "ImageMagick Unsharp Mask", + "ImageMagick Vignette", + "ImageMagick Wave", + "ImageMagick Wavelet Denoise", + "ImageMagick White Balance" + ], + { + "title_aux": "ComfyUI-MagickWand" + } + ], "https://github.com/Fannovel16/ComfyUI-MotionDiff": [ [ "EmptyMotionData", @@ -1087,6 +1296,8 @@ "SMPLShapeParameters", "SaveSMPL", "SmplifyMotionData", + "SpectreFaceReconLoader", + "SpectreImg2SMPL", "mgpt_model_loader", "mgpt_t2m" ], @@ -1350,7 +1561,11 @@ [ "ReActorBuildFaceModel", "ReActorFaceSwap", + "ReActorFaceSwapOpt", + "ReActorImageDublicator", "ReActorLoadFaceModel", + "ReActorMaskHelper", + "ReActorOptions", "ReActorRestoreFace", "ReActorSaveFaceModel" ], @@ -1459,7 +1674,7 @@ "description": "Just some nodes that I wanted/needed, so I made them.", "nickname": "HNodes", "title": "Hiero-Nodes", - "title_aux": "ComfyUI-Hiero-Nodes" + "title_aux": "Hiero-Nodes" } ], "https://github.com/IDGallagher/ComfyUI-IG-Nodes": [ @@ -1496,6 +1711,34 @@ "title_aux": "ikhor-nodes" } ], + "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes": [ + [ + "MX_AlphaBlend", + "MX_Blend", + "MX_Blur", + "MX_Canny", + "MX_ChromaticAberration", + "MX_ColorCorrect", + "MX_ColorMatch", + "MX_ColorTint", + "MX_Glow", + "MX_HSVThresholdMask", + "MX_KuwaharaBlur(Cartoon)", + "MX_LUT", + "MX_LensBokeh", + "MX_LensOpticAxis", + "MX_LensZoomBurst", + "MX_Mosaic", + "MX_Noise", + "MX_Posterize", + "MX_SineWave", + "MX_Solarize", + "MX_Vignette" + ], + { + "title_aux": "ComfyUI-MX-post-processing-nodes" + } + ], "https://github.com/Inzaniak/comfyui-ranbooru": [ [ "LockSeed", @@ -1524,6 +1767,7 @@ ], "https://github.com/JPS-GER/ComfyUI_JPS-Nodes": [ [ + "CLIPTextEncode SDXL Plus (JPS)", "Conditioning Switch (JPS)", "ControlNet Switch (JPS)", "Crop Image Pipe (JPS)", @@ -1545,13 +1789,23 @@ "Get Image Size (JPS)", "IP Adapter Settings (JPS)", "IP Adapter Settings Pipe (JPS)", - "IP Adapter Single Settings (JPS)", - "IP Adapter Single Settings Pipe (JPS)", + "IP Adapter Tiled Settings (JPS)", + "IP Adapter Tiled Settings Pipe (JPS)", "IPA Switch (JPS)", + "Image Prepare Pipe (JPS)", + "Image Prepare Settings (JPS)", "Image Switch (JPS)", "ImageToImage Pipe (JPS)", "ImageToImage Settings (JPS)", "Images Masks MultiPipe (JPS)", + "InstantID Mask Prepare Pipe (JPS)", + "InstantID Mask Prepare Settings (JPS)", + "InstantID Pipe (JPS)", + "InstantID Pose Prepare Pipe (JPS)", + "InstantID Pose Prepare Settings (JPS)", + "InstantID Settings (JPS)", + "InstantID Source Prepare Pipe (JPS)", + "InstantID Source Prepare Settings (JPS)", "Integer Switch (JPS)", "Largest Int (JPS)", "Latent Switch (JPS)", @@ -1561,6 +1815,9 @@ "Multiply Float Float (JPS)", "Multiply Int Float (JPS)", "Multiply Int Int (JPS)", + "Prepare Image (JPS)", + "Prepare Image Plus (JPS)", + "Prepare Image Tiled IPA (JPS)", "Resolution Multiply (JPS)", "Revision Settings (JPS)", "Revision Settings Pipe (JPS)", @@ -1572,11 +1829,15 @@ "SDXL Prompt Styler (JPS)", "SDXL Recommended Resolution Calc (JPS)", "SDXL Resolutions (JPS)", + "SDXL Settings (JPS)", + "SDXL Settings Pipe (JPS)", "Sampler Scheduler Settings (JPS)", "Save Images Plus (JPS)", "Substract Int Int (JPS)", "Text Concatenate (JPS)", "Text Prompt (JPS)", + "Text Prompt Combo (JPS)", + "Time Seed (JPS)", "VAE Switch (JPS)" ], { @@ -1598,6 +1859,7 @@ "DiffusersPipeline", "DiffusersPrepareLatents", "DiffusersTextureInversionLoader", + "DiffusersXLPipeline", "GetAverageColorFromImage", "GetFilledColorImage" ], @@ -1611,6 +1873,7 @@ "JNodes_AnyToString", "JNodes_AppendReversedFrames", "JNodes_BooleanSelectorWithString", + "JNodes_BreakMediaInfo", "JNodes_CheckpointSelectorWithString", "JNodes_GetOutputDirectory", "JNodes_GetParameterFromList", @@ -1619,7 +1882,9 @@ "JNodes_ImageFormatSelector", "JNodes_ImageSizeSelector", "JNodes_LoadVideo", + "JNodes_LoadVisualMediaFromPath", "JNodes_LoraExtractor", + "JNodes_MediaInfoToString", "JNodes_OutVideoInfo", "JNodes_ParseDynamicPrompts", "JNodes_ParseParametersToGlobalList", @@ -1643,6 +1908,7 @@ "JNodes_TokenCounter", "JNodes_TrimAndStrip", "JNodes_UploadVideo", + "JNodes_UploadVisualMedia", "JNodes_VaeSelectorWithString" ], { @@ -1676,7 +1942,15 @@ "description": "A ComfyUI custom node that randomly selects a height and width pair from a list in a config file", "nickname": "Random Size", "title": "Random Size", - "title_aux": "ComfyUI-RandomSize" + "title_aux": "Random Size" + } + ], + "https://github.com/JettHu/ComfyUI_TGate": [ + [ + "TGateApply" + ], + { + "title_aux": "ComfyUI_TGate" } ], "https://github.com/Jordach/comfy-plasma": [ @@ -1778,8 +2052,14 @@ "ADE_AnimateDiffUnload", "ADE_ApplyAnimateDiffModel", "ADE_ApplyAnimateDiffModelSimple", + "ADE_ApplyAnimateDiffModelWithCameraCtrl", "ADE_ApplyAnimateLCMI2VModel", "ADE_BatchedContextOptions", + "ADE_CameraCtrlAnimateDiffKeyframe", + "ADE_CameraManualPoseAppend", + "ADE_CameraPoseAdvanced", + "ADE_CameraPoseBasic", + "ADE_CameraPoseCombo", "ADE_CustomCFG", "ADE_CustomCFGKeyframe", "ADE_EmptyLatentImageLarge", @@ -1787,7 +2067,9 @@ "ADE_IterationOptsDefault", "ADE_IterationOptsFreeInit", "ADE_LoadAnimateDiffModel", + "ADE_LoadAnimateDiffModelWithCameraCtrl", "ADE_LoadAnimateLCMI2VModel", + "ADE_LoadCameraPoses", "ADE_LoopedUniformContextOptions", "ADE_LoopedUniformViewOptions", "ADE_MaskedLoadLora", @@ -1797,6 +2079,8 @@ "ADE_NoiseLayerAddWeighted", "ADE_NoiseLayerReplace", "ADE_RawSigmaSchedule", + "ADE_ReplaceCameraParameters", + "ADE_ReplaceOriginalPoseAspectRatio", "ADE_SigmaSchedule", "ADE_SigmaScheduleSplitAndCombine", "ADE_SigmaScheduleWeightedAverage", @@ -1825,6 +2109,7 @@ "VHS_GetLatentCount", "VHS_GetMaskCount", "VHS_LoadAudio", + "VHS_LoadAudioUpload", "VHS_LoadImages", "VHS_LoadImagesPath", "VHS_LoadVideo", @@ -2146,8 +2431,10 @@ ], "https://github.com/MNeMoNiCuZ/ComfyUI-mnemic-nodes": [ [ - "Generate Negative Prompt_mne", - "Save Text File_mne" + "\u26d4 Generate Negative Prompt", + "\u2728 Groq LLM API", + "\ud83d\udcbe Save Text File With Path", + "\ud83d\uddbc\ufe0f Download Image from URL" ], { "title_aux": "ComfyUI-mnemic-nodes" @@ -2214,28 +2501,43 @@ ], "https://github.com/MokkaBoss1/ComfyUI_Mokkaboss1": [ [ + "AnimeCosplayDir", "AspectRatioCondition", + "Colors", "ConnectFloat", "ConnectImage", "ConnectInteger", + "ConnectLatent", "ConnectString", + "DirSelector", "DoubleClipTextEncode", + "EmbeddingLoader", + "FilmCharDir", "HashText", + "HueSatLum", + "ImageDimensions", + "ImageResizeLong", "IndoorBackgrounds", + "IndoorDir", + "IntEvaluate", "IntFloatDict", "IntStringDict", "LandscapeBackgrounds", - "NatureColours", + "LandscapeDir", + "MakeupStylesDir", "OptimalCrop", - "SDXLAspectRatioDec", - "UrbanColours", + "SDXLEmptyLatent", + "SaveWithMetaData", + "SimplePrompts", + "SpecificStylesDir", + "TimeStamp", + "TricolorComposition", "WorkflowSettings", "WrapText", "X_In_a_Dress", "X_In_a_Suit", "X_In_a_Suit)", - "ZoomCrop", - "seveninabox" + "ZoomCrop" ], { "title_aux": "Node Pack mostly for manipulating strings and integers" @@ -2328,7 +2630,7 @@ "nickname": "Harronode", "nodename_pattern": "Harronode", "title": "Harrlogos Prompt Builder Node", - "title_aux": "Harronode" + "title_aux": "Harrlogos Prompt Builder Node" } ], "https://github.com/Nourepide/ComfyUI-Allor": [ @@ -2551,6 +2853,7 @@ "CyclistTimerStop", "CyclistTypeCast", "Interrupt", + "LoopManager", "MemorizeConditioning", "MemorizeFloat", "MemorizeInt", @@ -3083,6 +3386,22 @@ "title_aux": "ComfyUI_Mexx_Styler" } ], + "https://github.com/Sorcerio/MBM-Music-Visualizer": [ + [ + "id", + "mbmAudioFeatureCalculator", + "mbmAudioLoader", + "mbmImageConcat", + "mbmPromptSequenceBuilder", + "mbmPromptSequenceBuilderAdv", + "mbmPromptSequenceInterpolator", + "mbmPromptSequenceLoader", + "mbmPromptSequenceRenderer" + ], + { + "title_aux": "MBM's Music Visualizer" + } + ], "https://github.com/SpaceKendo/ComfyUI-svd_txt2vid": [ [ "SVD_txt2vid_ConditioningwithLatent" @@ -3091,6 +3410,20 @@ "title_aux": "Text to video for Stable Video Diffusion in ComfyUI" } ], + "https://github.com/Stability-AI/ComfyUI-SAI_API": [ + [ + "Stability Creative Upscale", + "Stability Image Core", + "Stability Inpainting", + "Stability Outpainting", + "Stability Remove Background", + "Stability SD3", + "Stability Search and Replace" + ], + { + "title_aux": "Stability API nodes for ComfyUI" + } + ], "https://github.com/Stability-AI/stability-ComfyUI-nodes": [ [ "ColorBlend", @@ -3364,7 +3697,7 @@ "description": "175 custom nodes for artists, designers and animators.", "nickname": "Comfyroll Studio", "title": "Comfyroll Studio", - "title_aux": "ComfyUI_Comfyroll_CustomNodes" + "title_aux": "Comfyroll Studio" } ], "https://github.com/Sxela/ComfyWarp": [ @@ -3451,8 +3784,12 @@ ], "https://github.com/TRI3D-LC/tri3d-comfyui-nodes": [ [ + "get_histogram_limits", "main_scaled_paste", + "simple_rescale_histogram", "tri3d-HistogramEqualization", + "tri3d-LAB_2_RGB", + "tri3d-RGB_2_LAB", "tri3d-adjust-neck", "tri3d-atr-parse", "tri3d-atr-parse-batch", @@ -3466,6 +3803,9 @@ "tri3d-face-recognise", "tri3d-float-to-image", "tri3d-fuzzification", + "tri3d-get_histogram_limits", + "tri3d-get_mean_and_standard_deviation", + "tri3d-get_threshold_for_bg_swap", "tri3d-image-mask-2-box", "tri3d-image-mask-box-2-image", "tri3d-interaction-canny", @@ -3480,7 +3820,10 @@ "tri3d-recolor-mask-LAB_space", "tri3d-recolor-mask-LAB_space_manual", "tri3d-recolor-mask-RGB_space", + "tri3d-renormalize_array", "tri3d-scaled-paste", + "tri3d-simple_bg_swap", + "tri3d-simple_rescale_histogram", "tri3d-skin-feathered-padded-mask", "tri3d-swap-pixels" ], @@ -3533,6 +3876,21 @@ "title_aux": "ComfyS3" } ], + "https://github.com/TencentQQGYLab/ComfyUI-ELLA": [ + [ + "ConcatConditionEllaEmbeds", + "ConditionToEllaEmbeds", + "ELLALoader", + "EllaAdvancedApply", + "EllaApply", + "EllaCombineEmbeds", + "T5TextEncode #ELLA", + "T5TextEncoderLoader #ELLA" + ], + { + "title_aux": "ComfyUI-ELLA" + } + ], "https://github.com/TheBarret/ZSuite": [ [ "ZSuite: Prompter", @@ -3676,6 +4034,16 @@ "title_aux": "select_folder_path_easy" } ], + "https://github.com/VAST-AI-Research/ComfyUI-Tripo": [ + [ + "TripoAPIImageToMeshNode", + "TripoAPITextToMeshNode", + "TripoGLBViewer" + ], + { + "title_aux": "Tripo for ComfyUI" + } + ], "https://github.com/WASasquatch/ASTERR": [ [ "ASTERR", @@ -3975,6 +4343,18 @@ "title_aux": "WebDev9000-Nodes" } ], + "https://github.com/Wicloz/ComfyUI-Simply-Nodes": [ + [ + "WF_ConditionalLoraLoader", + "WF_MultilineText", + "WF_RandomStyle", + "WF_ResolutionSDXL", + "WF_TextFlow" + ], + { + "title_aux": "ComfyUI-Simply-Nodes" + } + ], "https://github.com/XmYx/deforum-comfy-nodes": [ [ "DeforumAddNoiseNode", @@ -4137,12 +4517,16 @@ [ "ConcatText_Zho", "DisplayText_Zho", + "Gemini_15P_API_S_Advance_Zho", + "Gemini_15P_API_S_Chat_Advance_Zho", "Gemini_API_Chat_Zho", "Gemini_API_S_Chat_Zho", "Gemini_API_S_Vsion_ImgURL_Zho", "Gemini_API_S_Zho", "Gemini_API_Vsion_ImgURL_Zho", - "Gemini_API_Zho" + "Gemini_API_Zho", + "Gemini_FileUpload_API_S_Zho", + "Gemini_File_API_S_Zho" ], { "title_aux": "ComfyUI-Gemini" @@ -4289,14 +4673,16 @@ "title_aux": "ComfyUI-AudioScheduler" } ], - "https://github.com/abdozmantar/ComfyUI-InstaSwap": [ + "https://github.com/aburahamu/ComfyUI-RequestsPoster": [ [ - "InstaSwapFaceSwap", - "InstaSwapLoadFaceModel", - "InstaSwapSaveFaceModel" + "GetImageFromSD3byI2I", + "GetImageFromSD3byT2I", + "PostImage2Discord", + "PostImage2X", + "PostText" ], { - "title_aux": "InstaSwap Face Swap Node for ComfyUI" + "title_aux": "ComfyUI-RequestPoster" } ], "https://github.com/abyz22/image_control": [ @@ -4630,6 +5016,7 @@ "PCPromptFromSchedule", "PCScheduleSettings", "PCSplitSampling", + "PCWrapGuider", "PromptControlSimple", "PromptToSchedule", "ScheduleToCond", @@ -4688,7 +5075,7 @@ "description": "Include nodes for sam + bpy operation, that allows workflow creations for generative 2d character rig.", "nickname": "Avatar Graph", "title": "Avatar Graph", - "title_aux": "avatar-graph-comfyui" + "title_aux": "Avatar Graph" } ], "https://github.com/azure-dragon-ai/ComfyUI-ClipScore-Nodes": [ @@ -4832,11 +5219,14 @@ ], "https://github.com/blepping/ComfyUI-bleh": [ [ + "BlehBlockOps", "BlehDeepShrink", "BlehDiscardPenultimateSigma", "BlehForceSeedSampler", "BlehHyperTile", "BlehInsaneChainSampler", + "BlehLatentOps", + "BlehLatentScaleBy", "BlehModelPatchConditional", "BlehRefinerAfter" ], @@ -4859,6 +5249,18 @@ "title_aux": "ComfyUI-sonar" } ], + "https://github.com/blueraincoatli/comfyUI_SillyNodes": [ + [ + "BooleanJumper|SillyNode", + "QueueSequence|SillyNode", + "Screenshots|SillyNode", + "dummyInput|SillyNode", + "dummyInput|blueraincoat" + ], + { + "title_aux": "comfyUI_SillyNodes" + } + ], "https://github.com/bmad4ever/comfyui_ab_samplercustom": [ [ "AB SamplerCustom (experimental)" @@ -5152,7 +5554,9 @@ "SamplerDPMPP_2M_SDE_SUN", "SamplerDPMPP_3M_SDE_SUN", "SamplerDPMPP_SDE_SUN", - "SamplerEulerAncestral_SUN" + "SamplerEulerAncestral_SUN", + "SamplersSUNoise", + "SamplersSUNoiseAdvanced" ], { "title_aux": "ComfyUI_SUNoise" @@ -5233,6 +5637,19 @@ "title_aux": "ComfyUI-AniPortrait" } ], + "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper": [ + [ + "CameraBasic", + "CameraCombine", + "CameraCtrlLoader", + "CameraCtrlRun", + "CameraJoin", + "CameraTrajectory" + ], + { + "title_aux": "ComfyUI-CameraCtrl-Wrapper" + } + ], "https://github.com/chaojie/ComfyUI-Champ": [ [ "ChampLoader", @@ -5297,6 +5714,15 @@ "title_aux": "ComfyUI-DynamiCrafter" } ], + "https://github.com/chaojie/ComfyUI-EasyAnimate": [ + [ + "EasyAnimateLoader", + "EasyAnimateRun" + ], + { + "title_aux": "ComfyUI-EasyAnimate" + } + ], "https://github.com/chaojie/ComfyUI-Gemma": [ [ "GemmaLoader", @@ -5326,6 +5752,19 @@ "title_aux": "ComfyUI-Img2Img-Turbo" } ], + "https://github.com/chaojie/ComfyUI-LaVIT": [ + [ + "VideoLaVITI2I", + "VideoLaVITI2V", + "VideoLaVITI2VLong", + "VideoLaVITLoader", + "VideoLaVITT2V", + "VideoLaVITT2VLong" + ], + { + "title_aux": "ComfyUI-LaVIT" + } + ], "https://github.com/chaojie/ComfyUI-LightGlue": [ [ "LightGlue Loader", @@ -5482,6 +5921,7 @@ ], "https://github.com/chaojie/ComfyUI-dust3r": [ [ + "CameraPoseVideo", "Dust3rLoader", "Dust3rRun" ], @@ -5491,6 +5931,9 @@ ], "https://github.com/chaojie/ComfyUI_StreamingT2V": [ [ + "LoadText_StreamingT2V", + "PromptTravelIndex", + "SaveText_StreamingT2V", "StreamingT2VLoaderAnimateDiff", "StreamingT2VLoaderAnimateDiffModel", "StreamingT2VLoaderEnhanceModel", @@ -5504,10 +5947,14 @@ "StreamingT2VRunI2V", "StreamingT2VRunLongStep", "StreamingT2VRunLongStepVidXTendPipeline", + "StreamingT2VRunLongStepVidXTendPipelineCustomRef", + "StreamingT2VRunLongStepVidXTendPipelineCustomRefOutExtendOnly", + "StreamingT2VRunLongStepVidXTendPipelinePromptTravel", "StreamingT2VRunShortStepAnimateDiff", "StreamingT2VRunShortStepModelscopeT2V", "StreamingT2VRunShortStepSVD", - "StreamingT2VRunT2V" + "StreamingT2VRunT2V", + "VHS_FILENAMES_STRING_StreamingT2V" ], { "title_aux": "ComfyUI_StreamingT2V" @@ -5515,11 +5962,9 @@ ], "https://github.com/chaosaiart/Chaosaiart-Nodes": [ [ - "chaosaiart_ADD_Prompt", - "chaosaiart_Any_Display", "chaosaiart_Any_Switch", "chaosaiart_Any_Switch_Big_Number", - "chaosaiart_Batch_Loader_Number_Override", + "chaosaiart_Any_Switch_small", "chaosaiart_CheckpointLoader", "chaosaiart_CheckpointPrompt", "chaosaiart_CheckpointPrompt2", @@ -5531,13 +5976,19 @@ "chaosaiart_Denoising_Switch", "chaosaiart_EmptyLatentImage", "chaosaiart_FramePromptCLIPEncode", - "chaosaiart_ImageHolder_loop", - "chaosaiart_KSampler", + "chaosaiart_Frame_Switch", "chaosaiart_KSampler1", "chaosaiart_KSampler2", "chaosaiart_KSampler3", "chaosaiart_KSampler4", "chaosaiart_KSampler5", + "chaosaiart_KSampler7", + "chaosaiart_KSampler_a1", + "chaosaiart_KSampler_a1a", + "chaosaiart_KSampler_a2", + "chaosaiart_KSampler_expert_0", + "chaosaiart_KSampler_expert_1", + "chaosaiart_Ksampler_attribut", "chaosaiart_Load_Image_Batch", "chaosaiart_Load_Image_Batch_2img", "chaosaiart_MainPromptCLIPEncode", @@ -5547,48 +5998,40 @@ "chaosaiart_Number_Switch", "chaosaiart_Prompt", "chaosaiart_Prompt_Frame", - "chaosaiart_Prompt_mixer", "chaosaiart_Prompt_mixer_byFrame", "chaosaiart_SaveImage", - "chaosaiart_ShowInput", - "chaosaiart_Show_Any", "chaosaiart_Show_Info", "chaosaiart_Simple_Prompt", "chaosaiart_Style_Node", "chaosaiart_TextCLIPEncode", "chaosaiart_TextCLIPEncode_lora", - "chaosaiart_TextCLIPEncode_simple", "chaosaiart_adjust_color", "chaosaiart_any_array2input_1Input", "chaosaiart_any_array2input_all_big", "chaosaiart_any_array2input_all_small", "chaosaiart_any_input2array_big", "chaosaiart_any_input2array_small", - "chaosaiart_cn_math", "chaosaiart_controlnet_weidgth", "chaosaiart_convert", + "chaosaiart_convert_Prompt", + "chaosaiart_forPreview", "chaosaiart_image_loop", + "chaosaiart_img2gif", "chaosaiart_img2video", - "chaosaiart_imgHolder", "chaosaiart_lora", "chaosaiart_lora_advanced", - "chaosaiart_main_Prompt", + "chaosaiart_merge_Folders", "chaosaiart_oneNode", "chaosaiart_reloadAny_Load", "chaosaiart_reloadAny_Save", "chaosaiart_reloadIMG_Load", - "chaosaiart_reloadIMG_Load2", "chaosaiart_reloadIMG_Save", "chaosaiart_reloadLatent_Load", - "chaosaiart_reloadLatent_Load2", "chaosaiart_reloadLatent_Save", "chaosaiart_restarter", "chaosaiart_restarter_advanced", - "chaosaiart_saveImagePrefix", - "chaosaiart_test", - "chaosaiart_test2", "chaosaiart_video2img1", - "chaosaiart_video2img2" + "chaosaiart_zoom_frame" ], { "title_aux": "Chaosaiart-Nodes" @@ -5745,6 +6188,16 @@ "title_aux": "ComfyUI-Chibi-Nodes" } ], + "https://github.com/choey/Comfy-Topaz": [ + [ + "TopazPhotoAI", + "TopazSharpenSettings", + "TopazUpscaleSettings" + ], + { + "title_aux": "Comfy-Topaz" + } + ], "https://github.com/chrisgoringe/cg-image-picker": [ [ "Preview Chooser", @@ -5889,6 +6342,8 @@ ], "https://github.com/comfyanonymous/ComfyUI": [ [ + "AddNoise", + "AlignYourStepsScheduler", "BasicGuider", "BasicScheduler", "CFGGuider", @@ -6000,6 +6455,8 @@ "Morphology", "PatchModelAddDownscale", "PerpNeg", + "PerpNegGuider", + "PerturbedAttentionGuidance", "PhotoMakerEncode", "PhotoMakerLoader", "PolyexponentialScheduler", @@ -6162,20 +6619,26 @@ "IPAdapterAdvanced", "IPAdapterBatch", "IPAdapterCombineEmbeds", + "IPAdapterCombineParams", "IPAdapterEmbeds", "IPAdapterEncoder", "IPAdapterFaceID", + "IPAdapterFromParams", "IPAdapterInsightFaceLoader", "IPAdapterLoadEmbeds", + "IPAdapterMS", "IPAdapterModelLoader", "IPAdapterNoise", + "IPAdapterRegionalConditioning", "IPAdapterSaveEmbeds", "IPAdapterStyleComposition", + "IPAdapterStyleCompositionBatch", "IPAdapterTiled", "IPAdapterTiledBatch", "IPAdapterUnifiedLoader", "IPAdapterUnifiedLoaderCommunity", "IPAdapterUnifiedLoaderFaceID", + "IPAdapterWeights", "PrepImageForClipVision" ], { @@ -6209,12 +6672,14 @@ [ "BatchCount+", "CLIPTextEncodeSDXL+", + "ConditioningCombineMultiple+", "ConsoleDebug+", "DebugTensorShape+", "DrawText+", "ExtractKeyframes+", "GetImageSize+", "ImageApplyLUT+", + "ImageBatchMultiple+", "ImageCASharpening+", "ImageCompositeFromMaskBatch+", "ImageCrop+", @@ -6237,7 +6702,10 @@ "MaskFlip+", "MaskFromBatch+", "MaskFromColor+", + "MaskFromRGBCMYBW+", + "MaskFromSegmentation+", "MaskPreview+", + "MaskSmooth+", "ModelCompile+", "NoiseFromImage~", "PixelOEPixelize+", @@ -6260,7 +6728,7 @@ "description": "Face Compare", "nickname": "Face Compare", "title": "Face Compare", - "title_aux": "Comfyui-FaceCompare" + "title_aux": "Face Compare" } ], "https://github.com/dagthomas/comfyui_dagthomas": [ @@ -6348,9 +6816,11 @@ [ "JDCN_AnyFileList", "JDCN_AnyFileListHelper", + "JDCN_AnyFileListRandom", "JDCN_AnyFileSelector", "JDCN_BatchImageLoadFromList", "JDCN_BatchLatentLoadFromDir", + "JDCN_BatchLatentLoadFromList", "JDCN_BatchSaveLatent", "JDCN_FileMover", "JDCN_ImageSaver", @@ -6359,6 +6829,7 @@ "JDCN_SeamlessExperience", "JDCN_SplitString", "JDCN_StringToList", + "JDCN_TXTFileSaver", "JDCN_VHSFileMover" ], { @@ -6423,7 +6894,7 @@ "description": "CLIP text encoder that does BREAK prompting like A1111", "nickname": "CLIP with BREAK", "title": "CLIP with BREAK syntax", - "title_aux": "comfyui-clip-with-break" + "title_aux": "CLIP with BREAK syntax" } ], "https://github.com/dfl/comfyui-tcd-scheduler": [ @@ -6638,6 +7109,16 @@ "title_aux": "primitive-types" } ], + "https://github.com/e7mac/ComfyUI-ShadertoyGL": [ + [ + "ColorChannelOffset", + "Shader", + "Shadertoy" + ], + { + "title_aux": "ComfyUI-ShadertoyGL" + } + ], "https://github.com/ealkanat/comfyui_easy_padding": [ [ "comfyui-easy-padding" @@ -6656,8 +7137,10 @@ "Eden_Float", "Eden_Int", "Eden_String", + "HistogramMatching", "IMG_blender", "IMG_padder", + "IMG_resolution_multiple_of", "IMG_scaler", "IMG_unpadder", "If ANY execute A else B", @@ -6785,6 +7268,7 @@ ], "https://github.com/filliptm/ComfyUI_Fill-Nodes": [ [ + "FL_Ascii", "FL_AudioConverter", "FL_AudioFrameCalculator", "FL_AudioPreview", @@ -6811,6 +7295,21 @@ "title_aux": "fcSuite" } ], + "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite": [ + [ + "StabilityAI Suite - Creative Upscale", + "StabilityAI Suite - Creative Upscale Recover File", + "StabilityAI Suite - Image Core + Style Preset", + "StabilityAI Suite - Inpainting", + "StabilityAI Suite - Outpainting", + "StabilityAI Suite - Remove Background", + "StabilityAI Suite - SD3", + "StabilityAI Suite - Search and Replace" + ], + { + "title_aux": "ComfyUI StabilityAI Suite" + } + ], "https://github.com/florestefano1975/comfyui-portrait-master": [ [ "PortraitMaster" @@ -6897,6 +7396,16 @@ "title_aux": "As_ComfyUI_CustomNodes" } ], + "https://github.com/forever22777/comfyui-self-guidance": [ + [ + "CLIPConditioning", + "CheckpointLoaderMixWithDiffusers", + "SelfGuidanceSampler" + ], + { + "title_aux": "Self-Guidance nodes" + } + ], "https://github.com/foxtrot-roger/comfyui-rf-nodes": [ [ "LogBool", @@ -6946,6 +7455,14 @@ "title_aux": "ComfyUI_Aniportrait" } ], + "https://github.com/frankchieng/ComfyUI_MagicClothing": [ + [ + "MagicClothing_Generate" + ], + { + "title_aux": "ComfyUI_MagicClothing" + } + ], "https://github.com/gemell1/ComfyUI_GMIC": [ [ "GmicCliWrapper", @@ -7045,6 +7562,7 @@ [ "GlifConsistencyDecoder", "GlifPatchConsistencyDecoderTiled", + "HFHubLoraLoader", "ImageToMultipleOf", "SDXLAspectRatio" ], @@ -7156,9 +7674,16 @@ ], "https://github.com/hay86/ComfyUI_AceNodes": [ [ + "ACE_AudioLoad", + "ACE_AudioPlay", + "ACE_AudioSave", "ACE_Float", + "ACE_ImageColorFix", "ACE_ImageConstrain", + "ACE_ImageLoadFromCloud", + "ACE_ImageQA", "ACE_ImageRemoveBackground", + "ACE_ImageSaveToCloud", "ACE_Integer", "ACE_Seed", "ACE_Text", @@ -7174,18 +7699,68 @@ "ACE_TextTranslate" ], { - "title_aux": "ComfyUI_AceNodes" + "title_aux": "ComfyUI AceNodes" + } + ], + "https://github.com/hay86/ComfyUI_DDColor": [ + [ + "D_DDColor" + ], + { + "title_aux": "ComfyUI DDColor" } ], "https://github.com/hay86/ComfyUI_Dreamtalk": [ [ - "D_DreamTalk", - "D_LoadAudio" + "D_DreamTalk" ], { "title_aux": "ComfyUI Dreamtalk" } ], + "https://github.com/hay86/ComfyUI_MiniCPM-V": [ + [ + "D_MiniCPM_VQA" + ], + { + "title_aux": "ComfyUI MiniCPM-V" + } + ], + "https://github.com/hay86/ComfyUI_OpenVoice": [ + [ + "D_OpenVoice_STS", + "D_OpenVoice_TTS" + ], + { + "title_aux": "ComfyUI OpenVoice" + } + ], + "https://github.com/heshengtao/comfyui_LLM_party": [ + [ + "LLM", + "LLM_local", + "check_web_tool", + "classify_function", + "classify_persona", + "custom_persona", + "ebd_tool", + "end_dialog", + "file_combine", + "file_combine_plus", + "google_tool", + "interpreter_tool", + "load_file", + "load_persona", + "start_dialog", + "time_tool", + "tool_combine", + "tool_combine_plus", + "weather_tool" + ], + { + "title_aux": "comfyui_LLM_party" + } + ], "https://github.com/hhhzzyang/Comfyui_Lama": [ [ "LamaApply", @@ -7319,11 +7894,18 @@ "title_aux": "ComfyUI-Lora-Auto-Trigger-Words" } ], + "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode": [ + [ + "IF_WhisperSpeech" + ], + { + "title_aux": "ComfyUI-IF_AI_WishperSpeechNode" + } + ], "https://github.com/if-ai/ComfyUI-IF_AI_tools": [ [ + "IF_ChatPrompt", "IF_DisplayText", - "IF_HFDownload", - "IF_HFDownloadNode", "IF_ImagePrompt", "IF_PromptMkr", "IF_SaveText", @@ -7401,7 +7983,7 @@ "description": "This extension offers various audio generation tools", "nickname": "Audiotools", "title": "Jags_Audiotools", - "title_aux": "ComfyUI_Jags_Audiotools" + "title_aux": "Jags_Audiotools" } ], "https://github.com/jags111/ComfyUI_Jags_VectorMagic": [ @@ -7422,7 +8004,7 @@ "description": "This extension offers various vector manipulation and generation tools", "nickname": "Jags_VectorMagic", "title": "Jags_VectorMagic", - "title_aux": "ComfyUI_Jags_VectorMagic" + "title_aux": "Jags_VectorMagic" } ], "https://github.com/jags111/efficiency-nodes-comfyui": [ @@ -7562,6 +8144,15 @@ "title_aux": "ComfyUI-JaRue" } ], + "https://github.com/jtydhr88/ComfyUI-InstantMesh": [ + [ + "InstantMeshLoader", + "InstantMeshRun" + ], + { + "title_aux": "ComfyUI-InstantMesh" + } + ], "https://github.com/ka-puna/comfyui-yanc": [ [ "YANC.ConcatStrings", @@ -7602,6 +8193,60 @@ "title_aux": "ComfyUI_demucus" } ], + "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit": [ + [ + "SDT_AudioProperty", + "SDT_ConcatAudio", + "SDT_CutAudio", + "SDT_DemucsApply", + "SDT_DemucsLoader", + "SDT_FasterWhisperListSegments", + "SDT_FasterWhisperLoader", + "SDT_FasterWhisperSegmentProperty", + "SDT_FasterWhisperTextFromSegments", + "SDT_FasterWhisperTranscribe", + "SDT_GriffinLim", + "SDT_JoinAudio", + "SDT_LFCC", + "SDT_LoadAudio", + "SDT_LoadAudios", + "SDT_MFCC", + "SDT_MakeSilenceAudio", + "SDT_MelSpectrogram", + "SDT_NemoAsrListSegments", + "SDT_NemoAsrListSubwords", + "SDT_NemoAsrLoader", + "SDT_NemoAsrSegmentProperty", + "SDT_NemoAsrSubwordProperty", + "SDT_NemoAsrTranscribe", + "SDT_NueAsrLoader", + "SDT_NueAsrTranscribe", + "SDT_PlayAudio", + "SDT_PlotMelFilterBank", + "SDT_PlotPitch", + "SDT_PlotSpecgram", + "SDT_PlotSpectrogram", + "SDT_PlotWaveForm", + "SDT_ResampleAudio", + "SDT_SaveAudio", + "SDT_SaveAudioWithSequentialNumbering", + "SDT_SilenceAudio", + "SDT_SileroVADApply", + "SDT_SileroVADCollectChunks", + "SDT_SileroVADListTimestamps", + "SDT_SileroVADLoader", + "SDT_SileroVADTimestampProperty", + "SDT_Spectrogram", + "SDT_SpeechMOSLoader", + "SDT_SpeechMOSScore", + "SDT_SplitAudio", + "SDT_TrimAudio", + "SDT_TrimAudioBySample" + ], + { + "title_aux": "ComfyUI-speech-dataset-toolkit" + } + ], "https://github.com/kale4eat/ComfyUI-string-util": [ [ "string_util_Str", @@ -7640,6 +8285,15 @@ "title_aux": "ComfyUI-text-file-util" } ], + "https://github.com/kealiu/ComfyUI-S3-Tools": [ + [ + "Load Image From S3", + "Save Image To S3" + ], + { + "title_aux": "ComfyUI Load and Save file to S3" + } + ], "https://github.com/kenjiqq/qq-nodes-comfyui": [ [ "Any List", @@ -7688,6 +8342,27 @@ "title_aux": "Animatediff MotionLoRA Trainer" } ], + "https://github.com/kijai/ComfyUI-APISR-KJ": [ + [ + "APISR_upscale" + ], + { + "title_aux": "ComfyUI-APISR" + } + ], + "https://github.com/kijai/ComfyUI-BrushNet-Wrapper": [ + [ + "brushnet_ella_loader", + "brushnet_ipadapter_matteo", + "brushnet_model_loader", + "brushnet_sampler", + "brushnet_sampler_ella", + "powerpaint_brushnet_sampler" + ], + { + "title_aux": "ComfyUI-BrushNet-Wrapper" + } + ], "https://github.com/kijai/ComfyUI-CCSR": [ [ "CCSR_Model_Select", @@ -7724,6 +8399,16 @@ "title_aux": "ComfyUI-DynamiCrafterWrapper" } ], + "https://github.com/kijai/ComfyUI-ELLA-wrapper": [ + [ + "ella_model_loader", + "ella_sampler", + "ella_t5_embeds" + ], + { + "title_aux": "ComfyUI-ELLA-wrapper" + } + ], "https://github.com/kijai/ComfyUI-Geowizard": [ [ "geowizard_model_loader", @@ -7762,11 +8447,13 @@ "CreateTextMask", "CreateVoronoiMask", "CrossFadeImages", + "CustomSigmas", "DummyLatentOut", "EmptyLatentImagePresets", "FilterZeroMasksAndCorrespondingImages", "FlipSigmasAdjusted", "FloatConstant", + "FloatToMask", "GLIGENTextBoxApplyBatch", "GenerateNoise", "GetImageRangeFromBatch", @@ -7774,6 +8461,7 @@ "GetLatentsFromBatchIndexed", "GrowMaskWithBlur", "INTConstant", + "ImageAndMaskPreview", "ImageBatchRepeatInterleaving", "ImageBatchTestPattern", "ImageConcanate", @@ -7781,13 +8469,16 @@ "ImageGridComposite2x2", "ImageGridComposite3x3", "ImageNormalize_Neg1_To_1", + "ImagePadForOutpaintMasked", "ImageTransformByNormalizedAmplitude", "ImageUpscaleWithModelBatched", "InjectNoiseToLatent", "InsertImageBatchByIndexes", + "InsertImagesToBatchIndexed", "Intrinsic_lora_sampling", "JoinStrings", "LoadResAdapterNormalization", + "MaskOrImageToWeight", "NormalizedAmplitudeToMask", "OffsetMask", "OffsetMaskByNormalizedAmplitude", @@ -7803,18 +8494,32 @@ "Sleep", "SomethingToString", "SoundReactive", + "SplineEditor", "SplitBboxes", + "StabilityAPI_SD3", "StableZero123_BatchSchedule", "StringConstant", "StringConstantMultiline", "Superprompt", "VRAM_Debug", + "WeightScheduleConvert", "WidgetToString" ], { "title_aux": "KJNodes for ComfyUI" } ], + "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper": [ + [ + "lavi_bridge_llama_encoder", + "lavi_bridge_t5_encoder", + "lavibridge_model_loader", + "lavibridge_sampler" + ], + { + "title_aux": "ComfyUI-LaVi-Bridge-Wrapper" + } + ], "https://github.com/kijai/ComfyUI-Marigold": [ [ "ColorizeDepthmap", @@ -7900,12 +8605,12 @@ "https://github.com/klinter007/klinter_nodes": [ [ "Filter", + "ListStringToFloatNode", "PresentString", + "PrintFloats", "SingleString", "SizeSelector", - "concat", - "concat_klinter", - "whitelist" + "concat" ], { "title_aux": "Klinter_nodes" @@ -7973,6 +8678,28 @@ "title_aux": "komojini-comfyui-nodes" } ], + "https://github.com/kunieone/ComfyUI_alkaid": [ + [ + "A_EmptyLatentImageLongside", + "A_Face3DSwapper", + "A_FaceCrop", + "A_FacePaste", + "A_GetImageSize", + "A_OpenPosePreprocessor", + "AdapterFace", + "AdapterFaceLoader", + "AdapterStyle", + "AdapterStyleLoader", + "AlkaidLoader", + "ApplyAdapter", + "ApplyControlNet_KPS", + "CombineAdapterPatch", + "KSamplerHires" + ], + { + "title_aux": "ComfyUI_alkaid" + } + ], "https://github.com/kwaroran/abg-comfyui": [ [ "Remove Image Background (abg)" @@ -8144,6 +8871,16 @@ "title_aux": "ComfyUI-InversedNoise" } ], + "https://github.com/logtd/ComfyUI-RAVE_ATTN": [ + [ + "ApplyRaveAttentionNode", + "AttentionOverrideSD15Node", + "AttentionOverrideSDXLNode" + ], + { + "title_aux": "ComfyUI-RAVE Attention" + } + ], "https://github.com/logtd/ComfyUI-RefSampling": [ [ "ApplyRefContentNode", @@ -8176,6 +8913,7 @@ "https://github.com/longgui0318/comfyui-mask-util": [ [ "Image Adaptive Crop M&R", + "Image Adaptive Crop With Mask", "Image Change Device", "Image Resolution Adaptive With X", "Image Resolution Limit With 8K", @@ -8189,7 +8927,13 @@ ], "https://github.com/longgui0318/comfyui-oms-diffusion": [ [ - "Additional Features With Attention" + "Add Magic Clothing Attention", + "Change Pixel Value Normalization", + "InjectTensorHashLog", + "LOAD OMS", + "Load Magic Clothing Model", + "RUN OMS", + "VAE Mode Choose" ], { "title_aux": "comfyui-oms-diffusion" @@ -8524,7 +9268,7 @@ "description": "Various QoL improvements like prompt tweaking, variable assignment, image preview, fuzzy search, error reporting, organizing and node navigation.", "nickname": "\ud83d\udfe1 mape's helpers", "title": "mape's helpers", - "title_aux": "mape's ComfyUI Helpers" + "title_aux": "mape's helpers" } ], "https://github.com/maracman/ComfyUI-SubjectStyle-CSV": [ @@ -8766,6 +9510,7 @@ "IntToFloatMultiplication", "LogicNot", "NumeralToString", + "OneFloat", "PngColorMasksToMaskList", "PngColorMasksToRGB", "PngColorMasksToString", @@ -8791,15 +9536,6 @@ "title_aux": "ComfyUI_Mira" } ], - "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor": [ - [ - "LaMaPreprocessor", - "lamaPreprocessor" - ], - { - "title_aux": "LaMa Preprocessor [WIP]" - } - ], "https://github.com/modusCell/ComfyUI-dimension-node-modusCell": [ [ "DimensionProviderFree modusCell", @@ -9000,6 +9736,21 @@ "title_aux": "ntdviet/comfyui-ext" } ], + "https://github.com/nullquant/ComfyUI-BrushNet": [ + [ + "BlendInpaint", + "BrushNetInpaint", + "BrushNetLoader", + "BrushNetPipeline" + ], + { + "author": "nullquant", + "description": "This repository contains an custom nodes for inpaint using BrushNet and PowerPaint models", + "nickname": "BrushName nodes", + "title": "BrushNet", + "title_aux": "BrushNet" + } + ], "https://github.com/olduvai-jp/ComfyUI-HfLoader": [ [ "Lora Loader From HF" @@ -9115,6 +9866,14 @@ "title_aux": "Image Resize for ComfyUI" } ], + "https://github.com/pamparamm/sd-perturbed-attention": [ + [ + "PerturbedAttention" + ], + { + "title_aux": "Perturbed-Attention Guidance" + } + ], "https://github.com/pants007/comfy-pants": [ [ "CLIPTextEncodeAIO", @@ -9282,7 +10041,7 @@ "description": "ComfyUI node version of the SD Prompt Reader", "nickname": "SD Prompt Reader", "title": "SD Prompt Reader", - "title_aux": "comfyui-prompt-reader-node" + "title_aux": "SD Prompt Reader" } ], "https://github.com/redhottensors/ComfyUI-Prediction": [ @@ -9385,6 +10144,21 @@ "title_aux": "ComfyUI-Tara-LLM-Integration" } ], + "https://github.com/royceschultz/ComfyUI-TranscriptionTools": [ + [ + "TT-AudioSink", + "TT-ConvertVhsAudioToAudio", + "TT-LoadAudio", + "TT-LoadBatch", + "TT-LoadVideoAudio", + "TT-LoadWhisperModel", + "TT-WhisperTranscription", + "TT-WhisperTranscriptionBatch" + ], + { + "title_aux": "ComfyUI-TranscriptionTools" + } + ], "https://github.com/rui40000/RUI-Nodes": [ [ "ABCondition", @@ -9511,6 +10285,7 @@ "NewLayer", "NoiseImage", "OutlineMask", + "PreviewMask_", "PromptImage", "PromptSimplification", "PromptSlide", @@ -9751,6 +10526,40 @@ "title_aux": "kb-comfyui-nodes" } ], + "https://github.com/smthemex/ComfyUI_ChatGLM_API": [ + [ + "ZhipuaiApi_Txt", + "ZhipuaiApi_img" + ], + { + "title_aux": "ComfyUI_ChatGLM_API" + } + ], + "https://github.com/smthemex/ComfyUI_ParlerTTS": [ + [ + "ModelDownload", + "PromptToAudio" + ], + { + "title_aux": "ComfyUI_ParlerTTS" + } + ], + "https://github.com/smthemex/ComfyUI_Pic2Story": [ + [ + "Pic2Story" + ], + { + "title_aux": "ComfyUI_Pic2Story" + } + ], + "https://github.com/smthemex/ComfyUI_Pipeline_Tool": [ + [ + "Pipeline_Tool" + ], + { + "title_aux": "ComfyUI_Pipeline_Tool" + } + ], "https://github.com/space-nuko/ComfyUI-Disco-Diffusion": [ [ "DiscoDiffusion_DiscoDiffusion", @@ -9816,8 +10625,10 @@ "GuidedFilterAlpha", "ImageConstant", "ImageConstantHSV", + "InstructPixToPixConditioningAdvanced", "JitterImage", "Keyer", + "LatentNormalizeShuffle", "LatentStats", "NormalMapSimple", "OffsetLatentImage", @@ -9962,6 +10773,14 @@ "title_aux": "ComfyUI-sudo-latent-upscale" } ], + "https://github.com/sugarkwork/comfyui_tag_fillter": [ + [ + "TagFilter" + ], + { + "title_aux": "comfyui_tag_filter" + } + ], "https://github.com/syllebra/bilbox-comfyui": [ [ "BilboXLut", @@ -10148,6 +10967,27 @@ "title_aux": "ComfyUI_toyxyz_test_nodes" } ], + "https://github.com/traugdor/ComfyUI-quadMoons-nodes": [ + [ + "quadmoonCLIPTextEncode", + "quadmoonConvertBoolToString", + "quadmoonConvertFloatToString", + "quadmoonConvertIntToString", + "quadmoonConvertNormalizeHW", + "quadmoonConvertNumberToString", + "quadmoonINTConditionalOperation", + "quadmoonKSampler", + "quadmoonKSamplerAdvanced", + "quadmoonThebutton" + ], + { + "author": "quadmoon (https://github.com/traugdor)", + "description": "These are just some nodes I wanted and couldn't find where anyone else had made them yet.", + "nickname": "quadmoon's Nodes", + "title": "quadmoon's ComfyUI nodes", + "title_aux": "quadmoon's ComfyUI nodes" + } + ], "https://github.com/trojblue/trNodes": [ [ "JpgConvertNode", @@ -10219,6 +11059,22 @@ "title_aux": "Hakkun-ComfyUI-nodes" } ], + "https://github.com/turkyden/ComfyUI-Comic": [ + [ + "Image To Comic" + ], + { + "title_aux": "ComfyUI-Comic" + } + ], + "https://github.com/turkyden/ComfyUI-Sticker": [ + [ + "Image To Sticker" + ], + { + "title_aux": "ComfyUI-Sticker" + } + ], "https://github.com/tusharbhutt/Endless-Nodes": [ [ "ESS Aesthetic Scoring", @@ -10292,6 +11148,17 @@ "title_aux": "comfyui-webcam-node" } ], + "https://github.com/unwdef/unwdef-nodes-comfyui": [ + [ + "RandomTextFromMultiline", + "RandomizeLoras", + "RandomizeLorasStack", + "TextMultilineWithVariables" + ], + { + "title_aux": "unwdef-nodes" + } + ], "https://github.com/vanillacode314/SimpleWildcardsComfyUI": [ [ "SimpleConcat", @@ -10588,6 +11455,14 @@ "title_aux": "hd-nodes-comfyui" } ], + "https://github.com/xliry/ComfyUI_SendDiscord/raw/main/SendDiscord.py": [ + [ + "SendDiscord" + ], + { + "title_aux": "ComfyUI_SendDiscord" + } + ], "https://github.com/yffyhk/comfyui_auto_danbooru": [ [ "GetDanbooru", @@ -10622,6 +11497,8 @@ "easy cascadeKSampler", "easy cascadeLoader", "easy cleanGpuUsed", + "easy clearCacheAll", + "easy clearCacheKey", "easy comfyLoader", "easy compare", "easy controlnetLoader", @@ -10636,12 +11513,14 @@ "easy fullkSampler", "easy globalSeed", "easy hiresFix", + "easy humanParsing", "easy if", + "easy imageChooser", "easy imageInsetCrop", + "easy imageInterrogator", "easy imagePixelPerfect", "easy imageRatio", "easy imageRemBg", - "easy imageRemoveBG", "easy imageSave", "easy imageScaleDown", "easy imageScaleDownBy", @@ -10652,6 +11531,7 @@ "easy imageSplitList", "easy imageSwitch", "easy imageToMask", + "easy injectNoiseToLatent", "easy instantIDApply", "easy instantIDApplyADV", "easy int", @@ -10659,6 +11539,9 @@ "easy ipadapterApplyADV", "easy ipadapterApplyEmbeds", "easy ipadapterApplyEncoder", + "easy ipadapterApplyFromParams", + "easy ipadapterApplyRegional", + "easy ipadapterStyleComposition", "easy isSDXL", "easy joinImageBatch", "easy kSampler", @@ -10684,6 +11567,7 @@ "easy preSampling", "easy preSamplingAdvanced", "easy preSamplingCascade", + "easy preSamplingCustom", "easy preSamplingDynamicCFG", "easy preSamplingLayerDiffusion", "easy preSamplingLayerDiffusionADDTL", @@ -10701,6 +11585,7 @@ "easy showLoaderSettingsNames", "easy showSpentTime", "easy showTensorShape", + "easy stableDiffusion3API", "easy string", "easy stylesSelector", "easy sv3dLoader", @@ -10924,6 +11809,7 @@ [ "ConcatText", "ImageBatchOneOrMore", + "IntAndIntAddOffsetLiteral", "LoadImageWithSwitch", "ModifyTextGender" ], diff --git a/node_db/new/model-list.json b/node_db/new/model-list.json index 18ba54ac..ff610f8e 100644 --- a/node_db/new/model-list.json +++ b/node_db/new/model-list.json @@ -1,5 +1,25 @@ { "models": [ + { + "name": "Kijai/SUPIR-v0F_fp16.safetensors (pruned)", + "type": "checkpoints", + "base": "SUPIR", + "save_path": "checkpoints/SUPIR", + "description": "SUPIR checkpoint model", + "reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main", + "filename": "SUPIR-v0F_fp16.safetensors", + "url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0F_fp16.safetensors" + }, + { + "name": "Kijai/SUPIR-v0Q_fp16.safetensors (pruned)", + "type": "checkpoints", + "base": "SUPIR", + "save_path": "checkpoints/SUPIR", + "description": "SUPIR checkpoint model", + "reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main", + "filename": "SUPIR-v0Q_fp16.safetensors", + "url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0Q_fp16.safetensors" + }, { "name": "SUPIR-v0F.ckpt", "type": "checkpoints", @@ -641,86 +661,6 @@ "reference": "https://huggingface.co/Lightricks/LongAnimateDiff", "filename": "lt_long_mm_16_64_frames.ckpt", "url": "https://huggingface.co/Lightricks/LongAnimateDiff/resolve/main/lt_long_mm_16_64_frames.ckpt" - }, - { - "name": "ip-adapter_sd15.safetensors", - "type": "IP-Adapter", - "base": "SD1.5", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter_sd15.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15.safetensors" - }, - { - "name": "ip-adapter_sd15_light.safetensors", - "type": "IP-Adapter", - "base": "SD1.5", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter_sd15_light.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15_light.safetensors" - }, - { - "name": "ip-adapter_sd15_vit-G.safetensors", - "type": "IP-Adapter", - "base": "SD1.5", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter_sd15_vit-G.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15_vit-G.safetensors" - }, - { - "name": "ip-adapter-plus_sd15.safetensors", - "type": "IP-Adapter", - "base": "SD1.5", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter-plus_sd15.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-plus_sd15.safetensors" - }, - { - "name": "ip-adapter-plus-face_sd15.safetensors", - "type": "IP-Adapter", - "base": "SD1.5", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter-plus-face_sd15.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-plus-face_sd15.safetensors" - }, - { - "name": "ip-adapter-full-face_sd15.safetensors", - "type": "IP-Adapter", - "base": "SD1.5", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter-full-face_sd15.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-full-face_sd15.safetensors" - }, - { - "name": "ip-adapter_sdxl.safetensors", - "type": "IP-Adapter", - "base": "SDXL", - "save_path": "ipadapter", - "description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter_sdxl.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter_sdxl.safetensors" - }, - { - "name": "ip-adapter_sdxl_vit-h.safetensors", - "type": "IP-Adapter", - "base": "SDXL", - "save_path": "ipadapter", - "description": "This model requires the use of the SD1.5 encoder despite being for SDXL checkpoints", - "reference": "https://huggingface.co/h94/IP-Adapter", - "filename": "ip-adapter_sdxl_vit-h.safetensors", - "url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter_sdxl_vit-h.safetensors" } ] } diff --git a/node_db/tutorial/custom-node-list.json b/node_db/tutorial/custom-node-list.json index cc822d84..d71faec3 100644 --- a/node_db/tutorial/custom-node-list.json +++ b/node_db/tutorial/custom-node-list.json @@ -10,6 +10,16 @@ "install_type": "git-clone", "description": "There is a small node pack attached to this guide. This includes the init file and 3 nodes associated with the tutorials." }, + { + "author": "bamboodia", + "title": "BAM Nodes", + "reference": "https://github.com/bamboodia/BAM_Nodes", + "files": [ + "https://github.com/bamboodia/BAM_Nodes" + ], + "install_type": "git-clone", + "description": "A collection of comfyui nodes that I have made for nothing more than educational purposes." + }, { "author": "BadCafeCode", "title": "execution-inversion-demo-comfyui", @@ -159,6 +169,16 @@ ], "install_type": "git-clone", "description": "Nodes:Woman_in_a_dress" + }, + { + "author": "shinich39", + "title": "comfyui-concat-text-39", + "reference": "https://github.com/shinich39/comfyui-concat-text-39", + "files": [ + "https://github.com/shinich39/comfyui-concat-text-39" + ], + "install_type": "git-clone", + "description": "Nodes:Concatenate multiple text nodes." } ] } \ No newline at end of file diff --git a/notebooks/comfyui_colab_with_manager.ipynb b/notebooks/comfyui_colab_with_manager.ipynb index 36bab4fe..55ee514a 100644 --- a/notebooks/comfyui_colab_with_manager.ipynb +++ b/notebooks/comfyui_colab_with_manager.ipynb @@ -50,11 +50,21 @@ "\n", "if OPTIONS['UPDATE_COMFY_UI']:\n", " !echo -= Updating ComfyUI =-\n", + "\n", + " # Correction of the issue of permissions being deleted on Google Drive.\n", + " ![ -f \".ci/nightly/update_windows/update_comfyui_and_python_dependencies.bat\" ] && chmod 755 .ci/nightly/update_windows/update_comfyui_and_python_dependencies.bat\n", + " ![ -f \".ci/nightly/windows_base_files/run_nvidia_gpu.bat\" ] && chmod 755 .ci/nightly/windows_base_files/run_nvidia_gpu.bat\n", + " ![ -f \".ci/update_windows/update_comfyui_and_python_dependencies.bat\" ] && chmod 755 .ci/update_windows/update_comfyui_and_python_dependencies.bat\n", + " ![ -f \".ci/update_windows_cu118/update_comfyui_and_python_dependencies.bat\" ] && chmod 755 .ci/update_windows_cu118/update_comfyui_and_python_dependencies.bat\n", + " ![ -f \".ci/update_windows/update.py\" ] && chmod 755 .ci/update_windows/update.py\n", + " ![ -f \".ci/update_windows/update_comfyui.bat\" ] && chmod 755 .ci/update_windows/update_comfyui.bat\n", + " ![ -f \".ci/update_windows/README_VERY_IMPORTANT.txt\" ] && chmod 755 .ci/update_windows/README_VERY_IMPORTANT.txt\n", + " ![ -f \".ci/update_windows/run_cpu.bat\" ] && chmod 755 .ci/update_windows/run_cpu.bat\n", + " ![ -f \".ci/update_windows/run_nvidia_gpu.bat\" ] && chmod 755 .ci/update_windows/run_nvidia_gpu.bat\n", + "\n", " !git pull\n", "\n", "!echo -= Install dependencies =-\n", - "#Remove cu121 as it causes issues in Colab.\n", - "#!pip install xformers!=0.0.18 -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu121 --extra-index-url https://download.pytorch.org/whl/cu118 --extra-index-url https://download.pytorch.org/whl/cu117\n", "!pip3 install accelerate\n", "!pip3 install einops transformers>=4.25.1 safetensors>=0.3.0 aiohttp pyyaml Pillow scipy tqdm psutil\n", "!pip3 install xformers!=0.0.18 torch==2.1.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121\n", @@ -62,6 +72,14 @@ "\n", "if OPTIONS['USE_COMFYUI_MANAGER']:\n", " %cd custom_nodes\n", + "\n", + " # Correction of the issue of permissions being deleted on Google Drive.\n", + " ![ -f \"ComfyUI-Manager/check.sh\" ] && chmod 755 ComfyUI-Manager/check.sh\n", + " ![ -f \"ComfyUI-Manager/scan.sh\" ] && chmod 755 ComfyUI-Manager/scan.sh\n", + " ![ -f \"ComfyUI-Manager/node_db/dev/scan.sh\" ] && chmod 755 ComfyUI-Manager/node_db/dev/scan.sh\n", + " ![ -f \"ComfyUI-Manager/scripts/install-comfyui-venv-linux.sh\" ] && chmod 755 ComfyUI-Manager/scripts/install-comfyui-venv-linux.sh\n", + " ![ -f \"ComfyUI-Manager/scripts/install-comfyui-venv-win.bat\" ] && chmod 755 ComfyUI-Manager/scripts/install-comfyui-venv-win.bat\n", + "\n", " ![ ! -d ComfyUI-Manager ] && echo -= Initial setup ComfyUI-Manager =- && git clone https://github.com/ltdrdata/ComfyUI-Manager\n", " %cd ComfyUI-Manager\n", " !git pull\n", @@ -69,9 +87,9 @@ "%cd $WORKSPACE\n", "\n", "if OPTIONS['INSTALL_CUSTOM_NODES_DEPENDENCIES']:\n", - " !pwd\n", " !echo -= Install custom nodes dependencies =-\n", - " ![ -f \"custom_nodes/ComfyUI-Manager/scripts/colab-dependencies.py\" ] && python \"custom_nodes/ComfyUI-Manager/scripts/colab-dependencies.py\"\n" + " !pip install GitPython\n", + " !python custom_nodes/ComfyUI-Manager/cm-cli.py restore-dependencies\n" ] }, { @@ -350,4 +368,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file diff --git a/pip_overrides.json.template b/pip_overrides.json.template new file mode 100644 index 00000000..a6b1f262 --- /dev/null +++ b/pip_overrides.json.template @@ -0,0 +1,21 @@ +{ + "imageio-ffmpeg": "imageio", + "imageio[ffmpeg]": "imageio", + "imageio_ffmpeg": "imageio", + "diffusers~=0.21.4": "diffusers", + "huggingface_hub": "huggingface-hub", + "numpy<1.24>=1.18": "numpy", + "numpy>=1.18.5, <1.25.0": "numpy", + "opencv-contrib-python": "opencv-contrib-python-headless", + "opencv-python": "opencv-contrib-python-headless", + "opencv-python-headless": "opencv-contrib-python-headless", + "opencv-python-headless[ffmpeg]<=4.7.0.72": "opencv-contrib-python-headless", + "opencv-python>=4.7.0.72": "opencv-contrib-python-headless", + "pandas<=1.5.1": "pandas", + "scikit-image==0.20.0": "scikit-image", + "scipy>=1.11.4": "scipy", + "segment_anything": "segment-anything", + "timm==0.6.5": "timm", + "timm>=0.4.12": "timm", + "transformers==4.26.1": "transformers" +} \ No newline at end of file diff --git a/prestartup_script.py b/prestartup_script.py index 0134aeca..c3476c9b 100644 --- a/prestartup_script.py +++ b/prestartup_script.py @@ -7,13 +7,13 @@ import threading import re import locale import platform +import json glob_path = os.path.join(os.path.dirname(__file__), "glob") sys.path.append(glob_path) from manager_util import * - import cm_global @@ -69,6 +69,23 @@ custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, "..")) startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts") restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json") git_script_path = os.path.join(comfyui_manager_path, "git_helper.py") +pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json") + + +cm_global.pip_overrides = {} +if os.path.exists(pip_overrides_path): + with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file: + cm_global.pip_overrides = json.load(json_file) + + +def remap_pip_package(pkg): + if pkg in cm_global.pip_overrides: + res = cm_global.pip_overrides[pkg] + print(f"[ComfyUI-Manager] '{pkg}' is remapped to '{res}'") + return res + else: + return pkg + std_log_lock = threading.Lock() @@ -283,6 +300,30 @@ except Exception as e: print(f"[ComfyUI-Manager] Logging failed: {e}") +try: + import git +except: + my_path = os.path.dirname(__file__) + requirements_path = os.path.join(my_path, "requirements.txt") + + print(f"## ComfyUI-Manager: installing dependencies. (GitPython)") + + result = subprocess.check_output([sys.executable, '-s', '-m', 'pip', 'install', '-r', requirements_path]) + + try: + import git + except: + print(f"## [ERROR] ComfyUI-Manager: Attempting to reinstall dependencies using an alternative method.") + result = subprocess.check_output([sys.executable, '-s', '-m', 'pip', 'install', '--user', '-r', requirements_path]) + + try: + import git + except: + print(f"## [ERROR] ComfyUI-Manager: Failed to install the GitPython package in the correct Python environment. Please install it manually in the appropriate environment. (You can seek help at https://app.element.io/#/room/%23comfyui_space%3Amatrix.org)") + + print(f"## ComfyUI-Manager: installing dependencies done.") + + print("** ComfyUI startup time:", datetime.datetime.now()) print("** Platform:", platform.system()) print("** Python version:", sys.version) @@ -391,8 +432,6 @@ def is_installed(name): if os.path.exists(restore_snapshot_path): try: - import json - cloned_repos = [] def msg_capture(stream, prefix): @@ -420,40 +459,39 @@ if os.path.exists(restore_snapshot_path): cmd_str = [sys.executable, git_script_path, '--apply-snapshot', restore_snapshot_path] exit_code = process_wrap(cmd_str, custom_nodes_path, handler=msg_capture) - with open(restore_snapshot_path, 'r', encoding="UTF-8", errors="ignore") as json_file: - info = json.load(json_file) - for url in cloned_repos: - try: - repository_name = url.split("/")[-1].strip() - repo_path = os.path.join(custom_nodes_path, repository_name) - repo_path = os.path.abspath(repo_path) + repository_name = '' + for url in cloned_repos: + try: + repository_name = url.split("/")[-1].strip() + repo_path = os.path.join(custom_nodes_path, repository_name) + repo_path = os.path.abspath(repo_path) - requirements_path = os.path.join(repo_path, 'requirements.txt') - install_script_path = os.path.join(repo_path, 'install.py') + requirements_path = os.path.join(repo_path, 'requirements.txt') + install_script_path = os.path.join(repo_path, 'install.py') - this_exit_code = 0 + this_exit_code = 0 - if os.path.exists(requirements_path): - with open(requirements_path, 'r', encoding="UTF-8", errors="ignore") as file: - for line in file: - package_name = line.strip() - if package_name and not is_installed(package_name): - install_cmd = [sys.executable, "-m", "pip", "install", package_name] - this_exit_code += process_wrap(install_cmd, repo_path) + if os.path.exists(requirements_path): + with open(requirements_path, 'r', encoding="UTF-8", errors="ignore") as file: + for line in file: + package_name = remap_pip_package(line.strip()) + if package_name and not is_installed(package_name): + install_cmd = [sys.executable, "-m", "pip", "install", package_name] + this_exit_code += process_wrap(install_cmd, repo_path) - if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install: - processed_install.add(f'{repo_path}/install.py') - install_cmd = [sys.executable, install_script_path] - print(f">>> {install_cmd} / {repo_path}") - this_exit_code += process_wrap(install_cmd, repo_path) + if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install: + processed_install.add(f'{repo_path}/install.py') + install_cmd = [sys.executable, install_script_path] + print(f">>> {install_cmd} / {repo_path}") + this_exit_code += process_wrap(install_cmd, repo_path) - if this_exit_code != 0: - print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.") - - except Exception as e: - print(e) + if this_exit_code != 0: print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.") + except Exception as e: + print(e) + print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.") + if exit_code != 0: print(f"[ComfyUI-Manager] Restore snapshot failed.") else: @@ -476,7 +514,7 @@ def execute_lazy_install_script(repo_path, executable): print(f"Install: pip packages for '{repo_path}'") with open(requirements_path, "r") as requirements_file: for line in requirements_file: - package_name = line.strip() + package_name = remap_pip_package(line.strip()) if package_name and not is_installed(package_name): install_cmd = [executable, "-m", "pip", "install", package_name] process_wrap(install_cmd, repo_path) diff --git a/scanner.py b/scanner.py index 6fc473e6..c23bb5fc 100644 --- a/scanner.py +++ b/scanner.py @@ -14,7 +14,6 @@ import sys from urllib.parse import urlparse from github import Github -g = Github(os.environ.get('GITHUB_TOKEN')) # prepare temp dir if len(sys.argv) > 1: @@ -25,7 +24,15 @@ else: if not os.path.exists(temp_dir): os.makedirs(temp_dir) -skip_update = '--skip-update' in sys.argv + +skip_update = '--skip-update' in sys.argv or '--skip-all' in sys.argv +skip_stat_update = '--skip-stat-update' in sys.argv or '--skip-all' in sys.argv + +if not skip_stat_update: + g = Github(os.environ.get('GITHUB_TOKEN')) +else: + g = None + print(f"TEMP DIR: {temp_dir}") @@ -301,7 +308,9 @@ def update_custom_nodes(): # pass with concurrent.futures.ThreadPoolExecutor(11) as executor: - executor.submit(process_git_stats, git_url_titles_preemptions) # One single thread for `process_git_stats()`. Runs concurrently with `process_git_url_title()`. + if not skip_stat_update: + executor.submit(process_git_stats, git_url_titles_preemptions) # One single thread for `process_git_stats()`. Runs concurrently with `process_git_url_title()`. + for url, title, preemptions, node_pattern in git_url_titles_preemptions: executor.submit(process_git_url_title, url, title, preemptions, node_pattern)