diff --git a/disnake/abc.py b/disnake/abc.py index c0a5211698..e455d1c159 100644 --- a/disnake/abc.py +++ b/disnake/abc.py @@ -889,6 +889,7 @@ async def set_permissions( send_messages_in_threads: Optional[bool] = ..., send_tts_messages: Optional[bool] = ..., send_voice_messages: Optional[bool] = ..., + set_voice_channel_status: Optional[bool] = ..., speak: Optional[bool] = ..., start_embedded_activities: Optional[bool] = ..., stream: Optional[bool] = ..., diff --git a/disnake/enums.py b/disnake/enums.py index 0597343ff7..e957c4b995 100644 --- a/disnake/enums.py +++ b/disnake/enums.py @@ -1152,6 +1152,10 @@ class Event(Enum): """Called when a `Member` changes their `VoiceState`. Represents the :func:`on_voice_state_update` event. """ + voice_channel_status_update = "voice_channel_status_update" + """Called when a voice channel status is updated. + Represents the :func:`on_voice_channel_status_update` event. + """ stage_instance_create = "stage_instance_create" """Called when a `StageInstance` is created for a `StageChannel`. Represents the :func:`on_stage_instance_create` event. diff --git a/disnake/ext/commands/base_core.py b/disnake/ext/commands/base_core.py index ef46210495..785a9d1d54 100644 --- a/disnake/ext/commands/base_core.py +++ b/disnake/ext/commands/base_core.py @@ -673,6 +673,7 @@ def default_member_permissions( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., diff --git a/disnake/ext/commands/core.py b/disnake/ext/commands/core.py index b9d49ab269..0badb50faf 100644 --- a/disnake/ext/commands/core.py +++ b/disnake/ext/commands/core.py @@ -2034,6 +2034,7 @@ def has_permissions( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., @@ -2158,6 +2159,7 @@ def bot_has_permissions( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., @@ -2260,6 +2262,7 @@ def has_guild_permissions( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., @@ -2359,6 +2362,7 @@ def bot_has_guild_permissions( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., diff --git a/disnake/permissions.py b/disnake/permissions.py index 4760f51bcf..5b5d634cc0 100644 --- a/disnake/permissions.py +++ b/disnake/permissions.py @@ -199,6 +199,7 @@ def __init__( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., @@ -582,6 +583,7 @@ def update( send_messages_in_threads: bool = ..., send_tts_messages: bool = ..., send_voice_messages: bool = ..., + set_voice_channel_status: bool = ..., speak: bool = ..., start_embedded_activities: bool = ..., stream: bool = ..., @@ -1038,6 +1040,14 @@ def send_voice_messages(self) -> int: """ return 1 << 46 + @flag_value + def set_voice_channel_status(self) -> int: + """:class:`bool`: Returns ``True`` if a user can set voice channel statuses. + + .. versionadded:: 2.10 + """ + return 1 << 48 + def _augment_from_permissions(cls): cls.VALID_NAMES = set(Permissions.VALID_FLAGS) @@ -1145,6 +1155,7 @@ class PermissionOverwrite: send_messages_in_threads: Optional[bool] send_tts_messages: Optional[bool] send_voice_messages: Optional[bool] + set_voice_channel_status: Optional[bool] speak: Optional[bool] start_embedded_activities: Optional[bool] stream: Optional[bool] @@ -1211,6 +1222,7 @@ def __init__( send_messages_in_threads: Optional[bool] = ..., send_tts_messages: Optional[bool] = ..., send_voice_messages: Optional[bool] = ..., + set_voice_channel_status: Optional[bool] = ..., speak: Optional[bool] = ..., start_embedded_activities: Optional[bool] = ..., stream: Optional[bool] = ..., @@ -1344,6 +1356,7 @@ def update( send_messages_in_threads: Optional[bool] = ..., send_tts_messages: Optional[bool] = ..., send_voice_messages: Optional[bool] = ..., + set_voice_channel_status: Optional[bool] = ..., speak: Optional[bool] = ..., start_embedded_activities: Optional[bool] = ..., stream: Optional[bool] = ..., diff --git a/disnake/state.py b/disnake/state.py index f4885513d7..a0c79e9bf4 100644 --- a/disnake/state.py +++ b/disnake/state.py @@ -1795,6 +1795,27 @@ def parse_voice_server_update(self, data: gateway.VoiceServerUpdateEvent) -> Non logging_coroutine(coro, info="Voice Protocol voice server update handler") ) + def parse_voice_channel_status_update(self, data: gateway.VoiceChannelStatusUpdate) -> None: + guild_id = int(data["guild_id"]) + guild = self._get_guild(guild_id) + + if guild is None: + _log.debug( + "VOICE_CHANNEL_STATUS_UPDATE referencing an unknown guild ID: %s. Discarding", + guild_id, + ) + return + + channel_id = int(data["id"]) + channel = guild.get_channel(channel_id) + if channel is None: + _log.debug( + "VOICE_CHANNEL_STATUS_UPDATE referencing an unknown channel ID: %s. Discarding", + channel_id, + ) + + self.dispatch("voice_channel_status_update", channel, data["status"]) + # FIXME: this should be refactored. The `GroupChannel` path will never be hit, # `raw.timestamp` exists so no need to parse it twice, and `.get_user` should be used before falling back def parse_typing_start(self, data: gateway.TypingStartEvent) -> None: diff --git a/disnake/types/gateway.py b/disnake/types/gateway.py index e2494848b7..2c754a94d4 100644 --- a/disnake/types/gateway.py +++ b/disnake/types/gateway.py @@ -639,3 +639,10 @@ class AutoModerationActionExecutionEvent(TypedDict): # https://discord.com/developers/docs/monetization/entitlements#deleted-entitlement EntitlementDelete = Entitlement + + +# https://discord.com/developers/docs/topics/gateway-events#voice-channel-status-update +class VoiceChannelStatusUpdate(TypedDict): + id: Snowflake + guild_id: Snowflake + status: Optional[str] diff --git a/docs/api/events.rst b/docs/api/events.rst index aeb441f9a3..a157f4526c 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -503,6 +503,12 @@ This section documents events related to Discord channels and threads. :param channel: The channel that had its webhooks updated. :type channel: :class:`abc.GuildChannel` +.. function:: on_voice_channel_status_update(channel, status) + + Called whenever a channel status is modified. + + This requires :attr:`Intents.` to be enabled. + Guilds ~~~~~~