Compare commits

...

1 commit

2 changed files with 119 additions and 52 deletions

43
Schedule.json Normal file
View file

@ -0,0 +1,43 @@
{
"0": [
[9, 50, 10, 35, 5],
[10, 40, 11, 25, 30],
[11, 55, 12, 40, 5],
[12, 45, 13, 30, 15],
[13, 45, 14, 30, 5],
[14, 35, 15, 20, 30],
[15, 50, 16, 35, 5],
[16, 40, 17, 25, null]
],
"1": [
[9, 50, 10, 35, 5],
[10, 40, 11, 25, 30],
[11, 55, 12, 40, 5],
[12, 45, 13, 30, 15],
[13, 45, 14, 30, 5],
[14, 35, 15, 20, null]
],
"2": [],
"3": [
[8, 0, 8, 45, 5],
[8, 50, 9, 35, 15],
[9, 50, 10, 35, 5],
[10, 40, 11, 25, 30],
[11, 55, 12, 40, 5],
[12, 45, 13, 30, 15],
[13, 45, 14, 30, 5],
[14, 35, 15, 20, 30],
[15, 50, 16, 35, 5],
[16, 40, 17, 25, null]
],
"4": [
[9, 50, 10, 35, 5],
[10, 40, 11, 25, 30],
[11, 55, 12, 40, 5],
[12, 45, 13, 30, 15],
[13, 45, 14, 30, 5],
[14, 35, 15, 20, null]
],
"5": [],
"6": []
}

128
main.py
View file

@ -1,11 +1,12 @@
import asyncio import asyncio
import json
import logging import logging
import os import os
import re import re
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
from textwrap import wrap
import random import random
from typing import Any
from aiogram import Bot, Dispatcher, F, types from aiogram import Bot, Dispatcher, F, types
from aiogram.enums import ParseMode from aiogram.enums import ParseMode
@ -40,54 +41,80 @@ def templates_list_text() -> str:
# ---- Schedule & breaks ---- # ---- Schedule & breaks ----
def make_time(h: int, m: int) -> time: def _ensure_int(value: Any, field_name: str, day: int, lesson_idx: int) -> int:
return time(hour=h, minute=m) if isinstance(value, bool) or not isinstance(value, int):
raise ValueError(
f"Invalid {field_name} in day {day}, lesson #{lesson_idx + 1}: expected integer, got {value!r}"
)
return value
# Schedule format: list of (lesson_start, lesson_end, break_minutes_after) def load_schedule_from_json(file_path: str | Path = BASE_DIR / "Schedule.json") -> dict[int, list[tuple[time, time, int | None]]]:
SCHEDULE: dict[int, list[tuple[time, time, int | None]]] = { path = Path(file_path)
0: [ # Monday if not path.is_absolute():
(make_time(9, 50), make_time(10, 35), 5), path = BASE_DIR / path
(make_time(10, 40), make_time(11, 25), 30),
(make_time(11, 55), make_time(12, 40), 5), with path.open("r", encoding="utf-8") as f:
(make_time(12, 45), make_time(13, 30), 15), try:
(make_time(13, 45), make_time(14, 30), 5), raw_data = json.load(f)
(make_time(14, 35), make_time(15, 20), 30), except json.JSONDecodeError as exc:
(make_time(15, 50), make_time(16, 35), 5), raise ValueError(f"Invalid JSON in schedule file {path}: {exc}") from exc
(make_time(16, 40), make_time(17, 25), None),
], if not isinstance(raw_data, dict):
1: [ # Tuesday raise ValueError(f"Schedule JSON root must be an object, got: {type(raw_data).__name__}")
(make_time(9, 50), make_time(10, 35), 5),
(make_time(10, 40), make_time(11, 25), 30), formatted_schedule: dict[int, list[tuple[time, time, int | None]]] = {day: [] for day in range(7)}
(make_time(11, 55), make_time(12, 40), 5),
(make_time(12, 45), make_time(13, 30), 15), for day_key, lessons in raw_data.items():
(make_time(13, 45), make_time(14, 30), 5), try:
(make_time(14, 35), make_time(15, 20), None), day = int(day_key)
], except (TypeError, ValueError) as exc:
2: [], # Wednesday — кайфуем дома raise ValueError(f"Day key must be an integer from 0 to 6, got: {day_key!r}") from exc
3: [ # Thursday
(make_time(8, 0), make_time(8, 45), 5), if day < 0 or day > 6:
(make_time(8, 50), make_time(9, 35), 15), raise ValueError(f"Day key must be in range 0..6, got: {day}")
(make_time(9, 50), make_time(10, 35), 5),
(make_time(10, 40), make_time(11, 25), 30), if not isinstance(lessons, list):
(make_time(11, 55), make_time(12, 40), 5), raise ValueError(f"Lessons for day {day} must be a list, got: {type(lessons).__name__}")
(make_time(12, 45), make_time(13, 30), 15),
(make_time(13, 45), make_time(14, 30), 5), parsed_lessons: list[tuple[time, time, int | None]] = []
(make_time(14, 35), make_time(15, 20), 30), for idx, lesson in enumerate(lessons):
(make_time(15, 50), make_time(16, 35), 5), if not isinstance(lesson, list) or len(lesson) != 5:
(make_time(16, 40), make_time(17, 25), None), raise ValueError(
], f"Day {day}, lesson #{idx + 1} must be [start_h, start_m, end_h, end_m, break_minutes]"
4: [ # Friday )
(make_time(9, 50), make_time(10, 35), 5),
(make_time(10, 40), make_time(11, 25), 30), start_h = _ensure_int(lesson[0], "start_h", day, idx)
(make_time(11, 55), make_time(12, 40), 5), start_m = _ensure_int(lesson[1], "start_m", day, idx)
(make_time(12, 45), make_time(13, 30), 15), end_h = _ensure_int(lesson[2], "end_h", day, idx)
(make_time(13, 45), make_time(14, 30), 5), end_m = _ensure_int(lesson[3], "end_m", day, idx)
(make_time(14, 35), make_time(15, 20), None),
], break_minutes_raw = lesson[4]
5: [], # Saturday — выходной if break_minutes_raw is None:
6: [], # Sunday — выходной break_minutes = None
} else:
break_minutes = _ensure_int(break_minutes_raw, "break_minutes", day, idx)
if break_minutes < 0:
raise ValueError(f"Day {day}, lesson #{idx + 1}: break_minutes must be >= 0")
try:
start_t = time(start_h, start_m)
end_t = time(end_h, end_m)
except ValueError as exc:
raise ValueError(f"Day {day}, lesson #{idx + 1}: invalid lesson time") from exc
if (end_h, end_m) <= (start_h, start_m):
raise ValueError(f"Day {day}, lesson #{idx + 1}: end time must be after start time")
parsed_lessons.append((start_t, end_t, break_minutes))
parsed_lessons.sort(key=lambda item: (item[0].hour, item[0].minute))
formatted_schedule[day] = parsed_lessons
return formatted_schedule
# Теперь заменяем глобальный словарь SCHEDULE:
SCHEDULE = load_schedule_from_json()
def minutes_until_break(now: datetime | None = None) -> str: def minutes_until_break(now: datetime | None = None) -> str:
@ -364,7 +391,6 @@ async def handle_gen_mem(message: Message, bot: Bot):
await message.reply_photo(BufferedInputFile(output.getvalue(), filename="meme.jpg")) await message.reply_photo(BufferedInputFile(output.getvalue(), filename="meme.jpg"))
<<<<<<< HEAD
async def handle_size(message: Message): async def handle_size(message: Message):
size = round(random.uniform(0.1, 35.0), 1) size = round(random.uniform(0.1, 35.0), 1)
@ -385,8 +411,7 @@ async def handle_size(message: Message):
f"📏 Твой хуек: {size} см\n" f"📏 Твой хуек: {size} см\n"
f"Ты: {status}" f"Ты: {status}"
) )
======= KEYWORDS_CREEP = {'крип', 'радиохэд', 'creep', 'radiohead'}
KEYWORDS = {'крип', 'радиохэд', 'creep', 'radiohead'}
# I'M CREEP # I'M CREEP
async def handle_keywords(message: types.Message): async def handle_keywords(message: types.Message):
@ -395,7 +420,7 @@ async def handle_keywords(message: types.Message):
text = message.text.lower() text = message.text.lower()
if any(re.search(rf'\b{word}\b', text) for word in KEYWORDS): if any(re.search(rf'\b{word}\b', text) for word in KEYWORDS_CREEP):
audio_path = BASE_DIR / "maket" / "Radiohead - Creep.mp3" audio_path = BASE_DIR / "maket" / "Radiohead - Creep.mp3"
if audio_path.exists(): if audio_path.exists():
@ -405,7 +430,6 @@ async def handle_keywords(message: types.Message):
) )
else: else:
logger.warning(f"Файл не найден по пути: {audio_path}") logger.warning(f"Файл не найден по пути: {audio_path}")
>>>>>>> SUDOZOVCHIK-CREEP-FUNCTION
def main(): def main():