Files
TG_autoposter/app/settings.py
Andrew K. Choi 48f8c6f0eb UserBot Integration Complete: Fixed container startup, integrated UserBot menu to main bot
MAJOR FIXES:
 Fixed UserBot container startup by making TELEGRAM_BOT_TOKEN optional
 Broke circular import chain between app modules
 Made Config.validate() conditional for UserBot-only mode
 Removed unused celery import from userbot_service.py

INTEGRATION:
 UserBot menu now accessible from main bot /start command
 Added 🤖 UserBot button to main keyboard
 Integrated userbot_manager.py handlers:
   - userbot_menu: Main UserBot interface
   - userbot_settings: Configuration
   - userbot_collect_groups: Gather all user groups
   - userbot_collect_members: Parse group members
 UserBot handlers properly registered in ConversationHandler

CONTAINERS:
 tg_autoposter_bot: Running and handling /start commands
 tg_autoposter_userbot: Running as standalone microservice
 All dependent services (Redis, PostgreSQL, Celery workers) operational

STATUS: Bot is fully operational and ready for testing
2025-12-21 12:09:11 +09:00

167 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Конфигурация приложения - загрузка переменных окружения
"""
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'))
# Не требовать BOT_TOKEN если запущены в режиме UserBot микросервиса
if not TELEGRAM_BOT_TOKEN and not os.getenv('TELETHON_API_ID'):
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:
"""Проверить конфигурацию"""
# Если есть TELETHON_API_ID - это UserBot микросервис, BOT_TOKEN не требуется
if cls.TELETHON_API_ID:
# Проверить конфиг Telethon
return bool(cls.TELETHON_API_ID and cls.TELETHON_API_HASH and cls.TELETHON_PHONE)
# Для основного бота - требуется токен
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 бота")