Refactor code structure for improved readability and maintainability

This commit is contained in:
MaddoScientisto 2026-02-09 23:46:11 +01:00
commit e078cada3b
11 changed files with 1640 additions and 1184 deletions

158
modules/config.py Normal file
View file

@ -0,0 +1,158 @@
"""
Configuration management for Twitch Archive.
Handles loading global and per-streamer configuration files.
"""
import json
import pathlib
from typing import Dict, Any
from colorama import Fore, Style
from .constants import DEFAULT_CONFIG
class ConfigManager:
"""
Manages global and per-streamer configurations.
Loads global defaults from config/global.json and merges with per-streamer
configs from config/streamers/*.json.
"""
def __init__(self):
"""Initialize the configuration manager."""
self.config_dir = pathlib.Path(__file__).parent.parent / "config"
self.streamers_dir = self.config_dir / "streamers"
self.global_config = self._load_global_config()
def _load_global_config(self) -> Dict[str, Any]:
"""
Load global configuration from config/global.json.
Returns:
dict: Global configuration with defaults
"""
global_file = self.config_dir / "global.json"
# Start with DEFAULT_CONFIG as ultimate fallback
config = DEFAULT_CONFIG.copy()
# Try to load global config
if global_file.exists():
try:
with open(global_file, 'r', encoding='utf-8') as f:
user_config = json.load(f)
# Filter out comment fields and schema references
user_config = {k: v for k, v in user_config.items()
if not k.startswith('_') and k != '$schema'}
config.update(user_config)
print(f'{Fore.GREEN}✓ Global configuration loaded from config/global.json{Style.RESET_ALL}')
except json.JSONDecodeError as e:
print(f'{Fore.YELLOW}⚠ Warning: Invalid JSON in config/global.json: {e}{Style.RESET_ALL}')
print(f'{Fore.YELLOW} Using default configuration{Style.RESET_ALL}')
except Exception as e:
print(f'{Fore.YELLOW}⚠ Warning: Could not load config/global.json: {e}{Style.RESET_ALL}')
else:
print(f'{Fore.YELLOW}⚠ Warning: config/global.json not found{Style.RESET_ALL}')
print(f'{Fore.CYAN} → Create config/global.json with default settings{Style.RESET_ALL}')
return config
def load_streamer_config(self, username: str) -> Dict[str, Any]:
"""
Load configuration for a specific streamer.
Merges global config with streamer-specific overrides.
Args:
username: Twitch username
Returns:
dict: Complete configuration for the streamer
"""
# Start with global config
config = self.global_config.copy()
# Load streamer-specific config
streamer_file = self.streamers_dir / f"{username}.json"
if streamer_file.exists():
try:
with open(streamer_file, 'r', encoding='utf-8') as f:
streamer_config = json.load(f)
# Filter out comments and schema references
streamer_config = {k: v for k, v in streamer_config.items()
if not k.startswith('_') and k != '$schema'}
# Merge streamer config (overrides global)
config.update(streamer_config)
print(f'{Fore.GREEN}✓ Loaded config for {username}{Style.RESET_ALL}')
except json.JSONDecodeError as e:
print(f'{Fore.YELLOW}⚠ Warning: Invalid JSON in {streamer_file}: {e}{Style.RESET_ALL}')
except Exception as e:
print(f'{Fore.YELLOW}⚠ Warning: Could not load {streamer_file}: {e}{Style.RESET_ALL}')
else:
# Create default config for new streamer
print(f'{Fore.CYAN}→ Creating default config for new streamer: {username}{Style.RESET_ALL}')
self.create_default_streamer_config(username)
config['username'] = username
config['enabled'] = True
# Ensure username is set
config['username'] = username
return config
def create_default_streamer_config(self, username: str) -> None:
"""
Create a default configuration file for a new streamer.
Args:
username: Twitch username
"""
# Ensure streamers directory exists
self.streamers_dir.mkdir(parents=True, exist_ok=True)
streamer_file = self.streamers_dir / f"{username}.json"
default_config = {
"$schema": "../streamer.schema.json",
"username": username,
"enabled": True
}
try:
with open(streamer_file, 'w', encoding='utf-8') as f:
json.dump(default_config, f, indent=2)
print(f'{Fore.GREEN}✓ Created config file: config/streamers/{username}.json{Style.RESET_ALL}')
print(f'{Fore.CYAN} → Edit the file to add custom settings or overrides{Style.RESET_ALL}')
except Exception as e:
print(f'{Fore.RED}✗ Could not create config file for {username}: {e}{Style.RESET_ALL}')
def get_all_enabled_streamers(self) -> list:
"""
Get list of all enabled streamers.
Returns:
list: List of usernames configured and enabled
"""
if not self.streamers_dir.exists():
return []
enabled_streamers = []
for config_file in self.streamers_dir.glob("*.json"):
try:
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
# Filter comments and schema references
config = {k: v for k, v in config.items()
if not k.startswith('_') and k != '$schema'}
if config.get('enabled', False):
username = config.get('username') or config_file.stem
enabled_streamers.append(username)
except Exception as e:
print(f'{Fore.YELLOW}⚠ Warning: Could not read {config_file}: {e}{Style.RESET_ALL}')
return enabled_streamers