Compare commits
No commits in common. "5b916025f37f8351ea5f3956b64fc1b48bfabcc7" and "891cf71aa793d7378bd3d15cab547e6ef4aa5714" have entirely different histories.
5b916025f3
...
891cf71aa7
@ -3,33 +3,26 @@ from vollerei import __version__
|
||||
from vollerei.cli.hsr import HSR
|
||||
from vollerei.hsr import PatchType
|
||||
from vollerei.cli import utils
|
||||
from vollerei.cli.utils import msg
|
||||
|
||||
|
||||
class CLI:
|
||||
def __init__(
|
||||
self,
|
||||
game_path: str = None,
|
||||
patch_type=None,
|
||||
noconfirm: bool = False,
|
||||
silent: bool = False,
|
||||
self, game_path: str = None, patch_type=None, noconfirm: bool = False
|
||||
) -> None:
|
||||
"""
|
||||
Vollerei CLI
|
||||
"""
|
||||
utils.silent_message = silent
|
||||
msg(f"Vollerei v{__version__}")
|
||||
print(f"Vollerei v{__version__}")
|
||||
if noconfirm:
|
||||
msg("User requested to automatically answer yes to all questions.")
|
||||
print("User requested to automatically answer yes to all questions.")
|
||||
utils.no_confirm = noconfirm
|
||||
if not game_path:
|
||||
game_path = Path.cwd()
|
||||
game_path = Path(game_path)
|
||||
hsr_patch_type = patch_type
|
||||
if patch_type is None:
|
||||
hsr_patch_type = PatchType.Jadeite
|
||||
patch_type = PatchType.Jadeite
|
||||
elif isinstance(patch_type, str):
|
||||
hsr_patch_type = PatchType[patch_type]
|
||||
patch_type = PatchType[patch_type]
|
||||
elif isinstance(patch_type, int):
|
||||
hsr_patch_type = PatchType(patch_type)
|
||||
self.hsr = HSR(game_path=game_path, patch_type=hsr_patch_type)
|
||||
patch_type = PatchType(patch_type)
|
||||
self.hsr = HSR(game_path=game_path, patch_type=patch_type)
|
||||
|
@ -1,6 +1,6 @@
|
||||
from traceback import print_exc
|
||||
from platform import system
|
||||
from vollerei.cli.utils import ask, msg
|
||||
from vollerei.cli.utils import ask
|
||||
from vollerei.hsr import Game, Patcher
|
||||
from vollerei.exceptions.patcher import PatcherError, PatchUpdateError
|
||||
from vollerei.hsr.patcher import PatchType
|
||||
@ -11,8 +11,8 @@ class HSR:
|
||||
self, game_path=None, patch_type: PatchType = PatchType.Jadeite
|
||||
) -> None:
|
||||
self._game = Game(game_path)
|
||||
msg("Game directory:", self._game.path)
|
||||
msg("Game version:", self._game.get_version_str())
|
||||
print("Game directory:", self._game.path)
|
||||
print("Game version:", self._game.get_version_str())
|
||||
self._patcher = Patcher()
|
||||
self._patcher.patch_type = patch_type
|
||||
|
||||
@ -115,6 +115,3 @@ class HSR:
|
||||
self.__patch_jadeite()
|
||||
case PatchType.Astra:
|
||||
self.__patch_astra()
|
||||
|
||||
def get_version(self):
|
||||
print(self._game.get_version_str())
|
||||
|
@ -1,5 +1,4 @@
|
||||
no_confirm = False
|
||||
silent_message = False
|
||||
|
||||
|
||||
def ask(question: str):
|
||||
@ -13,12 +12,3 @@ def ask(question: str):
|
||||
# Pacman way, treat all other answers as no
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def msg(*args, **kwargs):
|
||||
"""
|
||||
Print but silentable
|
||||
"""
|
||||
if silent_message:
|
||||
return
|
||||
print(*args, **kwargs)
|
||||
|
@ -4,35 +4,11 @@ Class wrapper for API endpoint /resource
|
||||
|
||||
|
||||
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:
|
||||
"""
|
||||
@ -41,12 +17,7 @@ class VoicePack:
|
||||
`name` maybe converted from `path` if the server returns empty string.
|
||||
|
||||
Attributes:
|
||||
language (str): 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.
|
||||
TODO
|
||||
"""
|
||||
|
||||
language: str
|
||||
@ -58,33 +29,6 @@ class VoicePack:
|
||||
# str -> int
|
||||
package_size: int
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
language: str,
|
||||
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(
|
||||
data["language"],
|
||||
data["name"],
|
||||
data["path"],
|
||||
int(data["size"]),
|
||||
data["md5"],
|
||||
int(data["package_size"]),
|
||||
)
|
||||
|
||||
|
||||
class Diff:
|
||||
"""
|
||||
@ -105,39 +49,6 @@ class Diff:
|
||||
# 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:
|
||||
"""
|
||||
@ -147,35 +58,13 @@ class Latest:
|
||||
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.
|
||||
TODO
|
||||
"""
|
||||
|
||||
name: str
|
||||
version: str
|
||||
path: str | None
|
||||
path: str
|
||||
# str -> int
|
||||
size: int
|
||||
md5: str
|
||||
@ -221,14 +110,14 @@ class Latest:
|
||||
return Latest(
|
||||
data["name"],
|
||||
data["version"],
|
||||
data["path"] if data["path"] != "" else None,
|
||||
int(data["size"]),
|
||||
data["path"],
|
||||
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,
|
||||
data["decompressed_path"],
|
||||
[Segment.from_dict(i) for i in data["segments"]],
|
||||
int(data["package_size"]),
|
||||
data["package_size"],
|
||||
)
|
||||
|
||||
|
||||
@ -260,96 +149,27 @@ class Plugin:
|
||||
# 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
|
||||
self.size = size
|
||||
self.md5 = md5
|
||||
self.entry = entry
|
||||
self.package_size = package_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"]),
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
@ -378,6 +198,14 @@ class Resource:
|
||||
sdk: None,
|
||||
deprecated_files: list[DeprecatedFile],
|
||||
) -> None:
|
||||
# Fixups
|
||||
game_latest_path = game.latest.path
|
||||
if game.latest.name == "":
|
||||
print("A")
|
||||
if game_latest_path == "":
|
||||
game.latest.name = game.latest.segments[0].path.split("/")[-1]
|
||||
else:
|
||||
game.latest.name = game_latest_path.split("/")[-1]
|
||||
self.game = game
|
||||
self.plugin = plugin
|
||||
self.web_url = web_url
|
||||
|
@ -10,7 +10,7 @@ def get_resource(channel: GameChannel = GameChannel.Overseas) -> Resource:
|
||||
Get game resource information from the launcher API.
|
||||
|
||||
Args:
|
||||
channel: Game channel to get the resource information from.
|
||||
channel: Game channel to get the resource information from. (os, cn)
|
||||
|
||||
Returns:
|
||||
Resource: Game resource information.
|
||||
|
Loading…
Reference in New Issue
Block a user