mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-09 11:31:58 +00:00
Implement StageInstance
This commit is contained in:
parent
90a28d48d5
commit
9f98a9a87f
@ -55,6 +55,7 @@ from .audit_logs import *
|
|||||||
from .raw_models import *
|
from .raw_models import *
|
||||||
from .team import *
|
from .team import *
|
||||||
from .sticker import *
|
from .sticker import *
|
||||||
|
from .stage_instance import *
|
||||||
from .interactions import *
|
from .interactions import *
|
||||||
from .components import *
|
from .components import *
|
||||||
|
|
||||||
|
@ -30,11 +30,12 @@ from typing import Callable, Dict, List, Optional, TYPE_CHECKING, Union, overloa
|
|||||||
|
|
||||||
import discord.abc
|
import discord.abc
|
||||||
from .permissions import PermissionOverwrite, Permissions
|
from .permissions import PermissionOverwrite, Permissions
|
||||||
from .enums import ChannelType, try_enum, VoiceRegion, VideoQualityMode
|
from .enums import ChannelType, StagePrivacyLevel, try_enum, VoiceRegion, VideoQualityMode
|
||||||
from .mixins import Hashable
|
from .mixins import Hashable
|
||||||
from . import utils
|
from . import utils
|
||||||
from .asset import Asset
|
from .asset import Asset
|
||||||
from .errors import ClientException, NoMoreItems, InvalidArgument
|
from .errors import ClientException, NoMoreItems, InvalidArgument
|
||||||
|
from .stage_instance import StageInstance
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'TextChannel',
|
'TextChannel',
|
||||||
@ -49,7 +50,7 @@ __all__ = (
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .role import Role
|
from .role import Role
|
||||||
from .member import Member
|
from .member import Member, VoiceState
|
||||||
from .abc import Snowflake
|
from .abc import Snowflake
|
||||||
from .message import Message
|
from .message import Message
|
||||||
from .webhook import Webhook
|
from .webhook import Webhook
|
||||||
@ -611,7 +612,7 @@ class VocalGuildChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hasha
|
|||||||
return ChannelType.voice.value
|
return ChannelType.voice.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def members(self):
|
def members(self) -> List[Member]:
|
||||||
"""List[:class:`Member`]: Returns all members that are currently inside this voice channel."""
|
"""List[:class:`Member`]: Returns all members that are currently inside this voice channel."""
|
||||||
ret = []
|
ret = []
|
||||||
for user_id, state in self.guild._voice_states.items():
|
for user_id, state in self.guild._voice_states.items():
|
||||||
@ -622,7 +623,7 @@ class VocalGuildChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hasha
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def voice_states(self):
|
def voice_states(self) -> Dict[int, VoiceState]:
|
||||||
"""Returns a mapping of member IDs who have voice states in this channel.
|
"""Returns a mapping of member IDs who have voice states in this channel.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
.. versionadded:: 1.3
|
||||||
@ -640,7 +641,7 @@ class VocalGuildChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hasha
|
|||||||
return {key: value for key, value in self.guild._voice_states.items() if value.channel.id == self.id}
|
return {key: value for key, value in self.guild._voice_states.items() if value.channel.id == self.id}
|
||||||
|
|
||||||
@utils.copy_doc(discord.abc.GuildChannel.permissions_for)
|
@utils.copy_doc(discord.abc.GuildChannel.permissions_for)
|
||||||
def permissions_for(self, member):
|
def permissions_for(self, member: Union[Role, Member], /) -> Permissions:
|
||||||
base = super().permissions_for(member)
|
base = super().permissions_for(member)
|
||||||
|
|
||||||
# voice channels cannot be edited by people who can't connect to them
|
# voice channels cannot be edited by people who can't connect to them
|
||||||
@ -875,10 +876,35 @@ class StageChannel(VocalGuildChannel):
|
|||||||
self.topic = data.get('topic')
|
self.topic = data.get('topic')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def requesting_to_speak(self):
|
def requesting_to_speak(self) -> List[Member]:
|
||||||
"""List[:class:`Member`]: A list of members who are requesting to speak in the stage channel."""
|
"""List[:class:`Member`]: A list of members who are requesting to speak in the stage channel."""
|
||||||
return [member for member in self.members if member.voice.requested_to_speak_at is not None]
|
return [member for member in self.members if member.voice.requested_to_speak_at is not None]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def speakers(self) -> List[Member]:
|
||||||
|
"""List[:class:`Member`]: A list of members who have been permitted to speak in the stage channel.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return [member for member in self.members if not member.voice.suppress and member.voice.requested_to_speak_at is None]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def listeners(self) -> List[Member]:
|
||||||
|
"""List[:class:`Member`]: A list of members who are listening in the stage channel.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return [member for member in self.members if member.voice.suppress]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def moderators(self) -> List[Member]:
|
||||||
|
"""List[:class:`Member`]: A list of members who are moderating the stage channel.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
required_permissions = Permissions.stage_moderator()
|
||||||
|
return [member for member in self.members if self.permissions_for(member) >= required_permissions]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
""":class:`ChannelType`: The channel's Discord type."""
|
""":class:`ChannelType`: The channel's Discord type."""
|
||||||
@ -886,9 +912,83 @@ class StageChannel(VocalGuildChannel):
|
|||||||
|
|
||||||
@utils.copy_doc(discord.abc.GuildChannel.clone)
|
@utils.copy_doc(discord.abc.GuildChannel.clone)
|
||||||
async def clone(self, *, name: str = None, reason: Optional[str] = None) -> StageChannel:
|
async def clone(self, *, name: str = None, reason: Optional[str] = None) -> StageChannel:
|
||||||
return await self._clone_impl({
|
return await self._clone_impl({}, name=name, reason=reason)
|
||||||
'topic': self.topic,
|
|
||||||
}, name=name, reason=reason)
|
@property
|
||||||
|
def instance(self) -> Optional[StageInstance]:
|
||||||
|
"""Optional[:class:`StageInstance`]: The running stage instance of the stage channel.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return utils.get(self.guild.stage_instances, channel_id=self.id)
|
||||||
|
|
||||||
|
async def create_instance(self, *, topic: str, privacy_level: StagePrivacyLevel = utils.MISSING) -> StageInstance:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Create a stage instance.
|
||||||
|
|
||||||
|
You must have the :attr:`~Permissions.manage_channels` permission to
|
||||||
|
use this.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
topic: :class:`str`
|
||||||
|
The stage instance's topic.
|
||||||
|
privacy_level: :class:`StagePrivacyLevel`
|
||||||
|
The stage instance's privacy level. Defaults to :attr:`PrivacyLevel.guild_only`.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
InvalidArgument
|
||||||
|
If the ``privacy_level`` parameter is not the proper type.
|
||||||
|
Forbidden
|
||||||
|
You do not have permissions to create a stage instance.
|
||||||
|
HTTPException
|
||||||
|
Creating a stage instance failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`StageInstance`
|
||||||
|
The newly created stage instance.
|
||||||
|
"""
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'channel_id': self.id,
|
||||||
|
'topic': topic
|
||||||
|
}
|
||||||
|
|
||||||
|
if privacy_level is not utils.MISSING:
|
||||||
|
if not isinstance(privacy_level, StagePrivacyLevel):
|
||||||
|
raise InvalidArgument('privacy_level field must be of type PrivacyLevel')
|
||||||
|
|
||||||
|
payload['privacy_level'] = privacy_level.value
|
||||||
|
|
||||||
|
data = await self._state.http.create_stage_instance(**payload)
|
||||||
|
return StageInstance(guild=self.guild, state=self._state, data=data)
|
||||||
|
|
||||||
|
async def fetch_instance(self) -> StageInstance:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Gets the running :class:`StageInstance`.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
:exc:`.NotFound`
|
||||||
|
The stage instance or channel could not be found.
|
||||||
|
:exc:`.HTTPException`
|
||||||
|
Getting the stage instance failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`StageInstance`
|
||||||
|
The stage instance.
|
||||||
|
"""
|
||||||
|
data = await self._state.http.get_stage_instance(self.id)
|
||||||
|
return StageInstance(guild=self.guild, state=self._state, data=data)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
async def edit(
|
async def edit(
|
||||||
@ -918,12 +1018,13 @@ class StageChannel(VocalGuildChannel):
|
|||||||
You must have the :attr:`~Permissions.manage_channels` permission to
|
You must have the :attr:`~Permissions.manage_channels` permission to
|
||||||
use this.
|
use this.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.0
|
||||||
|
The ``topic`` parameter must now be set via :attr:`create_instance`.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
name: :class:`str`
|
name: :class:`str`
|
||||||
The new channel's name.
|
The new channel's name.
|
||||||
topic: Optional[:class:`str`]
|
|
||||||
The new channel's topic.
|
|
||||||
position: :class:`int`
|
position: :class:`int`
|
||||||
The new channel's position.
|
The new channel's position.
|
||||||
sync_permissions: :class:`bool`
|
sync_permissions: :class:`bool`
|
||||||
|
@ -29,7 +29,7 @@ import logging
|
|||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any, List, Optional, TYPE_CHECKING, Union
|
from typing import Any, Generator, List, Optional, TYPE_CHECKING, TypeVar, Union
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
@ -56,6 +56,7 @@ from .webhook import Webhook
|
|||||||
from .iterators import GuildIterator
|
from .iterators import GuildIterator
|
||||||
from .appinfo import AppInfo
|
from .appinfo import AppInfo
|
||||||
from .ui.view import View
|
from .ui.view import View
|
||||||
|
from .stage_instance import StageInstance
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Client',
|
'Client',
|
||||||
@ -693,6 +694,28 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
return self._connection.get_channel(id)
|
return self._connection.get_channel(id)
|
||||||
|
|
||||||
|
def get_stage_instance(self, id) -> Optional[StageInstance]:
|
||||||
|
"""Returns a stage instance with the given stage channel ID.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
id: :class:`int`
|
||||||
|
The ID to search for.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
Optional[:class:`StageInstance`]
|
||||||
|
The returns stage instance of ``None`` if not found.
|
||||||
|
"""
|
||||||
|
from .channel import StageChannel
|
||||||
|
|
||||||
|
channel = self._connection.get_channel(id)
|
||||||
|
|
||||||
|
if isinstance(channel, StageChannel):
|
||||||
|
return channel.instance
|
||||||
|
|
||||||
def get_guild(self, id):
|
def get_guild(self, id):
|
||||||
"""Returns a guild with the given ID.
|
"""Returns a guild with the given ID.
|
||||||
|
|
||||||
@ -1136,6 +1159,34 @@ class Client:
|
|||||||
data = await self.http.create_guild(name, region_value, icon)
|
data = await self.http.create_guild(name, region_value, icon)
|
||||||
return Guild(data=data, state=self._connection)
|
return Guild(data=data, state=self._connection)
|
||||||
|
|
||||||
|
async def fetch_stage_instance(self, channel_id: int) -> StageInstance:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Gets a :class:`StageInstance` for a stage channel id.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
channel_id: :class:`int`
|
||||||
|
The stage channel ID.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
:exc:`.NotFound`
|
||||||
|
The stage instance or channel could not be found.
|
||||||
|
:exc:`.HTTPException`
|
||||||
|
Getting the stage instance failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`StageInstance`
|
||||||
|
The stage instance from the stage channel ID.
|
||||||
|
"""
|
||||||
|
data = await self.http.get_stage_instance(channel_id)
|
||||||
|
guild = self.get_guild(int(data['guild_id']))
|
||||||
|
return StageInstance(guild=guild, state=self._connection, data=data) # type: ignore
|
||||||
|
|
||||||
# Invite management
|
# Invite management
|
||||||
|
|
||||||
async def fetch_invite(self, url: Union[Invite, str], *, with_counts: bool = True, with_expiration: bool = True) -> Invite:
|
async def fetch_invite(self, url: Union[Invite, str], *, with_counts: bool = True, with_expiration: bool = True) -> Invite:
|
||||||
@ -1261,7 +1312,7 @@ class Client:
|
|||||||
async def fetch_user(self, user_id):
|
async def fetch_user(self, user_id):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
Retrieves a :class:`~discord.User` based on their ID.
|
Retrieves a :class:`~discord.User` based on their ID.
|
||||||
You do not have to share any guilds with the user to get this information,
|
You do not have to share any guilds with the user to get this information,
|
||||||
however many operations do require that you do.
|
however many operations do require that you do.
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ __all__ = (
|
|||||||
'VideoQualityMode',
|
'VideoQualityMode',
|
||||||
'ComponentType',
|
'ComponentType',
|
||||||
'ButtonStyle',
|
'ButtonStyle',
|
||||||
|
'StagePrivacyLevel',
|
||||||
)
|
)
|
||||||
|
|
||||||
def _create_value_cls(name):
|
def _create_value_cls(name):
|
||||||
@ -480,6 +481,11 @@ class ButtonStyle(Enum):
|
|||||||
def __int__(self):
|
def __int__(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
class StagePrivacyLevel(Enum):
|
||||||
|
public = 1
|
||||||
|
closed = 2
|
||||||
|
guild_only = 2
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
|
||||||
def create_unknown_value(cls: Type[T], val: Any) -> T:
|
def create_unknown_value(cls: Type[T], val: Any) -> T:
|
||||||
|
@ -46,6 +46,7 @@ from .widget import Widget
|
|||||||
from .asset import Asset
|
from .asset import Asset
|
||||||
from .flags import SystemChannelFlags
|
from .flags import SystemChannelFlags
|
||||||
from .integrations import Integration, _integration_factory
|
from .integrations import Integration, _integration_factory
|
||||||
|
from .stage_instance import StageInstance
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Guild',
|
'Guild',
|
||||||
@ -182,7 +183,7 @@ class Guild(Hashable):
|
|||||||
'description', 'max_presences', 'max_members', 'max_video_channel_users',
|
'description', 'max_presences', 'max_members', 'max_video_channel_users',
|
||||||
'premium_tier', 'premium_subscription_count', '_system_channel_flags',
|
'premium_tier', 'premium_subscription_count', '_system_channel_flags',
|
||||||
'preferred_locale', '_discovery_splash', '_rules_channel_id',
|
'preferred_locale', '_discovery_splash', '_rules_channel_id',
|
||||||
'_public_updates_channel_id', 'nsfw')
|
'_public_updates_channel_id', '_stage_instances', 'nsfw')
|
||||||
|
|
||||||
_PREMIUM_GUILD_LIMITS = {
|
_PREMIUM_GUILD_LIMITS = {
|
||||||
None: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
|
None: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
|
||||||
@ -319,6 +320,11 @@ class Guild(Hashable):
|
|||||||
self._public_updates_channel_id = utils._get_as_snowflake(guild, 'public_updates_channel_id')
|
self._public_updates_channel_id = utils._get_as_snowflake(guild, 'public_updates_channel_id')
|
||||||
self.nsfw = guild.get('nsfw', False)
|
self.nsfw = guild.get('nsfw', False)
|
||||||
|
|
||||||
|
self._stage_instances = {}
|
||||||
|
for s in guild.get('stage_instances', []):
|
||||||
|
stage_instance = StageInstance(guild=self, data=s, state=state)
|
||||||
|
self._stage_instances[stage_instance.id] = stage_instance
|
||||||
|
|
||||||
cache_joined = self._state.member_cache_flags.joined
|
cache_joined = self._state.member_cache_flags.joined
|
||||||
self_id = self._state.self_id
|
self_id = self._state.self_id
|
||||||
for mdata in guild.get('members', []):
|
for mdata in guild.get('members', []):
|
||||||
@ -613,6 +619,32 @@ class Guild(Hashable):
|
|||||||
return role
|
return role
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stage_instances(self) -> List[StageInstance]:
|
||||||
|
"""List[:class:`StageInstance`]: Returns a :class:`list` of the guild's stage instances that
|
||||||
|
are currently running.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
"""
|
||||||
|
return list(self._stage_instances.values())
|
||||||
|
|
||||||
|
def get_stage_instance(self, stage_instance_id: int) -> Optional[StageInstance]:
|
||||||
|
"""Returns a stage instance with the given ID.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
stage_instance_id: :class:`int`
|
||||||
|
The ID to search for.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
Optional[:class:`StageInstance`]
|
||||||
|
The stage instance or ``None`` if not found.
|
||||||
|
"""
|
||||||
|
return self._stage_instances.get(stage_instance_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def owner(self):
|
def owner(self):
|
||||||
"""Optional[:class:`Member`]: The member that owns the guild."""
|
"""Optional[:class:`Member`]: The member that owns the guild."""
|
||||||
@ -1801,7 +1833,7 @@ class Guild(Hashable):
|
|||||||
The list of integrations that are attached to the guild.
|
The list of integrations that are attached to the guild.
|
||||||
"""
|
"""
|
||||||
data = await self._state.http.get_all_integrations(self.id)
|
data = await self._state.http.get_all_integrations(self.id)
|
||||||
|
|
||||||
def convert(d):
|
def convert(d):
|
||||||
factory, _ = _integration_factory(d['type'])
|
factory, _ = _integration_factory(d['type'])
|
||||||
if factory is None:
|
if factory is None:
|
||||||
|
@ -44,7 +44,9 @@ if TYPE_CHECKING:
|
|||||||
from .types import (
|
from .types import (
|
||||||
interactions,
|
interactions,
|
||||||
invite,
|
invite,
|
||||||
|
stage_instance,
|
||||||
)
|
)
|
||||||
|
from .types.snowflake import Snowflake
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
Response = Coroutine[Any, Any, T]
|
Response = Coroutine[Any, Any, T]
|
||||||
@ -1080,6 +1082,33 @@ class HTTPClient:
|
|||||||
def move_member(self, user_id, guild_id, channel_id, *, reason=None):
|
def move_member(self, user_id, guild_id, channel_id, *, reason=None):
|
||||||
return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason)
|
return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason)
|
||||||
|
|
||||||
|
# Stage instance management
|
||||||
|
|
||||||
|
def get_stage_instance(self, channel_id: Snowflake) -> Response[stage_instance.StageInstance]:
|
||||||
|
return self.request(Route('GET', '/stage-instances/{channel_id}', channel_id=channel_id))
|
||||||
|
|
||||||
|
def create_stage_instance(self, **payload) -> Response[stage_instance.StageInstance]:
|
||||||
|
valid_keys = (
|
||||||
|
'channel_id',
|
||||||
|
'topic',
|
||||||
|
'privacy_level',
|
||||||
|
)
|
||||||
|
payload = {k: v for k, v in payload.items() if k in valid_keys}
|
||||||
|
|
||||||
|
return self.request(Route('POST', '/stage-instances'), json=payload)
|
||||||
|
|
||||||
|
def edit_stage_instance(self, channel_id: Snowflake, **payload) -> Response[None]:
|
||||||
|
valid_keys = (
|
||||||
|
'topic',
|
||||||
|
'privacy_level',
|
||||||
|
)
|
||||||
|
payload = {k: v for k, v in payload.items() if k in valid_keys}
|
||||||
|
|
||||||
|
return self.request(Route('PATCH', '/stage-instances/{channel_id}', channel_id=channel_id), json=payload)
|
||||||
|
|
||||||
|
def delete_stage_instance(self, channel_id: Snowflake) -> Response[None]:
|
||||||
|
return self.request(Route('DELETE', '/stage-instances/{channel_id}', channel_id=channel_id))
|
||||||
|
|
||||||
# Application commands (global)
|
# Application commands (global)
|
||||||
|
|
||||||
def get_global_commands(self, application_id) -> Response[List[interactions.ApplicationCommand]]:
|
def get_global_commands(self, application_id) -> Response[List[interactions.ApplicationCommand]]:
|
||||||
|
168
discord/stage_instance.py
Normal file
168
discord/stage_instance.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
"""
|
||||||
|
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 Optional, TYPE_CHECKING
|
||||||
|
|
||||||
|
from .utils import MISSING, cached_slot_property
|
||||||
|
from .mixins import Hashable
|
||||||
|
from .errors import InvalidArgument
|
||||||
|
from .enums import StagePrivacyLevel, try_enum
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'StageInstance',
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .types.channel import StageInstance as StageInstancePayload
|
||||||
|
from .state import ConnectionState
|
||||||
|
from .channel import StageChannel
|
||||||
|
from .guild import Guild
|
||||||
|
|
||||||
|
|
||||||
|
class StageInstance(Hashable):
|
||||||
|
"""Represents a stage instance of a stage channel in a guild.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. container:: operations
|
||||||
|
|
||||||
|
.. describe:: x == y
|
||||||
|
|
||||||
|
Checks if two stagea instances are equal.
|
||||||
|
|
||||||
|
.. describe:: x != y
|
||||||
|
|
||||||
|
Checks if two stage instances are not equal.
|
||||||
|
|
||||||
|
.. describe:: hash(x)
|
||||||
|
|
||||||
|
Returns the stage instance's hash.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
id: :class:`int`
|
||||||
|
The stage instance's ID.
|
||||||
|
guild: :class:`Guild`
|
||||||
|
The guild that the stage instance is running in.
|
||||||
|
channel_id: :class:`int`
|
||||||
|
The ID of the channel that the stage instance is running in.
|
||||||
|
topic: :class:`str`
|
||||||
|
The topic of the stage instance.
|
||||||
|
privacy_level: :class:`StagePrivacyLevel`
|
||||||
|
The privacy level of the stage instance.
|
||||||
|
discoverable_disabled: :class:`bool`
|
||||||
|
Whether the stage instance is discoverable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = (
|
||||||
|
'_state',
|
||||||
|
'id',
|
||||||
|
'guild',
|
||||||
|
'channel_id',
|
||||||
|
'topic',
|
||||||
|
'privacy_level',
|
||||||
|
'discoverable_disabled',
|
||||||
|
'_cs_channel',
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *, state: ConnectionState, guild: Guild, data: StageInstancePayload) -> None:
|
||||||
|
self._state = state
|
||||||
|
self.guild = guild
|
||||||
|
self._update(data)
|
||||||
|
|
||||||
|
def _update(self, data: StageInstancePayload):
|
||||||
|
self.id: int = int(data['id'])
|
||||||
|
self.channel_id: int = int(data['channel_id'])
|
||||||
|
self.topic: str = data['topic']
|
||||||
|
self.privacy_level = try_enum(StagePrivacyLevel, data['privacy_level'])
|
||||||
|
self.discoverable_disabled = data['discoverable_disabled']
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'<StageInstance id={self.id} guild={self.guild!r} channel_id={self.channel_id} topic={self.topic!r}>'
|
||||||
|
|
||||||
|
@cached_slot_property('_cs_channel')
|
||||||
|
def channel(self) -> Optional[StageChannel]:
|
||||||
|
"""Optional[:class:`StageChannel`: The guild that stage instance is running in."""
|
||||||
|
return self._state.get_channel(self.channel_id)
|
||||||
|
|
||||||
|
def is_public(self) -> bool:
|
||||||
|
return self.privacy_level is StagePrivacyLevel.public
|
||||||
|
|
||||||
|
async def edit(self, *, topic: str = MISSING, privacy_level: StagePrivacyLevel = MISSING) -> None:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Edits the stage instance.
|
||||||
|
|
||||||
|
You must have the :attr:`~Permissions.manage_channels` permission to
|
||||||
|
use this.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
topic: :class:`str`
|
||||||
|
The stage instance's new topic.
|
||||||
|
privacy_level: :class:`StagePrivacyLevel`
|
||||||
|
The stage instance's new privacy level.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
InvalidArgument
|
||||||
|
If the ``privacy_level`` parameter is not the proper type.
|
||||||
|
Forbidden
|
||||||
|
You do not have permissions to edit the stage instance.
|
||||||
|
HTTPException
|
||||||
|
Editing a stage instance failed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
payload = {}
|
||||||
|
|
||||||
|
if topic is not MISSING:
|
||||||
|
payload['topic'] = topic
|
||||||
|
|
||||||
|
if privacy_level is not MISSING:
|
||||||
|
if not isinstance(privacy_level, StagePrivacyLevel):
|
||||||
|
raise InvalidArgument('privacy_level field must be of type PrivacyLevel')
|
||||||
|
|
||||||
|
payload['privacy_level'] = privacy_level.value
|
||||||
|
|
||||||
|
if payload:
|
||||||
|
await self._state.http.edit_stage_instance(self.channel_id, **payload)
|
||||||
|
|
||||||
|
async def delete(self) -> None:
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Deletes the stage instance.
|
||||||
|
|
||||||
|
You must have the :attr:`~Permissions.manage_channels` permission to
|
||||||
|
use this.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
Forbidden
|
||||||
|
You do not have permissions to delete the stage instance.
|
||||||
|
HTTPException
|
||||||
|
Deleting the stage instance failed.
|
||||||
|
"""
|
||||||
|
await self._state.http.delete_stage_instance(self.channel_id)
|
@ -53,6 +53,7 @@ from .object import Object
|
|||||||
from .invite import Invite
|
from .invite import Invite
|
||||||
from .interactions import Interaction
|
from .interactions import Interaction
|
||||||
from .ui.view import ViewStore
|
from .ui.view import ViewStore
|
||||||
|
from .stage_instance import StageInstance
|
||||||
|
|
||||||
class ChunkRequest:
|
class ChunkRequest:
|
||||||
def __init__(self, guild_id, loop, resolver, *, cache=True):
|
def __init__(self, guild_id, loop, resolver, *, cache=True):
|
||||||
@ -956,6 +957,40 @@ class ConnectionState:
|
|||||||
else:
|
else:
|
||||||
log.debug('WEBHOOKS_UPDATE referencing an unknown channel ID: %s. Discarding.', data['channel_id'])
|
log.debug('WEBHOOKS_UPDATE referencing an unknown channel ID: %s. Discarding.', data['channel_id'])
|
||||||
|
|
||||||
|
def parse_stage_instance_create(self, data):
|
||||||
|
guild = self._get_guild(int(data['guild_id']))
|
||||||
|
if guild is not None:
|
||||||
|
stage_instance = StageInstance(guild=guild, state=self, data=data)
|
||||||
|
guild._stage_instances[stage_instance.id] = stage_instance
|
||||||
|
self.dispatch('stage_instance_create', stage_instance)
|
||||||
|
else:
|
||||||
|
log.debug('STAGE_INSTANCE_CREATE referencing unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||||
|
|
||||||
|
def parse_stage_instance_update(self, data):
|
||||||
|
guild = self._get_guild(int(data['guild_id']))
|
||||||
|
if guild is not None:
|
||||||
|
stage_instance = guild._stage_instances.get(int(data['id']))
|
||||||
|
if stage_instance is not None:
|
||||||
|
old_stage_instance = copy.copy(stage_instance)
|
||||||
|
stage_instance._update(data)
|
||||||
|
self.dispatch('stage_instance_update', old_stage_instance, stage_instance)
|
||||||
|
else:
|
||||||
|
log.debug('STAGE_INSTANCE_UPDATE referencing unknown stage instance ID: %s. Discarding.', data['id'])
|
||||||
|
else:
|
||||||
|
log.debug('STAGE_INSTANCE_UPDATE referencing unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||||
|
|
||||||
|
def parse_stage_instance_delete(self, data):
|
||||||
|
guild = self._get_guild(int(data['guild_id']))
|
||||||
|
if guild is not None:
|
||||||
|
try:
|
||||||
|
stage_instance = guild._stage_instances.pop(int(data['id']))
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.dispatch('stage_instance_delete', stage_instance)
|
||||||
|
else:
|
||||||
|
log.debug('STAGE_INSTANCE_DELETE referencing unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||||
|
|
||||||
def parse_voice_state_update(self, data):
|
def parse_voice_state_update(self, data):
|
||||||
guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
|
guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
|
||||||
channel_id = utils._get_as_snowflake(data, 'channel_id')
|
channel_id = utils._get_as_snowflake(data, 'channel_id')
|
||||||
|
@ -89,3 +89,15 @@ class DMChannel(PartialChannel):
|
|||||||
class GroupDMChannel(DMChannel):
|
class GroupDMChannel(DMChannel):
|
||||||
icon: Optional[str]
|
icon: Optional[str]
|
||||||
owner_id: Snowflake
|
owner_id: Snowflake
|
||||||
|
|
||||||
|
|
||||||
|
PrivacyLevel = Literal[1, 2]
|
||||||
|
|
||||||
|
|
||||||
|
class StageInstance(TypedDict):
|
||||||
|
id: Snowflake
|
||||||
|
guild_id: Snowflake
|
||||||
|
channel_id: Snowflake
|
||||||
|
topic: str
|
||||||
|
privacy_level: PrivacyLevel
|
||||||
|
discoverable_disabled: bool
|
||||||
|
52
docs/api.rst
52
docs/api.rst
@ -835,6 +835,32 @@ to handle it, which defaults to print a traceback and ignoring the exception.
|
|||||||
:param after: The voice state after the changes.
|
:param after: The voice state after the changes.
|
||||||
:type after: :class:`VoiceState`
|
:type after: :class:`VoiceState`
|
||||||
|
|
||||||
|
.. function:: on_stage_instance_create(stage_instance)
|
||||||
|
on_stage_instance_delete(stage_instance)
|
||||||
|
|
||||||
|
Called when a :class:`StageInstance` is created or deleted for a :class:`StageChannel`.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
:param stage_instance: The stage instance that was created or deleted.
|
||||||
|
:type stage_instance: :class:`StageInstance`
|
||||||
|
|
||||||
|
.. function:: on_stage_instance_update(before, after)
|
||||||
|
|
||||||
|
Called when a :class:`StageInstance` is updated.
|
||||||
|
|
||||||
|
The following, but not limited to, examples illustrate when this event is called:
|
||||||
|
|
||||||
|
- The topic is changed.
|
||||||
|
- The privacy level is changed.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
:param before: The stage instance before the update.
|
||||||
|
:type before: :class:`StageInstance`
|
||||||
|
:param after: The stage instance after the update.
|
||||||
|
:type after: :class:`StageInstance`
|
||||||
|
|
||||||
.. function:: on_member_ban(guild, user)
|
.. function:: on_member_ban(guild, user)
|
||||||
|
|
||||||
Called when user gets banned from a :class:`Guild`.
|
Called when user gets banned from a :class:`Guild`.
|
||||||
@ -2120,6 +2146,23 @@ of :class:`enum.Enum`.
|
|||||||
|
|
||||||
Represents full camera video quality.
|
Represents full camera video quality.
|
||||||
|
|
||||||
|
.. class:: PrivacyLevel
|
||||||
|
|
||||||
|
Represents a stage instance's privacy level.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0
|
||||||
|
|
||||||
|
.. attribute:: public
|
||||||
|
|
||||||
|
The stage instance can be joined by external users.
|
||||||
|
|
||||||
|
.. attribute:: closed
|
||||||
|
|
||||||
|
The stage instance can only be joined by members of the guild.
|
||||||
|
|
||||||
|
.. attribute:: guild_only
|
||||||
|
|
||||||
|
Alias for :attr:`.closed`
|
||||||
|
|
||||||
Async Iterator
|
Async Iterator
|
||||||
----------------
|
----------------
|
||||||
@ -3126,6 +3169,15 @@ StageChannel
|
|||||||
:members:
|
:members:
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
|
|
||||||
|
|
||||||
|
StageInstance
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. attributetable:: StageInstance
|
||||||
|
|
||||||
|
.. autoclass:: StageInstance()
|
||||||
|
:members:
|
||||||
|
|
||||||
CategoryChannel
|
CategoryChannel
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user