parent
152b61aabb
commit
4055bafaa5
@ -24,6 +24,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
from typing import TYPE_CHECKING, Optional, Set, List
|
from typing import TYPE_CHECKING, Optional, Set, List
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -34,7 +35,8 @@ if TYPE_CHECKING:
|
|||||||
MessageUpdateEvent,
|
MessageUpdateEvent,
|
||||||
ReactionClearEvent,
|
ReactionClearEvent,
|
||||||
ReactionClearEmojiEvent,
|
ReactionClearEmojiEvent,
|
||||||
IntegrationDeleteEvent
|
IntegrationDeleteEvent,
|
||||||
|
TypingEvent
|
||||||
)
|
)
|
||||||
from .message import Message
|
from .message import Message
|
||||||
from .partial_emoji import PartialEmoji
|
from .partial_emoji import PartialEmoji
|
||||||
@ -49,6 +51,7 @@ __all__ = (
|
|||||||
'RawReactionClearEvent',
|
'RawReactionClearEvent',
|
||||||
'RawReactionClearEmojiEvent',
|
'RawReactionClearEmojiEvent',
|
||||||
'RawIntegrationDeleteEvent',
|
'RawIntegrationDeleteEvent',
|
||||||
|
'RawTypingEvent'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -276,3 +279,36 @@ class RawIntegrationDeleteEvent(_RawReprMixin):
|
|||||||
self.application_id: Optional[int] = int(data['application_id'])
|
self.application_id: Optional[int] = int(data['application_id'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.application_id: Optional[int] = None
|
self.application_id: Optional[int] = None
|
||||||
|
|
||||||
|
|
||||||
|
class RawTypingEvent(_RawReprMixin):
|
||||||
|
"""Represents the payload for a :func:`on_raw_typing` event.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
channel_id: :class:`int`
|
||||||
|
The channel ID where the typing originated from.
|
||||||
|
user_id: :class:`int`
|
||||||
|
The ID of the user that started typing.
|
||||||
|
when: :class:`datetime.datetime`
|
||||||
|
When the typing started as an aware datetime in UTC.
|
||||||
|
guild_id: Optional[:class:`int`]
|
||||||
|
The guild ID where the typing originated from, if applicable.
|
||||||
|
member: Optional[:class:`Member`]
|
||||||
|
The member who started typing. Only available if the member started typing in a guild.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ("channel_id", "user_id", "when", "guild_id", "member")
|
||||||
|
|
||||||
|
def __init__(self, data: TypingEvent) -> None:
|
||||||
|
self.channel_id: int = int(data['channel_id'])
|
||||||
|
self.user_id: int = int(data['user_id'])
|
||||||
|
self.when: datetime.datetime = datetime.datetime.fromtimestamp(data.get('timestamp'), tz=datetime.timezone.utc)
|
||||||
|
self.member: Optional[Member] = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.guild_id: Optional[int] = int(data['guild_id'])
|
||||||
|
except KeyError:
|
||||||
|
self.guild_id: Optional[int] = None
|
@ -1327,28 +1327,37 @@ class ConnectionState:
|
|||||||
asyncio.create_task(logging_coroutine(coro, info='Voice Protocol voice server update handler'))
|
asyncio.create_task(logging_coroutine(coro, info='Voice Protocol voice server update handler'))
|
||||||
|
|
||||||
def parse_typing_start(self, data) -> None:
|
def parse_typing_start(self, data) -> None:
|
||||||
channel, guild = self._get_guild_channel(data)
|
raw = RawTypingEvent(data)
|
||||||
if channel is not None:
|
|
||||||
member = None
|
|
||||||
user_id = utils._get_as_snowflake(data, 'user_id')
|
|
||||||
if isinstance(channel, DMChannel):
|
|
||||||
member = channel.recipient
|
|
||||||
|
|
||||||
elif isinstance(channel, (Thread, TextChannel)) and guild is not None:
|
|
||||||
# user_id won't be None
|
|
||||||
member = guild.get_member(user_id) # type: ignore
|
|
||||||
|
|
||||||
if member is None:
|
|
||||||
member_data = data.get('member')
|
member_data = data.get('member')
|
||||||
if member_data:
|
if member_data:
|
||||||
member = Member(data=member_data, state=self, guild=guild)
|
guild = self._get_guild(raw.guild_id)
|
||||||
|
if guild is not None:
|
||||||
|
raw.member = Member(data=member_data, guild=guild, state=self)
|
||||||
|
else:
|
||||||
|
raw.member = None
|
||||||
|
else:
|
||||||
|
raw.member = None
|
||||||
|
self.dispatch('raw_typing', raw)
|
||||||
|
|
||||||
|
channel, guild = self._get_guild_channel(data)
|
||||||
|
if channel is not None:
|
||||||
|
user = raw.member or self._get_typing_user(channel, raw.user_id)
|
||||||
|
|
||||||
|
if user is not None:
|
||||||
|
self.dispatch('typing', channel, user, raw.when)
|
||||||
|
|
||||||
|
def _get_typing_user(self, channel: Optional[MessageableChannel], user_id: int) -> Optional[Union[User, Member]]:
|
||||||
|
if isinstance(channel, DMChannel):
|
||||||
|
return channel.recipient
|
||||||
|
|
||||||
|
elif isinstance(channel, (Thread, TextChannel)) and channel.guild is not None:
|
||||||
|
return channel.guild.get_member(user_id) # type: ignore
|
||||||
|
|
||||||
elif isinstance(channel, GroupChannel):
|
elif isinstance(channel, GroupChannel):
|
||||||
member = utils.find(lambda x: x.id == user_id, channel.recipients)
|
return utils.find(lambda x: x.id == user_id, channel.recipients)
|
||||||
|
|
||||||
if member is not None:
|
return self.get_user(user_id)
|
||||||
timestamp = datetime.datetime.fromtimestamp(data.get('timestamp'), tz=datetime.timezone.utc)
|
|
||||||
self.dispatch('typing', channel, member, timestamp)
|
|
||||||
|
|
||||||
def _get_reaction_user(self, channel: MessageableChannel, user_id: int) -> Optional[Union[User, Member]]:
|
def _get_reaction_user(self, channel: MessageableChannel, user_id: int) -> Optional[Union[User, Member]]:
|
||||||
if isinstance(channel, TextChannel):
|
if isinstance(channel, TextChannel):
|
||||||
|
@ -85,3 +85,13 @@ class _IntegrationDeleteEventOptional(TypedDict, total=False):
|
|||||||
class IntegrationDeleteEvent(_IntegrationDeleteEventOptional):
|
class IntegrationDeleteEvent(_IntegrationDeleteEventOptional):
|
||||||
id: Snowflake
|
id: Snowflake
|
||||||
guild_id: Snowflake
|
guild_id: Snowflake
|
||||||
|
|
||||||
|
|
||||||
|
class _TypingEventOptional(TypedDict, total=False):
|
||||||
|
guild_id: Snowflake
|
||||||
|
member: Member
|
||||||
|
|
||||||
|
class TypingEvent(_TypingEventOptional):
|
||||||
|
channel_id: Snowflake
|
||||||
|
user_id: Snowflake
|
||||||
|
timestamp: int
|
19
docs/api.rst
19
docs/api.rst
@ -369,6 +369,17 @@ to handle it, which defaults to print a traceback and ignoring the exception.
|
|||||||
:param when: When the typing started as an aware datetime in UTC.
|
:param when: When the typing started as an aware datetime in UTC.
|
||||||
:type when: :class:`datetime.datetime`
|
:type when: :class:`datetime.datetime`
|
||||||
|
|
||||||
|
.. function:: on_raw_typing(payload)
|
||||||
|
|
||||||
|
Called when someone begins typing a message. Unlike :func:`on_typing`, this is
|
||||||
|
called regardless if the user can be found or not. This most often happens
|
||||||
|
when a user types in DMs.
|
||||||
|
|
||||||
|
This requires :attr:`Intents.typing` to be enabled.
|
||||||
|
|
||||||
|
:param payload: The raw typing payload.
|
||||||
|
:type payload: :class:`RawTypingEvent`
|
||||||
|
|
||||||
.. function:: on_message(message)
|
.. function:: on_message(message)
|
||||||
|
|
||||||
Called when a :class:`Message` is created and sent.
|
Called when a :class:`Message` is created and sent.
|
||||||
@ -3846,6 +3857,14 @@ GuildSticker
|
|||||||
.. autoclass:: GuildSticker()
|
.. autoclass:: GuildSticker()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
RawTypingEvent
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: RawTypingEvent
|
||||||
|
|
||||||
|
.. autoclass:: RawTypingEvent()
|
||||||
|
:members:
|
||||||
|
|
||||||
RawMessageDeleteEvent
|
RawMessageDeleteEvent
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user