Added on_raw_typing event
				
					
				
			This commit is contained in:
		@@ -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
 | 
				
			||||||
~~~~~~~~~~~~~~~~~~~~~~~
 | 
					~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user