From 26b49d2f3e9d7cd6d89d900a1b54aceb5c122254 Mon Sep 17 00:00:00 2001 From: Sacul0457Deve <183588943+Sacul0457@users.noreply.github.com.> Date: Sun, 26 Apr 2026 09:13:14 +0800 Subject: [PATCH] add last_pin_timestamp --- discord/app_commands/models.py | 14 +++++++++++-- discord/channel.py | 36 ++++++++++++++++++++++++++++++++-- discord/threads.py | 6 ++++++ discord/types/channel.py | 4 +++- discord/types/interactions.py | 1 + discord/types/threads.py | 2 +- 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/discord/app_commands/models.py b/discord/app_commands/models.py index b3a4b151e..df27d0860 100644 --- a/discord/app_commands/models.py +++ b/discord/app_commands/models.py @@ -604,6 +604,10 @@ class AppCommandChannel(Hashable): If the channel is marked as "not safe for work" or "age restricted". .. versionadded:: 2.6 + last_pin_timestamp: Optional[:class:`datetime.datetime`] + When the last pinned message was pinned. ``None`` if no messages are currently pinned. + + .. versionadded:: 2.8 """ __slots__ = ( @@ -618,7 +622,7 @@ class AppCommandChannel(Hashable): 'category_id', 'slowmode_delay', 'last_message_id', - '_last_pin', + 'last_pin_timestamp', '_flags', '_state', ) @@ -642,7 +646,7 @@ class AppCommandChannel(Hashable): self.category_id: Optional[int] = _get_as_snowflake(data, 'parent_id') self.slowmode_delay: int = data.get('rate_limit_per_user') or 0 self.last_message_id: Optional[int] = _get_as_snowflake(data, 'last_message_id') - self._last_pin: Optional[datetime] = parse_time(data.get('last_pin_timestamp')) + self.last_pin_timestamp: Optional[datetime] = parse_time(data.get('last_pin_timestamp')) self._flags: int = data.get('flags', 0) def __str__(self) -> str: @@ -793,6 +797,10 @@ class AppCommandThread(Hashable): The total number of messages sent, including deleted messages. .. versionadded:: 2.6 + last_pin_timestamp: Optional[:class:`datetime.datetime`] + When the last pinned message was pinned. ``None`` if no messages are currently pinned. + + .. versionadded:: 2.8 permissions: :class:`~discord.Permissions` The resolved permissions of the user who invoked the application command in that thread. @@ -833,6 +841,7 @@ class AppCommandThread(Hashable): 'slowmode_delay', 'last_message_id', 'total_message_sent', + 'last_pin_timestamp', '_applied_tags', '_flags', '_created_at', @@ -859,6 +868,7 @@ class AppCommandThread(Hashable): self.last_message_id: Optional[int] = _get_as_snowflake(data, 'last_message_id') self.slowmode_delay: int = data.get('rate_limit_per_user', 0) self.total_message_sent: int = data.get('total_message_sent', 0) + self.last_pin_timestamp: Optional[datetime] = parse_time(data.get('last_pin_timestamp')) self._applied_tags: array.array[int] = array.array('Q', map(int, data.get('applied_tags', []))) self._flags: int = data.get('flags', 0) self._unroll_metadata(data['thread_metadata']) diff --git a/discord/channel.py b/discord/channel.py index 8aee381e9..ca9fb9b45 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -333,6 +333,10 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): The default slowmode delay in seconds for threads created in this channel. .. versionadded:: 2.3 + last_pin_timestamp: Optional[:class:`datetime.datetime`] + When the last pinned message was pinned. ``None`` if no messages are currently pinned. + + .. versionadded:: 2.8 """ __slots__ = ( @@ -350,6 +354,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): 'last_message_id', 'default_auto_archive_duration', 'default_thread_slowmode_delay', + 'last_pin_timestamp', ) def __init__(self, *, state: ConnectionState, guild: Guild, data: Union[TextChannelPayload, NewsChannelPayload]): @@ -383,6 +388,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): self.default_thread_slowmode_delay: int = data.get('default_thread_rate_limit_per_user', 0) self._type: Literal[0, 5] = data.get('type', self._type) self.last_message_id: Optional[int] = utils._get_as_snowflake(data, 'last_message_id') + self.last_pin_timestamp: Optional[datetime.datetime] = utils.parse_time(data.get('last_pin_timestamp')) self._fill_overwrites(data) async def _get_channel(self) -> Self: @@ -3221,15 +3227,26 @@ class DMChannel(discord.abc.Messageable, discord.abc.PrivateChannel, Hashable): The user presenting yourself. id: :class:`int` The direct message channel ID. + last_pin_timestamp: Optional[:class:`datetime.datetime`] + When the last pinned message was pinned. ``None`` if no messages are currently pinned. + + .. versionadded:: 2.8 """ - __slots__ = ('id', 'recipients', 'me', '_state') + __slots__ = ( + 'id', + 'recipients', + 'me', + '_state', + 'last_pin_timestamp', + ) def __init__(self, *, me: ClientUser, state: ConnectionState, data: DMChannelPayload): self._state: ConnectionState = state self.recipients: List[User] = [state.store_user(u) for u in data.get('recipients', [])] self.me: ClientUser = me self.id: int = int(data['id']) + self.last_pin_timestamp: Optional[datetime.datetime] = utils.parse_time(data.get('last_pin_timestamp')) async def _get_channel(self) -> Self: return self @@ -3388,9 +3405,23 @@ class GroupChannel(discord.abc.Messageable, discord.abc.PrivateChannel, Hashable .. versionadded:: 2.0 name: Optional[:class:`str`] The group channel's name if provided. + last_pin_timestamp: Optional[:class:`datetime.datetime`] + When the last pinned message was pinned. ``None`` if no messages are currently pinned. + + .. versionadded:: 2.8 """ - __slots__ = ('id', 'recipients', 'owner_id', 'owner', '_icon', 'name', 'me', '_state') + __slots__ = ( + 'id', + 'recipients', + 'owner_id', + 'owner', + '_icon', + 'name', + 'me', + '_state', + 'last_pin_timestamp', + ) def __init__(self, *, me: ClientUser, state: ConnectionState, data: GroupChannelPayload): self._state: ConnectionState = state @@ -3409,6 +3440,7 @@ class GroupChannel(discord.abc.Messageable, discord.abc.PrivateChannel, Hashable self.owner = self.me else: self.owner = utils.find(lambda u: u.id == self.owner_id, self.recipients) + self.last_pin_timestamp: Optional[datetime.datetime] = utils.parse_time(data.get('last_pin_timestamp')) async def _get_channel(self) -> Self: return self diff --git a/discord/threads.py b/discord/threads.py index daa3a4a2b..6f0e1d772 100644 --- a/discord/threads.py +++ b/discord/threads.py @@ -133,6 +133,10 @@ class Thread(Messageable, Hashable): Usually a value of 60, 1440, 4320 and 10080. archive_timestamp: :class:`datetime.datetime` An aware timestamp of when the thread's archived status was last updated in UTC. + last_pin_timestamp: Optional[:class:`datetime.datetime`] + When the last pinned message was pinned. ``None`` if no messages are currently pinned. + + .. versionadded:: 2.8 """ __slots__ = ( @@ -156,6 +160,7 @@ class Thread(Messageable, Hashable): 'auto_archive_duration', 'archive_timestamp', 'total_message_sent', + 'last_pin_timestamp', '_created_at', '_flags', '_applied_tags', @@ -190,6 +195,7 @@ class Thread(Messageable, Hashable): self.message_count: int = data['message_count'] self.member_count: int = data['member_count'] self.total_message_sent: int = data.get('total_message_sent', 0) + self.last_pin_timestamp: Optional[datetime] = parse_time(data.get('last_pin_timestamp')) self._flags: int = data.get('flags', 0) # SnowflakeList is sorted, but this would not be proper for applied tags, where order actually matters. self._applied_tags: array.array[int] = array.array('Q', map(int, data.get('applied_tags', []))) diff --git a/discord/types/channel.py b/discord/types/channel.py index f3cc680b5..d1d11cbc8 100644 --- a/discord/types/channel.py +++ b/discord/types/channel.py @@ -65,7 +65,7 @@ class PartialChannel(_BaseChannel): class _BaseTextChannel(_BaseGuildChannel, total=False): topic: str last_message_id: Optional[Snowflake] - last_pin_timestamp: str + last_pin_timestamp: NotRequired[str] rate_limit_per_user: int default_thread_rate_limit_per_user: int default_auto_archive_duration: ThreadArchiveDuration @@ -178,6 +178,7 @@ GuildChannel = Union[ class _BaseDMChannel(_BaseChannel): type: Literal[1] last_message_id: Optional[Snowflake] + last_pin_timestamp: NotRequired[str] class DMChannel(_BaseDMChannel): @@ -193,6 +194,7 @@ class GroupDMChannel(_BaseChannel): icon: Optional[str] owner_id: Snowflake recipients: List[PartialUser] + last_pin_timestamp: NotRequired[str] Channel = Union[GuildChannel, DMChannel, GroupDMChannel] diff --git a/discord/types/interactions.py b/discord/types/interactions.py index 463800a90..bdb90fa68 100644 --- a/discord/types/interactions.py +++ b/discord/types/interactions.py @@ -92,6 +92,7 @@ class PartialThread(_BasePartialChannel): last_message_id: NotRequired[Optional[Snowflake]] flags: NotRequired[int] total_message_sent: int + last_pin_timestamp: NotRequired[str] class ResolvedData(TypedDict, total=False): diff --git a/discord/types/threads.py b/discord/types/threads.py index 1dce6fac1..a824886f4 100644 --- a/discord/types/threads.py +++ b/discord/types/threads.py @@ -65,7 +65,7 @@ class Thread(TypedDict): thread_metadata: ThreadMetadata member: NotRequired[ThreadMember] last_message_id: NotRequired[Optional[Snowflake]] - last_pin_timestamp: NotRequired[Optional[Snowflake]] + last_pin_timestamp: NotRequired[Optional[str]] newly_created: NotRequired[bool] flags: NotRequired[int] applied_tags: NotRequired[List[Snowflake]]