Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Configuration management module"""
|
||||
@@ -0,0 +1,168 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user