From 26c3664978a21be8ba77d321b99c291f550da7e3 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Mon, 10 Nov 2025 05:47:35 +0500 Subject: Add .quote daily and .quote random command to retrieve quotes from zenquotes.io api (#1707) * feat: Add .quote and .daily_quote command to retrieve a random quote and the daily quote from the zenquotes.io api respectively * Implement caching for daily quote to minimize API requests. --------- Co-authored-by: Joe Banks --- bot/utils/quote.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 bot/utils/quote.py (limited to 'bot/utils') diff --git a/bot/utils/quote.py b/bot/utils/quote.py new file mode 100644 index 00000000..9324a732 --- /dev/null +++ b/bot/utils/quote.py @@ -0,0 +1,53 @@ +"""Utility functions for fetching quotes from ZenQuotes API.""" + +from datetime import UTC, datetime, timedelta + +from pydis_core.utils.logging import get_logger + +from bot.bot import Bot + +RANDOM_QUOTE_URL = "https://zenquotes.io/api/random" +DAILY_QUOTE_URL = "https://zenquotes.io/api/today" +DAILY_QUOTE_KEY="daily_quote" + +log = get_logger(__name__) + +def seconds_until_midnight_utc() -> int: + """Calculate the number of seconds remaining until midnight UTC for Redis cache TTL.""" + now = datetime.now(UTC) + tomorrow = now + timedelta(days=1) + midnight = tomorrow.replace(hour=0, minute=0, second=0, microsecond=0) + time_to_midnight = (midnight - now) + return int(time_to_midnight.total_seconds()) + + +async def random_quote(bot: Bot) -> str: + """Retrieve a random quote from ZenQuotes API.""" + async with bot.http_session.get(RANDOM_QUOTE_URL) as response: + response.raise_for_status() + data = await response.json() + quote = f"{data[0]['q']}\n*— {data[0]['a']}*" + return quote + + +async def daily_quote(bot: Bot) -> str: + """Retrieve the daily quote from ZenQuotes API, cached until 00:00 UTC.""" + redis = bot.redis_session.client + + cached_quote = await redis.get(DAILY_QUOTE_KEY) + if cached_quote: + log.debug("Using cached daily quote.") + return cached_quote + + log.debug("No cached quote found.") + async with bot.http_session.get(DAILY_QUOTE_URL) as resp: + resp.raise_for_status() + data = await resp.json() + quote = f"{data[0]['q']}\n*— {data[0]['a']}*" + + ttl = seconds_until_midnight_utc() + + await redis.set(DAILY_QUOTE_KEY, quote, ex=ttl) + log.info(f"Cached daily quote for {ttl} seconds.") + + return quote -- cgit v1.2.3