"""Утилита для запуска утреннего дайджеста.""" import asyncio import logging from datetime import datetime, timedelta import discord from discord.ext import tasks from utils.pogoda import fetch_weather, pressure_to_mmhg, translate_weather from utils.news import fetch_rss, format_articles, RSS_URL_ARTICLES, RSS_URL_POSTS from utils.cat import fetch_cat logger = logging.getLogger(__name__) async def run_morning(bot: "commands.Bot", channel: discord.TextChannel): """Выполнить утренний дайджест и отправить в канал.""" try: api_url = "https://wttr.in/Magnitogorsk?format=j1&lang=ru" # Параллельный запрос погоды, новостей и котика weather_data, articles, posts, cat_url = await asyncio.gather( fetch_weather(api_url), fetch_rss(RSS_URL_ARTICLES), fetch_rss(RSS_URL_POSTS), fetch_cat(), ) # --- Формируем embed --- embed = discord.Embed(title="🌅 Утренний дайджест!", color=0xF4A460) # Котик как thumbnail if cat_url: embed.set_thumbnail(url=cat_url) description_lines = [] # --- Погода --- if weather_data is not None: current = weather_data.get("current_condition", [{}])[0] if current: temp = current.get("temp_C", "—") feels_like = current.get("FeelsLikeC", "—") description = translate_weather(current.get("weatherDesc", [{}])[0].get("value", "—")) humidity = current.get("humidity", "—") wind_kmh = current.get("windspeedKmph", "—") try: wind = round(int(wind_kmh) / 3.6, 1) if wind_kmh != "—" else "—" except (ValueError, TypeError): wind = "—" pressure_mb = current.get("pressure", "—") pressure_mm = pressure_to_mmhg(pressure_mb) description_lines.append( f"**Погода в Магнитогорске:**\n" f"Температура: {temp}°C (ощущается как {feels_like}°C)\n" f"Описание: {description}\n" f"Влажность: {humidity}%\n" f"Ветер: {wind} м/с\n" f"Давление: {pressure_mm} мм рт. ст." ) else: description_lines.append("Не удалось получить данные о погоде.") else: description_lines.append("Не удалось получить данные о погоде.") description_lines.append("") # --- Новости: статьи --- if articles is not None: if articles: lines = format_articles(articles, "Лучшие статьи за сутки / Искусственный интеллект / Хабr", "https://habr.com/ru/hubs/artificial_intelligence/articles/top/daily/") description_lines.append("\n".join(lines)) else: description_lines.append("Новостей пока нет.") else: description_lines.append("Не удалось получить новости.") description_lines.append("") # --- Новости: посты --- if posts is not None: if posts: lines = format_articles(posts, "Лучшие новости за сутки / Искусственный интеллект / Хабr", "https://habr.com/ru/hubs/artificial_intelligence/news/top/daily/") description_lines.append("\n".join(lines)) else: description_lines.append("Новостей пока нет.") else: description_lines.append("Не удалось получить новости.") embed.description = "\n".join(description_lines) await channel.send(embed=embed) logger.info("✅ Утренний дайджест отправлен в #%s", channel.name) except Exception as e: logger.error("Ошибка при выполнении утреннего дайджеста: %s", e, exc_info=True) try: await channel.send("❌ Не удалось выполнить утренний дайджест.") except Exception: pass class Scheduler: """Планировщик ежедневных задач.""" def __init__(self, bot: commands.Bot, morning_time: str = "07:00"): self.bot = bot self.morning_time = morning_time self._last_run_date = None self.morning_loop = tasks.loop(seconds=1.0)(self._check_and_run_morning) self._start_scheduler() def _start_scheduler(self): try: self.morning_loop.start() logger.info("Планировщик запущен (время: %s)", self.morning_time) except RuntimeError: logger.warning("Планировщик уже запущен") def _stop_scheduler(self): try: self.morning_loop.stop() logger.info("Планировщик остановлен") except RuntimeError: logger.warning("Планировщик уже остановлен") def _calculate_next_run(self) -> datetime: now = datetime.now() hour, minute = map(int, self.morning_time.split(":")) today_run = now.replace(hour=hour, minute=minute, second=0, microsecond=0) if now >= today_run: return today_run + timedelta(days=1) return today_run async def _check_and_run_morning(self): now = datetime.now() target = self._calculate_next_run() if now >= target and now.day != self._last_run_date: self._last_run_date = now.day await self._run_morning() async def _run_morning(self): logger.info(f"Выполняю morning в {self.morning_time}") for channel in self.bot.get_all_channels(): if isinstance(channel, discord.TextChannel): if channel.permissions_for(channel.guild.me).send_messages: try: await channel.send("🌅 Утренний дайджест!") await run_morning(self.bot, channel) return except Exception as e: logger.error("Ошибка отправки в #%s: %s", channel.name, e) continue def start(self): self._start_scheduler() def stop(self): self._stop_scheduler()