"""Configuration handling for toni-sync. Stores the mapping between local audio folders (e.g. exported Deezer playlists) and Kreativ-Tonies in a simple YAML file. Credentials for the TonieCloud account are NEVER stored here - they are provided via environment variables or interactive prompt (see client.py). """ from __future__ import annotations import os from pathlib import Path import yaml from pydantic import BaseModel, Field DEFAULT_CONFIG_PATH = Path( os.environ.get("TONI_SYNC_CONFIG", str(Path.home() / ".config" / "toni-sync" / "config.yaml")) ) class ToniMapping(BaseModel): """Mapping of a local folder to a Kreativ-Tonie.""" name: str # unique friendly identifier used on the CLI, e.g. "peppa-wutz" household_id: str tonie_id: str tonie_name: str | None = None # informational, kept in sync on config add/list folder: str # local path containing the audio files for this tonie playlist_ref: str | None = None # informational, e.g. deezer playlist URL/ID prune: bool = True # remove chapters on the tonie that no longer exist locally @property def folder_path(self) -> Path: return Path(self.folder).expanduser() class AppConfig(BaseModel): """The full toni-sync configuration.""" mappings: list[ToniMapping] = Field(default_factory=list) def get(self, name: str) -> ToniMapping | None: return next((m for m in self.mappings if m.name == name), None) def upsert(self, mapping: ToniMapping) -> None: for i, existing in enumerate(self.mappings): if existing.name == mapping.name: self.mappings[i] = mapping return self.mappings.append(mapping) def remove(self, name: str) -> bool: before = len(self.mappings) self.mappings = [m for m in self.mappings if m.name != name] return len(self.mappings) != before def load_config(path: Path | None = None) -> AppConfig: path = path or DEFAULT_CONFIG_PATH if not path.exists(): return AppConfig() with path.open("r", encoding="utf-8") as fh: raw = yaml.safe_load(fh) or {} return AppConfig(**raw) def save_config(config: AppConfig, path: Path | None = None) -> None: path = path or DEFAULT_CONFIG_PATH path.parent.mkdir(parents=True, exist_ok=True) with path.open("w", encoding="utf-8") as fh: yaml.safe_dump(config.model_dump(), fh, allow_unicode=True, sort_keys=False)