1
0
Fork 0
mirror of synced 2024-06-17 10:04:43 +12:00

GameInfo: Offer to also update the game after a verification if there is one

This commit is contained in:
loathingKernel 2022-07-31 23:00:50 +03:00
parent 785aaf648e
commit e5c7b029ff
5 changed files with 96 additions and 44 deletions

View file

@ -25,7 +25,7 @@ from rare.utils import config_helper
class InstallDialog(QDialog, Ui_InstallDialog):
result_ready = pyqtSignal(InstallQueueItemModel)
def __init__(self, dl_item: InstallQueueItemModel, update=False, silent=False, parent=None):
def __init__(self, dl_item: InstallQueueItemModel, update=False, repair=False, silent=False, parent=None):
super(InstallDialog, self).__init__(parent)
self.setupUi(self)
self.setAttribute(Qt.WA_DeleteOnClose, True)
@ -44,6 +44,7 @@ class InstallDialog(QDialog, Ui_InstallDialog):
self.game_path = self.game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value", "")
self.update = update
self.repair = repair
self.silent = silent
self.options_changed = False

View file

@ -85,7 +85,7 @@ class GameInfo(QWidget, Ui_GameInfo):
if self.args.offline:
self.repair_button.setDisabled(True)
else:
self.repair_button.clicked.connect(lambda: self.repair(self.igame))
self.repair_button.clicked.connect(self.repair)
self.install_button.clicked.connect(lambda: self.game_utils.launch_game(self.game.app_name))
@ -117,46 +117,78 @@ class GameInfo(QWidget, Ui_GameInfo):
self.game_utils.update_list.emit(self.game.app_name)
self.uninstalled.emit(self.game.app_name)
@pyqtSlot(InstalledGame)
def repair(self, igame: InstalledGame):
game = self.core.get_game(igame.app_name)
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f"{igame.app_name}.repair")
@pyqtSlot()
def repair(self):
""" This function is to be called from the button only """
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f"{self.igame.app_name}.repair")
if not os.path.exists(repair_file):
QMessageBox.warning(
self,
"Warning",
self.tr("Error - {}").format(self.igame.title),
self.tr(
"Repair file does not exist or game does not need a repair. Please verify game first"
),
)
return
update = igame.version != game.app_version(igame.platform)
self.repair_game(self.igame)
def repair_game(self, igame: InstalledGame):
game = self.core.get_game(igame.app_name)
ans = False
if igame.version != game.app_version(igame.platform):
ans = QMessageBox.question(
self,
self.tr("Repair and update?"),
self.tr(
"There is an update for <b>{}</b> from <b>{}</b> to <b>{}</b>."
"Do you want to update the game while repairing it?"
).format(igame.title, igame.version, game.app_version(igame.platform)),
) == QMessageBox.Yes
self.signals.install_game.emit(
InstallOptionsModel(app_name=self.game.app_name, repair_mode=True, repair_and_update=update, update=True)
InstallOptionsModel(
app_name=igame.app_name, repair_mode=True, repair_and_update=ans, update=True
)
)
@pyqtSlot()
def verify(self):
""" This function is to be called from the button only """
if not os.path.exists(self.igame.install_path):
logger.error("Path does not exist")
logger.error(f"Installation path {self.igame.install_path} for {self.igame.title} does not exist")
QMessageBox.warning(
self,
"Warning",
self.tr("Installation path of {} does not exist. Cannot verify").format(self.igame.title),
self.tr("Error - {}").format(self.igame.title),
self.tr("Installation path for <b>{}</b> does not exist. Cannot continue.").format(self.igame.title),
)
return
self.verify_game(self.igame)
def verify_game(self, igame: InstalledGame):
self.verify_widget.setCurrentIndex(1)
verify_worker = VerifyWorker(self.game.app_name)
verify_worker = VerifyWorker(igame.app_name)
verify_worker.signals.status.connect(self.verify_status)
verify_worker.signals.result.connect(self.verify_result)
verify_worker.signals.error.connect(self.verify_error)
self.verify_progress.setValue(0)
self.verify_threads[self.game.app_name] = verify_worker
self.verify_threads[igame.app_name] = verify_worker
self.verify_pool.start(verify_worker)
self.move_button.setEnabled(False)
def verify_cleanup(self, app_name: str):
self.verify_widget.setCurrentIndex(0)
self.verify_threads.pop(app_name)
self.move_button.setEnabled(True)
self.verify_button.setEnabled(True)
@pyqtSlot(str, str)
def verify_error(self, app_name, message):
pass
self.verify_cleanup(app_name)
igame = self.core.get_installed_game(app_name)
QMessageBox.warning(
self,
self.tr("Error - {}").format(igame.title),
message
)
@pyqtSlot(str, int, int, float, float)
def verify_status(self, app_name, num, total, percentage, speed):
@ -166,36 +198,30 @@ class GameInfo(QWidget, Ui_GameInfo):
@pyqtSlot(str, bool, int, int)
def verify_result(self, app_name, success, failed, missing):
self.verify_cleanup(app_name)
self.repair_button.setDisabled(success)
igame = self.core.get_installed_game(app_name)
if success:
QMessageBox.information(
self,
self.tr("Summary - {}").format(igame.title),
self.tr("Game has been verified successfully. No missing or corrupt files found").format(igame.title),
self.tr("<b>{}</b> has been verified successfully. "
"No missing or corrupt files found").format(igame.title),
)
if igame.needs_verification:
igame.needs_verification = False
self.core.lgd.set_installed_game(igame.app_name, igame)
self.verification_finished.emit(igame)
elif failed == missing == -1:
QMessageBox.warning(self, self.tr("Warning - {}").format(igame.title), self.tr("Something went wrong"))
self.verification_finished.emit(igame)
else:
ans = QMessageBox.question(
self,
self.tr("Summary - {}").format(igame.title),
self.tr(
"Verification failed, {} file(s) corrupted, {} file(s) are missing. Do you want to repair them?"
"Verification failed, <b>{}</b> file(s) corrupted, <b>{}</b> file(s) are missing. "
"Do you want to repair them?"
).format(failed, missing),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes,
)
if ans == QMessageBox.Yes:
self.repair(igame)
self.verify_widget.setCurrentIndex(0)
self.verify_threads.pop(app_name)
self.move_button.setEnabled(True)
self.verify_button.setEnabled(True)
self.repair_game(igame)
@pyqtSlot(str)
def move_game(self, dest_path):
@ -326,7 +352,9 @@ class GameInfo(QWidget, Ui_GameInfo):
self.uninstall_button.setDisabled(False)
self.verify_button.setDisabled(False)
if not self.args.offline:
self.repair_button.setDisabled(False)
self.repair_button.setDisabled(
not os.path.exists(os.path.join(self.core.lgd.get_tmp_path(), f"{self.igame.app_name}.repair"))
)
self.game_actions_stack.setCurrentIndex(0)
try:

View file

@ -43,7 +43,7 @@ class InstalledIconWidget(BaseInstalledWidget):
minilayout.setSpacing(0)
miniwidget.setLayout(minilayout)
self.title_label = ElideLabel(f"<h4>{self.game.app_title}</h4>", parent=miniwidget)
self.title_label = ElideLabel(f"<b>{self.game.app_title}</b>", parent=miniwidget)
self.title_label.setAlignment(Qt.AlignTop)
self.title_label.setObjectName("game_widget")
minilayout.addWidget(self.title_label, stretch=2)

View file

@ -29,7 +29,7 @@ class UninstalledIconWidget(BaseUninstalledWidget):
minilayout.setSpacing(0)
miniwidget.setLayout(minilayout)
self.title_label = ElideLabel(f"<h4>{game.app_title}</h4>", parent=miniwidget)
self.title_label = ElideLabel(f"<b>{game.app_title}</b>", parent=miniwidget)
self.title_label.setAlignment(Qt.AlignTop)
self.title_label.setObjectName("game_widget")
minilayout.addWidget(self.title_label, stretch=2)

View file

@ -8,7 +8,7 @@ from legendary.core import LegendaryCore
from rare.lgndr.api_monkeys import LgndrIndirectStatus
from rare.lgndr.api_arguments import LgndrVerifyGameArgs, LgndrUninstallGameArgs
from rare.lgndr.api_exception import LgndrException
from rare.shared import LegendaryCLISingleton, LegendaryCoreSingleton
from rare.shared import LegendaryCLISingleton, LegendaryCoreSingleton, ArgumentsSingleton
from rare.utils import config_helper
logger = getLogger("Legendary Utils")
@ -90,6 +90,7 @@ class VerifyWorker(QRunnable):
self.setAutoDelete(True)
self.cli = LegendaryCLISingleton()
self.core = LegendaryCoreSingleton()
self.args = ArgumentsSingleton()
self.app_name = app_name
def status_callback(self, num: int, total: int, percentage: float, speed: float):
@ -100,15 +101,37 @@ class VerifyWorker(QRunnable):
args = LgndrVerifyGameArgs(app_name=self.app_name,
indirect_status=status,
verify_stdout=self.status_callback)
# TODO: offer this as an alternative when manifest doesn't exist
# TODO: requires the client to be online. To do it this way, we need to
# TODO: somehow detect the error and offer a dialog in which case `verify_games` is
# TODO: re-run with `repair_mode` and `repair_online`
# FIXME: This will crash in offline mode. Offline mode needs a re-thinking in general.
# lk: first pass, verify with the current manifest
repair_mode = False
result = self.cli.verify_game(
args, print_command=False, repair_mode=True, repair_online=True)
# success, failed, missing = self.cli.verify_game(args, print_command=False)
if result:
self.signals.result.emit(self.app_name, not any(result), *result)
else:
self.signals.error.emit(self.app_name, status.message)
args, print_command=False, repair_mode=repair_mode, repair_online=not self.args.offline
)
if result is None:
# lk: second pass with the latest manifest
# lk: this happens if the manifest was not found and repair_mode was not requested
# lk: we already have checked if the directory exists before starting the worker
try:
# lk: this try-except block handles the exception caused by a missing manifest
# lk: and is raised only in the case we are offline
repair_mode = True
result = self.cli.verify_game(
args, print_command=False, repair_mode=repair_mode, repair_online=not self.args.offline
)
if result is None:
raise ValueError
except ValueError:
self.signals.error.emit(self.app_name, status.message)
return
success = result is not None and not any(result)
if success:
# lk: if verification was successful we delete the repair file and run the clean procedure
# lk: this could probably be cut down to what is relevant for this use-case and skip the `cli` call
igame = self.core.get_installed_game(self.app_name)
game = self.core.get_game(self.app_name, platform=igame.platform)
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f'{self.app_name}.repair')
self.cli.clean_post_install(game=game, igame=igame, repair=True, repair_file=repair_file)
self.signals.result.emit(self.app_name, success, *result)