""" Application configuration using Pydantic Settings """ from pydantic_settings import BaseSettings from pydantic import BaseModel, Field from typing import List, Optional import os import yaml from pathlib import Path class ThumbnailSettings(BaseModel): """Thumbnail generation settings""" small: int = 240 medium: int = 640 large: int = 1280 quality: int = 85 format: str = "webp" class ScannerSettings(BaseModel): """File scanner settings""" watch: bool = True initial_scan_on_start: bool = True batch_size: int = 100 concurrent_workers: int = 4 class SourceRoot(BaseModel): """Source root directory configuration""" name: str path: str class TrashSettings(BaseModel): """Trash settings""" path: str = "/data/trash" auto_empty_days: Optional[int] = 30 class PerformanceSettings(BaseModel): """Performance tuning settings""" max_concurrent_thumbnails: int = 10 cache_ttl: int = 3600 db_pool_size: int = 20 db_pool_recycle: int = 3600 class MulitaConfig(BaseModel): """Main configuration from YAML file""" source_roots: List[SourceRoot] = [] thumbnails: ThumbnailSettings = ThumbnailSettings() scanner: ScannerSettings = ScannerSettings() trash: TrashSettings = TrashSettings() performance: PerformanceSettings = PerformanceSettings() class Settings(BaseSettings): """Application settings""" # Database database_url: str = Field( default="sqlite+aiosqlite:///data/db/mulita.db", env="DATABASE_URL" ) # Redis redis_url: str = Field( default="redis://localhost:6379", env="REDIS_URL" ) # Celery celery_broker_url: str = Field( default="redis://localhost:6379", env="CELERY_BROKER_URL" ) celery_result_backend: str = Field( default="redis://localhost:6379", env="CELERY_RESULT_BACKEND" ) # Photo directories photo_dirs: str = Field( default="/photos", env="PHOTO_DIRS" ) # API settings api_host: str = Field(default="0.0.0.0", env="API_HOST") api_port: int = Field(default=8000, env="API_PORT") # App configuration from YAML _config: Optional[MulitaConfig] = None @property def config(self) -> MulitaConfig: """Load configuration from YAML file""" if self._config is None: config_path = Path("/app/config/mulita.yml") if not config_path.exists(): config_path = Path("mulita.yml") if config_path.exists(): with open(config_path, "r") as f: config_data = yaml.safe_load(f) self._config = MulitaConfig(**config_data) else: self._config = MulitaConfig() return self._config @property def thumbnails(self) -> ThumbnailSettings: return self.config.thumbnails @property def scanner(self) -> ScannerSettings: return self.config.scanner @property def trash(self) -> TrashSettings: return self.config.trash @property def performance(self) -> PerformanceSettings: return self.config.performance @property def source_roots(self) -> List[SourceRoot]: return self.config.source_roots class Config: env_file = ".env" case_sensitive = False # Global settings instance settings = Settings()