feat: support pre-downloading game & voicepacks
This commit is contained in:
parent
34a8ab6d99
commit
04dc922230
4
setup.py
4
setup.py
@ -9,12 +9,12 @@ README = (HERE / "README.md").read_text()
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='worthless',
|
name='worthless',
|
||||||
version='2.1.2-1',
|
version='2.2.0',
|
||||||
packages=['worthless', 'worthless.classes', 'worthless.classes.launcher', 'worthless.classes.installer'],
|
packages=['worthless', 'worthless.classes', 'worthless.classes.launcher', 'worthless.classes.installer'],
|
||||||
url='https://git.froggi.es/tretrauit/worthless-launcher',
|
url='https://git.froggi.es/tretrauit/worthless-launcher',
|
||||||
license='MIT License',
|
license='MIT License',
|
||||||
author='tretrauit',
|
author='tretrauit',
|
||||||
author_email='tretrauit@gmail.com',
|
author_email='tretrauit@cachyos.org',
|
||||||
description='A worthless CLI launcher written in Python.',
|
description='A worthless CLI launcher written in Python.',
|
||||||
long_description=README,
|
long_description=README,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
|
@ -10,7 +10,10 @@ class Game:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(data):
|
def from_dict(data):
|
||||||
|
try:
|
||||||
diffs = []
|
diffs = []
|
||||||
for diff in data['diffs']:
|
for diff in data['diffs']:
|
||||||
diffs.append(Diff.from_dict(diff))
|
diffs.append(Diff.from_dict(diff))
|
||||||
return Game(Latest.from_dict(data['latest']), diffs, data)
|
return Game(Latest.from_dict(data['latest']), diffs, data)
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
return data
|
||||||
|
@ -27,4 +27,4 @@ class Resource:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(data):
|
def from_dict(data):
|
||||||
return Resource(Game.from_dict(data['game']), data['plugin'], data['web_url'], data['force_update'],
|
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)
|
||||||
|
@ -12,13 +12,16 @@ import worthless.constants as constants
|
|||||||
|
|
||||||
|
|
||||||
class UI:
|
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._vo_version = None
|
||||||
self._noconfirm = noconfirm
|
self._noconfirm = noconfirm
|
||||||
self._gamedir = gamedir
|
self._gamedir = gamedir
|
||||||
self._launcher = Launcher(gamedir)
|
self._launcher = Launcher(gamedir)
|
||||||
self._installer = Installer(gamedir, data_dir=tempdir)
|
self._installer = Installer(gamedir, data_dir=tempdir)
|
||||||
self._patcher = Patcher(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):
|
def _ask(self, question):
|
||||||
if self._noconfirm:
|
if self._noconfirm:
|
||||||
@ -130,11 +133,11 @@ class UI:
|
|||||||
|
|
||||||
async def download_game(self):
|
async def download_game(self):
|
||||||
print("Downloading full game (This will take a long time)...")
|
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):
|
async def download_game_update(self):
|
||||||
print("Downloading game update (This will take a long time)...")
|
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):
|
async def download_voiceover(self, languages: str):
|
||||||
res_info = await self._launcher.get_resource_info()
|
res_info = await self._launcher.get_resource_info()
|
||||||
@ -143,7 +146,7 @@ class UI:
|
|||||||
if not self._installer.voiceover_lang_translate(lng) == vo.language:
|
if not self._installer.voiceover_lang_translate(lng) == vo.language:
|
||||||
continue
|
continue
|
||||||
print("Downloading voiceover pack for {} (This will take a long time)...".format(lng))
|
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):
|
async def download_voiceover_update(self, languages: str):
|
||||||
res_info = await self._launcher.get_resource_info()
|
res_info = await self._launcher.get_resource_info()
|
||||||
@ -152,17 +155,20 @@ class UI:
|
|||||||
if not self._installer.voiceover_lang_translate(lng) == vo.language:
|
if not self._installer.voiceover_lang_translate(lng) == vo.language:
|
||||||
continue
|
continue
|
||||||
print("Downloading voiceover update pack for {} (This will take a long time)...".format(lng))
|
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):
|
async def install_game(self, forced: bool = False):
|
||||||
res_info = await self._launcher.get_resource_info()
|
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?"):
|
if not self._ask("Do you want to install the game?"):
|
||||||
print("Aborting game installation process.")
|
print("Aborting game installation process.")
|
||||||
return
|
return
|
||||||
await self.download_game()
|
await self.download_game()
|
||||||
print("Game archive:", res_info.game.latest.get_name())
|
print("Game archive:", game.latest.get_name())
|
||||||
await self._install_from_archive(self._installer.temp_path.joinpath(res_info.game.latest.get_name()), forced)
|
await self._install_from_archive(self._installer.temp_path.joinpath(game.latest.get_name()), forced)
|
||||||
|
|
||||||
async def install_voiceover(self, languages: str):
|
async def install_voiceover(self, languages: str):
|
||||||
res_info = await self._launcher.get_resource_info()
|
res_info = await self._launcher.get_resource_info()
|
||||||
@ -172,13 +178,12 @@ class UI:
|
|||||||
continue
|
continue
|
||||||
if not self._ask("Do you want to install this voiceover pack? ({})".format(lng)):
|
if not self._ask("Do you want to install this voiceover pack? ({})".format(lng)):
|
||||||
print("Aborting voiceover installation process.")
|
print("Aborting voiceover installation process.")
|
||||||
return
|
break
|
||||||
print("Downloading voiceover pack (This will take a long time)...")
|
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(
|
await self._apply_voiceover_from_archive(
|
||||||
self._installer.temp_path.joinpath(vo.get_name())
|
self._installer.temp_path.joinpath(vo.get_name())
|
||||||
)
|
)
|
||||||
break
|
|
||||||
|
|
||||||
async def update_game(self):
|
async def update_game(self):
|
||||||
game_ver = await self._installer.get_game_version()
|
game_ver = await self._installer.get_game_version()
|
||||||
@ -188,15 +193,18 @@ class UI:
|
|||||||
print("Current game installation detected: {}".format(game_ver))
|
print("Current game installation detected: {}".format(game_ver))
|
||||||
diff_archive = await self._installer.get_game_diff_archive()
|
diff_archive = await self._installer.get_game_diff_archive()
|
||||||
res_info = await self._launcher.get_resource_info()
|
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:
|
if not diff_archive:
|
||||||
print("No game updates available.")
|
print("No game updates available.")
|
||||||
return
|
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?"):
|
if not self._ask("Do you want to update the game?"):
|
||||||
print("Aborting game update process.")
|
print("Aborting game update process.")
|
||||||
return
|
return
|
||||||
print("Downloading game update (This will take a long time)...")
|
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...")
|
print("Installing game update...")
|
||||||
await self.install_from_file(self._installer.temp_path.joinpath(diff_archive.get_name()))
|
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:
|
if self._installer.voiceover_lang_translate(lng, "locale") not in installed_voiceovers:
|
||||||
await self.install_voiceover(lng)
|
await self.install_voiceover(lng)
|
||||||
continue
|
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:
|
if not diff_archive:
|
||||||
print("No voiceover updates available for {}.".format(lng))
|
print("No voiceover updates available for {}.".format(lng))
|
||||||
continue
|
continue
|
||||||
@ -221,7 +229,7 @@ class UI:
|
|||||||
print("Aborting this voiceover language update process.")
|
print("Aborting this voiceover language update process.")
|
||||||
continue
|
continue
|
||||||
print("Downloading voiceover update (This may takes some time)...")
|
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))
|
print("Installing voiceover update for {}...".format(lng))
|
||||||
await self._apply_voiceover_from_archive(self._installer.temp_path.joinpath(diff_archive.get_name()))
|
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)")
|
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("-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("-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("-V", "--verify", action="store_true", help="Verify the game installation")
|
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("--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("--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("--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-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 "
|
parser.add_argument("--from-vo-ver", action="store", help="Override the detected game version for voiceover "
|
||||||
"detection", type=str, default=None)
|
"detection", type=str, default=None)
|
||||||
@ -310,7 +319,7 @@ async def main():
|
|||||||
if args.temporary_dir:
|
if args.temporary_dir:
|
||||||
args.temporary_dir.mkdir(parents=True, exist_ok=True)
|
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:
|
if args.install and args.update:
|
||||||
raise ValueError("Cannot specify both --install and --update arguments.")
|
raise ValueError("Cannot specify both --install and --update arguments.")
|
||||||
|
@ -389,19 +389,15 @@ class Installer:
|
|||||||
self._config.set_game_version(version)
|
self._config.set_game_version(version)
|
||||||
self._config.save()
|
self._config.save()
|
||||||
|
|
||||||
async def download_full_game(self):
|
async def download_full_game(self, pre_download=False):
|
||||||
resource = await self._launcher.get_resource_info()
|
game = await self._get_game(pre_download)
|
||||||
if resource is None:
|
archive_name = game.latest.path.split("/")[-1]
|
||||||
raise RuntimeError("Failed to fetch game resource info.")
|
await self._download_file(game.latest.path, archive_name, game.latest.size)
|
||||||
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_voiceover(self, language: str):
|
async def download_full_voiceover(self, language: str, pre_download=False):
|
||||||
archive = await self._launcher.get_resource_info()
|
game = await self._get_game(pre_download)
|
||||||
if archive is None:
|
|
||||||
raise RuntimeError("Failed to fetch game resource info.")
|
|
||||||
translated_lang = self.voiceover_lang_translate(language)
|
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:
|
if vo.language == translated_lang:
|
||||||
await self._download_file(vo.path, vo.get_name(), vo.size)
|
await self._download_file(vo.path, vo.get_name(), vo.size)
|
||||||
|
|
||||||
@ -452,52 +448,57 @@ class Installer:
|
|||||||
raise ValueError("Could not fetch game resource")
|
raise ValueError("Could not fetch game resource")
|
||||||
return 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:
|
if not from_version:
|
||||||
from_version = await self._get_game_version()
|
from_version = await self._get_game_version()
|
||||||
version_info = await self._get_game_resource()
|
game = await self._get_game(pre_download=pre_download)
|
||||||
if self._version == version_info.game.latest.version:
|
if self._version == game.latest.version:
|
||||||
raise ValueError("Game is already up to date.")
|
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:
|
if diff_archive is None:
|
||||||
raise ValueError("Game diff archive is not available for this version, please reinstall.")
|
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)
|
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:
|
if not from_version:
|
||||||
from_version = await self._get_game_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:
|
if diff_archive is None:
|
||||||
raise ValueError("Voiceover diff archive is not available for this version, please reinstall.")
|
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)
|
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
|
"""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 from_version is not specified, it will be taken from the game version.
|
||||||
"""
|
"""
|
||||||
if not from_version:
|
if not from_version:
|
||||||
from_version = await self._get_game_version()
|
from_version = await self._get_game_version()
|
||||||
game_resource = await self._get_game_resource()
|
game = await self._get_game(pre_download=pre_download)
|
||||||
if not game_resource:
|
|
||||||
raise ValueError("Could not fetch game resource")
|
|
||||||
translated_lang = self.voiceover_lang_translate(lang)
|
translated_lang = self.voiceover_lang_translate(lang)
|
||||||
for v in game_resource.game.diffs:
|
for v in game.diffs:
|
||||||
if v.version != from_version:
|
if v.version != from_version:
|
||||||
continue
|
continue
|
||||||
for vo in v.voice_packs:
|
for vo in v.voice_packs:
|
||||||
if vo.language == translated_lang:
|
if vo.language == translated_lang:
|
||||||
return vo
|
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
|
"""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 from_version is not specified, it will be taken from the game version.
|
||||||
"""
|
"""
|
||||||
if not from_version:
|
if not from_version:
|
||||||
from_version = await self._get_game_version()
|
from_version = await self._get_game_version()
|
||||||
game_resource = await self._get_game_resource()
|
game = await self._get_game(pre_download=pre_download)
|
||||||
for v in game_resource.game.diffs:
|
for v in game.diffs:
|
||||||
if v.version == from_version:
|
if v.version == from_version:
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user