Refactor code structure for improved readability and maintainability
This commit is contained in:
parent
efb320eb05
commit
e078cada3b
11 changed files with 1640 additions and 1184 deletions
158
modules/config.py
Normal file
158
modules/config.py
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue