import aiohttp import locale from worthless import constants from worthless.classes import launcher, installer from worthless.enums import GameVariant def _get_system_language() -> str: """Gets system language compatible with server parameters. Return: System language with format xx-xx (e.g. en-us). """ try: lang = locale.getdefaultlocale()[0] lowercase_lang = lang.lower().replace("_", "-") return lowercase_lang except ValueError: return "en-us" # Fallback to English if locale is not supported class Launcher: """ Contains functions to get information from server and client like the official launcher. """ def __init__( self, language: str = None, variant: GameVariant = None, ): """Initialize the launcher API""" if not variant: variant = GameVariant.INTERNATIONAL self._variant = variant match variant: case GameVariant.INTERNATIONAL: self._api = constants.LAUNCHER_API_URL_OS self._params = { "key": "gcStgarh", "launcher_id": "10", } self._lang = ( language.lower().replace("_", "-") if language else _get_system_language() ) case GameVariant.CHINESE: self._api = constants.LAUNCHER_API_URL_CN self._params = { "key": "eYd89JmJ", "launcher_id": "18", "channel_id": "1", } self._lang = ( "zh-cn" # Use chinese language because this is chinese version ) case GameVariant.BILIBILI: self._api = constants.LAUNCHER_API_URL_CN self._params = { "key": "KAtdSsoQ", "launcher_id": "17", "channel_id": "14", } self._lang = ( "zh-cn" # Use chinese language because this is chinese version ) self._session = aiohttp.ClientSession() async def _get(self, url, **kwargs) -> dict: # Workaround because miHoYo uses retcode for their API instead of HTTP status code rsp = await self._session.get(url, **kwargs) rsp_json = await rsp.json() if rsp_json["retcode"] != 0: # TODO: Add more information to the error message raise aiohttp.ClientResponseError( code=rsp_json["retcode"], message=rsp_json["message"], history=rsp.history, request_info=rsp.request_info, ) return rsp_json @property def lang(self): return self._lang async def _get_launcher_info(self, adv=True) -> launcher.Info: params = self._params | {"filter_adv": str(adv).lower(), "language": self._lang} rsp = await self._get(self._api + "/content", params=params) if rsp["data"]["adv"] is None: params["language"] = "en-us" rsp = await self._get(self._api + "/content", params=params) lc_info = launcher.Info.from_dict(rsp["data"]) return lc_info @lang.setter def lang(self, language: str) -> None: """Overrides system detected language with another language. Args: language (str): Language to override with. """ self._lang = language.lower().replace("_", "-") async def get_resource_info(self) -> installer.Resource: """Gets version info from the server. This function gets version info including audio pack and their download url from the server. Returns: A dict containing version info from the server. Raises: aiohttp.ClientResponseError: An error occurred while fetching the information. """ rsp = await self._get(self._api + "/resource", params=self._params) return installer.Resource.from_dict(rsp["data"]) async def get_launcher_info(self) -> launcher.Info: """Gets short launcher info from the server This function only gets background image and the FAQ url from the server. Returns: A dict containing short launcher info from the server. Raises: aiohttp.ClientResponseError: An error occurred while fetching the information. """ return await self._get_launcher_info(adv=True) async def get_launcher_full_info(self) -> launcher.Info: """Gets full launcher info from the server. Returns: A dict containing full launcher info from the server. Raises: aiohttp.ClientResponseError: An error occurred while fetching the information. """ return await self._get_launcher_info(adv=False) async def get_launcher_background_url(self) -> str: """Gets launcher background image url from the server. Returns: Background image url. Raises: aiohttp.ClientResponseError: An error occurred while fetching the background image. """ rsp = await self.get_launcher_info() return rsp.background.background