Initial commit.

This commit is contained in:
Storm Dragon
2025-10-04 02:55:01 -04:00
commit 1d19ed377c
16 changed files with 4401 additions and 0 deletions

221
src/config_manager.py Normal file
View File

@@ -0,0 +1,221 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Config Manager
Manages BookStorm settings using INI format.
Settings stored in ~/.config/stormux/bookstorm/settings.ini
"""
import configparser
from pathlib import Path
class ConfigManager:
"""Manages application configuration"""
def __init__(self, configPath=None):
"""
Initialize config manager
Args:
configPath: Path to config file (optional)
"""
if configPath is None:
homePath = Path.home()
configDir = homePath / ".config" / "stormux" / "bookstorm"
configDir.mkdir(parents=True, exist_ok=True)
configPath = configDir / "settings.ini"
self.configPath = Path(configPath)
self.config = configparser.ConfigParser()
# Load or create config
if self.configPath.exists():
self.config.read(self.configPath)
else:
self._create_default_config()
def _create_default_config(self):
"""Create default configuration"""
self.config['TTS'] = {
'voice_model': '/usr/share/piper-voices/en/en_US/hfc_male/medium/en_US-hfc_male-medium.onnx',
'voice_dir': '/usr/share/piper-voices/en/en_US',
'reader_engine': 'piper',
'speechd_voice': '',
'speechd_output_module': '',
'speech_rate': '0'
}
self.config['Reading'] = {
'auto_advance': 'true',
'auto_save_bookmark': 'true'
}
self.config['Display'] = {
'show_text': 'true'
}
self.config['Paths'] = {
'last_book': '',
'books_directory': str(Path.home()),
'library_directory': ''
}
self.save()
def get(self, section, key, fallback=None):
"""
Get configuration value
Args:
section: Config section
key: Config key
fallback: Default value if not found
Returns:
Configuration value
"""
try:
return self.config.get(section, key)
except (configparser.NoSectionError, configparser.NoOptionError):
return fallback
def get_bool(self, section, key, fallback=False):
"""
Get boolean configuration value
Args:
section: Config section
key: Config key
fallback: Default value if not found
Returns:
Boolean configuration value
"""
try:
return self.config.getboolean(section, key)
except (configparser.NoSectionError, configparser.NoOptionError):
return fallback
def set(self, section, key, value):
"""
Set configuration value
Args:
section: Config section
key: Config key
value: Value to set
"""
if not self.config.has_section(section):
self.config.add_section(section)
self.config.set(section, key, str(value))
def save(self):
"""Save configuration to file"""
with open(self.configPath, 'w') as configFile:
self.config.write(configFile)
def get_voice_model(self):
"""Get configured voice model path"""
return self.get('TTS', 'voice_model')
def set_voice_model(self, modelPath):
"""Set voice model path"""
self.set('TTS', 'voice_model', str(modelPath))
self.save()
def get_voice_dir(self):
"""Get voice models directory"""
return self.get('TTS', 'voice_dir', '/usr/share/piper-voices/en/en_US')
def set_voice_dir(self, voiceDir):
"""Set voice models directory"""
self.set('TTS', 'voice_dir', str(voiceDir))
self.save()
def get_last_book(self):
"""Get last opened book path"""
lastBook = self.get('Paths', 'last_book')
return lastBook if lastBook else None
def set_last_book(self, bookPath):
"""Set last opened book path"""
self.set('Paths', 'last_book', str(bookPath))
self.save()
def get_books_directory(self):
"""Get books directory for file browser"""
return self.get('Paths', 'books_directory', str(Path.home()))
def set_books_directory(self, booksDir):
"""Set books directory"""
self.set('Paths', 'books_directory', str(booksDir))
self.save()
def get_auto_advance(self):
"""Get auto-advance setting"""
return self.get_bool('Reading', 'auto_advance', True)
def get_auto_save(self):
"""Get auto-save bookmark setting"""
return self.get_bool('Reading', 'auto_save_bookmark', True)
def get_reader_engine(self):
"""Get reader engine (piper or speechd)"""
return self.get('TTS', 'reader_engine', 'piper')
def set_reader_engine(self, engine):
"""Set reader engine (piper or speechd)"""
if engine in ['piper', 'speechd']:
self.set('TTS', 'reader_engine', engine)
self.save()
def get_speechd_voice(self):
"""Get speech-dispatcher voice"""
return self.get('TTS', 'speechd_voice', '')
def set_speechd_voice(self, voice):
"""Set speech-dispatcher voice"""
self.set('TTS', 'speechd_voice', str(voice))
self.save()
def get_speechd_output_module(self):
"""Get speech-dispatcher output module"""
return self.get('TTS', 'speechd_output_module', '')
def set_speechd_output_module(self, module):
"""Set speech-dispatcher output module"""
self.set('TTS', 'speechd_output_module', str(module))
self.save()
def get_speech_rate(self):
"""Get speech rate"""
try:
return int(self.get('TTS', 'speech_rate', '0'))
except ValueError:
return 0
def set_speech_rate(self, rate):
"""Set speech rate"""
self.set('TTS', 'speech_rate', str(rate))
self.save()
def get_show_text(self):
"""Get show text display setting"""
return self.get_bool('Display', 'show_text', True)
def set_show_text(self, enabled):
"""Set show text display setting"""
self.set('Display', 'show_text', str(enabled).lower())
self.save()
def get_library_directory(self):
"""Get library directory (default starting point for book browser)"""
return self.get('Paths', 'library_directory', '')
def set_library_directory(self, libraryDir):
"""Set library directory"""
self.set('Paths', 'library_directory', str(libraryDir))
self.save()