Files
LGBot/src/main.py

184 lines
7.7 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.

from telebot.async_telebot import AsyncTeleBot
from telebot.asyncio_handler_backends import BaseMiddleware
import asyncio
import os
import sys
import importlib
from dotenv import load_dotenv
import logging
from logger import setup_logging
from database import db
from action_reporter import init_action_reporter
from config import MODULES_DIR
# Загружаем токен бота из .env
load_dotenv()
# Валидация переменных окружения
def validate_env_vars():
"""Проверяет наличие всех необходимых переменных окружения"""
required_vars = {
"BOT_TOKEN": "Токен бота",
"ADMIN_CHAT_ID": "ID админ-чата",
"LOG_THREAD_ID": "ID топика для логов"
}
missing_vars = []
for var_name, description in required_vars.items():
value = os.getenv(var_name)
if not value or value.strip() == "" or value == "...":
missing_vars.append(f"{var_name} ({description})")
if missing_vars:
print("\n❌ ОШИБКА: Не заполнены необходимые переменные окружения в файле .env:")
for var in missing_vars:
print(f"{var}")
print("\nПожалуйста, заполните файл .env на основе .env.example")
sys.exit(1)
# Проверяем переменные окружения
validate_env_vars()
bot = AsyncTeleBot(os.getenv("BOT_TOKEN"), parse_mode="html")
# Загружаем ID админ-чата из .env и инициализируемся для логов в чат
init_action_reporter(bot, os.getenv("ADMIN_CHAT_ID"), os.getenv("LOG_THREAD_ID"))
# Получаем логгер для текущего модуля
logger = logging.getLogger(__name__)
# Middleware для автоматического обновления информации о пользователях в базе данных
class UserUpdateMiddleware(BaseMiddleware):
def __init__(self, db):
super().__init__()
# message - все обычные сообщения
# chat_member - события изменения статуса участников чата
self.update_types = ['message', 'chat_member']
self.db = db
# Обработчик, вызываемый ДО обработки сообщения основными хэндлерами
async def pre_process(self, message, data):
# Логируем ВСЕ входящие сообщения для отладки
logger.info(f"[MIDDLEWARE] Получено сообщение от {message.from_user.id}, тип: {message.content_type}, текст: {message.text if hasattr(message, 'text') else 'N/A'}")
# Обработка пользователей, отправившие сообщение
if message.content_type == 'text':
self.db.add_or_update_user(
user_id=message.from_user.id,
nickname=message.from_user.first_name,
tag=message.from_user.username
)
# Обработка новых участников группы
elif message.content_type == 'new_chat_members':
for new_member in message.new_chat_members:
self.db.add_or_update_user(
user_id=new_member.id,
nickname=new_member.first_name,
tag=new_member.username
)
return data
# Обработчик, вызываемый ПОСЛЕ обработки сообщения основными хэндлерами
async def post_process(self, message, data, exception):
pass
# Регистрируем middleware
bot.setup_middleware(UserUpdateMiddleware(db))
# Загружает все модули из директории /modules
async def load_modules():
# Переменная для подсчёта модулей
loaded_count = 0
# Импортируем относительный путь проекта
modules_path = os.path.join(os.path.dirname(__file__), MODULES_DIR)
for filename in os.listdir(modules_path):
# Если файл содержит в конце .py (кроме __init__.py)
if filename.endswith(".py") and filename != "__init__.py":
# Убираем расширение .py
module_name = filename[:-3]
try:
# Импортируем модуль (modules.start)
module = importlib.import_module(f"{MODULES_DIR}.{module_name}")
# Если присутствует register_handlers
if hasattr(module, "register_handlers"):
module.register_handlers(bot)
loaded_count += 1
logger.info(f"Модуль {module_name} успешно загружен.")
# Если нет register_handlers
else:
# Записываем действие в логи
logger.warning(f"Модуль {module_name} не содержит функцию register_handlers.")
except Exception as e:
# Записываем ошибку в логи
logger.error(f"Ошибка при загрузке модуля {module_name}: {str(e)}")
# Записываем отчет о модулях в логи
logger.info(f"Загружено модулей: {loaded_count} шт. Бот запущен.")
# Устанавливаем меню команд бота
async def setup_bot_commands():
from telebot.types import BotCommand
commands = [
BotCommand("start", "Начало работы с ботом"),
BotCommand("help", "Справка по всем командам"),
BotCommand("log", "Инструкция по созданию лога ошибки"),
BotCommand("warn", "Выдать предупреждение. Использование: /warn help"),
BotCommand("ban", "Забанить пользователя. Использование: /ban help"),
BotCommand("unban", "Разбанить пользователя. Использование: /unban help"),
BotCommand("mute", "Замутить пользователя. Использование: /mute help"),
BotCommand("unmute", "Размутить пользователя. Использование: /unmute help"),
BotCommand("badwords", "Управление списком бранных слов. /badwords help"),
BotCommand("reset_violations", "Сбросить счётчик нарушений пользователя"),
BotCommand("botdata", "Получить данные бота (только для админов)"),
]
await bot.set_my_commands(commands)
logger.info("Команды бота успешно установлены.")
async def main():
# Инициализация логирования (должна быть первой)
setup_logging()
# Очищаем терминал
os.system('clear')
try:
# Проверяем и загружаем модули
await load_modules()
# Устанавливаем команды бота
await setup_bot_commands()
# Запускаем бота
await bot.infinity_polling()
except Exception as e:
# Записываем критическую ошибку в логи
logger.critical(f"Критическая ошибка: {str(e)}")
# Завершаем скрипт с критической ошибкой
sys.exit(1)
if __name__ == "__main__":
asyncio.run(main())