init commit

This commit is contained in:
2025-12-18 05:55:32 +09:00
commit a6817e487e
72 changed files with 13847 additions and 0 deletions

160
app/settings.py Normal file
View File

@@ -0,0 +1,160 @@
"""
Конфигурация приложения - загрузка переменных окружения
"""
import os
from pathlib import Path
from dotenv import load_dotenv
# Загрузить .env файл
env_path = Path(__file__).parent.parent / '.env'
load_dotenv(env_path)
class Config:
"""Базовая конфигурация"""
# ═══════════════════════════════════════════════════════════════
# TELEGRAM BOT
# ═══════════════════════════════════════════════════════════════
TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', '')
TELEGRAM_TIMEOUT = int(os.getenv('TELEGRAM_TIMEOUT', '30'))
if not TELEGRAM_BOT_TOKEN:
raise ValueError(
"❌ TELEGRAM_BOT_TOKEN не установлен в .env\n"
"Получите токен у @BotFather в Telegram"
)
# ═══════════════════════════════════════════════════════════════
# TELETHON (для групп, где боты не могут писать)
# ═══════════════════════════════════════════════════════════════
USE_TELETHON = os.getenv('USE_TELETHON', 'false').lower() == 'true'
TELETHON_API_ID = os.getenv('TELETHON_API_ID', '')
TELETHON_API_HASH = os.getenv('TELETHON_API_HASH', '')
TELETHON_PHONE = os.getenv('TELETHON_PHONE', '')
TELETHON_FLOOD_WAIT_MAX = int(os.getenv('TELETHON_FLOOD_WAIT_MAX', '60')) # Максимум ждать при FloodWait
if USE_TELETHON:
if not TELETHON_API_ID or not TELETHON_API_HASH or not TELETHON_PHONE:
raise ValueError(
"❌ Для использования Telethon нужны:\n"
" TELETHON_API_ID\n"
" TELETHON_API_HASH\n"
" TELETHON_PHONE\n"
"Получите их на https://my.telegram.org"
)
# ═══════════════════════════════════════════════════════════════
# DATABASE
# ═══════════════════════════════════════════════════════════════
DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite+aiosqlite:///./autoposter.db')
# Альтернативная конфигурация PostgreSQL
DB_USER = os.getenv('DB_USER')
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB_HOST = os.getenv('DB_HOST', 'localhost')
DB_PORT = os.getenv('DB_PORT', '5432')
DB_NAME = os.getenv('DB_NAME')
# Если указаны отдельные параметры, построить URL
if DB_USER and DB_PASSWORD and DB_NAME:
DATABASE_URL = (
f'postgresql+asyncpg://{DB_USER}:{DB_PASSWORD}'
f'@{DB_HOST}:{DB_PORT}/{DB_NAME}'
)
# ═══════════════════════════════════════════════════════════════
# LOGGING
# ═══════════════════════════════════════════════════════════════
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
LOG_MAX_SIZE = int(os.getenv('LOG_MAX_SIZE', '10485760'))
LOG_BACKUP_COUNT = int(os.getenv('LOG_BACKUP_COUNT', '5'))
# ═══════════════════════════════════════════════════════════════
# BOT SETTINGS
# ═══════════════════════════════════════════════════════════════
MAX_RETRIES = int(os.getenv('MAX_RETRIES', '3'))
RETRY_DELAY = int(os.getenv('RETRY_DELAY', '5'))
MIN_SEND_INTERVAL = float(os.getenv('MIN_SEND_INTERVAL', '0.5')) # Минимум между отправками
# ═══════════════════════════════════════════════════════════════
# PARSING SETTINGS
# ═══════════════════════════════════════════════════════════════
ENABLE_KEYWORD_PARSING = os.getenv('ENABLE_KEYWORD_PARSING', 'true').lower() == 'true'
GROUP_PARSE_INTERVAL = int(os.getenv('GROUP_PARSE_INTERVAL', '3600'))
MAX_MEMBERS_TO_LOAD = int(os.getenv('MAX_MEMBERS_TO_LOAD', '1000'))
# ═══════════════════════════════════════════════════════════════
# OPTIONAL SETTINGS
# ═══════════════════════════════════════════════════════════════
ENABLE_STATISTICS = os.getenv('ENABLE_STATISTICS', 'true').lower() == 'true'
MESSAGE_HISTORY_DAYS = int(os.getenv('MESSAGE_HISTORY_DAYS', '30'))
WEBHOOK_URL = os.getenv('WEBHOOK_URL')
WEBHOOK_PORT = int(os.getenv('WEBHOOK_PORT', '8443')) if os.getenv('WEBHOOK_PORT') else None
# ═══════════════════════════════════════════════════════════════
# CELERY & REDIS SETTINGS
# ═══════════════════════════════════════════════════════════════
REDIS_HOST = os.getenv('REDIS_HOST', 'redis')
REDIS_PORT = int(os.getenv('REDIS_PORT', '6379'))
REDIS_DB = int(os.getenv('REDIS_DB', '0'))
REDIS_PASSWORD = os.getenv('REDIS_PASSWORD', '')
# Построить URL Redis
if REDIS_PASSWORD:
CELERY_BROKER_URL = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'
CELERY_RESULT_BACKEND_URL = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB + 1}'
else:
CELERY_BROKER_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'
CELERY_RESULT_BACKEND_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB + 1}'
# ═══════════════════════════════════════════════════════════════
# MODES
# ═══════════════════════════════════════════════════════════════
BOT_MODE = 'bot' # 'bot' для бота, 'client' для Telethon клиента
USE_CLIENT_WHEN_BOT_FAILS = True # Использовать Telethon если бот не может отправить
@classmethod
def get_mode(cls) -> str:
"""Получить текущий режим работы"""
if cls.USE_TELETHON:
return 'hybrid' # Используем оба: бот и клиент
return cls.BOT_MODE
@classmethod
def get_database_url(cls) -> str:
"""Получить URL БД"""
return cls.DATABASE_URL
@classmethod
def validate(cls) -> bool:
"""Проверить конфигурацию"""
# Основное - токен бота
if not cls.TELEGRAM_BOT_TOKEN:
return False
# Если Telethon включен - проверить его конфиг
if cls.USE_TELETHON:
if not (cls.TELETHON_API_ID and cls.TELETHON_API_HASH and cls.TELETHON_PHONE):
return False
return True
# Создать экземпляр конфигурации
config = Config()
# Выводы при импорте
if config.get_mode() == 'hybrid':
import logging
logger = logging.getLogger(__name__)
logger.info("🔀 Гибридный режим: бот + Telethon клиент")
elif config.USE_TELETHON:
import logging
logger = logging.getLogger(__name__)
logger.info("📱 Режим Telethon клиента")
else:
import logging
logger = logging.getLogger(__name__)
logger.info("🤖 Режим Telegram бота")