implement guild stickers
This commit is contained in:
parent
ecf239d2a2
commit
60d82cf908
@ -31,12 +31,11 @@ from typing import (
|
|||||||
Callable,
|
Callable,
|
||||||
Dict,
|
Dict,
|
||||||
List,
|
List,
|
||||||
Mapping,
|
|
||||||
Optional,
|
Optional,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Protocol,
|
Protocol,
|
||||||
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
Type,
|
|
||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union,
|
||||||
overload,
|
overload,
|
||||||
@ -53,6 +52,7 @@ from .role import Role
|
|||||||
from .invite import Invite
|
from .invite import Invite
|
||||||
from .file import File
|
from .file import File
|
||||||
from .voice_client import VoiceClient, VoiceProtocol
|
from .voice_client import VoiceClient, VoiceProtocol
|
||||||
|
from .sticker import GuildSticker, StickerItem
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -1164,6 +1164,7 @@ class Messageable:
|
|||||||
tts: bool = ...,
|
tts: bool = ...,
|
||||||
embed: Embed = ...,
|
embed: Embed = ...,
|
||||||
file: File = ...,
|
file: File = ...,
|
||||||
|
stickers: Sequence[Union[GuildSticker, StickerItem]] = ...,
|
||||||
delete_after: float = ...,
|
delete_after: float = ...,
|
||||||
nonce: Union[str, int] = ...,
|
nonce: Union[str, int] = ...,
|
||||||
allowed_mentions: AllowedMentions = ...,
|
allowed_mentions: AllowedMentions = ...,
|
||||||
@ -1181,6 +1182,7 @@ class Messageable:
|
|||||||
tts: bool = ...,
|
tts: bool = ...,
|
||||||
embed: Embed = ...,
|
embed: Embed = ...,
|
||||||
files: List[File] = ...,
|
files: List[File] = ...,
|
||||||
|
stickers: Sequence[Union[GuildSticker, StickerItem]] = ...,
|
||||||
delete_after: float = ...,
|
delete_after: float = ...,
|
||||||
nonce: Union[str, int] = ...,
|
nonce: Union[str, int] = ...,
|
||||||
allowed_mentions: AllowedMentions = ...,
|
allowed_mentions: AllowedMentions = ...,
|
||||||
@ -1198,6 +1200,7 @@ class Messageable:
|
|||||||
tts: bool = ...,
|
tts: bool = ...,
|
||||||
embeds: List[Embed] = ...,
|
embeds: List[Embed] = ...,
|
||||||
file: File = ...,
|
file: File = ...,
|
||||||
|
stickers: Sequence[Union[GuildSticker, StickerItem]] = ...,
|
||||||
delete_after: float = ...,
|
delete_after: float = ...,
|
||||||
nonce: Union[str, int] = ...,
|
nonce: Union[str, int] = ...,
|
||||||
allowed_mentions: AllowedMentions = ...,
|
allowed_mentions: AllowedMentions = ...,
|
||||||
@ -1215,6 +1218,7 @@ class Messageable:
|
|||||||
tts: bool = ...,
|
tts: bool = ...,
|
||||||
embeds: List[Embed] = ...,
|
embeds: List[Embed] = ...,
|
||||||
files: List[File] = ...,
|
files: List[File] = ...,
|
||||||
|
stickers: Sequence[Union[GuildSticker, StickerItem]] = ...,
|
||||||
delete_after: float = ...,
|
delete_after: float = ...,
|
||||||
nonce: Union[str, int] = ...,
|
nonce: Union[str, int] = ...,
|
||||||
allowed_mentions: AllowedMentions = ...,
|
allowed_mentions: AllowedMentions = ...,
|
||||||
@ -1233,6 +1237,7 @@ class Messageable:
|
|||||||
embeds=None,
|
embeds=None,
|
||||||
file=None,
|
file=None,
|
||||||
files=None,
|
files=None,
|
||||||
|
stickers=None,
|
||||||
delete_after=None,
|
delete_after=None,
|
||||||
nonce=None,
|
nonce=None,
|
||||||
allowed_mentions=None,
|
allowed_mentions=None,
|
||||||
@ -1304,6 +1309,10 @@ class Messageable:
|
|||||||
embeds: List[:class:`~discord.Embed`]
|
embeds: List[:class:`~discord.Embed`]
|
||||||
A list of embeds to upload. Must be a maximum of 10.
|
A list of embeds to upload. Must be a maximum of 10.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
stickers: Sequence[Union[:class:`GuildSticker`, :class:`StickerItem`]]
|
||||||
|
A list of stickers to upload. Must be a maximum of 3.
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
@ -1340,6 +1349,9 @@ class Messageable:
|
|||||||
raise InvalidArgument('embeds parameter must be a list of up to 10 elements')
|
raise InvalidArgument('embeds parameter must be a list of up to 10 elements')
|
||||||
embeds = [embed.to_dict() for embed in embeds]
|
embeds = [embed.to_dict() for embed in embeds]
|
||||||
|
|
||||||
|
if stickers is not None:
|
||||||
|
stickers = [sticker.id for sticker in stickers]
|
||||||
|
|
||||||
if allowed_mentions is not None:
|
if allowed_mentions is not None:
|
||||||
if state.allowed_mentions is not None:
|
if state.allowed_mentions is not None:
|
||||||
allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()
|
allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()
|
||||||
@ -1384,6 +1396,7 @@ class Messageable:
|
|||||||
embeds=embeds,
|
embeds=embeds,
|
||||||
nonce=nonce,
|
nonce=nonce,
|
||||||
message_reference=reference,
|
message_reference=reference,
|
||||||
|
stickers=stickers,
|
||||||
components=components,
|
components=components,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
@ -1406,6 +1419,7 @@ class Messageable:
|
|||||||
nonce=nonce,
|
nonce=nonce,
|
||||||
allowed_mentions=allowed_mentions,
|
allowed_mentions=allowed_mentions,
|
||||||
message_reference=reference,
|
message_reference=reference,
|
||||||
|
stickers=stickers,
|
||||||
components=components,
|
components=components,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
@ -1421,6 +1435,7 @@ class Messageable:
|
|||||||
nonce=nonce,
|
nonce=nonce,
|
||||||
allowed_mentions=allowed_mentions,
|
allowed_mentions=allowed_mentions,
|
||||||
message_reference=reference,
|
message_reference=reference,
|
||||||
|
stickers=stickers,
|
||||||
components=components,
|
components=components,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -216,11 +216,11 @@ class Asset(AssetMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_sticker(cls, state, sticker_id: int, sticker_hash: str) -> Asset:
|
def _from_sticker_banner(cls, state, banner: int) -> Asset:
|
||||||
return cls(
|
return cls(
|
||||||
state,
|
state,
|
||||||
url=f'{cls.BASE}/stickers/{sticker_id}/{sticker_hash}.png?size=1024',
|
url=f'{cls.BASE}/app-assets/710982414301790216/store/{banner}.png',
|
||||||
key=sticker_hash,
|
key=str(banner),
|
||||||
animated=False,
|
animated=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ if TYPE_CHECKING:
|
|||||||
from .types.snowflake import Snowflake
|
from .types.snowflake import Snowflake
|
||||||
from .user import User
|
from .user import User
|
||||||
from .stage_instance import StageInstance
|
from .stage_instance import StageInstance
|
||||||
|
from .sticker import GuildSticker
|
||||||
from .threads import Thread
|
from .threads import Thread
|
||||||
|
|
||||||
|
|
||||||
@ -79,16 +80,15 @@ def _transform_channel(entry: AuditLogEntry, data: Optional[Snowflake]) -> Optio
|
|||||||
return entry.guild.get_channel(int(data)) or Object(id=data)
|
return entry.guild.get_channel(int(data)) or Object(id=data)
|
||||||
|
|
||||||
|
|
||||||
def _transform_owner_id(entry: AuditLogEntry, data: Optional[Snowflake]) -> Union[Member, User, None]:
|
def _transform_member_id(entry: AuditLogEntry, data: Optional[Snowflake]) -> Union[Member, User, None]:
|
||||||
if data is None:
|
if data is None:
|
||||||
return None
|
return None
|
||||||
return entry._get_member(int(data))
|
return entry._get_member(int(data))
|
||||||
|
|
||||||
|
def _transform_guild_id(entry: AuditLogEntry, data: Optional[Snowflake]) -> Optional[Guild]:
|
||||||
def _transform_inviter_id(entry: AuditLogEntry, data: Optional[Snowflake]) -> Union[Member, User, None]:
|
|
||||||
if data is None:
|
if data is None:
|
||||||
return None
|
return None
|
||||||
return entry._get_member(int(data))
|
return entry._state._get_guild(data)
|
||||||
|
|
||||||
|
|
||||||
def _transform_overwrites(
|
def _transform_overwrites(
|
||||||
@ -146,6 +146,11 @@ def _enum_transformer(enum: Type[T]) -> Callable[[AuditLogEntry, int], T]:
|
|||||||
|
|
||||||
return _transform
|
return _transform
|
||||||
|
|
||||||
|
def _transform_type(entry: AuditLogEntry, data: Union[int]) -> Union[enums.ChannelType, enums.StickerType]:
|
||||||
|
if entry.action.name.startswith('sticker_'):
|
||||||
|
return enums.try_enum(enums.StickerType, data)
|
||||||
|
else:
|
||||||
|
return enums.try_enum(enums.ChannelType, data)
|
||||||
|
|
||||||
class AuditLogDiff:
|
class AuditLogDiff:
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
@ -180,8 +185,8 @@ class AuditLogChanges:
|
|||||||
'permissions': (None, _transform_permissions),
|
'permissions': (None, _transform_permissions),
|
||||||
'id': (None, _transform_snowflake),
|
'id': (None, _transform_snowflake),
|
||||||
'color': ('colour', _transform_color),
|
'color': ('colour', _transform_color),
|
||||||
'owner_id': ('owner', _transform_owner_id),
|
'owner_id': ('owner', _transform_member_id),
|
||||||
'inviter_id': ('inviter', _transform_inviter_id),
|
'inviter_id': ('inviter', _transform_member_id),
|
||||||
'channel_id': ('channel', _transform_channel),
|
'channel_id': ('channel', _transform_channel),
|
||||||
'afk_channel_id': ('afk_channel', _transform_channel),
|
'afk_channel_id': ('afk_channel', _transform_channel),
|
||||||
'system_channel_id': ('system_channel', _transform_channel),
|
'system_channel_id': ('system_channel', _transform_channel),
|
||||||
@ -195,12 +200,15 @@ class AuditLogChanges:
|
|||||||
'icon_hash': ('icon', _transform_icon),
|
'icon_hash': ('icon', _transform_icon),
|
||||||
'avatar_hash': ('avatar', _transform_avatar),
|
'avatar_hash': ('avatar', _transform_avatar),
|
||||||
'rate_limit_per_user': ('slowmode_delay', None),
|
'rate_limit_per_user': ('slowmode_delay', None),
|
||||||
|
'guild_id': ('guild', _transform_guild_id),
|
||||||
|
'tags': ('emoji', None),
|
||||||
'default_message_notifications': ('default_notifications', _enum_transformer(enums.NotificationLevel)),
|
'default_message_notifications': ('default_notifications', _enum_transformer(enums.NotificationLevel)),
|
||||||
'region': (None, _enum_transformer(enums.VoiceRegion)),
|
'region': (None, _enum_transformer(enums.VoiceRegion)),
|
||||||
'rtc_region': (None, _enum_transformer(enums.VoiceRegion)),
|
'rtc_region': (None, _enum_transformer(enums.VoiceRegion)),
|
||||||
'video_quality_mode': (None, _enum_transformer(enums.VideoQualityMode)),
|
'video_quality_mode': (None, _enum_transformer(enums.VideoQualityMode)),
|
||||||
'privacy_level': (None, _enum_transformer(enums.StagePrivacyLevel)),
|
'privacy_level': (None, _enum_transformer(enums.StagePrivacyLevel)),
|
||||||
'type': (None, _enum_transformer(enums.ChannelType)),
|
'format_type': (None, _enum_transformer(enums.StickerFormatType)),
|
||||||
|
'type': (None, _transform_type),
|
||||||
}
|
}
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
@ -438,7 +446,7 @@ class AuditLogEntry(Hashable):
|
|||||||
return utils.snowflake_time(self.id)
|
return utils.snowflake_time(self.id)
|
||||||
|
|
||||||
@utils.cached_property
|
@utils.cached_property
|
||||||
def target(self) -> Union[Guild, abc.GuildChannel, Member, User, Role, Invite, Emoji, Object, Thread, None]:
|
def target(self) -> Union[Guild, abc.GuildChannel, Member, User, Role, Invite, Emoji, StageInstance, GuildSticker, Thread, Object, None]:
|
||||||
try:
|
try:
|
||||||
converter = getattr(self, '_convert_target_' + self.action.target_type)
|
converter = getattr(self, '_convert_target_' + self.action.target_type)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -509,5 +517,8 @@ class AuditLogEntry(Hashable):
|
|||||||
def _convert_target_stage_instance(self, target_id: int) -> Union[StageInstance, Object]:
|
def _convert_target_stage_instance(self, target_id: int) -> Union[StageInstance, Object]:
|
||||||
return self.guild.get_stage_instance(target_id) or Object(id=target_id)
|
return self.guild.get_stage_instance(target_id) or Object(id=target_id)
|
||||||
|
|
||||||
|
def _convert_target_sticker(self, target_id: int) -> Union[GuildSticker, Object]:
|
||||||
|
return self._state.get_sticker(target_id) or Object(id=target_id)
|
||||||
|
|
||||||
def _convert_target_thread(self, target_id: int) -> Union[Thread, Object]:
|
def _convert_target_thread(self, target_id: int) -> Union[Thread, Object]:
|
||||||
return self.guild.get_thread(target_id) or Object(id=target_id)
|
return self.guild.get_thread(target_id) or Object(id=target_id)
|
||||||
|
@ -60,6 +60,7 @@ from .appinfo import AppInfo
|
|||||||
from .ui.view import View
|
from .ui.view import View
|
||||||
from .stage_instance import StageInstance
|
from .stage_instance import StageInstance
|
||||||
from .threads import Thread
|
from .threads import Thread
|
||||||
|
from .sticker import GuildSticker, StandardSticker, StickerPack, _sticker_factory
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .abc import SnowflakeTime, PrivateChannel, GuildChannel, Snowflake
|
from .abc import SnowflakeTime, PrivateChannel, GuildChannel, Snowflake
|
||||||
@ -277,6 +278,14 @@ class Client:
|
|||||||
"""List[:class:`.Emoji`]: The emojis that the connected client has."""
|
"""List[:class:`.Emoji`]: The emojis that the connected client has."""
|
||||||
return self._connection.emojis
|
return self._connection.emojis
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stickers(self) -> List[GuildSticker]:
|
||||||
|
"""List[:class:`GuildSticker`]: The stickers that the connected client has.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return self._connection.stickers
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cached_messages(self) -> Sequence[Message]:
|
def cached_messages(self) -> Sequence[Message]:
|
||||||
"""Sequence[:class:`.Message`]: Read-only list of messages the connected client has cached.
|
"""Sequence[:class:`.Message`]: Read-only list of messages the connected client has cached.
|
||||||
@ -777,6 +786,23 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
return self._connection.get_emoji(id)
|
return self._connection.get_emoji(id)
|
||||||
|
|
||||||
|
def get_sticker(self, id: int) -> Optional[GuildSticker]:
|
||||||
|
"""Returns a guild sticker with the given ID.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
To retrieve standard stickers, use :meth:`.fetch_sticker`.
|
||||||
|
or :meth:`.fetch_nitro_sticker_packs`.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
Optional[:class:`.GuildSticker`]
|
||||||
|
The sticker or ``None`` if not found.
|
||||||
|
"""
|
||||||
|
return self._connection.get_sticker(id)
|
||||||
|
|
||||||
def get_all_channels(self) -> Generator[GuildChannel, None, None]:
|
def get_all_channels(self) -> Generator[GuildChannel, None, None]:
|
||||||
"""A generator that retrieves every :class:`.abc.GuildChannel` the client can 'access'.
|
"""A generator that retrieves every :class:`.abc.GuildChannel` the client can 'access'.
|
||||||
|
|
||||||
@ -1443,6 +1469,49 @@ class Client:
|
|||||||
data = await self.http.get_webhook(webhook_id)
|
data = await self.http.get_webhook(webhook_id)
|
||||||
return Webhook.from_state(data, state=self._connection)
|
return Webhook.from_state(data, state=self._connection)
|
||||||
|
|
||||||
|
async def fetch_sticker(self, sticker_id: int) -> Union[StandardSticker, GuildSticker]:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Retrieves a :class:`.Sticker` with the specified ID.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Raises
|
||||||
|
--------
|
||||||
|
:exc:`.HTTPException`
|
||||||
|
Retrieving the sticker failed.
|
||||||
|
:exc:`.NotFound`
|
||||||
|
Invalid sticker ID.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
Union[:class:`.StandardSticker`, :class:`.GuildSticker`]
|
||||||
|
The sticker you requested.
|
||||||
|
"""
|
||||||
|
data = await self.http.get_sticker(sticker_id)
|
||||||
|
cls, _ = _sticker_factory(data['type']) # type: ignore
|
||||||
|
return cls(state=self._connection, data=data) # type: ignore
|
||||||
|
|
||||||
|
async def fetch_nitro_sticker_packs(self) -> List[StickerPack]:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Retrieves all available nitro sticker packs.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
:exc:`.HTTPException`
|
||||||
|
Retrieving the sticker packs failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
List[:class:`.StickerPack`]
|
||||||
|
All available nitro sticker packs.
|
||||||
|
"""
|
||||||
|
data = await self.http.list_nitro_sticker_packs()
|
||||||
|
return [StickerPack(state=self._connection, data=pack) for pack in data['sticker_packs']]
|
||||||
|
|
||||||
async def create_dm(self, user: Snowflake) -> DMChannel:
|
async def create_dm(self, user: Snowflake) -> DMChannel:
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ __all__ = (
|
|||||||
'ExpireBehaviour',
|
'ExpireBehaviour',
|
||||||
'ExpireBehavior',
|
'ExpireBehavior',
|
||||||
'StickerType',
|
'StickerType',
|
||||||
|
'StickerFormatType',
|
||||||
'InviteTarget',
|
'InviteTarget',
|
||||||
'VideoQualityMode',
|
'VideoQualityMode',
|
||||||
'ComponentType',
|
'ComponentType',
|
||||||
@ -346,6 +347,9 @@ class AuditLogAction(Enum):
|
|||||||
stage_instance_create = 83
|
stage_instance_create = 83
|
||||||
stage_instance_update = 84
|
stage_instance_update = 84
|
||||||
stage_instance_delete = 85
|
stage_instance_delete = 85
|
||||||
|
sticker_create = 90
|
||||||
|
sticker_update = 91
|
||||||
|
sticker_delete = 92
|
||||||
thread_create = 110
|
thread_create = 110
|
||||||
thread_update = 111
|
thread_update = 111
|
||||||
thread_delete = 112
|
thread_delete = 112
|
||||||
@ -393,6 +397,9 @@ class AuditLogAction(Enum):
|
|||||||
AuditLogAction.stage_instance_create: AuditLogActionCategory.create,
|
AuditLogAction.stage_instance_create: AuditLogActionCategory.create,
|
||||||
AuditLogAction.stage_instance_update: AuditLogActionCategory.update,
|
AuditLogAction.stage_instance_update: AuditLogActionCategory.update,
|
||||||
AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete,
|
AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete,
|
||||||
|
AuditLogAction.sticker_create: AuditLogActionCategory.create,
|
||||||
|
AuditLogAction.sticker_update: AuditLogActionCategory.update,
|
||||||
|
AuditLogAction.sticker_delete: AuditLogActionCategory.delete,
|
||||||
AuditLogAction.thread_create: AuditLogActionCategory.create,
|
AuditLogAction.thread_create: AuditLogActionCategory.create,
|
||||||
AuditLogAction.thread_update: AuditLogActionCategory.update,
|
AuditLogAction.thread_update: AuditLogActionCategory.update,
|
||||||
AuditLogAction.thread_delete: AuditLogActionCategory.delete,
|
AuditLogAction.thread_delete: AuditLogActionCategory.delete,
|
||||||
@ -427,6 +434,8 @@ class AuditLogAction(Enum):
|
|||||||
return 'integration'
|
return 'integration'
|
||||||
elif v < 90:
|
elif v < 90:
|
||||||
return 'stage_instance'
|
return 'stage_instance'
|
||||||
|
elif v < 93:
|
||||||
|
return 'sticker'
|
||||||
elif v < 113:
|
elif v < 113:
|
||||||
return 'thread'
|
return 'thread'
|
||||||
|
|
||||||
@ -484,10 +493,26 @@ ExpireBehavior = ExpireBehaviour
|
|||||||
|
|
||||||
|
|
||||||
class StickerType(Enum):
|
class StickerType(Enum):
|
||||||
|
standard = 1
|
||||||
|
guild = 2
|
||||||
|
|
||||||
|
|
||||||
|
class StickerFormatType(Enum):
|
||||||
png = 1
|
png = 1
|
||||||
apng = 2
|
apng = 2
|
||||||
lottie = 3
|
lottie = 3
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_extension(self) -> str:
|
||||||
|
# fmt: off
|
||||||
|
lookup: Dict[StickerFormatType, str] = {
|
||||||
|
StickerFormatType.png: 'png',
|
||||||
|
StickerFormatType.apng: 'png',
|
||||||
|
StickerFormatType.lottie: 'json',
|
||||||
|
}
|
||||||
|
# fmt: on
|
||||||
|
return lookup[self]
|
||||||
|
|
||||||
|
|
||||||
class InviteTarget(Enum):
|
class InviteTarget(Enum):
|
||||||
unknown = 0
|
unknown = 0
|
||||||
|
@ -566,18 +566,34 @@ class Intents(BaseFlags):
|
|||||||
|
|
||||||
@flag_value
|
@flag_value
|
||||||
def emojis(self):
|
def emojis(self):
|
||||||
""":class:`bool`: Whether guild emoji related events are enabled.
|
""":class:`bool`: Alias of :attr:`.emojis_and_stickers`.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.0
|
||||||
|
Changed to an alias.
|
||||||
|
"""
|
||||||
|
return 1 << 3
|
||||||
|
|
||||||
|
@alias_flag_value
|
||||||
|
def emojis_and_stickers(self):
|
||||||
|
""":class:`bool`: Whether guild emoji and sticker related events are enabled.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
This corresponds to the following events:
|
This corresponds to the following events:
|
||||||
|
|
||||||
- :func:`on_guild_emojis_update`
|
- :func:`on_guild_emojis_update`
|
||||||
|
- :func:`on_guild_stickers_update`
|
||||||
|
|
||||||
This also corresponds to the following attributes and classes in terms of cache:
|
This also corresponds to the following attributes and classes in terms of cache:
|
||||||
|
|
||||||
- :class:`Emoji`
|
- :class:`Emoji`
|
||||||
|
- :class:`GuildSticker`
|
||||||
- :meth:`Client.get_emoji`
|
- :meth:`Client.get_emoji`
|
||||||
|
- :meth:`Client.get_sticker`
|
||||||
- :meth:`Client.emojis`
|
- :meth:`Client.emojis`
|
||||||
|
- :meth:`Client.stickers`
|
||||||
- :attr:`Guild.emojis`
|
- :attr:`Guild.emojis`
|
||||||
|
- :attr:`Guild.stickers`
|
||||||
"""
|
"""
|
||||||
return 1 << 3
|
return 1 << 3
|
||||||
|
|
||||||
|
174
discord/guild.py
174
discord/guild.py
@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import unicodedata
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
ClassVar,
|
ClassVar,
|
||||||
@ -72,6 +73,9 @@ from .flags import SystemChannelFlags
|
|||||||
from .integrations import Integration, _integration_factory
|
from .integrations import Integration, _integration_factory
|
||||||
from .stage_instance import StageInstance
|
from .stage_instance import StageInstance
|
||||||
from .threads import Thread
|
from .threads import Thread
|
||||||
|
from .sticker import GuildSticker
|
||||||
|
from .file import File
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Guild',
|
'Guild',
|
||||||
@ -107,6 +111,7 @@ class BanEntry(NamedTuple):
|
|||||||
|
|
||||||
class _GuildLimit(NamedTuple):
|
class _GuildLimit(NamedTuple):
|
||||||
emoji: int
|
emoji: int
|
||||||
|
stickers: int
|
||||||
bitrate: float
|
bitrate: float
|
||||||
filesize: int
|
filesize: int
|
||||||
|
|
||||||
@ -140,6 +145,10 @@ class Guild(Hashable):
|
|||||||
The guild name.
|
The guild name.
|
||||||
emojis: Tuple[:class:`Emoji`, ...]
|
emojis: Tuple[:class:`Emoji`, ...]
|
||||||
All emojis that the guild owns.
|
All emojis that the guild owns.
|
||||||
|
stickers: Tuple[:class:`GuildSticker`, ...]
|
||||||
|
All stickers that the guild owns.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
region: :class:`VoiceRegion`
|
region: :class:`VoiceRegion`
|
||||||
The region the guild belongs on. There is a chance that the region
|
The region the guild belongs on. There is a chance that the region
|
||||||
will be a :class:`str` if the value is not recognised by the enumerator.
|
will be a :class:`str` if the value is not recognised by the enumerator.
|
||||||
@ -234,6 +243,7 @@ class Guild(Hashable):
|
|||||||
'owner_id',
|
'owner_id',
|
||||||
'mfa_level',
|
'mfa_level',
|
||||||
'emojis',
|
'emojis',
|
||||||
|
'stickers',
|
||||||
'features',
|
'features',
|
||||||
'verification_level',
|
'verification_level',
|
||||||
'explicit_content_filter',
|
'explicit_content_filter',
|
||||||
@ -266,11 +276,11 @@ class Guild(Hashable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
_PREMIUM_GUILD_LIMITS: ClassVar[Dict[Optional[int], _GuildLimit]] = {
|
_PREMIUM_GUILD_LIMITS: ClassVar[Dict[Optional[int], _GuildLimit]] = {
|
||||||
None: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
|
None: _GuildLimit(emoji=50, stickers=0, bitrate=96e3, filesize=8388608),
|
||||||
0: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
|
0: _GuildLimit(emoji=50, stickers=0, bitrate=96e3, filesize=8388608),
|
||||||
1: _GuildLimit(emoji=100, bitrate=128e3, filesize=8388608),
|
1: _GuildLimit(emoji=100, stickers=15, bitrate=128e3, filesize=8388608),
|
||||||
2: _GuildLimit(emoji=150, bitrate=256e3, filesize=52428800),
|
2: _GuildLimit(emoji=150, stickers=30, bitrate=256e3, filesize=52428800),
|
||||||
3: _GuildLimit(emoji=250, bitrate=384e3, filesize=104857600),
|
3: _GuildLimit(emoji=250, stickers=60, bitrate=384e3, filesize=104857600),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *, data: GuildPayload, state: ConnectionState):
|
def __init__(self, *, data: GuildPayload, state: ConnectionState):
|
||||||
@ -412,6 +422,7 @@ class Guild(Hashable):
|
|||||||
|
|
||||||
self.mfa_level: MFALevel = guild.get('mfa_level')
|
self.mfa_level: MFALevel = guild.get('mfa_level')
|
||||||
self.emojis: Tuple[Emoji, ...] = tuple(map(lambda d: state.store_emoji(self, d), guild.get('emojis', [])))
|
self.emojis: Tuple[Emoji, ...] = tuple(map(lambda d: state.store_emoji(self, d), guild.get('emojis', [])))
|
||||||
|
self.stickers: Tuple[GuildSticker, ...] = tuple(map(lambda d: state.store_sticker(self, d), guild.get('stickers', [])))
|
||||||
self.features: List[GuildFeature] = guild.get('features', [])
|
self.features: List[GuildFeature] = guild.get('features', [])
|
||||||
self._splash: Optional[str] = guild.get('splash')
|
self._splash: Optional[str] = guild.get('splash')
|
||||||
self._system_channel_id: Optional[int] = utils._get_as_snowflake(guild, 'system_channel_id')
|
self._system_channel_id: Optional[int] = utils._get_as_snowflake(guild, 'system_channel_id')
|
||||||
@ -698,6 +709,15 @@ class Guild(Hashable):
|
|||||||
more_emoji = 200 if 'MORE_EMOJI' in self.features else 50
|
more_emoji = 200 if 'MORE_EMOJI' in self.features else 50
|
||||||
return max(more_emoji, self._PREMIUM_GUILD_LIMITS[self.premium_tier].emoji)
|
return max(more_emoji, self._PREMIUM_GUILD_LIMITS[self.premium_tier].emoji)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sticker_limit(self) -> int:
|
||||||
|
""":class:`int`: The maximum number of sticker slots this guild has.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
more_stickers = 60 if 'MORE_STICKERS' in self.features else 15
|
||||||
|
return max(more_stickers, self._PREMIUM_GUILD_LIMITS[self.premium_tier].stickers)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bitrate_limit(self) -> float:
|
def bitrate_limit(self) -> float:
|
||||||
""":class:`float`: The maximum bitrate for voice channels this guild can have."""
|
""":class:`float`: The maximum bitrate for voice channels this guild can have."""
|
||||||
@ -2027,6 +2047,150 @@ class Guild(Hashable):
|
|||||||
|
|
||||||
return [convert(d) for d in data]
|
return [convert(d) for d in data]
|
||||||
|
|
||||||
|
async def fetch_stickers(self) -> List[GuildSticker]:
|
||||||
|
r"""|coro|
|
||||||
|
|
||||||
|
Retrieves a list of all :class:`Sticker`\s for the guild.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This method is an API call. For general usage, consider :attr:`stickers` instead.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
---------
|
||||||
|
HTTPException
|
||||||
|
An error occurred fetching the stickers.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
List[:class:`GuildSticker`]
|
||||||
|
The retrieved stickers.
|
||||||
|
"""
|
||||||
|
data = await self._state.http.get_all_guild_stickers(self.id)
|
||||||
|
return [GuildSticker(state=self._state, data=d) for d in data]
|
||||||
|
|
||||||
|
async def fetch_sticker(self, sticker_id: int, /) -> GuildSticker:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Retrieves a custom :class:`Sticker` from the guild.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This method is an API call.
|
||||||
|
For general usage, consider iterating over :attr:`stickers` instead.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-------------
|
||||||
|
sticker_id: :class:`int`
|
||||||
|
The sticker's ID.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
---------
|
||||||
|
NotFound
|
||||||
|
The sticker requested could not be found.
|
||||||
|
HTTPException
|
||||||
|
An error occurred fetching the sticker.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`GuildSticker`
|
||||||
|
The retrieved sticker.
|
||||||
|
"""
|
||||||
|
data = await self._state.http.get_guild_sticker(self.id, sticker_id)
|
||||||
|
return GuildSticker(state=self._state, data=data)
|
||||||
|
|
||||||
|
async def create_sticker(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
name: str,
|
||||||
|
description: Optional[str] = None,
|
||||||
|
emoji: str,
|
||||||
|
file: File,
|
||||||
|
reason: Optional[str] = None,
|
||||||
|
) -> GuildSticker:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Creates a :class:`Sticker` for the guild.
|
||||||
|
|
||||||
|
You must have :attr:`~Permissions.manage_emojis_and_stickers` permission to
|
||||||
|
do this.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
name: :class:`str`
|
||||||
|
The sticker name. Must be at least 2 characters.
|
||||||
|
description: Optional[:class:`str`]
|
||||||
|
The sticker's description. Can be ``None``.
|
||||||
|
emoji: :class:`str`
|
||||||
|
The name of a unicode emoji that represents the sticker's expression.
|
||||||
|
file: :class:`File`
|
||||||
|
The file of the sticker to upload.
|
||||||
|
reason: :class:`str`
|
||||||
|
The reason for creating this sticker. Shows up on the audit log.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
Forbidden
|
||||||
|
You are not allowed to create stickers.
|
||||||
|
HTTPException
|
||||||
|
An error occurred creating a sticker.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`GuildSticker`
|
||||||
|
The created sticker.
|
||||||
|
"""
|
||||||
|
payload = {
|
||||||
|
'name': name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if description:
|
||||||
|
payload['description'] = description
|
||||||
|
|
||||||
|
try:
|
||||||
|
emoji = unicodedata.name(emoji)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
emoji = emoji.replace(' ', '_')
|
||||||
|
|
||||||
|
payload['tags'] = emoji
|
||||||
|
|
||||||
|
data = await self._state.http.create_guild_sticker(self.id, payload, file, reason)
|
||||||
|
return self._state.store_sticker(self, data)
|
||||||
|
|
||||||
|
async def delete_sticker(self, sticker: Snowflake, *, reason: Optional[str] = None) -> None:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Deletes the custom :class:`Sticker` from the guild.
|
||||||
|
|
||||||
|
You must have :attr:`~Permissions.manage_emojis_and_stickers` permission to
|
||||||
|
do this.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
sticker: :class:`abc.Snowflake`
|
||||||
|
The sticker you are deleting.
|
||||||
|
reason: Optional[:class:`str`]
|
||||||
|
The reason for deleting this sticker. Shows up on the audit log.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
Forbidden
|
||||||
|
You are not allowed to delete stickers.
|
||||||
|
HTTPException
|
||||||
|
An error occurred deleting the sticker.
|
||||||
|
"""
|
||||||
|
await self._state.http.delete_guild_sticker(self.id, sticker.id, reason)
|
||||||
|
|
||||||
async def fetch_emojis(self) -> List[Emoji]:
|
async def fetch_emojis(self) -> List[Emoji]:
|
||||||
r"""|coro|
|
r"""|coro|
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ import weakref
|
|||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from .errors import HTTPException, Forbidden, NotFound, LoginFailure, DiscordServerError, GatewayNotFound
|
from .errors import HTTPException, Forbidden, NotFound, LoginFailure, DiscordServerError, GatewayNotFound, InvalidArgument
|
||||||
from .gateway import DiscordClientWebSocketResponse
|
from .gateway import DiscordClientWebSocketResponse
|
||||||
from . import __version__, utils
|
from . import __version__, utils
|
||||||
from .utils import MISSING
|
from .utils import MISSING
|
||||||
@ -84,6 +84,7 @@ if TYPE_CHECKING:
|
|||||||
widget,
|
widget,
|
||||||
threads,
|
threads,
|
||||||
voice,
|
voice,
|
||||||
|
sticker,
|
||||||
)
|
)
|
||||||
from .types.snowflake import Snowflake, SnowflakeList
|
from .types.snowflake import Snowflake, SnowflakeList
|
||||||
|
|
||||||
@ -423,6 +424,7 @@ class HTTPClient:
|
|||||||
nonce: Optional[str] = None,
|
nonce: Optional[str] = None,
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
allowed_mentions: Optional[message.AllowedMentions] = None,
|
||||||
message_reference: Optional[message.MessageReference] = None,
|
message_reference: Optional[message.MessageReference] = None,
|
||||||
|
stickers: Optional[List[sticker.StickerItem]] = None,
|
||||||
components: Optional[List[components.Component]] = None,
|
components: Optional[List[components.Component]] = None,
|
||||||
) -> Response[message.Message]:
|
) -> Response[message.Message]:
|
||||||
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
||||||
@ -452,6 +454,9 @@ class HTTPClient:
|
|||||||
if components:
|
if components:
|
||||||
payload['components'] = components
|
payload['components'] = components
|
||||||
|
|
||||||
|
if stickers:
|
||||||
|
payload['sticker_items'] = stickers
|
||||||
|
|
||||||
return self.request(r, json=payload)
|
return self.request(r, json=payload)
|
||||||
|
|
||||||
def send_typing(self, channel_id: Snowflake) -> Response[None]:
|
def send_typing(self, channel_id: Snowflake) -> Response[None]:
|
||||||
@ -465,10 +470,11 @@ class HTTPClient:
|
|||||||
content: Optional[str] = None,
|
content: Optional[str] = None,
|
||||||
tts: bool = False,
|
tts: bool = False,
|
||||||
embed: Optional[embed.Embed] = None,
|
embed: Optional[embed.Embed] = None,
|
||||||
embeds: Iterable[Optional[embed.Embed]] = None,
|
embeds: Optional[Iterable[Optional[embed.Embed]]] = None,
|
||||||
nonce: Optional[str] = None,
|
nonce: Optional[str] = None,
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
allowed_mentions: Optional[message.AllowedMentions] = None,
|
||||||
message_reference: Optional[message.MessageReference] = None,
|
message_reference: Optional[message.MessageReference] = None,
|
||||||
|
stickers: Optional[List[sticker.StickerItem]] = None,
|
||||||
components: Optional[List[components.Component]] = None,
|
components: Optional[List[components.Component]] = None,
|
||||||
) -> Response[message.Message]:
|
) -> Response[message.Message]:
|
||||||
form = []
|
form = []
|
||||||
@ -488,6 +494,8 @@ class HTTPClient:
|
|||||||
payload['message_reference'] = message_reference
|
payload['message_reference'] = message_reference
|
||||||
if components:
|
if components:
|
||||||
payload['components'] = components
|
payload['components'] = components
|
||||||
|
if stickers:
|
||||||
|
payload['sticker_items'] = stickers
|
||||||
|
|
||||||
form.append({'name': 'payload_json', 'value': utils.to_json(payload)})
|
form.append({'name': 'payload_json', 'value': utils.to_json(payload)})
|
||||||
if len(files) == 1:
|
if len(files) == 1:
|
||||||
@ -525,6 +533,7 @@ class HTTPClient:
|
|||||||
nonce: Optional[str] = None,
|
nonce: Optional[str] = None,
|
||||||
allowed_mentions: Optional[message.AllowedMentions] = None,
|
allowed_mentions: Optional[message.AllowedMentions] = None,
|
||||||
message_reference: Optional[message.MessageReference] = None,
|
message_reference: Optional[message.MessageReference] = None,
|
||||||
|
stickers: Optional[List[sticker.StickerItem]] = None,
|
||||||
components: Optional[List[components.Component]] = None,
|
components: Optional[List[components.Component]] = None,
|
||||||
) -> Response[message.Message]:
|
) -> Response[message.Message]:
|
||||||
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
|
||||||
@ -538,6 +547,7 @@ class HTTPClient:
|
|||||||
nonce=nonce,
|
nonce=nonce,
|
||||||
allowed_mentions=allowed_mentions,
|
allowed_mentions=allowed_mentions,
|
||||||
message_reference=message_reference,
|
message_reference=message_reference,
|
||||||
|
stickers=stickers,
|
||||||
components=components,
|
components=components,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1160,6 +1170,54 @@ class HTTPClient:
|
|||||||
|
|
||||||
return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params)
|
return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params)
|
||||||
|
|
||||||
|
def get_sticker(self, sticker_id: Snowflake) -> Response[sticker.Sticker]:
|
||||||
|
return self.request(Route('GET', '/stickers/{sticker_id}', sticker_id=sticker_id))
|
||||||
|
|
||||||
|
def list_nitro_sticker_packs(self) -> Response[sticker.ListNitroStickerPacks]:
|
||||||
|
return self.request(Route('GET', '/sticker-packs'))
|
||||||
|
|
||||||
|
def get_all_guild_stickers(self, guild_id: Snowflake) -> Response[List[sticker.GuildSticker]]:
|
||||||
|
return self.request(Route('GET', '/guilds/{guild_id}/stickers', guild_id=guild_id))
|
||||||
|
|
||||||
|
def get_guild_sticker(self, guild_id: Snowflake, sticker_id: Snowflake) -> Response[sticker.GuildSticker]:
|
||||||
|
return self.request(Route('GET', '/guilds/{guild_id}/stickers/{sticker_id}', guild_id=guild_id, sticker_id=sticker_id))
|
||||||
|
|
||||||
|
def create_guild_sticker(self, guild_id: Snowflake, payload: sticker.CreateGuildSticker, file: File, reason: str) -> Response[sticker.GuildSticker]:
|
||||||
|
initial_bytes = file.fp.read(16)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mime_type = utils._get_mime_type_for_image(initial_bytes)
|
||||||
|
except InvalidArgument:
|
||||||
|
if initial_bytes.startswith(b'{'):
|
||||||
|
mime_type = 'application/json'
|
||||||
|
else:
|
||||||
|
mime_type = 'application/octet-stream'
|
||||||
|
finally:
|
||||||
|
file.reset()
|
||||||
|
|
||||||
|
form: List[Dict[str, Any]] = [
|
||||||
|
{
|
||||||
|
'name': 'file',
|
||||||
|
'value': file.fp,
|
||||||
|
'filename': file.filename,
|
||||||
|
'content_type': mime_type,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
for k, v in payload.items():
|
||||||
|
form.append({
|
||||||
|
'name': k,
|
||||||
|
'value': v,
|
||||||
|
})
|
||||||
|
|
||||||
|
return self.request(Route('POST', '/guilds/{guild_id}/stickers', guild_id=guild_id), form=form, files=[file], reason=reason)
|
||||||
|
|
||||||
|
def modify_guild_sticker(self, guild_id: Snowflake, sticker_id: Snowflake, payload: sticker.EditGuildSticker, reason: str) -> Response[sticker.GuildSticker]:
|
||||||
|
return self.request(Route('PATCH', '/guilds/{guild_id}/stickers/{sticker_id}', guild_id=guild_id, sticker_id=sticker_id), json=payload, reason=reason)
|
||||||
|
|
||||||
|
def delete_guild_sticker(self, guild_id: Snowflake, sticker_id: Snowflake, reason: str) -> Response[None]:
|
||||||
|
return self.request(Route('DELETE', '/guilds/{guild_id}/stickers/{sticker_id}', guild_id=guild_id, sticker_id=sticker_id), reason=reason)
|
||||||
|
|
||||||
def get_all_custom_emojis(self, guild_id: Snowflake) -> Response[List[emoji.Emoji]]:
|
def get_all_custom_emojis(self, guild_id: Snowflake) -> Response[List[emoji.Emoji]]:
|
||||||
return self.request(Route('GET', '/guilds/{guild_id}/emojis', guild_id=guild_id))
|
return self.request(Route('GET', '/guilds/{guild_id}/emojis', guild_id=guild_id))
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ from .file import File
|
|||||||
from .utils import escape_mentions, MISSING
|
from .utils import escape_mentions, MISSING
|
||||||
from .guild import Guild
|
from .guild import Guild
|
||||||
from .mixins import Hashable
|
from .mixins import Hashable
|
||||||
from .sticker import Sticker
|
from .sticker import StickerItem
|
||||||
from .threads import Thread
|
from .threads import Thread
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -588,8 +588,8 @@ class Message(Hashable):
|
|||||||
- ``description``: A string representing the application's description.
|
- ``description``: A string representing the application's description.
|
||||||
- ``icon``: A string representing the icon ID of the application.
|
- ``icon``: A string representing the icon ID of the application.
|
||||||
- ``cover_image``: A string representing the embed's image asset ID.
|
- ``cover_image``: A string representing the embed's image asset ID.
|
||||||
stickers: List[:class:`Sticker`]
|
stickers: List[:class:`StickerItem`]
|
||||||
A list of stickers given to the message.
|
A list of sticker items given to the message.
|
||||||
|
|
||||||
.. versionadded:: 1.6
|
.. versionadded:: 1.6
|
||||||
components: List[:class:`Component`]
|
components: List[:class:`Component`]
|
||||||
@ -666,7 +666,7 @@ class Message(Hashable):
|
|||||||
self.tts: bool = data['tts']
|
self.tts: bool = data['tts']
|
||||||
self.content: str = data['content']
|
self.content: str = data['content']
|
||||||
self.nonce: Optional[Union[int, str]] = data.get('nonce')
|
self.nonce: Optional[Union[int, str]] = data.get('nonce')
|
||||||
self.stickers: List[Sticker] = [Sticker(data=d, state=state) for d in data.get('stickers', [])]
|
self.stickers: List[StickerItem] = [StickerItem(data=d, state=state) for d in data.get('sticker_items', [])]
|
||||||
self.components: List[Component] = [_component_factory(d) for d in data.get('components', [])]
|
self.components: List[Component] = [_component_factory(d) for d in data.get('components', [])]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -462,6 +462,14 @@ class Permissions(BaseFlags):
|
|||||||
""":class:`bool`: Returns ``True`` if a user can create, edit, or delete emojis."""
|
""":class:`bool`: Returns ``True`` if a user can create, edit, or delete emojis."""
|
||||||
return 1 << 30
|
return 1 << 30
|
||||||
|
|
||||||
|
@make_permission_alias('manage_emojis')
|
||||||
|
def manage_emojis_and_stickers(self):
|
||||||
|
""":class:`bool`: An alias for :attr:`manage_emojis`.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return 1 << 30
|
||||||
|
|
||||||
@flag_value
|
@flag_value
|
||||||
def use_slash_commands(self) -> int:
|
def use_slash_commands(self) -> int:
|
||||||
""":class:`bool`: Returns ``True`` if a user can use slash commands.
|
""":class:`bool`: Returns ``True`` if a user can use slash commands.
|
||||||
@ -510,6 +518,22 @@ class Permissions(BaseFlags):
|
|||||||
"""
|
"""
|
||||||
return 1 << 36
|
return 1 << 36
|
||||||
|
|
||||||
|
@flag_value
|
||||||
|
def external_stickers(self) -> int:
|
||||||
|
""":class:`bool`: Returns ``True`` if a user can use stickers from other guilds.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return 1 << 37
|
||||||
|
|
||||||
|
@make_permission_alias('external_stickers')
|
||||||
|
def use_external_stickers(self) -> int:
|
||||||
|
""":class:`bool`: An alias for :attr:`external_stickers`.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return 1 << 37
|
||||||
|
|
||||||
PO = TypeVar('PO', bound='PermissionOverwrite')
|
PO = TypeVar('PO', bound='PermissionOverwrite')
|
||||||
|
|
||||||
def _augment_from_permissions(cls):
|
def _augment_from_permissions(cls):
|
||||||
|
@ -57,6 +57,7 @@ from .interactions import Interaction
|
|||||||
from .ui.view import ViewStore
|
from .ui.view import ViewStore
|
||||||
from .stage_instance import StageInstance
|
from .stage_instance import StageInstance
|
||||||
from .threads import Thread, ThreadMember
|
from .threads import Thread, ThreadMember
|
||||||
|
from .sticker import GuildSticker
|
||||||
|
|
||||||
class ChunkRequest:
|
class ChunkRequest:
|
||||||
def __init__(self, guild_id, loop, resolver, *, cache=True):
|
def __init__(self, guild_id, loop, resolver, *, cache=True):
|
||||||
@ -204,6 +205,7 @@ class ConnectionState:
|
|||||||
# though more testing will have to be done.
|
# though more testing will have to be done.
|
||||||
self._users: Dict[int, User] = {}
|
self._users: Dict[int, User] = {}
|
||||||
self._emojis = {}
|
self._emojis = {}
|
||||||
|
self._stickers = {}
|
||||||
self._guilds = {}
|
self._guilds = {}
|
||||||
self._view_store = ViewStore(self)
|
self._view_store = ViewStore(self)
|
||||||
self._voice_clients = {}
|
self._voice_clients = {}
|
||||||
@ -298,6 +300,11 @@ class ConnectionState:
|
|||||||
self._emojis[emoji_id] = emoji = Emoji(guild=guild, state=self, data=data)
|
self._emojis[emoji_id] = emoji = Emoji(guild=guild, state=self, data=data)
|
||||||
return emoji
|
return emoji
|
||||||
|
|
||||||
|
def store_sticker(self, guild, data):
|
||||||
|
sticker_id = int(data['id'])
|
||||||
|
self._stickers[sticker_id] = sticker = GuildSticker(state=self, data=data)
|
||||||
|
return sticker
|
||||||
|
|
||||||
def store_view(self, view, message_id=None):
|
def store_view(self, view, message_id=None):
|
||||||
self._view_store.add_view(view, message_id)
|
self._view_store.add_view(view, message_id)
|
||||||
|
|
||||||
@ -324,15 +331,25 @@ class ConnectionState:
|
|||||||
for emoji in guild.emojis:
|
for emoji in guild.emojis:
|
||||||
self._emojis.pop(emoji.id, None)
|
self._emojis.pop(emoji.id, None)
|
||||||
|
|
||||||
|
for sticker in guild.stickers:
|
||||||
|
self._stickers.pop(sticker.id, None)
|
||||||
|
|
||||||
del guild
|
del guild
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def emojis(self):
|
def emojis(self):
|
||||||
return list(self._emojis.values())
|
return list(self._emojis.values())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stickers(self):
|
||||||
|
return list(self._stickers.values())
|
||||||
|
|
||||||
def get_emoji(self, emoji_id):
|
def get_emoji(self, emoji_id):
|
||||||
return self._emojis.get(emoji_id)
|
return self._emojis.get(emoji_id)
|
||||||
|
|
||||||
|
def get_sticker(self, sticker_id):
|
||||||
|
return self._stickers.get(sticker_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def private_channels(self):
|
def private_channels(self):
|
||||||
return list(self._private_channels.values())
|
return list(self._private_channels.values())
|
||||||
@ -925,6 +942,18 @@ class ConnectionState:
|
|||||||
guild.emojis = tuple(map(lambda d: self.store_emoji(guild, d), data['emojis']))
|
guild.emojis = tuple(map(lambda d: self.store_emoji(guild, d), data['emojis']))
|
||||||
self.dispatch('guild_emojis_update', guild, before_emojis, guild.emojis)
|
self.dispatch('guild_emojis_update', guild, before_emojis, guild.emojis)
|
||||||
|
|
||||||
|
def parse_guild_stickers_update(self, data):
|
||||||
|
guild = self._get_guild(int(data['guild_id']))
|
||||||
|
if guild is None:
|
||||||
|
log.debug('GUILD_STICKERS_UPDATE referencing an unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||||
|
return
|
||||||
|
|
||||||
|
before_stickers = guild.stickers
|
||||||
|
for emoji in before_stickers:
|
||||||
|
self._stickers.pop(emoji.id, None)
|
||||||
|
guild.stickers = tuple(map(lambda d: self.store_sticker(guild, d), data['stickers']))
|
||||||
|
self.dispatch('guild_stickers_update', guild, before_stickers, guild.stickers)
|
||||||
|
|
||||||
def _get_create_guild(self, data):
|
def _get_create_guild(self, data):
|
||||||
if data.get('unavailable') is False:
|
if data.get('unavailable') is False:
|
||||||
# GUILD_CREATE with unavailable in the response
|
# GUILD_CREATE with unavailable in the response
|
||||||
|
@ -23,24 +23,213 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING, List, Optional
|
from typing import Literal, TYPE_CHECKING, List, Optional, Tuple, Type, Union
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
from .mixins import Hashable
|
from .mixins import Hashable
|
||||||
from .asset import Asset
|
from .asset import Asset, AssetMixin
|
||||||
from .utils import snowflake_time
|
from .utils import cached_slot_property, find, snowflake_time, get, MISSING
|
||||||
from .enums import StickerType, try_enum
|
from .errors import InvalidData
|
||||||
|
from .enums import StickerType, StickerFormatType, try_enum
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
'StickerPack',
|
||||||
|
'StickerItem',
|
||||||
'Sticker',
|
'Sticker',
|
||||||
|
'StandardSticker',
|
||||||
|
'GuildSticker',
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import datetime
|
import datetime
|
||||||
from .state import ConnectionState
|
from .state import ConnectionState
|
||||||
from .types.message import Sticker as StickerPayload
|
from .user import User
|
||||||
|
from .guild import Guild
|
||||||
|
from .types.sticker import (
|
||||||
|
StickerPack as StickerPackPayload,
|
||||||
|
StickerItem as StickerItemPayload,
|
||||||
|
Sticker as StickerPayload,
|
||||||
|
StandardSticker as StandardStickerPayload,
|
||||||
|
GuildSticker as GuildStickerPayload,
|
||||||
|
ListNitroStickerPacks as ListNitroStickerPacksPayload
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Sticker(Hashable):
|
class StickerPack(Hashable):
|
||||||
|
"""Represents a sticker pack.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. container:: operations
|
||||||
|
|
||||||
|
.. describe:: str(x)
|
||||||
|
|
||||||
|
Returns the name of the sticker pack.
|
||||||
|
|
||||||
|
.. describe:: x == y
|
||||||
|
|
||||||
|
Checks if the sticker pack is equal to another sticker pack.
|
||||||
|
|
||||||
|
.. describe:: x != y
|
||||||
|
|
||||||
|
Checks if the sticker pack is not equal to another sticker pack.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
name: :class:`str`
|
||||||
|
The name of the sticker pack.
|
||||||
|
description: :class:`str`
|
||||||
|
The description of the sticker pack.
|
||||||
|
id: :class:`int`
|
||||||
|
The id of the sticker pack.
|
||||||
|
stickers: List[:class:`StandardSticker`]
|
||||||
|
The stickers of this sticker pack.
|
||||||
|
sku_id: :class:`int`
|
||||||
|
The SKU ID of the sticker pack.
|
||||||
|
cover_sticker_id: :class:`int`
|
||||||
|
The ID of the sticker used for the cover of the sticker pack.
|
||||||
|
cover_sticker: :class:`StandardSticker`
|
||||||
|
The sticker used for the cover of the sticker pack.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = (
|
||||||
|
'_state',
|
||||||
|
'id',
|
||||||
|
'stickers',
|
||||||
|
'name',
|
||||||
|
'sku_id',
|
||||||
|
'cover_sticker_id',
|
||||||
|
'cover_sticker',
|
||||||
|
'description',
|
||||||
|
'_banner',
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *, state: ConnectionState, data: StickerPackPayload) -> None:
|
||||||
|
self._state: ConnectionState = state
|
||||||
|
self._from_data(data)
|
||||||
|
|
||||||
|
def _from_data(self, data: StickerPackPayload) -> None:
|
||||||
|
self.id: int = int(data['id'])
|
||||||
|
stickers = data['stickers']
|
||||||
|
self.stickers: List[StandardSticker] = [StandardSticker(state=self._state, data=sticker) for sticker in stickers]
|
||||||
|
self.name: str = data['name']
|
||||||
|
self.sku_id: int = int(data['sku_id'])
|
||||||
|
self.cover_sticker_id: int = int(data['cover_sticker_id'])
|
||||||
|
self.cover_sticker: StandardSticker = get(self.stickers, id=self.cover_sticker_id) # type: ignore
|
||||||
|
self.description: str = data['description']
|
||||||
|
self._banner: int = int(data['banner_asset_id'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def banner(self) -> Asset:
|
||||||
|
""":class:`Asset`: The banner asset of the sticker pack."""
|
||||||
|
return Asset._from_sticker_banner(self._state, self._banner)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'<StickerPack id={self.id} name={self.name!r} description={self.description!r}>'
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class _StickerTag(Hashable, AssetMixin):
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
id: int
|
||||||
|
format: StickerFormatType
|
||||||
|
|
||||||
|
async def read(self) -> bytes:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Retrieves the content of this sticker as a :class:`bytes` object.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Stickers that use the :attr:`StickerFormatType.lottie` format cannot be read.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
HTTPException
|
||||||
|
Downloading the asset failed.
|
||||||
|
NotFound
|
||||||
|
The asset was deleted.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
:class:`bytes`
|
||||||
|
The content of the asset.
|
||||||
|
"""
|
||||||
|
if self.format is StickerFormatType.lottie:
|
||||||
|
raise TypeError('Cannot read stickers of format "lottie".')
|
||||||
|
return await super().read()
|
||||||
|
|
||||||
|
|
||||||
|
class StickerItem(_StickerTag):
|
||||||
|
"""Represents a sticker item.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. container:: operations
|
||||||
|
|
||||||
|
.. describe:: str(x)
|
||||||
|
|
||||||
|
Returns the name of the sticker item.
|
||||||
|
|
||||||
|
.. describe:: x == y
|
||||||
|
|
||||||
|
Checks if the sticker item is equal to another sticker item.
|
||||||
|
|
||||||
|
.. describe:: x != y
|
||||||
|
|
||||||
|
Checks if the sticker item is not equal to another sticker item.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
name: :class:`str`
|
||||||
|
The sticker's name.
|
||||||
|
id: :class:`int`
|
||||||
|
The id of the sticker.
|
||||||
|
format: :class:`StickerFormatType`
|
||||||
|
The format for the sticker's image.
|
||||||
|
url: :class:`str`
|
||||||
|
The URL for the sticker's image.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('_state', 'name', 'id', 'format', 'url')
|
||||||
|
|
||||||
|
def __init__(self, *, state: ConnectionState, data: StickerItemPayload):
|
||||||
|
self._state: ConnectionState = state
|
||||||
|
self.name: str = data['name']
|
||||||
|
self.id: int = int(data['id'])
|
||||||
|
self.format: StickerFormatType = try_enum(StickerFormatType, data['format_type'])
|
||||||
|
self.url: str = f'{Asset.BASE}/stickers/{self.id}.{self.format.file_extension}'
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'<StickerItem id={self.id} name={self.name!r} format={self.format}>'
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
async def fetch(self) -> Union[Sticker, StandardSticker, GuildSticker]:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Attempts to retrieve the full sticker data of the sticker item.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
--------
|
||||||
|
HTTPException
|
||||||
|
Retrieving the sticker failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
Union[:class:`StandardSticker`, :class:`GuildSticker`]
|
||||||
|
The retrieved sticker.
|
||||||
|
"""
|
||||||
|
data: StickerPayload = await self._state.http.get_sticker(self.id)
|
||||||
|
cls, _ = _sticker_factory(data['type']) # type: ignore
|
||||||
|
return cls(state=self._state, data=data)
|
||||||
|
|
||||||
|
|
||||||
|
class Sticker(_StickerTag):
|
||||||
"""Represents a sticker.
|
"""Represents a sticker.
|
||||||
|
|
||||||
.. versionadded:: 1.6
|
.. versionadded:: 1.6
|
||||||
@ -69,30 +258,27 @@ class Sticker(Hashable):
|
|||||||
The description of the sticker.
|
The description of the sticker.
|
||||||
pack_id: :class:`int`
|
pack_id: :class:`int`
|
||||||
The id of the sticker's pack.
|
The id of the sticker's pack.
|
||||||
format: :class:`StickerType`
|
format: :class:`StickerFormatType`
|
||||||
The format for the sticker's image.
|
The format for the sticker's image.
|
||||||
tags: List[:class:`str`]
|
url: :class:`str`
|
||||||
A list of tags for the sticker.
|
The URL for the sticker's image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ('_state', 'id', 'name', 'description', 'pack_id', 'format', '_image', 'tags')
|
__slots__ = ('_state', 'id', 'name', 'description', 'format', 'url')
|
||||||
|
|
||||||
def __init__(self, *, state: ConnectionState, data: StickerPayload):
|
def __init__(self, *, state: ConnectionState, data: StickerPayload) -> None:
|
||||||
self._state: ConnectionState = state
|
self._state: ConnectionState = state
|
||||||
|
self._from_data(data)
|
||||||
|
|
||||||
|
def _from_data(self, data: StickerPayload) -> None:
|
||||||
self.id: int = int(data['id'])
|
self.id: int = int(data['id'])
|
||||||
self.name: str = data['name']
|
self.name: str = data['name']
|
||||||
self.description: str = data['description']
|
self.description: str = data['description']
|
||||||
self.pack_id: int = int(data.get('pack_id', 0))
|
self.format: StickerFormatType = try_enum(StickerFormatType, data['format_type'])
|
||||||
self.format: StickerType = try_enum(StickerType, data['format_type'])
|
self.url: str = f'{Asset.BASE}/stickers/{self.id}.{self.format.file_extension}'
|
||||||
self._image: str = data['asset']
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.tags: List[str] = [tag.strip() for tag in data['tags'].split(',')]
|
|
||||||
except KeyError:
|
|
||||||
self.tags = []
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'<{self.__class__.__name__} id={self.id} name={self.name!r}>'
|
return f'<Sticker id={self.id} name={self.name!r}>'
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.name
|
return self.name
|
||||||
@ -102,19 +288,229 @@ class Sticker(Hashable):
|
|||||||
""":class:`datetime.datetime`: Returns the sticker's creation time in UTC."""
|
""":class:`datetime.datetime`: Returns the sticker's creation time in UTC."""
|
||||||
return snowflake_time(self.id)
|
return snowflake_time(self.id)
|
||||||
|
|
||||||
@property
|
|
||||||
def image(self) -> Optional[Asset]:
|
|
||||||
"""Returns an :class:`Asset` for the sticker's image.
|
|
||||||
|
|
||||||
.. note::
|
class StandardSticker(Sticker):
|
||||||
This will return ``None`` if the format is ``StickerType.lottie``.
|
"""Represents a sticker that is found in a standard sticker pack.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. container:: operations
|
||||||
|
|
||||||
|
.. describe:: str(x)
|
||||||
|
|
||||||
|
Returns the name of the sticker.
|
||||||
|
|
||||||
|
.. describe:: x == y
|
||||||
|
|
||||||
|
Checks if the sticker is equal to another sticker.
|
||||||
|
|
||||||
|
.. describe:: x != y
|
||||||
|
|
||||||
|
Checks if the sticker is not equal to another sticker.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
name: :class:`str`
|
||||||
|
The sticker's name.
|
||||||
|
id: :class:`int`
|
||||||
|
The id of the sticker.
|
||||||
|
description: :class:`str`
|
||||||
|
The description of the sticker.
|
||||||
|
pack_id: :class:`int`
|
||||||
|
The id of the sticker's pack.
|
||||||
|
format: :class:`StickerFormatType`
|
||||||
|
The format for the sticker's image.
|
||||||
|
tags: List[:class:`str`]
|
||||||
|
A list of tags for the sticker.
|
||||||
|
sort_value: :class:`int`
|
||||||
|
The sticker's sort order within its pack.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('sort_value', 'pack_id', 'type', 'tags')
|
||||||
|
|
||||||
|
def _from_data(self, data: StandardStickerPayload) -> None:
|
||||||
|
super()._from_data(data)
|
||||||
|
self.sort_value: int = data['sort_value']
|
||||||
|
self.pack_id: int = int(data['pack_id'])
|
||||||
|
self.type: StickerType = StickerType.standard
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.tags: List[str] = [tag.strip() for tag in data['tags'].split(',')]
|
||||||
|
except KeyError:
|
||||||
|
self.tags = []
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'<StandardSticker id={self.id} name={self.name!r} pack_id={self.pack_id}>'
|
||||||
|
|
||||||
|
async def pack(self) -> StickerPack:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Retrieves the sticker pack that this sticker belongs to.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
--------
|
||||||
|
InvalidData
|
||||||
|
The corresponding sticker pack was not found.
|
||||||
|
HTTPException
|
||||||
|
Retrieving the sticker pack failed.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
--------
|
||||||
Optional[:class:`Asset`]
|
:class:`StickerPack`
|
||||||
The resulting CDN asset.
|
The retrieved sticker pack.
|
||||||
"""
|
"""
|
||||||
if self.format is StickerType.lottie:
|
data: ListNitroStickerPacksPayload = await self._state.http.list_nitro_sticker_packs()
|
||||||
return None
|
packs = data['sticker_packs']
|
||||||
|
pack = find(lambda d: int(d['id']) == self.pack_id, packs)
|
||||||
|
|
||||||
return Asset._from_sticker(self._state, self.id, self._image)
|
if pack:
|
||||||
|
return StickerPack(state=self._state, data=pack)
|
||||||
|
raise InvalidData(f'Could not find corresponding sticker pack for {self!r}')
|
||||||
|
|
||||||
|
|
||||||
|
class GuildSticker(Sticker):
|
||||||
|
"""Represents a sticker that belongs to a guild.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. container:: operations
|
||||||
|
|
||||||
|
.. describe:: str(x)
|
||||||
|
|
||||||
|
Returns the name of the sticker.
|
||||||
|
|
||||||
|
.. describe:: x == y
|
||||||
|
|
||||||
|
Checks if the sticker is equal to another sticker.
|
||||||
|
|
||||||
|
.. describe:: x != y
|
||||||
|
|
||||||
|
Checks if the sticker is not equal to another sticker.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
name: :class:`str`
|
||||||
|
The sticker's name.
|
||||||
|
id: :class:`int`
|
||||||
|
The id of the sticker.
|
||||||
|
description: :class:`str`
|
||||||
|
The description of the sticker.
|
||||||
|
format: :class:`StickerFormatType`
|
||||||
|
The format for the sticker's image.
|
||||||
|
available: :class:`bool`
|
||||||
|
Whether this sticker is available for use.
|
||||||
|
guild_id: :class:`int`
|
||||||
|
The ID of the guild that this sticker is from.
|
||||||
|
user: Optional[:class:`User`]
|
||||||
|
The user that created this sticker. This can only be retrieved using :meth:`Guild.fetch_sticker` and
|
||||||
|
having the :attr:`~Permissions.manage_emojis_and_stickers` permission.
|
||||||
|
emoji: :class:`str`
|
||||||
|
The name of a unicode emoji that represents this sticker.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('available', 'guild_id', 'user', 'emoji', 'type', '_cs_guild')
|
||||||
|
|
||||||
|
def _from_data(self, data: GuildStickerPayload) -> None:
|
||||||
|
super()._from_data(data)
|
||||||
|
self.available: bool = data['available']
|
||||||
|
self.guild_id: int = int(data['guild_id'])
|
||||||
|
user = data.get('user')
|
||||||
|
self.user: Optional[User] = self._state.store_user(user) if user else None
|
||||||
|
self.emoji: str = data['tags']
|
||||||
|
self.type: StickerType = StickerType.guild
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'<GuildSticker name={self.name!r} id={self.id} guild_id={self.guild_id} user={self.user!r}>'
|
||||||
|
|
||||||
|
@cached_slot_property('_cs_guild')
|
||||||
|
def guild(self) -> Optional[Guild]:
|
||||||
|
"""Optional[:class:`Guild`]: The guild that this sticker is from.
|
||||||
|
Could be ``None`` if the bot is not in the guild.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return self._state._get_guild(self.guild_id)
|
||||||
|
|
||||||
|
async def edit(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
name: str = MISSING,
|
||||||
|
description: str = MISSING,
|
||||||
|
emoji: str = MISSING,
|
||||||
|
reason: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Edits a :class:`Sticker` for the guild.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
name: :class:`str`
|
||||||
|
The sticker's new name. Must be at least 2 characters.
|
||||||
|
description: Optional[:class:`str`]
|
||||||
|
The sticker's new description. Can be ``None``.
|
||||||
|
emoji: :class:`str`
|
||||||
|
The name of a unicode emoji that represents the sticker's expression.
|
||||||
|
reason: :class:`str`
|
||||||
|
The reason for editing this sticker. Shows up on the audit log.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
Forbidden
|
||||||
|
You are not allowed to edit stickers.
|
||||||
|
HTTPException
|
||||||
|
An error occurred editing the sticker.
|
||||||
|
"""
|
||||||
|
payload = {}
|
||||||
|
|
||||||
|
if name is not MISSING:
|
||||||
|
payload['name'] = name
|
||||||
|
|
||||||
|
if description is not MISSING:
|
||||||
|
payload['description'] = description
|
||||||
|
|
||||||
|
if emoji is not MISSING:
|
||||||
|
try:
|
||||||
|
emoji = unicodedata.name(emoji)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
emoji = emoji.replace(' ', '_')
|
||||||
|
|
||||||
|
payload['tags'] = emoji
|
||||||
|
|
||||||
|
data: GuildStickerPayload = await self._state.http.modify_guild_sticker(self.guild_id, self.id, payload, reason)
|
||||||
|
|
||||||
|
self._from_data(data)
|
||||||
|
|
||||||
|
async def delete(self, *, reason: Optional[str] = None) -> None:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Deletes the custom :class:`Sticker` from the guild.
|
||||||
|
|
||||||
|
You must have :attr:`~Permissions.manage_emojis_and_stickers` permission to
|
||||||
|
do this.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
reason: Optional[:class:`str`]
|
||||||
|
The reason for deleting this sticker. Shows up on the audit log.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
Forbidden
|
||||||
|
You are not allowed to delete stickers.
|
||||||
|
HTTPException
|
||||||
|
An error occurred deleting the sticker.
|
||||||
|
"""
|
||||||
|
await self._state.http.delete_guild_sticker(self.guild_id, self.id, reason)
|
||||||
|
|
||||||
|
|
||||||
|
def _sticker_factory(sticker_type: Literal[1, 2]) -> Tuple[Type[Union[StandardSticker, GuildSticker, Sticker]], StickerType]:
|
||||||
|
value = try_enum(StickerType, sticker_type)
|
||||||
|
if value == StickerType.standard:
|
||||||
|
return StandardSticker, value
|
||||||
|
elif value == StickerType.guild:
|
||||||
|
return GuildSticker, value
|
||||||
|
else:
|
||||||
|
return Sticker, value
|
||||||
|
@ -73,6 +73,9 @@ AuditLogEvent = Literal[
|
|||||||
83,
|
83,
|
||||||
84,
|
84,
|
||||||
85,
|
85,
|
||||||
|
90,
|
||||||
|
91,
|
||||||
|
92,
|
||||||
110,
|
110,
|
||||||
111,
|
111,
|
||||||
112,
|
112,
|
||||||
@ -81,14 +84,14 @@ AuditLogEvent = Literal[
|
|||||||
|
|
||||||
class _AuditLogChange_Str(TypedDict):
|
class _AuditLogChange_Str(TypedDict):
|
||||||
key: Literal[
|
key: Literal[
|
||||||
'name', 'description', 'preferred_locale', 'vanity_url_code', 'topic', 'code', 'allow', 'deny', 'permissions'
|
'name', 'description', 'preferred_locale', 'vanity_url_code', 'topic', 'code', 'allow', 'deny', 'permissions', 'tags'
|
||||||
]
|
]
|
||||||
new_value: str
|
new_value: str
|
||||||
old_value: str
|
old_value: str
|
||||||
|
|
||||||
|
|
||||||
class _AuditLogChange_AssetHash(TypedDict):
|
class _AuditLogChange_AssetHash(TypedDict):
|
||||||
key: Literal['icon_hash', 'splash_hash', 'discovery_splash_hash', 'banner_hash', 'avatar_hash']
|
key: Literal['icon_hash', 'splash_hash', 'discovery_splash_hash', 'banner_hash', 'avatar_hash', 'asset']
|
||||||
new_value: str
|
new_value: str
|
||||||
old_value: str
|
old_value: str
|
||||||
|
|
||||||
@ -105,6 +108,7 @@ class _AuditLogChange_Snowflake(TypedDict):
|
|||||||
'application_id',
|
'application_id',
|
||||||
'channel_id',
|
'channel_id',
|
||||||
'inviter_id',
|
'inviter_id',
|
||||||
|
'guild_id',
|
||||||
]
|
]
|
||||||
new_value: Snowflake
|
new_value: Snowflake
|
||||||
old_value: Snowflake
|
old_value: Snowflake
|
||||||
@ -123,6 +127,7 @@ class _AuditLogChange_Bool(TypedDict):
|
|||||||
'enabled_emoticons',
|
'enabled_emoticons',
|
||||||
'region',
|
'region',
|
||||||
'rtc_region',
|
'rtc_region',
|
||||||
|
'available',
|
||||||
'archived',
|
'archived',
|
||||||
'locked',
|
'locked',
|
||||||
]
|
]
|
||||||
|
@ -33,6 +33,7 @@ from .embed import Embed
|
|||||||
from .channel import ChannelType
|
from .channel import ChannelType
|
||||||
from .components import Component
|
from .components import Component
|
||||||
from .interactions import MessageInteraction
|
from .interactions import MessageInteraction
|
||||||
|
from .sticker import StickerItem
|
||||||
|
|
||||||
|
|
||||||
class ChannelMention(TypedDict):
|
class ChannelMention(TypedDict):
|
||||||
@ -89,22 +90,6 @@ class MessageReference(TypedDict, total=False):
|
|||||||
fail_if_not_exists: bool
|
fail_if_not_exists: bool
|
||||||
|
|
||||||
|
|
||||||
class _StickerOptional(TypedDict, total=False):
|
|
||||||
tags: str
|
|
||||||
|
|
||||||
|
|
||||||
StickerFormatType = Literal[1, 2, 3]
|
|
||||||
|
|
||||||
|
|
||||||
class Sticker(_StickerOptional):
|
|
||||||
id: Snowflake
|
|
||||||
pack_id: Snowflake
|
|
||||||
name: str
|
|
||||||
description: str
|
|
||||||
asset: str
|
|
||||||
format_type: StickerFormatType
|
|
||||||
|
|
||||||
|
|
||||||
class _MessageOptional(TypedDict, total=False):
|
class _MessageOptional(TypedDict, total=False):
|
||||||
guild_id: Snowflake
|
guild_id: Snowflake
|
||||||
member: Member
|
member: Member
|
||||||
@ -117,7 +102,7 @@ class _MessageOptional(TypedDict, total=False):
|
|||||||
application_id: Snowflake
|
application_id: Snowflake
|
||||||
message_reference: MessageReference
|
message_reference: MessageReference
|
||||||
flags: int
|
flags: int
|
||||||
stickers: List[Sticker]
|
sticker_items: List[StickerItem]
|
||||||
referenced_message: Optional[Message]
|
referenced_message: Optional[Message]
|
||||||
interaction: MessageInteraction
|
interaction: MessageInteraction
|
||||||
components: List[Component]
|
components: List[Component]
|
||||||
|
93
discord/types/sticker.py
Normal file
93
discord/types/sticker.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
"""
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015-present Rapptz
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import List, Literal, TypedDict, Union
|
||||||
|
from .snowflake import Snowflake
|
||||||
|
from .user import User
|
||||||
|
|
||||||
|
StickerFormatType = Literal[1, 2, 3]
|
||||||
|
|
||||||
|
|
||||||
|
class StickerItem(TypedDict):
|
||||||
|
id: Snowflake
|
||||||
|
name: str
|
||||||
|
format_type: StickerFormatType
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSticker(TypedDict):
|
||||||
|
id: Snowflake
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
tags: str
|
||||||
|
format_type: StickerFormatType
|
||||||
|
|
||||||
|
|
||||||
|
class StandardSticker(BaseSticker):
|
||||||
|
type: Literal[1]
|
||||||
|
sort_value: int
|
||||||
|
pack_id: Snowflake
|
||||||
|
|
||||||
|
|
||||||
|
class _GuildStickerOptional(TypedDict, total=False):
|
||||||
|
user: User
|
||||||
|
|
||||||
|
|
||||||
|
class GuildSticker(BaseSticker, _GuildStickerOptional):
|
||||||
|
type: Literal[2]
|
||||||
|
available: bool
|
||||||
|
guild_id: Snowflake
|
||||||
|
|
||||||
|
|
||||||
|
Sticker = Union[BaseSticker, StandardSticker, GuildSticker]
|
||||||
|
|
||||||
|
|
||||||
|
class StickerPack(TypedDict):
|
||||||
|
id: Snowflake
|
||||||
|
stickers: List[StandardSticker]
|
||||||
|
name: str
|
||||||
|
sku_id: Snowflake
|
||||||
|
cover_sticker_id: Snowflake
|
||||||
|
description: str
|
||||||
|
banner_asset_id: Snowflake
|
||||||
|
|
||||||
|
|
||||||
|
class _CreateGuildStickerOptional(TypedDict, total=False):
|
||||||
|
description: str
|
||||||
|
|
||||||
|
|
||||||
|
class CreateGuildSticker(_CreateGuildStickerOptional):
|
||||||
|
name: str
|
||||||
|
tags: str
|
||||||
|
|
||||||
|
|
||||||
|
class EditGuildSticker(TypedDict, total=False):
|
||||||
|
name: str
|
||||||
|
tags: str
|
||||||
|
description: str
|
||||||
|
|
||||||
|
|
||||||
|
class ListNitroStickerPacks(TypedDict):
|
||||||
|
sticker_packs: List[StickerPack]
|
162
docs/api.rst
162
docs/api.rst
@ -926,7 +926,7 @@ to handle it, which defaults to print a traceback and ignoring the exception.
|
|||||||
|
|
||||||
Called when a :class:`Guild` adds or removes :class:`Emoji`.
|
Called when a :class:`Guild` adds or removes :class:`Emoji`.
|
||||||
|
|
||||||
This requires :attr:`Intents.emojis` to be enabled.
|
This requires :attr:`Intents.emojis_and_stickers` to be enabled.
|
||||||
|
|
||||||
:param guild: The guild who got their emojis updated.
|
:param guild: The guild who got their emojis updated.
|
||||||
:type guild: :class:`Guild`
|
:type guild: :class:`Guild`
|
||||||
@ -935,6 +935,21 @@ to handle it, which defaults to print a traceback and ignoring the exception.
|
|||||||
:param after: A list of emojis after the update.
|
:param after: A list of emojis after the update.
|
||||||
:type after: Sequence[:class:`Emoji`]
|
:type after: Sequence[:class:`Emoji`]
|
||||||
|
|
||||||
|
.. function:: on_guild_stickers_update(guild, before, after)
|
||||||
|
|
||||||
|
Called when a :class:`Guild` updates its stickers.
|
||||||
|
|
||||||
|
This requires :attr:`Intents.emojis_and_stickers` to be enabled.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
:param guild: The guild who got their stickers updated.
|
||||||
|
:type guild: :class:`Guild`
|
||||||
|
:param before: A list of stickers before the update.
|
||||||
|
:type before: Sequence[:class:`GuildSticker`]
|
||||||
|
:param after: A list of stickers after the update.
|
||||||
|
:type after: Sequence[:class:`GuildSticker`]
|
||||||
|
|
||||||
.. function:: on_guild_available(guild)
|
.. function:: on_guild_available(guild)
|
||||||
on_guild_unavailable(guild)
|
on_guild_unavailable(guild)
|
||||||
|
|
||||||
@ -2205,6 +2220,63 @@ of :class:`enum.Enum`.
|
|||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. attribute:: sticker_create
|
||||||
|
|
||||||
|
A sticker was created.
|
||||||
|
|
||||||
|
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||||
|
the :class:`GuildSticker` or :class:`Object` with the ID of the sticker
|
||||||
|
which was updated.
|
||||||
|
|
||||||
|
Possible attributes for :class:`AuditLogDiff`:
|
||||||
|
|
||||||
|
- :attr:`~AuditLogDiff.name`
|
||||||
|
- :attr:`~AuditLogDiff.emoji`
|
||||||
|
- :attr:`~AuditLogDiff.type`
|
||||||
|
- :attr:`~AuditLogDiff.format_type`
|
||||||
|
- :attr:`~AuditLogDiff.description`
|
||||||
|
- :attr:`~AuditLogDiff.available`
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. attribute:: sticker_update
|
||||||
|
|
||||||
|
A sticker was updated.
|
||||||
|
|
||||||
|
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||||
|
the :class:`GuildSticker` or :class:`Object` with the ID of the sticker
|
||||||
|
which was updated.
|
||||||
|
|
||||||
|
Possible attributes for :class:`AuditLogDiff`:
|
||||||
|
|
||||||
|
- :attr:`~AuditLogDiff.name`
|
||||||
|
- :attr:`~AuditLogDiff.emoji`
|
||||||
|
- :attr:`~AuditLogDiff.type`
|
||||||
|
- :attr:`~AuditLogDiff.format_type`
|
||||||
|
- :attr:`~AuditLogDiff.description`
|
||||||
|
- :attr:`~AuditLogDiff.available`
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. attribute:: sticker_delete
|
||||||
|
|
||||||
|
A sticker was deleted.
|
||||||
|
|
||||||
|
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||||
|
the :class:`GuildSticker` or :class:`Object` with the ID of the sticker
|
||||||
|
which was updated.
|
||||||
|
|
||||||
|
Possible attributes for :class:`AuditLogDiff`:
|
||||||
|
|
||||||
|
- :attr:`~AuditLogDiff.name`
|
||||||
|
- :attr:`~AuditLogDiff.emoji`
|
||||||
|
- :attr:`~AuditLogDiff.type`
|
||||||
|
- :attr:`~AuditLogDiff.format_type`
|
||||||
|
- :attr:`~AuditLogDiff.description`
|
||||||
|
- :attr:`~AuditLogDiff.available`
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
.. attribute:: thread_create
|
.. attribute:: thread_create
|
||||||
|
|
||||||
A thread was created.
|
A thread was created.
|
||||||
@ -2356,6 +2428,20 @@ of :class:`enum.Enum`.
|
|||||||
|
|
||||||
.. class:: StickerType
|
.. class:: StickerType
|
||||||
|
|
||||||
|
Represents the type of sticker.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. attribute:: standard
|
||||||
|
|
||||||
|
Represents a standard sticker that all Nitro users can use.
|
||||||
|
|
||||||
|
.. attribute:: guild
|
||||||
|
|
||||||
|
Represents a custom sticker created in a guild.
|
||||||
|
|
||||||
|
.. class:: StickerFormatType
|
||||||
|
|
||||||
Represents the type of sticker images.
|
Represents the type of sticker images.
|
||||||
|
|
||||||
.. versionadded:: 1.6
|
.. versionadded:: 1.6
|
||||||
@ -2825,15 +2911,9 @@ AuditLogDiff
|
|||||||
|
|
||||||
.. attribute:: type
|
.. attribute:: type
|
||||||
|
|
||||||
The type of channel or channel permission overwrite.
|
The type of channel or sticker.
|
||||||
|
|
||||||
If the type is an :class:`int`, then it is a type of channel which can be either
|
:type: Union[:class:`ChannelType`, :class:`StickerType`]
|
||||||
``0`` to indicate a text channel or ``1`` to indicate a voice channel.
|
|
||||||
|
|
||||||
If the type is a :class:`str`, then it is a type of permission overwrite which
|
|
||||||
can be either ``'role'`` or ``'member'``.
|
|
||||||
|
|
||||||
:type: Union[:class:`int`, :class:`str`]
|
|
||||||
|
|
||||||
.. attribute:: topic
|
.. attribute:: topic
|
||||||
|
|
||||||
@ -3040,6 +3120,38 @@ AuditLogDiff
|
|||||||
|
|
||||||
:type: :class:`VideoQualityMode`
|
:type: :class:`VideoQualityMode`
|
||||||
|
|
||||||
|
.. attribute:: format_type
|
||||||
|
|
||||||
|
The format type of a sticker being changed.
|
||||||
|
|
||||||
|
See also :attr:`GuildSticker.format_type`
|
||||||
|
|
||||||
|
:type: :class:`StickerFormatType`
|
||||||
|
|
||||||
|
.. attribute:: emoji
|
||||||
|
|
||||||
|
The name of the emoji that represents a sticker being changed.
|
||||||
|
|
||||||
|
See also :attr:`GuildSticker.emoji`
|
||||||
|
|
||||||
|
:type: :class:`str`
|
||||||
|
|
||||||
|
.. attribute:: description
|
||||||
|
|
||||||
|
The description of a sticker being changed.
|
||||||
|
|
||||||
|
See also :attr:`GuildSticker.description`
|
||||||
|
|
||||||
|
:type: :class:`str`
|
||||||
|
|
||||||
|
.. attribute:: available
|
||||||
|
|
||||||
|
The availability of a sticker being changed.
|
||||||
|
|
||||||
|
See also :attr:`GuildSticker.available`
|
||||||
|
|
||||||
|
:type: :class:`bool`
|
||||||
|
|
||||||
.. attribute:: archived
|
.. attribute:: archived
|
||||||
|
|
||||||
The thread is now archived.
|
The thread is now archived.
|
||||||
@ -3620,6 +3732,22 @@ Widget
|
|||||||
.. autoclass:: Widget()
|
.. autoclass:: Widget()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
StickerPack
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: StickerPack
|
||||||
|
|
||||||
|
.. autoclass:: StickerPack()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
StickerItem
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: StickerItem
|
||||||
|
|
||||||
|
.. autoclass:: StickerItem()
|
||||||
|
:members:
|
||||||
|
|
||||||
Sticker
|
Sticker
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -3628,6 +3756,22 @@ Sticker
|
|||||||
.. autoclass:: Sticker()
|
.. autoclass:: Sticker()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
StandardSticker
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: StandardSticker
|
||||||
|
|
||||||
|
.. autoclass:: StandardSticker()
|
||||||
|
:members:
|
||||||
|
|
||||||
|
GuildSticker
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: GuildSticker
|
||||||
|
|
||||||
|
.. autoclass:: GuildSticker()
|
||||||
|
:members:
|
||||||
|
|
||||||
RawMessageDeleteEvent
|
RawMessageDeleteEvent
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user