Add files via upload
Initial release v1.0
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"id":"c500f3f0-4711-4aa1-8a72-d7aded65e375","revision":0,"last_node_id":2,"last_link_id":1,"nodes":[{"id":2,"type":"ShowText|pysssss","pos":[1184.7082734890591,382.55434679367886],"size":[310.7533638412674,125.03695102793529],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"text","name":"text","type":"STRING","link":1}],"outputs":[{"localized_name":"STRING","name":"STRING","shape":6,"type":"STRING","links":null}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}},"cnr_id":"comfyui-custom-scripts","ver":"1.2.5","Node name for S&R":"ShowText|pysssss"}},{"id":1,"type":"WorkflowBackup","pos":[811.6121734958897,382.5543467936786],"size":[313.91953125,130],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"workflows_path","name":"workflows_path","type":"STRING","widget":{"name":"workflows_path"},"link":null},{"localized_name":"backup_destination","name":"backup_destination","type":"STRING","widget":{"name":"backup_destination"},"link":null},{"localized_name":"mode","name":"mode","type":"COMBO","widget":{"name":"mode"},"link":null},{"localized_name":"language","name":"language","type":"COMBO","widget":{"name":"language"},"link":null}],"outputs":[{"localized_name":"status_report","name":"status_report","type":"STRING","links":[1]}],"properties":{"ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{}},"Node name for S&R":"WorkflowBackup"},"widgets_values":["Paste your path here","D:/ComfyUI_Backup","ANALYSIS_ONLY","English"]}],"links":[[1,1,0,2,0,"STRING"]],"groups":[],"config":{},"extra":{"workflowRendererVersion":"LG","ue_links":[],"ds":{"scale":1.4641000000000006,"offset":[-318.1349519946265,-112.59061053932456]}},"version":0.4}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
from .nodes import WorkflowBackupNode
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"WorkflowBackup": WorkflowBackupNode
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"WorkflowBackup": "📦 ComfyUI Backup & Packager"
|
||||
}
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
@@ -0,0 +1,192 @@
|
||||
import os
|
||||
import json
|
||||
import shutil
|
||||
import folder_paths
|
||||
from pathlib import Path
|
||||
from comfy.utils import ProgressBar # <--- NUEVO: Importamos la barra de progreso
|
||||
|
||||
class WorkflowBackupNode:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"workflows_path": ("STRING", {"default": "Paste your path here", "multiline": False}),
|
||||
"backup_destination": ("STRING", {"default": "D:/ComfyUI_Backup", "multiline": False}),
|
||||
"mode": (["ANALYSIS_ONLY", "EXECUTE_BACKUP"],),
|
||||
"language": (["English", "Spanish"],),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("status_report",)
|
||||
FUNCTION = "process_backup"
|
||||
OUTPUT_NODE = True
|
||||
CATEGORY = "utils/backup"
|
||||
|
||||
def process_backup(self, workflows_path, backup_destination, mode, language):
|
||||
# 1. Path Cleaning
|
||||
w_path = Path(workflows_path.strip('"').strip("'"))
|
||||
dest_path = Path(backup_destination.strip('"').strip("'"))
|
||||
|
||||
# 2. Setup Messages
|
||||
msgs = {
|
||||
"English": {
|
||||
"err_path": "❌ ERROR: The workflows folder does not exist: ",
|
||||
"err_no_json": "⚠️ No .json files found in ",
|
||||
"analyzing": "🔍 Analyzing {count} workflows in: {path}",
|
||||
"err_read": "⚠️ Error reading {file}: {error}",
|
||||
"found": "✅ Found {count} unique models required.",
|
||||
"size": "📦 Estimated Total Size: {size:.2f} GB",
|
||||
"err_dest": "❌ Error creating destination folder: {path}",
|
||||
"copying": "Copying: {name}...",
|
||||
"err_copy": "Error copying {src}: {error}",
|
||||
"done": "🎉 BACKUP COMPLETED: {count} new models copied.",
|
||||
"location": "📁 Location: {path}",
|
||||
"analysis_mode": "ℹ️ ANALYSIS MODE: No files were copied. Switch mode to EXECUTE_BACKUP to perform the copy."
|
||||
},
|
||||
"Spanish": {
|
||||
"err_path": "❌ ERROR: La carpeta de workflows no existe: ",
|
||||
"err_no_json": "⚠️ No se encontraron archivos .json en ",
|
||||
"analyzing": "🔍 Analizando {count} workflows en: {path}",
|
||||
"err_read": "⚠️ Error leyendo {file}: {error}",
|
||||
"found": "✅ Se encontraron {count} modelos únicos necesarios.",
|
||||
"size": "📦 Tamaño total estimado: {size:.2f} GB",
|
||||
"err_dest": "❌ Error creando carpeta destino: {path}",
|
||||
"copying": "Copiando: {name}...",
|
||||
"err_copy": "Error copiando {src}: {error}",
|
||||
"done": "🎉 RESPALDO COMPLETADO: {count} modelos nuevos copiados.",
|
||||
"location": "📁 Ubicación: {path}",
|
||||
"analysis_mode": "ℹ️ MODO ANÁLISIS: No se copiaron archivos. Cambia el modo a EXECUTE_BACKUP para copiar."
|
||||
}
|
||||
}
|
||||
|
||||
T = msgs[language]
|
||||
|
||||
# 3. ComfyUI Root Detection
|
||||
comfy_root = Path(folder_paths.base_path)
|
||||
models_root = comfy_root / "models"
|
||||
|
||||
if not w_path.exists():
|
||||
return (f"{T['err_path']}{workflows_path}",)
|
||||
|
||||
# 4. Logic
|
||||
workflows_found = list(w_path.rglob("*.json"))
|
||||
if not workflows_found:
|
||||
return (f"{T['err_no_json']}{workflows_path}",)
|
||||
|
||||
report = []
|
||||
report.append(T['analyzing'].format(count=len(workflows_found), path=w_path))
|
||||
|
||||
files_to_copy = {} # {source_path: category}
|
||||
|
||||
# Categories Map
|
||||
CATEGORIES_MAP = {
|
||||
'checkpoints': ['ckpt', 'checkpoint', 'model_name', 'load_checkpoint'],
|
||||
'loras': ['lora'],
|
||||
'vae': ['vae'],
|
||||
'controlnet': ['control', 'controlnet'],
|
||||
'upscale_models': ['upscale', 'esrgan', 'realesrgan'],
|
||||
'clip_vision': ['clip_vision'],
|
||||
'embeddings': ['embedding'],
|
||||
'ipadapter': ['ipadapter'],
|
||||
'unet': ['unet'],
|
||||
'clip': ['clip']
|
||||
}
|
||||
|
||||
# --- ANALYSIS PHASE ---
|
||||
for wf_file in workflows_found:
|
||||
try:
|
||||
with open(wf_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
nodes = data.get('nodes', [])
|
||||
if not nodes and isinstance(data, dict):
|
||||
nodes = list(data.values())
|
||||
|
||||
for node in nodes:
|
||||
if not isinstance(node, dict): continue
|
||||
|
||||
valores = []
|
||||
widgets = node.get('widgets_values', [])
|
||||
inputs = node.get('inputs', {})
|
||||
|
||||
if isinstance(widgets, list): valores.extend(widgets)
|
||||
if isinstance(inputs, dict): valores.extend(inputs.values())
|
||||
|
||||
for val in valores:
|
||||
if not isinstance(val, str): continue
|
||||
|
||||
if any(ext in val.lower() for ext in ['.safetensors', '.pt', '.pth', '.ckpt', '.bin']):
|
||||
ruta_real = self.buscar_archivo(models_root, val)
|
||||
if ruta_real:
|
||||
cat_detectada = Path(ruta_real).parent.name
|
||||
files_to_copy[ruta_real] = cat_detectada
|
||||
except Exception as e:
|
||||
report.append(T['err_read'].format(file=wf_file.name, error=str(e)))
|
||||
|
||||
total_files = len(files_to_copy)
|
||||
total_size = sum(os.path.getsize(f) for f in files_to_copy.keys()) / (1024**3)
|
||||
|
||||
report.append(T['found'].format(count=total_files))
|
||||
report.append(T['size'].format(size=total_size))
|
||||
|
||||
# --- EXECUTION PHASE ---
|
||||
if mode == "EXECUTE_BACKUP":
|
||||
if not dest_path.exists():
|
||||
try:
|
||||
dest_path.mkdir(parents=True)
|
||||
except:
|
||||
return (f"{T['err_dest'].format(path=dest_path)}",)
|
||||
|
||||
# 1. Backup Workflows
|
||||
wf_dest = dest_path / "workflows_backup"
|
||||
wf_dest.mkdir(exist_ok=True)
|
||||
for wf in workflows_found:
|
||||
try:
|
||||
shutil.copy2(wf, wf_dest)
|
||||
except: pass
|
||||
|
||||
# 2. Backup Models (CON BARRA DE PROGRESO)
|
||||
copied_count = 0
|
||||
|
||||
# Inicializamos la barra de progreso
|
||||
pbar = ProgressBar(total_files) # <--- NUEVO
|
||||
|
||||
for src, cat in files_to_copy.items():
|
||||
try:
|
||||
final_dest_folder = dest_path / "models" / cat
|
||||
final_dest_folder.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_path = Path(src)
|
||||
final_dest_file = final_dest_folder / src_path.name
|
||||
|
||||
if not final_dest_file.exists():
|
||||
print(T['copying'].format(name=src_path.name))
|
||||
shutil.copy2(src_path, final_dest_file)
|
||||
copied_count += 1
|
||||
|
||||
# Actualizamos la barra
|
||||
pbar.update(1) # <--- NUEVO: Avanza 1 paso en la barra azul
|
||||
|
||||
except Exception as e:
|
||||
print(T['err_copy'].format(src=src, error=str(e)))
|
||||
|
||||
report.append(T['done'].format(count=copied_count))
|
||||
report.append(T['location'].format(path=dest_path))
|
||||
|
||||
else:
|
||||
report.append(T['analysis_mode'])
|
||||
|
||||
return ("\n".join(report),)
|
||||
|
||||
def buscar_archivo(self, root_path, filename):
|
||||
possible_path = root_path / filename
|
||||
if possible_path.exists(): return str(possible_path)
|
||||
|
||||
clean_name = Path(filename).name
|
||||
for file in root_path.rglob(clean_name):
|
||||
return str(file)
|
||||
return None
|
||||
Reference in New Issue
Block a user