Skip to content

Commit 5008db3

Browse files
authored
Merge branch 'master' into soundboard
2 parents 7c81d85 + 4ccb0c0 commit 5008db3

File tree

11 files changed

+173
-3
lines changed

11 files changed

+173
-3
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ These changes are available on the `master` branch, but have not yet been releas
7272
([#2775](https://github.com/Pycord-Development/pycord/pull/2775))
7373
- Added `discord.Interaction.created_at`.
7474
([#2801](https://github.com/Pycord-Development/pycord/pull/2801))
75+
- Added `User.nameplate` property.
76+
([#2817](https://github.com/Pycord-Development/pycord/pull/2817))
7577
- Added role gradients support with `Role.colours` and the `RoleColours` class.
7678
([#2818](https://github.com/Pycord-Development/pycord/pull/2818))
7779

@@ -130,6 +132,9 @@ These changes are available on the `master` branch, but have not yet been releas
130132
([#2761](https://github.com/Pycord-Development/pycord/pull/2761))
131133
- Updated `valid_locales` to support `in` and `es-419`.
132134
([#2767](https://github.com/Pycord-Development/pycord/pull/2767))
135+
- Added support for emoji aliases like `:smile:` in PartialEmoji.from_str. Also applied
136+
the same logic in PartialEmojiConverter.
137+
([#2815](https://github.com/Pycord-Development/pycord/pull/2815))
133138
- Fixed `Webhook.edit` not working with `attachments=[]`.
134139
([#2779](https://github.com/Pycord-Development/pycord/pull/2779))
135140
- Fixed GIF-based `Sticker` returning the wrong `url`.

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ include LICENSE
33
include requirements.txt
44
include discord/bin/*.dll
55
include discord/py.typed
6+
include discord/emojis.json
67

78
prune .github
89
prune docs

discord/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from .channel import *
3636
from .client import *
3737
from .cog import *
38+
from .collectibles import *
3839
from .colour import *
3940
from .commands import *
4041
from .components import *

discord/collectibles.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2021-present Pycord Development
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a
7+
copy of this software and associated documentation files (the "Software"),
8+
to deal in the Software without restriction, including without limitation
9+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
10+
and/or sell copies of the Software, and to permit persons to whom the
11+
Software is furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22+
DEALINGS IN THE SOFTWARE.
23+
"""
24+
25+
from typing import TYPE_CHECKING
26+
27+
if TYPE_CHECKING:
28+
from .state import ConnectionState
29+
30+
from .asset import Asset
31+
from .types.collectibles import Nameplate as NameplatePayload
32+
33+
34+
class Nameplate:
35+
"""
36+
Represents a Discord Nameplate.
37+
38+
.. versionadded:: 2.7
39+
40+
Attributes
41+
----------
42+
sku_id: int
43+
The SKU ID of the nameplate.
44+
palette: str
45+
The color palette of the nameplate.
46+
"""
47+
48+
def __init__(self, data: NameplatePayload, state: "ConnectionState") -> None:
49+
self.sku_id: int = data["sku_id"]
50+
self.palette: str = data["palette"]
51+
self._label: str = data["label"]
52+
self._asset: str = data["asset"]
53+
self._state: "ConnectionState" = state
54+
55+
def __repr__(self) -> str:
56+
return f"<Nameplate sku_id={self.sku_id} palette={self.palette}>"
57+
58+
def get_asset(self, animated: bool = False) -> Asset:
59+
"""Returns the asset of the nameplate.
60+
61+
Parameters
62+
----------
63+
animated: :class:`bool`
64+
Whether to return the animated version of the asset, in webm version. Defaults to ``False``.
65+
"""
66+
fn = "static.png" if not animated else "asset.webm"
67+
return Asset(
68+
state=self._state,
69+
url=f"{Asset.BASE}/assets/collectibles/{self._asset}{fn}",
70+
key=self._asset.split("/")[-1],
71+
animated=animated,
72+
)
73+
74+
75+
__all__ = ("Nameplate",)

discord/emojis.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

discord/ext/commands/converter.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
)
4242

4343
import discord
44+
from discord.utils import UNICODE_EMOJIS
4445

4546
from .errors import *
4647

@@ -851,7 +852,8 @@ async def convert(self, ctx: Context, argument: str) -> discord.GuildEmoji:
851852
class PartialEmojiConverter(Converter[discord.PartialEmoji]):
852853
"""Converts to a :class:`~discord.PartialEmoji`.
853854
854-
This is done by extracting the animated flag, name and ID from the emoji.
855+
This is done by extracting the animated flag, name, and ID for custom emojis,
856+
or by using the standard Unicode emojis supported by Discord.
855857
856858
.. versionchanged:: 1.5
857859
Raise :exc:`.PartialEmojiConversionFailure` instead of generic :exc:`.BadArgument`
@@ -872,6 +874,14 @@ async def convert(self, ctx: Context, argument: str) -> discord.PartialEmoji:
872874
id=emoji_id,
873875
)
874876

877+
if argument in UNICODE_EMOJIS:
878+
return discord.PartialEmoji.with_state(
879+
ctx.bot._connection,
880+
animated=False,
881+
name=argument,
882+
id=None,
883+
)
884+
875885
raise PartialEmojiConversionFailure(argument)
876886

877887

@@ -1094,7 +1104,11 @@ def get_converter(param: inspect.Parameter) -> Any:
10941104

10951105

10961106
def is_generic_type(tp: Any, *, _GenericAlias: type = _GenericAlias) -> bool:
1097-
return isinstance(tp, type) and issubclass(tp, Generic) or isinstance(tp, _GenericAlias) # type: ignore
1107+
return (
1108+
isinstance(tp, type)
1109+
and issubclass(tp, Generic)
1110+
or isinstance(tp, _GenericAlias)
1111+
) # type: ignore
10981112

10991113

11001114
CONVERTER_MAPPING: dict[type[Any], Any] = {

discord/partial_emoji.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def from_str(cls: type[PE], value: str) -> PE:
127127
- ``name:id``
128128
- ``<:name:id>``
129129
130-
If the format does not match then it is assumed to be a unicode emoji.
130+
If the format does not match then it is assumed to be a Unicode emoji block, either as Unicode characters or as a Discord alias (``:smile:``).
131131
132132
.. versionadded:: 2.0
133133
@@ -141,6 +141,11 @@ def from_str(cls: type[PE], value: str) -> PE:
141141
:class:`PartialEmoji`
142142
The partial emoji from this string.
143143
"""
144+
if unicode_emoji := utils.EMOJIS_MAP.get(
145+
value.removeprefix(":").removesuffix(":")
146+
):
147+
return cls(name=unicode_emoji, id=None, animated=False)
148+
144149
match = cls._CUSTOM_EMOJI_RE.match(value)
145150
if match is not None:
146151
groups = match.groupdict()

discord/types/collectibles.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2021-present Pycord Development
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a
7+
copy of this software and associated documentation files (the "Software"),
8+
to deal in the Software without restriction, including without limitation
9+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
10+
and/or sell copies of the Software, and to permit persons to whom the
11+
Software is furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22+
DEALINGS IN THE SOFTWARE.
23+
"""
24+
25+
from __future__ import annotations
26+
27+
from typing import TypedDict
28+
29+
from .snowflake import Snowflake
30+
31+
32+
class Nameplate(TypedDict):
33+
sku_id: Snowflake
34+
asset: str
35+
label: str
36+
palette: str

discord/user.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import discord.abc
3131

3232
from .asset import Asset
33+
from .collectibles import Nameplate
3334
from .colour import Colour
3435
from .flags import PublicUserFlags
3536
from .iterators import EntitlementIterator
@@ -76,6 +77,7 @@ class BaseUser(_UserTag):
7677
"_public_flags",
7778
"_avatar_decoration",
7879
"_state",
80+
"nameplate",
7981
)
8082

8183
if TYPE_CHECKING:
@@ -91,6 +93,7 @@ class BaseUser(_UserTag):
9193
_accent_colour: int | None
9294
_avatar_decoration: dict | None
9395
_public_flags: int
96+
nameplate: Nameplate | None
9497

9598
def __init__(
9699
self, *, state: ConnectionState, data: UserPayload | PartialUserPayload
@@ -143,6 +146,11 @@ def _update(self, data: UserPayload) -> None:
143146
self._banner = data.get("banner", None)
144147
self._accent_colour = data.get("accent_color", None)
145148
self._avatar_decoration = data.get("avatar_decoration_data", None)
149+
nameplate = (data.get("collectibles") or {}).get("nameplate", None)
150+
if nameplate:
151+
self.nameplate = Nameplate(data=nameplate, state=self._state)
152+
else:
153+
self.nameplate = None
146154
self._public_flags = data.get("public_flags", 0)
147155
self.bot = data.get("bot", False)
148156
self.system = data.get("system", False)
@@ -534,6 +542,10 @@ class User(BaseUser, discord.abc.Messageable):
534542
Specifies if the user is a bot account.
535543
system: :class:`bool`
536544
Specifies if the user is a system user (i.e. represents Discord officially).
545+
nameplate: Optional[:class:`Nameplate`]
546+
The user's nameplate, if the user has one.
547+
548+
.. versionadded:: 2.7
537549
"""
538550

539551
__slots__ = ("_stored",)

discord/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import collections.abc
3131
import datetime
3232
import functools
33+
import importlib.resources
3334
import itertools
3435
import json
3536
import re
@@ -101,6 +102,15 @@
101102

102103
DISCORD_EPOCH = 1420070400000
103104

105+
with (
106+
importlib.resources.files(__package__)
107+
.joinpath("emojis.json")
108+
.open(encoding="utf-8") as f
109+
):
110+
EMOJIS_MAP = json.load(f)
111+
112+
UNICODE_EMOJIS = set(EMOJIS_MAP.values())
113+
104114

105115
class _MissingSentinel:
106116
def __eq__(self, other) -> bool:

0 commit comments

Comments
 (0)