forked from zovos/bot_tg
auto send to smoke
This commit is contained in:
parent
8bc905331c
commit
6afc30570f
2 changed files with 85 additions and 1 deletions
86
main.py
86
main.py
|
|
@ -83,6 +83,84 @@ def minutes_until_break(now: datetime | None = None) -> str:
|
||||||
|
|
||||||
return "Пары закончились, перекур только завтра."
|
return "Пары закончились, перекур только завтра."
|
||||||
|
|
||||||
|
|
||||||
|
def next_break_window(now: datetime | None = None) -> tuple[datetime | None, datetime | None]:
|
||||||
|
"""Возвращает (начало, конец) ближайшего перекура или (None, None)."""
|
||||||
|
if now is None:
|
||||||
|
now = datetime.now(ZoneInfo(config.DEFAULT_TZ))
|
||||||
|
elif now.tzinfo is None:
|
||||||
|
now = now.replace(tzinfo=ZoneInfo(config.DEFAULT_TZ))
|
||||||
|
|
||||||
|
day = now.weekday()
|
||||||
|
today_schedule = config.SCHEDULE.get(day, [])
|
||||||
|
if not today_schedule:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
def dt_for(t: time) -> datetime:
|
||||||
|
return now.replace(hour=t.hour, minute=t.minute, second=0, microsecond=0)
|
||||||
|
|
||||||
|
for start_t, end_t, br_minutes in today_schedule:
|
||||||
|
if not br_minutes:
|
||||||
|
continue
|
||||||
|
end_dt = dt_for(end_t)
|
||||||
|
br_start = end_dt
|
||||||
|
br_end = end_dt + timedelta(minutes=br_minutes)
|
||||||
|
# Ближайший будущий или текущий перекур
|
||||||
|
if now < br_end:
|
||||||
|
return br_start, br_end
|
||||||
|
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
# --- Авто-напоминание о перекуре ---
|
||||||
|
_break_tasks: dict[int, tuple[datetime, asyncio.Task]] = {}
|
||||||
|
_break_notified: dict[int, datetime] = {}
|
||||||
|
|
||||||
|
|
||||||
|
async def _send_break_photo(chat_id: int, bot: Bot, start_dt: datetime) -> None:
|
||||||
|
last = _break_notified.get(chat_id)
|
||||||
|
if last and last == start_dt:
|
||||||
|
return # Уже кидали уведомление для этого слота
|
||||||
|
|
||||||
|
photo_path = config.BASE_DIR / "vape.jpg"
|
||||||
|
if not photo_path.exists():
|
||||||
|
logger.warning("vape.jpg not found, skip break photo")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
await bot.send_photo(chat_id=chat_id, photo=FSInputFile(photo_path), caption="идем курить")
|
||||||
|
_break_notified[chat_id] = start_dt
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to send break photo")
|
||||||
|
|
||||||
|
|
||||||
|
async def _break_notification(chat_id: int, bot: Bot, start_dt: datetime) -> None:
|
||||||
|
try:
|
||||||
|
now = datetime.now(start_dt.tzinfo)
|
||||||
|
delay = (start_dt - now).total_seconds()
|
||||||
|
if delay > 0:
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
await _send_break_photo(chat_id, bot, start_dt)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
stored = _break_tasks.get(chat_id)
|
||||||
|
if stored and stored[0] == start_dt:
|
||||||
|
_break_tasks.pop(chat_id, None)
|
||||||
|
|
||||||
|
|
||||||
|
def schedule_break_notification(chat_id: int, bot: Bot, start_dt: datetime) -> None:
|
||||||
|
existing = _break_tasks.get(chat_id)
|
||||||
|
if existing:
|
||||||
|
scheduled_start, task = existing
|
||||||
|
if scheduled_start == start_dt and not task.done():
|
||||||
|
return # Уже ждём этот же слот
|
||||||
|
if not task.done():
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
task = asyncio.create_task(_break_notification(chat_id, bot, start_dt))
|
||||||
|
_break_tasks[chat_id] = (start_dt, task)
|
||||||
|
|
||||||
# --- Работа с изображениями (Макеты и Мемы) ---
|
# --- Работа с изображениями (Макеты и Мемы) ---
|
||||||
|
|
||||||
def load_font(size: int) -> ImageFont.FreeTypeFont:
|
def load_font(size: int) -> ImageFont.FreeTypeFont:
|
||||||
|
|
@ -414,7 +492,13 @@ async def handle_start(message: Message):
|
||||||
await message.answer("Соси")
|
await message.answer("Соси")
|
||||||
|
|
||||||
async def handle_break_cmd(message: Message):
|
async def handle_break_cmd(message: Message):
|
||||||
await message.answer(minutes_until_break())
|
now = datetime.now(ZoneInfo(config.DEFAULT_TZ))
|
||||||
|
await message.answer(minutes_until_break(now))
|
||||||
|
|
||||||
|
# Ставим будильник на ближайший перекур для этого чата
|
||||||
|
start_dt, _ = next_break_window(now)
|
||||||
|
if start_dt:
|
||||||
|
schedule_break_notification(message.chat.id, message.bot, start_dt)
|
||||||
|
|
||||||
async def handle_penis_cmd(message: Message):
|
async def handle_penis_cmd(message: Message):
|
||||||
if not message.from_user:
|
if not message.from_user:
|
||||||
|
|
|
||||||
BIN
vape.jpg
Normal file
BIN
vape.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Loading…
Reference in a new issue