mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-08-29 22:45:09 +00:00
Add support for user collectibles
This commit is contained in:
parent
69f06c9456
commit
cbff6ddef9
@ -75,6 +75,7 @@ from .subscription import *
|
||||
from .presences import *
|
||||
from .primary_guild import *
|
||||
from .onboarding import *
|
||||
from .collectible import *
|
||||
|
||||
|
||||
class VersionInfo(NamedTuple):
|
||||
|
@ -355,6 +355,16 @@ class Asset(AssetMixin):
|
||||
animated=False,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _from_user_collectible(cls, state: _State, asset: str, animated: bool = False) -> Self:
|
||||
name = 'static.png' if not animated else 'asset.webm'
|
||||
return cls(
|
||||
state,
|
||||
url=f'{cls.BASE}/assets/collectibles/{asset}{name}',
|
||||
key=asset,
|
||||
animated=animated,
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self._url
|
||||
|
||||
|
109
discord/collectible.py
Normal file
109
discord/collectible.py
Normal file
@ -0,0 +1,109 @@
|
||||
"""
|
||||
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 Optional, TYPE_CHECKING
|
||||
|
||||
|
||||
from .asset import Asset
|
||||
from .enums import NameplatePalette, CollectibleType, try_enum
|
||||
from .utils import parse_time
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from datetime import datetime
|
||||
|
||||
from .state import ConnectionState
|
||||
from .types.user import (
|
||||
Collectible as CollectiblePayload,
|
||||
)
|
||||
|
||||
|
||||
__all__ = ('Collectible',)
|
||||
|
||||
|
||||
class Collectible:
|
||||
"""Represents a user's collectible.
|
||||
|
||||
.. versionadded:: 2.7
|
||||
|
||||
Attributes
|
||||
----------
|
||||
label: :class:`str`
|
||||
The label of the collectible.
|
||||
palette: Optional[:class:`NameplatePalette`]
|
||||
The palette of the collectible.
|
||||
This is only available if ``type`` is
|
||||
:class:`CollectibleType.nameplate`.
|
||||
sku_id: :class:`int`
|
||||
The SKU ID of the collectible.
|
||||
type: :class:`CollectibleType`
|
||||
The type of the collectible.
|
||||
expires_at: Optional[:class:`datetime.datetime`]
|
||||
The expiration date of the collectible. If applicable.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'type',
|
||||
'sku_id',
|
||||
'label',
|
||||
'expires_at',
|
||||
'palette',
|
||||
'_state',
|
||||
'_asset',
|
||||
)
|
||||
|
||||
def __init__(self, *, state: ConnectionState, type: str, data: CollectiblePayload) -> None:
|
||||
self._state: ConnectionState = state
|
||||
self.type: CollectibleType = try_enum(CollectibleType, type)
|
||||
self._asset: str = data['asset']
|
||||
self.sku_id: int = int(data['sku_id'])
|
||||
self.label: str = data['label']
|
||||
self.expires_at: Optional[datetime] = parse_time(data.get('expires_at'))
|
||||
|
||||
# nameplate
|
||||
self.palette: Optional[NameplatePalette]
|
||||
try:
|
||||
self.palette = try_enum(NameplatePalette, data['palette']) # type: ignore
|
||||
except KeyError:
|
||||
self.palette = None
|
||||
|
||||
@property
|
||||
def static(self) -> Asset:
|
||||
""":class:`Asset`: The static asset of the collectible."""
|
||||
return Asset._from_user_collectible(self._state, self._asset)
|
||||
|
||||
@property
|
||||
def animated(self) -> Asset:
|
||||
""":class:`Asset`: The animated asset of the collectible."""
|
||||
return Asset._from_user_collectible(self._state, self._asset, animated=True)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
attrs = ['sku_id']
|
||||
if self.palette:
|
||||
attrs.append('palette')
|
||||
|
||||
joined_attrs = ' '.join(f'{attr}={getattr(self, attr)!r}' for attr in attrs)
|
||||
return f'<{self.type.name.title()} {joined_attrs}>'
|
@ -83,6 +83,8 @@ __all__ = (
|
||||
'OnboardingMode',
|
||||
'SeparatorSpacing',
|
||||
'MediaItemLoadingState',
|
||||
'CollectibleType',
|
||||
'NameplatePalette',
|
||||
)
|
||||
|
||||
|
||||
@ -968,6 +970,24 @@ class MediaItemLoadingState(Enum):
|
||||
not_found = 3
|
||||
|
||||
|
||||
class CollectibleType(Enum):
|
||||
nameplate = 'nameplate'
|
||||
|
||||
|
||||
class NameplatePalette(Enum):
|
||||
crimson = 'crimson'
|
||||
berry = 'berry'
|
||||
sky = 'sky'
|
||||
teal = 'teal'
|
||||
forest = 'forest'
|
||||
bubble_gum = 'bubble_gum'
|
||||
violet = 'violet'
|
||||
cobalt = 'cobalt'
|
||||
clover = 'clover'
|
||||
lemon = 'lemon'
|
||||
white = 'white'
|
||||
|
||||
|
||||
def create_unknown_value(cls: Type[E], val: Any) -> E:
|
||||
value_cls = cls._enum_value_cls_ # type: ignore # This is narrowed below
|
||||
name = f'unknown_{val}'
|
||||
|
@ -75,6 +75,7 @@ if TYPE_CHECKING:
|
||||
VoiceState as VoiceStatePayload,
|
||||
)
|
||||
from .primary_guild import PrimaryGuild
|
||||
from .collectible import Collectible
|
||||
|
||||
VocalGuildChannel = Union[VoiceChannel, StageChannel]
|
||||
|
||||
@ -311,6 +312,7 @@ class Member(discord.abc.Messageable, _UserTag):
|
||||
avatar_decoration: Optional[Asset]
|
||||
avatar_decoration_sku_id: Optional[int]
|
||||
primary_guild: PrimaryGuild
|
||||
collectibles: List[Collectible]
|
||||
|
||||
def __init__(self, *, data: MemberWithUserPayload, guild: Guild, state: ConnectionState):
|
||||
self._state: ConnectionState = state
|
||||
|
@ -27,11 +27,38 @@ from typing import Literal, Optional, TypedDict
|
||||
from typing_extensions import NotRequired
|
||||
|
||||
|
||||
class AvatarDecorationData(TypedDict):
|
||||
PremiumType = Literal[0, 1, 2, 3]
|
||||
NameplatePallete = Literal['crimson', 'berry', 'sky', 'teal', 'forest', 'bubble_gum', 'violet', 'cobalt', 'clover']
|
||||
|
||||
|
||||
class _UserSKU(TypedDict):
|
||||
asset: str
|
||||
sku_id: Snowflake
|
||||
|
||||
|
||||
AvatarDecorationData = _UserSKU
|
||||
|
||||
|
||||
class PrimaryGuild(TypedDict):
|
||||
identity_guild_id: Optional[int]
|
||||
identity_enabled: Optional[bool]
|
||||
tag: Optional[str]
|
||||
badge: Optional[str]
|
||||
|
||||
|
||||
class Collectible(_UserSKU):
|
||||
label: str
|
||||
expires_at: Optional[str]
|
||||
|
||||
|
||||
class NameplateCollectible(Collectible):
|
||||
palette: str
|
||||
|
||||
|
||||
class UserCollectibles(TypedDict):
|
||||
nameplate: NameplateCollectible
|
||||
|
||||
|
||||
class PartialUser(TypedDict):
|
||||
id: Snowflake
|
||||
username: str
|
||||
@ -39,9 +66,8 @@ class PartialUser(TypedDict):
|
||||
avatar: Optional[str]
|
||||
global_name: Optional[str]
|
||||
avatar_decoration_data: NotRequired[AvatarDecorationData]
|
||||
|
||||
|
||||
PremiumType = Literal[0, 1, 2, 3]
|
||||
primary_guild: NotRequired[PrimaryGuild]
|
||||
collectibles: NotRequired[UserCollectibles]
|
||||
|
||||
|
||||
class User(PartialUser, total=False):
|
||||
@ -54,10 +80,3 @@ class User(PartialUser, total=False):
|
||||
flags: int
|
||||
premium_type: PremiumType
|
||||
public_flags: int
|
||||
|
||||
|
||||
class PrimaryGuild(TypedDict):
|
||||
identity_guild_id: Optional[int]
|
||||
identity_enabled: Optional[bool]
|
||||
tag: Optional[str]
|
||||
badge: Optional[str]
|
||||
|
@ -33,6 +33,7 @@ from .enums import DefaultAvatar
|
||||
from .flags import PublicUserFlags
|
||||
from .utils import snowflake_time, _bytes_to_base64_data, MISSING, _get_as_snowflake
|
||||
from .primary_guild import PrimaryGuild
|
||||
from .collectible import Collectible
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
@ -49,6 +50,7 @@ if TYPE_CHECKING:
|
||||
User as UserPayload,
|
||||
AvatarDecorationData,
|
||||
PrimaryGuild as PrimaryGuildPayload,
|
||||
UserCollectibles as UserCollectiblesPayload,
|
||||
)
|
||||
|
||||
|
||||
@ -78,6 +80,7 @@ class BaseUser(_UserTag):
|
||||
'_state',
|
||||
'_avatar_decoration_data',
|
||||
'_primary_guild',
|
||||
'_collectibles',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -94,6 +97,7 @@ class BaseUser(_UserTag):
|
||||
_public_flags: int
|
||||
_avatar_decoration_data: Optional[AvatarDecorationData]
|
||||
_primary_guild: Optional[PrimaryGuildPayload]
|
||||
_collectibles: Optional[UserCollectiblesPayload]
|
||||
|
||||
def __init__(self, *, state: ConnectionState, data: Union[UserPayload, PartialUserPayload]) -> None:
|
||||
self._state = state
|
||||
@ -132,6 +136,7 @@ class BaseUser(_UserTag):
|
||||
self.system = data.get('system', False)
|
||||
self._avatar_decoration_data = data.get('avatar_decoration_data')
|
||||
self._primary_guild = data.get('primary_guild', None)
|
||||
self._collectibles = data.get('collectibles', None)
|
||||
|
||||
@classmethod
|
||||
def _copy(cls, user: Self) -> Self:
|
||||
@ -149,6 +154,7 @@ class BaseUser(_UserTag):
|
||||
self._public_flags = user._public_flags
|
||||
self._avatar_decoration_data = user._avatar_decoration_data
|
||||
self._primary_guild = user._primary_guild
|
||||
self._collectibles = user._collectibles
|
||||
|
||||
return self
|
||||
|
||||
@ -324,6 +330,16 @@ class BaseUser(_UserTag):
|
||||
return PrimaryGuild(state=self._state, data=self._primary_guild)
|
||||
return PrimaryGuild._default(self._state)
|
||||
|
||||
@property
|
||||
def collectibles(self) -> List[Collectible]:
|
||||
"""List[:class:`Collectible`]: Returns a list of the user's collectibles.
|
||||
|
||||
.. versionadded:: 2.7
|
||||
"""
|
||||
if self._collectibles is None:
|
||||
return []
|
||||
return [Collectible(state=self._state, type=key, data=value) for key, value in self._collectibles.items() if value] # type: ignore
|
||||
|
||||
def mentioned_in(self, message: Message) -> bool:
|
||||
"""Checks if the user is mentioned in the specified message.
|
||||
|
||||
|
70
docs/api.rst
70
docs/api.rst
@ -4052,8 +4052,6 @@ of :class:`enum.Enum`.
|
||||
|
||||
Default channels and questions count towards onboarding constraints.
|
||||
|
||||
|
||||
|
||||
.. class:: MediaItemLoadingState
|
||||
|
||||
Represents a :class:`UnfurledMediaItem` load state.
|
||||
@ -4074,6 +4072,66 @@ of :class:`enum.Enum`.
|
||||
|
||||
The media item was not found.
|
||||
|
||||
.. class:: CollectibleType
|
||||
|
||||
Represents the type of a :class:`Collectible`.
|
||||
|
||||
.. versionadded:: 2.7
|
||||
|
||||
.. attribute:: nameplate
|
||||
|
||||
The collectible is a nameplate.
|
||||
|
||||
.. class:: NameplatePalette
|
||||
|
||||
Represents the available palettes for a nameplate.
|
||||
|
||||
.. versionadded:: 2.7
|
||||
|
||||
.. attribute:: crimson
|
||||
|
||||
The collectible nameplate palette is crimson.
|
||||
|
||||
.. attribute:: berry
|
||||
|
||||
The collectible nameplate palette is berry.
|
||||
|
||||
.. attribute:: sky
|
||||
|
||||
The collectible nameplate palette is sky.
|
||||
|
||||
.. attribute:: teal
|
||||
|
||||
The collectible nameplate palette is teal.
|
||||
|
||||
.. attribute:: forest
|
||||
|
||||
The collectible nameplate palette is forest.
|
||||
|
||||
.. attribute:: bubble_gum
|
||||
|
||||
The collectible nameplate palette is bubble gum.
|
||||
|
||||
.. attribute:: violet
|
||||
|
||||
The collectible nameplate palette is violet.
|
||||
|
||||
.. attribute:: cobalt
|
||||
|
||||
The collectible nameplate palette is cobalt.
|
||||
|
||||
.. attribute:: clover
|
||||
|
||||
The collectible nameplate palette is clover.
|
||||
|
||||
.. attribute:: lemon
|
||||
|
||||
The collectible nameplate palette is lemon.
|
||||
|
||||
.. attribute:: white
|
||||
|
||||
The collectible nameplate palette is white.
|
||||
|
||||
.. _discord-api-audit-logs:
|
||||
|
||||
Audit Log Data
|
||||
@ -5770,6 +5828,14 @@ PrimaryGuild
|
||||
.. autoclass:: PrimaryGuild()
|
||||
:members:
|
||||
|
||||
Collectible
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. attributetable:: Collectible
|
||||
|
||||
.. autoclass:: Collectible()
|
||||
:members:
|
||||
|
||||
CallMessage
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user