227 lines
9.3 KiB
Python
227 lines
9.3 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
# Copyright (C) 2025 ComfyUI-GeometryPack Contributors
|
|
|
|
"""
|
|
GeometryPack PreStartup Script
|
|
- Copies 3D viewer infrastructure from comfy-3d-viewers package
|
|
- Generates dynamic widget visibility mappings
|
|
- Copies example 3D assets to ComfyUI input folder on startup
|
|
"""
|
|
import json
|
|
import os
|
|
import shutil
|
|
|
|
|
|
def copy_3d_viewers():
|
|
"""Copy 3D viewer files from comfy-3d-viewers package to web/ directory."""
|
|
try:
|
|
from comfy_3d_viewers import get_js_dir, get_html_dir, get_utils_dir, get_nodes_dir, get_assets_dir
|
|
|
|
custom_node_dir = os.path.dirname(os.path.abspath(__file__))
|
|
web_js_dir = os.path.join(custom_node_dir, "web", "js")
|
|
web_dir = os.path.join(custom_node_dir, "web")
|
|
|
|
# Ensure directories exist
|
|
os.makedirs(web_js_dir, exist_ok=True)
|
|
os.makedirs(os.path.join(web_js_dir, "utils"), exist_ok=True)
|
|
os.makedirs(os.path.join(web_js_dir, "viewer"), exist_ok=True)
|
|
|
|
copied_count = 0
|
|
|
|
# Copy JS bundles (vtk-gltf.js, gsplat-bundle.js, viewer-bundle.js)
|
|
src_js_dir = get_js_dir()
|
|
for filename in os.listdir(src_js_dir):
|
|
if filename.endswith('.js') and not os.path.isdir(os.path.join(src_js_dir, filename)):
|
|
src = os.path.join(src_js_dir, filename)
|
|
dst = os.path.join(web_js_dir, filename)
|
|
if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
|
|
shutil.copy2(src, dst)
|
|
copied_count += 1
|
|
|
|
# Copy utils directory
|
|
src_utils_dir = get_utils_dir()
|
|
if os.path.exists(src_utils_dir):
|
|
dst_utils_dir = os.path.join(web_js_dir, "utils")
|
|
for filename in os.listdir(src_utils_dir):
|
|
if filename.endswith('.js'):
|
|
src = os.path.join(src_utils_dir, filename)
|
|
dst = os.path.join(dst_utils_dir, filename)
|
|
if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
|
|
shutil.copy2(src, dst)
|
|
copied_count += 1
|
|
|
|
# Copy viewer directory (modular viewer source)
|
|
src_viewer_dir = os.path.join(src_js_dir, "viewer")
|
|
if os.path.exists(src_viewer_dir):
|
|
dst_viewer_dir = os.path.join(web_js_dir, "viewer")
|
|
for root, dirs, files in os.walk(src_viewer_dir):
|
|
rel_path = os.path.relpath(root, src_viewer_dir)
|
|
dst_root = os.path.join(dst_viewer_dir, rel_path) if rel_path != '.' else dst_viewer_dir
|
|
os.makedirs(dst_root, exist_ok=True)
|
|
for filename in files:
|
|
if filename.endswith('.js') or filename.endswith('.css'):
|
|
src = os.path.join(root, filename)
|
|
dst = os.path.join(dst_root, filename)
|
|
if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
|
|
shutil.copy2(src, dst)
|
|
copied_count += 1
|
|
|
|
# Copy HTML viewer templates
|
|
src_html_dir = get_html_dir()
|
|
if os.path.exists(src_html_dir):
|
|
for filename in os.listdir(src_html_dir):
|
|
if filename.endswith('.html'):
|
|
src = os.path.join(src_html_dir, filename)
|
|
dst = os.path.join(web_dir, filename)
|
|
if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
|
|
shutil.copy2(src, dst)
|
|
copied_count += 1
|
|
|
|
# Copy node widget JS files
|
|
src_nodes_dir = get_nodes_dir()
|
|
if os.path.exists(src_nodes_dir):
|
|
for filename in os.listdir(src_nodes_dir):
|
|
if filename.endswith('.js'):
|
|
src = os.path.join(src_nodes_dir, filename)
|
|
dst = os.path.join(web_js_dir, filename)
|
|
if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
|
|
shutil.copy2(src, dst)
|
|
copied_count += 1
|
|
|
|
# Copy assets (HDR environments, etc.)
|
|
src_assets_dir = get_assets_dir()
|
|
if os.path.exists(src_assets_dir):
|
|
dst_assets_dir = os.path.join(web_dir, "assets")
|
|
os.makedirs(dst_assets_dir, exist_ok=True)
|
|
for filename in os.listdir(src_assets_dir):
|
|
src = os.path.join(src_assets_dir, filename)
|
|
dst = os.path.join(dst_assets_dir, filename)
|
|
if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst):
|
|
shutil.copy2(src, dst)
|
|
copied_count += 1
|
|
|
|
if copied_count > 0:
|
|
print(f"[GeometryPack] Copied {copied_count} file(s) from comfy-3d-viewers package")
|
|
|
|
except ImportError:
|
|
print("[GeometryPack] Warning: comfy-3d-viewers not installed, 3D viewers may not work")
|
|
except Exception as e:
|
|
print(f"[GeometryPack] Error copying 3D viewers: {e}")
|
|
|
|
|
|
def copy_example_assets():
|
|
"""Copy all files and folders from assets/ directory to ComfyUI input/3d directory."""
|
|
try:
|
|
import folder_paths
|
|
|
|
input_folder = folder_paths.get_input_directory()
|
|
custom_node_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
# Create input/3d subdirectory
|
|
input_3d_folder = os.path.join(input_folder, "3d")
|
|
os.makedirs(input_3d_folder, exist_ok=True)
|
|
|
|
# Copy entire assets/ folder structure
|
|
assets_folder = os.path.join(custom_node_dir, "assets")
|
|
if not os.path.exists(assets_folder):
|
|
print(f"[GeometryPack] Warning: assets folder not found at {assets_folder}")
|
|
return
|
|
|
|
copied_count = 0
|
|
for root, dirs, files in os.walk(assets_folder):
|
|
# Calculate relative path from assets folder
|
|
rel_path = os.path.relpath(root, assets_folder)
|
|
|
|
# Create corresponding subdirectory in destination
|
|
if rel_path != '.':
|
|
dest_dir = os.path.join(input_3d_folder, rel_path)
|
|
os.makedirs(dest_dir, exist_ok=True)
|
|
else:
|
|
dest_dir = input_3d_folder
|
|
|
|
# Copy files
|
|
for file in files:
|
|
source_file = os.path.join(root, file)
|
|
dest_file = os.path.join(dest_dir, file)
|
|
|
|
if not os.path.exists(dest_file):
|
|
shutil.copy2(source_file, dest_file)
|
|
copied_count += 1
|
|
# Show relative path for clarity
|
|
rel_dest = os.path.join(rel_path, file) if rel_path != '.' else file
|
|
print(f"[GeometryPack] Copied {rel_dest} to input/3d/")
|
|
|
|
if copied_count > 0:
|
|
print(f"[GeometryPack] [OK] Copied {copied_count} asset(s) to {input_3d_folder}")
|
|
else:
|
|
print(f"[GeometryPack] All assets already exist in {input_3d_folder}")
|
|
|
|
except Exception as e:
|
|
print(f"[GeometryPack] Error copying assets: {e}")
|
|
|
|
|
|
def copy_dynamic_widgets_js():
|
|
"""Copy dynamic_widgets.js from pip package to web/js/."""
|
|
try:
|
|
from comfy_dynamic_widgets import get_js_path
|
|
|
|
source = get_js_path()
|
|
if not os.path.exists(source):
|
|
print(f"[GeometryPack] Warning: dynamic_widgets.js not found at {source}")
|
|
return
|
|
|
|
custom_node_dir = os.path.dirname(os.path.abspath(__file__))
|
|
dest = os.path.join(custom_node_dir, "web", "js", "dynamic_widgets.js")
|
|
|
|
# Ensure web/js directory exists
|
|
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
|
|
|
# Copy if source is newer or dest doesn't exist
|
|
if not os.path.exists(dest) or os.path.getmtime(source) > os.path.getmtime(dest):
|
|
shutil.copy2(source, dest)
|
|
print("[GeometryPack] Copied dynamic_widgets.js from comfy-dynamic-widgets package")
|
|
|
|
except ImportError:
|
|
print("[GeometryPack] Warning: comfy-dynamic-widgets not installed")
|
|
except Exception as e:
|
|
print(f"[GeometryPack] Error copying JS: {e}")
|
|
|
|
|
|
def generate_widget_mappings():
|
|
"""Generate dynamic widget visibility mappings using comfy-dynamic-widgets."""
|
|
try:
|
|
from comfy_dynamic_widgets import scan_all_nodes, generate_mappings
|
|
|
|
# Scan all nodes for visible_when metadata
|
|
configs = scan_all_nodes()
|
|
|
|
if not configs:
|
|
print("[GeometryPack] No visible_when metadata found in any nodes")
|
|
return
|
|
|
|
# Generate JS-friendly mappings
|
|
mappings = generate_mappings(configs)
|
|
|
|
# Write to web/js/mappings.json
|
|
custom_node_dir = os.path.dirname(os.path.abspath(__file__))
|
|
output_path = os.path.join(custom_node_dir, "web", "js", "mappings.json")
|
|
|
|
with open(output_path, "w") as f:
|
|
json.dump(mappings, f, indent=2)
|
|
|
|
node_count = len(configs)
|
|
selector_count = sum(len(c.get("selectors", {})) for c in configs.values())
|
|
print(f"[GeometryPack] Generated widget mappings for {node_count} nodes ({selector_count} selectors)")
|
|
|
|
except ImportError:
|
|
print("[GeometryPack] Warning: comfy-dynamic-widgets not installed, skipping widget mappings")
|
|
except Exception as e:
|
|
print(f"[GeometryPack] Error generating widget mappings: {e}")
|
|
|
|
|
|
# Run on import
|
|
copy_3d_viewers()
|
|
copy_dynamic_widgets_js()
|
|
# Note: generate_widget_mappings() moved to __init__.py where NODE_CLASS_MAPPINGS is available
|
|
copy_example_assets()
|