138 lines
4.5 KiB
Python
138 lines
4.5 KiB
Python
"""Persist a handful of user choices to ~/HVideoTool/settings.json.
|
|
|
|
For the project-based tool this file holds the **defaults for new projects** (the
|
|
detector, model path, overlay threshold, restore engine) plus app-level state: the
|
|
last opened project, the recent-projects list, and the last directory used in file
|
|
dialogs. Per-project settings live in each project's ``project.json``, not here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from .config import AppConfig
|
|
|
|
_PATH = Path.home() / "HVideoTool" / "settings.json"
|
|
|
|
|
|
def _read() -> dict:
|
|
try:
|
|
return json.loads(_PATH.read_text(encoding="utf-8"))
|
|
except (OSError, ValueError):
|
|
return {}
|
|
|
|
|
|
def _write(data: dict) -> None:
|
|
_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
_PATH.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
|
|
|
|
def apply(config: AppConfig) -> None:
|
|
"""Overlay persisted settings onto ``config`` (mutates it in place)."""
|
|
data = _read()
|
|
if data.get("detector"):
|
|
config.detector = data["detector"]
|
|
if isinstance(data.get("detector_models"), list):
|
|
config.detector_models = [str(m) for m in data["detector_models"]]
|
|
if "threshold" in data:
|
|
config.default_threshold = float(data["threshold"])
|
|
if isinstance(data.get("model_thresholds"), dict):
|
|
config.model_thresholds = {
|
|
str(k): float(v) for k, v in data["model_thresholds"].items()
|
|
}
|
|
if "cross_model_nms" in data:
|
|
config.cross_model_nms = bool(data["cross_model_nms"])
|
|
if "nms_iou" in data:
|
|
config.nms_iou = float(data["nms_iou"])
|
|
if data.get("restorer"):
|
|
config.restorer = data["restorer"]
|
|
for key in ("dm_dir", "dm_model", "dm_gpu"):
|
|
if key in data:
|
|
setattr(config, key, data[key])
|
|
if "dm_feed_restored" in data:
|
|
config.dm_feed_restored = bool(data["dm_feed_restored"])
|
|
# diffusion-inpaint engine
|
|
for key in ("diff_backend", "diff_url", "diff_model", "diff_prompt", "diff_negative"):
|
|
if key in data:
|
|
setattr(config, key, data[key])
|
|
if "diff_steps" in data:
|
|
config.diff_steps = int(data["diff_steps"])
|
|
if "diff_cfg" in data:
|
|
config.diff_cfg = float(data["diff_cfg"])
|
|
if "diff_denoise" in data:
|
|
config.diff_denoise = float(data["diff_denoise"])
|
|
if "diff_seed" in data:
|
|
config.diff_seed = int(data["diff_seed"])
|
|
if "diff_mask_dilate" in data:
|
|
config.diff_mask_dilate = int(data["diff_mask_dilate"])
|
|
if "diff_mask_blur" in data:
|
|
config.diff_mask_blur = int(data["diff_mask_blur"])
|
|
|
|
|
|
def save(config: AppConfig) -> None:
|
|
"""Persist the configurable settings, preserving other keys (e.g. last_dir)."""
|
|
data = _read()
|
|
data.update(
|
|
detector=config.detector,
|
|
detector_models=list(config.detector_models),
|
|
threshold=config.default_threshold,
|
|
model_thresholds=dict(config.model_thresholds),
|
|
cross_model_nms=config.cross_model_nms,
|
|
nms_iou=config.nms_iou,
|
|
restorer=config.restorer,
|
|
dm_dir=config.dm_dir,
|
|
dm_model=config.dm_model,
|
|
dm_gpu=config.dm_gpu,
|
|
dm_feed_restored=config.dm_feed_restored,
|
|
diff_backend=config.diff_backend,
|
|
diff_url=config.diff_url,
|
|
diff_model=config.diff_model,
|
|
diff_prompt=config.diff_prompt,
|
|
diff_negative=config.diff_negative,
|
|
diff_steps=config.diff_steps,
|
|
diff_cfg=config.diff_cfg,
|
|
diff_denoise=config.diff_denoise,
|
|
diff_seed=config.diff_seed,
|
|
diff_mask_dilate=config.diff_mask_dilate,
|
|
diff_mask_blur=config.diff_mask_blur,
|
|
)
|
|
_write(data)
|
|
|
|
|
|
def last_dir() -> str | None:
|
|
return _read().get("last_dir")
|
|
|
|
|
|
def set_last_dir(path: str) -> None:
|
|
data = _read()
|
|
data["last_dir"] = path
|
|
_write(data)
|
|
|
|
|
|
def last_project() -> str | None:
|
|
return _read().get("last_project")
|
|
|
|
|
|
def set_last_project(path: str) -> None:
|
|
data = _read()
|
|
data["last_project"] = path
|
|
_write(data)
|
|
|
|
|
|
_RECENTS_CAP = 10
|
|
|
|
|
|
def recent_projects() -> list[str]:
|
|
recents = _read().get("recent_projects", [])
|
|
return [p for p in recents if isinstance(p, str)]
|
|
|
|
|
|
def add_recent_project(path: str) -> None:
|
|
"""Push ``path`` to the front of the recent-projects list (deduped, capped)."""
|
|
data = _read()
|
|
recents = [p for p in data.get("recent_projects", []) if isinstance(p, str) and p != path]
|
|
recents.insert(0, path)
|
|
data["recent_projects"] = recents[:_RECENTS_CAP]
|
|
_write(data)
|