# This file is part of Senator Sperma # Licensed under the GPL-3.0 License # Copyright (C) 2026 Salmonik @ salmonik@tuta.io # https://codeberg.org/salmonik/senator-sperma import json import logging import aiofiles import os from dataclasses import dataclass, field logger = logging.getLogger(__name__) settings_file = "data/settings.json" DEFAULT_BASEURL = "http://localhost:8080" @dataclass class Settings: volume: float = 1.0 baseurl: str = DEFAULT_BASEURL _data: dict = field(default_factory=dict, init=False) async def load(self) -> "Settings": default_settings = { "volume": 1.0, "baseurl": DEFAULT_BASEURL, } try: if os.path.exists(settings_file): async with aiofiles.open(settings_file, "r") as f: content = await f.read() if content.strip(): self._data = json.loads(content) self._sync_from_data() logger.info("Settings loaded into memory") else: self._data = default_settings.copy() self._sync_from_data() await self.save() logger.warning("Empty settings.json, reset to defaults") else: self._data = default_settings.copy() self._sync_from_data() await self.save() logger.info("Created default settings.json") except json.JSONDecodeError as e: logger.error(f"Error loading settings: {e}") self._data = default_settings.copy() self._sync_from_data() return self def _sync_from_data(self): self.volume = self._data.get("volume", 1.0) self.baseurl = self._data.get("baseurl", DEFAULT_BASEURL) def _sync_to_data(self): self._data["volume"] = self.volume self._data["baseurl"] = self.baseurl async def save(self): self._sync_to_data() async with aiofiles.open(settings_file, "w") as f: await f.write(json.dumps(self._data, indent=2)) _settings_instance: Settings | None = None async def load_settings() -> Settings: global _settings_instance _settings_instance = Settings() await _settings_instance.load() return _settings_instance async def save_settings(): if _settings_instance: await _settings_instance.save() def get_settings() -> Settings | None: return _settings_instance def get_volume() -> float: return _settings_instance.volume if _settings_instance else 1.0 def get_baseurl() -> str: return _settings_instance.baseurl.rstrip("/") if _settings_instance else DEFAULT_BASEURL