132 lines
4.7 KiB
Python
132 lines
4.7 KiB
Python
"""
|
|
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!")
|
|
|