Skip to content

Commit

Permalink
feat: app emojis (Pycord-Development#2501)
Browse files Browse the repository at this point in the history
* add routes

* unfinished methods, needs rework

* style(pre-commit): auto fixes from pre-commit.com hooks

* new classes

* style(pre-commit): auto fixes from pre-commit.com hooks

* refinements

* style(pre-commit): auto fixes from pre-commit.com hooks

* fix kwargs

* _state -> _connection

* style(pre-commit): auto fixes from pre-commit.com hooks

* cache on ready

* full cache

* remove delete reason

* style(pre-commit): auto fixes from pre-commit.com hooks

* adjust slots

* style(pre-commit): auto fixes from pre-commit.com hooks

* Update discord/emoji.py

Signed-off-by: plun1331 <[email protected]>

* style(pre-commit): auto fixes from pre-commit.com hooks

* update all references to the Emoji class

* style(pre-commit): auto fixes from pre-commit.com hooks

* misc

* cl

* style(pre-commit): auto fixes from pre-commit.com hooks

* add deprecation

---------

Signed-off-by: plun1331 <[email protected]>
Signed-off-by: UK <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Lala Sabathil <[email protected]>
Co-authored-by: plun1331 <[email protected]>
  • Loading branch information
4 people authored and OmLanke committed Dec 16, 2024
1 parent 461acfa commit 3db6ae3
Show file tree
Hide file tree
Showing 25 changed files with 595 additions and 174 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ These changes are available on the `master` branch, but have not yet been releas
`tags`. ([#2520](https://github.com/Pycord-Development/pycord/pull/2520))
- Added `Member.guild_banner` and `Member.display_banner` properties.
([#2556](https://github.com/Pycord-Development/pycord/pull/2556))
- Added support for Application Emojis.
([#2501](https://github.com/Pycord-Development/pycord/pull/2501))
- Added `cache_app_emojis` parameter to `Client`.
([#2501](https://github.com/Pycord-Development/pycord/pull/2501))
- Added `elapsed` method to `VoiceClient`.
([#2587](https://github.com/Pycord-Development/pycord/pull/2587/))
- Added optional `filter` parameter to `utils.basic_autocomplete()`.
Expand Down Expand Up @@ -52,6 +56,8 @@ These changes are available on the `master` branch, but have not yet been releas
([#2496](https://github.com/Pycord-Development/pycord/pull/2496))
- ⚠️ **Removed support for Python 3.8.**
([#2521](https://github.com/Pycord-Development/pycord/pull/2521))
- `Emoji` has been renamed to `GuildEmoji`.
([#2501](https://github.com/Pycord-Development/pycord/pull/2501))
- Replaced audioop (deprecated module) implementation of `PCMVolumeTransformer.read`
method with a pure Python equivalent.
([#2176](https://github.com/Pycord-Development/pycord/pull/2176))
Expand All @@ -60,6 +66,8 @@ These changes are available on the `master` branch, but have not yet been releas

- Deprecated `AppInfo.summary` in favor of `AppInfo.description`.
([#2520](https://github.com/Pycord-Development/pycord/pull/2520))
- Deprecated `Emoji` in favor of `GuildEmoji`
([#2501](https://github.com/Pycord-Development/pycord/pull/2501))

## [2.6.1] - 2024-09-15

Expand Down
10 changes: 6 additions & 4 deletions discord/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,9 @@ async def _edit(
except KeyError:
pass
else:
if isinstance(default_reaction_emoji, _EmojiTag): # Emoji, PartialEmoji
if isinstance(
default_reaction_emoji, _EmojiTag
): # GuildEmoji, PartialEmoji
default_reaction_emoji = default_reaction_emoji._to_partial()
elif isinstance(default_reaction_emoji, int):
default_reaction_emoji = PartialEmoji(
Expand All @@ -523,7 +525,7 @@ async def _edit(
default_reaction_emoji = PartialEmoji.from_str(default_reaction_emoji)
else:
raise InvalidArgument(
"default_reaction_emoji must be of type: Emoji | int | str"
"default_reaction_emoji must be of type: GuildEmoji | int | str"
)

options["default_reaction_emoji"] = (
Expand Down Expand Up @@ -1792,7 +1794,7 @@ def can_send(self, *objects) -> bool:
"Message": "send_messages",
"Embed": "embed_links",
"File": "attach_files",
"Emoji": "use_external_emojis",
"GuildEmoji": "use_external_emojis",
"GuildSticker": "use_external_stickers",
}
# Can't use channel = await self._get_channel() since its async
Expand All @@ -1817,7 +1819,7 @@ def can_send(self, *objects) -> bool:
mapping.get(type(obj).__name__) or mapping[obj.__name__]
)

if type(obj).__name__ == "Emoji":
if type(obj).__name__ == "GuildEmoji":
if (
obj._to_partial().is_unicode_emoji
or obj.guild_id == channel.guild.id
Expand Down
6 changes: 3 additions & 3 deletions discord/audit_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import datetime

from . import abc
from .emoji import Emoji
from .emoji import GuildEmoji
from .guild import Guild
from .member import Member
from .role import Role
Expand Down Expand Up @@ -617,7 +617,7 @@ def target(
| User
| Role
| Invite
| Emoji
| GuildEmoji
| StageInstance
| GuildSticker
| Thread
Expand Down Expand Up @@ -689,7 +689,7 @@ def _convert_target_invite(self, target_id: int) -> Invite:
pass
return obj

def _convert_target_emoji(self, target_id: int) -> Emoji | Object:
def _convert_target_emoji(self, target_id: int) -> GuildEmoji | Object:
return self._state.get_emoji(target_id) or Object(id=target_id)

def _convert_target_message(self, target_id: int) -> Member | User | None:
Expand Down
12 changes: 6 additions & 6 deletions discord/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

from . import utils
from .asset import Asset
from .emoji import Emoji
from .emoji import GuildEmoji
from .enums import (
ChannelType,
EmbeddedActivity,
Expand Down Expand Up @@ -143,7 +143,7 @@ def __init__(
self.emoji = PartialEmoji.from_str(emoji)
else:
raise TypeError(
"emoji must be a Emoji, PartialEmoji, or str and not"
"emoji must be a GuildEmoji, PartialEmoji, or str and not"
f" {emoji.__class__!r}"
)

Expand Down Expand Up @@ -1018,7 +1018,7 @@ class ForumChannel(_TextChannel):
The initial slowmode delay to set on newly created threads in this channel.
.. versionadded:: 2.3
default_reaction_emoji: Optional[:class:`str` | :class:`discord.Emoji`]
default_reaction_emoji: Optional[:class:`str` | :class:`discord.GuildEmoji`]
The default forum reaction emoji.
.. versionadded:: 2.5
Expand Down Expand Up @@ -1087,7 +1087,7 @@ async def edit(
default_auto_archive_duration: ThreadArchiveDuration = ...,
default_thread_slowmode_delay: int = ...,
default_sort_order: SortOrder = ...,
default_reaction_emoji: Emoji | int | str | None = ...,
default_reaction_emoji: GuildEmoji | int | str | None = ...,
available_tags: list[ForumTag] = ...,
require_tag: bool = ...,
overwrites: Mapping[Role | Member | Snowflake, PermissionOverwrite] = ...,
Expand Down Expand Up @@ -1138,10 +1138,10 @@ async def edit(self, *, reason=None, **options):
The default sort order type to use to order posts in this channel.
.. versionadded:: 2.3
default_reaction_emoji: Optional[:class:`discord.Emoji` | :class:`int` | :class:`str`]
default_reaction_emoji: Optional[:class:`discord.GuildEmoji` | :class:`int` | :class:`str`]
The default reaction emoji.
Can be a unicode emoji or a custom emoji in the forms:
:class:`Emoji`, snowflake ID, string representation (eg. '<a:emoji_name:emoji_id>').
:class:`GuildEmoji`, snowflake ID, string representation (eg. '<a:emoji_name:emoji_id>').
.. versionadded:: 2.5
available_tags: List[:class:`ForumTag`]
Expand Down
149 changes: 144 additions & 5 deletions discord/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from .application_role_connection import ApplicationRoleConnectionMetadata
from .backoff import ExponentialBackoff
from .channel import PartialMessageable, _threaded_channel_factory
from .emoji import Emoji
from .emoji import AppEmoji, GuildEmoji
from .enums import ChannelType, Status
from .errors import *
from .flags import ApplicationFlags, Intents
Expand Down Expand Up @@ -199,6 +199,16 @@ class Client:
To enable these events, this must be set to ``True``. Defaults to ``False``.
.. versionadded:: 2.0
cache_app_emojis: :class:`bool`
Whether to automatically fetch and cache the application's emojis on startup and when fetching. Defaults to ``False``.
.. warning::
There are no events related to application emojis - if any are created/deleted on the
Developer Dashboard while the client is running, the cache will not be updated until you manually
run :func:`fetch_emojis`.
.. versionadded:: 2.7
Attributes
-----------
Expand Down Expand Up @@ -330,10 +340,30 @@ def guilds(self) -> list[Guild]:
return self._connection.guilds

@property
def emojis(self) -> list[Emoji]:
"""The emojis that the connected client has."""
def emojis(self) -> list[GuildEmoji | AppEmoji]:
"""The emojis that the connected client has.
.. note::
This only includes the application's emojis if `cache_app_emojis` is ``True``.
"""
return self._connection.emojis

@property
def guild_emojis(self) -> list[GuildEmoji]:
"""The :class:`~discord.GuildEmoji` that the connected client has."""
return [e for e in self.emojis if isinstance(e, GuildEmoji)]

@property
def app_emojis(self) -> list[AppEmoji]:
"""The :class:`~discord.AppEmoji` that the connected client has.
.. note::
This is only available if `cache_app_emojis` is ``True``.
"""
return [e for e in self.emojis if isinstance(e, AppEmoji)]

@property
def stickers(self) -> list[GuildSticker]:
"""The stickers that the connected client has.
Expand Down Expand Up @@ -994,7 +1024,7 @@ def get_user(self, id: int, /) -> User | None:
"""
return self._connection.get_user(id)

def get_emoji(self, id: int, /) -> Emoji | None:
def get_emoji(self, id: int, /) -> GuildEmoji | AppEmoji | None:
"""Returns an emoji with the given ID.
Parameters
Expand All @@ -1004,7 +1034,7 @@ def get_emoji(self, id: int, /) -> Emoji | None:
Returns
-------
Optional[:class:`.Emoji`]
Optional[:class:`.GuildEmoji` | :class:`.AppEmoji`]
The custom emoji or ``None`` if not found.
"""
return self._connection.get_emoji(id)
Expand Down Expand Up @@ -2130,3 +2160,112 @@ def store_url(self) -> str:
.. versionadded:: 2.6
"""
return f"https://discord.com/application-directory/{self.application_id}/store"

async def fetch_emojis(self) -> list[AppEmoji]:
r"""|coro|
Retrieves all custom :class:`AppEmoji`\s from the application.
Raises
---------
HTTPException
An error occurred fetching the emojis.
Returns
--------
List[:class:`AppEmoji`]
The retrieved emojis.
"""
data = await self._connection.http.get_all_application_emojis(
self.application_id
)
return [
self._connection.maybe_store_app_emoji(self.application_id, d)
for d in data["items"]
]

async def fetch_emoji(self, emoji_id: int, /) -> AppEmoji:
"""|coro|
Retrieves a custom :class:`AppEmoji` from the application.
Parameters
----------
emoji_id: :class:`int`
The emoji's ID.
Returns
-------
:class:`AppEmoji`
The retrieved emoji.
Raises
------
NotFound
The emoji requested could not be found.
HTTPException
An error occurred fetching the emoji.
"""
data = await self._connection.http.get_application_emoji(
self.application_id, emoji_id
)
return self._connection.maybe_store_app_emoji(self.application_id, data)

async def create_emoji(
self,
*,
name: str,
image: bytes,
) -> AppEmoji:
r"""|coro|
Creates a custom :class:`AppEmoji` for the application.
There is currently a limit of 2000 emojis per application.
Parameters
-----------
name: :class:`str`
The emoji name. Must be at least 2 characters.
image: :class:`bytes`
The :term:`py:bytes-like object` representing the image data to use.
Only JPG, PNG and GIF images are supported.
Raises
-------
HTTPException
An error occurred creating an emoji.
Returns
--------
:class:`AppEmoji`
The created emoji.
"""

img = utils._bytes_to_base64_data(image)
data = await self._connection.http.create_application_emoji(
self.application_id, name, img
)
return self._connection.maybe_store_app_emoji(self.application_id, data)

async def delete_emoji(self, emoji: Snowflake) -> None:
"""|coro|
Deletes the custom :class:`AppEmoji` from the application.
Parameters
----------
emoji: :class:`abc.Snowflake`
The emoji you are deleting.
Raises
------
HTTPException
An error occurred deleting the emoji.
"""

await self._connection.http.delete_application_emoji(
self.application_id, emoji.id
)
if self._connection.cache_app_emojis and self._connection.get_emoji(emoji.id):
self._connection.remove_emoji(emoji)
8 changes: 4 additions & 4 deletions discord/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from .utils import MISSING, get_slots

if TYPE_CHECKING:
from .emoji import Emoji
from .emoji import AppEmoji, GuildEmoji
from .types.components import ActionRow as ActionRowPayload
from .types.components import ButtonComponent as ButtonComponentPayload
from .types.components import Component as ComponentPayload
Expand Down Expand Up @@ -412,7 +412,7 @@ def __init__(
label: str,
value: str = MISSING,
description: str | None = None,
emoji: str | Emoji | PartialEmoji | None = None,
emoji: str | GuildEmoji | AppEmoji | PartialEmoji | None = None,
default: bool = False,
) -> None:
if len(label) > 100:
Expand Down Expand Up @@ -444,7 +444,7 @@ def __str__(self) -> str:
return base

@property
def emoji(self) -> str | Emoji | PartialEmoji | None:
def emoji(self) -> str | GuildEmoji | AppEmoji | PartialEmoji | None:
"""The emoji of the option, if available."""
return self._emoji

Expand All @@ -457,7 +457,7 @@ def emoji(self, value) -> None:
value = value._to_partial()
else:
raise TypeError(
"expected emoji to be str, Emoji, or PartialEmoji not"
"expected emoji to be str, GuildEmoji, AppEmoji, or PartialEmoji, not"
f" {value.__class__}"
)

Expand Down
Loading

0 comments on commit 3db6ae3

Please sign in to comment.