""" Shared configuration for bot and web application """ from pydantic_settings import BaseSettings from typing import Optional import os class Settings(BaseSettings): """Application settings""" # Telegram Bot BOT_TOKEN: str TELEGRAM_API_ID: int TELEGRAM_API_HASH: str OWNER_ID: int # Authorization AUTHORIZED_USERS: str = "" ADMIN_IDS: str = "" BLOCKED_USERS: str = "" PRIVATE_MODE: bool = False # If True, only users from AUTHORIZED_USERS or database can use the bot # Database DATABASE_URL: str = "sqlite+aiosqlite:///./data/bot.db" # Redis (for sessions) REDIS_HOST: str = "localhost" REDIS_PORT: int = 6379 REDIS_DB: int = 0 USE_REDIS_SESSIONS: bool = False # Use Redis for sessions instead of in-memory # Web WEB_HOST: str = "0.0.0.0" WEB_PORT: int = 5000 WEB_SECRET_KEY: str = "" # Logging LOG_LEVEL: str = "INFO" LOG_FILE: str = "logs/bot.log" # Media Download COOKIES_FILE: Optional[str] = None # Path to cookies file (Netscape format) for Instagram and other sites # Download Limits MAX_FILE_SIZE: Optional[str] = None # Maximum file size in bytes (empty or None = no limit) MAX_DURATION_MINUTES: Optional[str] = None # Maximum duration in minutes (empty or None = no limit) MAX_CONCURRENT_TASKS: int = 5 # Maximum number of concurrent tasks per user @property def max_file_size_bytes(self) -> Optional[int]: """Get maximum file size in bytes""" if not self.MAX_FILE_SIZE or self.MAX_FILE_SIZE.strip() == '' or self.MAX_FILE_SIZE.lower() == 'none': return None try: return int(self.MAX_FILE_SIZE) except (ValueError, TypeError): return None @property def max_duration_minutes_int(self) -> Optional[int]: """Get maximum duration in minutes""" if not self.MAX_DURATION_MINUTES or self.MAX_DURATION_MINUTES.strip() == '' or self.MAX_DURATION_MINUTES.lower() == 'none': return None try: return int(self.MAX_DURATION_MINUTES) except (ValueError, TypeError): return None class Config: # Configuration file structure: # - .env - for Docker (used via docker-compose env_file) # - .env.local - for local development (used here if not in Docker) # In Docker, environment variables are passed through environment in docker-compose # env_file is only used for local development # In Docker, env_file should not be loaded as variables are passed through environment # Load .env.local only if not in Docker (determined by DOCKER_ENV environment variable) # In Docker, environment variables have priority over env_file # If DOCKER_ENV is set, do not load .env.local file env_file = None if os.getenv("DOCKER_ENV") else ".env.local" env_file_encoding = "utf-8" case_sensitive = True # Pydantic Settings automatically reads environment variables from system # Priority: environment variables > env_file > default values @property def authorized_users_list(self) -> list[int]: """List of authorized users""" if not self.AUTHORIZED_USERS: return [] return [int(uid.strip()) for uid in self.AUTHORIZED_USERS.split(",") if uid.strip()] @property def admin_ids_list(self) -> list[int]: """List of administrators""" if not self.ADMIN_IDS: return [] return [int(uid.strip()) for uid in self.ADMIN_IDS.split(",") if uid.strip()] @property def blocked_users_list(self) -> list[int]: """List of blocked users""" if not self.BLOCKED_USERS: return [] return [int(uid.strip()) for uid in self.BLOCKED_USERS.split(",") if uid.strip()] # Global settings instance settings = Settings() # Log the DATABASE_URL being used on load (for debugging) import logging _logger = logging.getLogger(__name__) # Log only if DATABASE_URL is not default SQLite if settings.DATABASE_URL and "sqlite" not in settings.DATABASE_URL.lower(): db_url_safe = settings.DATABASE_URL if '@' in db_url_safe: # Hide password in logs parts = db_url_safe.split('@') if len(parts) == 2: auth_part = parts[0].split('://') if len(auth_part) == 2: scheme = auth_part[0] user_pass = auth_part[1] if ':' in user_pass: user = user_pass.split(':')[0] db_url_safe = f"{scheme}://{user}:***@{parts[1]}" _logger.info(f"Using DATABASE_URL: {db_url_safe}") else: _logger.warning(f"⚠️ Using SQLite database: {settings.DATABASE_URL}. For Docker, use PostgreSQL!")