Wrap game resource info from the server
Also add function to get the diff archive (for faster updating) Download function soon, although I can't make sure that the download function will work properly (like pause, resume download etc.)
This commit is contained in:
parent
81fbdec553
commit
da3ee30ab1
@ -1,38 +1,47 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import asyncio
|
import asyncio
|
||||||
import worthless
|
import worthless
|
||||||
from worthless.classes import launcher
|
from worthless.classes import launcher, installer
|
||||||
client = worthless.Launcher()
|
game_launcher = worthless.Launcher()
|
||||||
|
game_installer = worthless.Installer()
|
||||||
|
|
||||||
|
|
||||||
class LauncherOverseasTest(unittest.TestCase):
|
class LauncherOverseasTest(unittest.TestCase):
|
||||||
def test_get_version_info(self):
|
def test_get_version_info(self):
|
||||||
version_info = asyncio.run(client.get_version_info())
|
version_info = asyncio.run(game_launcher.get_resource_info())
|
||||||
print("get_version_info test.")
|
print("get_resource_info test.")
|
||||||
print("get_version_info: ", version_info)
|
print("get_resource_info: ", version_info)
|
||||||
self.assertIsInstance(version_info, dict)
|
print("raw: ", version_info.raw)
|
||||||
|
self.assertIsInstance(version_info, installer.Resource)
|
||||||
|
|
||||||
def test_get_launcher_info(self):
|
def test_get_launcher_info(self):
|
||||||
launcher_info = asyncio.run(client.get_launcher_info())
|
launcher_info = asyncio.run(game_launcher.get_launcher_info())
|
||||||
print("get_launcher_info test.")
|
print("get_launcher_info test.")
|
||||||
print("get_launcher_info: ", launcher_info)
|
print("get_launcher_info: ", launcher_info)
|
||||||
print("raw: ", launcher_info.raw)
|
print("raw: ", launcher_info.raw)
|
||||||
self.assertIsInstance(launcher_info, launcher.Info)
|
self.assertIsInstance(launcher_info, launcher.Info)
|
||||||
|
|
||||||
def test_get_launcher_full_info(self):
|
def test_get_launcher_full_info(self):
|
||||||
launcher_info = asyncio.run(client.get_launcher_full_info())
|
launcher_info = asyncio.run(game_launcher.get_launcher_full_info())
|
||||||
print("get_launcher_full_info test.")
|
print("get_launcher_full_info test.")
|
||||||
print("get_launcher_full_info: ", launcher_info)
|
print("get_launcher_full_info: ", launcher_info)
|
||||||
print("raw: ", launcher_info.raw)
|
print("raw: ", launcher_info.raw)
|
||||||
self.assertIsInstance(launcher_info, launcher.Info)
|
self.assertIsInstance(launcher_info, launcher.Info)
|
||||||
|
|
||||||
def test_get_launcher_background_url(self):
|
def test_get_launcher_background_url(self):
|
||||||
bg_url = asyncio.run(client.get_launcher_background_url())
|
bg_url = asyncio.run(game_launcher.get_launcher_background_url())
|
||||||
print("get_launcher_background_url test.")
|
print("get_launcher_background_url test.")
|
||||||
print("get_launcher_background_url: ", bg_url)
|
print("get_launcher_background_url: ", bg_url)
|
||||||
self.assertIsInstance(bg_url, str)
|
self.assertIsInstance(bg_url, str)
|
||||||
self.assertTrue(bg_url)
|
self.assertTrue(bg_url)
|
||||||
|
|
||||||
|
def test_get_installer_diff(self):
|
||||||
|
game_diff = asyncio.run(game_installer.get_game_diff_archive("2.4.0"))
|
||||||
|
print("get_game_diff_archive test.")
|
||||||
|
print("get_game_diff_archive: ", game_diff)
|
||||||
|
print("raw: ", game_diff.raw)
|
||||||
|
self.assertIsInstance(game_diff, installer.Diff)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
from worthless import launcher
|
from worthless import launcher, installer
|
||||||
|
|
||||||
Launcher = launcher.Launcher
|
Launcher = launcher.Launcher
|
||||||
|
Installer = installer.Installer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import gui as gui
|
from worthless import gui
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
gui.main()
|
gui.main()
|
||||||
|
6
worthless/classes/installer/__init__.py
Normal file
6
worthless/classes/installer/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from worthless.classes.installer import resource, game, latest, diff, voicepack
|
||||||
|
Resource = resource.Resource
|
||||||
|
Game = game.Game
|
||||||
|
Latest = latest.Latest
|
||||||
|
Diff = diff.Diff
|
||||||
|
Voicepack = voicepack.Voicepack
|
21
worthless/classes/installer/diff.py
Normal file
21
worthless/classes/installer/diff.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from worthless.classes.installer.voicepack import Voicepack
|
||||||
|
|
||||||
|
|
||||||
|
class Diff:
|
||||||
|
def __init__(self, name, version, path, size, md5, is_recommended_update, voice_packs, raw):
|
||||||
|
self.name = name
|
||||||
|
self.version = version
|
||||||
|
self.path = path
|
||||||
|
self.size = size
|
||||||
|
self.md5 = md5
|
||||||
|
self.is_recommended_update = is_recommended_update
|
||||||
|
self.voice_packs = voice_packs
|
||||||
|
self.raw = raw
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data):
|
||||||
|
voice_packs = []
|
||||||
|
for v in data['voice_packs']:
|
||||||
|
voice_packs.append(Voicepack.from_dict(v))
|
||||||
|
return Diff(data["name"], data["version"], data["path"], data["size"], data["md5"],
|
||||||
|
data["is_recommended_update"], voice_packs, data)
|
16
worthless/classes/installer/game.py
Normal file
16
worthless/classes/installer/game.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from worthless.classes.installer.latest import Latest
|
||||||
|
from worthless.classes.installer.diff import Diff
|
||||||
|
|
||||||
|
|
||||||
|
class Game:
|
||||||
|
def __init__(self, latest, diffs, raw):
|
||||||
|
self.latest = latest
|
||||||
|
self.diffs = diffs
|
||||||
|
self.raw = raw
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data):
|
||||||
|
diffs = []
|
||||||
|
for diff in data['diffs']:
|
||||||
|
diffs.append(Diff.from_dict(diff))
|
||||||
|
return Game(Latest.from_dict(data['latest']), diffs, data)
|
23
worthless/classes/installer/latest.py
Normal file
23
worthless/classes/installer/latest.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from worthless.classes.installer.voicepack import Voicepack
|
||||||
|
|
||||||
|
|
||||||
|
class Latest:
|
||||||
|
def __init__(self, name, version, path, size, md5, entry, voice_packs, decompressed_path, segments, raw):
|
||||||
|
self.name = name
|
||||||
|
self.version = version
|
||||||
|
self.path = path
|
||||||
|
self.size = size
|
||||||
|
self.md5 = md5
|
||||||
|
self.entry = entry
|
||||||
|
self.voice_packs = voice_packs
|
||||||
|
self.decompressed_path = decompressed_path
|
||||||
|
self.segments = segments
|
||||||
|
self.raw = raw
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data):
|
||||||
|
voice_packs = []
|
||||||
|
for v in data['voice_packs']:
|
||||||
|
voice_packs.append(Voicepack.from_dict(v))
|
||||||
|
return Latest(data["name"], data["version"], data["path"], data["size"], data["md5"], data["entry"],
|
||||||
|
voice_packs, data["decompressed_path"], data["segments"], data)
|
30
worthless/classes/installer/resource.py
Normal file
30
worthless/classes/installer/resource.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from worthless.classes.installer.game import Game
|
||||||
|
|
||||||
|
|
||||||
|
class Resource:
|
||||||
|
"""Contains the game resource information.
|
||||||
|
|
||||||
|
Everything except `game` is not wrapped yet
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
|
||||||
|
- :class:`worthless.classes.launcher.background.Background` background: The launcher background information.
|
||||||
|
- :class:`worthless.classes.launcher.banner.Banner` banner: The launcher banner information.
|
||||||
|
- :class:`worthless.classes.launcher.iconbutton.IconButton` icon: The launcher icon buttons information.
|
||||||
|
- :class:`worthless.classes.launcher.qq.QQ` post: The launcher QQ posts information.
|
||||||
|
- :class:`dict` raw: The launcher raw information.
|
||||||
|
"""
|
||||||
|
def __init__(self, game, plugin, web_url, force_update, pre_download_game, deprecated_packages, sdk, raw):
|
||||||
|
self.game = game
|
||||||
|
self.plugin = plugin
|
||||||
|
self.web_url = web_url
|
||||||
|
self.force_update = force_update
|
||||||
|
self.pre_download_game = pre_download_game
|
||||||
|
self.deprecated_packages = deprecated_packages
|
||||||
|
self.sdk = sdk
|
||||||
|
self.raw = raw
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data):
|
||||||
|
return Resource(Game.from_dict(data['game']), data['plugin'], data['web_url'], data['force_update'],
|
||||||
|
data['pre_download_game'], data['deprecated_packages'], data['sdk'], data)
|
12
worthless/classes/installer/voicepack.py
Normal file
12
worthless/classes/installer/voicepack.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class Voicepack:
|
||||||
|
def __init__(self, language, name, path, size, md5, raw):
|
||||||
|
self.language = language
|
||||||
|
self.name = name
|
||||||
|
self.path = path
|
||||||
|
self.size = size
|
||||||
|
self.md5 = md5
|
||||||
|
self.raw = raw
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(data):
|
||||||
|
return Voicepack(data["language"], data["name"], data["path"], data["size"], data["md5"], data)
|
@ -1,7 +1,8 @@
|
|||||||
from worthless.classes.launcher import background, banner, iconbutton, iconotherlink, info, post
|
from worthless.classes.launcher import background, banner, iconbutton, iconotherlink, info, post, qq
|
||||||
Background = background.Background
|
Background = background.Background
|
||||||
Banner = banner.Banner
|
Banner = banner.Banner
|
||||||
IconButton = iconbutton.IconButton
|
IconButton = iconbutton.IconButton
|
||||||
IconOtherLink = iconotherlink.IconOtherLink
|
IconOtherLink = iconotherlink.IconOtherLink
|
||||||
Info = info.Info
|
Info = info.Info
|
||||||
Post = post.Post
|
Post = post.Post
|
||||||
|
QQ = qq.QQ
|
@ -1,6 +1,6 @@
|
|||||||
APP_NAME="worthless"
|
APP_NAME="worthless"
|
||||||
APP_AUTHOR="tretrauit"
|
APP_AUTHOR="tretrauit"
|
||||||
LAUNCHER_API_URL_OS = "https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api"
|
LAUNCHER_API_URL_OS = "https://sdk-os-static.hoyoverse.com/hk4e_global/mdk/launcher/api"
|
||||||
LAUNCHER_API_URL_CN = "https://sdk-static.mihoyo.com/hk4e_cn/mdk/launcher/api"
|
LAUNCHER_API_URL_CN = "https://sdk-static.mihoyo.com/hk4e_cn/mdk/launcher/api"
|
||||||
PATCH_GIT_URL = "https://notabug.org/Krock/dawn"
|
PATCH_GIT_URL = "https://notabug.org/Krock/dawn"
|
||||||
TELEMETRY_URL_LIST = [
|
TELEMETRY_URL_LIST = [
|
||||||
|
@ -3,17 +3,24 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import appdirs
|
import appdirs
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import constants
|
from worthless.launcher import Launcher
|
||||||
|
from worthless.installer import Installer
|
||||||
|
import worthless.constants as constants
|
||||||
|
|
||||||
|
|
||||||
class UI:
|
class UI:
|
||||||
def __init__(self, gamedir: str, noconfirm: bool) -> None:
|
def __init__(self, gamedir: str, noconfirm: bool) -> None:
|
||||||
self._noconfirm = noconfirm
|
self._noconfirm = noconfirm
|
||||||
self._gamedir = gamedir
|
self._gamedir = gamedir
|
||||||
|
self._launcher = Launcher(gamedir)
|
||||||
|
self._installer = Installer(gamedir)
|
||||||
|
|
||||||
def _ask(self, title, description):
|
def _ask(self, title, description):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def get_game_version(self):
|
||||||
|
print(self._installer.get_game_version())
|
||||||
|
|
||||||
def install_game(self):
|
def install_game(self):
|
||||||
# TODO
|
# TODO
|
||||||
raise NotImplementedError("Install game is not implemented.")
|
raise NotImplementedError("Install game is not implemented.")
|
||||||
@ -38,7 +45,7 @@ def main():
|
|||||||
help="Specify the temporary directory (default {} and {})".format(default_dirs.user_data_dir,
|
help="Specify the temporary directory (default {} and {})".format(default_dirs.user_data_dir,
|
||||||
default_dirs.user_cache_dir))
|
default_dirs.user_cache_dir))
|
||||||
parser.add_argument("-S", "--install", action="store_true",
|
parser.add_argument("-S", "--install", action="store_true",
|
||||||
help="Install the game (if not already installed, else do nothing)")
|
help="Install/update the game (if not already installed, else do nothing)")
|
||||||
parser.add_argument("-U", "--install-from-file", action="store_true",
|
parser.add_argument("-U", "--install-from-file", action="store_true",
|
||||||
help="Install the game from the game archive (if not already installed, \
|
help="Install the game from the game archive (if not already installed, \
|
||||||
else update from archive)")
|
else update from archive)")
|
||||||
@ -46,21 +53,28 @@ def main():
|
|||||||
help="Patch the game (if not already patched, else do nothing)")
|
help="Patch the game (if not already patched, else do nothing)")
|
||||||
parser.add_argument("-Sy", "--update", action="store_true",
|
parser.add_argument("-Sy", "--update", action="store_true",
|
||||||
help="Update the game and specified voiceover pack only (or install if not found)")
|
help="Update the game and specified voiceover pack only (or install if not found)")
|
||||||
|
parser.add_argument("-Sv", "--update-voiceover", action="store_true",
|
||||||
|
help="Update the voiceover pack only (or install if not found)")
|
||||||
parser.add_argument("-Syu", "--update-all", action="store_true",
|
parser.add_argument("-Syu", "--update-all", action="store_true",
|
||||||
help="Update the game and all installed voiceover packs (or install if not found)")
|
help="Update the game and all installed voiceover packs (or install if not found)")
|
||||||
parser.add_argument("-Rs", "--remove", action="store_true", help="Remove the game (if installed)")
|
parser.add_argument("-Rs", "--remove", action="store_true", help="Remove the game (if installed)")
|
||||||
parser.add_argument("-Rp", "--remove-patch", action="store_true", help="Revert the game patch (if patched)")
|
parser.add_argument("-Rp", "--remove-patch", action="store_true", help="Revert the game patch (if patched)")
|
||||||
parser.add_argument("-Rv", "--remove-voiceover", action="store_true", help="Remove a Voiceover pack (if installed)")
|
parser.add_argument("-Rv", "--remove-voiceover", action="store_true", help="Remove a Voiceover pack (if installed)")
|
||||||
|
parser.add_argument("--get-game-version", action="store_true", help="Get the current game version")
|
||||||
|
parser.add_argument("--no-overseas", action="store_true", help="Don't use overseas server")
|
||||||
parser.add_argument("--noconfirm", action="store_true",
|
parser.add_argument("--noconfirm", action="store_true",
|
||||||
help="Do not ask any for confirmation. (Ignored in interactive mode)")
|
help="Do not ask any for confirmation. (Ignored in interactive mode)")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
interactive_mode = not args.install and not args.install_from_file and not args.patch and not args.update and not \
|
interactive_mode = not args.install and not args.install_from_file and not args.patch and not args.update and not \
|
||||||
args.remove and not args.remove_patch and not args.remove_voiceover
|
args.remove and not args.remove_patch and not args.remove_voiceover and not args.get_game_version
|
||||||
ui = UI(args.dir, args.noconfirm)
|
ui = UI(args.dir, args.noconfirm)
|
||||||
|
|
||||||
if args.install and args.update:
|
if args.install and args.update:
|
||||||
raise ValueError("Cannot specify both --install and --update arguments.")
|
raise ValueError("Cannot specify both --install and --update arguments.")
|
||||||
|
|
||||||
|
if args.get_game_version:
|
||||||
|
ui.get_game_version()
|
||||||
|
|
||||||
if args.install:
|
if args.install:
|
||||||
ui.install_game()
|
ui.install_game()
|
||||||
|
|
||||||
|
@ -7,27 +7,35 @@ from worthless import constants
|
|||||||
from worthless.launcher import Launcher
|
from worthless.launcher import Launcher
|
||||||
|
|
||||||
|
|
||||||
|
def _read_version_from_game_file(globalgamemanagers: Path):
|
||||||
|
with globalgamemanagers.open("rb") as f:
|
||||||
|
data = f.read().decode("ascii", errors="ignore")
|
||||||
|
result = re.search(r"([1-9]+\.[0-9]+\.[0-9]+)_[\d]+_[\d]+", data)
|
||||||
|
if not result:
|
||||||
|
raise ValueError("Could not find version in game file")
|
||||||
|
return result.group(1)
|
||||||
|
|
||||||
|
|
||||||
class Installer:
|
class Installer:
|
||||||
def _read_version_from_config(self):
|
def _read_version_from_config(self):
|
||||||
if self._config_file.exists():
|
if not self._config_file.exists():
|
||||||
raise FileNotFoundError(f"Config file {self._config_file} not found")
|
raise FileNotFoundError(f"Config file {self._config_file} not found")
|
||||||
cfg = ConfigParser()
|
cfg = ConfigParser()
|
||||||
cfg.read(str(self._config_file))
|
cfg.read(str(self._config_file))
|
||||||
return cfg.get("miHoYo", "game_version")
|
return cfg.get("General", "game_version")
|
||||||
|
|
||||||
# https://gitlab.com/KRypt0n_/an-anime-game-launcher/-/blob/main/src/ts/Game.ts#L26
|
# https://gitlab.com/KRypt0n_/an-anime-game-launcher/-/blob/main/src/ts/Game.ts#L26
|
||||||
def _read_version_from_game_file(self):
|
def get_game_version(self):
|
||||||
if self._overseas:
|
if self._config_file.exists():
|
||||||
globalgamemanagers = self._gamedir.joinpath("./GenshinImpact_Data/globalgamemanagers")
|
return self._read_version_from_config()
|
||||||
else:
|
else:
|
||||||
globalgamemanagers = self._gamedir.joinpath("./YuanShen_Data/globalgamemanagers")
|
if self._overseas:
|
||||||
if globalgamemanagers.exists():
|
globalgamemanagers = self._gamedir.joinpath("./GenshinImpact_Data/globalgamemanagers")
|
||||||
with globalgamemanagers.open("rb") as f:
|
else:
|
||||||
data = f.read().decode("ascii")
|
globalgamemanagers = self._gamedir.joinpath("./YuanShen_Data/globalgamemanagers")
|
||||||
result = re.search(r"([1-9]+\.[0-9]+\.[0-9]+)_[\d]+_[\d]+", data)
|
if not globalgamemanagers.exists():
|
||||||
if not result:
|
return
|
||||||
raise ValueError("Could not find version in game file")
|
return _read_version_from_game_file(globalgamemanagers)
|
||||||
return result.group(1)
|
|
||||||
|
|
||||||
def __init__(self, gamedir: str | Path = Path.cwd(), overseas: bool = True, data_dir: str | Path = None):
|
def __init__(self, gamedir: str | Path = Path.cwd(), overseas: bool = True, data_dir: str | Path = None):
|
||||||
if isinstance(gamedir, str):
|
if isinstance(gamedir, str):
|
||||||
@ -44,9 +52,24 @@ class Installer:
|
|||||||
self._config_file = config_file.resolve()
|
self._config_file = config_file.resolve()
|
||||||
self._version = None
|
self._version = None
|
||||||
self._overseas = overseas
|
self._overseas = overseas
|
||||||
self._launcher = Launcher(self._gamedir, self._overseas)
|
self._launcher = Launcher(self._gamedir, overseas=self._overseas)
|
||||||
if config_file.exists():
|
self._version = self.get_game_version()
|
||||||
self._version = self._read_version_from_config()
|
|
||||||
elif gamedir.joinpath("./GenshinImpact_Data/globalgamemanagers").exists():
|
|
||||||
self._version = self._read_version_from_game_file()
|
|
||||||
|
|
||||||
|
async def get_game_diff_archive(self, from_version: str = None):
|
||||||
|
"""Gets a diff archive from `from_version` to the latest one
|
||||||
|
|
||||||
|
If from_version is not specified, it will be taken from the game version.
|
||||||
|
"""
|
||||||
|
if not from_version:
|
||||||
|
if self._version:
|
||||||
|
from_version = self._version
|
||||||
|
else:
|
||||||
|
from_version = self._version = self.get_game_version()
|
||||||
|
if not from_version:
|
||||||
|
raise ValueError("No game version found")
|
||||||
|
game_resource = await self._launcher.get_resource_info()
|
||||||
|
if not game_resource:
|
||||||
|
raise ValueError("Could not fetch game resource")
|
||||||
|
for v in game_resource.game.diffs:
|
||||||
|
if v.version == from_version:
|
||||||
|
return v
|
||||||
|
@ -2,7 +2,36 @@ import aiohttp
|
|||||||
import locale
|
import locale
|
||||||
from worthless import constants
|
from worthless import constants
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from worthless.classes import launcher
|
from worthless.classes import launcher, installer
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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" # Fallback to English if locale is not supported
|
||||||
|
|
||||||
|
|
||||||
class Launcher:
|
class Launcher:
|
||||||
@ -10,7 +39,7 @@ class Launcher:
|
|||||||
Contains functions to get information from server and client like the official launcher.
|
Contains functions to get information from server and client like the official launcher.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, gamedir=Path.cwd(), language=None, overseas=True):
|
def __init__(self, gamedir: str | Path = Path.cwd(), language: str = None, overseas=True):
|
||||||
"""Initialize the launcher API
|
"""Initialize the launcher API
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -23,7 +52,7 @@ class Launcher:
|
|||||||
"key": "gcStgarh",
|
"key": "gcStgarh",
|
||||||
"launcher_id": "10",
|
"launcher_id": "10",
|
||||||
}
|
}
|
||||||
self._lang = self._get_system_language() if not language else language.lower().replace("_", "-")
|
self._lang = language.lower().replace("_", "-") if language else _get_system_language()
|
||||||
else:
|
else:
|
||||||
self._api = constants.LAUNCHER_API_URL_CN
|
self._api = constants.LAUNCHER_API_URL_CN
|
||||||
self._params = {
|
self._params = {
|
||||||
@ -36,42 +65,13 @@ class Launcher:
|
|||||||
gamedir = Path(gamedir)
|
gamedir = Path(gamedir)
|
||||||
self._gamedir = gamedir.resolve()
|
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
|
|
||||||
|
|
||||||
@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" # Fallback to English if locale is not supported
|
|
||||||
|
|
||||||
async def _get_launcher_info(self, adv=True) -> launcher.Info:
|
async def _get_launcher_info(self, adv=True) -> launcher.Info:
|
||||||
params = self._params | {"filter_adv": str(adv).lower(),
|
params = self._params | {"filter_adv": str(adv).lower(),
|
||||||
"language": self._lang}
|
"language": self._lang}
|
||||||
rsp = await self._get(self._api + "/content", params=params)
|
rsp = await _get(self._api + "/content", params=params)
|
||||||
if rsp["data"]["adv"] is None:
|
if rsp["data"]["adv"] is None:
|
||||||
params["language"] = "en-us"
|
params["language"] = "en-us"
|
||||||
rsp = await self._get(self._api + "/content", params=params)
|
rsp = await _get(self._api + "/content", params=params)
|
||||||
lc_info = launcher.Info.from_dict(rsp["data"])
|
lc_info = launcher.Info.from_dict(rsp["data"])
|
||||||
return lc_info
|
return lc_info
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ class Launcher:
|
|||||||
|
|
||||||
self._lang = language.lower().replace("_", "-")
|
self._lang = language.lower().replace("_", "-")
|
||||||
|
|
||||||
async def get_version_info(self) -> dict:
|
async def get_resource_info(self) -> installer.Resource:
|
||||||
"""Gets version info from the server.
|
"""Gets version info from the server.
|
||||||
|
|
||||||
This function gets version info including audio pack and their download url from the server.
|
This function gets version info including audio pack and their download url from the server.
|
||||||
@ -105,8 +105,8 @@ class Launcher:
|
|||||||
aiohttp.ClientResponseError: An error occurred while fetching the information.
|
aiohttp.ClientResponseError: An error occurred while fetching the information.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
rsp = await self._get(self._api + "/resource", params=self._params)
|
rsp = await _get(self._api + "/resource", params=self._params)
|
||||||
return rsp
|
return installer.Resource.from_dict(rsp["data"])
|
||||||
|
|
||||||
async def get_launcher_info(self) -> launcher.Info:
|
async def get_launcher_info(self) -> launcher.Info:
|
||||||
"""Gets short launcher info from the server
|
"""Gets short launcher info from the server
|
||||||
@ -143,16 +143,3 @@ class Launcher:
|
|||||||
|
|
||||||
rsp = await self.get_launcher_info()
|
rsp = await self.get_launcher_info()
|
||||||
return rsp.background.background
|
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"]
|
|
||||||
|
Loading…
Reference in New Issue
Block a user