From e5d1672f0cdef03ade46363f559a79cf8f612c38 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Mon, 3 Nov 2025 11:23:35 +0500 Subject: [PATCH 01/13] feat: Add .quote and .daily_quote command to retrieve a random quote and the daily quote from the zenquotes.io api respectively --- bot/exts/fun/fun.py | 17 +++++++++++++++++ bot/utils/quote.py | 28 ++++++++++++++++++++++++++++ pyproject.toml | 1 + 3 files changed, 46 insertions(+) create mode 100644 bot/utils/quote.py diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py index 66c4851729..2dc856edbd 100644 --- a/bot/exts/fun/fun.py +++ b/bot/exts/fun/fun.py @@ -14,6 +14,7 @@ from bot.bot import Bot from bot.constants import Client, Colours, Emojis from bot.utils import helpers, messages +from bot.utils.quote import daily_quote, random_quote log = get_logger(__name__) @@ -158,6 +159,22 @@ async def joke(self, ctx: commands.Context, category: Literal["neutral", "chuck" joke = pyjokes.get_joke(category=category) await ctx.send(joke) + @commands.command(name="quote", aliases=("rquote", "randomquote", "random_quote",)) + async def quote(self, ctx: commands.Context) -> None: + """Retrieves a random quote from the zenquotes.io api.""" + quote = await random_quote() + if quote.startswith("Error:"): + log.warning("Failed to fetch random quote.") + await ctx.send(quote if not quote.startswith("Error:") else "Couldn't fetch a quote 😢") + + @commands.command(name="daily_quote", aliases=("dquote", "dailyquote")) + async def daily_quote(self, ctx: commands.Context) -> None: + """Retrieves the daily quote from zenquotes.io api.""" + quote = await daily_quote() + if quote.startswith("Error:"): + log.warning("Failed to fetch random quote.") + await ctx.send(quote if not quote.startswith("Error:") else "Couldn't fetch a quote 😢") + async def setup(bot: Bot) -> None: """Load the Fun cog.""" diff --git a/bot/utils/quote.py b/bot/utils/quote.py new file mode 100644 index 0000000000..fb57690dc5 --- /dev/null +++ b/bot/utils/quote.py @@ -0,0 +1,28 @@ +import aiohttp + +async def random_quote() -> str: + """Retrieves a random quote from zenquotes.io api.""" + url = "https://zenquotes.io/api/random" + + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + if response.status != 200: + return "Error: Data not Retrieved" + data = await response.json() + + quote = f"{data[0]['q']}\n-{data[0]['a']}" + return quote + + +async def daily_quote() -> str: + """Retrieves the daily quote from zenquotes.io api.""" + url = "https://zenquotes.io/api/today" + + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + if response.status != 200: + return "Error: Data not Retrieved" + data = await response.json() + + quote = f"{data[0]['q']}\n-{data[0]['a']}" + return quote diff --git a/pyproject.toml b/pyproject.toml index 940e383334..4b5286cd57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ "PyYAML==6.0.2", "rapidfuzz==3.12.2", "sentry-sdk==2.19.2", + "aiohttp==3.9.0", ] [dependency-groups] From d5708a7cd40ac105b1954b388f33c0f25fe48310 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Mon, 3 Nov 2025 12:50:24 +0500 Subject: [PATCH 02/13] run pre-commit hooks --- bot/utils/quote.py | 29 ++++++++++++++--------------- pyproject.toml | 2 +- uv.lock | 39 +++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/bot/utils/quote.py b/bot/utils/quote.py index fb57690dc5..b025bab54c 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -1,28 +1,27 @@ import aiohttp + async def random_quote() -> str: """Retrieves a random quote from zenquotes.io api.""" url = "https://zenquotes.io/api/random" - async with aiohttp.ClientSession() as session: - async with session.get(url) as response: - if response.status != 200: - return "Error: Data not Retrieved" - data = await response.json() + async with aiohttp.ClientSession() as session, session.get(url) as response: + if response.status != 200: + return "Error: Data not Retrieved" + data = await response.json() + + quote = f"{data[0]['q']}\n-{data[0]['a']}" + return quote - quote = f"{data[0]['q']}\n-{data[0]['a']}" - return quote - async def daily_quote() -> str: """Retrieves the daily quote from zenquotes.io api.""" url = "https://zenquotes.io/api/today" - async with aiohttp.ClientSession() as session: - async with session.get(url) as response: - if response.status != 200: - return "Error: Data not Retrieved" - data = await response.json() + async with aiohttp.ClientSession() as session, session.get(url) as response: + if response.status != 200: + return "Error: Data not Retrieved" + data = await response.json() - quote = f"{data[0]['q']}\n-{data[0]['a']}" - return quote + quote = f"{data[0]['q']}\n-{data[0]['a']}" + return quote diff --git a/pyproject.toml b/pyproject.toml index 4b5286cd57..04432e90a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "PyYAML==6.0.2", "rapidfuzz==3.12.2", "sentry-sdk==2.19.2", - "aiohttp==3.9.0", + "aiohttp==3.10.10", ] [dependency-groups] diff --git a/uv.lock b/uv.lock index 259cd0996a..6b9e68a5c6 100644 --- a/uv.lock +++ b/uv.lock @@ -28,7 +28,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.13.1" +version = "3.10.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -36,28 +36,25 @@ dependencies = [ { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, - { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/fa/3ae643cd525cf6844d3dc810481e5748107368eb49563c15a5fb9f680750/aiohttp-3.13.1.tar.gz", hash = "sha256:4b7ee9c355015813a6aa085170b96ec22315dabc3d866fd77d147927000e9464", size = 7835344, upload-time = "2025-10-17T14:03:29.337Z" } +sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993, upload-time = "2024-10-10T21:54:08.355Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/6d/d267b132342e1080f4c1bb7e1b4e96b168b3cbce931ec45780bff693ff95/aiohttp-3.13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:55785a7f8f13df0c9ca30b5243d9909bd59f48b274262a8fe78cee0828306e5d", size = 730727, upload-time = "2025-10-17T14:00:39.681Z" }, - { url = "https://files.pythonhosted.org/packages/92/c8/1cf495bac85cf71b80fad5f6d7693e84894f11b9fe876b64b0a1e7cbf32f/aiohttp-3.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bef5b83296cebb8167707b4f8d06c1805db0af632f7a72d7c5288a84667e7c3", size = 488678, upload-time = "2025-10-17T14:00:41.541Z" }, - { url = "https://files.pythonhosted.org/packages/a8/19/23c6b81cca587ec96943d977a58d11d05a82837022e65cd5502d665a7d11/aiohttp-3.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27af0619c33f9ca52f06069ec05de1a357033449ab101836f431768ecfa63ff5", size = 487637, upload-time = "2025-10-17T14:00:43.527Z" }, - { url = "https://files.pythonhosted.org/packages/48/58/8f9464afb88b3eed145ad7c665293739b3a6f91589694a2bb7e5778cbc72/aiohttp-3.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a47fe43229a8efd3764ef7728a5c1158f31cdf2a12151fe99fde81c9ac87019c", size = 1718975, upload-time = "2025-10-17T14:00:45.496Z" }, - { url = "https://files.pythonhosted.org/packages/e1/8b/c3da064ca392b2702f53949fd7c403afa38d9ee10bf52c6ad59a42537103/aiohttp-3.13.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e68e126de5b46e8b2bee73cab086b5d791e7dc192056916077aa1e2e2b04437", size = 1686905, upload-time = "2025-10-17T14:00:47.707Z" }, - { url = "https://files.pythonhosted.org/packages/0a/a4/9c8a3843ecf526daee6010af1a66eb62579be1531d2d5af48ea6f405ad3c/aiohttp-3.13.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e65ef49dd22514329c55970d39079618a8abf856bae7147913bb774a3ab3c02f", size = 1754907, upload-time = "2025-10-17T14:00:49.702Z" }, - { url = "https://files.pythonhosted.org/packages/a4/80/1f470ed93e06436e3fc2659a9fc329c192fa893fb7ed4e884d399dbfb2a8/aiohttp-3.13.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e425a7e0511648b3376839dcc9190098671a47f21a36e815b97762eb7d556b0", size = 1857129, upload-time = "2025-10-17T14:00:51.822Z" }, - { url = "https://files.pythonhosted.org/packages/cc/e6/33d305e6cce0a8daeb79c7d8d6547d6e5f27f4e35fa4883fc9c9eb638596/aiohttp-3.13.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:010dc9b7110f055006acd3648d5d5955bb6473b37c3663ec42a1b4cba7413e6b", size = 1738189, upload-time = "2025-10-17T14:00:53.976Z" }, - { url = "https://files.pythonhosted.org/packages/ac/42/8df03367e5a64327fe0c39291080697795430c438fc1139c7cc1831aa1df/aiohttp-3.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b5c722d0ca5f57d61066b5dfa96cdb87111e2519156b35c1f8dd17c703bee7a", size = 1553608, upload-time = "2025-10-17T14:00:56.144Z" }, - { url = "https://files.pythonhosted.org/packages/96/17/6d5c73cd862f1cf29fddcbb54aac147037ff70a043a2829d03a379e95742/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:93029f0e9b77b714904a281b5aa578cdc8aa8ba018d78c04e51e1c3d8471b8ec", size = 1681809, upload-time = "2025-10-17T14:00:58.603Z" }, - { url = "https://files.pythonhosted.org/packages/be/31/8926c8ab18533f6076ce28d2c329a203b58c6861681906e2d73b9c397588/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d1824c7d08d8ddfc8cb10c847f696942e5aadbd16fd974dfde8bd2c3c08a9fa1", size = 1711161, upload-time = "2025-10-17T14:01:01.744Z" }, - { url = "https://files.pythonhosted.org/packages/f2/36/2f83e1ca730b1e0a8cf1c8ab9559834c5eec9f5da86e77ac71f0d16b521d/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8f47d0ff5b3eb9c1278a2f56ea48fda667da8ebf28bd2cb378b7c453936ce003", size = 1731999, upload-time = "2025-10-17T14:01:04.626Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ec/1f818cc368dfd4d5ab4e9efc8f2f6f283bfc31e1c06d3e848bcc862d4591/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8a396b1da9b51ded79806ac3b57a598f84e0769eaa1ba300655d8b5e17b70c7b", size = 1548684, upload-time = "2025-10-17T14:01:06.828Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ad/33d36efd16e4fefee91b09a22a3a0e1b830f65471c3567ac5a8041fac812/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d9c52a65f54796e066b5d674e33b53178014752d28bca555c479c2c25ffcec5b", size = 1756676, upload-time = "2025-10-17T14:01:09.517Z" }, - { url = "https://files.pythonhosted.org/packages/3c/c4/4a526d84e77d464437713ca909364988ed2e0cd0cdad2c06cb065ece9e08/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a89da72d18d6c95a653470b78d8ee5aa3c4b37212004c103403d0776cbea6ff0", size = 1715577, upload-time = "2025-10-17T14:01:11.958Z" }, - { url = "https://files.pythonhosted.org/packages/a2/21/e39638b7d9c7f1362c4113a91870f89287e60a7ea2d037e258b81e8b37d5/aiohttp-3.13.1-cp313-cp313-win32.whl", hash = "sha256:02e0258b7585ddf5d01c79c716ddd674386bfbf3041fbbfe7bdf9c7c32eb4a9b", size = 424468, upload-time = "2025-10-17T14:01:14.344Z" }, - { url = "https://files.pythonhosted.org/packages/cc/00/f3a92c592a845ebb2f47d102a67f35f0925cb854c5e7386f1a3a1fdff2ab/aiohttp-3.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:ef56ffe60e8d97baac123272bde1ab889ee07d3419606fae823c80c2b86c403e", size = 450806, upload-time = "2025-10-17T14:01:16.437Z" }, + { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114, upload-time = "2024-10-10T21:52:38.096Z" }, + { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901, upload-time = "2024-10-10T21:52:39.809Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418, upload-time = "2024-10-10T21:52:41.415Z" }, + { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073, upload-time = "2024-10-10T21:52:43.12Z" }, + { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612, upload-time = "2024-10-10T21:52:45.472Z" }, + { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406, upload-time = "2024-10-10T21:52:47.501Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761, upload-time = "2024-10-10T21:52:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518, upload-time = "2024-10-10T21:52:51.529Z" }, + { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344, upload-time = "2024-10-10T21:52:53.233Z" }, + { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956, upload-time = "2024-10-10T21:52:54.936Z" }, + { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379, upload-time = "2024-10-10T21:52:57.887Z" }, + { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108, upload-time = "2024-10-10T21:52:59.581Z" }, + { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546, upload-time = "2024-10-10T21:53:01.333Z" }, + { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516, upload-time = "2024-10-10T21:53:03.427Z" }, + { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785, upload-time = "2024-10-10T21:53:05.044Z" }, ] [[package]] @@ -841,6 +838,7 @@ name = "sir-lancebot" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "aiohttp" }, { name = "arrow" }, { name = "beautifulsoup4" }, { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -869,6 +867,7 @@ dev = [ [package.metadata] requires-dist = [ + { name = "aiohttp", specifier = "==3.10.10" }, { name = "arrow", specifier = "==1.3.0" }, { name = "beautifulsoup4", specifier = "==4.12.3" }, { name = "colorama", marker = "sys_platform == 'win32'", specifier = "==0.4.6" }, From 6b354d03530e39305bbc82e2bb291fb9e7c8f7d9 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Wed, 5 Nov 2025 13:47:15 +0500 Subject: [PATCH 03/13] Implement suggested changes except daily quote caching. --- bot/exts/fun/fun.py | 70 ++++++++++++++++++++++++++++++++++----------- bot/utils/quote.py | 37 +++++++++++------------- pyproject.toml | 1 - uv.lock | 2 -- 4 files changed, 71 insertions(+), 39 deletions(-) diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py index 2dc856edbd..5e7fa7bfb5 100644 --- a/bot/exts/fun/fun.py +++ b/bot/exts/fun/fun.py @@ -8,6 +8,8 @@ from discord import Embed from discord.ext import commands from discord.ext.commands import BadArgument, Cog, Context +from aiohttp import ClientResponseError, ClientError +from asyncio import TimeoutError from pydis_core.utils.commands import clean_text_or_reply from pydis_core.utils.logging import get_logger @@ -159,22 +161,58 @@ async def joke(self, ctx: commands.Context, category: Literal["neutral", "chuck" joke = pyjokes.get_joke(category=category) await ctx.send(joke) - @commands.command(name="quote", aliases=("rquote", "randomquote", "random_quote",)) - async def quote(self, ctx: commands.Context) -> None: - """Retrieves a random quote from the zenquotes.io api.""" - quote = await random_quote() - if quote.startswith("Error:"): - log.warning("Failed to fetch random quote.") - await ctx.send(quote if not quote.startswith("Error:") else "Couldn't fetch a quote 😢") - - @commands.command(name="daily_quote", aliases=("dquote", "dailyquote")) - async def daily_quote(self, ctx: commands.Context) -> None: - """Retrieves the daily quote from zenquotes.io api.""" - quote = await daily_quote() - if quote.startswith("Error:"): - log.warning("Failed to fetch random quote.") - await ctx.send(quote if not quote.startswith("Error:") else "Couldn't fetch a quote 😢") - + @commands.group(name="quote") + async def quote(self, ctx: Context) -> None: + """Retrieve a quote from zenquotes.io api + + see `random`, `daily` subcommands. + """ + if ctx.invoked_subcommand is None: + await ctx.invoke(self.bot.get_command("help"), "quote") + + @quote.command(name='daily') + async def quote_daily(self, ctx: Context) -> None: + """Retrieve the daily quote from zenquotes.io api.""" + try: + quote = await daily_quote(self.bot) + embed = Embed( + title="Daily Quote", + description=quote + ) + embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) + embed.set_footer(text="Powered by zenquotes.io") + await ctx.send(embed=embed) + except ClientResponseError as e: + log.warning(f"ZenQuotes API error: {e.status} {e.message}") + await ctx.send("Could not retrieve quote from API.") + except (ClientError, TimeoutError) as e: + log.error(f"Network error fetching quote: {e}") + await ctx.send("Could not connect to the quote service.") + except Exception as e: + log.exception("Unexpected error fetching quote.") + await ctx.send("Something unexpected happened. Try again later.") + + @quote.command(name='random') + async def quote_random(self, ctx: Context) -> None: + """Retrieve a random quote from zenquotes.io api.""" + try: + quote = await random_quote(self.bot) + embed = Embed( + title="Daily Quote", + description=quote + ) + embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) + embed.set_footer(text="Powered by zenquotes.io") + await ctx.send(embed=embed) + except ClientResponseError as e: + log.warning(f"ZenQuotes API error: {e.status} {e.message}") + await ctx.send("Could not retrieve quote from API.") + except (ClientError, TimeoutError) as e: + log.error(f"Network error fetching quote: {e}") + await ctx.send("Could not connect to the quote service.") + except Exception as e: + log.exception("Unexpected error fetching quote.") + await ctx.send("Something unexpected happened. Try again later.") async def setup(bot: Bot) -> None: """Load the Fun cog.""" diff --git a/bot/utils/quote.py b/bot/utils/quote.py index b025bab54c..6f21df6252 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -1,27 +1,24 @@ -import aiohttp +"""Utility functions for fetching quotes from ZenQuotes API.""" +from discord.ext.commands import Bot -async def random_quote() -> str: - """Retrieves a random quote from zenquotes.io api.""" - url = "https://zenquotes.io/api/random" +RANDOM_QUOTE_URL = "https://zenquotes.io/api/random" +DAILY_QUOTE_URL = "https://zenquotes.io/api/today" - async with aiohttp.ClientSession() as session, session.get(url) as response: - if response.status != 200: - return "Error: Data not Retrieved" - data = await response.json() - quote = f"{data[0]['q']}\n-{data[0]['a']}" +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() -> str: - """Retrieves the daily quote from zenquotes.io api.""" - url = "https://zenquotes.io/api/today" - - async with aiohttp.ClientSession() as session, session.get(url) as response: - if response.status != 200: - return "Error: Data not Retrieved" - 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.""" + async with bot.http_session.get(DAILY_QUOTE_URL) as response: + response.raise_for_status() + data = await response.json() + quote = f"{data[0]['q']}\n— {data[0]['a']}" + return quote \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 04432e90a0..940e383334 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,6 @@ dependencies = [ "PyYAML==6.0.2", "rapidfuzz==3.12.2", "sentry-sdk==2.19.2", - "aiohttp==3.10.10", ] [dependency-groups] diff --git a/uv.lock b/uv.lock index 6b9e68a5c6..28b3a624fb 100644 --- a/uv.lock +++ b/uv.lock @@ -838,7 +838,6 @@ name = "sir-lancebot" version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "aiohttp" }, { name = "arrow" }, { name = "beautifulsoup4" }, { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -867,7 +866,6 @@ dev = [ [package.metadata] requires-dist = [ - { name = "aiohttp", specifier = "==3.10.10" }, { name = "arrow", specifier = "==1.3.0" }, { name = "beautifulsoup4", specifier = "==4.12.3" }, { name = "colorama", marker = "sys_platform == 'win32'", specifier = "==0.4.6" }, From e22bf2a70635388263dbb62c5b9a3a2e2cdf3f71 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Wed, 5 Nov 2025 13:52:35 +0500 Subject: [PATCH 04/13] run pre-commit hooks --- bot/exts/fun/fun.py | 18 +++++++++--------- bot/utils/quote.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py index 5e7fa7bfb5..207f7b1a67 100644 --- a/bot/exts/fun/fun.py +++ b/bot/exts/fun/fun.py @@ -5,11 +5,10 @@ from typing import Literal import pyjokes +from aiohttp import ClientError, ClientResponseError from discord import Embed from discord.ext import commands from discord.ext.commands import BadArgument, Cog, Context -from aiohttp import ClientResponseError, ClientError -from asyncio import TimeoutError from pydis_core.utils.commands import clean_text_or_reply from pydis_core.utils.logging import get_logger @@ -163,14 +162,15 @@ async def joke(self, ctx: commands.Context, category: Literal["neutral", "chuck" @commands.group(name="quote") async def quote(self, ctx: Context) -> None: - """Retrieve a quote from zenquotes.io api - - see `random`, `daily` subcommands. + """ + Retrieve a quote from zenquotes.io api. + + see `random`, `daily` subcommands. """ if ctx.invoked_subcommand is None: await ctx.invoke(self.bot.get_command("help"), "quote") - @quote.command(name='daily') + @quote.command(name="daily") async def quote_daily(self, ctx: Context) -> None: """Retrieve the daily quote from zenquotes.io api.""" try: @@ -188,11 +188,11 @@ async def quote_daily(self, ctx: Context) -> None: except (ClientError, TimeoutError) as e: log.error(f"Network error fetching quote: {e}") await ctx.send("Could not connect to the quote service.") - except Exception as e: + except Exception: log.exception("Unexpected error fetching quote.") await ctx.send("Something unexpected happened. Try again later.") - @quote.command(name='random') + @quote.command(name="random") async def quote_random(self, ctx: Context) -> None: """Retrieve a random quote from zenquotes.io api.""" try: @@ -210,7 +210,7 @@ async def quote_random(self, ctx: Context) -> None: except (ClientError, TimeoutError) as e: log.error(f"Network error fetching quote: {e}") await ctx.send("Could not connect to the quote service.") - except Exception as e: + except Exception: log.exception("Unexpected error fetching quote.") await ctx.send("Something unexpected happened. Try again later.") diff --git a/bot/utils/quote.py b/bot/utils/quote.py index 6f21df6252..23ba1a9b92 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -21,4 +21,4 @@ async def daily_quote(bot: Bot) -> str: response.raise_for_status() data = await response.json() quote = f"{data[0]['q']}\n— {data[0]['a']}" - return quote \ No newline at end of file + return quote From 6b873c27434608292c5bd17903867d32b6e8da7d Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Wed, 5 Nov 2025 14:02:27 +0500 Subject: [PATCH 05/13] Add attribution hyperlink --- bot/exts/fun/fun.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py index 207f7b1a67..bb29f8948c 100644 --- a/bot/exts/fun/fun.py +++ b/bot/exts/fun/fun.py @@ -177,10 +177,9 @@ async def quote_daily(self, ctx: Context) -> None: quote = await daily_quote(self.bot) embed = Embed( title="Daily Quote", - description=quote + description=f"{quote}\n\nPowered by [zenquotes.io](https://zenquotes.io)" ) embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) - embed.set_footer(text="Powered by zenquotes.io") await ctx.send(embed=embed) except ClientResponseError as e: log.warning(f"ZenQuotes API error: {e.status} {e.message}") @@ -199,10 +198,9 @@ async def quote_random(self, ctx: Context) -> None: quote = await random_quote(self.bot) embed = Embed( title="Daily Quote", - description=quote + description=f"{quote}\n\nPowered by [zenquotes.io](https://zenquotes.io)" ) embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) - embed.set_footer(text="Powered by zenquotes.io") await ctx.send(embed=embed) except ClientResponseError as e: log.warning(f"ZenQuotes API error: {e.status} {e.message}") From b717bfa0c6c17619bc0fa148f6cf7101087cccee Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Wed, 5 Nov 2025 14:58:52 +0500 Subject: [PATCH 06/13] Implement caching for daily quote to minimize API requests. --- bot/utils/quote.py | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/bot/utils/quote.py b/bot/utils/quote.py index 23ba1a9b92..2470894213 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -1,9 +1,22 @@ """Utility functions for fetching quotes from ZenQuotes API.""" -from discord.ext.commands import Bot +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)).replace(hour=0, minute=0, second=0, microsecond=0) + return int((tomorrow - now).total_seconds()) async def random_quote(bot: Bot) -> str: @@ -17,8 +30,22 @@ async def random_quote(bot: Bot) -> str: async def daily_quote(bot: Bot) -> str: """Retrieve the daily quote from ZenQuotes API, cached until 00:00 UTC.""" - async with bot.http_session.get(DAILY_QUOTE_URL) as response: - response.raise_for_status() - data = await response.json() - quote = f"{data[0]['q']}\n— {data[0]['a']}" - return quote + 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("https://zenquotes.io/api/today") 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 From 5adb196a70597d601f4b4c3dc00da490b50a1f61 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Thu, 6 Nov 2025 09:58:21 +0500 Subject: [PATCH 07/13] fix typos --- bot/exts/fun/fun.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py index bb29f8948c..7ee0cfd071 100644 --- a/bot/exts/fun/fun.py +++ b/bot/exts/fun/fun.py @@ -197,7 +197,7 @@ async def quote_random(self, ctx: Context) -> None: try: quote = await random_quote(self.bot) embed = Embed( - title="Daily Quote", + title="Random Quote", description=f"{quote}\n\nPowered by [zenquotes.io](https://zenquotes.io)" ) embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) From 4131e4042b571f6cfa6949cfadfc6703a1458ab0 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Thu, 6 Nov 2025 10:00:26 +0500 Subject: [PATCH 08/13] fix typos --- bot/utils/quote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/utils/quote.py b/bot/utils/quote.py index 2470894213..7e3e7df2a6 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -38,7 +38,7 @@ async def daily_quote(bot: Bot) -> str: return cached_quote log.debug("No cached quote found.") - async with bot.http_session.get("https://zenquotes.io/api/today") as resp: + 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']}" From 686014bf79ff74608db7f1d162df72835aa0da09 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Fri, 7 Nov 2025 10:50:49 +0500 Subject: [PATCH 09/13] Implement suggested changes --- bot/exts/fun/fun.py | 22 +++++++++++----------- bot/utils/quote.py | 6 ++++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/bot/exts/fun/fun.py b/bot/exts/fun/fun.py index 7ee0cfd071..25c4641304 100644 --- a/bot/exts/fun/fun.py +++ b/bot/exts/fun/fun.py @@ -165,7 +165,7 @@ async def quote(self, ctx: Context) -> None: """ Retrieve a quote from zenquotes.io api. - see `random`, `daily` subcommands. + See `random`, `daily` subcommands. """ if ctx.invoked_subcommand is None: await ctx.invoke(self.bot.get_command("help"), "quote") @@ -177,19 +177,19 @@ async def quote_daily(self, ctx: Context) -> None: quote = await daily_quote(self.bot) embed = Embed( title="Daily Quote", - description=f"{quote}\n\nPowered by [zenquotes.io](https://zenquotes.io)" + description=f"> {quote}\n\n-# Powered by [zenquotes.io](https://zenquotes.io)", + colour=Colours.blue ) - embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) await ctx.send(embed=embed) except ClientResponseError as e: log.warning(f"ZenQuotes API error: {e.status} {e.message}") - await ctx.send("Could not retrieve quote from API.") + await ctx.send(":x: Could not retrieve quote from API.") except (ClientError, TimeoutError) as e: log.error(f"Network error fetching quote: {e}") - await ctx.send("Could not connect to the quote service.") + await ctx.send(":x: Could not connect to the quote service.") except Exception: log.exception("Unexpected error fetching quote.") - await ctx.send("Something unexpected happened. Try again later.") + await ctx.send(":x: Something unexpected happened. Try again later.") @quote.command(name="random") async def quote_random(self, ctx: Context) -> None: @@ -198,19 +198,19 @@ async def quote_random(self, ctx: Context) -> None: quote = await random_quote(self.bot) embed = Embed( title="Random Quote", - description=f"{quote}\n\nPowered by [zenquotes.io](https://zenquotes.io)" + description=f"> {quote}\n\n-# Powered by [zenquotes.io](https://zenquotes.io)", + colour=Colours.blue ) - embed.set_author(name=self.bot.user.display_name, icon_url=self.bot.user.display_avatar.url) await ctx.send(embed=embed) except ClientResponseError as e: log.warning(f"ZenQuotes API error: {e.status} {e.message}") - await ctx.send("Could not retrieve quote from API.") + await ctx.send(":x: Could not retrieve quote from API.") except (ClientError, TimeoutError) as e: log.error(f"Network error fetching quote: {e}") - await ctx.send("Could not connect to the quote service.") + await ctx.send(":x: Could not connect to the quote service.") except Exception: log.exception("Unexpected error fetching quote.") - await ctx.send("Something unexpected happened. Try again later.") + await ctx.send(":x: Something unexpected happened. Try again later.") async def setup(bot: Bot) -> None: """Load the Fun cog.""" diff --git a/bot/utils/quote.py b/bot/utils/quote.py index 7e3e7df2a6..e196540097 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -15,8 +15,10 @@ 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)).replace(hour=0, minute=0, second=0, microsecond=0) - return int((tomorrow - now).total_seconds()) + 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: From 40a944524d6133771952c77ce42eb164e4c6e591 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Fri, 7 Nov 2025 15:25:15 +0500 Subject: [PATCH 10/13] Revert uv.lock since aiohttp is unpinned --- uv.lock | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/uv.lock b/uv.lock index 28b3a624fb..9f0a584583 100644 --- a/uv.lock +++ b/uv.lock @@ -28,7 +28,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.10.10" +version = "3.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -36,25 +36,28 @@ dependencies = [ { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, + { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993, upload-time = "2024-10-10T21:54:08.355Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/fa/3ae643cd525cf6844d3dc810481e5748107368eb49563c15a5fb9f680750/aiohttp-3.13.1.tar.gz", hash = "sha256:4b7ee9c355015813a6aa085170b96ec22315dabc3d866fd77d147927000e9464", size = 7835344, upload-time = "2025-10-17T14:03:29.337Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114, upload-time = "2024-10-10T21:52:38.096Z" }, - { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901, upload-time = "2024-10-10T21:52:39.809Z" }, - { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418, upload-time = "2024-10-10T21:52:41.415Z" }, - { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073, upload-time = "2024-10-10T21:52:43.12Z" }, - { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612, upload-time = "2024-10-10T21:52:45.472Z" }, - { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406, upload-time = "2024-10-10T21:52:47.501Z" }, - { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761, upload-time = "2024-10-10T21:52:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518, upload-time = "2024-10-10T21:52:51.529Z" }, - { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344, upload-time = "2024-10-10T21:52:53.233Z" }, - { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956, upload-time = "2024-10-10T21:52:54.936Z" }, - { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379, upload-time = "2024-10-10T21:52:57.887Z" }, - { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108, upload-time = "2024-10-10T21:52:59.581Z" }, - { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546, upload-time = "2024-10-10T21:53:01.333Z" }, - { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516, upload-time = "2024-10-10T21:53:03.427Z" }, - { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785, upload-time = "2024-10-10T21:53:05.044Z" }, + { url = "https://files.pythonhosted.org/packages/16/6d/d267b132342e1080f4c1bb7e1b4e96b168b3cbce931ec45780bff693ff95/aiohttp-3.13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:55785a7f8f13df0c9ca30b5243d9909bd59f48b274262a8fe78cee0828306e5d", size = 730727, upload-time = "2025-10-17T14:00:39.681Z" }, + { url = "https://files.pythonhosted.org/packages/92/c8/1cf495bac85cf71b80fad5f6d7693e84894f11b9fe876b64b0a1e7cbf32f/aiohttp-3.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bef5b83296cebb8167707b4f8d06c1805db0af632f7a72d7c5288a84667e7c3", size = 488678, upload-time = "2025-10-17T14:00:41.541Z" }, + { url = "https://files.pythonhosted.org/packages/a8/19/23c6b81cca587ec96943d977a58d11d05a82837022e65cd5502d665a7d11/aiohttp-3.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27af0619c33f9ca52f06069ec05de1a357033449ab101836f431768ecfa63ff5", size = 487637, upload-time = "2025-10-17T14:00:43.527Z" }, + { url = "https://files.pythonhosted.org/packages/48/58/8f9464afb88b3eed145ad7c665293739b3a6f91589694a2bb7e5778cbc72/aiohttp-3.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a47fe43229a8efd3764ef7728a5c1158f31cdf2a12151fe99fde81c9ac87019c", size = 1718975, upload-time = "2025-10-17T14:00:45.496Z" }, + { url = "https://files.pythonhosted.org/packages/e1/8b/c3da064ca392b2702f53949fd7c403afa38d9ee10bf52c6ad59a42537103/aiohttp-3.13.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e68e126de5b46e8b2bee73cab086b5d791e7dc192056916077aa1e2e2b04437", size = 1686905, upload-time = "2025-10-17T14:00:47.707Z" }, + { url = "https://files.pythonhosted.org/packages/0a/a4/9c8a3843ecf526daee6010af1a66eb62579be1531d2d5af48ea6f405ad3c/aiohttp-3.13.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e65ef49dd22514329c55970d39079618a8abf856bae7147913bb774a3ab3c02f", size = 1754907, upload-time = "2025-10-17T14:00:49.702Z" }, + { url = "https://files.pythonhosted.org/packages/a4/80/1f470ed93e06436e3fc2659a9fc329c192fa893fb7ed4e884d399dbfb2a8/aiohttp-3.13.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e425a7e0511648b3376839dcc9190098671a47f21a36e815b97762eb7d556b0", size = 1857129, upload-time = "2025-10-17T14:00:51.822Z" }, + { url = "https://files.pythonhosted.org/packages/cc/e6/33d305e6cce0a8daeb79c7d8d6547d6e5f27f4e35fa4883fc9c9eb638596/aiohttp-3.13.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:010dc9b7110f055006acd3648d5d5955bb6473b37c3663ec42a1b4cba7413e6b", size = 1738189, upload-time = "2025-10-17T14:00:53.976Z" }, + { url = "https://files.pythonhosted.org/packages/ac/42/8df03367e5a64327fe0c39291080697795430c438fc1139c7cc1831aa1df/aiohttp-3.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b5c722d0ca5f57d61066b5dfa96cdb87111e2519156b35c1f8dd17c703bee7a", size = 1553608, upload-time = "2025-10-17T14:00:56.144Z" }, + { url = "https://files.pythonhosted.org/packages/96/17/6d5c73cd862f1cf29fddcbb54aac147037ff70a043a2829d03a379e95742/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:93029f0e9b77b714904a281b5aa578cdc8aa8ba018d78c04e51e1c3d8471b8ec", size = 1681809, upload-time = "2025-10-17T14:00:58.603Z" }, + { url = "https://files.pythonhosted.org/packages/be/31/8926c8ab18533f6076ce28d2c329a203b58c6861681906e2d73b9c397588/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d1824c7d08d8ddfc8cb10c847f696942e5aadbd16fd974dfde8bd2c3c08a9fa1", size = 1711161, upload-time = "2025-10-17T14:01:01.744Z" }, + { url = "https://files.pythonhosted.org/packages/f2/36/2f83e1ca730b1e0a8cf1c8ab9559834c5eec9f5da86e77ac71f0d16b521d/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8f47d0ff5b3eb9c1278a2f56ea48fda667da8ebf28bd2cb378b7c453936ce003", size = 1731999, upload-time = "2025-10-17T14:01:04.626Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ec/1f818cc368dfd4d5ab4e9efc8f2f6f283bfc31e1c06d3e848bcc862d4591/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8a396b1da9b51ded79806ac3b57a598f84e0769eaa1ba300655d8b5e17b70c7b", size = 1548684, upload-time = "2025-10-17T14:01:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ad/33d36efd16e4fefee91b09a22a3a0e1b830f65471c3567ac5a8041fac812/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d9c52a65f54796e066b5d674e33b53178014752d28bca555c479c2c25ffcec5b", size = 1756676, upload-time = "2025-10-17T14:01:09.517Z" }, + { url = "https://files.pythonhosted.org/packages/3c/c4/4a526d84e77d464437713ca909364988ed2e0cd0cdad2c06cb065ece9e08/aiohttp-3.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a89da72d18d6c95a653470b78d8ee5aa3c4b37212004c103403d0776cbea6ff0", size = 1715577, upload-time = "2025-10-17T14:01:11.958Z" }, + { url = "https://files.pythonhosted.org/packages/a2/21/e39638b7d9c7f1362c4113a91870f89287e60a7ea2d037e258b81e8b37d5/aiohttp-3.13.1-cp313-cp313-win32.whl", hash = "sha256:02e0258b7585ddf5d01c79c716ddd674386bfbf3041fbbfe7bdf9c7c32eb4a9b", size = 424468, upload-time = "2025-10-17T14:01:14.344Z" }, + { url = "https://files.pythonhosted.org/packages/cc/00/f3a92c592a845ebb2f47d102a67f35f0925cb854c5e7386f1a3a1fdff2ab/aiohttp-3.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:ef56ffe60e8d97baac123272bde1ab889ee07d3419606fae823c80c2b86c403e", size = 450806, upload-time = "2025-10-17T14:01:16.437Z" }, ] [[package]] @@ -1054,4 +1057,4 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, -] +] \ No newline at end of file From f7a7b13ec1e981e34be6aa924bdacf036b7e000f Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Fri, 7 Nov 2025 15:26:03 +0500 Subject: [PATCH 11/13] escape special characters before author's names --- bot/utils/quote.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/utils/quote.py b/bot/utils/quote.py index e196540097..422e62eb40 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -26,7 +26,7 @@ async def random_quote(bot: Bot) -> str: 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']}" + quote = f"{data[0]['q']}\n*\— {data[0]['a']}*" return quote @@ -43,7 +43,7 @@ async def daily_quote(bot: Bot) -> str: 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']}" + quote = f"{data[0]['q']}\n*\— {data[0]['a']}*" ttl = seconds_until_midnight_utc() From 84b497f868fe9dbedaa8f49d592bf000ed63f454 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Fri, 7 Nov 2025 15:27:36 +0500 Subject: [PATCH 12/13] run pre-commit hooks --- bot/utils/quote.py | 4 ++-- uv.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bot/utils/quote.py b/bot/utils/quote.py index 422e62eb40..bdf4bc65df 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -26,7 +26,7 @@ async def random_quote(bot: Bot) -> str: 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']}*" + quote = f"{data[0]['q']}\n*\\— {data[0]['a']}*" return quote @@ -43,7 +43,7 @@ async def daily_quote(bot: Bot) -> str: 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']}*" + quote = f"{data[0]['q']}\n*\\— {data[0]['a']}*" ttl = seconds_until_midnight_utc() diff --git a/uv.lock b/uv.lock index 9f0a584583..259cd0996a 100644 --- a/uv.lock +++ b/uv.lock @@ -1057,4 +1057,4 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, -] \ No newline at end of file +] From 60303e66044841bdd49ea40349723a3aff8c18e1 Mon Sep 17 00:00:00 2001 From: Muhammad Hasan Date: Sat, 8 Nov 2025 13:27:31 +0500 Subject: [PATCH 13/13] =?UTF-8?q?remove=20\=20because=20escaping=20the=20?= =?UTF-8?q?=E2=80=94=20was=20not=20needed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/utils/quote.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/utils/quote.py b/bot/utils/quote.py index bdf4bc65df..9324a732a0 100644 --- a/bot/utils/quote.py +++ b/bot/utils/quote.py @@ -26,7 +26,7 @@ async def random_quote(bot: Bot) -> str: 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']}*" + quote = f"{data[0]['q']}\n*— {data[0]['a']}*" return quote @@ -43,7 +43,7 @@ async def daily_quote(bot: Bot) -> str: 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']}*" + quote = f"{data[0]['q']}\n*— {data[0]['a']}*" ttl = seconds_until_midnight_utc()