1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
import re
from random import randint
from discord import Embed
from discord.ext import tasks
from discord.ext.commands import Cog, Context, command
from pydis_core.utils.logging import get_logger
from bot.bot import Bot
from bot.constants import Colours
log = get_logger(__name__)
COMIC_FORMAT = re.compile(r"latest|[0-9]+")
BASE_URL = "https://xkcd.com"
class XKCD(Cog):
"""Retrieving XKCD comics."""
def __init__(self, bot: Bot):
self.bot = bot
self.latest_comic_info: dict[str, str | int] = {}
self.get_latest_comic_info.start()
def cog_unload(self) -> None:
"""Cancels refreshing of the task for refreshing the most recent comic info."""
self.get_latest_comic_info.cancel()
@tasks.loop(minutes=30)
async def get_latest_comic_info(self) -> None:
"""Refreshes latest comic's information ever 30 minutes. Also used for finding a random comic."""
async with self.bot.http_session.get(f"{BASE_URL}/info.0.json") as resp:
if resp.status == 200:
self.latest_comic_info = await resp.json()
else:
log.debug(f"Failed to get latest XKCD comic information. Status code {resp.status}")
@command(name="xkcd")
async def fetch_xkcd_comics(self, ctx: Context, comic: str | None) -> None:
"""
Getting an xkcd comic's information along with the image.
To get a random comic, don't type any number as an argument. To get the latest, type 'latest'.
"""
embed = Embed(title=f"XKCD comic '{comic}'")
embed.colour = Colours.soft_red
if comic and (comic := re.match(COMIC_FORMAT, comic)) is None:
embed.description = "Comic parameter should either be an integer or 'latest'."
await ctx.send(embed=embed)
return
comic = randint(1, self.latest_comic_info["num"]) if comic is None else comic.group(0)
if comic == "latest":
info = self.latest_comic_info
else:
async with self.bot.http_session.get(f"{BASE_URL}/{comic}/info.0.json") as resp:
if resp.status == 200:
info = await resp.json()
else:
embed.title = f"XKCD comic #{comic}"
embed.description = f"{resp.status}: Could not retrieve xkcd comic #{comic}."
log.debug(f"Retrieving xkcd comic #{comic} failed with status code {resp.status}.")
await ctx.send(embed=embed)
return
embed.title = f"XKCD comic #{info['num']}"
embed.description = info["alt"]
embed.url = f"{BASE_URL}/{info['num']}"
if info["img"][-3:] in ("jpg", "png", "gif"):
embed.set_image(url=info["img"])
date = f"{info['year']}/{info['month']}/{info['day']}"
embed.set_footer(text=f"{date} - #{info['num']}, '{info['safe_title']}'")
embed.colour = Colours.soft_green
else:
embed.description = (
"The selected comic is interactive, and cannot be displayed within an embed.\n"
f"Comic can be viewed [here](https://xkcd.com/{info['num']})."
)
await ctx.send(embed=embed)
async def setup(bot: Bot) -> None:
"""Load the XKCD cog."""
await bot.add_cog(XKCD(bot))
|