Skip to content

Commit

Permalink
feat: implement voice channel statuses (#2368)
Browse files Browse the repository at this point in the history
Signed-off-by: Icebluewolf <44532864+Icebluewolf@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: plun1331 <plun1331@gmail.com>
Co-authored-by: Lala Sabathil <lala@pycord.dev>
Co-authored-by: Dorukyum <53639936+Dorukyum@users.noreply.github.com>
  • Loading branch information
5 people committed Feb 28, 2024
1 parent 2276914 commit 76a3e4c
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -93,6 +93,8 @@ These changes are available on the `master` branch, but have not yet been releas
([#2342](https://github.com/Pycord-Development/pycord/pull/2342))
- Added `invitable` and `slowmode_delay` to `Thread` creation methods.
([#2350](https://github.com/Pycord-Development/pycord/pull/2350))
- Added support for voice channel statuses.
([#2368](https://github.com/Pycord-Development/pycord/pull/2368))

### Changed

Expand Down
42 changes: 42 additions & 0 deletions discord/channel.py
Expand Up @@ -1519,20 +1519,37 @@ class VoiceChannel(discord.abc.Messageable, VocalGuildChannel):
Bots and users with :attr:`~Permissions.manage_channels` or
:attr:`~Permissions.manage_messages` bypass slowmode.
.. versionadded:: 2.5
status: Optional[:class:`str`]
The channel's status, if set.
.. versionadded:: 2.5
flags: :class:`ChannelFlags`
Extra features of the channel.
.. versionadded:: 2.0
"""

def __init__(
self,
*,
state: ConnectionState,
guild: Guild,
data: VoiceChannelPayload,
):
self.status: str | None = None
super().__init__(state=state, guild=guild, data=data)

def _update(self, guild: Guild, data: VoiceChannelPayload):
super()._update(guild, data)
if data.get("status"):
self.status = data.get("status")

def __repr__(self) -> str:
attrs = [
("id", self.id),
("name", self.name),
("status", self.status),
("rtc_region", self.rtc_region),
("position", self.position),
("bitrate", self.bitrate),
Expand Down Expand Up @@ -1955,6 +1972,31 @@ async def create_activity_invite(
**kwargs,
)

async def set_status(
self, status: str | None, *, reason: str | None = None
) -> None:
"""|coro|
Sets the status of the voice channel.
You must have the :attr:`~Permissions.set_voice_channel_status` permission to use this.
Parameters
----------
status: Union[:class:`str`, None]
The new status.
reason: Optional[:class:`str`]
The reason for setting the status. Shows up on the audit log.
Raises
------
Forbidden
You do not have proper permissions to set the status.
HTTPException
Setting the status failed.
"""
await self._state.http.set_voice_channel_status(self.id, status, reason=reason)


class StageChannel(discord.abc.Messageable, VocalGuildChannel):
"""Represents a Discord guild stage channel.
Expand Down
7 changes: 7 additions & 0 deletions discord/http.py
Expand Up @@ -2185,6 +2185,13 @@ def move_member(
guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason
)

def set_voice_channel_status(
self, channel_id: Snowflake, status: str | None, *, reason: str | None = None
) -> Response[None]:
payload = {"status": status}
r = Route("PUT", "/channels/{channel_id}/voice-status", channel_id=channel_id)
return self.request(r, json=payload, reason=reason)

# Stage instance management

def get_stage_instance(
Expand Down
13 changes: 11 additions & 2 deletions discord/permissions.py
Expand Up @@ -180,7 +180,7 @@ def all(cls: type[P]) -> P:
"""A factory method that creates a :class:`Permissions` with all
permissions set to ``True``.
"""
return cls(0b11111111111111111111111111111111111111111)
return cls(0b1111111111111111111111111111111111111111111111111)

@classmethod
def all_channel(cls: type[P]) -> P:
Expand Down Expand Up @@ -250,7 +250,7 @@ def voice(cls: type[P]) -> P:
"""A factory method that creates a :class:`Permissions` with all
"Voice" permissions from the official Discord UI set to ``True``.
"""
return cls(0b00000011111100000000001100000000)
return cls(0b1000000001000000000000011111100000000001100000000)

@classmethod
def stage(cls: type[P]) -> P:
Expand Down Expand Up @@ -618,6 +618,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 member can set voice channel status.
.. versionadded:: 2.5
"""
return 1 << 48


PO = TypeVar("PO", bound="PermissionOverwrite")

Expand Down Expand Up @@ -736,6 +744,7 @@ class PermissionOverwrite:
start_embedded_activities: bool | None
moderate_members: bool | None
send_voice_messages: bool | None
set_voice_channel_status: bool | None

def __init__(self, **kwargs: bool | None):
self._values: dict[str, bool | None] = {}
Expand Down
32 changes: 32 additions & 0 deletions discord/raw_models.py
Expand Up @@ -56,6 +56,7 @@
ThreadMembersUpdateEvent,
ThreadUpdateEvent,
TypingEvent,
VoiceChannelStatusUpdateEvent,
)


Expand All @@ -75,6 +76,7 @@
"AutoModActionExecutionEvent",
"RawThreadMembersUpdateEvent",
"RawAuditLogEntryEvent",
"RawVoiceChannelStatusUpdateEvent",
)


Expand Down Expand Up @@ -441,6 +443,36 @@ def __init__(self, data: ThreadDeleteEvent) -> None:
self.data: ThreadDeleteEvent = data


class RawVoiceChannelStatusUpdateEvent(_RawReprMixin):
"""Represents the payload for an :func:`on_raw_voice_channel_status_update` event.
.. versionadded:: 2.5
Attributes
----------
id: :class:`int`
The channel ID where the voice channel status update originated from.
guild_id: :class:`int`
The guild ID where the voice channel status update originated from.
status: Optional[:class:`str`]
The new new voice channel status.
data: :class:`dict`
The raw data sent by the `gateway <https://discord.com/developers/docs/topics/gateway-events#voice-channel-status-update>`_.
"""

__slots__ = ("id", "guild_id", "status", "data")

def __init__(self, data: VoiceChannelStatusUpdateEvent) -> None:
self.id: int = int(data["id"])
self.guild_id: int = int(data["guild_id"])

try:
self.status: str | None = data["status"]
except KeyError:
self.status: str | None = None
self.data: VoiceChannelStatusUpdateEvent = data


class RawTypingEvent(_RawReprMixin):
"""Represents the payload for a :func:`on_raw_typing` event.
Expand Down
24 changes: 24 additions & 0 deletions discord/state.py
Expand Up @@ -1785,6 +1785,30 @@ def parse_voice_server_update(self, data) -> None:
)
)

def parse_voice_channel_status_update(self, data) -> None:
raw = RawVoiceChannelStatusUpdateEvent(data)
self.dispatch("raw_voice_channel_status_update", raw)
guild = self._get_guild(int(data["guild_id"]))
channel_id = int(data["id"])
if guild is not None:
channel = guild.get_channel(channel_id)
if channel is not None:
old_status = channel.status
channel.status = data.get("status", None)
self.dispatch(
"voice_channel_status_update", channel, old_status, channel.status
)
else:
_log.debug(
"VOICE_CHANNEL_STATUS_UPDATE referencing an unknown channel ID: %s. Discarding.",
channel_id,
)
else:
_log.debug(
"VOICE_CHANNEL_STATUS_UPDATE referencing unknown guild ID: %s. Discarding.",
data["guild_id"],
)

def parse_typing_start(self, data) -> None:
raw = RawTypingEvent(data)

Expand Down
1 change: 1 addition & 0 deletions discord/types/channel.py
Expand Up @@ -108,6 +108,7 @@ class NewsChannel(_BaseGuildChannel, _TextChannelOptional):
class VoiceChannel(_BaseGuildChannel):
rtc_region: NotRequired[str | None]
video_quality_mode: NotRequired[VideoQualityMode]
status: NotRequired[str | None]
type: Literal[2]
bitrate: int
user_limit: int
Expand Down
6 changes: 6 additions & 0 deletions discord/types/raw_models.py
Expand Up @@ -131,6 +131,12 @@ class MemberRemoveEvent(TypedDict):
user: User


class VoiceChannelStatusUpdateEvent(TypedDict):
id: Snowflake
guild_id: Snowflake
status: NotRequired[str]


class ThreadMembersUpdateEvent(TypedDict):
id: Snowflake
guild_id: Snowflake
Expand Down
25 changes: 25 additions & 0 deletions docs/api/events.rst
Expand Up @@ -1299,3 +1299,28 @@ Typing

:param payload: The raw typing payload.
:type payload: :class:`RawTypingEvent`


Voice Channel Status Update
---------------------------
.. function:: on_voice_channel_status_update(channel, before, after)

Called when someone updates a voice channel status.

.. versionadded:: 2.5

:param channel: The channel where the voice channel status update originated from.
:type channel: :class:`abc.GuildChannel`
:param before: The old voice channel status.
:type before: Optional[:class:`str`]
:param after: The new voice channel status.
:type after: Optional[:class:`str`]

.. function:: on_raw_voice_channel_status_update(payload)

Called when someone updates a voice channels status.

.. versionadded:: 2.5

:param payload: The raw voice channel status update payload.
:type payload: :class:`RawVoiceChannelStatusUpdateEvent`
5 changes: 5 additions & 0 deletions docs/api/models.rst
Expand Up @@ -556,6 +556,11 @@ Events
.. autoclass:: RawAuditLogEntryEvent()
:members:

.. attributetable:: RawVoiceChannelStatusUpdateEvent

.. autoclass:: RawVoiceChannelStatusUpdateEvent()
:members:



Webhooks
Expand Down

0 comments on commit 76a3e4c

Please sign in to comment.