From c4e5db021e966027022f7d2796d8b817f4c1acfb Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:43:32 +0200 Subject: [PATCH 01/14] implement new voice state endpoint --- disnake/http.py | 12 ++++++++++++ disnake/member.py | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/disnake/http.py b/disnake/http.py index f10cd3fdd8..9c82ca963d 100644 --- a/disnake/http.py +++ b/disnake/http.py @@ -935,6 +935,18 @@ def change_nickname( } return self.request(r, json=payload, reason=reason) + def get_my_voice_state(self, guild_id: Snowflake) -> Response[voice.GuildVoiceState]: + r = Route("GET", "/guilds/{guild_id}/voice-states/@me", guild_id=guild_id) + return self.request(r) + + def get_voice_state( + self, guild_id: Snowflake, user_id: Snowflake + ) -> Response[voice.GuildVoiceState]: + r = Route( + "GET", "/guilds/{guild_id}/voice-states/{user_id}", guild_id=guild_id, user_id=user_id + ) + return self.request(r) + def edit_my_voice_state(self, guild_id: Snowflake, payload: Dict[str, Any]) -> Response[None]: r = Route("PATCH", "/guilds/{guild_id}/voice-states/@me", guild_id=guild_id) return self.request(r, json=payload) diff --git a/disnake/member.py b/disnake/member.py index 149fc97ecc..f5bd94bcef 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1004,6 +1004,19 @@ async def edit( data = await http.edit_member(guild_id, self.id, reason=reason, **payload) return Member(data=data, guild=self.guild, state=self._state) + async def fetch_voice_state(self) -> VoiceState: + """|coro| + + Fetches the :class:`VoiceState` of the member. + + .. versionadded:: 2.10 + """ + data = await self._state.http.get_voice_state(self.guild.id, self.id) + channel_id = utils._get_as_snowflake(data, "channel_id") + + _, _, after = self.guild._update_voice_state(data, channel_id) + return after + async def request_to_speak(self) -> None: """|coro| From 980e970abb4a6ff5d42184f4f77cbf8c89c40fa5 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:12:53 +0200 Subject: [PATCH 02/14] add new voice state endpoints --- changelog/1216.feature.rst | 1 + disnake/member.py | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 changelog/1216.feature.rst diff --git a/changelog/1216.feature.rst b/changelog/1216.feature.rst new file mode 100644 index 0000000000..7fb162d1ea --- /dev/null +++ b/changelog/1216.feature.rst @@ -0,0 +1 @@ +Add :meth:`Member.fetch_voice_state` to fetch the :class:`VoiceState` of a member. diff --git a/disnake/member.py b/disnake/member.py index f5bd94bcef..6882954b1c 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1004,18 +1004,38 @@ async def edit( data = await http.edit_member(guild_id, self.id, reason=reason, **payload) return Member(data=data, guild=self.guild, state=self._state) - async def fetch_voice_state(self) -> VoiceState: + async def fetch_voice_state(self, *, cache: bool) -> VoiceState: """|coro| Fetches the :class:`VoiceState` of the member. .. versionadded:: 2.10 + + Parameters + ---------- + cache: :class:`bool` + Whether to cache the fetched voice state. + + Raises + ------ + NotFound + The member for which you tried to fetch a voice state is not + connected to a channel. + + Returns + ------- + :class:`VoiceState` + The voice state of the member. """ data = await self._state.http.get_voice_state(self.guild.id, self.id) channel_id = utils._get_as_snowflake(data, "channel_id") - _, _, after = self.guild._update_voice_state(data, channel_id) - return after + if cache: + _, _, after = self.guild._update_voice_state(data, channel_id) + return after + + channel: Optional[VocalGuildChannel] = self.guild.get_channel(channel_id) # type: ignore + return VoiceState(data=data, channel=channel) async def request_to_speak(self) -> None: """|coro| From 6cbe91be986add5423119f2db98aa5f2f68b5b20 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:07:41 +0200 Subject: [PATCH 03/14] remove unimplemented endpoint --- disnake/http.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/disnake/http.py b/disnake/http.py index 9c82ca963d..2b7d36ccd1 100644 --- a/disnake/http.py +++ b/disnake/http.py @@ -935,10 +935,6 @@ def change_nickname( } return self.request(r, json=payload, reason=reason) - def get_my_voice_state(self, guild_id: Snowflake) -> Response[voice.GuildVoiceState]: - r = Route("GET", "/guilds/{guild_id}/voice-states/@me", guild_id=guild_id) - return self.request(r) - def get_voice_state( self, guild_id: Snowflake, user_id: Snowflake ) -> Response[voice.GuildVoiceState]: From 996be0134cee7080bb6d22d89fcbeb63f182a305 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:25:27 +0200 Subject: [PATCH 04/14] Update disnake/member.py Co-authored-by: shiftinv <8530778+shiftinv@users.noreply.github.com> Signed-off-by: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> --- disnake/member.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disnake/member.py b/disnake/member.py index 6882954b1c..fc8c1cbf1c 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1020,7 +1020,7 @@ async def fetch_voice_state(self, *, cache: bool) -> VoiceState: ------ NotFound The member for which you tried to fetch a voice state is not - connected to a channel. + connected to a channel in this guild. Returns ------- From 97e37c88f709cc82863c4a5a4aa92eee441195c9 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:29:20 +0200 Subject: [PATCH 05/14] make cache default to false --- disnake/member.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/disnake/member.py b/disnake/member.py index fc8c1cbf1c..f20e907d30 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1004,7 +1004,7 @@ async def edit( data = await http.edit_member(guild_id, self.id, reason=reason, **payload) return Member(data=data, guild=self.guild, state=self._state) - async def fetch_voice_state(self, *, cache: bool) -> VoiceState: + async def fetch_voice_state(self, *, cache: bool = False) -> VoiceState: """|coro| Fetches the :class:`VoiceState` of the member. @@ -1014,7 +1014,7 @@ async def fetch_voice_state(self, *, cache: bool) -> VoiceState: Parameters ---------- cache: :class:`bool` - Whether to cache the fetched voice state. + Whether to cache the fetched voice state. Defaults to ``False``. Raises ------ From 12c1d3729113dadb9443c92e1aaed52c912b0320 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:32:19 +0200 Subject: [PATCH 06/14] add a warning about caching voice_states with the intent disabled --- disnake/member.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/disnake/member.py b/disnake/member.py index f20e907d30..ce23c8958d 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1011,6 +1011,12 @@ async def fetch_voice_state(self, *, cache: bool = False) -> VoiceState: .. versionadded:: 2.10 + .. warning:: + + If the :attr:`disnake.Intents.voice_states` is disabled caching this could lead to a memory leak. + This could happen because with the intent disabled you don't receive voice state updates, hence + the cached voice state could possibly never be removed from the cache. + Parameters ---------- cache: :class:`bool` From 58efec1e7053c1f970f0ab2d062052a60ad9fd93 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:33:48 +0100 Subject: [PATCH 07/14] Update disnake/member.py Co-authored-by: shiftinv <8530778+shiftinv@users.noreply.github.com> Signed-off-by: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> --- disnake/member.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/disnake/member.py b/disnake/member.py index ce23c8958d..faaaac61be 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1028,6 +1028,10 @@ async def fetch_voice_state(self, *, cache: bool = False) -> VoiceState: The member for which you tried to fetch a voice state is not connected to a channel in this guild. + Forbidden + You do not have permission to fetch the member's voice state. + HTTPException + Fetching the voice state failed. Returns ------- :class:`VoiceState` From c16013c758524c9e21b3335ac63e725537057945 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:40:14 +0100 Subject: [PATCH 08/14] fix: add spacing in docstrings --- disnake/member.py | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/disnake/member.py b/disnake/member.py index 70d1bd83b4..cf6d22d8c7 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1023,34 +1023,23 @@ async def edit( data = await http.edit_member(guild_id, self.id, reason=reason, **payload) return Member(data=data, guild=self.guild, state=self._state) - async def fetch_voice_state(self, *, cache: bool = False) -> VoiceState: + async def fetch_voice_state(self) -> VoiceState: """|coro| Fetches the :class:`VoiceState` of the member. .. versionadded:: 2.10 - .. warning:: - - If the :attr:`disnake.Intents.voice_states` is disabled caching this could lead to a memory leak. - This could happen because with the intent disabled you don't receive voice state updates, hence - the cached voice state could possibly never be removed from the cache. - - Parameters - ---------- - cache: :class:`bool` - Whether to cache the fetched voice state. Defaults to ``False``. - Raises ------ NotFound The member for which you tried to fetch a voice state is not connected to a channel in this guild. - Forbidden You do not have permission to fetch the member's voice state. HTTPException Fetching the voice state failed. + Returns ------- :class:`VoiceState` @@ -1058,11 +1047,6 @@ async def fetch_voice_state(self, *, cache: bool = False) -> VoiceState: """ data = await self._state.http.get_voice_state(self.guild.id, self.id) channel_id = utils._get_as_snowflake(data, "channel_id") - - if cache: - _, _, after = self.guild._update_voice_state(data, channel_id) - return after - channel: Optional[VocalGuildChannel] = self.guild.get_channel(channel_id) # type: ignore return VoiceState(data=data, channel=channel) From 6e24f3ff75d0cf74174f5b5250b60aa88ab8ced7 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:42:57 +0100 Subject: [PATCH 09/14] implement new endpoint and add new method to guild --- changelog/1216.feature.rst | 2 +- disnake/guild.py | 28 ++++++++++++++++++++++++++++ disnake/http.py | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/changelog/1216.feature.rst b/changelog/1216.feature.rst index 7fb162d1ea..b28073e2b4 100644 --- a/changelog/1216.feature.rst +++ b/changelog/1216.feature.rst @@ -1 +1 @@ -Add :meth:`Member.fetch_voice_state` to fetch the :class:`VoiceState` of a member. +Add :meth:`Guild.fetch_voice_state` to fetch the :class:`VoiceState` of a member. diff --git a/disnake/guild.py b/disnake/guild.py index 97ea1e80ac..dd80815a81 100644 --- a/disnake/guild.py +++ b/disnake/guild.py @@ -4642,6 +4642,34 @@ async def fetch_voice_regions(self) -> List[VoiceRegion]: data = await self._state.http.get_guild_voice_regions(self.id) return [VoiceRegion(data=region) for region in data] + async def fetch_voice_state(self, member_id: int) -> VoiceState: + """|coro| + + Fetches the :class:`VoiceState` of the member. + + .. versionadded:: 2.10 + + Raises + ------ + NotFound + The member for which you tried to fetch a voice state is not + connected to a channel in this guild. + Forbidden + You do not have permission to fetch the member's voice state. + HTTPException + Fetching the voice state failed. + + Returns + ------- + :class:`VoiceState` + The voice state of the member. + """ + if member_id == self.me.id: + data = await self._state.http.get_my_voice_state(self.id) + else: + data = await self._state.http.get_voice_state(self.id, member_id) + return VoiceState(data=data) + async def change_voice_state( self, *, channel: Optional[Snowflake], self_mute: bool = False, self_deaf: bool = False ) -> None: diff --git a/disnake/http.py b/disnake/http.py index c314c95752..962e95d21c 100644 --- a/disnake/http.py +++ b/disnake/http.py @@ -984,6 +984,9 @@ def change_nickname( } return self.request(r, json=payload, reason=reason) + def get_my_voice_state(self, guild_id: Snowflake) -> Response[voice.GuildVoiceState]: + return self.request(Route("GET", "/guilds/{guild_id}/voice-states/@me", guild_id=guild_id)) + def get_voice_state( self, guild_id: Snowflake, user_id: Snowflake ) -> Response[voice.GuildVoiceState]: From 39c899763b57ef9c3b7b6e0a9799215fac9341b5 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:45:14 +0100 Subject: [PATCH 10/14] feat: add channel when building voice state --- disnake/guild.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/disnake/guild.py b/disnake/guild.py index dd80815a81..c7fa2054e7 100644 --- a/disnake/guild.py +++ b/disnake/guild.py @@ -4668,7 +4668,10 @@ async def fetch_voice_state(self, member_id: int) -> VoiceState: data = await self._state.http.get_my_voice_state(self.id) else: data = await self._state.http.get_voice_state(self.id, member_id) - return VoiceState(data=data) + + channel_id = utils._get_as_snowflake(data, "channel_id") + channel: Optional[VocalGuildChannel] = self.get_channel(channel_id) # type: ignore + return VoiceState(data=data, channel=channel) async def change_voice_state( self, *, channel: Optional[Snowflake], self_mute: bool = False, self_deaf: bool = False From a719e021ab8b7adbc979338d6578b2825136e8b3 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:45:50 +0100 Subject: [PATCH 11/14] remove fetch voice state from member object --- disnake/member.py | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/disnake/member.py b/disnake/member.py index cf6d22d8c7..7ce63f8c9e 100644 --- a/disnake/member.py +++ b/disnake/member.py @@ -1023,33 +1023,6 @@ async def edit( data = await http.edit_member(guild_id, self.id, reason=reason, **payload) return Member(data=data, guild=self.guild, state=self._state) - async def fetch_voice_state(self) -> VoiceState: - """|coro| - - Fetches the :class:`VoiceState` of the member. - - .. versionadded:: 2.10 - - Raises - ------ - NotFound - The member for which you tried to fetch a voice state is not - connected to a channel in this guild. - Forbidden - You do not have permission to fetch the member's voice state. - HTTPException - Fetching the voice state failed. - - Returns - ------- - :class:`VoiceState` - The voice state of the member. - """ - data = await self._state.http.get_voice_state(self.guild.id, self.id) - channel_id = utils._get_as_snowflake(data, "channel_id") - channel: Optional[VocalGuildChannel] = self.guild.get_channel(channel_id) # type: ignore - return VoiceState(data=data, channel=channel) - async def request_to_speak(self) -> None: """|coro| From bad55a200511e8b6de2bfea8304915ce10e408d6 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:03:57 +0100 Subject: [PATCH 12/14] Update disnake/guild.py Co-authored-by: vi <8530778+shiftinv@users.noreply.github.com> Signed-off-by: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> --- disnake/guild.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/disnake/guild.py b/disnake/guild.py index 81a4d9de2d..1bc363e1e6 100644 --- a/disnake/guild.py +++ b/disnake/guild.py @@ -4676,7 +4676,11 @@ async def fetch_voice_regions(self) -> List[VoiceRegion]: async def fetch_voice_state(self, member_id: int) -> VoiceState: """|coro| - Fetches the :class:`VoiceState` of the member. + Fetches the :class:`VoiceState` of a member. + + .. note:: + + This method is an API call. For general usage, consider :attr:`Member.voice` instead. .. versionadded:: 2.10 From af9842799507e624b61dd55b58d357aecbf4f1a5 Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:04:08 +0100 Subject: [PATCH 13/14] Update disnake/guild.py Co-authored-by: vi <8530778+shiftinv@users.noreply.github.com> Signed-off-by: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> --- disnake/guild.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/disnake/guild.py b/disnake/guild.py index 1bc363e1e6..ef627405af 100644 --- a/disnake/guild.py +++ b/disnake/guild.py @@ -4684,6 +4684,11 @@ async def fetch_voice_state(self, member_id: int) -> VoiceState: .. versionadded:: 2.10 + Parameters + ---------- + member_id: :class:`int` + The ID of the member. + Raises ------ NotFound From d0d88fb4f691691756a5f43b62ac25463761217a Mon Sep 17 00:00:00 2001 From: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:04:16 +0100 Subject: [PATCH 14/14] Update disnake/guild.py Co-authored-by: vi <8530778+shiftinv@users.noreply.github.com> Signed-off-by: Snipy7374 <100313469+Snipy7374@users.noreply.github.com> --- disnake/guild.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disnake/guild.py b/disnake/guild.py index ef627405af..a0609063bf 100644 --- a/disnake/guild.py +++ b/disnake/guild.py @@ -4673,7 +4673,7 @@ async def fetch_voice_regions(self) -> List[VoiceRegion]: data = await self._state.http.get_guild_voice_regions(self.id) return [VoiceRegion(data=region) for region in data] - async def fetch_voice_state(self, member_id: int) -> VoiceState: + async def fetch_voice_state(self, member_id: int, /) -> VoiceState: """|coro| Fetches the :class:`VoiceState` of a member.