feat: support pre-downloading game & voicepacks

This commit is contained in:
tretrauit 2022-08-23 17:02:20 +07:00
parent 34a8ab6d99
commit 04dc922230
Signed by: tretrauit
GPG Key ID: CDDE1C97EE305DAF
5 changed files with 62 additions and 49 deletions

View File

@ -9,12 +9,12 @@ README = (HERE / "README.md").read_text()
setup(
name='worthless',
version='2.1.2-1',
version='2.2.0',
packages=['worthless', 'worthless.classes', 'worthless.classes.launcher', 'worthless.classes.installer'],
url='https://git.froggi.es/tretrauit/worthless-launcher',
license='MIT License',
author='tretrauit',
author_email='tretrauit@gmail.com',
author_email='tretrauit@cachyos.org',
description='A worthless CLI launcher written in Python.',
long_description=README,
long_description_content_type="text/markdown",

View File

@ -10,7 +10,10 @@ class Game:
@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)
try:
diffs = []
for diff in data['diffs']:
diffs.append(Diff.from_dict(diff))
return Game(Latest.from_dict(data['latest']), diffs, data)
except (KeyError, ValueError):
return data

View File

@ -27,4 +27,4 @@ class Resource:
@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)
Game.from_dict(data['pre_download_game']), data['deprecated_packages'], data['sdk'], data)

View File

@ -12,13 +12,16 @@ import worthless.constants as constants
class UI:
def __init__(self, gamedir: str, noconfirm: bool, tempdir: str | Path = None) -> None:
def __init__(self, gamedir: str, noconfirm: bool, tempdir: str | Path = None, pre_download=False) -> None:
self._vo_version = None
self._noconfirm = noconfirm
self._gamedir = gamedir
self._launcher = Launcher(gamedir)
self._installer = Installer(gamedir, data_dir=tempdir)
self._patcher = Patcher(gamedir, data_dir=tempdir)
self._pre_download = pre_download
if self._pre_download:
print("Pre-download is enabled, use at your own risk!")
def _ask(self, question):
if self._noconfirm:
@ -130,11 +133,11 @@ class UI:
async def download_game(self):
print("Downloading full game (This will take a long time)...")
await self._installer.download_full_game()
await self._installer.download_full_game(self._pre_download)
async def download_game_update(self):
print("Downloading game update (This will take a long time)...")
await self._installer.download_game_update()
await self._installer.download_game_update(pre_download=self._pre_download)
async def download_voiceover(self, languages: str):
res_info = await self._launcher.get_resource_info()
@ -143,7 +146,7 @@ class UI:
if not self._installer.voiceover_lang_translate(lng) == vo.language:
continue
print("Downloading voiceover pack for {} (This will take a long time)...".format(lng))
await self._installer.download_full_voiceover(lng)
await self._installer.download_full_voiceover(lng, pre_download=self._pre_download)
async def download_voiceover_update(self, languages: str):
res_info = await self._launcher.get_resource_info()
@ -152,17 +155,20 @@ class UI:
if not self._installer.voiceover_lang_translate(lng) == vo.language:
continue
print("Downloading voiceover update pack for {} (This will take a long time)...".format(lng))
await self._installer.download_voiceover_update(lng)
await self._installer.download_voiceover_update(lng, pre_download=self._pre_download)
async def install_game(self, forced: bool = False):
res_info = await self._launcher.get_resource_info()
print("Latest game version: {}".format(res_info.game.latest.version))
game = res_info.game
if self._pre_download:
game = res_info.pre_download_game
print("Latest game version: {}".format(game.latest.version))
if not self._ask("Do you want to install the game?"):
print("Aborting game installation process.")
return
await self.download_game()
print("Game archive:", res_info.game.latest.get_name())
await self._install_from_archive(self._installer.temp_path.joinpath(res_info.game.latest.get_name()), forced)
print("Game archive:", game.latest.get_name())
await self._install_from_archive(self._installer.temp_path.joinpath(game.latest.get_name()), forced)
async def install_voiceover(self, languages: str):
res_info = await self._launcher.get_resource_info()
@ -172,13 +178,12 @@ class UI:
continue
if not self._ask("Do you want to install this voiceover pack? ({})".format(lng)):
print("Aborting voiceover installation process.")
return
break
print("Downloading voiceover pack (This will take a long time)...")
await self._installer.download_full_voiceover(lng)
await self._installer.download_full_voiceover(lng, pre_download=self._pre_download)
await self._apply_voiceover_from_archive(
self._installer.temp_path.joinpath(vo.get_name())
)
break
async def update_game(self):
game_ver = await self._installer.get_game_version()
@ -188,15 +193,18 @@ class UI:
print("Current game installation detected: {}".format(game_ver))
diff_archive = await self._installer.get_game_diff_archive()
res_info = await self._launcher.get_resource_info()
game = res_info.game
if self._pre_download:
game = res_info.pre_download_game
if not diff_archive:
print("No game updates available.")
return
print("Latest game version: {}".format(res_info.game.latest.version))
print("Latest game version: {}".format(game.latest.version))
if not self._ask("Do you want to update the game?"):
print("Aborting game update process.")
return
print("Downloading game update (This will take a long time)...")
await self._installer.download_game_update()
await self._installer.download_game_update(pre_download=self._pre_download)
print("Installing game update...")
await self.install_from_file(self._installer.temp_path.joinpath(diff_archive.get_name()))
@ -213,7 +221,7 @@ class UI:
if self._installer.voiceover_lang_translate(lng, "locale") not in installed_voiceovers:
await self.install_voiceover(lng)
continue
diff_archive = await self._installer.get_voiceover_diff_archive(lng)
diff_archive = await self._installer.get_voiceover_diff_archive(lng, pre_download=self._pre_download)
if not diff_archive:
print("No voiceover updates available for {}.".format(lng))
continue
@ -221,7 +229,7 @@ class UI:
print("Aborting this voiceover language update process.")
continue
print("Downloading voiceover update (This may takes some time)...")
await self._installer.download_voiceover_update(lng)
await self._installer.download_voiceover_update(lng, pre_download=self._pre_download)
print("Installing voiceover update for {}...".format(lng))
await self._apply_voiceover_from_archive(self._installer.temp_path.joinpath(diff_archive.get_name()))
@ -293,14 +301,15 @@ async def main():
help="Update the voiceover pack only (or install if not found)")
parser.add_argument("-Syu", "--update-all", action="store_true",
help="Update the game and all installed voiceover packs (or install if not found)")
parser.add_argument("-Scc", "--clear-cache", action="store_true", help="Clear cache used by worthless")
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("-Rv", "--remove-voiceover", action="store_true", help="Remove a Voiceover pack (if installed)")
parser.add_argument("-V", "--verify", action="store_true", help="Verify the game installation")
parser.add_argument("--predownload", action="store_true", help="Download the game for the next update", default=False)
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("--check-telemetry", action="store_true", help="Check for the telemetry information")
parser.add_argument("--clear-cache", action="store_true", help="Clear cache used by worthless")
parser.add_argument("--from-ver", action="store", help="Override the detected game version", type=str, default=None)
parser.add_argument("--from-vo-ver", action="store", help="Override the detected game version for voiceover "
"detection", type=str, default=None)
@ -310,7 +319,7 @@ async def main():
if args.temporary_dir:
args.temporary_dir.mkdir(parents=True, exist_ok=True)
ui = UI(args.dir, args.noconfirm, args.temporary_dir)
ui = UI(args.dir, args.noconfirm, args.temporary_dir, args.predownload)
if args.install and args.update:
raise ValueError("Cannot specify both --install and --update arguments.")

View File

@ -389,19 +389,15 @@ class Installer:
self._config.set_game_version(version)
self._config.save()
async def download_full_game(self):
resource = await self._launcher.get_resource_info()
if resource is None:
raise RuntimeError("Failed to fetch game resource info.")
archive_name = resource.game.latest.path.split("/")[-1]
await self._download_file(resource.game.latest.path, archive_name, resource.game.latest.size)
async def download_full_game(self, pre_download=False):
game = await self._get_game(pre_download)
archive_name = game.latest.path.split("/")[-1]
await self._download_file(game.latest.path, archive_name, game.latest.size)
async def download_full_voiceover(self, language: str):
archive = await self._launcher.get_resource_info()
if archive is None:
raise RuntimeError("Failed to fetch game resource info.")
async def download_full_voiceover(self, language: str, pre_download=False):
game = await self._get_game(pre_download)
translated_lang = self.voiceover_lang_translate(language)
for vo in archive.game.latest.voice_packs:
for vo in game.latest.voice_packs:
if vo.language == translated_lang:
await self._download_file(vo.path, vo.get_name(), vo.size)
@ -452,52 +448,57 @@ class Installer:
raise ValueError("Could not fetch game resource")
return game_resource
async def download_game_update(self, from_version: str = None):
async def _get_game(self, pre_download=False):
game_resource = await self._get_game_resource()
game = game_resource.game
if pre_download:
game = game_resource.pre_download_game
return game
async def download_game_update(self, from_version: str = None, pre_download=False):
if not from_version:
from_version = await self._get_game_version()
version_info = await self._get_game_resource()
if self._version == version_info.game.latest.version:
game = await self._get_game(pre_download=pre_download)
if self._version == game.latest.version:
raise ValueError("Game is already up to date.")
diff_archive = await self.get_game_diff_archive(from_version)
diff_archive = await self.get_game_diff_archive(from_version, pre_download)
if diff_archive is None:
raise ValueError("Game diff archive is not available for this version, please reinstall.")
await self._download_file(diff_archive.path, diff_archive.name, diff_archive.size)
async def download_voiceover_update(self, language: str, from_version: str = None):
async def download_voiceover_update(self, language: str, from_version: str = None, pre_download=False):
if not from_version:
from_version = await self._get_game_version()
diff_archive = await self.get_voiceover_diff_archive(language, from_version)
diff_archive = await self.get_voiceover_diff_archive(language, from_version, pre_download)
if diff_archive is None:
raise ValueError("Voiceover diff archive is not available for this version, please reinstall.")
await self._download_file(diff_archive.path, diff_archive.name, diff_archive.size)
async def get_voiceover_diff_archive(self, lang: str, from_version: str = None):
async def get_voiceover_diff_archive(self, lang: str, from_version: str = None, pre_download=False):
"""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:
from_version = await self._get_game_version()
game_resource = await self._get_game_resource()
if not game_resource:
raise ValueError("Could not fetch game resource")
game = await self._get_game(pre_download=pre_download)
translated_lang = self.voiceover_lang_translate(lang)
for v in game_resource.game.diffs:
for v in game.diffs:
if v.version != from_version:
continue
for vo in v.voice_packs:
if vo.language == translated_lang:
return vo
async def get_game_diff_archive(self, from_version: str = None):
async def get_game_diff_archive(self, from_version: str = None, pre_download=False):
"""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:
from_version = await self._get_game_version()
game_resource = await self._get_game_resource()
for v in game_resource.game.diffs:
game = await self._get_game(pre_download=pre_download)
for v in game.diffs:
if v.version == from_version:
return v