import asyncio import logging import pytz from datetime import datetime from pathlib import Path from aiogram import Bot, Dispatcher, executor, types from aiogram.dispatcher.filters import Text import config from main import start_parser logging.basicConfig( level=logging.INFO, filename="logs/bot.log", format="%(asctime)s - %(module)s - %(levelname)s - %(funcName)s: %(lineno)d - %(message)s", datefmt='%H:%M:%S', ) logger = logging.getLogger(__name__) TZ = pytz.timezone('Europe/Moscow') USER_LOG = Path("logs/users.log") UPDATE_INTERVAL = 300 # 5 минут в секундах bot = Bot(token=config.token) dp = Dispatcher(bot) async def periodic_update(): while True: logger.info("Запуск автоматического обновления данных...") try: start_parser() logger.info("Автоматическое обновление завершено") except Exception as e: logger.error(f"Ошибка при автоматическом обновлении: {e}") await asyncio.sleep(UPDATE_INTERVAL) @dp.message_handler(commands='start') async def cmd_start(message: types.Message): buttons = ['Плановые', 'Внерегламентные', 'Аварийные', 'Информация'] keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True) keyboard.add(*buttons) await message.answer('Выберите тип отключений:', reply_markup=keyboard) # Утилита для отправки файла async def send_file_content(message: types.Message, file_path: Path, empty_msg: str, log_msg: str): await message.answer("Обновляю...") if not file_path.exists() or file_path.stat().st_size == 0: await message.answer(empty_msg) else: text = file_path.read_text(encoding='utf-8') if len(text) > 4095: for i in range(0, len(text), 4095): await message.answer(text[i:i + 4095]) else: await message.answer(text) now = datetime.now(TZ).strftime('%d/%m/%Y %H:%M') username = message.from_user.username or f"id{message.from_user.id}" log_entry = f"{now} t.me/{username} получил инфу по {log_msg}.\n" USER_LOG.parent.mkdir(exist_ok=True) with USER_LOG.open('a', encoding='utf-8') as f: f.write(log_entry) logger.info(f"Пользователь {username} запросил {log_msg}") @dp.message_handler(Text(equals='Плановые')) async def plan(message: types.Message): await send_file_content( message, Path("plan.txt"), "[Нет плановых отключений]", "плановым отключениям" ) @dp.message_handler(Text(equals='Внерегламентные')) async def vnereglament(message: types.Message): await send_file_content( message, Path("vnereglament.txt"), "[Нет внерегламентных отключений]", "внерегламентным отключениям" ) @dp.message_handler(Text(equals='Аварийные')) async def avar(message: types.Message): await send_file_content( message, Path("avar.txt"), "[Нет аварийных отключений]", "аварийным отключениям" ) @dp.message_handler(Text(equals='Информация')) async def info(message: types.Message): await message.answer( "ℹ️ Информация МРСК Белгород по отключениям эл-ва (v2)\n\n" "✅ Данные обновляются автоматически каждые 5 минут.\n" "📩 Вопросы и предложения: @pikusQQ" ) @dp.message_handler() async def fallback(message: types.Message): await message.answer("Нажмите /start для начала работы.") # Webhook handlers async def on_startup(dp): await bot.set_webhook(config.URL_APP) # Запуск фоновой задачи после старта asyncio.create_task(periodic_update()) logger.info("Webhook установлен. Фоновое обновление запущено.") async def on_shutdown(dp): await bot.delete_webhook() logger.info("Webhook удалён") if __name__ == '__main__': executor.start_webhook( dispatcher=dp, webhook_path='', on_startup=on_startup, on_shutdown=on_shutdown, skip_updates=True, host='0.0.0.0', port=5000, )