Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f4184b887 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,8 +1,6 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
.history/
|
|
||||||
*.code-workspace
|
|
||||||
.tmp
|
.tmp
|
||||||
.cache
|
.cache
|
||||||
config.ini
|
config.ini
|
||||||
@@ -17,4 +15,3 @@ github-stats-cache.json
|
|||||||
pip_overrides.json
|
pip_overrides.json
|
||||||
*.json
|
*.json
|
||||||
check2.sh
|
check2.sh
|
||||||
/venv/
|
|
||||||
@@ -320,9 +320,6 @@ NODE_CLASS_MAPPINGS.update({
|
|||||||
* Use `aria2` as downloader
|
* Use `aria2` as downloader
|
||||||
* [howto](docs/en/use_aria2.md)
|
* [howto](docs/en/use_aria2.md)
|
||||||
|
|
||||||
* If you add the item `skip_migration_check = True` to `config.ini`, it will not check whether there are nodes that can be migrated at startup.
|
|
||||||
* This option can be used if performance issues occur in a Colab+GDrive environment.
|
|
||||||
|
|
||||||
## Scanner
|
## Scanner
|
||||||
When you run the `scan.sh` script:
|
When you run the `scan.sh` script:
|
||||||
|
|
||||||
|
|||||||
1
check.sh
1
check.sh
@@ -9,7 +9,6 @@ files=(
|
|||||||
"alter-list.json"
|
"alter-list.json"
|
||||||
"extension-node-map.json"
|
"extension-node-map.json"
|
||||||
"github-stats.json"
|
"github-stats.json"
|
||||||
"extras.json"
|
|
||||||
"node_db/new/custom-node-list.json"
|
"node_db/new/custom-node-list.json"
|
||||||
"node_db/new/model-list.json"
|
"node_db/new/model-list.json"
|
||||||
"node_db/new/extension-node-map.json"
|
"node_db/new/extension-node-map.json"
|
||||||
|
|||||||
25
extras.json
25
extras.json
@@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"favorites": [
|
|
||||||
"comfyui_ipadapter_plus",
|
|
||||||
"comfyui-animatediff-evolved",
|
|
||||||
"comfyui_controlnet_aux",
|
|
||||||
"comfyui-impact-pack",
|
|
||||||
"comfyui-custom-scripts",
|
|
||||||
"comfyui-layerdiffuse",
|
|
||||||
"comfyui-liveportraitkj",
|
|
||||||
"aigodlike-comfyui-translation",
|
|
||||||
"comfyui-reactor-node",
|
|
||||||
"comfyui_instantid",
|
|
||||||
"sd-dynamic-thresholding",
|
|
||||||
"pr-was-node-suite-comfyui-47064894",
|
|
||||||
"comfyui-advancedliveportrait",
|
|
||||||
"comfyui_layerstyle",
|
|
||||||
"efficiency-nodes-comfyui",
|
|
||||||
"comfyui-crystools",
|
|
||||||
"comfyui-advanced-controlnet",
|
|
||||||
"comfyui-videohelpersuite",
|
|
||||||
"comfyui-kjnodes",
|
|
||||||
"comfy-mtb",
|
|
||||||
"comfyui_essentials"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import traceback
|
|||||||
|
|
||||||
import git
|
import git
|
||||||
import configparser
|
import configparser
|
||||||
|
import re
|
||||||
import json
|
import json
|
||||||
import yaml
|
import yaml
|
||||||
import requests
|
import requests
|
||||||
@@ -12,14 +13,6 @@ from tqdm.auto import tqdm
|
|||||||
from git.remote import RemoteProgress
|
from git.remote import RemoteProgress
|
||||||
|
|
||||||
|
|
||||||
comfy_path = os.environ.get('COMFYUI_PATH')
|
|
||||||
|
|
||||||
if comfy_path is None:
|
|
||||||
print("\n[bold yellow]WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.[/bold yellow]", file=sys.stderr)
|
|
||||||
comfy_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def download_url(url, dest_folder, filename=None):
|
def download_url(url, dest_folder, filename=None):
|
||||||
# Ensure the destination folder exists
|
# Ensure the destination folder exists
|
||||||
if not os.path.exists(dest_folder):
|
if not os.path.exists(dest_folder):
|
||||||
@@ -66,11 +59,9 @@ class GitProgress(RemoteProgress):
|
|||||||
self.pbar.refresh()
|
self.pbar.refresh()
|
||||||
|
|
||||||
|
|
||||||
def gitclone(custom_nodes_path, url, target_hash=None, repo_path=None):
|
def gitclone(custom_nodes_path, url, target_hash=None):
|
||||||
repo_name = os.path.splitext(os.path.basename(url))[0]
|
repo_name = os.path.splitext(os.path.basename(url))[0]
|
||||||
|
repo_path = os.path.join(custom_nodes_path, repo_name)
|
||||||
if repo_path is None:
|
|
||||||
repo_path = os.path.join(custom_nodes_path, repo_name)
|
|
||||||
|
|
||||||
# Clone the repository from the remote URL
|
# Clone the repository from the remote URL
|
||||||
repo = git.Repo.clone_from(url, repo_path, recursive=True, progress=GitProgress())
|
repo = git.Repo.clone_from(url, repo_path, recursive=True, progress=GitProgress())
|
||||||
@@ -103,12 +94,7 @@ def gitcheck(path, do_fetch=False):
|
|||||||
|
|
||||||
# Get the current commit hash and the commit hash of the remote branch
|
# Get the current commit hash and the commit hash of the remote branch
|
||||||
commit_hash = repo.head.commit.hexsha
|
commit_hash = repo.head.commit.hexsha
|
||||||
|
remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha
|
||||||
if f'{remote_name}/{branch_name}' in repo.refs:
|
|
||||||
remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha
|
|
||||||
else:
|
|
||||||
print("CUSTOM NODE CHECK: True") # non default branch is treated as updatable
|
|
||||||
return
|
|
||||||
|
|
||||||
# Compare the commit hashes to determine if the local repository is behind the remote repository
|
# Compare the commit hashes to determine if the local repository is behind the remote repository
|
||||||
if commit_hash != remote_commit_hash:
|
if commit_hash != remote_commit_hash:
|
||||||
@@ -127,8 +113,11 @@ def gitcheck(path, do_fetch=False):
|
|||||||
|
|
||||||
|
|
||||||
def switch_to_default_branch(repo):
|
def switch_to_default_branch(repo):
|
||||||
default_branch = repo.git.symbolic_ref('refs/remotes/origin/HEAD').replace('refs/remotes/origin/', '')
|
show_result = repo.git.remote("show", "origin")
|
||||||
repo.git.checkout(default_branch)
|
matches = re.search(r"\s*HEAD branch:\s*(.*)", show_result)
|
||||||
|
if matches:
|
||||||
|
default_branch = matches.group(1)
|
||||||
|
repo.git.checkout(default_branch)
|
||||||
|
|
||||||
|
|
||||||
def gitpull(path):
|
def gitpull(path):
|
||||||
@@ -139,7 +128,6 @@ def gitpull(path):
|
|||||||
# Pull the latest changes from the remote repository
|
# Pull the latest changes from the remote repository
|
||||||
repo = git.Repo(path)
|
repo = git.Repo(path)
|
||||||
if repo.is_dirty():
|
if repo.is_dirty():
|
||||||
print(f"STASH: '{path}' is dirty.")
|
|
||||||
repo.git.stash()
|
repo.git.stash()
|
||||||
|
|
||||||
commit_hash = repo.head.commit.hexsha
|
commit_hash = repo.head.commit.hexsha
|
||||||
@@ -153,11 +141,6 @@ def gitpull(path):
|
|||||||
remote_name = current_branch.tracking_branch().remote_name
|
remote_name = current_branch.tracking_branch().remote_name
|
||||||
remote = repo.remote(name=remote_name)
|
remote = repo.remote(name=remote_name)
|
||||||
|
|
||||||
if f'{remote_name}/{branch_name}' not in repo.refs:
|
|
||||||
switch_to_default_branch(repo)
|
|
||||||
current_branch = repo.active_branch
|
|
||||||
branch_name = current_branch.name
|
|
||||||
|
|
||||||
remote.fetch()
|
remote.fetch()
|
||||||
remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha
|
remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha
|
||||||
|
|
||||||
@@ -183,7 +166,9 @@ def gitpull(path):
|
|||||||
|
|
||||||
|
|
||||||
def checkout_comfyui_hash(target_hash):
|
def checkout_comfyui_hash(target_hash):
|
||||||
repo = git.Repo(comfy_path)
|
repo_path = os.path.abspath(os.path.join(working_directory, '..')) # ComfyUI dir
|
||||||
|
|
||||||
|
repo = git.Repo(repo_path)
|
||||||
commit_hash = repo.head.commit.hexsha
|
commit_hash = repo.head.commit.hexsha
|
||||||
|
|
||||||
if commit_hash != target_hash:
|
if commit_hash != target_hash:
|
||||||
@@ -265,9 +250,6 @@ def checkout_custom_node_hash(git_custom_node_infos):
|
|||||||
|
|
||||||
# clone missing
|
# clone missing
|
||||||
for k, v in git_custom_node_infos.items():
|
for k, v in git_custom_node_infos.items():
|
||||||
if 'ComfyUI-Manager' in k:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not v['disabled']:
|
if not v['disabled']:
|
||||||
repo_name = k.split('/')[-1]
|
repo_name = k.split('/')[-1]
|
||||||
if repo_name.endswith('.git'):
|
if repo_name.endswith('.git'):
|
||||||
@@ -276,7 +258,7 @@ def checkout_custom_node_hash(git_custom_node_infos):
|
|||||||
path = os.path.join(working_directory, repo_name)
|
path = os.path.join(working_directory, repo_name)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
print(f"CLONE: {path}")
|
print(f"CLONE: {path}")
|
||||||
gitclone(working_directory, k, target_hash=v['hash'])
|
gitclone(working_directory, k, v['hash'])
|
||||||
|
|
||||||
|
|
||||||
def invalidate_custom_node_file(file_custom_node_infos):
|
def invalidate_custom_node_file(file_custom_node_infos):
|
||||||
@@ -326,18 +308,19 @@ def invalidate_custom_node_file(file_custom_node_infos):
|
|||||||
download_url(url, working_directory)
|
download_url(url, working_directory)
|
||||||
|
|
||||||
|
|
||||||
def apply_snapshot(path):
|
def apply_snapshot(target):
|
||||||
try:
|
try:
|
||||||
|
path = os.path.join(os.path.dirname(__file__), 'snapshots', f"{target}")
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
if not path.endswith('.json') and not path.endswith('.yaml'):
|
if not target.endswith('.json') and not target.endswith('.yaml'):
|
||||||
print(f"Snapshot file not found: `{path}`")
|
print(f"Snapshot file not found: `{path}`")
|
||||||
print("APPLY SNAPSHOT: False")
|
print("APPLY SNAPSHOT: False")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
with open(path, 'r', encoding="UTF-8") as snapshot_file:
|
with open(path, 'r', encoding="UTF-8") as snapshot_file:
|
||||||
if path.endswith('.json'):
|
if target.endswith('.json'):
|
||||||
info = json.load(snapshot_file)
|
info = json.load(snapshot_file)
|
||||||
elif path.endswith('.yaml'):
|
elif target.endswith('.yaml'):
|
||||||
info = yaml.load(snapshot_file, Loader=yaml.SafeLoader)
|
info = yaml.load(snapshot_file, Loader=yaml.SafeLoader)
|
||||||
info = info['custom_nodes']
|
info = info['custom_nodes']
|
||||||
else:
|
else:
|
||||||
@@ -442,11 +425,7 @@ setup_environment()
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if sys.argv[1] == "--clone":
|
if sys.argv[1] == "--clone":
|
||||||
repo_path = None
|
gitclone(sys.argv[2], sys.argv[3])
|
||||||
if len(sys.argv) > 4:
|
|
||||||
repo_path = sys.argv[4]
|
|
||||||
|
|
||||||
gitclone(sys.argv[2], sys.argv[3], repo_path=repo_path)
|
|
||||||
elif sys.argv[1] == "--check":
|
elif sys.argv[1] == "--check":
|
||||||
gitcheck(sys.argv[2], False)
|
gitcheck(sys.argv[2], False)
|
||||||
elif sys.argv[1] == "--fetch":
|
elif sys.argv[1] == "--fetch":
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
import requests
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import List
|
|
||||||
import manager_util
|
|
||||||
import toml
|
|
||||||
import os
|
|
||||||
|
|
||||||
base_url = "https://api.comfy.org"
|
|
||||||
|
|
||||||
|
|
||||||
async def get_cnr_data(page=1, limit=1000, cache_mode=True):
|
|
||||||
try:
|
|
||||||
uri = f'{base_url}/nodes?page={page}&limit={limit}'
|
|
||||||
json_obj = await manager_util.get_data_with_cache(uri, cache_mode=cache_mode)
|
|
||||||
|
|
||||||
for v in json_obj['nodes']:
|
|
||||||
if 'latest_version' not in v:
|
|
||||||
v['latest_version'] = dict(version='nightly')
|
|
||||||
|
|
||||||
return json_obj['nodes']
|
|
||||||
except:
|
|
||||||
res = {}
|
|
||||||
print("Cannot connect to comfyregistry.")
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class NodeVersion:
|
|
||||||
changelog: str
|
|
||||||
dependencies: List[str]
|
|
||||||
deprecated: bool
|
|
||||||
id: str
|
|
||||||
version: str
|
|
||||||
download_url: str
|
|
||||||
|
|
||||||
|
|
||||||
def map_node_version(api_node_version):
|
|
||||||
"""
|
|
||||||
Maps node version data from API response to NodeVersion dataclass.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
api_data (dict): The 'node_version' part of the API response.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
NodeVersion: An instance of NodeVersion dataclass populated with data from the API.
|
|
||||||
"""
|
|
||||||
return NodeVersion(
|
|
||||||
changelog=api_node_version.get(
|
|
||||||
"changelog", ""
|
|
||||||
), # Provide a default value if 'changelog' is missing
|
|
||||||
dependencies=api_node_version.get(
|
|
||||||
"dependencies", []
|
|
||||||
), # Provide a default empty list if 'dependencies' is missing
|
|
||||||
deprecated=api_node_version.get(
|
|
||||||
"deprecated", False
|
|
||||||
), # Assume False if 'deprecated' is not specified
|
|
||||||
id=api_node_version[
|
|
||||||
"id"
|
|
||||||
], # 'id' should be mandatory; raise KeyError if missing
|
|
||||||
version=api_node_version[
|
|
||||||
"version"
|
|
||||||
], # 'version' should be mandatory; raise KeyError if missing
|
|
||||||
download_url=api_node_version.get(
|
|
||||||
"downloadUrl", ""
|
|
||||||
), # Provide a default value if 'downloadUrl' is missing
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def install_node(node_id, version=None):
|
|
||||||
"""
|
|
||||||
Retrieves the node version for installation.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
node_id (str): The unique identifier of the node.
|
|
||||||
version (str, optional): Specific version of the node to retrieve. If omitted, the latest version is returned.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
NodeVersion: Node version data or error message.
|
|
||||||
"""
|
|
||||||
if version is None:
|
|
||||||
url = f"{base_url}/nodes/{node_id}/install"
|
|
||||||
else:
|
|
||||||
url = f"{base_url}/nodes/{node_id}/install?version={version}"
|
|
||||||
|
|
||||||
response = requests.get(url)
|
|
||||||
if response.status_code == 200:
|
|
||||||
# Convert the API response to a NodeVersion object
|
|
||||||
return map_node_version(response.json())
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def all_versions_of_node(node_id):
|
|
||||||
url = f"https://api.comfy.org/nodes/{node_id}/versions"
|
|
||||||
|
|
||||||
response = requests.get(url)
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def read_cnr_info(fullpath):
|
|
||||||
try:
|
|
||||||
toml_path = os.path.join(fullpath, 'pyproject.toml')
|
|
||||||
tracking_path = os.path.join(fullpath, '.tracking')
|
|
||||||
|
|
||||||
if not os.path.exists(toml_path) or not os.path.exists(tracking_path):
|
|
||||||
return None # not valid CNR node pack
|
|
||||||
|
|
||||||
with open(toml_path, "r", encoding="utf-8") as f:
|
|
||||||
data = toml.load(f)
|
|
||||||
|
|
||||||
project = data.get('project', {})
|
|
||||||
name = project.get('name')
|
|
||||||
version = project.get('version')
|
|
||||||
|
|
||||||
urls = project.get('urls', {})
|
|
||||||
repository = urls.get('Repository')
|
|
||||||
|
|
||||||
if name and version: # repository is optional
|
|
||||||
return {
|
|
||||||
"id": name,
|
|
||||||
"version": version,
|
|
||||||
"url": repository
|
|
||||||
}
|
|
||||||
|
|
||||||
return None
|
|
||||||
except Exception:
|
|
||||||
return None # not valid CNR node pack
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import os
|
|
||||||
import configparser
|
|
||||||
|
|
||||||
|
|
||||||
def is_git_repo(path: str) -> bool:
|
|
||||||
""" Check if the path is a git repository. """
|
|
||||||
# NOTE: Checking it through `git.Repo` must be avoided.
|
|
||||||
# It locks the file, causing issues on Windows.
|
|
||||||
return os.path.exists(os.path.join(path, '.git'))
|
|
||||||
|
|
||||||
|
|
||||||
def get_commit_hash(fullpath):
|
|
||||||
git_head = os.path.join(fullpath, '.git', 'HEAD')
|
|
||||||
if os.path.exists(git_head):
|
|
||||||
with open(git_head) as f:
|
|
||||||
line = f.readline()
|
|
||||||
|
|
||||||
if line.startswith("ref: "):
|
|
||||||
ref = os.path.join(fullpath, '.git', line[5:].strip())
|
|
||||||
if os.path.exists(ref):
|
|
||||||
with open(ref) as f2:
|
|
||||||
return f2.readline().strip()
|
|
||||||
else:
|
|
||||||
return "unknown"
|
|
||||||
else:
|
|
||||||
return line
|
|
||||||
|
|
||||||
return "unknown"
|
|
||||||
|
|
||||||
|
|
||||||
def git_url(fullpath):
|
|
||||||
"""
|
|
||||||
resolve version of unclassified custom node based on remote url in .git/config
|
|
||||||
"""
|
|
||||||
git_config_path = os.path.join(fullpath, '.git', 'config')
|
|
||||||
|
|
||||||
if not os.path.exists(git_config_path):
|
|
||||||
return None
|
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config.read(git_config_path)
|
|
||||||
|
|
||||||
for k, v in config.items():
|
|
||||||
if k.startswith('remote ') and 'url' in v:
|
|
||||||
return v['url']
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def normalize_url(url) -> str:
|
|
||||||
url = url.replace("git@github.com:", "https://github.com/")
|
|
||||||
if url.endswith('.git'):
|
|
||||||
url = url[:-4]
|
|
||||||
|
|
||||||
return url
|
|
||||||
|
|
||||||
def normalize_url_http(url) -> str:
|
|
||||||
url = url.replace("https://github.com/", "git@github.com:")
|
|
||||||
if url.endswith('.git'):
|
|
||||||
url = url[:-4]
|
|
||||||
|
|
||||||
return url
|
|
||||||
2366
glob/manager_core.py
2366
glob/manager_core.py
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
import urllib
|
|
||||||
import sys
|
|
||||||
|
|
||||||
aria2 = os.getenv('COMFYUI_MANAGER_ARIA2_SERVER')
|
aria2 = os.getenv('COMFYUI_MANAGER_ARIA2_SERVER')
|
||||||
HF_ENDPOINT = os.getenv('HF_ENDPOINT')
|
HF_ENDPOINT = os.getenv('HF_ENDPOINT')
|
||||||
@@ -16,27 +14,6 @@ if aria2 is not None:
|
|||||||
aria2 = aria2p.API(aria2p.Client(host=host, port=port, secret=secret))
|
aria2 = aria2p.API(aria2p.Client(host=host, port=port, secret=secret))
|
||||||
|
|
||||||
|
|
||||||
def basic_download_url(url, dest_folder, filename):
|
|
||||||
import requests
|
|
||||||
|
|
||||||
# Ensure the destination folder exists
|
|
||||||
if not os.path.exists(dest_folder):
|
|
||||||
os.makedirs(dest_folder)
|
|
||||||
|
|
||||||
# Full path to save the file
|
|
||||||
dest_path = os.path.join(dest_folder, filename)
|
|
||||||
|
|
||||||
# Download the file
|
|
||||||
response = requests.get(url, stream=True)
|
|
||||||
if response.status_code == 200:
|
|
||||||
with open(dest_path, 'wb') as file:
|
|
||||||
for chunk in response.iter_content(chunk_size=1024):
|
|
||||||
if chunk:
|
|
||||||
file.write(chunk)
|
|
||||||
else:
|
|
||||||
raise Exception(f"Failed to download file from {url}")
|
|
||||||
|
|
||||||
|
|
||||||
def download_url(model_url: str, model_dir: str, filename: str):
|
def download_url(model_url: str, model_dir: str, filename: str):
|
||||||
if HF_ENDPOINT:
|
if HF_ENDPOINT:
|
||||||
model_url = model_url.replace('https://huggingface.co', HF_ENDPOINT)
|
model_url = model_url.replace('https://huggingface.co', HF_ENDPOINT)
|
||||||
@@ -44,6 +21,7 @@ def download_url(model_url: str, model_dir: str, filename: str):
|
|||||||
return aria2_download_url(model_url, model_dir, filename)
|
return aria2_download_url(model_url, model_dir, filename)
|
||||||
else:
|
else:
|
||||||
from torchvision.datasets.utils import download_url as torchvision_download_url
|
from torchvision.datasets.utils import download_url as torchvision_download_url
|
||||||
|
|
||||||
return torchvision_download_url(model_url, model_dir, filename)
|
return torchvision_download_url(model_url, model_dir, filename)
|
||||||
|
|
||||||
|
|
||||||
@@ -89,26 +67,3 @@ def aria2_download_url(model_url: str, model_dir: str, filename: str):
|
|||||||
progress_bar.update(download.completed_length - progress_bar.n)
|
progress_bar.update(download.completed_length - progress_bar.n)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
download.update()
|
download.update()
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,5 @@
|
|||||||
import aiohttp
|
|
||||||
import json
|
|
||||||
import threading
|
|
||||||
import os
|
|
||||||
from datetime import datetime
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import re
|
|
||||||
|
|
||||||
cache_lock = threading.Lock()
|
|
||||||
|
|
||||||
comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
||||||
cache_dir = os.path.join(comfyui_manager_path, '.cache')
|
|
||||||
|
|
||||||
|
|
||||||
# DON'T USE StrictVersion - cannot handle pre_release version
|
# DON'T USE StrictVersion - cannot handle pre_release version
|
||||||
# try:
|
# try:
|
||||||
@@ -78,89 +66,8 @@ class StrictVersion:
|
|||||||
return not self == other
|
return not self == other
|
||||||
|
|
||||||
|
|
||||||
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(uri, silent=False):
|
|
||||||
if not silent:
|
|
||||||
print(f"FETCH DATA from: {uri}", end="")
|
|
||||||
|
|
||||||
if uri.startswith("http"):
|
|
||||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
|
||||||
headers = {
|
|
||||||
'Cache-Control': 'no-cache',
|
|
||||||
'Pragma': 'no-cache',
|
|
||||||
'Expires': '0'
|
|
||||||
}
|
|
||||||
async with session.get(uri, headers=headers) 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)
|
|
||||||
|
|
||||||
if not silent:
|
|
||||||
print(" [DONE]")
|
|
||||||
|
|
||||||
return json_obj
|
|
||||||
|
|
||||||
|
|
||||||
async def get_data_with_cache(uri, silent=False, cache_mode=True):
|
|
||||||
cache_uri = str(simple_hash(uri)) + '_' + os.path.basename(uri).replace('&', "_").replace('?', "_").replace('=', "_")
|
|
||||||
cache_uri = os.path.join(cache_dir, cache_uri+'.json')
|
|
||||||
|
|
||||||
if cache_mode and is_file_created_within_one_day(cache_uri):
|
|
||||||
json_obj = await get_data(cache_uri, silent=silent)
|
|
||||||
else:
|
|
||||||
json_obj = await get_data(uri, silent=silent)
|
|
||||||
|
|
||||||
with cache_lock:
|
|
||||||
with open(cache_uri, "w", encoding='utf-8') as file:
|
|
||||||
json.dump(json_obj, file, indent=4, sort_keys=True)
|
|
||||||
if not silent:
|
|
||||||
print(f"[ComfyUI-Manager] default cache updated: {uri}")
|
|
||||||
|
|
||||||
return json_obj
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize_tag(x):
|
|
||||||
return x.replace('<', '<').replace('>', '>')
|
|
||||||
|
|
||||||
|
|
||||||
def extract_package_as_zip(file_path, extract_path):
|
|
||||||
import zipfile
|
|
||||||
try:
|
|
||||||
with zipfile.ZipFile(file_path, "r") as zip_ref:
|
|
||||||
zip_ref.extractall(extract_path)
|
|
||||||
extracted_files = zip_ref.namelist()
|
|
||||||
print(f"Extracted zip file to {extract_path}")
|
|
||||||
return extracted_files
|
|
||||||
except zipfile.BadZipFile:
|
|
||||||
print(f"File '{file_path}' is not a zip or is corrupted.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
pip_map = None
|
pip_map = None
|
||||||
|
|
||||||
|
|
||||||
def get_installed_packages(renew=False):
|
def get_installed_packages(renew=False):
|
||||||
global pip_map
|
global pip_map
|
||||||
|
|
||||||
@@ -305,12 +212,3 @@ class PIPFixer:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[manager-core] Failed to restore numpy")
|
print("[manager-core] Failed to restore numpy")
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
def sanitize(data):
|
|
||||||
return data.replace("<", "<").replace(">", ">")
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize_filename(input_string):
|
|
||||||
result_string = re.sub(r'[^a-zA-Z0-9_]', '_', input_string)
|
|
||||||
return result_string
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
import os
|
|
||||||
|
|
||||||
from git_utils import get_commit_hash
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class InstalledNodePackage:
|
|
||||||
"""Information about an installed node package."""
|
|
||||||
|
|
||||||
id: str
|
|
||||||
fullpath: str
|
|
||||||
disabled: bool
|
|
||||||
version: str
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_unknown(self) -> bool:
|
|
||||||
return self.version == "unknown"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_nightly(self) -> bool:
|
|
||||||
return self.version == "nightly"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_from_cnr(self) -> bool:
|
|
||||||
return not self.is_unknown and not self.is_nightly
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_enabled(self) -> bool:
|
|
||||||
return not self.disabled
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_disabled(self) -> bool:
|
|
||||||
return self.disabled
|
|
||||||
|
|
||||||
def get_commit_hash(self) -> str:
|
|
||||||
return get_commit_hash(self.fullpath)
|
|
||||||
|
|
||||||
def isValid(self) -> bool:
|
|
||||||
if self.is_from_cnr:
|
|
||||||
return os.path.exists(os.path.join(self.fullpath, '.tracking'))
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_fullpath(fullpath: str, resolve_from_path) -> InstalledNodePackage:
|
|
||||||
parent_folder_name = os.path.basename(os.path.dirname(fullpath))
|
|
||||||
module_name = os.path.basename(fullpath)
|
|
||||||
|
|
||||||
if module_name.endswith(".disabled"):
|
|
||||||
node_id = module_name[:-9]
|
|
||||||
disabled = True
|
|
||||||
elif parent_folder_name == ".disabled":
|
|
||||||
# Nodes under custom_nodes/.disabled/* are disabled
|
|
||||||
node_id = module_name
|
|
||||||
disabled = True
|
|
||||||
else:
|
|
||||||
node_id = module_name
|
|
||||||
disabled = False
|
|
||||||
|
|
||||||
info = resolve_from_path(fullpath)
|
|
||||||
if info is None:
|
|
||||||
version = 'unknown'
|
|
||||||
else:
|
|
||||||
node_id = info['id'] # robust module guessing
|
|
||||||
version = info['ver']
|
|
||||||
|
|
||||||
return InstalledNodePackage(
|
|
||||||
id=node_id, fullpath=fullpath, disabled=disabled, version=version
|
|
||||||
)
|
|
||||||
@@ -65,10 +65,10 @@ async def share_option(request):
|
|||||||
|
|
||||||
|
|
||||||
def get_openart_auth():
|
def get_openart_auth():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, ".openart_key")):
|
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".openart_key")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, ".openart_key"), "r") as f:
|
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "r") as f:
|
||||||
openart_key = f.read().strip()
|
openart_key = f.read().strip()
|
||||||
return openart_key if openart_key else None
|
return openart_key if openart_key else None
|
||||||
except:
|
except:
|
||||||
@@ -76,10 +76,10 @@ def get_openart_auth():
|
|||||||
|
|
||||||
|
|
||||||
def get_matrix_auth():
|
def get_matrix_auth():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, "matrix_auth")):
|
if not os.path.exists(os.path.join(core.comfyui_manager_path, "matrix_auth")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, "matrix_auth"), "r") as f:
|
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "r") as f:
|
||||||
matrix_auth = f.read()
|
matrix_auth = f.read()
|
||||||
homeserver, username, password = matrix_auth.strip().split("\n")
|
homeserver, username, password = matrix_auth.strip().split("\n")
|
||||||
if not homeserver or not username or not password:
|
if not homeserver or not username or not password:
|
||||||
@@ -94,10 +94,10 @@ def get_matrix_auth():
|
|||||||
|
|
||||||
|
|
||||||
def get_comfyworkflows_auth():
|
def get_comfyworkflows_auth():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, "comfyworkflows_sharekey")):
|
if not os.path.exists(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, "comfyworkflows_sharekey"), "r") as f:
|
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f:
|
||||||
share_key = f.read()
|
share_key = f.read()
|
||||||
if not share_key.strip():
|
if not share_key.strip():
|
||||||
return None
|
return None
|
||||||
@@ -107,10 +107,10 @@ def get_comfyworkflows_auth():
|
|||||||
|
|
||||||
|
|
||||||
def get_youml_settings():
|
def get_youml_settings():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, ".youml")):
|
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".youml")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, ".youml"), "r") as f:
|
with open(os.path.join(core.comfyui_manager_path, ".youml"), "r") as f:
|
||||||
youml_settings = f.read().strip()
|
youml_settings = f.read().strip()
|
||||||
return youml_settings if youml_settings else None
|
return youml_settings if youml_settings else None
|
||||||
except:
|
except:
|
||||||
@@ -118,7 +118,7 @@ def get_youml_settings():
|
|||||||
|
|
||||||
|
|
||||||
def set_youml_settings(settings):
|
def set_youml_settings(settings):
|
||||||
with open(os.path.join(core.manager_files_path, ".youml"), "w") as f:
|
with open(os.path.join(core.comfyui_manager_path, ".youml"), "w") as f:
|
||||||
f.write(settings)
|
f.write(settings)
|
||||||
|
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ async def api_get_openart_auth(request):
|
|||||||
async def api_set_openart_auth(request):
|
async def api_set_openart_auth(request):
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
openart_key = json_data['openart_key']
|
openart_key = json_data['openart_key']
|
||||||
with open(os.path.join(core.manager_files_path, ".openart_key"), "w") as f:
|
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "w") as f:
|
||||||
f.write(openart_key)
|
f.write(openart_key)
|
||||||
return web.Response(status=200)
|
return web.Response(status=200)
|
||||||
|
|
||||||
@@ -178,14 +178,14 @@ async def api_get_comfyworkflows_auth(request):
|
|||||||
@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images")
|
@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images")
|
||||||
async def set_esheep_workflow_and_images(request):
|
async def set_esheep_workflow_and_images(request):
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
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)
|
json.dump(json_data, file, indent=4)
|
||||||
return web.Response(status=200)
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images")
|
@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images")
|
||||||
async def get_esheep_workflow_and_images(request):
|
async def get_esheep_workflow_and_images(request):
|
||||||
with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
return web.Response(status=200, text=json.dumps(data))
|
return web.Response(status=200, text=json.dumps(data))
|
||||||
|
|
||||||
@@ -194,12 +194,12 @@ def set_matrix_auth(json_data):
|
|||||||
homeserver = json_data['homeserver']
|
homeserver = json_data['homeserver']
|
||||||
username = json_data['username']
|
username = json_data['username']
|
||||||
password = json_data['password']
|
password = json_data['password']
|
||||||
with open(os.path.join(core.manager_files_path, "matrix_auth"), "w") as f:
|
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "w") as f:
|
||||||
f.write("\n".join([homeserver, username, password]))
|
f.write("\n".join([homeserver, username, password]))
|
||||||
|
|
||||||
|
|
||||||
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||||
with open(os.path.join(core.manager_files_path, "comfyworkflows_sharekey"), "w") as f:
|
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f:
|
||||||
f.write(comfyworkflows_sharekey)
|
f.write(comfyworkflows_sharekey)
|
||||||
|
|
||||||
|
|
||||||
@@ -317,7 +317,7 @@ async def share_art(request):
|
|||||||
form.add_field("shareWorkflowTitle", title)
|
form.add_field("shareWorkflowTitle", title)
|
||||||
form.add_field("shareWorkflowDescription", description)
|
form.add_field("shareWorkflowDescription", description)
|
||||||
form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower())
|
form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower())
|
||||||
form.add_field("currentSnapshot", json.dumps(await core.get_current_snapshot()))
|
form.add_field("currentSnapshot", json.dumps(core.get_current_snapshot()))
|
||||||
form.add_field("modelsInfo", json.dumps(models_info))
|
form.add_field("modelsInfo", json.dumps(models_info))
|
||||||
|
|
||||||
async with session.post(
|
async with session.post(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { api } from "../../scripts/api.js";
|
import { api } from "../../scripts/api.js";
|
||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { sleep, customConfirm, customAlert } from "./common.js";
|
import { sleep, customConfirm } from "./common.js";
|
||||||
|
|
||||||
async function tryInstallCustomNode(event) {
|
async function tryInstallCustomNode(event) {
|
||||||
let msg = '-= [ComfyUI Manager] extension installation request =-\n\n';
|
let msg = '-= [ComfyUI Manager] extension installation request =-\n\n';
|
||||||
@@ -19,7 +19,7 @@ async function tryInstallCustomNode(event) {
|
|||||||
msg += `\n\nRequest message:\n${event.detail.msg}`;
|
msg += `\n\nRequest message:\n${event.detail.msg}`;
|
||||||
|
|
||||||
if(event.detail.target.installed == 'True') {
|
if(event.detail.target.installed == 'True') {
|
||||||
customAlert(msg);
|
alert(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res = await customConfirm(msg);
|
const res = await customConfirm(msg);
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import {
|
|||||||
showYouMLShareDialog
|
showYouMLShareDialog
|
||||||
} from "./comfyui-share-common.js";
|
} from "./comfyui-share-common.js";
|
||||||
import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
||||||
import {
|
import { free_models, install_pip, install_via_git_url, manager_instance, rebootAPI, setManagerInstance, show_message } from "./common.js";
|
||||||
free_models, install_pip, install_via_git_url, manager_instance,
|
|
||||||
rebootAPI, migrateAPI, setManagerInstance, show_message, customAlert, customPrompt } from "./common.js";
|
|
||||||
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
||||||
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
||||||
import { ModelManager } from "./model-manager.js";
|
import { ModelManager } from "./model-manager.js";
|
||||||
@@ -241,7 +239,6 @@ function is_legacy_front() {
|
|||||||
document.head.appendChild(docStyle);
|
document.head.appendChild(docStyle);
|
||||||
|
|
||||||
var update_comfyui_button = null;
|
var update_comfyui_button = null;
|
||||||
var switch_comfyui_button = null;
|
|
||||||
var fetch_updates_button = null;
|
var fetch_updates_button = null;
|
||||||
var update_all_button = null;
|
var update_all_button = null;
|
||||||
var badge_mode = "none";
|
var badge_mode = "none";
|
||||||
@@ -290,18 +287,6 @@ const style = `
|
|||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.cm-button-orange {
|
|
||||||
width: 310px;
|
|
||||||
height: 30px;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: 17px !important;
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: orange !important;
|
|
||||||
color: black !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-experimental-button {
|
.cm-experimental-button {
|
||||||
width: 290px;
|
width: 290px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
@@ -610,154 +595,6 @@ async function updateComfyUI() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showVersionSelectorDialog(versions, current, onSelect) {
|
|
||||||
const dialog = new ComfyDialog();
|
|
||||||
dialog.element.style.zIndex = 1100;
|
|
||||||
dialog.element.style.width = "300px";
|
|
||||||
dialog.element.style.padding = "0";
|
|
||||||
dialog.element.style.backgroundColor = "#2a2a2a";
|
|
||||||
dialog.element.style.border = "1px solid #3a3a3a";
|
|
||||||
dialog.element.style.borderRadius = "8px";
|
|
||||||
dialog.element.style.boxSizing = "border-box";
|
|
||||||
dialog.element.style.overflow = "hidden";
|
|
||||||
|
|
||||||
const contentStyle = {
|
|
||||||
width: "300px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
padding: "20px",
|
|
||||||
boxSizing: "border-box",
|
|
||||||
gap: "15px"
|
|
||||||
};
|
|
||||||
|
|
||||||
let selectedVersion = versions[0];
|
|
||||||
|
|
||||||
const versionList = $el("select", {
|
|
||||||
multiple: true,
|
|
||||||
size: Math.min(10, versions.length),
|
|
||||||
style: {
|
|
||||||
width: "260px",
|
|
||||||
height: "auto",
|
|
||||||
backgroundColor: "#383838",
|
|
||||||
color: "#ffffff",
|
|
||||||
border: "1px solid #4a4a4a",
|
|
||||||
borderRadius: "4px",
|
|
||||||
padding: "5px",
|
|
||||||
boxSizing: "border-box"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
versions.map((v, index) => $el("option", {
|
|
||||||
value: v,
|
|
||||||
textContent: v,
|
|
||||||
selected: v === current
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
versionList.addEventListener('change', (e) => {
|
|
||||||
selectedVersion = e.target.value;
|
|
||||||
Array.from(e.target.options).forEach(opt => {
|
|
||||||
opt.selected = opt.value === selectedVersion;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const content = $el("div", {
|
|
||||||
style: contentStyle
|
|
||||||
}, [
|
|
||||||
$el("h3", {
|
|
||||||
textContent: "Select Version",
|
|
||||||
style: {
|
|
||||||
color: "#ffffff",
|
|
||||||
backgroundColor: "#1a1a1a",
|
|
||||||
padding: "10px 15px",
|
|
||||||
margin: "0 0 10px 0",
|
|
||||||
width: "260px",
|
|
||||||
textAlign: "center",
|
|
||||||
borderRadius: "4px",
|
|
||||||
boxSizing: "border-box",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "ellipsis"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
versionList,
|
|
||||||
$el("div", {
|
|
||||||
style: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
width: "260px",
|
|
||||||
gap: "10px"
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
$el("button", {
|
|
||||||
textContent: "Cancel",
|
|
||||||
onclick: () => dialog.close(),
|
|
||||||
style: {
|
|
||||||
flex: "1",
|
|
||||||
padding: "8px",
|
|
||||||
backgroundColor: "#4a4a4a",
|
|
||||||
color: "#ffffff",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "4px",
|
|
||||||
cursor: "pointer",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "ellipsis"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
$el("button", {
|
|
||||||
textContent: "Select",
|
|
||||||
onclick: () => {
|
|
||||||
if (selectedVersion) {
|
|
||||||
onSelect(selectedVersion);
|
|
||||||
dialog.close();
|
|
||||||
} else {
|
|
||||||
customAlert("Please select a version.");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
flex: "1",
|
|
||||||
padding: "8px",
|
|
||||||
backgroundColor: "#4CAF50",
|
|
||||||
color: "#ffffff",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "4px",
|
|
||||||
cursor: "pointer",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "ellipsis"
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
|
|
||||||
dialog.show(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function switchComfyUI() {
|
|
||||||
let res = await api.fetchApi(`/comfyui_manager/comfyui_versions`, { cache: "no-store" });
|
|
||||||
|
|
||||||
if(res.status == 200) {
|
|
||||||
let obj = await res.json();
|
|
||||||
|
|
||||||
let versions = [];
|
|
||||||
let default_version;
|
|
||||||
|
|
||||||
for(let v of obj.versions) {
|
|
||||||
default_version = v;
|
|
||||||
versions.push(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
showVersionSelectorDialog(versions, obj.current, (selected_version) => {
|
|
||||||
api.fetchApi(`/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
show_message('Failed to fetch ComfyUI versions.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function fetchUpdates(update_check_checkbox) {
|
async function fetchUpdates(update_check_checkbox) {
|
||||||
let prev_text = fetch_updates_button.innerText;
|
let prev_text = fetch_updates_button.innerText;
|
||||||
fetch_updates_button.innerText = "Fetching updates...";
|
fetch_updates_button.innerText = "Fetching updates...";
|
||||||
@@ -908,14 +745,6 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
() => updateComfyUI()
|
() => updateComfyUI()
|
||||||
});
|
});
|
||||||
|
|
||||||
switch_comfyui_button =
|
|
||||||
$el("button.cm-button", {
|
|
||||||
type: "button",
|
|
||||||
textContent: "Switch ComfyUI",
|
|
||||||
onclick:
|
|
||||||
() => switchComfyUI()
|
|
||||||
});
|
|
||||||
|
|
||||||
fetch_updates_button =
|
fetch_updates_button =
|
||||||
$el("button.cm-button", {
|
$el("button.cm-button", {
|
||||||
type: "button",
|
type: "button",
|
||||||
@@ -974,8 +803,8 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
$el("button.cm-button", {
|
$el("button.cm-button", {
|
||||||
type: "button",
|
type: "button",
|
||||||
textContent: "Install via Git URL",
|
textContent: "Install via Git URL",
|
||||||
onclick: async () => {
|
onclick: () => {
|
||||||
var url = await customPrompt("Please enter the URL of the Git repository to install", "");
|
var url = prompt("Please enter the URL of the Git repository to install", "");
|
||||||
|
|
||||||
if (url !== null) {
|
if (url !== null) {
|
||||||
install_via_git_url(url, self);
|
install_via_git_url(url, self);
|
||||||
@@ -986,7 +815,6 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
$el("br", {}, []),
|
$el("br", {}, []),
|
||||||
update_all_button,
|
update_all_button,
|
||||||
update_comfyui_button,
|
update_comfyui_button,
|
||||||
switch_comfyui_button,
|
|
||||||
fetch_updates_button,
|
fetch_updates_button,
|
||||||
|
|
||||||
$el("br", {}, []),
|
$el("br", {}, []),
|
||||||
@@ -1010,28 +838,6 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
let migration_btn =
|
|
||||||
$el("button.cm-button-orange", {
|
|
||||||
type: "button",
|
|
||||||
textContent: "Migrate to New Node System",
|
|
||||||
onclick: () => migrateAPI()
|
|
||||||
});
|
|
||||||
|
|
||||||
migration_btn.style.display = 'none';
|
|
||||||
|
|
||||||
res.push(migration_btn);
|
|
||||||
|
|
||||||
api.fetchApi('/manager/need_to_migrate')
|
|
||||||
.then(response => response.text())
|
|
||||||
.then(text => {
|
|
||||||
if (text === 'True') {
|
|
||||||
migration_btn.style.display = 'block';
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error checking migration status:', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1242,8 +1048,8 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
type: "button",
|
type: "button",
|
||||||
textContent: "Install PIP packages",
|
textContent: "Install PIP packages",
|
||||||
onclick:
|
onclick:
|
||||||
async () => {
|
() => {
|
||||||
var url = await customPrompt("Please enumerate the pip packages to be installed.\n\nExample: insightface opencv-python-headless>=4.1.1\n", "");
|
var url = prompt("Please enumerate the pip packages to be installed.\n\nExample: insightface opencv-python-headless>=4.1.1\n", "");
|
||||||
|
|
||||||
if (url !== null) {
|
if (url !== null) {
|
||||||
install_pip(url, self);
|
install_pip(url, self);
|
||||||
@@ -1507,23 +1313,9 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVersion() {
|
|
||||||
let version = await api.fetchApi(`/manager/version`);
|
|
||||||
return await version.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
app.registerExtension({
|
app.registerExtension({
|
||||||
name: "Comfy.ManagerMenu",
|
name: "Comfy.ManagerMenu",
|
||||||
|
|
||||||
aboutPageBadges: [
|
|
||||||
{
|
|
||||||
label: `ComfyUI-Manager ${await getVersion()}`,
|
|
||||||
url: 'https://github.com/ltdrdata/ComfyUI-Manager',
|
|
||||||
icon: 'pi pi-th-large'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
$el("style", {
|
$el("style", {
|
||||||
textContent: style,
|
textContent: style,
|
||||||
@@ -1548,6 +1340,7 @@ app.registerExtension({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// new style Manager buttons
|
// new style Manager buttons
|
||||||
|
|
||||||
// unload models button into new style Manager button
|
// unload models button into new style Manager button
|
||||||
let cmGroup = new (await import("../../scripts/ui/components/buttonGroup.js")).ComfyButtonGroup(
|
let cmGroup = new (await import("../../scripts/ui/components/buttonGroup.js")).ComfyButtonGroup(
|
||||||
new(await import("../../scripts/ui/components/button.js")).ComfyButton({
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({
|
||||||
@@ -1561,19 +1354,6 @@ app.registerExtension({
|
|||||||
content: "Manager",
|
content: "Manager",
|
||||||
classList: "comfyui-button comfyui-menu-mobile-collapse primary"
|
classList: "comfyui-button comfyui-menu-mobile-collapse primary"
|
||||||
}).element,
|
}).element,
|
||||||
new(await import("../../scripts/ui/components/button.js")).ComfyButton({
|
|
||||||
icon: "star",
|
|
||||||
action: () => {
|
|
||||||
if(!manager_instance)
|
|
||||||
setManagerInstance(new ManagerMenuDialog());
|
|
||||||
|
|
||||||
if(!CustomNodesManager.instance) {
|
|
||||||
CustomNodesManager.instance = new CustomNodesManager(app, self);
|
|
||||||
}
|
|
||||||
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.FAVORITES);
|
|
||||||
},
|
|
||||||
tooltip: "Show favorite custom node list"
|
|
||||||
}).element,
|
|
||||||
new(await import("../../scripts/ui/components/button.js")).ComfyButton({
|
new(await import("../../scripts/ui/components/button.js")).ComfyButton({
|
||||||
icon: "vacuum-outline",
|
icon: "vacuum-outline",
|
||||||
action: () => {
|
action: () => {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { $el, ComfyDialog } from "../../scripts/ui.js";
|
|||||||
import { CopusShareDialog } from "./comfyui-share-copus.js";
|
import { CopusShareDialog } from "./comfyui-share-copus.js";
|
||||||
import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
||||||
import { YouMLShareDialog } from "./comfyui-share-youml.js";
|
import { YouMLShareDialog } from "./comfyui-share-youml.js";
|
||||||
import { customAlert } from "./common.js";
|
|
||||||
|
|
||||||
export const SUPPORTED_OUTPUT_NODE_TYPES = [
|
export const SUPPORTED_OUTPUT_NODE_TYPES = [
|
||||||
"PreviewImage",
|
"PreviewImage",
|
||||||
@@ -253,9 +252,9 @@ export const showShareDialog = async (share_option) => {
|
|||||||
if (potential_output_nodes.length === 0) {
|
if (potential_output_nodes.length === 0) {
|
||||||
// todo: add support for other output node types (animatediff combine, etc.)
|
// todo: add support for other output node types (animatediff combine, etc.)
|
||||||
const supported_nodes_string = SUPPORTED_OUTPUT_NODE_TYPES.join(", ");
|
const supported_nodes_string = SUPPORTED_OUTPUT_NODE_TYPES.join(", ");
|
||||||
customAlert(`No supported output node found (${supported_nodes_string}). To share this workflow, please add an output node to your graph and re-run your prompt.`);
|
alert(`No supported output node found (${supported_nodes_string}). To share this workflow, please add an output node to your graph and re-run your prompt.`);
|
||||||
} else {
|
} else {
|
||||||
customAlert("To share this, first run a prompt. Once it's done, click 'Share'.\n\nNOTE: Images of the Share target can only be selected in the PreviewImage, SaveImage, and VHS_VideoCombine nodes. In the case of VHS_VideoCombine, only the image/gif and image/webp formats are supported.");
|
alert("To share this, first run a prompt. Once it's done, click 'Share'.\n\nNOTE: Images of the Share target can only be selected in the PreviewImage, SaveImage, and VHS_VideoCombine nodes. In the case of VHS_VideoCombine, only the image/gif and image/webp formats are supported.");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -513,7 +512,7 @@ export class ShareDialogChooser extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
show() {
|
show() {
|
||||||
this.element.style.display = "block";
|
this.element.style.display = "block";
|
||||||
this.element.style.zIndex = 1099;
|
this.element.style.zIndex = 1100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class ShareDialog extends ComfyDialog {
|
export class ShareDialog extends ComfyDialog {
|
||||||
@@ -862,7 +861,7 @@ export class ShareDialog extends ComfyDialog {
|
|||||||
if (destinations.includes("matrix")) {
|
if (destinations.includes("matrix")) {
|
||||||
let definedMatrixAuth = !!this.matrix_homeserver_input.value && !!this.matrix_username_input.value && !!this.matrix_password_input.value;
|
let definedMatrixAuth = !!this.matrix_homeserver_input.value && !!this.matrix_username_input.value && !!this.matrix_password_input.value;
|
||||||
if (!definedMatrixAuth) {
|
if (!definedMatrixAuth) {
|
||||||
customAlert("Please set your Matrix account details.");
|
alert("Please set your Matrix account details.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -879,9 +878,9 @@ export class ShareDialog extends ComfyDialog {
|
|||||||
if (potential_output_nodes.length === 0) {
|
if (potential_output_nodes.length === 0) {
|
||||||
// todo: add support for other output node types (animatediff combine, etc.)
|
// todo: add support for other output node types (animatediff combine, etc.)
|
||||||
const supported_nodes_string = SUPPORTED_OUTPUT_NODE_TYPES.join(", ");
|
const supported_nodes_string = SUPPORTED_OUTPUT_NODE_TYPES.join(", ");
|
||||||
customAlert(`No supported output node found (${supported_nodes_string}). To share this workflow, please add an output node to your graph and re-run your prompt.`);
|
alert(`No supported output node found (${supported_nodes_string}). To share this workflow, please add an output node to your graph and re-run your prompt.`);
|
||||||
} else {
|
} else {
|
||||||
customAlert("To share this, first run a prompt. Once it's done, click 'Share'.\n\nNOTE: Images of the Share target can only be selected in the PreviewImage, SaveImage, and VHS_VideoCombine nodes. In the case of VHS_VideoCombine, only the image/gif and image/webp formats are supported.");
|
alert("To share this, first run a prompt. Once it's done, click 'Share'.\n\nNOTE: Images of the Share target can only be selected in the PreviewImage, SaveImage, and VHS_VideoCombine nodes. In the case of VHS_VideoCombine, only the image/gif and image/webp formats are supported.");
|
||||||
}
|
}
|
||||||
this.selectedOutputIndex = 0;
|
this.selectedOutputIndex = 0;
|
||||||
this.close();
|
this.close();
|
||||||
@@ -919,16 +918,16 @@ export class ShareDialog extends ComfyDialog {
|
|||||||
try {
|
try {
|
||||||
const response_json = await response.json();
|
const response_json = await response.json();
|
||||||
if (response_json.error) {
|
if (response_json.error) {
|
||||||
customAlert(response_json.error);
|
alert(response_json.error);
|
||||||
this.close();
|
this.close();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
customAlert("Failed to share your art. Please try again.");
|
alert("Failed to share your art. Please try again.");
|
||||||
this.close();
|
this.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
customAlert("Failed to share your art. Please try again.");
|
alert("Failed to share your art. Please try again.");
|
||||||
this.close();
|
this.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { $el, ComfyDialog } from "../../scripts/ui.js";
|
import { $el, ComfyDialog } from "../../scripts/ui.js";
|
||||||
import { customAlert } from "./common.js";
|
|
||||||
|
|
||||||
const env = "prod";
|
const env = "prod";
|
||||||
|
|
||||||
let DEFAULT_HOMEPAGE_URL = "https://copus.io";
|
let DEFAULT_HOMEPAGE_URL = "https://copus.io";
|
||||||
@@ -605,7 +603,7 @@ export class CopusShareDialog extends ComfyDialog {
|
|||||||
this.shareButton.textContent = "Sharing...";
|
this.shareButton.textContent = "Sharing...";
|
||||||
await this.share();
|
await this.share();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
customAlert(e.message);
|
alert(e.message);
|
||||||
}
|
}
|
||||||
this.shareButton.disabled = false;
|
this.shareButton.disabled = false;
|
||||||
this.shareButton.textContent = "Share";
|
this.shareButton.textContent = "Share";
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import {app} from "../../scripts/app.js";
|
import {app} from "../../scripts/app.js";
|
||||||
import {api} from "../../scripts/api.js";
|
import {api} from "../../scripts/api.js";
|
||||||
import {ComfyDialog, $el} from "../../scripts/ui.js";
|
import {ComfyDialog, $el} from "../../scripts/ui.js";
|
||||||
import { customAlert } from "./common.js";
|
|
||||||
|
|
||||||
const LOCAL_STORAGE_KEY = "openart_comfy_workflow_key";
|
const LOCAL_STORAGE_KEY = "openart_comfy_workflow_key";
|
||||||
const DEFAULT_HOMEPAGE_URL = "https://openart.ai/workflows/dev?developer=true";
|
const DEFAULT_HOMEPAGE_URL = "https://openart.ai/workflows/dev?developer=true";
|
||||||
@@ -432,7 +431,7 @@ export class OpenArtShareDialog extends ComfyDialog {
|
|||||||
this.shareButton.textContent = "Sharing...";
|
this.shareButton.textContent = "Sharing...";
|
||||||
await this.share();
|
await this.share();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
customAlert(e.message);
|
alert(e.message);
|
||||||
}
|
}
|
||||||
this.shareButton.disabled = false;
|
this.shareButton.disabled = false;
|
||||||
this.shareButton.textContent = "Share";
|
this.shareButton.textContent = "Share";
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import {app} from "../../scripts/app.js";
|
import {app} from "../../scripts/app.js";
|
||||||
import {api} from "../../scripts/api.js";
|
import {api} from "../../scripts/api.js";
|
||||||
import {ComfyDialog, $el} from "../../scripts/ui.js";
|
import {ComfyDialog, $el} from "../../scripts/ui.js";
|
||||||
import { customAlert } from "./common.js";
|
|
||||||
|
|
||||||
const BASE_URL = "https://youml.com";
|
const BASE_URL = "https://youml.com";
|
||||||
//const BASE_URL = "http://localhost:3000";
|
//const BASE_URL = "http://localhost:3000";
|
||||||
@@ -348,7 +347,7 @@ export class YouMLShareDialog extends ComfyDialog {
|
|||||||
this.shareButton.textContent = "Sharing...";
|
this.shareButton.textContent = "Sharing...";
|
||||||
await this.share();
|
await this.share();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
customAlert(e.message);
|
alert(e.message);
|
||||||
} finally {
|
} finally {
|
||||||
this.shareButton.disabled = false;
|
this.shareButton.disabled = false;
|
||||||
this.shareButton.textContent = "Share";
|
this.shareButton.textContent = "Share";
|
||||||
|
|||||||
50
js/common.js
50
js/common.js
@@ -16,7 +16,7 @@ function internalCustomConfirm(message, confirmMessage, cancelMessage) {
|
|||||||
modalOverlay.style.display = 'flex';
|
modalOverlay.style.display = 'flex';
|
||||||
modalOverlay.style.alignItems = 'center';
|
modalOverlay.style.alignItems = 'center';
|
||||||
modalOverlay.style.justifyContent = 'center';
|
modalOverlay.style.justifyContent = 'center';
|
||||||
modalOverlay.style.zIndex = '1100';
|
modalOverlay.style.zIndex = '1101';
|
||||||
|
|
||||||
// Modal window container (dark bg)
|
// Modal window container (dark bg)
|
||||||
const modalDialog = document.createElement('div');
|
const modalDialog = document.createElement('div');
|
||||||
@@ -96,7 +96,7 @@ function internalCustomConfirm(message, confirmMessage, cancelMessage) {
|
|||||||
|
|
||||||
export function show_message(msg) {
|
export function show_message(msg) {
|
||||||
app.ui.dialog.show(msg);
|
app.ui.dialog.show(msg);
|
||||||
app.ui.dialog.element.style.zIndex = 1099;
|
app.ui.dialog.element.style.zIndex = 1100;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sleep(ms) {
|
export async function sleep(ms) {
|
||||||
@@ -120,34 +120,6 @@ export async function customConfirm(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function customAlert(message) {
|
|
||||||
try {
|
|
||||||
window['app'].extensionManager.toast.addAlert(message);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
alert(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export async function customPrompt(title, message) {
|
|
||||||
try {
|
|
||||||
let res = await
|
|
||||||
window['app'].extensionManager.dialog
|
|
||||||
.prompt({
|
|
||||||
title: title,
|
|
||||||
message: message
|
|
||||||
});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
return prompt(title, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function rebootAPI() {
|
export function rebootAPI() {
|
||||||
if ('electronAPI' in window) {
|
if ('electronAPI' in window) {
|
||||||
window.electronAPI.restartApp();
|
window.electronAPI.restartApp();
|
||||||
@@ -166,24 +138,6 @@ export function rebootAPI() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function migrateAPI() {
|
|
||||||
let confirmed = await customConfirm("When performing a migration, existing installed custom nodes will be renamed and the server will be restarted. Are you sure you want to apply this?\n\n(If you don't perform the migration, ComfyUI-Manager's start-up time will be longer each time due to re-checking during startup.)")
|
|
||||||
if (confirmed) {
|
|
||||||
try {
|
|
||||||
await api.fetchApi("/manager/migrate_unmanaged_nodes");
|
|
||||||
api.fetchApi("/manager/reboot");
|
|
||||||
}
|
|
||||||
catch(exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export var manager_instance = null;
|
export var manager_instance = null;
|
||||||
|
|
||||||
export function setManagerInstance(obj) {
|
export function setManagerInstance(obj) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
import { api } from "../../scripts/api.js"
|
import { api } from "../../scripts/api.js"
|
||||||
import { sleep, show_message, customConfirm, customAlert } from "./common.js";
|
import { sleep, show_message, customConfirm } from "./common.js";
|
||||||
import { GroupNodeConfig, GroupNodeHandler } from "../../extensions/core/groupNode.js";
|
import { GroupNodeConfig, GroupNodeHandler } from "../../extensions/core/groupNode.js";
|
||||||
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
||||||
|
|
||||||
@@ -456,7 +456,7 @@ export class ComponentBuilderDialog extends ComfyDialog {
|
|||||||
this.invalidateControl();
|
this.invalidateControl();
|
||||||
|
|
||||||
this.element.style.display = "block";
|
this.element.style.display = "block";
|
||||||
this.element.style.zIndex = 1099;
|
this.element.style.zIndex = 1100;
|
||||||
this.element.style.width = "500px";
|
this.element.style.width = "500px";
|
||||||
this.element.style.height = "480px";
|
this.element.style.height = "480px";
|
||||||
}
|
}
|
||||||
@@ -622,7 +622,7 @@ export class ComponentBuilderDialog extends ComfyDialog {
|
|||||||
self.version_string.value = self.default_ver;
|
self.version_string.value = self.default_ver;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
customAlert('If you are not the author, it is not recommended to change the version, as it may cause component update issues.');
|
alert('If you are not the author, it is not recommended to change the version, as it may cause component update issues.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ import TG from "./turbogrid.esm.js";
|
|||||||
const pageCss = `
|
const pageCss = `
|
||||||
.cmm-manager {
|
.cmm-manager {
|
||||||
--grid-font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
--grid-font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||||
z-index: 1099;
|
z-index: 1100;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -235,7 +235,7 @@ const pageHtml = `
|
|||||||
<div class="cmm-manager-selection"></div>
|
<div class="cmm-manager-selection"></div>
|
||||||
<div class="cmm-manager-message"></div>
|
<div class="cmm-manager-message"></div>
|
||||||
<div class="cmm-manager-footer">
|
<div class="cmm-manager-footer">
|
||||||
<button class="cmm-manager-back">Back</button>
|
<button class="cmm-manager-close">Close</button>
|
||||||
<div class="cmm-flex-auto"></div>
|
<div class="cmm-flex-auto"></div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -365,12 +365,10 @@ export class ModelManager {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
".cmm-manager-back": {
|
".cmm-manager-close": {
|
||||||
click: (e) => {
|
click: (e) => this.close()
|
||||||
this.close()
|
|
||||||
manager_instance.show();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
Object.keys(eventsMap).forEach(selector => {
|
Object.keys(eventsMap).forEach(selector => {
|
||||||
const target = this.element.querySelector(selector);
|
const target = this.element.querySelector(selector);
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ export class SnapshotManager extends ComfyDialog {
|
|||||||
try {
|
try {
|
||||||
this.invalidateControl();
|
this.invalidateControl();
|
||||||
this.element.style.display = "block";
|
this.element.style.display = "block";
|
||||||
this.element.style.zIndex = 1099;
|
this.element.style.zIndex = 1100;
|
||||||
}
|
}
|
||||||
catch(exception) {
|
catch(exception) {
|
||||||
app.ui.dialog.show(`Failed to get external model list. / ${exception}`);
|
app.ui.dialog.show(`Failed to get external model list. / ${exception}`);
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
/**
|
|
||||||
* Attaches metadata to the workflow on save
|
|
||||||
* - custom node pack version to all custom nodes used in the workflow
|
|
||||||
*
|
|
||||||
* Example metadata:
|
|
||||||
"extra": {
|
|
||||||
"node_versions": {
|
|
||||||
"comfy-core": "v0.3.8-4-g0b2eb7f",
|
|
||||||
"comfyui-easy-use": "1.2.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { app } from "../../scripts/app.js";
|
|
||||||
import { api } from "../../scripts/api.js";
|
|
||||||
|
|
||||||
class WorkflowMetadataExtension {
|
|
||||||
constructor() {
|
|
||||||
this.name = "Comfy.CustomNodesManager.WorkflowMetadata";
|
|
||||||
this.installedNodeVersions = {};
|
|
||||||
this.comfyCoreVersion = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the installed node versions
|
|
||||||
* @returns {Promise<Record<string, string>>} The mapping from node name to version
|
|
||||||
* version can either be a git commit hash or a semantic version such as "1.0.0"
|
|
||||||
*/
|
|
||||||
async getInstalledNodeVersions() {
|
|
||||||
const res = await api.fetchApi("/customnode/installed");
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the node versions for the given graph
|
|
||||||
* @param {LGraph} graph The graph to get the node versions for
|
|
||||||
* @returns {Promise<Record<string, string>>} The mapping from node name to version
|
|
||||||
*/
|
|
||||||
getGraphNodeVersions(graph) {
|
|
||||||
const nodeVersions = {};
|
|
||||||
for (const node of graph.nodes) {
|
|
||||||
const nodeData = node.constructor.nodeData;
|
|
||||||
// Frontend only nodes don't have nodeData
|
|
||||||
if (!nodeData) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const modules = nodeData.python_module.split(".");
|
|
||||||
|
|
||||||
if (modules[0] === "custom_nodes") {
|
|
||||||
const nodePackageName = modules[1];
|
|
||||||
const nodeVersion = this.installedNodeVersions[nodePackageName];
|
|
||||||
nodeVersions[nodePackageName] = nodeVersion;
|
|
||||||
} else if (["nodes", "comfy_extras"].includes(modules[0])) {
|
|
||||||
nodeVersions["comfy-core"] = this.comfyCoreVersion;
|
|
||||||
} else {
|
|
||||||
console.warn(`Unknown node source: ${nodeData.python_module}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodeVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
const extension = this;
|
|
||||||
this.installedNodeVersions = await this.getInstalledNodeVersions();
|
|
||||||
this.comfyCoreVersion = (await api.getSystemStats()).system.comfyui_version;
|
|
||||||
|
|
||||||
// Attach metadata when app.graphToPrompt is called.
|
|
||||||
const originalSerialize = LGraph.prototype.serialize;
|
|
||||||
LGraph.prototype.serialize = function () {
|
|
||||||
const workflow = originalSerialize.apply(this, arguments);
|
|
||||||
|
|
||||||
// Add metadata to the workflow
|
|
||||||
if (!workflow.extra) {
|
|
||||||
workflow.extra = {};
|
|
||||||
}
|
|
||||||
const graph = this;
|
|
||||||
workflow.extra["node_versions"] = extension.getGraphNodeVersions(graph);
|
|
||||||
|
|
||||||
return workflow;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.registerExtension(new WorkflowMetadataExtension());
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -14,11 +15,8 @@ glob_path = os.path.join(os.path.dirname(__file__), "glob")
|
|||||||
sys.path.append(glob_path)
|
sys.path.append(glob_path)
|
||||||
|
|
||||||
import security_check
|
import security_check
|
||||||
import manager_util
|
from manager_util import PIPFixer, StrictVersion, get_installed_packages, clear_pip_cache
|
||||||
import cm_global
|
import cm_global
|
||||||
import manager_downloader
|
|
||||||
from datetime import datetime
|
|
||||||
import folder_paths
|
|
||||||
|
|
||||||
security_check.security_check()
|
security_check.security_check()
|
||||||
|
|
||||||
@@ -73,20 +71,17 @@ cm_global.register_api('cm.register_message_collapse', register_message_collapse
|
|||||||
cm_global.register_api('cm.is_import_failed_extension', is_import_failed_extension)
|
cm_global.register_api('cm.is_import_failed_extension', is_import_failed_extension)
|
||||||
|
|
||||||
|
|
||||||
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
comfyui_manager_path = os.path.dirname(__file__)
|
||||||
|
custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, ".."))
|
||||||
custom_nodes_base_path = folder_paths.get_folder_paths('custom_nodes')[0]
|
startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts")
|
||||||
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))
|
restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json")
|
||||||
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
|
||||||
restore_snapshot_path = os.path.join(manager_files_path, "startup-scripts", "restore-snapshot.json")
|
|
||||||
|
|
||||||
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
|
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
|
||||||
cm_cli_path = os.path.join(comfyui_manager_path, "cm-cli.py")
|
pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json")
|
||||||
|
|
||||||
|
|
||||||
cm_global.pip_overrides = {}
|
cm_global.pip_overrides = {}
|
||||||
if os.path.exists(manager_pip_overrides_path):
|
if os.path.exists(pip_overrides_path):
|
||||||
with open(manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
||||||
cm_global.pip_overrides = json.load(json_file)
|
cm_global.pip_overrides = json.load(json_file)
|
||||||
cm_global.pip_overrides['numpy'] = 'numpy<2'
|
cm_global.pip_overrides['numpy'] = 'numpy<2'
|
||||||
cm_global.pip_overrides['ultralytics'] = 'ultralytics==8.3.40' # for security
|
cm_global.pip_overrides['ultralytics'] = 'ultralytics==8.3.40' # for security
|
||||||
@@ -149,18 +144,15 @@ try:
|
|||||||
postfix = ""
|
postfix = ""
|
||||||
|
|
||||||
# Logger setup
|
# Logger setup
|
||||||
log_path_base = None
|
|
||||||
if enable_file_logging:
|
if enable_file_logging:
|
||||||
log_path_base = os.path.join(folder_paths.user_directory, 'comfyui')
|
if os.path.exists(f"comfyui{postfix}.log"):
|
||||||
|
if os.path.exists(f"comfyui{postfix}.prev.log"):
|
||||||
|
if os.path.exists(f"comfyui{postfix}.prev2.log"):
|
||||||
|
os.remove(f"comfyui{postfix}.prev2.log")
|
||||||
|
os.rename(f"comfyui{postfix}.prev.log", f"comfyui{postfix}.prev2.log")
|
||||||
|
os.rename(f"comfyui{postfix}.log", f"comfyui{postfix}.prev.log")
|
||||||
|
|
||||||
if os.path.exists(f"{log_path_base}{postfix}.log"):
|
log_file = open(f"comfyui{postfix}.log", "w", encoding="utf-8", errors="ignore")
|
||||||
if os.path.exists(f"{log_path_base}{postfix}.prev.log"):
|
|
||||||
if os.path.exists(f"{log_path_base}{postfix}.prev2.log"):
|
|
||||||
os.remove(f"{log_path_base}{postfix}.prev2.log")
|
|
||||||
os.rename(f"{log_path_base}{postfix}.prev.log", f"{log_path_base}{postfix}.prev2.log")
|
|
||||||
os.rename(f"{log_path_base}{postfix}.log", f"{log_path_base}{postfix}.prev.log")
|
|
||||||
|
|
||||||
log_file = open(f"{log_path_base}{postfix}.log", "w", encoding="utf-8", errors="ignore")
|
|
||||||
|
|
||||||
log_lock = threading.Lock()
|
log_lock = threading.Lock()
|
||||||
|
|
||||||
@@ -181,7 +173,7 @@ try:
|
|||||||
write_stderr = wrapper_stderr
|
write_stderr = wrapper_stderr
|
||||||
|
|
||||||
pat_tqdm = r'\d+%.*\[(.*?)\]'
|
pat_tqdm = r'\d+%.*\[(.*?)\]'
|
||||||
pat_import_fail = r'seconds \(IMPORT FAILED\):(.*)$'
|
pat_import_fail = r'seconds \(IMPORT FAILED\):.*[/\\]custom_nodes[/\\](.*)$'
|
||||||
|
|
||||||
is_start_mode = True
|
is_start_mode = True
|
||||||
|
|
||||||
@@ -214,7 +206,7 @@ try:
|
|||||||
if is_start_mode:
|
if is_start_mode:
|
||||||
match = re.search(pat_import_fail, message)
|
match = re.search(pat_import_fail, message)
|
||||||
if match:
|
if match:
|
||||||
import_failed_extensions.add(match.group(1).strip())
|
import_failed_extensions.add(match.group(1))
|
||||||
|
|
||||||
if 'Starting server' in message:
|
if 'Starting server' in message:
|
||||||
is_start_mode = False
|
is_start_mode = False
|
||||||
@@ -236,7 +228,7 @@ try:
|
|||||||
|
|
||||||
def sync_write(self, message, file_only=False):
|
def sync_write(self, message, file_only=False):
|
||||||
with log_lock:
|
with log_lock:
|
||||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
|
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
|
||||||
if self.last_char != '\n':
|
if self.last_char != '\n':
|
||||||
log_file.write(message)
|
log_file.write(message)
|
||||||
else:
|
else:
|
||||||
@@ -300,7 +292,7 @@ try:
|
|||||||
if is_start_mode:
|
if is_start_mode:
|
||||||
match = re.search(pat_import_fail, message)
|
match = re.search(pat_import_fail, message)
|
||||||
if match:
|
if match:
|
||||||
import_failed_extensions.add(match.group(1).strip())
|
import_failed_extensions.add(match.group(1))
|
||||||
|
|
||||||
if 'Starting server' in message:
|
if 'Starting server' in message:
|
||||||
is_start_mode = False
|
is_start_mode = False
|
||||||
@@ -339,14 +331,14 @@ except:
|
|||||||
print("## [ERROR] ComfyUI-Manager: GitPython package seems to be installed, but failed to load somehow. Make sure you have a working git client installed")
|
print("## [ERROR] ComfyUI-Manager: GitPython package seems to be installed, but failed to load somehow. Make sure you have a working git client installed")
|
||||||
|
|
||||||
|
|
||||||
print("** ComfyUI startup time:", datetime.now())
|
print("** ComfyUI startup time:", datetime.datetime.now())
|
||||||
print("** Platform:", platform.system())
|
print("** Platform:", platform.system())
|
||||||
print("** Python version:", sys.version)
|
print("** Python version:", sys.version)
|
||||||
print("** Python executable:", sys.executable)
|
print("** Python executable:", sys.executable)
|
||||||
print("** ComfyUI Path:", comfy_path)
|
print("** ComfyUI Path:", comfy_path)
|
||||||
|
|
||||||
if log_path_base is not None:
|
if enable_file_logging:
|
||||||
print("** Log path:", os.path.abspath(f'{log_path_base}.log'))
|
print("** Log path:", os.path.abspath('comfyui.log'))
|
||||||
else:
|
else:
|
||||||
print("** Log path: file logging is disabled")
|
print("** Log path: file logging is disabled")
|
||||||
|
|
||||||
@@ -392,8 +384,8 @@ check_bypass_ssl()
|
|||||||
|
|
||||||
# Perform install
|
# Perform install
|
||||||
processed_install = set()
|
processed_install = set()
|
||||||
script_list_path = os.path.join(folder_paths.user_directory, "default", "ComfyUI-Manager", "startup-scripts", "install-scripts.txt")
|
script_list_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "startup-scripts", "install-scripts.txt")
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages())
|
pip_fixer = PIPFixer(get_installed_packages())
|
||||||
|
|
||||||
|
|
||||||
def is_installed(name):
|
def is_installed(name):
|
||||||
@@ -412,18 +404,18 @@ def is_installed(name):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if name in cm_global.pip_downgrade_blacklist:
|
if name in cm_global.pip_downgrade_blacklist:
|
||||||
pips = manager_util.get_installed_packages()
|
pips = get_installed_packages()
|
||||||
|
|
||||||
if match is None:
|
if match is None:
|
||||||
if name in pips:
|
if name in pips:
|
||||||
return True
|
return True
|
||||||
elif match.group(2) in ['<=', '==', '<']:
|
elif match.group(2) in ['<=', '==', '<']:
|
||||||
if name in pips:
|
if name in pips:
|
||||||
if manager_util.StrictVersion(pips[name]) >= manager_util.StrictVersion(match.group(3)):
|
if StrictVersion(pips[name]) >= StrictVersion(match.group(3)):
|
||||||
print(f"[ComfyUI-Manager] skip black listed pip installation: '{name}'")
|
print(f"[ComfyUI-Manager] skip black listed pip installation: '{name}'")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
pkg = manager_util.get_installed_packages().get(name.lower())
|
pkg = get_installed_packages().get(name.lower())
|
||||||
if pkg is None:
|
if pkg is None:
|
||||||
return False # update if not installed
|
return False # update if not installed
|
||||||
|
|
||||||
@@ -431,9 +423,9 @@ def is_installed(name):
|
|||||||
return True # don't update if version is not specified
|
return True # don't update if version is not specified
|
||||||
|
|
||||||
if match.group(2) in ['>', '>=']:
|
if match.group(2) in ['>', '>=']:
|
||||||
if manager_util.StrictVersion(pkg) < manager_util.StrictVersion(match.group(3)):
|
if StrictVersion(pkg) < StrictVersion(match.group(3)):
|
||||||
return False
|
return False
|
||||||
elif manager_util.StrictVersion(pkg) > manager_util.StrictVersion(match.group(3)):
|
elif StrictVersion(pkg) > StrictVersion(match.group(3)):
|
||||||
print(f"[SKIP] Downgrading pip package isn't allowed: {name.lower()} (cur={pkg})")
|
print(f"[SKIP] Downgrading pip package isn't allowed: {name.lower()} (cur={pkg})")
|
||||||
|
|
||||||
return True # prevent downgrade
|
return True # prevent downgrade
|
||||||
@@ -465,11 +457,53 @@ if os.path.exists(restore_snapshot_path):
|
|||||||
print(prefix, msg, end="")
|
print(prefix, msg, end="")
|
||||||
|
|
||||||
print("[ComfyUI-Manager] Restore snapshot.")
|
print("[ComfyUI-Manager] Restore snapshot.")
|
||||||
|
cmd_str = [sys.executable, git_script_path, '--apply-snapshot', restore_snapshot_path]
|
||||||
|
|
||||||
new_env = os.environ.copy()
|
new_env = os.environ.copy()
|
||||||
new_env["COMFYUI_PATH"] = comfy_path
|
new_env["COMFYUI_PATH"] = comfy_path
|
||||||
|
exit_code = process_wrap(cmd_str, custom_nodes_path, handler=msg_capture, env=new_env)
|
||||||
|
|
||||||
cmd_str = [sys.executable, cm_cli_path, 'restore-snapshot', restore_snapshot_path]
|
repository_name = ''
|
||||||
exit_code = process_wrap(cmd_str, custom_nodes_base_path, handler=msg_capture, env=new_env)
|
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')
|
||||||
|
|
||||||
|
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 = remap_pip_package(line.strip())
|
||||||
|
if package_name and not is_installed(package_name):
|
||||||
|
if not package_name.startswith('#'):
|
||||||
|
if '--index-url' in package_name:
|
||||||
|
s = package_name.split('--index-url')
|
||||||
|
install_cmd = [sys.executable, "-m", "pip", "install", s[0].strip(), '--index-url', s[1].strip()]
|
||||||
|
else:
|
||||||
|
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}")
|
||||||
|
|
||||||
|
new_env = os.environ.copy()
|
||||||
|
new_env["COMFYUI_PATH"] = comfy_path
|
||||||
|
this_exit_code += process_wrap(install_cmd, repo_path, env=new_env)
|
||||||
|
|
||||||
|
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:
|
if exit_code != 0:
|
||||||
print("[ComfyUI-Manager] Restore snapshot failed.")
|
print("[ComfyUI-Manager] Restore snapshot failed.")
|
||||||
@@ -513,65 +547,6 @@ def execute_lazy_install_script(repo_path, executable):
|
|||||||
process_wrap(install_cmd, repo_path, env=new_env)
|
process_wrap(install_cmd, repo_path, env=new_env)
|
||||||
|
|
||||||
|
|
||||||
def execute_lazy_cnr_switch(target, zip_url, from_path, to_path, no_deps, custom_nodes_path):
|
|
||||||
import uuid
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
# 1. download
|
|
||||||
archive_name = f"CNR_temp_{str(uuid.uuid4())}.zip" # should be unpredictable name - security precaution
|
|
||||||
download_path = os.path.join(custom_nodes_path, archive_name)
|
|
||||||
manager_downloader.download_url(zip_url, custom_nodes_path, archive_name)
|
|
||||||
|
|
||||||
# 2. extract files into <node_id>@<cur_ver>
|
|
||||||
extracted = manager_util.extract_package_as_zip(download_path, from_path)
|
|
||||||
os.remove(download_path)
|
|
||||||
|
|
||||||
if extracted is None:
|
|
||||||
if len(os.listdir(from_path)) == 0:
|
|
||||||
shutil.rmtree(from_path)
|
|
||||||
|
|
||||||
print(f'Empty archive file: {target}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# 3. calculate garbage files (.tracking - extracted)
|
|
||||||
tracking_info_file = os.path.join(from_path, '.tracking')
|
|
||||||
prev_files = set()
|
|
||||||
with open(tracking_info_file, 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
prev_files.add(line.strip())
|
|
||||||
garbage = prev_files.difference(extracted)
|
|
||||||
garbage = [os.path.join(custom_nodes_path, x) for x in garbage]
|
|
||||||
|
|
||||||
# 4-1. remove garbage files
|
|
||||||
for x in garbage:
|
|
||||||
if os.path.isfile(x):
|
|
||||||
os.remove(x)
|
|
||||||
|
|
||||||
# 4-2. remove garbage dir if empty
|
|
||||||
for x in garbage:
|
|
||||||
if os.path.isdir(x):
|
|
||||||
if not os.listdir(x):
|
|
||||||
os.rmdir(x)
|
|
||||||
|
|
||||||
# 5. rename dir name <node_id>@<prev_ver> ==> <node_id>@<cur_ver>
|
|
||||||
print(f"'{from_path}' is moved to '{to_path}'")
|
|
||||||
shutil.move(from_path, to_path)
|
|
||||||
|
|
||||||
# 6. create .tracking file
|
|
||||||
tracking_info_file = os.path.join(to_path, '.tracking')
|
|
||||||
with open(tracking_info_file, "w", encoding='utf-8') as file:
|
|
||||||
file.write('\n'.join(list(extracted)))
|
|
||||||
|
|
||||||
|
|
||||||
def execute_migration(moves):
|
|
||||||
import shutil
|
|
||||||
for x in moves:
|
|
||||||
if os.path.exists(x[0]) and not os.path.exists(x[1]):
|
|
||||||
shutil.move(x[0], x[1])
|
|
||||||
print(f"[ComfyUI-Manager] MIGRATION: '{x[0]}' -> '{x[1]}'")
|
|
||||||
|
|
||||||
|
|
||||||
# Check if script_list_path exists
|
# Check if script_list_path exists
|
||||||
if os.path.exists(script_list_path):
|
if os.path.exists(script_list_path):
|
||||||
print("\n#######################################################################")
|
print("\n#######################################################################")
|
||||||
@@ -593,13 +568,6 @@ if os.path.exists(script_list_path):
|
|||||||
if script[1] == "#LAZY-INSTALL-SCRIPT":
|
if script[1] == "#LAZY-INSTALL-SCRIPT":
|
||||||
execute_lazy_install_script(script[0], script[2])
|
execute_lazy_install_script(script[0], script[2])
|
||||||
|
|
||||||
elif script[1] == "#LAZY-CNR-SWITCH-SCRIPT":
|
|
||||||
execute_lazy_cnr_switch(script[0], script[2], script[3], script[4], script[5], script[6])
|
|
||||||
execute_lazy_install_script(script[3], script[7])
|
|
||||||
|
|
||||||
elif script[1] == "#LAZY-MIGRATION":
|
|
||||||
execute_migration(script[2])
|
|
||||||
|
|
||||||
elif os.path.exists(script[0]):
|
elif os.path.exists(script[0]):
|
||||||
if script[1] == "#FORCE":
|
if script[1] == "#FORCE":
|
||||||
del script[1]
|
del script[1]
|
||||||
@@ -633,7 +601,7 @@ pip_fixer.fix_broken()
|
|||||||
|
|
||||||
del processed_install
|
del processed_install
|
||||||
del pip_fixer
|
del pip_fixer
|
||||||
manager_util.clear_pip_cache()
|
clear_pip_cache()
|
||||||
|
|
||||||
|
|
||||||
def check_windows_event_loop_policy():
|
def check_windows_event_loop_policy():
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-manager"
|
name = "comfyui-manager"
|
||||||
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
|
||||||
version = "3.3"
|
version = "2.56.2"
|
||||||
license = { file = "LICENSE.txt" }
|
license = { file = "LICENSE.txt" }
|
||||||
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,3 @@ huggingface-hub>0.20
|
|||||||
typer
|
typer
|
||||||
rich
|
rich
|
||||||
typing-extensions
|
typing-extensions
|
||||||
toml
|
|
||||||
Reference in New Issue
Block a user