""" Unified Configuration Manager Provides a single source of truth for all configuration values with a clear hierarchy: 1. Environment variables (highest priority) 2. .env file 3. Database settings 4. Hardcoded defaults (lowest priority) """ import os from pathlib import Path from typing import Any, Dict, Optional from functools import lru_cache from dotenv import load_dotenv # Load environment variables from .env file PROJECT_ROOT = Path(__file__).parent.parent.parent.parent ENV_PATH = PROJECT_ROOT / '.env' if ENV_PATH.exists(): load_dotenv(ENV_PATH) class Settings: """Centralized configuration settings""" # Project paths PROJECT_ROOT: Path = PROJECT_ROOT DB_PATH: Path = PROJECT_ROOT / 'database' / 'media_downloader.db' CONFIG_PATH: Path = PROJECT_ROOT / 'config' / 'settings.json' LOG_PATH: Path = PROJECT_ROOT / 'logs' TEMP_DIR: Path = PROJECT_ROOT / 'temp' COOKIES_DIR: Path = PROJECT_ROOT / 'cookies' DATA_DIR: Path = PROJECT_ROOT / 'data' VENV_BIN: Path = PROJECT_ROOT / 'venv' / 'bin' MEDIA_BASE_PATH: Path = Path(os.getenv("MEDIA_BASE_PATH", "/opt/immich/md")) REVIEW_PATH: Path = Path(os.getenv("REVIEW_PATH", "/opt/immich/review")) RECYCLE_PATH: Path = Path(os.getenv("RECYCLE_PATH", "/opt/immich/recycle")) # External tool paths (use venv by default) YT_DLP_PATH: Path = VENV_BIN / 'yt-dlp' GALLERY_DL_PATH: Path = VENV_BIN / 'gallery-dl' PYTHON_PATH: Path = VENV_BIN / 'python3' # Database configuration DATABASE_BACKEND: str = os.getenv("DATABASE_BACKEND", "sqlite") DATABASE_URL: str = os.getenv("DATABASE_URL", "") DB_POOL_SIZE: int = int(os.getenv("DB_POOL_SIZE", "20")) DB_CONNECTION_TIMEOUT: float = float(os.getenv("DB_CONNECTION_TIMEOUT", "30.0")) # Process timeouts (seconds) PROCESS_TIMEOUT_SHORT: int = int(os.getenv("PROCESS_TIMEOUT_SHORT", "2")) PROCESS_TIMEOUT_MEDIUM: int = int(os.getenv("PROCESS_TIMEOUT_MEDIUM", "10")) PROCESS_TIMEOUT_LONG: int = int(os.getenv("PROCESS_TIMEOUT_LONG", "120")) # WebSocket configuration WEBSOCKET_TIMEOUT: float = float(os.getenv("WEBSOCKET_TIMEOUT", "30.0")) # Background task intervals (seconds) ACTIVITY_LOG_INTERVAL: int = int(os.getenv("ACTIVITY_LOG_INTERVAL", "300")) EMBEDDING_QUEUE_CHECK_INTERVAL: int = int(os.getenv("EMBEDDING_QUEUE_CHECK_INTERVAL", "30")) EMBEDDING_BATCH_SIZE: int = int(os.getenv("EMBEDDING_BATCH_SIZE", "10")) EMBEDDING_BATCH_LIMIT: int = int(os.getenv("EMBEDDING_BATCH_LIMIT", "50000")) # Thumbnail generation THUMBNAIL_DB_TIMEOUT: float = float(os.getenv("THUMBNAIL_DB_TIMEOUT", "30.0")) THUMBNAIL_SIZE: tuple = (300, 300) # Video proxy configuration PROXY_FILE_CACHE_DURATION: int = int(os.getenv("PROXY_FILE_CACHE_DURATION", "300")) # Redis cache configuration REDIS_HOST: str = os.getenv("REDIS_HOST", "127.0.0.1") REDIS_PORT: int = int(os.getenv("REDIS_PORT", "6379")) REDIS_DB: int = int(os.getenv("REDIS_DB", "0")) REDIS_TTL: int = int(os.getenv("REDIS_TTL", "300")) # API configuration API_VERSION: str = "13.13.1" API_TITLE: str = "Media Downloader API" API_DESCRIPTION: str = "Web API for managing media downloads" # CORS configuration ALLOWED_ORIGINS: list = os.getenv( "ALLOWED_ORIGINS", "http://localhost:5173,http://localhost:3000,http://127.0.0.1:5173,http://127.0.0.1:3000" ).split(",") # Security SECURE_COOKIES: bool = os.getenv("SECURE_COOKIES", "false").lower() == "true" SESSION_SECRET_KEY: str = os.getenv("SESSION_SECRET_KEY", "") CSRF_SECRET_KEY: str = os.getenv("CSRF_SECRET_KEY", "") # Rate limiting RATE_LIMIT_DEFAULT: str = os.getenv("RATE_LIMIT_DEFAULT", "100/minute") RATE_LIMIT_STRICT: str = os.getenv("RATE_LIMIT_STRICT", "10/minute") @classmethod def get(cls, key: str, default: Any = None) -> Any: """Get a configuration value by key""" return getattr(cls, key, default) @classmethod def get_path(cls, key: str) -> Path: """Get a path configuration value, ensuring it's a Path object""" value = getattr(cls, key, None) if value is None: raise ValueError(f"Configuration key {key} not found") if isinstance(value, Path): return value return Path(value) @lru_cache() def get_settings() -> Settings: """Get cached settings instance""" return Settings() # Convenience exports settings = get_settings()