import aiohttp import locale from worthless import constants from pathlib import Path from worthless.classes import launcher class Launcher: """ Contains functions to get information from server and client like the official launcher. """ def __init__(self, gamedir=Path.cwd()): """Initialize the launcher API Args: gamedir (Path): Path to the game directory. """ self._api = constants.LAUNCHER_API_URL self._lang = self._get_system_language() if isinstance(gamedir, str): gamedir = Path(gamedir) self._gamedir = gamedir.resolve() @staticmethod async def _get(url, **kwargs) -> dict: # Workaround because miHoYo uses retcode for their API instead of HTTP status code async with aiohttp.ClientSession() as session: rsp = await 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 async def _get_launcher_info(self, adv=True) -> launcher.Info: params = {"key": "gcStgarh", "filter_adv": str(adv).lower(), "launcher_id": "10", "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 @staticmethod def _get_system_language() -> str: """Gets system language compatible with server parameters. Return: System language with format xx-xx. """ try: lang = locale.getdefaultlocale()[0] lowercase_lang = lang.lower().replace("_", "-") return lowercase_lang except ValueError: return "en-us" async def override_gamedir(self, gamedir: str) -> None: """Overrides game directory with another directory. Args: gamedir (str): New directory to override with. """ self._gamedir = Path(gamedir).resolve() async def override_language(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_version_info(self) -> dict: """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={"key": "gcStgarh", "launcher_id": "10"}) return rsp 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 async def get_system_game_info(self, table_handle, keys, require_all_keys): # TODO: Implement raise NotImplementedError("Not implemented yet.") pass async def get_system_game_version(self) -> str: """Gets the game version from the current system. :return: str: System game version. """ rsp = await self.get_version_info() return rsp["data"]["system"]["game_version"]