diff --git a/vollerei/cli/hsr.py b/vollerei/cli/hsr.py
index c651ee2..fc5f052 100644
--- a/vollerei/cli/hsr.py
+++ b/vollerei/cli/hsr.py
@@ -1,8 +1,10 @@
+import traceback
from cleo.commands.command import Command
from cleo.helpers import option, argument
from copy import deepcopy
+from pathlib import PurePath
from platform import system
-from vollerei.hsr.launcher.enums import GameChannel
+from vollerei.common.enums import GameChannel
from vollerei.cli import utils
from vollerei.exceptions.game import GameError
from vollerei.hsr import Game, Patcher
@@ -434,11 +436,12 @@ class UpdateCommand(Command):
update_diff = State.game.get_update(pre_download=pre_download)
game_info = State.game.get_remote_game(pre_download=pre_download)
except Exception as e:
+ print(traceback.format_exc())
progress.finish(
f"Update checking failed with following error: {e} ({e.__context__})"
)
return
- if update_diff is None:
+ if update_diff is None or isinstance(game_info.major, str | None):
progress.finish("Game is already updated.")
return
progress.finish("Update available.")
@@ -446,16 +449,17 @@ class UpdateCommand(Command):
f"The current version is: {State.game.get_version_str()}"
)
self.line(
- f"The latest version is: {game_info.latest.version}"
+ f"The latest version is: {game_info.major.version}"
)
if not self.confirm("Do you want to update the game?"):
self.line("Update aborted.")
return
self.line("Downloading update package...")
- out_path = State.game.cache.joinpath(update_diff.name)
+ update_game_url = update_diff.game_pkgs[0].url
+ out_path = State.game.cache.joinpath(PurePath(update_game_url).name)
try:
download_result = utils.download(
- update_diff.path, out_path, file_len=update_diff.size
+ update_game_url, out_path, file_len=update_diff.game_pkgs[0].size
)
except Exception as e:
self.line_error(f"Couldn't download update: {e}")
@@ -478,14 +482,14 @@ class UpdateCommand(Command):
# Get installed voicepacks
installed_voicepacks = State.game.get_installed_voicepacks()
# Voicepack update
- for remote_voicepack in update_diff.voice_packs:
+ for remote_voicepack in update_diff.audio_pkgs:
if remote_voicepack.language not in installed_voicepacks:
continue
# Voicepack is installed, update it
- archive_file = State.game.cache.joinpath(remote_voicepack.name)
+ archive_file = State.game.cache.joinpath(PurePath(remote_voicepack.url).name)
try:
download_result = utils.download(
- remote_voicepack.path, archive_file, file_len=update_diff.size
+ remote_voicepack.url, archive_file, file_len=remote_voicepack.size
)
except Exception as e:
self.line_error(f"Couldn't download update: {e}")
diff --git a/vollerei/common/api/__init__.py b/vollerei/common/api/__init__.py
index a5c2823..b556abb 100644
--- a/vollerei/common/api/__init__.py
+++ b/vollerei/common/api/__init__.py
@@ -1,4 +1,35 @@
-from vollerei.common.api.resource import Resource
+import requests
+from vollerei.common.api import resource
+from vollerei.common.enums import GameChannel
+from vollerei.constants import LAUNCHER_API
-__all__ = ["Resource"]
+__all__ = ["GamePackage"]
+
+
+def get_game_packages(
+ channel: GameChannel = GameChannel.Overseas,
+) -> list[resource.GameInfo]:
+ """
+ Get game packages information from the launcher API.
+
+ Default channel is overseas.
+
+ Args:
+ channel: Game channel to get the resource information from.
+
+ Returns:
+ Resource: Game resource information.
+ """
+ resource_path: dict = None
+ match channel:
+ case GameChannel.Overseas:
+ resource_path = LAUNCHER_API.OS
+ case GameChannel.China:
+ resource_path = LAUNCHER_API.CN
+ return resource.from_dict(
+ requests.get(
+ resource_path["url"] + LAUNCHER_API.RESOURCE_PATH,
+ params=resource_path["params"],
+ ).json()["data"]
+ )
diff --git a/vollerei/common/api/resource.py b/vollerei/common/api/resource.py
index e323eda..1a3e357 100644
--- a/vollerei/common/api/resource.py
+++ b/vollerei/common/api/resource.py
@@ -1,409 +1,134 @@
-"""
-Class wrapper for API endpoint /resource
-"""
-
from vollerei.common.enums import VoicePackLanguage
-class Segment:
- """
- A segment of the game archive.
-
- Attributes:
- path (str): Segment download path.
- md5 (str): Segment md5 checksum.
- package_size (int | None): Segment package size.
- """
-
- path: str
- md5: str
- # str -> int and checked if int is 0 then None
- package_size: int | None
-
- def __init__(self, path: str, md5: str, package_size: int | None) -> None:
- self.path = path
- self.md5 = md5
- self.package_size = package_size
-
- @staticmethod
- def from_dict(data: dict) -> "Segment":
- return Segment(
- data["path"],
- data["md5"],
- (
- int(data["package_size"])
- if data["package_size"] and data["package_size"] != "0"
- else None
- ),
- )
-
-
-class VoicePack:
- """
- Voice pack information
-
- `name` maybe converted from `path` if the server returns empty string.
-
- Attributes:
- language (VoicePackLanguage): Language of the voice pack.
- name (str): Voice pack archive name.
- path (str): Voice pack download path.
- size (int): Voice pack size.
- md5 (str): Voice pack md5 checksum.
- package_size (int): Voice pack package size.
- """
-
- language: VoicePackLanguage
- name: str
- path: str
- # str -> int
- size: int
- md5: str
- # str -> int
- package_size: int
-
- def __init__(
- self,
- language: VoicePackLanguage,
- name: str,
- path: str,
- size: int,
- md5: str,
- package_size: int,
- ) -> None:
- self.language = language
- self.name = name
- self.path = path
- self.size = size
- self.md5 = md5
- self.package_size = package_size
-
- @staticmethod
- def from_dict(data: dict) -> "VoicePack":
- return VoicePack(
- VoicePackLanguage.from_remote_str(data["language"]),
- data["name"],
- data["path"],
- int(data["size"]),
- data["md5"],
- int(data["package_size"]),
- )
-
-
-class Diff:
- """
- Game resource diff from a version to latest information
-
- Attributes:
- TODO
- """
-
- name: str
- version: str
- path: str
- # str -> int
- size: int
- md5: str
- is_recommended_update: bool
- voice_packs: list[VoicePack]
- # str -> int
- package_size: int
-
- def __init__(
- self,
- name: str,
- version: str,
- path: str,
- size: int,
- md5: str,
- is_recommended_update: bool,
- voice_packs: list[VoicePack],
- package_size: int,
- ) -> None:
- 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.package_size = package_size
-
- @staticmethod
- def from_dict(data: dict) -> "Diff":
- return Diff(
- data["name"],
- data["version"],
- data["path"],
- int(data["size"]),
- data["md5"],
- data["is_recommended_update"],
- [VoicePack.from_dict(i) for i in data["voice_packs"]],
- int(data["package_size"]),
- )
-
-
-class Latest:
- """
- Latest game resource information
-
- `name` maybe converted from `path` if the server returns empty string,
- and if `path` is empty too then it'll convert the name from the first
- segment of `segments` list.
-
- `path` maybe None if the server returns empty string, in that case
- you'll have to download the game using `segments` list and merge them.
-
- `voice_packs` will be empty for Star Rail, they force you to download
- in-game instead.
-
- `decompressed_path` is useful for repairing game files by only having
- to re-download the corrupted files.
-
- `segments` is a list of game archive segments, you'll have to download
- them and merge them together to get the full game archive. Not available
- on Star Rail.
-
- Attributes:
- name (str): Game archive name.
- version (str): Game version in the archive.
- path (str | None): Game archive download path.
- size (int): Game archive size in bytes.
- md5 (str): Game archive MD5 checksum.
- entry (str): Game entry file (e.g. GenshinImpact.exe).
- voice_packs (list[VoicePack]): Game voice packs.
- decompressed_path (str | None): Game archive decompressed path.
- segments (list[Segment]): Game archive segments.
- package_size (int): Game archive package size in bytes.
- """
-
- name: str
- version: str
- path: str | None
- # str -> int
- size: int
- md5: str
- entry: str
- voice_packs: list[VoicePack]
- # str but checked for empty string
- decompressed_path: str | None
- segments: list[Segment]
- # str -> int
- package_size: int
-
- def __init__(
- self,
- name: str,
- version: str,
- path: str,
- size: int,
- md5: str,
- entry: str,
- voice_packs: list[VoicePack],
- decompressed_path: str | None,
- segments: list[Segment],
- package_size: int,
- ) -> None:
- 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.package_size = package_size
-
- @staticmethod
- def from_dict(data: dict) -> "Latest":
- if data["name"] == "":
- if data["path"] == "":
- data["name"] = data["segments"][0]["path"].split("/")[-1]
- else:
- data["name"] = data["path"].split("/")[-1]
- return Latest(
- data["name"],
- data["version"],
- data["path"] if data["path"] != "" else None,
- int(data["size"]),
- data["md5"],
- data["entry"],
- [VoicePack.from_dict(i) for i in data["voice_packs"]],
- data["decompressed_path"] if data["decompressed_path"] != "" else None,
- [Segment.from_dict(i) for i in data["segments"]],
- int(data["package_size"]),
- )
-
-
class Game:
- latest: Latest
- diffs: list[Diff]
-
- def __init__(self, latest: Latest, diffs: list[Diff]) -> None:
- self.latest = latest
- self.diffs = diffs
+ def __init__(self, id: str, biz: str):
+ self.id = id
+ self.biz = biz
@staticmethod
def from_dict(data: dict) -> "Game":
- return Game(
- Latest.from_dict(data["latest"]), [Diff.from_dict(i) for i in data["diffs"]]
- )
+ return Game(id=data["id"], biz=data["biz"])
-class Plugin:
- name: str
- # str but checked for empty string
- version: str | None
- path: str
- # str -> int
- size: int
- md5: str
- # str but checked for empty string
- entry: str | None
- # str -> int
- package_size: int
-
- def __init__(
- self,
- name: str,
- version: str | None,
- path: str,
- size: int,
- md5: str,
- entry: str | None,
- package_size: int,
- ) -> None:
- self.name = name
- self.version = version
- self.path = path
+class GamePackage:
+ def __init__(self, url: str, md5: str, size: int, decompressed_size: int):
+ self.url = url
+ self.md5 = md5
self.size = size
- self.md5 = md5
- self.entry = entry
- self.package_size = package_size
+ self.decompressed_size = decompressed_size
@staticmethod
- def from_dict(data: dict) -> "Plugin":
- return Plugin(
- data["name"],
- data["version"] if data["version"] != "" else None,
- data["path"],
- int(data["size"]),
- data["md5"],
- data["entry"] if data["entry"] != "" else None,
- int(data["package_size"]),
+ def from_dict(data: dict) -> "GamePackage":
+ return GamePackage(
+ url=data["url"],
+ md5=data["md5"],
+ size=int(data["size"]),
+ decompressed_size=int(data["decompressed_size"]),
)
-class LauncherPlugin:
- plugins: list[Plugin]
- # str -> int
- version: int
-
- def __init__(self, plugins: list[Plugin], version: int) -> None:
- self.plugins = plugins
- self.version = version
-
- @staticmethod
- def from_dict(data: dict) -> "LauncherPlugin":
- return LauncherPlugin(
- [Plugin.from_dict(i) for i in data["plugins"]], int(data["version"])
- )
-
-
-class DeprecatedPackage:
- name: str
- md5: str
-
- def __init__(self, name: str, md5: str) -> None:
- self.name = name
- self.md5 = md5
-
- @staticmethod
- def from_dict(data: dict) -> "DeprecatedPackage":
- return DeprecatedPackage(data["name"], data["md5"])
-
-
-class DeprecatedFile:
- path: str
- # str but checked for empty string
- md5: str | None
-
- def __init__(self, path: str, md5: str | None) -> None:
- self.path = path
- self.md5 = md5
-
- @staticmethod
- def from_dict(data: dict) -> "DeprecatedFile":
- return DeprecatedFile(data["path"], data["md5"] if data["md5"] != "" else None)
-
-
-class Resource:
- """
- Data class for /resource endpoint
-
- I'm still unclear about `force_update` and `sdk` attributes, so I'll
- leave them as None for now.
-
- Attributes:
- game (Game): Game resource information.
- plugin (LauncherPlugin): Launcher plugin information.
- web_url (str): Game official launcher web URL.
- force_update (None): Not used by official launcher I guess?
- pre_download_game (Game | None): Pre-download game resource information.
- deprecated_packages (list[DeprecatedPackage]): Deprecated game packages.
- sdk (None): Maybe for Bilibili version of Genshin?
- deprecated_files (list[DeprecatedFile]): Deprecated game files.
- """
-
- # I'm generous enough to convert the string into int
- # for you guys, wtf Mihoyo?
- game: Game
- # ?? Mihoyo for plugin["plugins"] which is a list of Plugin objects
- plugin: LauncherPlugin
- web_url: str
- # ?? Mihoyo
- force_update: None
- # Will be a Game object if a pre-download is available.
- pre_download_game: Game | None
- deprecated_packages: list[DeprecatedPackage]
- # Maybe a SDK for Bilibili version in Genshin?
- sdk: None
- deprecated_files: list[DeprecatedFile]
-
+class AudioPackage:
def __init__(
self,
- game: Game,
- plugin: Plugin,
- web_url: str,
- force_update: None,
- pre_download_game: Game | None,
- deprecated_packages: list[DeprecatedPackage],
- sdk: None,
- deprecated_files: list[DeprecatedFile],
- ) -> None:
- 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.deprecated_files = deprecated_files
+ language: VoicePackLanguage,
+ url: str,
+ md5: str,
+ size: int,
+ decompressed_size: int,
+ ):
+ self.language = language
+ self.url = url
+ self.md5 = md5
+ self.size = size
+ self.decompressed_size = decompressed_size
@staticmethod
- def from_dict(json: dict) -> "Resource":
- return Resource(
- Game.from_dict(json["game"]),
- LauncherPlugin.from_dict(json["plugin"]),
- json["web_url"],
- json["force_update"],
- (
- Game.from_dict(json["pre_download_game"])
- if json["pre_download_game"]
- else None
- ),
- [DeprecatedPackage.from_dict(x) for x in json["deprecated_packages"]],
- json["sdk"],
- [DeprecatedFile.from_dict(x) for x in json["deprecated_files"]],
+ def from_dict(data: dict) -> "AudioPackage":
+ return AudioPackage(
+ language=VoicePackLanguage.from_remote_str(data["language"]),
+ url=data["url"],
+ md5=data["md5"],
+ size=int(data["size"]),
+ decompressed_size=int(data["decompressed_size"]),
)
+
+
+class Major:
+ def __init__(
+ self,
+ version: str,
+ game_pkgs: list[GamePackage],
+ audio_pkgs: list[AudioPackage],
+ res_list_url: str,
+ ):
+ self.version = version
+ self.game_pkgs = game_pkgs
+ self.audio_pkgs = audio_pkgs
+ self.res_list_url = res_list_url
+
+ @staticmethod
+ def from_dict(data: dict) -> "Major":
+ return Major(
+ version=data["version"],
+ game_pkgs=[GamePackage(**x) for x in data["game_pkgs"]],
+ audio_pkgs=[AudioPackage(**x) for x in data["audio_pkgs"]],
+ res_list_url=data["res_list_url"],
+ )
+
+
+# Currently patch has the same fields as major
+Patch = Major
+
+
+class Main:
+ def __init__(self, major: Major, patches: list[Patch]):
+ self.major = major
+ self.patches = patches
+
+ @staticmethod
+ def from_dict(data: dict) -> "Main":
+ return Main(
+ major=Major.from_dict(data["major"]),
+ patches=[Patch.from_dict(x) for x in data["patches"]],
+ )
+
+
+class PreDownload:
+ def __init__(self, major: Major | str | None, patches: list[Patch]):
+ self.major = major
+ self.patches = patches
+
+ @staticmethod
+ def from_dict(data: dict) -> "PreDownload":
+ return PreDownload(
+ major=(
+ data["major"]
+ if isinstance(data["major"], str | None)
+ else Major.from_dict(data["major"])
+ ),
+ patches=[Patch.from_dict(x) for x in data["patches"]],
+ )
+
+
+# Why miHoYo uses the same name "game_packages" for this big field and smol field
+class GameInfo:
+ def __init__(self, game: Game, main: Main, pre_download: PreDownload):
+ self.game = game
+ self.main = main
+ self.pre_download = pre_download
+
+ @staticmethod
+ def from_dict(data: dict) -> "GameInfo":
+ return GameInfo(
+ game=Game.from_dict(data["game"]),
+ main=Main.from_dict(data["main"]),
+ pre_download=PreDownload.from_dict(data["pre_download"]),
+ )
+
+
+def from_dict(data: dict) -> list[GameInfo]:
+ game_pkgs = []
+ for pkg in data["game_packages"]:
+ game_pkgs.append(GameInfo.from_dict(pkg))
+ return game_pkgs
diff --git a/vollerei/common/enums.py b/vollerei/common/enums.py
index 2ae981c..9f8e24a 100644
--- a/vollerei/common/enums.py
+++ b/vollerei/common/enums.py
@@ -1,6 +1,11 @@
from enum import Enum
+class GameChannel(Enum):
+ Overseas = 0
+ China = 1
+
+
class VoicePackLanguage(Enum):
Japanese = "ja-jp"
Chinese = "zh-cn"
diff --git a/vollerei/constants.py b/vollerei/constants.py
index 43a5de1..598a0a3 100644
--- a/vollerei/constants.py
+++ b/vollerei/constants.py
@@ -1,3 +1,21 @@
+class LAUNCHER_API:
+ """Launcher API constants."""
+
+ RESOURCE_PATH: str = "hyp/hyp-connect/api/getGamePackages"
+ OS: dict = {
+ "url": "https://sg-hyp-api.hoyoverse.com/",
+ "params": {
+ "launcher_id": "VYTpXlbWo8",
+ },
+ }
+ CN: dict = {
+ "url": "https://hyp-api.mihoyo.com/",
+ "params": {
+ "launcher_id": "jGHBHlcOq1",
+ },
+ }
+
+
TELEMETRY_HOSTS = [
# Global
"log-upload-os.hoyoverse.com",
diff --git a/vollerei/hi3/constants.py b/vollerei/hi3/constants.py
deleted file mode 100644
index 54fceae..0000000
--- a/vollerei/hi3/constants.py
+++ /dev/null
@@ -1,24 +0,0 @@
-class LAUNCHER_API:
- """Launcher API constants."""
-
- RESOURCE_PATH: str = "mdk/launcher/api/resource"
- OS: dict = {
- "url": "https://hkrpg-launcher-static.hoyoverse.com/hkrpg_global/",
- "params": {
- "channel_id": 1,
- "key": "vplOVX8Vn7cwG8yb",
- "launcher_id": 35,
- },
- }
- ASIA: dict = {}
- CN: dict = {
- "url": "https://api-launcher.mihoyo.com/hkrpg_cn/mdk/launcher/api/resource",
- "params": {
- "channel_id": 1,
- "key": "6KcVuOkbcqjJomjZ",
- "launcher_id": 33,
- },
- }
-
-
-LATEST_VERSION = (7, 2, 0)
diff --git a/vollerei/hi3/launcher/enums.py b/vollerei/hi3/launcher/enums.py
deleted file mode 100644
index fe1f2e0..0000000
--- a/vollerei/hi3/launcher/enums.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from enum import Enum
-
-
-class GameChannel(Enum):
- Global = 0
- Asia = 1
- Taiwan = 2
- Korea = 3
- China = 4
diff --git a/vollerei/hsr/constants.py b/vollerei/hsr/constants.py
index 6617df9..3977b25 100644
--- a/vollerei/hsr/constants.py
+++ b/vollerei/hsr/constants.py
@@ -1,26 +1,4 @@
-class LAUNCHER_API:
- """Launcher API constants."""
-
- RESOURCE_PATH: str = "mdk/launcher/api/resource"
- OS: dict = {
- "url": "https://hkrpg-launcher-static.hoyoverse.com/hkrpg_global/",
- "params": {
- "channel_id": 1,
- "key": "vplOVX8Vn7cwG8yb",
- "launcher_id": 35,
- },
- }
- CN: dict = {
- "url": "https://api-launcher.mihoyo.com/hkrpg_cn/mdk/launcher/api/resource",
- "params": {
- "channel_id": 1,
- "key": "6KcVuOkbcqjJomjZ",
- "launcher_id": 33,
- },
- }
-
-
-LATEST_VERSION = (1, 6, 0)
+LATEST_VERSION = (2, 5, 0)
MD5SUMS = {
"1.0.5": {
"cn": {
diff --git a/vollerei/hsr/launcher/api.py b/vollerei/hsr/launcher/api.py
index 69598f9..f7864f9 100644
--- a/vollerei/hsr/launcher/api.py
+++ b/vollerei/hsr/launcher/api.py
@@ -1,13 +1,10 @@
-import requests
-
-from vollerei.common.api import Resource
-from vollerei.hsr.constants import LAUNCHER_API
-from vollerei.hsr.launcher.enums import GameChannel
+from vollerei.common.api import get_game_packages, resource
+from vollerei.common.enums import GameChannel
-def get_resource(channel: GameChannel = GameChannel.Overseas) -> Resource:
+def get_game_package(channel: GameChannel = GameChannel.Overseas) -> resource.GameInfo:
"""
- Get game resource information from the launcher API.
+ Get game package information from the launcher API.
Default channel is overseas.
@@ -17,15 +14,7 @@ def get_resource(channel: GameChannel = GameChannel.Overseas) -> Resource:
Returns:
Resource: Game resource information.
"""
- resource_path: dict = None
- match channel:
- case GameChannel.Overseas:
- resource_path = LAUNCHER_API.OS
- case GameChannel.China:
- resource_path = LAUNCHER_API.CN
- return Resource.from_dict(
- requests.get(
- resource_path["url"] + LAUNCHER_API.RESOURCE_PATH,
- params=resource_path["params"],
- ).json()["data"]
- )
+ game_packages = get_game_packages(channel=channel)
+ for package in game_packages:
+ if "hkrpg" in package.game.biz:
+ return package
diff --git a/vollerei/hsr/launcher/enums.py b/vollerei/hsr/launcher/enums.py
deleted file mode 100644
index 4726217..0000000
--- a/vollerei/hsr/launcher/enums.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from enum import Enum
-
-
-class GameChannel(Enum):
- Overseas = 0
- China = 1
diff --git a/vollerei/hsr/launcher/game.py b/vollerei/hsr/launcher/game.py
index 6c2669c..57be18f 100644
--- a/vollerei/hsr/launcher/game.py
+++ b/vollerei/hsr/launcher/game.py
@@ -3,12 +3,12 @@ from configparser import ConfigParser
from hashlib import md5
from io import IOBase
from os import PathLike
-from pathlib import Path
+from pathlib import Path, PurePath
from shutil import move, copyfile
from vollerei.abc.launcher.game import GameABC
from vollerei.common import ConfigFile, functions
from vollerei.common.api import resource
-from vollerei.common.enums import VoicePackLanguage
+from vollerei.common.enums import VoicePackLanguage, GameChannel
from vollerei.exceptions.game import (
GameAlreadyUpdatedError,
GameNotInstalledError,
@@ -16,7 +16,6 @@ from vollerei.exceptions.game import (
ScatteredFilesNotAvailableError,
)
from vollerei.hsr.constants import MD5SUMS
-from vollerei.hsr.launcher.enums import GameChannel
from vollerei.hsr.launcher import api
from vollerei import paths
from vollerei.utils import download
@@ -189,7 +188,7 @@ class Game(GameABC):
cfg_file = self._path.joinpath("config.ini")
if cfg_file.exists():
cfg = ConfigFile(cfg_file)
- cfg.set("General", "game_version", self.get_version_str())
+ cfg.set("general", "game_version", self.get_version_str())
cfg.save()
else:
cfg = ConfigParser()
@@ -307,7 +306,7 @@ class Game(GameABC):
pass
return voicepacks
- def get_remote_game(self, pre_download: bool = False) -> resource.Game:
+ def get_remote_game(self, pre_download: bool = False) -> resource.Main | resource.PreDownload:
"""
Gets the current game information from remote.
@@ -316,17 +315,17 @@ class Game(GameABC):
Defaults to False.
Returns:
- A `Game` object that contains the game information.
+ A `Main` or `PreDownload` object that contains the game information.
"""
channel = self._channel_override or self.get_channel()
if pre_download:
- game = api.get_resource(channel=channel).pre_download_game
+ game = api.get_game_package(channel=channel).pre_download
if not game:
raise PreDownloadNotAvailable("Pre-download version is not available.")
return game
- return api.get_resource(channel=channel).game
+ return api.get_game_package(channel=channel).main
- def get_update(self, pre_download: bool = False) -> resource.Diff | None:
+ def get_update(self, pre_download: bool = False) -> resource.Patch | None:
"""
Gets the current game update.
@@ -335,7 +334,7 @@ class Game(GameABC):
Defaults to False.
Returns:
- A `Diff` object that contains the update information or
+ A `Patch` object that contains the update information or
`None` if the game is not installed or already up-to-date.
"""
if not self.is_installed():
@@ -345,9 +344,9 @@ class Game(GameABC):
if self._version_override
else self.get_version_str()
)
- for diff in self.get_remote_game(pre_download=pre_download).diffs:
- if diff.version == version:
- return diff
+ for patch in self.get_remote_game(pre_download=pre_download).patches:
+ if patch.version == version:
+ return patch
return None
def _repair_file(self, file: PathLike, game: resource.Game) -> None:
@@ -486,10 +485,10 @@ class Game(GameABC):
functions.apply_update_archive(self, archive_file, auto_repair=auto_repair)
def install_update(
- self, update_info: resource.Diff = None, auto_repair: bool = True
+ self, update_info: resource.Patch = None, auto_repair: bool = True
):
"""
- Installs an update from a `Diff` object.
+ Installs an update from a `Patch` object.
You may want to download the update manually and pass it to
`apply_update_archive()` instead for better control, and after that
@@ -506,19 +505,20 @@ class Game(GameABC):
update_info = self.get_update()
if not update_info or update_info.version == self.get_version_str():
raise GameAlreadyUpdatedError("Game is already updated.")
+ update_url = update_info.game_pkgs[0].url
# Base game update
- archive_file = self.cache.joinpath(update_info.name)
- download(update_info.path, archive_file)
+ archive_file = self.cache.joinpath(PurePath(update_url).name)
+ download(update_url, archive_file)
self.apply_update_archive(archive_file=archive_file, auto_repair=auto_repair)
# Get installed voicepacks
installed_voicepacks = self.get_installed_voicepacks()
# Voicepack update
- for remote_voicepack in update_info.voice_packs:
+ for remote_voicepack in update_info.audio_pkgs:
if remote_voicepack.language not in installed_voicepacks:
continue
# Voicepack is installed, update it
- archive_file = self.cache.joinpath(remote_voicepack.name)
- download(remote_voicepack.path, archive_file)
+ archive_file = self.cache.joinpath(PurePath(remote_voicepack.url).name)
+ download(remote_voicepack.url, archive_file)
self.apply_update_archive(
archive_file=archive_file, auto_repair=auto_repair
)
diff --git a/vollerei/utils/hdiffpatch/__init__.py b/vollerei/utils/hdiffpatch/__init__.py
index ba66684..07216ed 100644
--- a/vollerei/utils/hdiffpatch/__init__.py
+++ b/vollerei/utils/hdiffpatch/__init__.py
@@ -34,6 +34,8 @@ class HDiffPatch:
return "windows32"
case "x86_64":
return "windows64"
+ case "AMD64":
+ return "windows64"
case "arm":
return "windows_arm32"
case "arm64":