Skip to content

Commit 463b4bd

Browse files
SoheabDA-344Rapptz
authored
Add support for application emojis
Co-authored-by: DA344 <[email protected]> Co-authored-by: Danny <[email protected]>
1 parent 62e5280 commit 463b4bd

File tree

4 files changed

+209
-4
lines changed

4 files changed

+209
-4
lines changed

discord/client.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,13 @@ def guilds(self) -> Sequence[Guild]:
366366

367367
@property
368368
def emojis(self) -> Sequence[Emoji]:
369-
"""Sequence[:class:`.Emoji`]: The emojis that the connected client has."""
369+
"""Sequence[:class:`.Emoji`]: The emojis that the connected client has.
370+
371+
.. note::
372+
373+
This not include the emojis that are owned by the application.
374+
Use :meth:`.fetch_application_emoji` to get those.
375+
"""
370376
return self._connection.emojis
371377

372378
@property
@@ -3073,3 +3079,97 @@ def persistent_views(self) -> Sequence[View]:
30733079
.. versionadded:: 2.0
30743080
"""
30753081
return self._connection.persistent_views
3082+
3083+
async def create_application_emoji(
3084+
self,
3085+
*,
3086+
name: str,
3087+
image: bytes,
3088+
) -> Emoji:
3089+
"""|coro|
3090+
3091+
Create an emoji for the current application.
3092+
3093+
.. versionadded:: 2.5
3094+
3095+
Parameters
3096+
----------
3097+
name: :class:`str`
3098+
The emoji name. Must be at least 2 characters.
3099+
image: :class:`bytes`
3100+
The :term:`py:bytes-like object` representing the image data to use.
3101+
Only JPG, PNG and GIF images are supported.
3102+
3103+
Raises
3104+
------
3105+
MissingApplicationID
3106+
The application ID could not be found.
3107+
HTTPException
3108+
Creating the emoji failed.
3109+
3110+
Returns
3111+
-------
3112+
:class:`.Emoji`
3113+
The emoji that was created.
3114+
"""
3115+
if self.application_id is None:
3116+
raise MissingApplicationID
3117+
3118+
img = utils._bytes_to_base64_data(image)
3119+
data = await self.http.create_application_emoji(self.application_id, name, img)
3120+
return Emoji(guild=Object(0), state=self._connection, data=data)
3121+
3122+
async def fetch_application_emoji(self, emoji_id: int, /) -> Emoji:
3123+
"""|coro|
3124+
3125+
Retrieves an emoji for the current application.
3126+
3127+
.. versionadded:: 2.5
3128+
3129+
Parameters
3130+
----------
3131+
emoji_id: :class:`int`
3132+
The emoji ID to retrieve.
3133+
3134+
Raises
3135+
------
3136+
MissingApplicationID
3137+
The application ID could not be found.
3138+
HTTPException
3139+
Retrieving the emoji failed.
3140+
3141+
Returns
3142+
-------
3143+
:class:`.Emoji`
3144+
The emoji requested.
3145+
"""
3146+
if self.application_id is None:
3147+
raise MissingApplicationID
3148+
3149+
data = await self.http.get_application_emoji(self.application_id, emoji_id)
3150+
return Emoji(guild=Object(0), state=self._connection, data=data)
3151+
3152+
async def fetch_application_emojis(self) -> List[Emoji]:
3153+
"""|coro|
3154+
3155+
Retrieves all emojis for the current application.
3156+
3157+
.. versionadded:: 2.5
3158+
3159+
Raises
3160+
-------
3161+
MissingApplicationID
3162+
The application ID could not be found.
3163+
HTTPException
3164+
Retrieving the emojis failed.
3165+
3166+
Returns
3167+
-------
3168+
List[:class:`.Emoji`]
3169+
The list of emojis for the current application.
3170+
"""
3171+
if self.application_id is None:
3172+
raise MissingApplicationID
3173+
3174+
data = await self.http.get_application_emojis(self.application_id)
3175+
return [Emoji(guild=Object(0), state=self._connection, data=emoji) for emoji in data['items']]

discord/emoji.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
from .utils import SnowflakeList, snowflake_time, MISSING
3030
from .partial_emoji import _EmojiTag, PartialEmoji
3131
from .user import User
32+
from .app_commands.errors import MissingApplicationID
33+
from .object import Object
3234

3335
# fmt: off
3436
__all__ = (
@@ -93,6 +95,10 @@ class Emoji(_EmojiTag, AssetMixin):
9395
user: Optional[:class:`User`]
9496
The user that created the emoji. This can only be retrieved using :meth:`Guild.fetch_emoji` and
9597
having :attr:`~Permissions.manage_emojis`.
98+
99+
Or if :meth:`.is_application_owned` is ``True``, this is the team member that uploaded
100+
the emoji, or the bot user if it was uploaded using the API and this can
101+
only be retrieved using :meth:`~discord.Client.fetch_application_emoji` or :meth:`~discord.Client.fetch_application_emojis`.
96102
"""
97103

98104
__slots__: Tuple[str, ...] = (
@@ -108,7 +114,7 @@ class Emoji(_EmojiTag, AssetMixin):
108114
'available',
109115
)
110116

111-
def __init__(self, *, guild: Guild, state: ConnectionState, data: EmojiPayload) -> None:
117+
def __init__(self, *, guild: Snowflake, state: ConnectionState, data: EmojiPayload) -> None:
112118
self.guild_id: int = guild.id
113119
self._state: ConnectionState = state
114120
self._from_data(data)
@@ -196,20 +202,32 @@ async def delete(self, *, reason: Optional[str] = None) -> None:
196202
197203
Deletes the custom emoji.
198204
199-
You must have :attr:`~Permissions.manage_emojis` to do this.
205+
You must have :attr:`~Permissions.manage_emojis` to do this if
206+
:meth:`.is_application_owned` is ``False``.
200207
201208
Parameters
202209
-----------
203210
reason: Optional[:class:`str`]
204211
The reason for deleting this emoji. Shows up on the audit log.
205212
213+
This does not apply if :meth:`.is_application_owned` is ``True``.
214+
206215
Raises
207216
-------
208217
Forbidden
209218
You are not allowed to delete emojis.
210219
HTTPException
211220
An error occurred deleting the emoji.
221+
MissingApplicationID
222+
The emoji is owned by an application but the application ID is missing.
212223
"""
224+
if self.is_application_owned():
225+
application_id = self._state.application_id
226+
if application_id is None:
227+
raise MissingApplicationID
228+
229+
await self._state.http.delete_application_emoji(application_id, self.id)
230+
return
213231

214232
await self._state.http.delete_custom_emoji(self.guild_id, self.id, reason=reason)
215233

@@ -231,15 +249,22 @@ async def edit(
231249
The new emoji name.
232250
roles: List[:class:`~discord.abc.Snowflake`]
233251
A list of roles that can use this emoji. An empty list can be passed to make it available to everyone.
252+
253+
This does not apply if :meth:`.is_application_owned` is ``True``.
254+
234255
reason: Optional[:class:`str`]
235256
The reason for editing this emoji. Shows up on the audit log.
236257
258+
This does not apply if :meth:`.is_application_owned` is ``True``.
259+
237260
Raises
238261
-------
239262
Forbidden
240263
You are not allowed to edit emojis.
241264
HTTPException
242265
An error occurred editing the emoji.
266+
MissingApplicationID
267+
The emoji is owned by an application but the application ID is missing
243268
244269
Returns
245270
--------
@@ -253,5 +278,25 @@ async def edit(
253278
if roles is not MISSING:
254279
payload['roles'] = [role.id for role in roles]
255280

281+
if self.is_application_owned():
282+
application_id = self._state.application_id
283+
if application_id is None:
284+
raise MissingApplicationID
285+
286+
payload.pop('roles', None)
287+
data = await self._state.http.edit_application_emoji(
288+
application_id,
289+
self.id,
290+
payload=payload,
291+
)
292+
return Emoji(guild=Object(0), data=data, state=self._state)
293+
256294
data = await self._state.http.edit_custom_emoji(self.guild_id, self.id, payload=payload, reason=reason)
257295
return Emoji(guild=self.guild, data=data, state=self._state) # type: ignore # if guild is None, the http request would have failed
296+
297+
def is_application_owned(self) -> bool:
298+
""":class:`bool`: Whether the emoji is owned by an application.
299+
300+
.. versionadded:: 2.5
301+
"""
302+
return self.guild_id == 0

discord/http.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2515,7 +2515,7 @@ def delete_entitlement(self, application_id: Snowflake, entitlement_id: Snowflak
25152515
),
25162516
)
25172517

2518-
# Misc
2518+
# Application
25192519

25202520
def application_info(self) -> Response[appinfo.AppInfo]:
25212521
return self.request(Route('GET', '/oauth2/applications/@me'))
@@ -2536,6 +2536,59 @@ def edit_application_info(self, *, reason: Optional[str], payload: Any) -> Respo
25362536
payload = {k: v for k, v in payload.items() if k in valid_keys}
25372537
return self.request(Route('PATCH', '/applications/@me'), json=payload, reason=reason)
25382538

2539+
def get_application_emojis(self, application_id: Snowflake) -> Response[appinfo.ListAppEmojis]:
2540+
return self.request(Route('GET', '/applications/{application_id}/emojis', application_id=application_id))
2541+
2542+
def get_application_emoji(self, application_id: Snowflake, emoji_id: Snowflake) -> Response[emoji.Emoji]:
2543+
return self.request(
2544+
Route(
2545+
'GET', '/applications/{application_id}/emojis/{emoji_id}', application_id=application_id, emoji_id=emoji_id
2546+
)
2547+
)
2548+
2549+
def create_application_emoji(
2550+
self,
2551+
application_id: Snowflake,
2552+
name: str,
2553+
image: str,
2554+
) -> Response[emoji.Emoji]:
2555+
payload = {
2556+
'name': name,
2557+
'image': image,
2558+
}
2559+
2560+
return self.request(
2561+
Route('POST', '/applications/{application_id}/emojis', application_id=application_id), json=payload
2562+
)
2563+
2564+
def edit_application_emoji(
2565+
self,
2566+
application_id: Snowflake,
2567+
emoji_id: Snowflake,
2568+
*,
2569+
payload: Dict[str, Any],
2570+
) -> Response[emoji.Emoji]:
2571+
r = Route(
2572+
'PATCH', '/applications/{application_id}/emojis/{emoji_id}', application_id=application_id, emoji_id=emoji_id
2573+
)
2574+
return self.request(r, json=payload)
2575+
2576+
def delete_application_emoji(
2577+
self,
2578+
application_id: Snowflake,
2579+
emoji_id: Snowflake,
2580+
) -> Response[None]:
2581+
return self.request(
2582+
Route(
2583+
'DELETE',
2584+
'/applications/{application_id}/emojis/{emoji_id}',
2585+
application_id=application_id,
2586+
emoji_id=emoji_id,
2587+
)
2588+
)
2589+
2590+
# Poll
2591+
25392592
def get_poll_answer_voters(
25402593
self,
25412594
channel_id: Snowflake,
@@ -2573,6 +2626,8 @@ def end_poll(self, channel_id: Snowflake, message_id: Snowflake) -> Response[mes
25732626
)
25742627
)
25752628

2629+
# Misc
2630+
25762631
async def get_gateway(self, *, encoding: str = 'json', zlib: bool = True) -> str:
25772632
try:
25782633
data = await self.request(Route('GET', '/gateway'))

discord/types/appinfo.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from .user import User
3131
from .team import Team
3232
from .snowflake import Snowflake
33+
from .emoji import Emoji
3334

3435

3536
class InstallParams(TypedDict):
@@ -79,3 +80,7 @@ class PartialAppInfo(BaseAppInfo, total=False):
7980
class GatewayAppInfo(TypedDict):
8081
id: Snowflake
8182
flags: int
83+
84+
85+
class ListAppEmojis(TypedDict):
86+
items: List[Emoji]

0 commit comments

Comments
 (0)