Merge branch 'iDevision:2.0' into 2.0

This commit is contained in:
Sengolda 2021-10-28 01:10:34 +05:30 committed by GitHub
commit 4a93653357
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 328 additions and 9 deletions

View File

@ -55,6 +55,7 @@ __all__ = (
"InteractionType", "InteractionType",
"InteractionResponseType", "InteractionResponseType",
"NSFWLevel", "NSFWLevel",
"ProtocolURL",
) )
@ -529,6 +530,7 @@ class InteractionType(Enum):
ping = 1 ping = 1
application_command = 2 application_command = 2
component = 3 component = 3
application_command_autocomplete = 4
class InteractionResponseType(Enum): class InteractionResponseType(Enum):
@ -539,6 +541,7 @@ class InteractionResponseType(Enum):
deferred_channel_message = 5 # (with source) deferred_channel_message = 5 # (with source)
deferred_message_update = 6 # for components deferred_message_update = 6 # for components
message_update = 7 # for components message_update = 7 # for components
application_command_autocomplete_result = 8
class VideoQualityMode(Enum): class VideoQualityMode(Enum):
@ -590,6 +593,74 @@ class NSFWLevel(Enum, comparable=True):
age_restricted = 3 age_restricted = 3
class ProtocolURL(Enum):
# General
home = "discord://-/channels/@me/"
nitro = "discord://-/store"
apps = "discord://-/apps" # Breaks the client on windows (Shows download links for different OS)
guild_discovery = "discord://-/guild-discovery"
guild_create = "discord://-/guilds/create"
guild_invite = "discord://-/invite/{invite_code}"
# Settings
account_settings = "discord://-/settings/account"
profile_settings = "discord://-/settings/profile-customization"
privacy_settings = "discord://-/settings/privacy-and-safety"
safety_settings = "discord://-/settings/privacy-and-safety" # Alias
authorized_apps_settings = "discord://-/settings/authorized-apps"
connections_settings = "discord://-/settings/connections"
nitro_settings = "discord://-/settings/premium" # Same as store, but inside of settings
guild_premium_subscription = "discord://-/settings/premium-guild-subscription"
subscription_settings = "discord://-/settings/subscriptions"
gift_inventory_settings = "discord://-/settings/inventory"
billing_settings = "discord://-/settings/billing"
appearance_settings = "discord://-/settings/appearance"
accessibility_settings = "discord://-/settings/accessibility"
voice_video_settings = "discord://-/settings/voice"
text_images_settings = "discord://-/settings/text"
notifications_settings = "discord://-/settings/notifications"
keybinds_settings = "discord://-/settings/keybinds"
language_settings = "discord://-/settings/locale"
windows_settings = "discord://-/settings/windows" # Doesnt work if used on wrong platform
linux_settings = "discord://-/settings/linux" # Doesnt work if used on wrong platform
streamer_mode_settings = "discord://-/settings/streamer-mode"
advanced_settings = "discord://-/settings/advanced"
activity_status_settings = "discord://-/settings/activity-status"
game_overlay_settings = "discord://-/settings/overlay"
hypesquad_settings = "discord://-/settings/hypesquad-online"
changelogs = "discord://-/settings/changelogs"
# Doesn't work if you don't have it actually activated. Just blank screen.
experiments = "discord://-/settings/experiments"
developer_options = "discord://-/settings/developer-options" # Same as experiments
hotspot_options = "discord://-/settings/hotspot-options" # Same as experiments
# Users, Guilds, and DMs
user_profile = "discord://-/users/{user_id}"
dm_channel = "discord://-/channels/@me/{channel_id}"
dm_message = "discord://-/channels/@me/{channel_id}/{message_id}"
guild_channel = "discord://-/channels/{guild_id}/{channel_id}"
guild_message = "discord://-/channels/{guild_id}/{channel_id}/{message_id}"
guild_membership_screening = "discord://-/member-verification/{guild_id}"
# Library
games_library = "discord://-/library"
library_settings = "discord://-/library/settings"
def __str__(self) -> str:
return self.value
def format(self, **kwargs: Any) -> str:
return self.value.format(**kwargs)
T = TypeVar("T") T = TypeVar("T")

View File

@ -22,11 +22,12 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations from __future__ import annotations
import asyncio
import inspect import inspect
import re import re
from datetime import timedelta from datetime import timedelta
from typing import Any, Dict, Generic, List, Literal, Optional, TYPE_CHECKING, TypeVar, Union, overload from typing import Any, Dict, Generic, List, Literal, NoReturn, Optional, TYPE_CHECKING, TypeVar, Union, overload
import discord.abc import discord.abc
import discord.utils import discord.utils
@ -155,6 +156,7 @@ class Context(discord.abc.Messageable, Generic[BotT]):
self.command_failed: bool = command_failed self.command_failed: bool = command_failed
self.current_parameter: Optional[inspect.Parameter] = current_parameter self.current_parameter: Optional[inspect.Parameter] = current_parameter
self._ignored_params: List[inspect.Parameter] = [] self._ignored_params: List[inspect.Parameter] = []
self._typing_task: Optional[asyncio.Task[NoReturn]] = None
self._state: ConnectionState = self.message._state self._state: ConnectionState = self.message._state
async def invoke(self, command: Command[CogT, P, T], /, *args: P.args, **kwargs: P.kwargs) -> T: async def invoke(self, command: Command[CogT, P, T], /, *args: P.args, **kwargs: P.kwargs) -> T:
@ -455,6 +457,10 @@ class Context(discord.abc.Messageable, Generic[BotT]):
In a normal context, it always returns a :class:`.Message` In a normal context, it always returns a :class:`.Message`
""" """
if self._typing_task is not None:
self._typing_task.cancel()
self._typing_task = None
if self.interaction is None or ( if self.interaction is None or (
self.interaction.response.responded_at is not None self.interaction.response.responded_at is not None
and discord.utils.utcnow() - self.interaction.response.responded_at >= timedelta(minutes=15) and discord.utils.utcnow() - self.interaction.response.responded_at >= timedelta(minutes=15)
@ -500,3 +506,30 @@ class Context(discord.abc.Messageable, Generic[BotT]):
self, content: Optional[str] = None, return_message: bool = True, **kwargs: Any self, content: Optional[str] = None, return_message: bool = True, **kwargs: Any
) -> Optional[Union[Message, WebhookMessage]]: ) -> Optional[Union[Message, WebhookMessage]]:
return await self.send(content, return_message=return_message, reference=self.message, **kwargs) # type: ignore return await self.send(content, return_message=return_message, reference=self.message, **kwargs) # type: ignore
async def defer(self, *, ephemeral: bool = False, trigger_typing: bool = True) -> None:
"""|coro|
Defers the Slash Command interaction if ran in a slash command **or**
Loops triggering ``Bot is typing`` in the channel if run in a message command.
Parameters
------------
trigger_typing: :class:`bool`
Indicates whether to trigger typing in a message command.
ephemeral: :class:`bool`
Indicates whether the deferred message will eventually be ephemeral in a slash command.
"""
if self.interaction is None:
if self._typing_task is None and trigger_typing:
async def typing_task():
while True:
await self.trigger_typing()
await asyncio.sleep(10)
self._typing_task = self.bot.loop.create_task(typing_task())
else:
await self.interaction.response.defer(ephemeral=ephemeral)

View File

@ -1264,9 +1264,10 @@ class Command(_BaseCommand, Generic[CogT, P, T]):
annotation = str annotation = str
origin = None origin = None
if not required and origin is not None and len(annotation.__args__) == 2: if not required and origin is Union and annotation.__args__[-1] is type(None):
# Unpack Optional[T] (Union[T, None]) into just T # Unpack Optional[T] (Union[T, None]) into just T
annotation, origin = annotation.__args__[0], None annotation = annotation.__args__[0]
origin = getattr(annotation, "__origin__", None)
option: Dict[str, Any] = { option: Dict[str, Any] = {
"type": 3, "type": 3,

View File

@ -51,6 +51,7 @@ if TYPE_CHECKING:
from .types.interactions import ( from .types.interactions import (
Interaction as InteractionPayload, Interaction as InteractionPayload,
ApplicationCommandOptionChoice,
InteractionData, InteractionData,
) )
from .guild import Guild from .guild import Guild
@ -632,6 +633,43 @@ class InteractionResponse:
self.responded_at = utils.utcnow() self.responded_at = utils.utcnow()
async def autocomplete_result(self, choices: List[ApplicationCommandOptionChoice]):
"""|coro|
Responds to this autocomplete interaction with the resulting choices.
This should rarely be used.
Parameters
-----------
choices: List[Dict[:class:`str`, :class:`str`]]
The choices to be shown in the autocomplete UI of the user.
Must be a list of dictionaries with the ``name`` and ``value`` keys.
Raises
-------
HTTPException
Responding to the interaction failed.
InteractionResponded
This interaction has already been responded to before.
"""
if self.is_done():
raise InteractionResponded(self._parent)
parent = self._parent
if parent.type is not InteractionType.application_command_autocomplete:
return
adapter = async_context.get()
await adapter.create_interaction_response(
parent.id,
parent.token,
session=parent._session,
type=InteractionResponseType.application_command_autocomplete_result.value,
data={"choices": choices},
)
self.responded_at = utils.utcnow()
class _InteractionMessageState: class _InteractionMessageState:
__slots__ = ("_parent", "_interaction") __slots__ = ("_parent", "_interaction")

View File

@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from typing import Callable, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union from typing import Any, Callable, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union
import inspect import inspect
import os import os
@ -60,7 +60,7 @@ class Button(Item[V]):
The ID of the button that gets received during an interaction. The ID of the button that gets received during an interaction.
If this button is for a URL, it does not have a custom ID. If this button is for a URL, it does not have a custom ID.
url: Optional[:class:`str`] url: Optional[:class:`str`]
The URL this button sends you to. The URL this button sends you to. This param is automatically casted to :class:`str`.
disabled: :class:`bool` disabled: :class:`bool`
Whether the button is disabled or not. Whether the button is disabled or not.
label: Optional[:class:`str`] label: Optional[:class:`str`]
@ -91,7 +91,7 @@ class Button(Item[V]):
label: Optional[str] = None, label: Optional[str] = None,
disabled: bool = False, disabled: bool = False,
custom_id: Optional[str] = None, custom_id: Optional[str] = None,
url: Optional[str] = None, url: Optional[Any] = None,
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None, emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
row: Optional[int] = None, row: Optional[int] = None,
): ):
@ -117,7 +117,7 @@ class Button(Item[V]):
self._underlying = ButtonComponent._raw_construct( self._underlying = ButtonComponent._raw_construct(
type=ComponentType.button, type=ComponentType.button,
custom_id=custom_id, custom_id=custom_id,
url=url, url=str(url) if url else None,
disabled=disabled, disabled=disabled,
label=label, label=label,
style=style, style=style,

View File

@ -72,7 +72,7 @@ class Select(Item[V]):
The placeholder text that is shown if nothing is selected, if any. The placeholder text that is shown if nothing is selected, if any.
min_values: :class:`int` min_values: :class:`int`
The minimum number of items that must be chosen for this select menu. The minimum number of items that must be chosen for this select menu.
Defaults to 1 and must be between 1 and 25. Defaults to 1 and must be between 0 and 25.
max_values: :class:`int` max_values: :class:`int`
The maximum number of items that must be chosen for this select menu. The maximum number of items that must be chosen for this select menu.
Defaults to 1 and must be between 1 and 25. Defaults to 1 and must be between 1 and 25.
@ -327,7 +327,7 @@ def select(
ordering. The row number must be between 0 and 4 (i.e. zero indexed). ordering. The row number must be between 0 and 4 (i.e. zero indexed).
min_values: :class:`int` min_values: :class:`int`
The minimum number of items that must be chosen for this select menu. The minimum number of items that must be chosen for this select menu.
Defaults to 1 and must be between 1 and 25. Defaults to 1 and must be between 0 and 25.
max_values: :class:`int` max_values: :class:`int`
The maximum number of items that must be chosen for this select menu. The maximum number of items that must be chosen for this select menu.
Defaults to 1 and must be between 1 and 25. Defaults to 1 and must be between 1 and 25.

View File

@ -2656,6 +2656,182 @@ of :class:`enum.Enum`.
The guild may contain NSFW content. The guild may contain NSFW content.
.. class:: ProtocolURL
Represents the different `discord://` URLs
.. attribute:: home
The URL for the home page.
.. attribute:: nitro
The URL for the nitro page.
.. attribute:: apps
The URL for the downloads page. This breaks the client and needs it to be restarted.
.. attribute:: guild_discovery
The URL for the server discovery page.
.. attribute:: new_guild
The URL for the new server modal.
.. attribute:: guild_invite
The URL for the join server page. Needs to be formatted with `invite_code`.
.. attribute:: account_settings
The URL for the "My Account" page in settings.
.. attribute:: profile_settings
The URL for the "User Profile" page in settings.
.. attribute:: privacy_settings
The URL for the "Privacy & Safety" page in settings.
.. attribute:: safety_settings
An alias for :attr:`privacy_settings`.
.. attribute:: authorized_apps_settings
The URL for the "Authorized Apps" page in settings.
.. attribute:: connections_settings
The URL for the "Connections" page in settings.
.. attribute:: nitro_settings
The URL for the "Discord Nitro" page in settings. Same page as :attr:`nitro`, but inside of settings.
.. attribute:: guild_premium_subscription
The URL for the "Server Boost" page in settings.
.. attribute:: subscription_settings
The URL for the "Subscriptions" page in settings.
.. attribute:: gift_inventory_settings
The URL for the "Gift Inventory" page in settings.
.. attribute:: billing_settings
The URL for the "Billing" page in settings.
.. attribute:: appearance_settings
The URL for the "Appearance" page in settings.
.. attribute:: accessibility_settings
The URL for the "Accessibility" page in settings.
.. attribute:: voice_video_settings
The URL for the "Voice & Video" page in settings.
.. attribute:: test_images_settings
The URL for the "Text & Images" page in settings.
.. attribute:: notifications_settings
The URL for the "Notifications" page in settings.
.. attribute:: keybinds_settings
The URL for the "Keybinds" page in settings.
.. attribute:: language_settings
The URL for the "Language" page in settings.
.. attribute:: windows_settings
The URL for the "Windows Settings" page in settings. Leads to a blank screen if used on the wrong platform.
.. attribute:: linux_settings
The URL for the "Linux Settings" page in settings. Leads to a blank screen if used on the wrong platform.
.. attribute:: streamer_mode_settings
The URL for the "Streamer Mode" page in settings.
.. attribute:: advanced_settings
The URL for the "Advanced" page in settings.
.. attribute:: activity_status_settings
The URL for the "Activity Status" page in settings.
.. attribute:: game_overlay_settings
The URL for the "Game Overlay" page in settings.
.. attribute:: hypesquad_settings
The URL for the "Hypesquad" page in settings.
.. attribute:: changelogs
The URL for the changelogs modal.
.. attribute:: experiments
The URL for the "Experiments" page in settings. Leads to a blank screen if it isn't activated.
.. attribute:: developer_options
The URL for the "Developer Options" page in settings. Leads to a blank screen if it isn't activated.
.. attribute:: hotspot_options
The URL for the "Hotspot Options" page in settings. Leads to a blank screen if it isn't activated.
.. attribute:: user_profile
The URL for a user's profile modal. Needs to be formatted with `user_id`.
.. attribute:: dm_channel
The URL for a DM channel. Needs to be formatted with `channel_id`.
.. attribute:: dm_message
The URL for a message in a DM channel. Needs to be formatted with `channel_id` and `message_id`.
.. attribute:: guild_channel
The URL for a guild channel. Needs to be formatted with `guild_id` and `channel_id`.
.. attribute:: guild_message
The URL for a guild channel. Needs to be formatted with `guild_id`, `channel_id` and `message_id`.
.. attribute:: guild_membership_screening
The URL for a guild's membership screening page. Needs to be formatted with `guild_id`.
.. attribute:: games_library
The URL for the game library.
.. attribute:: library_settings
The URL for the library settings.
Async Iterator Async Iterator
---------------- ----------------