104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
# SimpleSyrup - workflow-focused ComfyUI extensions for image generation
|
|
# Copyright (C) 2026 Artificial Sweetener and contributors
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
"""Persist validated SimpleSyrup settings in ComfyUI's user directory."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import json
|
|
from json import JSONDecodeError
|
|
from pathlib import Path
|
|
from types import ModuleType
|
|
from typing import Any, Final
|
|
|
|
from ..shared.logging import get_logger
|
|
from .settings import SimpleSyrupSettings, SimpleSyrupSettingsError
|
|
|
|
LOGGER = get_logger(__name__)
|
|
SETTINGS_FILENAME: Final = "settings.json"
|
|
|
|
|
|
class SimpleSyrupSettingsRepository:
|
|
"""Load and save SimpleSyrup settings from Comfy's user directory."""
|
|
|
|
def __init__(
|
|
self,
|
|
settings_path: Path | None = None,
|
|
folder_paths_module: ModuleType | None = None,
|
|
) -> None:
|
|
"""Create a repository with injectable filesystem and Comfy boundaries."""
|
|
|
|
self._settings_path = settings_path
|
|
self._folder_paths_module = folder_paths_module
|
|
|
|
def load(self) -> SimpleSyrupSettings:
|
|
"""Load settings or return defaults for missing/malformed files."""
|
|
|
|
path = self.settings_path()
|
|
if not path.is_file():
|
|
return SimpleSyrupSettings()
|
|
|
|
try:
|
|
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
return SimpleSyrupSettings.from_payload(payload)
|
|
except (JSONDecodeError, OSError, SimpleSyrupSettingsError) as error:
|
|
LOGGER.warning(
|
|
"using default settings after failed load",
|
|
extra={"settings_path": str(path), "reason": str(error)},
|
|
)
|
|
return SimpleSyrupSettings()
|
|
|
|
def save(self, settings: SimpleSyrupSettings) -> SimpleSyrupSettings:
|
|
"""Persist validated settings and return the saved value."""
|
|
|
|
path = self.settings_path()
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
temporary_path = path.with_name(f"{path.name}.tmp")
|
|
temporary_path.write_text(
|
|
json.dumps(settings.to_payload(), indent=2, sort_keys=True) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
temporary_path.replace(path)
|
|
return settings
|
|
|
|
def settings_path(self) -> Path:
|
|
"""Return the resolved settings path."""
|
|
|
|
if self._settings_path is not None:
|
|
return self._settings_path
|
|
|
|
folder_paths = self._folder_paths_module or _folder_paths()
|
|
return (
|
|
_user_directory(folder_paths)
|
|
/ "default"
|
|
/ "SimpleSyrup"
|
|
/ SETTINGS_FILENAME
|
|
)
|
|
|
|
|
|
def _user_directory(folder_paths: ModuleType) -> Path:
|
|
"""Return Comfy's user directory from stable APIs or conservative fallback."""
|
|
|
|
get_user_directory = getattr(folder_paths, "get_user_directory", None)
|
|
if callable(get_user_directory):
|
|
user_directory = get_user_directory()
|
|
return Path(str(user_directory))
|
|
|
|
user_directory_attribute = getattr(folder_paths, "user_directory", None)
|
|
if user_directory_attribute is not None:
|
|
return Path(str(user_directory_attribute))
|
|
|
|
models_dir: Any = folder_paths.models_dir
|
|
return Path(str(models_dir)).parent / "user"
|
|
|
|
|
|
def _folder_paths() -> ModuleType:
|
|
"""Import ComfyUI folder paths lazily."""
|
|
|
|
module: Any = importlib.import_module("folder_paths")
|
|
if not isinstance(module, ModuleType):
|
|
raise TypeError("folder_paths import did not return a module.")
|
|
return module
|