Files
videofeedback-comfyui-rende…/config_manager.py
T

124 lines
4.3 KiB
Python

# ComfyUI Render Time — config_manager.py
# Author: Ramiro Montes De Oca
# GitHub: https://github.com/videofeedback/comfyui-render-time
#
# Reads and writes plugin settings from/to config.json in the plugin directory.
# Author/contact identity is stored separately in author.txt (blank on fresh install).
import json
from pathlib import Path
from typing import Any
PLUGIN_DIR = Path(__file__).parent
CONFIG_FILE = PLUGIN_DIR / "config.json"
AUTHOR_FILE = PLUGIN_DIR / "author.txt"
# Default configuration — all output types enabled, all default to ComfyUI output/.
# workflow_author / workflow_contact are intentionally NOT here — they live in author.txt
# so a fresh install always starts with blank identity fields.
DEFAULT_CONFIG: dict = {
"embed_json": {
"enabled": True,
"location": "default", # "default" | "custom"
"custom_path": "",
},
"txt_report": {
"enabled": True,
"location": "default",
"custom_path": "",
},
"isolated_json": {
"enabled": True,
"location": "default",
"custom_path": "",
},
"workflow_png": {
"enabled": True,
"location": "default",
"custom_path": "",
},
# Audio notification when a render + report completes
"notify_on_complete": True,
}
def _deep_merge(base: dict, override: dict) -> dict:
"""Merge override into base recursively; base fills in missing keys."""
result = dict(base)
for key, val in override.items():
if key in result and isinstance(result[key], dict) and isinstance(val, dict):
result[key] = _deep_merge(result[key], val)
else:
result[key] = val
return result
def get_author_info() -> dict:
"""
Read workflow_author / workflow_contact from author.txt.
Returns empty strings for both fields if the file does not exist.
This is intentional — a fresh install should never inherit someone else's name.
"""
if not AUTHOR_FILE.exists():
return {"workflow_author": "", "workflow_contact": ""}
try:
lines = AUTHOR_FILE.read_text(encoding="utf-8").splitlines()
author = lines[0].strip() if len(lines) > 0 else ""
contact = lines[1].strip() if len(lines) > 1 else ""
return {"workflow_author": author, "workflow_contact": contact}
except Exception:
return {"workflow_author": "", "workflow_contact": ""}
def save_author_info(author: str, contact: str) -> None:
"""
Persist workflow_author / workflow_contact to author.txt.
Called ONLY when the user explicitly saves from the Settings panel or
Properties panel — never called automatically during report generation.
"""
AUTHOR_FILE.write_text(f"{author}\n{contact}\n", encoding="utf-8")
def get_config() -> dict:
"""
Load config from disk, filling in any missing keys with defaults.
Author/contact are overlaid from author.txt (blank on fresh install).
"""
if not CONFIG_FILE.exists():
cfg = dict(DEFAULT_CONFIG)
else:
try:
with open(CONFIG_FILE, encoding="utf-8") as f:
on_disk = json.load(f)
# Strip any stale author fields that may have been saved by older versions
on_disk.pop("workflow_author", None)
on_disk.pop("workflow_contact", None)
cfg = _deep_merge(DEFAULT_CONFIG, on_disk)
except Exception:
cfg = dict(DEFAULT_CONFIG)
# Always overlay from author.txt so the frontend gets the right values
cfg.update(get_author_info())
return cfg
def save_config(cfg: dict) -> None:
"""
Persist config to disk. Author/contact fields are stripped — they belong
in author.txt, not config.json. Unknown keys are preserved as-is.
"""
cfg_to_save = {k: v for k, v in cfg.items()
if k not in ("workflow_author", "workflow_contact")}
merged = _deep_merge(DEFAULT_CONFIG, cfg_to_save)
CONFIG_FILE.write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding="utf-8")
def get_default_descriptions() -> dict:
"""Return human-readable default path descriptions for the UI."""
return {
"embed_json": "Default: ComfyUI output/",
"txt_report": "Default: ComfyUI output/",
"isolated_json": "Default: ComfyUI output/",
"workflow_png": "Default: ComfyUI output/",
}