Browse Source

Split detectable applications, add new application fields

pull/10109/head
dolfies 5 months ago
parent
commit
93a56799d6
  1. 377
      discord/application.py
  2. 25
      discord/client.py
  3. 119
      discord/flags.py
  4. 2
      discord/http.py
  5. 6
      discord/profile.py
  6. 27
      discord/types/application.py
  7. 1
      discord/types/profile.py
  8. 3
      discord/utils.py
  9. 11
      docs/api.rst

377
discord/application.py

@ -50,7 +50,7 @@ from .enums import (
UserFlags, UserFlags,
try_enum, try_enum,
) )
from .flags import ApplicationDiscoveryFlags, ApplicationFlags from .flags import ApplicationDiscoveryFlags, ApplicationFlags, OverlayMethodFlags
from .mixins import Hashable from .mixins import Hashable
from .object import OLDEST_OBJECT, Object from .object import OLDEST_OBJECT, Object
from .permissions import Permissions from .permissions import Permissions
@ -83,6 +83,7 @@ if TYPE_CHECKING:
Branch as BranchPayload, Branch as BranchPayload,
Build as BuildPayload, Build as BuildPayload,
Company as CompanyPayload, Company as CompanyPayload,
DetectableApplication as DetectableApplicationPayload,
EmbeddedActivityConfig as EmbeddedActivityConfigPayload, EmbeddedActivityConfig as EmbeddedActivityConfigPayload,
EmbeddedActivityPlatform as EmbeddedActivityPlatformValues, EmbeddedActivityPlatform as EmbeddedActivityPlatformValues,
EmbeddedActivityPlatformConfig as EmbeddedActivityPlatformConfigPayload, EmbeddedActivityPlatformConfig as EmbeddedActivityPlatformConfigPayload,
@ -682,13 +683,13 @@ class ApplicationBot(User):
Attributes Attributes
----------- -----------
application: :class:`Application` application: :class:`PartialApplication`
The application that the bot is attached to. The application that the bot is attached to.
""" """
__slots__ = ('application',) __slots__ = ('application',)
def __init__(self, *, data: PartialUserPayload, state: ConnectionState, application: Application): def __init__(self, *, data: PartialUserPayload, state: ConnectionState, application: PartialApplication):
super().__init__(state=state, data=data) super().__init__(state=state, data=data)
self.application = application self.application = application
@ -852,7 +853,7 @@ class ApplicationExecutable:
The type of this attribute has changed to :class:`OperatingSystem`. The type of this attribute has changed to :class:`OperatingSystem`.
launcher: :class:`bool` launcher: :class:`bool`
Whether the executable is a launcher or not. Whether the executable is a launcher or not.
application: :class:`PartialApplication` application: Union[:class:`PartialApplication`, :class:`DetectableApplication`]
The application that the executable is for. The application that the executable is for.
""" """
@ -863,7 +864,7 @@ class ApplicationExecutable:
'application', 'application',
) )
def __init__(self, *, data: ApplicationExecutablePayload, application: PartialApplication): def __init__(self, *, data: ApplicationExecutablePayload, application: _BaseApplication):
self.name: str = data['name'] self.name: str = data['name']
self.os: OperatingSystem = OperatingSystem.from_string(data['os']) self.os: OperatingSystem = OperatingSystem.from_string(data['os'])
self.launcher: bool = data['is_launcher'] self.launcher: bool = data['is_launcher']
@ -1736,8 +1737,137 @@ class ApplicationTester(User):
await self._state.http.delete_app_whitelist(self.application.id, self.id) await self._state.http.delete_app_whitelist(self.application.id, self.id)
class PartialApplication(Hashable): class _BaseApplication(Hashable):
"""Represents a partial Application. __slots__ = (
'_state',
'id',
'name',
'aliases',
'executables',
'hook',
'overlay',
'overlay_warn',
'overlay_compatibility_hook',
'_overlay_methods',
)
def __init__(self, *, state: ConnectionState, data: DetectableApplicationPayload):
self._state: ConnectionState = state
self._update(data)
def _update(self, data: DetectableApplicationPayload) -> None:
self.id: int = int(data['id'])
self.name: str = data['name']
self.aliases: List[str] = data.get('aliases', [])
self.executables: List[ApplicationExecutable] = [
ApplicationExecutable(data=e, application=self) for e in data.get('executables', [])
]
self.hook: bool = data.get('hook', False)
self.overlay: bool = data.get('overlay', False)
self.overlay_warn: bool = data.get('overlay_warn', False)
self.overlay_compatibility_hook: bool = data.get('overlay_compatibility_hook', False)
self._overlay_methods: int = data.get('overlay_methods', 0)
async def ticket(self) -> str:
"""|coro|
Retrieves the license ticket for this application.
Raises
-------
HTTPException
Retrieving the ticket failed.
Returns
--------
:class:`str`
The ticket retrieved.
"""
state = self._state
data = await state.http.get_app_ticket(self.id)
return data['ticket']
async def entitlement_ticket(self) -> str:
"""|coro|
Retrieves the entitlement ticket for this application.
Raises
-------
HTTPException
Retrieving the ticket failed.
Returns
--------
:class:`str`
The ticket retrieved.
"""
state = self._state
data = await state.http.get_app_entitlement_ticket(self.id)
return data['ticket']
class DetectableApplication(_BaseApplication):
"""Represents a detectable application.
.. container:: operations
.. describe:: x == y
Checks if two applications are equal.
.. describe:: x != y
Checks if two applications are not equal.
.. describe:: hash(x)
Return the application's hash.
.. describe:: str(x)
Returns the application's name.
.. versionadded:: 2.1
Attributes
-------------
id: :class:`int`
The application ID.
name: :class:`str`
The application name.
hook: :class:`bool`
Whether the Discord client can hook into the application directly.
overlay: :class:`bool`
Whether the application supports the `Discord overlay <https://support.discord.com/hc/en-us/articles/217659737-Game-Overlay-101>`_.
overlay_warn: :class:`bool`
Whether the Discord overlay is known to be problematic with the application.
overlay_compatibility_hook: :class:`bool`
Whether to use the compatibility hook for the Discord overlay.
aliases: List[:class:`str`]
A list of aliases that can be used to identify the application.
executables: List[:class:`ApplicationExecutable`]
A list of executables that are the application's.
"""
__slots__ = ()
def __repr__(self) -> str:
return f'<DetectableApplication id={self.id} name={self.name!r} overlay={self.overlay}>'
@property
def created_at(self) -> datetime:
""":class:`datetime.datetime`: Returns the application's creation time in UTC."""
return utils.snowflake_time(self.id)
@property
def overlay_methods(self) -> OverlayMethodFlags:
""":class:`OverlayMethodFlags`: The overlay methods that the application supports."""
return OverlayMethodFlags._from_value(self._overlay_methods)
class PartialApplication(_BaseApplication):
"""Represents a partial application.
.. container:: operations .. container:: operations
@ -1797,8 +1927,30 @@ class PartialApplication(Hashable):
The type of application. The type of application.
tags: List[:class:`str`] tags: List[:class:`str`]
A list of tags that describe the application. A list of tags that describe the application.
hook: :class:`bool`
Whether the Discord client can hook into the application directly.
overlay: :class:`bool` overlay: :class:`bool`
Whether the application has a Discord overlay or not. Whether the application supports the `Discord overlay <https://support.discord.com/hc/en-us/articles/217659737-Game-Overlay-101>`_.
overlay_warn: :class:`bool`
Whether the Discord overlay is known to be problematic with the application.
overlay_compatibility_hook: :class:`bool`
Whether to use the compatibility hook for the Discord overlay.
verified: :class:`bool`
Whether the application is verified.
.. versionadded:: 2.1
discoverable: :class:`bool`
Whether the application is discoverable in the application directory.
.. versionadded:: 2.1
monetized: :class:`bool`
Whether the application has monetization enabled.
.. versionadded:: 2.1
storefront_available: :class:`bool`
Whether the application has public subscriptions or products available for purchase.
.. versionadded:: 2.1
guild_id: Optional[:class:`int`] guild_id: Optional[:class:`int`]
The ID of the guild the application is attached to, if any. The ID of the guild the application is attached to, if any.
primary_sku_id: Optional[:class:`int`] primary_sku_id: Optional[:class:`int`]
@ -1827,6 +1979,10 @@ class PartialApplication(Hashable):
The parameters to use for authorizing the application, if specified. The parameters to use for authorizing the application, if specified.
embedded_activity_config: Optional[:class:`EmbeddedActivityConfig`] embedded_activity_config: Optional[:class:`EmbeddedActivityConfig`]
The application's embedded activity configuration, if any. The application's embedded activity configuration, if any.
bot: Optional[:class:`User`]
The bot attached to the application, if any.
.. versionadded:: 2.1
owner: Optional[:class:`User`] owner: Optional[:class:`User`]
The application owner. This may be a team user account. The application owner. This may be a team user account.
@ -1838,7 +1994,7 @@ class PartialApplication(Hashable):
.. note:: .. note::
In almost all cases, this is not available. In almost all cases, this is not available. See :attr:`owner` instead.
""" """
__slots__ = ( __slots__ = (
@ -1864,6 +2020,10 @@ class PartialApplication(Hashable):
'overlay', 'overlay',
'overlay_warn', 'overlay_warn',
'overlay_compatibility_hook', 'overlay_compatibility_hook',
'verified',
'discoverable',
'monetized',
'storefront_available',
'aliases', 'aliases',
'developers', 'developers',
'publishers', 'publishers',
@ -1877,6 +2037,7 @@ class PartialApplication(Hashable):
'store_listing_sku_id', 'store_listing_sku_id',
'slug', 'slug',
'eula_id', 'eula_id',
'bot',
'owner', 'owner',
'team', 'team',
'_guild', '_guild',
@ -1887,23 +2048,17 @@ class PartialApplication(Hashable):
owner: Optional[User] owner: Optional[User]
team: Optional[Team] team: Optional[Team]
def __init__(self, *, state: ConnectionState, data: PartialApplicationPayload):
self._state: ConnectionState = state
self._update(data)
def __str__(self) -> str: def __str__(self) -> str:
return self.name return self.name
def _update(self, data: PartialApplicationPayload) -> None: def _update(self, data: PartialApplicationPayload) -> None:
super()._update(data)
state = self._state state = self._state
self.id: int = int(data['id'])
self.name: str = data['name']
self.description: str = data['description'] self.description: str = data['description']
self.rpc_origins: Optional[List[str]] = data.get('rpc_origins') self.rpc_origins: Optional[List[str]] = data.get('rpc_origins')
self.verify_key: str = data['verify_key'] self.verify_key: str = data['verify_key']
self.aliases: List[str] = data.get('aliases', [])
self.developers: List[Company] = [Company(data=d) for d in data.get('developers', [])] self.developers: List[Company] = [Company(data=d) for d in data.get('developers', [])]
self.publishers: List[Company] = [Company(data=d) for d in data.get('publishers', [])] self.publishers: List[Company] = [Company(data=d) for d in data.get('publishers', [])]
self.executables: List[ApplicationExecutable] = [ self.executables: List[ApplicationExecutable] = [
@ -1928,6 +2083,10 @@ class PartialApplication(Hashable):
self.overlay: bool = data.get('overlay', False) self.overlay: bool = data.get('overlay', False)
self.overlay_warn: bool = data.get('overlay_warn', False) self.overlay_warn: bool = data.get('overlay_warn', False)
self.overlay_compatibility_hook: bool = data.get('overlay_compatibility_hook', False) self.overlay_compatibility_hook: bool = data.get('overlay_compatibility_hook', False)
self.verified: bool = data.get('is_verified', False)
self.discoverable: bool = data.get('is_discoverable', False)
self.monetized: bool = data.get('is_monetized', False)
self.storefront_available: bool = data.get('storefront_available', False)
self.guild_id: Optional[int] = utils._get_as_snowflake(data, 'guild_id') self.guild_id: Optional[int] = utils._get_as_snowflake(data, 'guild_id')
self.primary_sku_id: Optional[int] = utils._get_as_snowflake(data, 'primary_sku_id') self.primary_sku_id: Optional[int] = utils._get_as_snowflake(data, 'primary_sku_id')
self.store_listing_sku_id: Optional[int] = utils._get_as_snowflake(data, 'store_listing_sku_id') self.store_listing_sku_id: Optional[int] = utils._get_as_snowflake(data, 'store_listing_sku_id')
@ -1952,16 +2111,20 @@ class PartialApplication(Hashable):
# Hacky, but I want these to be persisted # Hacky, but I want these to be persisted
existing = getattr(self, 'bot', None)
bot = data.get('bot')
self.bot: Optional[User] = state.create_user(bot) if bot else existing
existing = getattr(self, 'owner', None) existing = getattr(self, 'owner', None)
owner = data.get('owner') owner = data.get('owner')
self.owner = state.create_user(owner) if owner else existing self.owner: Optional[User] = state.create_user(owner) if owner else existing
existing = getattr(self, 'team', None) existing = getattr(self, 'team', None)
team = data.get('team') team = data.get('team')
if existing and team: if existing and team:
existing._update(team) existing._update(team)
else: else:
self.team = Team(state=state, data=team) if team else existing self.team: Optional[Team] = Team(state=state, data=team) if team else existing
if self.team and not self.owner: if self.team and not self.owner:
# We can create a team user from the team data # We can create a team user from the team data
@ -2038,12 +2201,20 @@ class PartialApplication(Hashable):
"""Optional[:class:`Guild`]: The guild linked to the application, if any and available.""" """Optional[:class:`Guild`]: The guild linked to the application, if any and available."""
return self._state._get_guild(self.guild_id) or self._guild return self._state._get_guild(self.guild_id) or self._guild
@property
def overlay_methods(self) -> OverlayMethodFlags:
""":class:`OverlayMethodFlags`: The overlay methods that the application supports.
.. versionadded:: 2.1
"""
return OverlayMethodFlags._from_value(self._overlay_methods)
def has_bot(self) -> bool: def has_bot(self) -> bool:
""":class:`bool`: Whether the application has an attached bot. """:class:`bool`: Whether the application has an attached bot.
.. versionadded:: 2.1 .. versionadded:: 2.1
""" """
return self._has_bot return self._has_bot or self.bot is not None
def is_rpc_enabled(self) -> bool: def is_rpc_enabled(self) -> bool:
""":class:`bool`: Whether the application has the ability to access the client RPC server. """:class:`bool`: Whether the application has the ability to access the client RPC server.
@ -2199,44 +2370,6 @@ class PartialApplication(Hashable):
data = await state.http.get_eula(self.eula_id) data = await state.http.get_eula(self.eula_id)
return EULA(data=data) return EULA(data=data)
async def ticket(self) -> str:
"""|coro|
Retrieves the license ticket for this application.
Raises
-------
HTTPException
Retrieving the ticket failed.
Returns
--------
:class:`str`
The ticket retrieved.
"""
state = self._state
data = await state.http.get_app_ticket(self.id)
return data['ticket']
async def entitlement_ticket(self) -> str:
"""|coro|
Retrieves the entitlement ticket for this application.
Raises
-------
HTTPException
Retrieving the ticket failed.
Returns
--------
:class:`str`
The ticket retrieved.
"""
state = self._state
data = await state.http.get_app_entitlement_ticket(self.id)
return data['ticket']
async def activity_statistics(self) -> List[ApplicationActivityStatistics]: async def activity_statistics(self) -> List[ApplicationActivityStatistics]:
"""|coro| """|coro|
@ -2283,10 +2416,104 @@ class Application(PartialApplication):
Attributes Attributes
------------- -------------
owner: :class:`User` id: :class:`int`
The application owner. This may be a team user account. The application ID.
name: :class:`str`
The application name.
description: :class:`str`
The application description.
rpc_origins: Optional[List[:class:`str`]]
A list of RPC origin URLs, if RPC is enabled.
.. versionchanged:: 2.1
The type of this attribute has changed to Optional[List[:class:`str`]].
verify_key: :class:`str`
The hex encoded key for verification in interactions and the
GameSDK's :ddocs:`GetTicket <game-sdk/applications#getticket`.
terms_of_service_url: Optional[:class:`str`]
The application's terms of service URL, if set.
privacy_policy_url: Optional[:class:`str`]
The application's privacy policy URL, if set.
deeplink_uri: Optional[:class:`str`]
The application's deeplink URI, if set.
.. versionadded:: 2.1
public: :class:`bool`
Whether the integration can be invited by anyone or if it is locked
to the application owner.
require_code_grant: :class:`bool`
Whether the integration requires the completion of the full OAuth2 code
grant flow to join
max_participants: Optional[:class:`int`]
The max number of people that can participate in the activity.
Only available for embedded activities.
type: Optional[:class:`ApplicationType`]
The type of application.
tags: List[:class:`str`]
A list of tags that describe the application.
hook: :class:`bool`
Whether the Discord client can hook into the application directly.
overlay: :class:`bool`
Whether the application supports the `Discord overlay <https://support.discord.com/hc/en-us/articles/217659737-Game-Overlay-101>`_.
overlay_warn: :class:`bool`
Whether the Discord overlay is known to be problematic with the application.
overlay_compatibility_hook: :class:`bool`
Whether to use the compatibility hook for the Discord overlay.
verified: :class:`bool`
Whether the application is verified.
.. versionadded:: 2.1
discoverable: :class:`bool`
Whether the application is discoverable in the application directory.
.. versionadded:: 2.1
monetized: :class:`bool`
Whether the application has monetization enabled.
.. versionadded:: 2.1
storefront_available: :class:`bool`
Whether the application has public subscriptions or products available for purchase.
.. versionadded:: 2.1
guild_id: Optional[:class:`int`]
The ID of the guild the application is attached to, if any.
primary_sku_id: Optional[:class:`int`]
The application's primary SKU ID, if any.
This can be an application's game SKU, subscription SKU, etc.
store_listing_sku_id: Optional[:class:`int`]
The application's store listing SKU ID, if any.
If exists, this SKU ID should be used for checks.
slug: Optional[:class:`str`]
The slug for the application's primary SKU, if any.
eula_id: Optional[:class:`int`]
The ID of the EULA for the application, if any.
aliases: List[:class:`str`]
A list of aliases that can be used to identify the application.
developers: List[:class:`Company`]
A list of developers that developed the application.
publishers: List[:class:`Company`]
A list of publishers that published the application.
executables: List[:class:`ApplicationExecutable`]
A list of executables that are the application's.
third_party_skus: List[:class:`ThirdPartySKU`]
A list of third party platforms the SKU is available at.
custom_install_url: Optional[:class:`str`]
The custom URL to use for authorizing the application, if specified.
install_params: Optional[:class:`ApplicationInstallParams`]
The parameters to use for authorizing the application, if specified.
embedded_activity_config: Optional[:class:`EmbeddedActivityConfig`]
The application's embedded activity configuration, if any.
bot: Optional[:class:`ApplicationBot`] bot: Optional[:class:`ApplicationBot`]
The bot attached to the application, if any. The bot attached to the application, if any.
owner: :class:`User`
The application owner. This may be a team user account.
team: Optional[:class:`Team`]
The team that owns the application.
.. note::
In almost all cases, this is not available. See :attr:`owner` instead.
disabled: :class:`bool` disabled: :class:`bool`
Whether the bot attached to this application is disabled by Discord. Whether the bot attached to this application is disabled by Discord.
@ -2334,7 +2561,6 @@ class Application(PartialApplication):
'interactions_version', 'interactions_version',
'interactions_event_types', 'interactions_event_types',
'role_connections_verification_url', 'role_connections_verification_url',
'bot',
'disabled', 'disabled',
'quarantined', 'quarantined',
'verification_state', 'verification_state',
@ -2371,16 +2597,15 @@ class Application(PartialApplication):
self.approximate_guild_count: int = data.get('approximate_guild_count', 0) self.approximate_guild_count: int = data.get('approximate_guild_count', 0)
state = self._state state = self._state
self.owner = self.owner or state.user
# Hacky, but I want these to be persisted # Hacky, but I want these to be persisted
existing = getattr(self, 'bot', None) existing = getattr(self, 'bot', None)
bot = data.get('bot') bot = data.get('bot')
if existing is not None: if existing and bot:
existing._update(bot) existing._update(bot)
else: else:
self.bot: Optional[ApplicationBot] = ApplicationBot(data=bot, state=state, application=self) if bot else None self.bot: Optional[ApplicationBot] = ApplicationBot(data=bot, state=state, application=self) if bot else existing
self.owner = self.owner or state.user
def __repr__(self) -> str: def __repr__(self) -> str:
return ( return (
@ -3692,6 +3917,22 @@ class IntegrationApplication(Hashable):
.. versionadded:: 2.1 .. versionadded:: 2.1
type: Optional[:class:`ApplicationType`] type: Optional[:class:`ApplicationType`]
The type of application. The type of application.
verified: :class:`bool`
Whether the application is verified.
.. versionadded:: 2.1
discoverable: :class:`bool`
Whether the application is discoverable in the application directory.
.. versionadded:: 2.1
monetized: :class:`bool`
Whether the application has monetization enabled.
.. versionadded:: 2.1
storefront_available: :class:`bool`
Whether the application has public subscriptions or products available for purchase.
.. versionadded:: 2.1
primary_sku_id: Optional[:class:`int`] primary_sku_id: Optional[:class:`int`]
The application's primary SKU ID, if any. The application's primary SKU ID, if any.
This can be an application's game SKU, subscription SKU, etc. This can be an application's game SKU, subscription SKU, etc.
@ -3712,6 +3953,10 @@ class IntegrationApplication(Hashable):
'description', 'description',
'deeplink_uri', 'deeplink_uri',
'type', 'type',
'verified',
'discoverable',
'monetized',
'storefront_available',
'primary_sku_id', 'primary_sku_id',
'role_connections_verification_url', 'role_connections_verification_url',
'third_party_skus', 'third_party_skus',
@ -3733,6 +3978,10 @@ class IntegrationApplication(Hashable):
self.description: str = data.get('description') or '' self.description: str = data.get('description') or ''
self.deeplink_uri: Optional[str] = data.get('deeplink_uri') self.deeplink_uri: Optional[str] = data.get('deeplink_uri')
self.type: Optional[ApplicationType] = try_enum(ApplicationType, data['type']) if 'type' in data else None self.type: Optional[ApplicationType] = try_enum(ApplicationType, data['type']) if 'type' in data else None
self.verified: bool = data.get('is_verified', False)
self.discoverable: bool = data.get('is_discoverable', False)
self.monetized: bool = data.get('is_monetized', False)
self.storefront_available: bool = data.get('storefront_available', False)
self._icon: Optional[str] = data.get('icon') self._icon: Optional[str] = data.get('icon')
self._cover_image: Optional[str] = data.get('cover_image') self._cover_image: Optional[str] = data.get('cover_image')

25
discord/client.py

@ -72,7 +72,15 @@ from .utils import MISSING
from .object import Object, OLDEST_OBJECT from .object import Object, OLDEST_OBJECT
from .backoff import ExponentialBackoff from .backoff import ExponentialBackoff
from .webhook import Webhook from .webhook import Webhook
from .application import Application, ApplicationActivityStatistics, Company, EULA, PartialApplication, UnverifiedApplication from .application import (
Application,
ApplicationActivityStatistics,
Company,
EULA,
DetectableApplication,
PartialApplication,
UnverifiedApplication,
)
from .stage_instance import StageInstance from .stage_instance import StageInstance
from .threads import Thread from .threads import Thread
from .sticker import GuildSticker, StandardSticker, StickerPack, _sticker_factory from .sticker import GuildSticker, StandardSticker, StickerPack, _sticker_factory
@ -369,7 +377,9 @@ class Client:
if status is None: if status is None:
status = getattr(state.settings, 'status', None) or Status.unknown status = getattr(state.settings, 'status', None) or Status.unknown
_log.debug('Setting initial presence to %s %s', status, activities) _log.debug('Setting initial presence to %s %s', status, activities)
self.loop.create_task(self.change_presence(activities=activities, status=status, edit_settings=self._sync_presences)) self.loop.create_task(
self.change_presence(activities=activities, status=status, edit_settings=self._sync_presences)
)
@property @property
def latency(self) -> float: def latency(self) -> float:
@ -3254,13 +3264,18 @@ class Client:
data = await state.http.get_my_applications(with_team_applications=with_team_applications) data = await state.http.get_my_applications(with_team_applications=with_team_applications)
return [Application(state=state, data=d) for d in data] return [Application(state=state, data=d) for d in data]
async def detectable_applications(self) -> List[PartialApplication]: async def detectable_applications(self) -> List[DetectableApplication]:
"""|coro| """|coro|
Retrieves the list of applications detectable by the Discord client. Retrieves the list of applications detectable by the Discord client.
.. versionadded:: 2.0 .. versionadded:: 2.0
.. versionchanged:: 2.1
The method now returns a list of :class:`.DetectableApplication`
instead of :class:`.PartialApplication` due to an API change.
Raises Raises
------- -------
HTTPException HTTPException
@ -3268,12 +3283,12 @@ class Client:
Returns Returns
------- -------
List[:class:`.PartialApplication`] List[:class:`.DetectableApplication`]
The applications detectable by the Discord client. The applications detectable by the Discord client.
""" """
state = self._connection state = self._connection
data = await state.http.get_detectable_applications() data = await state.http.get_detectable_applications()
return [PartialApplication(state=state, data=d) for d in data] return [DetectableApplication(state=state, data=d) for d in data]
async def fetch_application(self, application_id: int, /) -> Application: async def fetch_application(self, application_id: int, /) -> Application:
"""|coro| """|coro|

119
discord/flags.py

@ -66,6 +66,7 @@ __all__ = (
'GiftFlags', 'GiftFlags',
'LibraryApplicationFlags', 'LibraryApplicationFlags',
'ApplicationDiscoveryFlags', 'ApplicationDiscoveryFlags',
'OverlayMethodFlags',
'FriendSourceFlags', 'FriendSourceFlags',
'FriendDiscoveryFlags', 'FriendDiscoveryFlags',
'HubProgressFlags', 'HubProgressFlags',
@ -1269,15 +1270,8 @@ class ApplicationFlags(BaseFlags):
rather than using this raw value. rather than using this raw value.
""" """
# Commented-out flags are no longer used; they are kept here for historical purposes
__slots__ = () __slots__ = ()
# @flag_value
# def embedded_released(self):
# """:class:`bool`: Returns ``True`` if the embedded application is released to the public."""
# return 1 << 1
@flag_value @flag_value
def managed_emoji(self): def managed_emoji(self):
""":class:`bool`: Returns ``True`` if the application has the ability to create managed emoji.""" """:class:`bool`: Returns ``True`` if the application has the ability to create managed emoji."""
@ -1293,11 +1287,6 @@ class ApplicationFlags(BaseFlags):
""":class:`bool`: Returns ``True`` if the application has the ability to create group DMs without limit.""" """:class:`bool`: Returns ``True`` if the application has the ability to create group DMs without limit."""
return 1 << 4 return 1 << 4
# @flag_value
# def rpc_private_beta(self):
# """:class:`bool`: Returns ``True`` if the application has the ability to access the client RPC server."""
# return 1 << 5
@flag_value @flag_value
def automod_badge(self): def automod_badge(self):
""":class:`bool`: Returns ``True`` if the application has created at least 100 automod rules across all guilds. """:class:`bool`: Returns ``True`` if the application has created at least 100 automod rules across all guilds.
@ -1306,25 +1295,21 @@ class ApplicationFlags(BaseFlags):
""" """
return 1 << 6 return 1 << 6
# @flag_value @flag_value
# def allow_assets(self): def game_profile_disabled(self):
# """:class:`bool`: Returns ``True`` if the application has the ability to use activity assets.""" """:class:`bool`: Returns ``True`` if the application has its game profile page disabled.
# return 1 << 8
# @flag_value .. versionadded:: 2.1
# def allow_activity_action_spectate(self): """
# """:class:`bool`: Returns ``True`` if the application has the ability to enable spectating activities.""" return 1 << 7
# return 1 << 9
# @flag_value @flag_value
# def allow_activity_action_join_request(self): def public_oauth2_client(self):
# """:class:`bool`: Returns ``True`` if the application has the ability to enable activity join requests.""" """:class:`bool`: Returns ``True`` if the application's OAuth2 credentials are public.
# return 1 << 10
# @flag_value .. versionadded:: 2.1
# def rpc_has_connected(self): """
# """:class:`bool`: Returns ``True`` if the application has accessed the client RPC server before.""" return 1 << 8
# return 1 << 11
@flag_value @flag_value
def gateway_presence(self): def gateway_presence(self):
@ -1395,6 +1380,26 @@ class ApplicationFlags(BaseFlags):
""" """
return 1 << 24 return 1 << 24
@flag_value
def iframe_modal(self):
""":class:`bool`: Returns ``True`` if the application can use iframes within modals."""
return 1 << 26
@flag_value
def social_layer_integration(self):
""":class:`bool`: Returns ``True`` if the application can use the social layer SDK."""
return 1 << 27
@flag_value
def promoted(self):
""":class:`bool`: Returns ``True`` if the application is promoted by Discord."""
return 1 << 29
@flag_value
def partner(self):
""":class:`bool`: Returns ``True`` if the application is a Discord partner."""
return 1 << 30
@fill_with_flags() @fill_with_flags()
class ChannelFlags(BaseFlags): class ChannelFlags(BaseFlags):
@ -2088,10 +2093,62 @@ class ApplicationDiscoveryFlags(BaseFlags):
""":class:`bool`: Returns ``True`` if the application's role connections metadata is safe for work.""" """:class:`bool`: Returns ``True`` if the application's role connections metadata is safe for work."""
return 1 << 15 return 1 << 15
@fill_with_flags()
class OverlayMethodFlags(BaseFlags):
r"""Wraps up the Discord application overlay method flags.
.. container:: operations
.. describe:: x == y
Checks if two OverlayMethodFlags are equal.
.. describe:: x != y
Checks if two OverlayMethodFlags are not equal.
.. describe:: x | y, x |= y
Returns a OverlayMethodFlags instance with all enabled flags from
both x and y.
.. describe:: x & y, x &= y
Returns a OverlayMethodFlags instance with only flags enabled on
both x and y.
.. describe:: x ^ y, x ^= y
Returns a OverlayMethodFlags instance with only flags enabled on
only one of x or y, not on both.
.. describe:: ~x
Returns a OverlayMethodFlags instance with all flags inverted from x.
.. describe:: hash(x)
Return the flag's hash.
.. describe:: iter(x)
Returns an iterator of ``(name, value)`` pairs. This allows it
to be, for example, constructed as a dict or a list of pairs.
Note that aliases are not shown.
.. describe:: bool(b)
Returns whether any flag is set to ``True``.
.. versionadded:: 2.1
Attributes
-----------
value: :class:`int`
The raw value. This value is a bit array field of a 53-bit integer
representing the currently available flags. You should query
flags via the properties rather than using this raw value.
"""
__slots__ = ()
@flag_value @flag_value
def eligible(self): def out_of_process(self):
""":class:`bool`: Returns ``True`` if the application has met all the above criteria and is eligible for discovery.""" """:class:`bool`: Returns ``True`` if the overlay can be rendered out of process for this application."""
return 1 << 16 return 1 << 0
@fill_with_flags() @fill_with_flags()

2
discord/http.py

@ -3357,7 +3357,7 @@ class HTTPClient:
def reset_bot_token(self, app_id: Snowflake) -> Response[application.Token]: def reset_bot_token(self, app_id: Snowflake) -> Response[application.Token]:
return self.request(Route('POST', '/applications/{app_id}/bot/reset', app_id=app_id)) return self.request(Route('POST', '/applications/{app_id}/bot/reset', app_id=app_id))
def get_detectable_applications(self) -> Response[List[application.PartialApplication]]: def get_detectable_applications(self) -> Response[List[application.DetectableApplication]]:
return self.request(Route('GET', '/applications/detectable')) return self.request(Route('GET', '/applications/detectable'))
def get_guild_applications( def get_guild_applications(

6
discord/profile.py

@ -302,6 +302,10 @@ class ApplicationProfile(Hashable):
The application's ID. The application's ID.
verified: :class:`bool` verified: :class:`bool`
Indicates if the application is verified. Indicates if the application is verified.
storefront_available: :class:`bool`
Indicates if the application has public subscriptions or products available for purchase.
.. versionadded:: 2.1
popular_application_command_ids: List[:class:`int`] popular_application_command_ids: List[:class:`int`]
A list of the IDs of the application's popular commands. A list of the IDs of the application's popular commands.
primary_sku_id: Optional[:class:`int`] primary_sku_id: Optional[:class:`int`]
@ -316,6 +320,7 @@ class ApplicationProfile(Hashable):
__slots__ = ( __slots__ = (
'id', 'id',
'verified', 'verified',
'storefront_available',
'popular_application_command_ids', 'popular_application_command_ids',
'primary_sku_id', 'primary_sku_id',
'_flags', '_flags',
@ -326,6 +331,7 @@ class ApplicationProfile(Hashable):
def __init__(self, data: ProfileApplicationPayload) -> None: def __init__(self, data: ProfileApplicationPayload) -> None:
self.id: int = int(data['id']) self.id: int = int(data['id'])
self.verified: bool = data.get('verified', False) self.verified: bool = data.get('verified', False)
self.storefront_available: bool = data.get('storefront_available', False)
self.popular_application_command_ids: List[int] = [int(id) for id in data.get('popular_application_command_ids', [])] self.popular_application_command_ids: List[int] = [int(id) for id in data.get('popular_application_command_ids', [])]
self.primary_sku_id: Optional[int] = utils._get_as_snowflake(data, 'primary_sku_id') self.primary_sku_id: Optional[int] = utils._get_as_snowflake(data, 'primary_sku_id')
self._flags: int = data.get('flags', 0) self._flags: int = data.get('flags', 0)

27
discord/types/application.py

@ -47,7 +47,7 @@ class Secret(TypedDict):
secret: str secret: str
class _BaseApplication(TypedDict): class BaseApplication(TypedDict):
id: Snowflake id: Snowflake
name: str name: str
description: str description: str
@ -59,26 +59,35 @@ class _BaseApplication(TypedDict):
summary: NotRequired[Literal['']] summary: NotRequired[Literal['']]
deeplink_uri: NotRequired[str] deeplink_uri: NotRequired[str]
third_party_skus: NotRequired[List[ThirdPartySKU]] third_party_skus: NotRequired[List[ThirdPartySKU]]
bot: NotRequired[PartialUser]
is_verified: bool
is_discoverable: bool
is_monetized: bool
storefront_available: bool
class BaseApplication(_BaseApplication): class DetectableApplication(TypedDict):
bot: NotRequired[PartialUser] id: Snowflake
name: str
hook: bool
overlay: NotRequired[bool]
overlay_methods: NotRequired[int]
overlay_warn: NotRequired[bool]
overlay_compatibility_hook: NotRequired[bool]
aliases: NotRequired[List[str]]
executables: NotRequired[List[ApplicationExecutable]]
class IntegrationApplication(BaseApplication): class IntegrationApplication(BaseApplication):
role_connections_verification_url: NotRequired[Optional[str]] role_connections_verification_url: NotRequired[Optional[str]]
class PartialApplication(_BaseApplication): class PartialApplication(BaseApplication, DetectableApplication):
owner: NotRequired[APIUser] # Not actually ever present in partial app owner: NotRequired[APIUser] # Not actually ever present in partial app
team: NotRequired[Team] team: NotRequired[Team]
verify_key: str verify_key: str
flags: NotRequired[int] flags: NotRequired[int]
rpc_origins: NotRequired[List[str]] rpc_origins: NotRequired[List[str]]
hook: NotRequired[bool]
overlay: NotRequired[bool]
overlay_warn: NotRequired[bool]
overlay_compatibility_hook: NotRequired[bool]
terms_of_service_url: NotRequired[str] terms_of_service_url: NotRequired[str]
privacy_policy_url: NotRequired[str] privacy_policy_url: NotRequired[str]
max_participants: NotRequired[Optional[int]] max_participants: NotRequired[Optional[int]]
@ -91,13 +100,11 @@ class PartialApplication(_BaseApplication):
slug: NotRequired[str] slug: NotRequired[str]
developers: NotRequired[List[Company]] developers: NotRequired[List[Company]]
publishers: NotRequired[List[Company]] publishers: NotRequired[List[Company]]
aliases: NotRequired[List[str]]
eula_id: NotRequired[Snowflake] eula_id: NotRequired[Snowflake]
embedded_activity_config: NotRequired[EmbeddedActivityConfig] embedded_activity_config: NotRequired[EmbeddedActivityConfig]
guild: NotRequired[PartialGuild] guild: NotRequired[PartialGuild]
install_params: NotRequired[ApplicationInstallParams] install_params: NotRequired[ApplicationInstallParams]
store_listing_sku_id: NotRequired[Snowflake] store_listing_sku_id: NotRequired[Snowflake]
executables: NotRequired[List[ApplicationExecutable]]
class ApplicationDiscoverability(TypedDict): class ApplicationDiscoverability(TypedDict):

1
discord/types/profile.py

@ -61,6 +61,7 @@ class MutualGuild(TypedDict):
class ProfileApplication(TypedDict): class ProfileApplication(TypedDict):
id: Snowflake id: Snowflake
verified: bool verified: bool
storefront_available: bool
popular_application_command_ids: NotRequired[List[Snowflake]] popular_application_command_ids: NotRequired[List[Snowflake]]
primary_sku_id: NotRequired[Snowflake] primary_sku_id: NotRequired[Snowflake]
flags: int flags: int

3
discord/utils.py

@ -443,6 +443,7 @@ def oauth_url(
url += f'&{urlencode({"state": state})}' url += f'&{urlencode({"state": state})}'
return url return url
def snowflake_worker_id(id: int, /) -> int: def snowflake_worker_id(id: int, /) -> int:
"""Returns the worker ID of the given snowflake """Returns the worker ID of the given snowflake
@ -460,6 +461,7 @@ def snowflake_worker_id(id: int, /) -> int:
""" """
return (id >> 17) & 0x1F return (id >> 17) & 0x1F
def snowflake_process_id(id: int, /) -> int: def snowflake_process_id(id: int, /) -> int:
"""Returns the process ID of the given snowflake """Returns the process ID of the given snowflake
@ -477,6 +479,7 @@ def snowflake_process_id(id: int, /) -> int:
""" """
return (id >> 12) & 0x1F return (id >> 12) & 0x1F
def snowflake_increment(id: int, /) -> int: def snowflake_increment(id: int, /) -> int:
"""Returns the increment of the given snowflake. """Returns the increment of the given snowflake.
For every generated ID on that process, this number is incremented. For every generated ID on that process, this number is incremented.

11
docs/api.rst

@ -7169,6 +7169,7 @@ Application
.. autoclass:: PartialApplication() .. autoclass:: PartialApplication()
:members: :members:
:inherited-members:
.. attributetable:: ApplicationProfile .. attributetable:: ApplicationProfile
@ -7216,6 +7217,11 @@ Application
.. autoclass:: EmbeddedActivityPlatformConfig() .. autoclass:: EmbeddedActivityPlatformConfig()
:members: :members:
.. attributetable:: DetectableApplication
.. autoclass:: DetectableApplication()
:members:
.. attributetable:: UnverifiedApplication .. attributetable:: UnverifiedApplication
.. autoclass:: UnverifiedApplication() .. autoclass:: UnverifiedApplication()
@ -8399,6 +8405,11 @@ Flags
.. autoclass:: OnboardingProgressFlags() .. autoclass:: OnboardingProgressFlags()
:members: :members:
.. attributetable:: OverlayMethodFlags
.. autoclass:: OverlayMethodFlags()
:members:
.. attributetable:: PaymentFlags .. attributetable:: PaymentFlags
.. autoclass:: PaymentFlags() .. autoclass:: PaymentFlags()

Loading…
Cancel
Save