Files
navipy/src/config/settings.py
Storm Dragon 555ca0bba9 Initial commit
2025-12-15 04:09:55 -05:00

169 lines
5.5 KiB
Python

"""
Configuration management with XDG compliance
"""
import os
import json
from pathlib import Path
from typing import Optional, Dict, Any
APP_VENDOR = "stormux"
APP_NAME = "navipy"
def getConfigDir() -> Path:
"""Get XDG-compliant config directory"""
xdgConfig = os.environ.get('XDG_CONFIG_HOME')
baseDir = Path(xdgConfig) if xdgConfig else Path.home() / '.config'
configDir = baseDir / APP_VENDOR / APP_NAME
configDir.mkdir(parents=True, exist_ok=True)
return configDir
def getDataDir() -> Path:
"""Get XDG-compliant data directory"""
xdgData = os.environ.get('XDG_DATA_HOME')
baseDir = Path(xdgData) if xdgData else Path.home() / '.local' / 'share'
dataDir = baseDir / APP_VENDOR / APP_NAME
dataDir.mkdir(parents=True, exist_ok=True)
return dataDir
def getCacheDir() -> Path:
"""Get XDG-compliant cache directory"""
xdgCache = os.environ.get('XDG_CACHE_HOME')
baseDir = Path(xdgCache) if xdgCache else Path.home() / '.cache'
cacheDir = baseDir / APP_VENDOR / APP_NAME
cacheDir.mkdir(parents=True, exist_ok=True)
return cacheDir
class Settings:
"""Application settings manager"""
def __init__(self):
self.configDir = getConfigDir()
self.configFile = self.configDir / 'settings.json'
self.serversFile = self.configDir / 'servers.json'
self._legacyConfigDir = self._getLegacyConfigDir()
self._settings = self._loadSettings()
self._servers = self._loadServers()
def _getLegacyConfigDir(self) -> Path:
"""Legacy configuration path kept for backwards compatibility."""
xdgConfig = os.environ.get('XDG_CONFIG_HOME')
baseDir = Path(xdgConfig) if xdgConfig else Path.home() / '.config'
return baseDir / APP_NAME
def _loadSettings(self) -> Dict[str, Any]:
"""Load settings from file"""
defaults = {
'general': {
'defaultServer': None,
'startMinimized': False
},
'playback': {
'volume': 100,
'shuffle': False,
'repeat': 'none', # none, one, all
'gapless': True
},
'interface': {
'pageStep': 5,
'announceTrackChanges': True
}
}
for candidate in (self.configFile, self._legacyConfigDir / 'settings.json'):
if candidate.exists():
try:
with open(candidate, 'r', encoding='utf-8') as f:
loaded = json.load(f)
# Merge loaded settings with defaults
for section in defaults:
if section in loaded:
defaults[section].update(loaded[section])
return defaults
except (json.JSONDecodeError, IOError):
continue
return defaults
def _loadServers(self) -> Dict[str, Dict[str, str]]:
"""Load server configurations from file"""
for candidate in (self.serversFile, self._legacyConfigDir / 'servers.json'):
if candidate.exists():
try:
with open(candidate, 'r', encoding='utf-8') as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
continue
return {}
def save(self) -> None:
"""Save settings to file"""
try:
with open(self.configFile, 'w', encoding='utf-8') as f:
json.dump(self._settings, f, indent=2)
except IOError as e:
print(f"Failed to save settings: {e}")
def saveServers(self) -> None:
"""Save server configurations to file"""
try:
with open(self.serversFile, 'w', encoding='utf-8') as f:
json.dump(self._servers, f, indent=2)
except IOError as e:
print(f"Failed to save servers: {e}")
def get(self, section: str, key: str, default: Any = None) -> Any:
"""Get a setting value"""
return self._settings.get(section, {}).get(key, default)
def set(self, section: str, key: str, value: Any) -> None:
"""Set a setting value"""
if section not in self._settings:
self._settings[section] = {}
self._settings[section][key] = value
self.save()
# Server management
def getServers(self) -> Dict[str, Dict[str, str]]:
"""Get all server configurations"""
return self._servers
def getServer(self, name: str) -> Optional[Dict[str, str]]:
"""Get a specific server configuration"""
return self._servers.get(name)
def addServer(self, name: str, url: str, username: str, password: str) -> None:
"""Add or update a server configuration"""
self._servers[name] = {
'url': url,
'username': username,
'password': password
}
self.saveServers()
def removeServer(self, name: str) -> None:
"""Remove a server configuration"""
if name in self._servers:
del self._servers[name]
self.saveServers()
def getDefaultServer(self) -> Optional[str]:
"""Get the default server name"""
return self.get('general', 'defaultServer')
def setDefaultServer(self, name: str) -> None:
"""Set the default server"""
self.set('general', 'defaultServer', name)
def hasServers(self) -> bool:
"""Check if any servers are configured"""
return len(self._servers) > 0