Source code for discord_http.emoji

import re

from typing import TYPE_CHECKING, Union, Optional, Self

from . import utils
from .asset import Asset
from .object import PartialBase, Snowflake
from .role import PartialRole

if TYPE_CHECKING:
    from .guild import PartialGuild
    from .http import DiscordAPI
    from .user import User

MISSING = utils.MISSING

__all__ = (
    "Emoji",
    "EmojiParser",
    "PartialEmoji",
)


[docs] class EmojiParser: """ This is used to accept any input and convert to either a normal emoji or a Discord emoji automatically. It is used for things like reactions, forum, components, etc Examples: --------- - `EmojiParser("👍")` - `EmojiParser("<:name:1234567890>")` - `EmojiParser("1234567890")` """ def __init__(self, emoji: str): self._original_name: str = emoji self.id: Optional[int] = None self.animated: bool = False self.discord_emoji: bool = False is_custom: Optional[re.Match] = utils.re_emoji.search(emoji) if is_custom: _animated, _name, _id = is_custom.groups() self.discord_emoji = True self.animated = bool(_animated) self.name: str = _name self.id = int(_id) elif emoji.isdigit(): self.discord_emoji = True self.id = int(emoji) self.name: str = emoji else: self.name: str = emoji def __repr__(self) -> str: if self.discord_emoji: return f"<EmojiParser name='{self.name}' id={self.id}>" return f"<EmojiParser name='{self.name}'>" def __str__(self) -> str: return self._original_name def __int__(self) -> Optional[int]: if self.discord_emoji: return self.id return None
[docs] @classmethod def from_dict(cls, data: dict) -> Self: return cls( f"<{'a' if data.get('animated', None) else ''}:" f"{data['name']}:{data['id']}>" )
@property def url(self) -> Optional[str]: """ `str`: Returns the URL of the emoji if it's a Discord emoji """ if self.discord_emoji: return f"{Asset.BASE}/emojis/{self.id}.{'gif' if self.animated else 'png'}" return None
[docs] def to_dict(self) -> dict: """ `dict`: Returns a dict representation of the emoji """ if self.discord_emoji: # Include animated if it's a Discord emoji return {"id": self.id, "name": self.name, "animated": self.animated} return {"name": self.name, "id": None}
[docs] def to_forum_dict(self) -> dict: """ `dict`: Returns a dict representation of emoji to forum/media channel """ payload = { "emoji_name": self.name, "emoji_id": None } if self.discord_emoji: return {"emoji_name": None, "emoji_id": str(self.id)} return payload
[docs] def to_reaction(self) -> str: """ `str`: Returns a string representation of the emoji """ if self.discord_emoji: return f"{self.name}:{self.id}" return self.name
[docs] class PartialEmoji(PartialBase): def __init__( self, *, state: "DiscordAPI", id: int, guild_id: Optional[int] = None ): super().__init__(id=int(id)) self._state = state self.id: int = id self.guild_id: Optional[int] = guild_id def __repr__(self) -> str: return f"<PartialEmoji id={self.id}>" @property def guild(self) -> Optional["PartialGuild"]: """ `PartialGuild`: The guild of the member. """ if not self.guild_id: return None from .guild import PartialGuild return PartialGuild(state=self._state, id=self.guild_id) @property def url(self) -> str: """ `str`: Returns the URL of the emoji. It will always be PNG as it's a partial emoji. """ return f"{Asset.BASE}/emojis/{self.id}.png"
[docs] async def fetch(self) -> "Emoji": """ `Emoji`: Fetches the emoji. If `guild_id` is not defined, it will fetch the emoji from the application. """ if self.guild_id: r = await self._state.query( "GET", f"/guilds/{self.guild_id}/emojis/{self.id}" ) return Emoji( state=self._state, guild=self.guild, data=r.response ) else: r = await self._state.query( "GET", f"/applications/{self._state.application_id}/emojis/{self.id}" ) return Emoji( state=self._state, data=r.response )
[docs] async def delete( self, *, reason: Optional[str] = None ) -> None: """ Deletes the emoji. If `guild_id` is not defined, it will delete the emoji from the application. Parameters ---------- reason: `Optional[str]` The reason for deleting the emoji. """ if self.guild_id: await self._state.query( "DELETE", f"/guilds/{self.guild.id}/emojis/{self.id}", res_method="text", reason=reason ) else: await self._state.query( "DELETE", f"/applications/{self._state.application_id}/emojis/{self.id}", res_method="text" )
[docs] async def edit( self, *, name: Optional[str] = MISSING, roles: Optional[list[Union[PartialRole, int]]] = MISSING, reason: Optional[str] = None ): """ Edits the emoji. Parameters ---------- name: `Optional[str]` The new name of the emoji. roles: `Optional[list[Union[PartialRole, int]]]` Roles that are allowed to use the emoji. (Only for guilds) reason: `Optional[str]` The reason for editing the emoji. (Only for guilds) Returns ------- `Emoji` The edited emoji. Raises ------ ValueError Whenever guild_id is not defined """ payload = {} if name is not MISSING: payload["name"] = name if isinstance(roles, list): payload["roles"] = [ int(r) for r in roles if isinstance(r, Snowflake) ] if self.guild_id: r = await self._state.query( "PATCH", f"/guilds/{self.guild.id}/emojis/{self.id}", json=payload, reason=reason ) return Emoji( state=self._state, guild=self.guild, data=r.response ) else: if not payload.get("name", None): raise ValueError( "name is required when guild_id for emoji is not defined" ) r = await self._state.query( "PATCH", f"/applications/{self._state.application_id}/emojis/{self.id}", json={"name": payload["name"]}, )
[docs] class Emoji(PartialEmoji): def __init__( self, *, state: "DiscordAPI", data: dict, guild: Optional["PartialGuild"] = None, ): super().__init__( state=state, id=int(data["id"]), guild_id=guild.id if guild else None ) self.name: str = data["name"] self.animated: bool = data.get("animated", False) self.available: bool = data.get("available", True) self.require_colons: bool = data.get("require_colons", True) self.managed: bool = data.get("managed", False) self.user: Optional["User"] = None self.roles: list[PartialRole] = [ PartialRole(state=state, id=r, guild_id=guild.id) for r in data.get("roles", []) ] self._from_data(data) def __repr__(self) -> str: return f"<Emoji id={self.id} name='{self.name}' animated={self.animated}>" def __str__(self) -> str: return f"<{'a' if self.animated else ''}:{self.name}:{self.id}>" def _from_data(self, data: dict): if data.get("user", None): from .user import User self.user = User(state=self._state, data=data["user"]) @property def url(self) -> str: """ `str`: Returns the URL of the emoji """ return f"{Asset.BASE}/emojis/{self.id}.{'gif' if self.animated else 'png'}"