I add command /prasp

It's version 0.2.2
This commit is contained in:
Niken
2025-10-05 22:29:49 +03:00
parent c5f6da31ba
commit 3ef1327b67
4 changed files with 89 additions and 14 deletions
-1
View File
@@ -24,7 +24,6 @@ class TelegramBot:
#add addons #add addons
self.addons.load("example_addon") self.addons.load("example_addon")
self.addons.load("id") self.addons.load("id")
self.addons.load("dowloadmp4_to_youtube")
async def start(self): async def start(self):
"""Запуск бота""" """Запуск бота"""
+19 -1
View File
@@ -19,7 +19,25 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
day_offset = int(args[2]) if len(args) > 2 and args[2].isdigit() else 0 day_offset = int(args[2]) if len(args) > 2 and args[2].isdigit() else 0
schedule_service = ScheduleService() schedule_service = ScheduleService()
clip_png, url, day, mouth = await schedule_service.get_schedule(group, day_offset) text, url, day, month = await schedule_service.get_schedule(group, day_offset)
# Отправляем текст расписания
msg = await message.answer(text, parse_mode="Markdown")
save_message(message.chat.id, msg.message_id)
@dp.message(Command("prasp"))
async def send_schedule(message: types.Message):
"""Отправка расписания"""
if is_chat_spam(message.chat.id, state):
await message.answer("НЕ СПАМЬТЕ!!!")
return
args = message.text.split(maxsplit=2)
group = args[1].strip() if len(args) > 1 else "30тс"
day_offset = int(args[2]) if len(args) > 2 and args[2].isdigit() else 0
schedule_service = ScheduleService()
clip_png, url, day, mouth = await schedule_service.get_pschedule(group, day_offset)
if clip_png: if clip_png:
save_message(message.chat.id, message.message_id) save_message(message.chat.id, message.message_id)
+61 -2
View File
@@ -1,8 +1,11 @@
import hashlib
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional, Tuple from typing import Optional, Tuple
from playwright.async_api import async_playwright, ViewportSize, FloatRect from playwright.async_api import async_playwright, ViewportSize, FloatRect
import logging import logging
import aiohttp
from bs4 import BeautifulSoup
import ssl
import certifi
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -23,7 +26,63 @@ class ScheduleService:
else: else:
return self.base_url.format(day=int(day), mouth=d.month), int(day), int(d.month) return self.base_url.format(day=int(day), mouth=d.month), int(day), int(d.month)
async def get_schedule(self, group: str, day_offset: int = 0) -> Tuple[Optional[bytes], str, int, int]: async def get_schedule(
self, group: str, day_offset: int = 0
) -> Tuple[str, str, int, int]:
"""Получение текста расписания (аналог Rust parse_schedule)"""
url, day, month = self._make_url(day_offset)
ssl_context = ssl.create_default_context(cafile=certifi.where())
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
connector = aiohttp.TCPConnector(ssl=ssl_context)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
}
# тут можно использовать aiohttp + chardet/charset_normalizer
async with aiohttp.ClientSession(connector=connector, headers=headers) as session:
async with session.get(url) as resp:
raw_bytes = await resp.read()
decoded = raw_bytes.decode("cp1251", errors="ignore")
document = BeautifulSoup(decoded, "html.parser")
# ищем <p class="MsoPlainText"><b>...</b>
elements = document.select("p.MsoPlainText b")
found_group = False
schedule_lines = []
for el in elements:
text = el.get_text(strip=True)
if not found_group:
if group in text:
found_group = True
schedule_lines.append(text)
else:
if "-----" in text or "+----" in text:
break
schedule_lines.append(text)
if not schedule_lines:
result = f"Расписание для группы {group} на {day} число не найдено"
else:
result = f"📅 Расписание для {day} числа:\n```\n"
for line in schedule_lines:
formatted = (
line.replace("¦", "")
.replace(" ", " ")
.strip()
)
if formatted:
result += f"{formatted}\n"
result += "```"
return result, url, day, month
async def get_pschedule(self, group: str, day_offset: int = 0) -> Tuple[Optional[bytes], str, int, int]:
"""Получение скриншота расписания""" """Получение скриншота расписания"""
url, day, month = self._make_url(day_offset) url, day, month = self._make_url(day_offset)
+9 -10
View File
@@ -2,7 +2,6 @@ import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
from random import randint from random import randint
from aiogram import Bot from aiogram import Bot
from aiogram.types import BufferedInputFile
from models.state import BotState from models.state import BotState
from config import Config from config import Config
from services.schedule_service import ScheduleService from services.schedule_service import ScheduleService
@@ -74,21 +73,21 @@ class WatcherService:
async def _check_group_schedule(self, group: str, chat_id: int, day: int): async def _check_group_schedule(self, group: str, chat_id: int, day: int):
"""Проверка расписания для конкретной группы""" """Проверка расписания для конкретной группы"""
clip_png, url, data_day, data_mouth = await self.schedule_service.get_schedule(group, day) text, url, data_day, data_month = await self.schedule_service.get_schedule(group, day)
if clip_png:
msg = await self.bot.send_photo( if text and "не найдено" not in text.lower():
msg = await self.bot.send_message(
chat_id, chat_id,
BufferedInputFile(clip_png, filename=f"{group}.png"), f"Авто-расписание для {group} на {data_day:02d}.{data_month:02d}\n\n{text}",
caption=f"Авто-расписание для {group} на {data_day:02d}.{data_mouth:02d}" parse_mode="Markdown"
) )
await self.bot.pin_chat_message(chat_id, msg.message_id, disable_notification=True) await self.bot.pin_chat_message(chat_id, msg.message_id, disable_notification=True)
else: else:
logger.warning(f"Не удалось получить расписание для {group}, {data_day}, {data_mouth}, {url}") logger.warning(
f"Не удалось получить расписание для {group}, {data_day}, {data_month}, {url}"
)
return return
#clip_hash = hashlib.md5(clip_png).hexdigest() #clip_hash = hashlib.md5(clip_png).hexdigest()
# Логика проверки изменений и отправки сообщений # Логика проверки изменений и отправки сообщений