Skip to content

Commit f5f2c3c

Browse files
refactor: sync emojis to the test guild
1 parent 3540b26 commit f5f2c3c

File tree

1 file changed

+55
-2
lines changed

1 file changed

+55
-2
lines changed

botstrap.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import base64
12
import logging
23
import os
34
import re
45
import sys
56
from pathlib import Path
6-
from typing import Any, cast
7+
from typing import Any, Final, cast
78

89
from dotenv import load_dotenv
910
from httpx import Client, HTTPStatusError, Response
@@ -15,6 +16,7 @@
1516
Webhooks,
1617
_Categories, # pyright: ignore[reportPrivateUsage]
1718
_Channels, # pyright: ignore[reportPrivateUsage]
19+
_Emojis, # pyright: ignore[reportPrivateUsage]
1820
_Roles, # pyright: ignore[reportPrivateUsage]
1921
)
2022
from bot.log import get_logger # noqa: E402
@@ -35,6 +37,7 @@
3537
RULES_CHANNEL_NAME = "rules"
3638
GUILD_CATEGORY_TYPE = 4
3739
GUILD_FORUM_TYPE = 15
40+
EMOJI_REGEX = re.compile(r"<:(\w+):(\d+)>")
3841

3942
if not BOT_TOKEN:
4043
message = (
@@ -76,6 +79,8 @@ def __getitem__(self, item: str):
7679
class DiscordClient(Client):
7780
"""An HTTP client to communicate with Discord's APIs."""
7881

82+
CDN_BASE_URL: Final[str] = "https://cdn.discordapp.com"
83+
7984
def __init__(self, guild_id: int | str):
8085
super().__init__(
8186
base_url="https://discord.com/api/v10",
@@ -238,6 +243,37 @@ def create_webhook(self, name: str, channel_id_: int) -> str:
238243
new_webhook = response.json()
239244
return new_webhook["id"]
240245

246+
def list_emojis(self) -> list[dict[str, Any]]:
247+
"""Lists all the emojis for the guild."""
248+
response = self.get(f"/guilds/{self.guild_id}/emojis")
249+
return response.json()
250+
251+
def get_emoji_contents(self, emoji_id: str | int) -> bytes | None:
252+
"""Fetches the image data for an emoji by ID."""
253+
# emojis are located at https://cdn.discordapp.com/emojis/821611231663751168.png?size=4096
254+
response = self.get(f"{self.CDN_BASE_URL}/emojis/{emoji_id!s}.webp")
255+
return response.content
256+
257+
def clone_emoji(self, *, name: str, id: str | int) -> str:
258+
"""Creates a new emoji in the guild, cloned from another emoji by ID."""
259+
emoji_data = self.get_emoji_contents(id)
260+
if not emoji_data:
261+
log.warning(f"Couldn't find emoji with ID {id}.")
262+
return ""
263+
264+
payload = {
265+
"name": name,
266+
"image": f"data:image/png;base64,{base64.b64encode(emoji_data).decode('utf-8')}",
267+
}
268+
269+
response = self.post(
270+
f"/guilds/{self.guild_id}/emojis",
271+
json=payload,
272+
headers={"X-Audit-Log-Reason": f"Creating {name} emoji as part of PyDis botstrap"},
273+
)
274+
new_emoji = response.json()
275+
return new_emoji["id"]
276+
241277

242278
with DiscordClient(guild_id=GUILD_ID) as discord_client:
243279
if discord_client.upgrade_application_flags_if_necessary():
@@ -329,7 +365,24 @@ def create_webhook(self, name: str, channel_id_: int) -> str:
329365
config_str += f"webhooks_{webhook_name}__id={webhook_id}\n"
330366

331367
config_str += "\n#Emojis\n"
332-
config_str += "emojis_trashcan=🗑️"
368+
369+
existing_emojis = discord_client.list_emojis()
370+
log.debug("Syncing emojis with bot configuration.")
371+
for emoji_config_name, emoji_config in _Emojis.model_fields.items():
372+
if not (match := EMOJI_REGEX.match(emoji_config.default)):
373+
continue
374+
emoji_name = match.group(1)
375+
emoji_id = match.group(2)
376+
377+
for emoji in existing_emojis:
378+
if emoji["name"] == emoji_name:
379+
emoji_id = emoji["id"]
380+
break
381+
else:
382+
log.info("Creating emoji %s", emoji_name)
383+
emoji_id = discord_client.clone_emoji(name=emoji_name, id=emoji_id)
384+
385+
config_str += f"emojis_{emoji_config_name}=<:{emoji_name}:{emoji_id}>\n"
333386

334387
with env_file_path.open("wb") as file:
335388
file.write(config_str.encode("utf-8"))

0 commit comments

Comments
 (0)