Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: application emojis #1209

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions disnake/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
from .channel import CategoryChannel, DMChannel, PartialMessageable
from .client import Client
from .embeds import Embed
from .emoji import Emoji
from .emoji import AnyEmoji
from .enums import InviteTarget
from .guild import Guild, GuildMessageable
from .guild_scheduled_event import GuildScheduledEvent
Expand Down Expand Up @@ -338,7 +338,7 @@ async def _edit(
video_quality_mode: VideoQualityMode = MISSING,
flags: ChannelFlags = MISSING,
available_tags: Sequence[ForumTag] = MISSING,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = MISSING,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = MISSING,
default_sort_order: Optional[ThreadSortOrder] = MISSING,
default_layout: ThreadLayout = MISSING,
reason: Optional[str] = None,
Expand Down
6 changes: 3 additions & 3 deletions disnake/audit_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

from .app_commands import APIApplicationCommand
from .automod import AutoModRule
from .emoji import Emoji
from .emoji import AnyEmoji, Emoji
from .guild import Guild
from .guild_scheduled_event import GuildScheduledEvent
from .integrations import PartialIntegration
Expand Down Expand Up @@ -280,7 +280,7 @@ def _transform_automod_trigger_metadata(

def _transform_default_reaction(
entry: AuditLogEntry, data: Optional[DefaultReactionPayload]
) -> Optional[Union[Emoji, PartialEmoji]]:
) -> Optional[Union[AnyEmoji, PartialEmoji]]:
if data is None:
return None
return entry._state._get_emoji_from_fields(
Expand Down Expand Up @@ -817,7 +817,7 @@ def _convert_target_invite(self, target_id: int) -> Invite:
def _convert_target_webhook(self, target_id: int) -> Union[Webhook, Object]:
return self._webhooks.get(target_id) or Object(id=target_id)

def _convert_target_emoji(self, target_id: int) -> Union[Emoji, Object]:
def _convert_target_emoji(self, target_id: int) -> Union[AnyEmoji, Object]:
return self._state.get_emoji(target_id) or Object(id=target_id)

def _convert_target_message(self, target_id: int) -> Union[Member, User, Object, None]:
Expand Down
16 changes: 8 additions & 8 deletions disnake/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
from .abc import Snowflake, SnowflakeTime
from .asset import AssetBytes
from .embeds import Embed
from .emoji import Emoji
from .emoji import AnyEmoji
from .guild import Guild, GuildChannel as GuildChannelType
from .member import Member, VoiceState
from .message import AllowedMentions, Message, PartialMessage
Expand Down Expand Up @@ -3314,7 +3314,7 @@ def requires_tag(self) -> bool:
return self.flags.require_tag

@property
def default_reaction(self) -> Optional[Union[Emoji, PartialEmoji]]:
def default_reaction(self) -> Optional[Union[AnyEmoji, PartialEmoji]]:
"""Optional[Union[:class:`Emoji`, :class:`PartialEmoji`]]:
The default emoji shown for reacting to threads.

Expand Down Expand Up @@ -3932,7 +3932,7 @@ async def edit(
flags: ChannelFlags = ...,
require_tag: bool = ...,
available_tags: Sequence[ForumTag] = ...,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = ...,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = ...,
default_sort_order: Optional[ThreadSortOrder] = ...,
default_layout: ThreadLayout = ...,
reason: Optional[str] = ...,
Expand All @@ -3955,7 +3955,7 @@ async def edit(
flags: ChannelFlags = MISSING,
require_tag: bool = MISSING,
available_tags: Sequence[ForumTag] = MISSING,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = MISSING,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = MISSING,
default_sort_order: Optional[ThreadSortOrder] = MISSING,
default_layout: ThreadLayout = MISSING,
reason: Optional[str] = None,
Expand Down Expand Up @@ -4102,7 +4102,7 @@ async def clone(
default_thread_slowmode_delay: Optional[int] = MISSING,
default_auto_archive_duration: Optional[AnyThreadArchiveDuration] = MISSING,
available_tags: Sequence[ForumTag] = MISSING,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = MISSING,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = MISSING,
default_sort_order: Optional[ThreadSortOrder] = MISSING,
default_layout: ThreadLayout = MISSING,
overwrites: Mapping[Union[Role, Member], PermissionOverwrite] = MISSING,
Expand Down Expand Up @@ -4362,7 +4362,7 @@ async def edit(
flags: ChannelFlags = ...,
require_tag: bool = ...,
available_tags: Sequence[ForumTag] = ...,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = ...,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = ...,
default_sort_order: Optional[ThreadSortOrder] = ...,
reason: Optional[str] = ...,
) -> MediaChannel:
Expand All @@ -4384,7 +4384,7 @@ async def edit(
flags: ChannelFlags = MISSING,
require_tag: bool = MISSING,
available_tags: Sequence[ForumTag] = MISSING,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = MISSING,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = MISSING,
default_sort_order: Optional[ThreadSortOrder] = MISSING,
reason: Optional[str] = None,
**kwargs: Never,
Expand Down Expand Up @@ -4503,7 +4503,7 @@ async def clone(
default_thread_slowmode_delay: Optional[int] = MISSING,
default_auto_archive_duration: Optional[AnyThreadArchiveDuration] = MISSING,
available_tags: Sequence[ForumTag] = MISSING,
default_reaction: Optional[Union[str, Emoji, PartialEmoji]] = MISSING,
default_reaction: Optional[Union[str, AnyEmoji, PartialEmoji]] = MISSING,
default_sort_order: Optional[ThreadSortOrder] = MISSING,
overwrites: Mapping[Union[Role, Member], PermissionOverwrite] = MISSING,
reason: Optional[str] = None,
Expand Down
100 changes: 95 additions & 5 deletions disnake/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,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 AnyEmoji, ApplicationEmoji
from .entitlement import Entitlement
from .enums import ApplicationCommandType, ChannelType, Event, Status
from .errors import (
Expand Down Expand Up @@ -373,6 +373,9 @@ class Client:
application commands.

.. versionadded:: 2.5
cache_app_emojis: :class:`bool`
Whether to automatically fetch and cache the application's emojis on startup and when fetching.
Defaults to ``False``.
"""

def __init__(
Expand Down Expand Up @@ -401,6 +404,7 @@ def __init__(
intents: Optional[Intents] = None,
chunk_guilds_at_startup: Optional[bool] = None,
member_cache_flags: Optional[MemberCacheFlags] = None,
cache_app_emojis: bool = False,
) -> None:
# self.ws is set in the connect method
self.ws: DiscordWebSocket = None # type: ignore
Expand Down Expand Up @@ -444,6 +448,7 @@ def __init__(
intents=intents,
chunk_guilds_at_startup=chunk_guilds_at_startup,
member_cache_flags=member_cache_flags,
cache_app_emojis=cache_app_emojis,
)
self.shard_id: Optional[int] = shard_id
self.shard_count: Optional[int] = shard_count
Expand Down Expand Up @@ -492,6 +497,7 @@ def _get_state(
application_id: Optional[int],
heartbeat_timeout: float,
guild_ready_timeout: float,
cache_app_emojis: bool,
allowed_mentions: Optional[AllowedMentions],
activity: Optional[BaseActivity],
status: Optional[Union[str, Status]],
Expand All @@ -515,6 +521,7 @@ def _get_state(
intents=intents,
chunk_guilds_at_startup=chunk_guilds_at_startup,
member_cache_flags=member_cache_flags,
cache_app_emojis=cache_app_emojis,
)

def _handle_ready(self) -> None:
Expand Down Expand Up @@ -559,8 +566,13 @@ def guilds(self) -> List[Guild]:
return self._connection.guilds

@property
def emojis(self) -> List[Emoji]:
"""List[:class:`.Emoji`]: The emojis that the connected client has."""
def emojis(self) -> List[AnyEmoji]:
"""The emojis that the connected client has.

.. note::
This only includes the application's emojis if :attr:`.cache_app_emojis` is
``True``.
"""
return self._connection.emojis

@property
Expand Down Expand Up @@ -1474,7 +1486,7 @@ def get_user(self, id: int, /) -> Optional[User]:
"""
return self._connection.get_user(id)

def get_emoji(self, id: int, /) -> Optional[Emoji]:
def get_emoji(self, id: int, /) -> Optional[AnyEmoji]:
"""Returns an emoji with the given ID.

Parameters
Expand All @@ -1484,7 +1496,7 @@ def get_emoji(self, id: int, /) -> Optional[Emoji]:

Returns
-------
Optional[:class:`.Emoji`]
Optional[Union[:class:`disnake.emoji.GuildEmoji`, :class:`disnake.emoji.ApplicationEmoji`]]
The custom emoji or ``None`` if not found.
"""
return self._connection.get_emoji(id)
Expand Down Expand Up @@ -3211,3 +3223,81 @@ async def create_entitlement(
owner_type=2 if isinstance(owner, abc.User) else 1,
)
return Entitlement(data=data, state=self._connection)

async def fetch_application_emojis(self) -> list[ApplicationEmoji]:
r"""|coro|
Retrieves all custom :class:`disnake.emoji.ApplicationEmoji`\s from the application.

Raises
------
HTTPException
An error occurred fetching the emojis.

Returns
-------
List[:class:`disnake.emoji.ApplicationEmoji`]
The retrieved emojis.
"""
emojis = await self._connection.http.get_all_application_emojis(self.application_id)
return [
self._connection.store_application_emoji(self.application_id, e)
for e in emojis["items"]
]

async def fetch_application_emoji(self, emoji_id: int, /) -> ApplicationEmoji:
"""|coro|
Retrieves a custom :class:`disnake.emoji.ApplicationEmoji` from the application.

Parameters
----------
emoji_id: :class:`int`
The emoji's ID.

Returns
-------
:class:`disnake.emoji.ApplicationEmoji`
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.store_application_emoji(self.application_id, data)

async def create_application_emoji(
self,
*,
name: str,
image: bytes,
) -> ApplicationEmoji:
r"""|coro|
Creates a custom :class:`disnake.emoji.ApplicationEmoji` 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
------
Forbidden
You are not allowed to create emojis.
HTTPException
An error occurred creating an emoji.

Returns
-------
:class:`disnake.emoji.ApplicationEmoji`
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.store_application_emoji(self.application_id, data)
4 changes: 2 additions & 2 deletions disnake/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
if TYPE_CHECKING:
from typing_extensions import Self, TypeAlias

from .emoji import Emoji
from .emoji import AnyEmoji
from .types.components import (
ActionRow as ActionRowPayload,
AnySelectMenu as AnySelectMenuPayload,
Expand Down Expand Up @@ -546,7 +546,7 @@ def __init__(
label: str,
value: str = MISSING,
description: Optional[str] = None,
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
emoji: Optional[Union[str, AnyEmoji, PartialEmoji]] = None,
default: bool = False,
) -> None:
self.label = label
Expand Down
Loading
Loading