From 65d1efef25884b51e3de86f82830bf46e37d0365 Mon Sep 17 00:00:00 2001 From: dolfies Date: Fri, 13 May 2022 19:42:56 -0400 Subject: [PATCH] Expose Client.country_code and Client.preferred_voice_regions --- discord/client.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++ discord/http.py | 14 ++++++++++++ discord/state.py | 11 +++++++--- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/discord/client.py b/discord/client.py index 089a18644..ba4234080 100644 --- a/discord/client.py +++ b/discord/client.py @@ -351,6 +351,22 @@ class Client: """ return self._connection.voice_clients + @property + def country_code(self) -> Optional[str]: + """Optional[:class:`str`]: The country code of the client. ``None`` if not connected. + + .. versionadded:: 2.0 + """ + return self._connection.country_code + + @property + def preferred_voice_regions(self) -> List[str]: + """List[:class:`str`]: Geo-ordered list of voice regions the connected client can use. + + .. versionadded:: 2.0 + """ + return self._connection.preferred_regions + def is_ready(self) -> bool: """:class:`bool`: Specifies if the client's internal cache is ready for use.""" return self._ready is not MISSING and self._ready.is_set() @@ -2224,6 +2240,46 @@ class Client: channels = await state.http.get_private_channels() return [_private_channel_factory(data['type'])[0](me=self.user, data=data, state=state) for data in channels] # type: ignore # user is always present when logged in + async def fetch_country_code(self) -> str: + """|coro| + + Retrieves the country code of the client. + + .. versionadded:: 2.0 + + Raises + ------- + HTTPException + Retrieving the country code failed. + + Returns + ------- + :class:`str` + The country code of the client. + """ + data = await self.http.get_country_code() + return data['country_code'] + + async def fetch_preferred_voice_regions(self) -> List[str]: + """|coro| + + Retrieves the preferred voice regions of the client. + + .. versionadded:: 2.0 + + Raises + ------- + HTTPException + Retrieving the preferred voice regions failed. + + Returns + ------- + List[:class:`str`] + The preferred voice regions of the client. + """ + data = await self.http.get_preferred_voice_regions() + return [v['region'] for v in data] + async def create_dm(self, user: Snowflake, /) -> DMChannel: """|coro| diff --git a/discord/http.py b/discord/http.py index e9aa7eedb..0804a5b54 100644 --- a/discord/http.py +++ b/discord/http.py @@ -2433,3 +2433,17 @@ class HTTPClient: payload = None return self.request(Route('POST', '/interactions'), json=payload, form=form, files=files) + + def get_country_code(self): + return self.request(Route('GET', '/users/@me/billing/country-code')) + + async def get_preferred_voice_regions(self) -> List[dict]: + async with self.__session.get('https://latency.discord.media/rtc') as resp: + if resp.status == 200: + return await resp.json() + elif resp.status == 404: + raise NotFound(resp, 'rtc regions not found') + elif resp.status == 403: + raise Forbidden(resp, 'cannot retrieve rtc regions') + else: + raise HTTPException(resp, 'failed to get rtc regions') diff --git a/discord/state.py b/discord/state.py index ac405f9c7..7dd2ce5af 100644 --- a/discord/state.py +++ b/discord/state.py @@ -454,7 +454,8 @@ class ConnectionState: self.settings: Optional[UserSettings] = None self.consents: Optional[Tracking] = None self.analytics_token: Optional[str] = None - self.preferred_region: Optional[str] = None + self.preferred_regions: List[str] = [] + self.country_code: Optional[str] = None self._emojis: Dict[int, Emoji] = {} self._stickers: Dict[int, GuildSticker] = {} self._guilds: Dict[int, Guild] = {} @@ -521,6 +522,10 @@ class ConnectionState: u = self.user return u.id if u else None + @property + def preferred_region(self) -> str: + return self.preferred_regions[0] if self.preferred_regions else 'us-central' + @property def voice_clients(self) -> List[VoiceProtocol]: return list(self._voice_clients.values()) @@ -875,10 +880,10 @@ class ConnectionState: # Extras self.analytics_token = data.get('analytics_token') - region = data.get('geo_ordered_rtc_regions', ['us-west'])[0] - self.preferred_region = region + self.preferred_regions = data.get('geo_ordered_rtc_regions', ['us-central']) self.settings = UserSettings(data=data.get('user_settings', {}), state=self) self.consents = Tracking(data=data.get('consents', {}), state=self) + self.country_code = data.get('country_code', 'US') if 'required_action' in data: # Locked more than likely self.parse_user_required_action_update(data)