Skip to content

Commit

Permalink
feat: Add support for voice channel status
Browse files Browse the repository at this point in the history
  • Loading branch information
mccoderpy committed Sep 3, 2023
1 parent 288173e commit c34a462
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 2 deletions.
35 changes: 34 additions & 1 deletion discord/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,11 @@ class VoiceChannel(VocalGuildChannel, abc.Messageable):
.. versionadded:: 2.0
"""

__slots__ = ('last_message_id',)
__slots__ = ('last_message_id', '_status')

def __init__(self, *, state: ConnectionState, guild: Guild, data: VoiceChannelData) -> None:
super().__init__(state=state, guild=guild, data=data)
self._status: Optional[str] = data.get('status')

def __repr__(self) -> str:
attrs = [
Expand All @@ -1840,6 +1844,11 @@ def type(self) -> ChannelType:
""":class:`ChannelType`: The channel's Discord type."""
return ChannelType.voice

@property
def status(self) -> Optional[str]:
"""Optional[:class:`str`]: The current channel "status" (0-500 characters) if any."""
return self._status

@utils.copy_doc(abc.GuildChannel.clone)
async def clone(self, *, name: Optional[str] = None, reason: Optional[str] = None) -> VoiceChannel:
return await self._clone_impl({
Expand Down Expand Up @@ -1911,6 +1920,30 @@ async def edit(self, *, reason: Optional[str] = None, **options):

await self._edit(options, reason=reason)

# TODO: Add/remove this when we got a statement from Discord why bots can't set the channel status
# async def set_status(self, status: Optional[str], reason: Optional[str] = None) -> None:
# """|coro|
#
# Sets the channels status (for example the current conversation topic or game being played).
# This requires being connected to the voice channel.
#
# Parameters
# ----------
# status: Optional[:class:`str`]
# The new status of the channel. Pass ``None`` to remove the status.
# reason: Optional[:class:`str`] = None
# The reason for editing this channel. Shows up on the audit log.
#
# Raises
# ------
# Forbidden
# You do not have permissions to edit the channel.
# HTTPException
# Editing the channel status failed.
# """
#
# await self._state.http.set_voice_channel_status(self.id, status=status, reason=reason)


class StageChannel(VocalGuildChannel, abc.Messageable):
"""Represents a Discord guild stage channel.
Expand Down
9 changes: 8 additions & 1 deletion discord/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,8 @@ class AuditLogAction(Enum):
onboarding_update = 167
server_guide_create = 190
server_guide_update = 191
voice_channel_status_update = 192
voice_channel_status_clear = 193

@property
def category(self):
Expand Down Expand Up @@ -932,6 +934,8 @@ def category(self):
AuditLogAction.onboarding_update: AuditLogActionCategory.update,
AuditLogAction.server_guide_create: AuditLogActionCategory.create,
AuditLogAction.server_guide_update: AuditLogActionCategory.update,
AuditLogAction.voice_channel_status_update: AuditLogActionCategory.update,
AuditLogAction.voice_channel_status_clear: AuditLogActionCategory.delete,
}
return lookup[self]

Expand Down Expand Up @@ -978,8 +982,11 @@ def target_type(self):
return 'onboarding_question'
elif v < 168:
return 'onboarding'
elif 189 < v < 200:
elif 189 < v < 192:
return 'server_guide'
elif v < 194:
return 'voice_channel_status'



class UserFlags(Enum):
Expand Down
13 changes: 13 additions & 0 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,19 @@ def edit_stage_instance(self, channel_id, topic, privacy_level=None, *, reason=N
def delete_stage_instance(self, channel_id, *, reason=None):
return self.request(Route('DELETE', '/stage-instances/{channel_id}', channel_id=channel_id), reason=reason)

# TODO: Add/remove this when we got a statement from Discord why bots can't set the channel status
# def set_voice_channel_status(
# self,
# channel_id: int,
# status: Optional[str],
# reason: Optional[str] = None
# ):
# return self.request(
# Route('PUT', '/channels/{channel_id}/voice-status', channel_id=channel_id),
# json={'status': status},
# reason=reason
# )

# Webhook management

def create_webhook(self, channel_id, *, name, avatar=None, reason=None):
Expand Down
8 changes: 8 additions & 0 deletions discord/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,13 @@ def send_voice_messages(self):
.. versionadded:: 2.0"""
return 1 << 46

@flag_value
def set_voice_channel_status(self):
""":class:`bool`: Returns ``True`` if a user can set the status of a voice channel.
.. versionadded:: 2.0"""
return 1 << 48


def augment_from_permissions(cls):
cls.VALID_NAMES = set(Permissions.VALID_FLAGS)
Expand Down Expand Up @@ -763,6 +770,7 @@ class PermissionOverwrite:
use_soundboard: Optional[bool]
use_external_sounds: Optional[bool]
send_voice_messages: Optional[bool]
set_voice_channel_status: Optional[bool]

def __init__(self, **kwargs: Optional[bool]) -> None:
self._values = {}
Expand Down
19 changes: 19 additions & 0 deletions discord/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,25 @@ def parse_voice_channel_effect_send(self, data: gw.VoiceChannelEffectSendEvent):
else:
log.debug('VOICE_CHANNEL_EFFECT_SEND referencing an unknown guild ID: %s. Discarding.', data['guild_id'])

def parse_voice_channel_status_update(self, data):
guild = self._get_guild(int(data['guild_id']))
if guild is not None:
channel = guild.get_channel(int(data['id']))
if channel is not None:
before = copy.copy(channel.status)
channel._status = status = data['status']
self.dispatch('voice_channel_status_update', channel, before, status)
else:
log.debug(
'VOICE_CHANNEL_STATUS_UPDATE referencing an unknown channel ID: %s. Discarding.',
data['channel_id']
)
else:
log.debug(
'VOICE_CHANNEL_STATUS_UPDATE referencing an unknown guild ID: %s. Discarding.',
data['guild_id']
)

def parse_message_reaction_add(self, data):
emoji = data['emoji']
emoji_id = utils._get_as_snowflake(emoji, 'id')
Expand Down
1 change: 1 addition & 0 deletions discord/types/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class VoiceChannel(GuildChannel, total=False):
nsfw: bool
icon_emoji: Optional[PartialEmoji]
rtc_region: Optional[str]
status: Optional[str]


class StageChannel(VoiceChannel, total=False):
Expand Down
13 changes: 13 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,19 @@ to handle it, which defaults to print a traceback and ignoring the exception.
:param after: The voice state after the changes.
:type after: :class:`VoiceState`

.. function:: on_voice_channel_status_update(channel, before, after)

Called when the :attr:`~discord.VoiceChannel.status` gets changed by a member or cleared by discord automatically.

.. versionadded:: 2.0

:param channel: The voice channel that had its status updated.
:type channel: :class:`VoiceChannel`
:param before: The voice channel's old status.
:type before: :class:`str`
:param after: The voice channel's new status.
:type after: :class:`str`

.. function:: on_member_ban(guild, user)

Called when user gets banned from a :class:`Guild`.
Expand Down

0 comments on commit c34a462

Please sign in to comment.