Skip to content

Commit 4a38ba3

Browse files
committed
Implement custom emoji uploading
1 parent f98bd88 commit 4a38ba3

File tree

7 files changed

+68
-10
lines changed

7 files changed

+68
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
88

99
### Changed
1010

11+
* Implemented a system for custom application emoji, currently only used by the "apps icon" when resending a private message publicly.
1112
* Updated discord.py to `2.5.0`.
1213

1314
## `0.2.2` - 2025-02-17

bot/src/ghutils/cogs/commands/sync.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ async def sync_all(self, ctx: GHUtilsContext):
3535

3636
await ctx.reply("Synced global slash commands to all guilds.")
3737

38+
@sync.command(name="emoji", aliases=["emojis", "emotes"])
39+
async def sync_emoji(self, ctx: GHUtilsContext):
40+
async with ctx.channel.typing():
41+
await self.bot.sync_custom_emojis()
42+
43+
await ctx.reply("Synced custom bot emojis.")
44+
3845
@commands.group(invoke_without_command=True)
3946
@commands.guild_only()
4047
async def clear(self, ctx: GHUtilsContext):

bot/src/ghutils/cogs/events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class EventsCog(GHUtilsCog):
1717
async def on_ready(self):
1818
logger.info(f"Logged in as {self.bot.user}")
1919
self.bot.add_dynamic_items(PermanentDeleteButton)
20+
await self.bot.fetch_custom_emojis()
2021

2122
@Cog.listener()
2223
async def on_interaction(self, interaction: Interaction):

bot/src/ghutils/core/bot.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing import Any
66

77
import yaml
8-
from discord import Color, CustomActivity, Intents, Interaction
8+
from discord import Color, CustomActivity, Emoji, Intents, Interaction
99
from discord.app_commands import AppCommandContext, AppInstallationType
1010
from discord.ext import commands
1111
from discord.ext.commands import Bot, Context, NoEntryPointError
@@ -21,7 +21,7 @@
2121
from .env import GHUtilsEnv
2222
from .translator import GHUtilsTranslator
2323
from .tree import GHUtilsCommandTree
24-
from .types import LoginState
24+
from .types import CustomEmoji, LoginState
2525

2626
logger = logging.getLogger(__name__)
2727

@@ -50,6 +50,7 @@ def __post_init__(self):
5050
self.engine = create_engine(self.env.db_url)
5151
self.start_time = datetime.now()
5252
self.language_colors = self._load_language_colors()
53+
self._custom_emoji = dict[CustomEmoji, Emoji]()
5354

5455
@classmethod
5556
def of(cls, interaction: Interaction):
@@ -139,3 +140,34 @@ def get_language_color(self, language: str) -> Color:
139140
gh_default: Color = Color.from_str("#1B1F24")
140141

141142
return self.language_colors.get(language, gh_default)
143+
144+
async def fetch_custom_emojis(self):
145+
logger.info("Fetching custom emojis")
146+
147+
application_emojis = {
148+
emoji.name: emoji for emoji in await self.fetch_application_emojis()
149+
}
150+
151+
self._custom_emoji.clear()
152+
for custom_emoji in CustomEmoji:
153+
if emoji := application_emojis.get(custom_emoji.name):
154+
self._custom_emoji[custom_emoji] = emoji
155+
else:
156+
logger.warning(
157+
f"Failed to find custom emoji (try running `sync emoji` command): {custom_emoji.name}"
158+
)
159+
160+
async def sync_custom_emojis(self):
161+
logger.info("Syncing/uploading custom emojis")
162+
self._custom_emoji.clear()
163+
for custom_emoji in CustomEmoji:
164+
self._custom_emoji[custom_emoji] = await self.create_application_emoji(
165+
name=custom_emoji.name,
166+
image=custom_emoji.load_image(),
167+
)
168+
169+
def get_custom_emoji(self, custom_emoji: CustomEmoji) -> Emoji:
170+
emoji = self._custom_emoji.get(custom_emoji)
171+
if emoji is None:
172+
raise ValueError(f"Failed to find custom emoji: {custom_emoji.name}")
173+
return emoji

bot/src/ghutils/core/types.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
from enum import Enum, auto
22

3+
from typing_extensions import deprecated
4+
5+
from ghutils.resources import get_resource
6+
37

48
class LoginState(Enum):
59
LOGGED_IN = auto()
610
LOGGED_OUT = auto()
711
EXPIRED = auto()
12+
13+
14+
class CustomEmoji(Enum):
15+
apps_icon = "apps_icon.png"
16+
17+
def __init__(self, filename: str):
18+
self.filename = filename
19+
20+
@property
21+
@deprecated("Use name or filename instead", category=None)
22+
def value(self):
23+
return super().value
24+
25+
def load_image(self) -> bytes:
26+
return get_resource(f"emoji/{self.filename}").read_bytes()
3 KB
Loading

bot/src/ghutils/utils/discord/visibility.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33
from re import Match
44
from typing import Any, Literal, Self
55

6-
from discord import (
7-
Embed,
8-
Interaction,
9-
PartialEmoji,
10-
ui,
11-
)
6+
from discord import Embed, Interaction, ui
127
from discord.app_commands import Command, ContextMenu
138
from discord.ui import Button, DynamicItem, Item, View
149
from discord.utils import MISSING
1510

11+
from ghutils.core.bot import GHUtilsBot
12+
from ghutils.core.types import CustomEmoji
13+
1614
from .commands import AnyCommand
1715

1816
type MessageVisibility = Literal["public", "private"]
@@ -76,10 +74,10 @@ def _get_view(
7674
label = f"{interaction.user.name} used /{command_name}"
7775
case _:
7876
label = f"Sent by {interaction.user.name}"
77+
bot = GHUtilsBot.of(interaction)
7978
view.add_item(
8079
Button(
81-
# FIXME: remove hardcoded emoji id
82-
emoji=PartialEmoji(name="apps_icon", id=1279865345250693151),
80+
emoji=bot.get_custom_emoji(CustomEmoji.apps_icon),
8381
label=label,
8482
disabled=True,
8583
)

0 commit comments

Comments
 (0)