Files
PyQt6_LaTaniere/src/config/config_manager.py
2026-03-16 13:47:30 +01:00

138 lines
3.8 KiB
Python

import json
from pathlib import Path
from typing import Any, Callable, NotRequired, TypedDict, cast
from utils import get_bundle_dir
class ConfigData(TypedDict):
discord_user_id: NotRequired[str]
volume: NotRequired[int]
Validator = Callable[[Any], bool]
Normalizer = Callable[[Any], Any]
class ConfigField(TypedDict):
default: Any
validator: Validator
normalizer: Normalizer
CONFIG_PATH = get_bundle_dir() / "config.json"
DISCORD_USER_KEY = "discord_user_id"
VOLUME_KEY = "volume"
CONFIG_SCHEMA: dict[str, ConfigField] = {
DISCORD_USER_KEY: {
"default": "",
"validator": lambda value: isinstance(value, str),
"normalizer": lambda value: str(value).strip(),
},
VOLUME_KEY: {
"default": 30,
"validator": lambda value: isinstance(value, int) and 0 <= value <= 100,
"normalizer": lambda value: max(0, min(int(value), 100)),
},
}
class ConfigManager:
def __init__(self, path: Path | None = None) -> None:
self.path = path or CONFIG_PATH
self._data: ConfigData = self._load()
self._dirty = False
# Lecture du fichier de configuration
def _load(self) -> ConfigData:
if not self.path.exists():
return {}
try:
with self.path.open("r", encoding="utf-8") as file:
data = json.load(file)
except (json.JSONDecodeError, OSError):
return {}
if not isinstance(data, dict):
return {}
return cast(ConfigData, data)
# Sauvegarde du fichier de configuration
def save(self) -> None:
if not self._dirty:
return
self.path.parent.mkdir(parents=True, exist_ok=True)
with self.path.open("w", encoding="utf-8") as file:
json.dump(self._data, file, indent=4, ensure_ascii=False)
self._dirty = False
def _get_field(self, key: str) -> ConfigField:
if key not in CONFIG_SCHEMA:
raise KeyError(f"Unknown config key: {key}")
return CONFIG_SCHEMA[key]
def get(self, key: str) -> Any:
field = self._get_field(key)
value = self._data.get(key, field["default"])
if not field["validator"](value):
return field["default"]
return value
def set(self, key: str, value: Any) -> None:
field = self._get_field(key)
normalized = field["normalizer"](value)
if not field["validator"](normalized):
raise ValueError(f"Invalid value for {key}")
if self._data.get(key) == normalized:
return
self._data[key] = normalized
self._dirty = True
def reset_all(self) -> None:
defaults: ConfigData = cast(
ConfigData,
{key: field["default"] for key, field in CONFIG_SCHEMA.items()},
)
self.save(defaults)
def get_all(self) -> ConfigData:
return cast(
ConfigData,
{key: self.get(key) for key in CONFIG_SCHEMA},
)
# ---------------------------------------------------------------------------
# SETTERS MÉTIER
# ---------------------------------------------------------------------------
# Set Discord ID
def set_discord_user(self, user_id: str) -> None:
self.set(DISCORD_USER_KEY, user_id)
# Set volume
def set_volume(self, volume: int) -> None:
self.set(VOLUME_KEY, volume)
# ---------------------------------------------------------------------------
# GETTERS MÉTIER
# ---------------------------------------------------------------------------
# Get discord ID
def get_default(self, key: str):
return CONFIG_SCHEMA[key]["default"]
# Get volume value
def get_discord_user(self) -> str:
return cast(str, self.get(DISCORD_USER_KEY))
def get_volume(self) -> int:
return cast(int, self.get(VOLUME_KEY))