mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-18 15:06:07 +00:00
Add raw presence update evemt
This commit is contained in:
parent
afbbc07e98
commit
418a7915e6
@ -72,6 +72,7 @@ from .automod import *
|
|||||||
from .poll import *
|
from .poll import *
|
||||||
from .soundboard import *
|
from .soundboard import *
|
||||||
from .subscription import *
|
from .subscription import *
|
||||||
|
from .presences import *
|
||||||
|
|
||||||
|
|
||||||
class VersionInfo(NamedTuple):
|
class VersionInfo(NamedTuple):
|
||||||
|
@ -237,6 +237,15 @@ class Client:
|
|||||||
To enable these events, this must be set to ``True``. Defaults to ``False``.
|
To enable these events, this must be set to ``True``. Defaults to ``False``.
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
|
enable_raw_presences: :class:`bool`
|
||||||
|
Whether to manually enable or disable the :func:`on_raw_presence_update` event.
|
||||||
|
|
||||||
|
Setting this flag to ``True`` requires :attr:`Intents.presences` to be enabled.
|
||||||
|
|
||||||
|
By default, this flag is set to ``True`` only when :attr:`Intents.presences` is enabled and :attr:`Intents.members`
|
||||||
|
is disabled, otherwise it's set to ``False``.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
http_trace: :class:`aiohttp.TraceConfig`
|
http_trace: :class:`aiohttp.TraceConfig`
|
||||||
The trace configuration to use for tracking HTTP requests the library does using ``aiohttp``.
|
The trace configuration to use for tracking HTTP requests the library does using ``aiohttp``.
|
||||||
This allows you to check requests the library is using. For more information, check the
|
This allows you to check requests the library is using. For more information, check the
|
||||||
|
@ -95,7 +95,7 @@ from .welcome_screen import WelcomeScreen, WelcomeChannel
|
|||||||
from .automod import AutoModRule, AutoModTrigger, AutoModRuleAction
|
from .automod import AutoModRule, AutoModTrigger, AutoModRuleAction
|
||||||
from .partial_emoji import _EmojiTag, PartialEmoji
|
from .partial_emoji import _EmojiTag, PartialEmoji
|
||||||
from .soundboard import SoundboardSound
|
from .soundboard import SoundboardSound
|
||||||
|
from .presences import RawPresenceUpdateEvent
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Guild',
|
'Guild',
|
||||||
@ -653,10 +653,11 @@ class Guild(Hashable):
|
|||||||
|
|
||||||
empty_tuple = ()
|
empty_tuple = ()
|
||||||
for presence in guild.get('presences', []):
|
for presence in guild.get('presences', []):
|
||||||
user_id = int(presence['user']['id'])
|
raw_presence = RawPresenceUpdateEvent(data=presence, state=self._state)
|
||||||
member = self.get_member(user_id)
|
member = self.get_member(raw_presence.user_id)
|
||||||
|
|
||||||
if member is not None:
|
if member is not None:
|
||||||
member._presence_update(presence, empty_tuple) # type: ignore
|
member._presence_update(raw_presence, empty_tuple) # type: ignore
|
||||||
|
|
||||||
if 'threads' in guild:
|
if 'threads' in guild:
|
||||||
threads = guild['threads']
|
threads = guild['threads']
|
||||||
|
@ -36,13 +36,13 @@ from . import utils
|
|||||||
from .asset import Asset
|
from .asset import Asset
|
||||||
from .utils import MISSING
|
from .utils import MISSING
|
||||||
from .user import BaseUser, ClientUser, User, _UserTag
|
from .user import BaseUser, ClientUser, User, _UserTag
|
||||||
from .activity import create_activity, ActivityTypes
|
|
||||||
from .permissions import Permissions
|
from .permissions import Permissions
|
||||||
from .enums import Status, try_enum
|
from .enums import Status
|
||||||
from .errors import ClientException
|
from .errors import ClientException
|
||||||
from .colour import Colour
|
from .colour import Colour
|
||||||
from .object import Object
|
from .object import Object
|
||||||
from .flags import MemberFlags
|
from .flags import MemberFlags
|
||||||
|
from .presences import ClientStatus
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'VoiceState',
|
'VoiceState',
|
||||||
@ -57,10 +57,8 @@ if TYPE_CHECKING:
|
|||||||
from .channel import DMChannel, VoiceChannel, StageChannel
|
from .channel import DMChannel, VoiceChannel, StageChannel
|
||||||
from .flags import PublicUserFlags
|
from .flags import PublicUserFlags
|
||||||
from .guild import Guild
|
from .guild import Guild
|
||||||
from .types.activity import (
|
from .activity import ActivityTypes
|
||||||
ClientStatus as ClientStatusPayload,
|
from .presences import RawPresenceUpdateEvent
|
||||||
PartialPresenceUpdate,
|
|
||||||
)
|
|
||||||
from .types.member import (
|
from .types.member import (
|
||||||
MemberWithUser as MemberWithUserPayload,
|
MemberWithUser as MemberWithUserPayload,
|
||||||
Member as MemberPayload,
|
Member as MemberPayload,
|
||||||
@ -168,46 +166,6 @@ class VoiceState:
|
|||||||
return f'<{self.__class__.__name__} {inner}>'
|
return f'<{self.__class__.__name__} {inner}>'
|
||||||
|
|
||||||
|
|
||||||
class _ClientStatus:
|
|
||||||
__slots__ = ('_status', 'desktop', 'mobile', 'web')
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self._status: str = 'offline'
|
|
||||||
|
|
||||||
self.desktop: Optional[str] = None
|
|
||||||
self.mobile: Optional[str] = None
|
|
||||||
self.web: Optional[str] = None
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
attrs = [
|
|
||||||
('_status', self._status),
|
|
||||||
('desktop', self.desktop),
|
|
||||||
('mobile', self.mobile),
|
|
||||||
('web', self.web),
|
|
||||||
]
|
|
||||||
inner = ' '.join('%s=%r' % t for t in attrs)
|
|
||||||
return f'<{self.__class__.__name__} {inner}>'
|
|
||||||
|
|
||||||
def _update(self, status: str, data: ClientStatusPayload, /) -> None:
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
self.desktop = data.get('desktop')
|
|
||||||
self.mobile = data.get('mobile')
|
|
||||||
self.web = data.get('web')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _copy(cls, client_status: Self, /) -> Self:
|
|
||||||
self = cls.__new__(cls) # bypass __init__
|
|
||||||
|
|
||||||
self._status = client_status._status
|
|
||||||
|
|
||||||
self.desktop = client_status.desktop
|
|
||||||
self.mobile = client_status.mobile
|
|
||||||
self.web = client_status.web
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def flatten_user(cls: T) -> T:
|
def flatten_user(cls: T) -> T:
|
||||||
for attr, value in itertools.chain(BaseUser.__dict__.items(), User.__dict__.items()):
|
for attr, value in itertools.chain(BaseUser.__dict__.items(), User.__dict__.items()):
|
||||||
# ignore private/special methods
|
# ignore private/special methods
|
||||||
@ -306,6 +264,10 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
This will be set to ``None`` or a time in the past if the user is not timed out.
|
This will be set to ``None`` or a time in the past if the user is not timed out.
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
|
client_status: :class:`ClientStatus`
|
||||||
|
Model which holds information about the status of the member on various clients/platforms via presence updates.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
@ -318,7 +280,7 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
'nick',
|
'nick',
|
||||||
'timed_out_until',
|
'timed_out_until',
|
||||||
'_permissions',
|
'_permissions',
|
||||||
'_client_status',
|
'client_status',
|
||||||
'_user',
|
'_user',
|
||||||
'_state',
|
'_state',
|
||||||
'_avatar',
|
'_avatar',
|
||||||
@ -354,7 +316,7 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
self.joined_at: Optional[datetime.datetime] = utils.parse_time(data.get('joined_at'))
|
self.joined_at: Optional[datetime.datetime] = utils.parse_time(data.get('joined_at'))
|
||||||
self.premium_since: Optional[datetime.datetime] = utils.parse_time(data.get('premium_since'))
|
self.premium_since: Optional[datetime.datetime] = utils.parse_time(data.get('premium_since'))
|
||||||
self._roles: utils.SnowflakeList = utils.SnowflakeList(map(int, data['roles']))
|
self._roles: utils.SnowflakeList = utils.SnowflakeList(map(int, data['roles']))
|
||||||
self._client_status: _ClientStatus = _ClientStatus()
|
self.client_status: ClientStatus = ClientStatus()
|
||||||
self.activities: Tuple[ActivityTypes, ...] = ()
|
self.activities: Tuple[ActivityTypes, ...] = ()
|
||||||
self.nick: Optional[str] = data.get('nick', None)
|
self.nick: Optional[str] = data.get('nick', None)
|
||||||
self.pending: bool = data.get('pending', False)
|
self.pending: bool = data.get('pending', False)
|
||||||
@ -430,7 +392,7 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
self._roles = utils.SnowflakeList(member._roles, is_sorted=True)
|
self._roles = utils.SnowflakeList(member._roles, is_sorted=True)
|
||||||
self.joined_at = member.joined_at
|
self.joined_at = member.joined_at
|
||||||
self.premium_since = member.premium_since
|
self.premium_since = member.premium_since
|
||||||
self._client_status = _ClientStatus._copy(member._client_status)
|
self.client_status = member.client_status
|
||||||
self.guild = member.guild
|
self.guild = member.guild
|
||||||
self.nick = member.nick
|
self.nick = member.nick
|
||||||
self.pending = member.pending
|
self.pending = member.pending
|
||||||
@ -473,13 +435,12 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
self._flags = data.get('flags', 0)
|
self._flags = data.get('flags', 0)
|
||||||
self._avatar_decoration_data = data.get('avatar_decoration_data')
|
self._avatar_decoration_data = data.get('avatar_decoration_data')
|
||||||
|
|
||||||
def _presence_update(self, data: PartialPresenceUpdate, user: UserPayload) -> Optional[Tuple[User, User]]:
|
def _presence_update(self, raw: RawPresenceUpdateEvent, user: UserPayload) -> Optional[Tuple[User, User]]:
|
||||||
self.activities = tuple(create_activity(d, self._state) for d in data['activities'])
|
self.activities = raw.activities
|
||||||
self._client_status._update(data['status'], data['client_status'])
|
self.client_status = raw.client_status
|
||||||
|
|
||||||
if len(user) > 1:
|
if len(user) > 1:
|
||||||
return self._update_inner_user(user)
|
return self._update_inner_user(user)
|
||||||
return None
|
|
||||||
|
|
||||||
def _update_inner_user(self, user: UserPayload) -> Optional[Tuple[User, User]]:
|
def _update_inner_user(self, user: UserPayload) -> Optional[Tuple[User, User]]:
|
||||||
u = self._user
|
u = self._user
|
||||||
@ -518,7 +479,7 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
@property
|
@property
|
||||||
def status(self) -> Status:
|
def status(self) -> Status:
|
||||||
""":class:`Status`: The member's overall status. If the value is unknown, then it will be a :class:`str` instead."""
|
""":class:`Status`: The member's overall status. If the value is unknown, then it will be a :class:`str` instead."""
|
||||||
return try_enum(Status, self._client_status._status)
|
return self.client_status.status
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def raw_status(self) -> str:
|
def raw_status(self) -> str:
|
||||||
@ -526,31 +487,36 @@ class Member(discord.abc.Messageable, _UserTag):
|
|||||||
|
|
||||||
.. versionadded:: 1.5
|
.. versionadded:: 1.5
|
||||||
"""
|
"""
|
||||||
return self._client_status._status
|
return self.client_status._status
|
||||||
|
|
||||||
@status.setter
|
@status.setter
|
||||||
def status(self, value: Status) -> None:
|
def status(self, value: Status) -> None:
|
||||||
# internal use only
|
# internal use only
|
||||||
self._client_status._status = str(value)
|
self.client_status._status = str(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mobile_status(self) -> Status:
|
def mobile_status(self) -> Status:
|
||||||
""":class:`Status`: The member's status on a mobile device, if applicable."""
|
""":class:`Status`: The member's status on a mobile device, if applicable."""
|
||||||
return try_enum(Status, self._client_status.mobile or 'offline')
|
return self.client_status.mobile_status
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def desktop_status(self) -> Status:
|
def desktop_status(self) -> Status:
|
||||||
""":class:`Status`: The member's status on the desktop client, if applicable."""
|
""":class:`Status`: The member's status on the desktop client, if applicable."""
|
||||||
return try_enum(Status, self._client_status.desktop or 'offline')
|
return self.client_status.desktop_status
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def web_status(self) -> Status:
|
def web_status(self) -> Status:
|
||||||
""":class:`Status`: The member's status on the web client, if applicable."""
|
""":class:`Status`: The member's status on the web client, if applicable."""
|
||||||
return try_enum(Status, self._client_status.web or 'offline')
|
return self.client_status.web_status
|
||||||
|
|
||||||
def is_on_mobile(self) -> bool:
|
def is_on_mobile(self) -> bool:
|
||||||
""":class:`bool`: A helper function that determines if a member is active on a mobile device."""
|
"""A helper function that determines if a member is active on a mobile device.
|
||||||
return self._client_status.mobile is not None
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
:class:`bool`
|
||||||
|
"""
|
||||||
|
return self.client_status.is_on_mobile()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def colour(self) -> Colour:
|
def colour(self) -> Colour:
|
||||||
|
150
discord/presences.py
Normal file
150
discord/presences.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
"""
|
||||||
|
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 TYPE_CHECKING, Optional, Tuple
|
||||||
|
|
||||||
|
from .activity import create_activity
|
||||||
|
from .enums import Status, try_enum
|
||||||
|
from .utils import MISSING, _get_as_snowflake, _RawReprMixin
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from .activity import ActivityTypes
|
||||||
|
from .guild import Guild
|
||||||
|
from .state import ConnectionState
|
||||||
|
from .types.activity import ClientStatus as ClientStatusPayload, PartialPresenceUpdate
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'RawPresenceUpdateEvent',
|
||||||
|
'ClientStatus',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ClientStatus:
|
||||||
|
"""Represents the :ddocs:`Client Status Object <events/gateway-events#client-status-object>` from Discord,
|
||||||
|
which holds information about the status of the user on various clients/platforms, with additional helpers.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('_status', 'desktop', 'mobile', 'web')
|
||||||
|
|
||||||
|
def __init__(self, *, status: str = MISSING, data: ClientStatusPayload = MISSING) -> None:
|
||||||
|
self._status: str = status or 'offline'
|
||||||
|
|
||||||
|
data = data or {}
|
||||||
|
self.desktop: Optional[str] = data.get('desktop')
|
||||||
|
self.mobile: Optional[str] = data.get('mobile')
|
||||||
|
self.web: Optional[str] = data.get('web')
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
attrs = [
|
||||||
|
('_status', self._status),
|
||||||
|
('desktop', self.desktop),
|
||||||
|
('mobile', self.mobile),
|
||||||
|
('web', self.web),
|
||||||
|
]
|
||||||
|
inner = ' '.join('%s=%r' % t for t in attrs)
|
||||||
|
return f'<{self.__class__.__name__} {inner}>'
|
||||||
|
|
||||||
|
def _update(self, status: str, data: ClientStatusPayload, /) -> None:
|
||||||
|
self._status = status
|
||||||
|
|
||||||
|
self.desktop = data.get('desktop')
|
||||||
|
self.mobile = data.get('mobile')
|
||||||
|
self.web = data.get('web')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _copy(cls, client_status: Self, /) -> Self:
|
||||||
|
self = cls.__new__(cls) # bypass __init__
|
||||||
|
|
||||||
|
self._status = client_status._status
|
||||||
|
|
||||||
|
self.desktop = client_status.desktop
|
||||||
|
self.mobile = client_status.mobile
|
||||||
|
self.web = client_status.web
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self) -> Status:
|
||||||
|
""":class:`Status`: The user's overall status. If the value is unknown, then it will be a :class:`str` instead."""
|
||||||
|
return try_enum(Status, self._status)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def raw_status(self) -> str:
|
||||||
|
""":class:`str`: The user's overall status as a string value."""
|
||||||
|
return self._status
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mobile_status(self) -> Status:
|
||||||
|
""":class:`Status`: The user's status on a mobile device, if applicable."""
|
||||||
|
return try_enum(Status, self.mobile or 'offline')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def desktop_status(self) -> Status:
|
||||||
|
""":class:`Status`: The user's status on the desktop client, if applicable."""
|
||||||
|
return try_enum(Status, self.desktop or 'offline')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def web_status(self) -> Status:
|
||||||
|
""":class:`Status`: The user's status on the web client, if applicable."""
|
||||||
|
return try_enum(Status, self.web or 'offline')
|
||||||
|
|
||||||
|
def is_on_mobile(self) -> bool:
|
||||||
|
""":class:`bool`: A helper function that determines if a user is active on a mobile device."""
|
||||||
|
return self.mobile is not None
|
||||||
|
|
||||||
|
|
||||||
|
class RawPresenceUpdateEvent(_RawReprMixin):
|
||||||
|
"""Represents the payload for a :func:`on_raw_presence_update` event.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
user_id: :class:`int`
|
||||||
|
The ID of the user that triggered the presence update.
|
||||||
|
guild_id: Optional[:class:`int`]
|
||||||
|
The guild ID for the users presence update. Could be ``None``.
|
||||||
|
guild: Optional[:class:`Guild`]
|
||||||
|
The guild associated with the presence update and user. Could be ``None``.
|
||||||
|
client_status: :class:`ClientStatus`
|
||||||
|
The :class:`~.ClientStatus` model which holds information about the status of the user on various clients.
|
||||||
|
activities: Tuple[Union[:class:`BaseActivity`, :class:`Spotify`]]
|
||||||
|
The activities the user is currently doing. Due to a Discord API limitation, a user's Spotify activity may not appear
|
||||||
|
if they are listening to a song with a title longer than ``128`` characters. See :issue:`1738` for more information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('user_id', 'guild_id', 'guild', 'client_status', 'activities')
|
||||||
|
|
||||||
|
def __init__(self, *, data: PartialPresenceUpdate, state: ConnectionState) -> None:
|
||||||
|
self.user_id: int = int(data['user']['id'])
|
||||||
|
self.client_status: ClientStatus = ClientStatus(status=data['status'], data=data['client_status'])
|
||||||
|
self.activities: Tuple[ActivityTypes, ...] = tuple(create_activity(d, state) for d in data['activities'])
|
||||||
|
self.guild_id: Optional[int] = _get_as_snowflake(data, 'guild_id')
|
||||||
|
self.guild: Optional[Guild] = state._get_guild(self.guild_id)
|
@ -25,10 +25,10 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from typing import TYPE_CHECKING, Literal, Optional, Set, List, Tuple, Union
|
from typing import TYPE_CHECKING, Literal, Optional, Set, List, Union
|
||||||
|
|
||||||
from .enums import ChannelType, try_enum, ReactionType
|
from .enums import ChannelType, try_enum, ReactionType
|
||||||
from .utils import _get_as_snowflake
|
from .utils import _get_as_snowflake, _RawReprMixin
|
||||||
from .app_commands import AppCommandPermissions
|
from .app_commands import AppCommandPermissions
|
||||||
from .colour import Colour
|
from .colour import Colour
|
||||||
|
|
||||||
@ -82,14 +82,6 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class _RawReprMixin:
|
|
||||||
__slots__: Tuple[str, ...] = ()
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
value = ' '.join(f'{attr}={getattr(self, attr)!r}' for attr in self.__slots__)
|
|
||||||
return f'<{self.__class__.__name__} {value}>'
|
|
||||||
|
|
||||||
|
|
||||||
class RawMessageDeleteEvent(_RawReprMixin):
|
class RawMessageDeleteEvent(_RawReprMixin):
|
||||||
"""Represents the event payload for a :func:`on_raw_message_delete` event.
|
"""Represents the event payload for a :func:`on_raw_message_delete` event.
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ from .message import Message
|
|||||||
from .channel import *
|
from .channel import *
|
||||||
from .channel import _channel_factory
|
from .channel import _channel_factory
|
||||||
from .raw_models import *
|
from .raw_models import *
|
||||||
|
from .presences import RawPresenceUpdateEvent
|
||||||
from .member import Member
|
from .member import Member
|
||||||
from .role import Role
|
from .role import Role
|
||||||
from .enums import ChannelType, try_enum, Status
|
from .enums import ChannelType, try_enum, Status
|
||||||
@ -261,6 +262,10 @@ class ConnectionState(Generic[ClientT]):
|
|||||||
if not intents.members or cache_flags._empty:
|
if not intents.members or cache_flags._empty:
|
||||||
self.store_user = self.store_user_no_intents
|
self.store_user = self.store_user_no_intents
|
||||||
|
|
||||||
|
self.raw_presence_flag: bool = options.get('enable_raw_presences', utils.MISSING)
|
||||||
|
if self.raw_presence_flag is utils.MISSING:
|
||||||
|
self.raw_presence_flag = not intents.members and intents.presences
|
||||||
|
|
||||||
self.parsers: Dict[str, Callable[[Any], None]]
|
self.parsers: Dict[str, Callable[[Any], None]]
|
||||||
self.parsers = parsers = {}
|
self.parsers = parsers = {}
|
||||||
for attr, func in inspect.getmembers(self):
|
for attr, func in inspect.getmembers(self):
|
||||||
@ -827,22 +832,24 @@ class ConnectionState(Generic[ClientT]):
|
|||||||
self.dispatch('interaction', interaction)
|
self.dispatch('interaction', interaction)
|
||||||
|
|
||||||
def parse_presence_update(self, data: gw.PresenceUpdateEvent) -> None:
|
def parse_presence_update(self, data: gw.PresenceUpdateEvent) -> None:
|
||||||
guild_id = utils._get_as_snowflake(data, 'guild_id')
|
raw = RawPresenceUpdateEvent(data=data, state=self)
|
||||||
# guild_id won't be None here
|
|
||||||
guild = self._get_guild(guild_id)
|
if self.raw_presence_flag:
|
||||||
if guild is None:
|
self.dispatch('raw_presence_update', raw)
|
||||||
_log.debug('PRESENCE_UPDATE referencing an unknown guild ID: %s. Discarding.', guild_id)
|
|
||||||
|
if raw.guild is None:
|
||||||
|
_log.debug('PRESENCE_UPDATE referencing an unknown guild ID: %s. Discarding.', raw.guild_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
user = data['user']
|
member = raw.guild.get_member(raw.user_id)
|
||||||
member_id = int(user['id'])
|
|
||||||
member = guild.get_member(member_id)
|
|
||||||
if member is None:
|
if member is None:
|
||||||
_log.debug('PRESENCE_UPDATE referencing an unknown member ID: %s. Discarding', member_id)
|
_log.debug('PRESENCE_UPDATE referencing an unknown member ID: %s. Discarding', raw.user_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
old_member = Member._copy(member)
|
old_member = Member._copy(member)
|
||||||
user_update = member._presence_update(data=data, user=user)
|
user_update = member._presence_update(raw=raw, user=data['user'])
|
||||||
|
|
||||||
if user_update:
|
if user_update:
|
||||||
self.dispatch('user_update', user_update[0], user_update[1])
|
self.dispatch('user_update', user_update[0], user_update[1])
|
||||||
|
|
||||||
@ -1430,8 +1437,10 @@ class ConnectionState(Generic[ClientT]):
|
|||||||
user = presence['user']
|
user = presence['user']
|
||||||
member_id = user['id']
|
member_id = user['id']
|
||||||
member = member_dict.get(member_id)
|
member = member_dict.get(member_id)
|
||||||
|
|
||||||
if member is not None:
|
if member is not None:
|
||||||
member._presence_update(presence, user)
|
raw_presence = RawPresenceUpdateEvent(data=presence, state=self)
|
||||||
|
member._presence_update(raw_presence, user)
|
||||||
|
|
||||||
complete = data.get('chunk_index', 0) + 1 == data.get('chunk_count')
|
complete = data.get('chunk_index', 0) + 1 == data.get('chunk_count')
|
||||||
self.process_chunk_requests(guild_id, data.get('nonce'), members, complete)
|
self.process_chunk_requests(guild_id, data.get('nonce'), members, complete)
|
||||||
|
@ -1532,3 +1532,11 @@ def _format_call_duration(duration: datetime.timedelta) -> str:
|
|||||||
formatted = f"{years} years"
|
formatted = f"{years} years"
|
||||||
|
|
||||||
return formatted
|
return formatted
|
||||||
|
|
||||||
|
|
||||||
|
class _RawReprMixin:
|
||||||
|
__slots__: Tuple[str, ...] = ()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
value = ' '.join(f'{attr}={getattr(self, attr)!r}' for attr in self.__slots__)
|
||||||
|
return f'<{self.__class__.__name__} {value}>'
|
||||||
|
39
docs/api.rst
39
docs/api.rst
@ -916,6 +916,29 @@ Members
|
|||||||
:param after: The updated member's updated info.
|
:param after: The updated member's updated info.
|
||||||
:type after: :class:`Member`
|
:type after: :class:`Member`
|
||||||
|
|
||||||
|
.. function:: on_raw_presence_update(payload)
|
||||||
|
|
||||||
|
Called when a :class:`Member` updates their presence.
|
||||||
|
|
||||||
|
This requires :attr:`Intents.presences` to be enabled.
|
||||||
|
|
||||||
|
Unlike :func:`on_presence_update`, when enabled, this is called regardless of the state of internal guild
|
||||||
|
and member caches, and **does not** provide a comparison between the previous and updated states of the :class:`Member`.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
By default, this event is only dispatched when :attr:`Intents.presences` is enabled **and** :attr:`Intents.members`
|
||||||
|
is disabled.
|
||||||
|
|
||||||
|
You can manually override this behaviour by setting the **enable_raw_presences** flag in the :class:`Client`,
|
||||||
|
however :attr:`Intents.presences` is always required for this event to work.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
|
|
||||||
|
:param payload: The raw presence update event model.
|
||||||
|
:type payload: :class:`RawPresenceUpdateEvent`
|
||||||
|
|
||||||
|
|
||||||
Messages
|
Messages
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
@ -5364,6 +5387,14 @@ RawPollVoteActionEvent
|
|||||||
.. autoclass:: RawPollVoteActionEvent()
|
.. autoclass:: RawPollVoteActionEvent()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
RawPresenceUpdateEvent
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: RawPresenceUpdateEvent
|
||||||
|
|
||||||
|
.. autoclass:: RawPresenceUpdateEvent()
|
||||||
|
:members:
|
||||||
|
|
||||||
PartialWebhookGuild
|
PartialWebhookGuild
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -5398,6 +5429,14 @@ MessageSnapshot
|
|||||||
.. autoclass:: MessageSnapshot
|
.. autoclass:: MessageSnapshot
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
ClientStatus
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: ClientStatus
|
||||||
|
|
||||||
|
.. autoclass:: ClientStatus()
|
||||||
|
:members:
|
||||||
|
|
||||||
Data Classes
|
Data Classes
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user