Update tests

This commit is contained in:
tretrauit 2022-01-29 23:32:38 +07:00
parent a7ddd0c49a
commit 048a7ac9d0
Signed by: tretrauit
GPG Key ID: 862760FF1903319E
8 changed files with 195 additions and 50 deletions

View File

@ -1,6 +1,7 @@
import unittest
import asyncio
import worthless
from worthless.classes import launcher
client = worthless.Launcher()
@ -15,13 +16,13 @@ class LauncherTest(unittest.TestCase):
launcher_info = asyncio.run(client.get_launcher_info())
print("get_launcher_info test.")
print("get_launcher_info: ", launcher_info)
self.assertIsInstance(launcher_info, dict)
self.assertIsInstance(launcher_info, launcher.Info)
def test_get_launcher_full_info(self):
launcher_info = asyncio.run(client.get_launcher_full_info())
print("get_launcher_full_info test.")
print("get_launcher_full_info: ", launcher_info)
self.assertIsInstance(launcher_info, dict)
self.assertIsInstance(launcher_info, launcher.Info)
def test_get_launcher_background_url(self):
bg_url = asyncio.run(client.get_launcher_background_url())

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3
from app import main
from worthless import gui
if __name__ == '__main__':
main()
gui.main()

View File

@ -0,0 +1,7 @@
from worthless.classes.launcher import background, banner, iconbutton, iconotherlink, info, post
Background = background.Background
Banner = banner.Banner
IconButton = iconbutton.IconButton
IconOtherLink = iconotherlink.IconOtherLink
Info = info.Info
Post = post.Post

View File

@ -1,4 +1,4 @@
from worthless.classes.launcher.launchericonotherlink import IconOtherLink
from worthless.classes.launcher.iconotherlink import IconOtherLink
class IconButton:

View File

@ -1,3 +1,28 @@
class LauncherInfo:
def __init__(self):
pass
from worthless.classes.launcher import background, banner, iconbutton, post
Background = background.Background
Banner = banner.Banner
IconButton = iconbutton.IconButton
Post = post.Post
class Info:
def __init__(self, lc_background: Background, lc_banner: list[Banner], icon: list[IconButton], lc_post: list[Post]):
self.background = lc_background
self.banner = lc_banner
self.icon = icon
self.post = lc_post
@staticmethod
def from_dict(data):
bg = Background.from_dict(data["adv"])
lc_banner = []
for b in data["banner"]:
lc_banner.append(Banner.from_dict(b))
lc_icon = []
for i in data["icon"]:
lc_icon.append(IconButton.from_dict(i))
lc_post = []
for p in data["post"]:
lc_post.append(Post.from_dict(p))
return Info(bg, lc_banner, lc_icon, lc_post)

View File

@ -1,29 +1,38 @@
class Banner:
"""Contains a launcher banner information
class Post:
"""Contains a launcher post information
Note that the banner name is in chinese, so you may not find this variable useful.
Also, the banner has a variable called `order`, you can use that to sort the banner
like the official launcher does.
The `type` variable can be POST_TYPE_ANNOUNCE, POST_TYPE_ACTIVITY and POST_TYPE_INFO
where announce is an announcement, activity is an activity/event and info is an information.
The `show_time` variable is the time in DD/MM format when the post will be shown.
Also, `tittle` is not my typo, and it's the server intention (probably there are clients
where their developers wrote `tittle` instead of `title`), and the post has a variable
called `order`, you can use that to sort the post like the official launcher does.
Attributes:
- :class:`str` banner_id: The launcher banner id.
- :class:`str` name: The banner name.
- :class:`str` img: The banner image url.
- :class:`str` url: The banner target url.
- :class:`str` order: The banner order.
- :class:`str` name: The banner name.
- :class:`str` post_id: The launcher post id.
- :class:`str` type: The post type, as explained above.
- :class:`str` tittle: The post title.
- :class:`str` url: The post target url.
- :class:`str` show_time: The time when the post will be shown.
- :class:`str` order: The post order.
- :class:`str` title: The post title.
- :class:`dict` raw: The banner raw information.
"""
def __init__(self, banner_id, name, img, url, order, raw):
self.banner_id = banner_id
self.name = name
self.img = img
def __init__(self, post_id, post_type, tittle, url, show_time, order, title, raw):
self.post_id = post_id
self.type = post_type # Shadow built-in name `type`
self.tittle = tittle
self.url = url
self.show_time = show_time
self.order = order
self.title = title
self.raw = raw
@staticmethod
def from_dict(data) -> 'Banner':
"""Creates a launcher banner from a dictionary."""
return Banner(data["banner_id"], data["name"], data["img"], data["url"], data["order"], data)
def from_dict(data) -> 'Post':
"""Creates a launcher post from a dictionary."""
return Post(data["post_id"], data["type"], data["tittle"], data["url"],
data["show_time"], data["order"], data["title"], data)

View File

@ -1,28 +1,42 @@
import aiohttp
import locale
from worthless import constants
from pathlib import Path
from worthless.classes import launcher
class Launcher:
def __init__(self):
"""
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()
# Workaround because miHoYo uses retcode for their API
@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()
# Why retcode seriously? They can just make the page not returning 200 status code.
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) -> dict:
async def _get_launcher_info(self, adv=True) -> launcher.Info:
params = {"key": "gcStgarh",
"filter_adv": str(adv).lower(),
"launcher_id": "10",
@ -31,13 +45,17 @@ class Launcher:
if rsp["data"]["adv"] is None:
params["language"] = "en-us"
rsp = await self._get(self._api + "/content", params=params)
return rsp
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.
"""
Get system language compatible with server parameters.
"""
try:
lang = locale.getdefaultlocale()[0]
lowercase_lang = lang.lower().replace("_", "-")
@ -45,38 +63,84 @@ class Launcher:
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.
"""
Override system detected language with another language.
:param language: The language to override with.
:return: None
"""
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) -> dict:
"""
This function will get short launcher info from the server (only contains background image and FAQ)
:return: dict: Launcher info from the server.
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) -> dict:
"""
This function will get full launcher info from the server.
Since the server content is very long for a short explanation, you should see it manually.
:return: dict: Launcher info from the server.
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.
"""
This function will get launcher background image from the server.
:return: str: Background image URL.
"""
rsp = await self.get_launcher_info()
return rsp["data"]["adv"]["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"]

View File

@ -0,0 +1,39 @@
import constants
from pathlib import Path
class Patcher:
def __init__(self, gamedir=Path.cwd()):
self._gamedir = gamedir
self._patch_url = constants.PATCH_GIT_URL
def override_patch_url(self, url) -> None:
"""
Override the patch url.
:param url: Patch repository url, the url must be a valid git repository.
:return: None
"""
self._patch_url = url
def download_patch(self) -> None:
"""
If `git` exists, this will clone the patch git url and save it to a temporary directory.
Else, this will download the patch from the patch url and save it to a temporary directory. (Not reliable)
:return: None
"""
pass
def apply_patch(self, crash_fix=False) -> None:
"""
Patch the game (and optionally patch the login door crash fix if specified)
:param crash_fix: Whether to patch the login door crash fix or not
:return: None
"""
pass
def revert_patch(self):
"""
Revert the patch (and revert the login door crash fix if patched)
:return: None
"""
pass