GameInfo: Offer to also update the game after a verification if there is one
This commit is contained in:
parent
785aaf648e
commit
e5c7b029ff
|
@ -25,7 +25,7 @@ from rare.utils import config_helper
|
||||||
class InstallDialog(QDialog, Ui_InstallDialog):
|
class InstallDialog(QDialog, Ui_InstallDialog):
|
||||||
result_ready = pyqtSignal(InstallQueueItemModel)
|
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)
|
super(InstallDialog, self).__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.setAttribute(Qt.WA_DeleteOnClose, True)
|
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.game_path = self.game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value", "")
|
||||||
|
|
||||||
self.update = update
|
self.update = update
|
||||||
|
self.repair = repair
|
||||||
self.silent = silent
|
self.silent = silent
|
||||||
|
|
||||||
self.options_changed = False
|
self.options_changed = False
|
||||||
|
|
|
@ -85,7 +85,7 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
if self.args.offline:
|
if self.args.offline:
|
||||||
self.repair_button.setDisabled(True)
|
self.repair_button.setDisabled(True)
|
||||||
else:
|
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))
|
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.game_utils.update_list.emit(self.game.app_name)
|
||||||
self.uninstalled.emit(self.game.app_name)
|
self.uninstalled.emit(self.game.app_name)
|
||||||
|
|
||||||
@pyqtSlot(InstalledGame)
|
@pyqtSlot()
|
||||||
def repair(self, igame: InstalledGame):
|
def repair(self):
|
||||||
game = self.core.get_game(igame.app_name)
|
""" This function is to be called from the button only """
|
||||||
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f"{igame.app_name}.repair")
|
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f"{self.igame.app_name}.repair")
|
||||||
if not os.path.exists(repair_file):
|
if not os.path.exists(repair_file):
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
"Warning",
|
self.tr("Error - {}").format(self.igame.title),
|
||||||
self.tr(
|
self.tr(
|
||||||
"Repair file does not exist or game does not need a repair. Please verify game first"
|
"Repair file does not exist or game does not need a repair. Please verify game first"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return
|
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(
|
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):
|
def verify(self):
|
||||||
|
""" This function is to be called from the button only """
|
||||||
if not os.path.exists(self.igame.install_path):
|
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(
|
QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
"Warning",
|
self.tr("Error - {}").format(self.igame.title),
|
||||||
self.tr("Installation path of {} does not exist. Cannot verify").format(self.igame.title),
|
self.tr("Installation path for <b>{}</b> does not exist. Cannot continue.").format(self.igame.title),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
self.verify_game(self.igame)
|
||||||
|
|
||||||
|
def verify_game(self, igame: InstalledGame):
|
||||||
self.verify_widget.setCurrentIndex(1)
|
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.status.connect(self.verify_status)
|
||||||
verify_worker.signals.result.connect(self.verify_result)
|
verify_worker.signals.result.connect(self.verify_result)
|
||||||
verify_worker.signals.error.connect(self.verify_error)
|
verify_worker.signals.error.connect(self.verify_error)
|
||||||
self.verify_progress.setValue(0)
|
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.verify_pool.start(verify_worker)
|
||||||
self.move_button.setEnabled(False)
|
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)
|
@pyqtSlot(str, str)
|
||||||
def verify_error(self, app_name, message):
|
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)
|
@pyqtSlot(str, int, int, float, float)
|
||||||
def verify_status(self, app_name, num, total, percentage, speed):
|
def verify_status(self, app_name, num, total, percentage, speed):
|
||||||
|
@ -166,36 +198,30 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
|
|
||||||
@pyqtSlot(str, bool, int, int)
|
@pyqtSlot(str, bool, int, int)
|
||||||
def verify_result(self, app_name, success, failed, missing):
|
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)
|
igame = self.core.get_installed_game(app_name)
|
||||||
if success:
|
if success:
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self,
|
self,
|
||||||
self.tr("Summary - {}").format(igame.title),
|
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:
|
self.verification_finished.emit(igame)
|
||||||
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"))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ans = QMessageBox.question(
|
ans = QMessageBox.question(
|
||||||
self,
|
self,
|
||||||
self.tr("Summary - {}").format(igame.title),
|
self.tr("Summary - {}").format(igame.title),
|
||||||
self.tr(
|
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),
|
).format(failed, missing),
|
||||||
QMessageBox.Yes | QMessageBox.No,
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
QMessageBox.Yes,
|
QMessageBox.Yes,
|
||||||
)
|
)
|
||||||
if ans == QMessageBox.Yes:
|
if ans == QMessageBox.Yes:
|
||||||
self.repair(igame)
|
self.repair_game(igame)
|
||||||
self.verify_widget.setCurrentIndex(0)
|
|
||||||
self.verify_threads.pop(app_name)
|
|
||||||
self.move_button.setEnabled(True)
|
|
||||||
self.verify_button.setEnabled(True)
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def move_game(self, dest_path):
|
def move_game(self, dest_path):
|
||||||
|
@ -326,7 +352,9 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
self.uninstall_button.setDisabled(False)
|
self.uninstall_button.setDisabled(False)
|
||||||
self.verify_button.setDisabled(False)
|
self.verify_button.setDisabled(False)
|
||||||
if not self.args.offline:
|
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)
|
self.game_actions_stack.setCurrentIndex(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -43,7 +43,7 @@ class InstalledIconWidget(BaseInstalledWidget):
|
||||||
minilayout.setSpacing(0)
|
minilayout.setSpacing(0)
|
||||||
miniwidget.setLayout(minilayout)
|
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.setAlignment(Qt.AlignTop)
|
||||||
self.title_label.setObjectName("game_widget")
|
self.title_label.setObjectName("game_widget")
|
||||||
minilayout.addWidget(self.title_label, stretch=2)
|
minilayout.addWidget(self.title_label, stretch=2)
|
||||||
|
|
|
@ -29,7 +29,7 @@ class UninstalledIconWidget(BaseUninstalledWidget):
|
||||||
minilayout.setSpacing(0)
|
minilayout.setSpacing(0)
|
||||||
miniwidget.setLayout(minilayout)
|
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.setAlignment(Qt.AlignTop)
|
||||||
self.title_label.setObjectName("game_widget")
|
self.title_label.setObjectName("game_widget")
|
||||||
minilayout.addWidget(self.title_label, stretch=2)
|
minilayout.addWidget(self.title_label, stretch=2)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from legendary.core import LegendaryCore
|
||||||
from rare.lgndr.api_monkeys import LgndrIndirectStatus
|
from rare.lgndr.api_monkeys import LgndrIndirectStatus
|
||||||
from rare.lgndr.api_arguments import LgndrVerifyGameArgs, LgndrUninstallGameArgs
|
from rare.lgndr.api_arguments import LgndrVerifyGameArgs, LgndrUninstallGameArgs
|
||||||
from rare.lgndr.api_exception import LgndrException
|
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
|
from rare.utils import config_helper
|
||||||
|
|
||||||
logger = getLogger("Legendary Utils")
|
logger = getLogger("Legendary Utils")
|
||||||
|
@ -90,6 +90,7 @@ class VerifyWorker(QRunnable):
|
||||||
self.setAutoDelete(True)
|
self.setAutoDelete(True)
|
||||||
self.cli = LegendaryCLISingleton()
|
self.cli = LegendaryCLISingleton()
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
|
self.args = ArgumentsSingleton()
|
||||||
self.app_name = app_name
|
self.app_name = app_name
|
||||||
|
|
||||||
def status_callback(self, num: int, total: int, percentage: float, speed: float):
|
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,
|
args = LgndrVerifyGameArgs(app_name=self.app_name,
|
||||||
indirect_status=status,
|
indirect_status=status,
|
||||||
verify_stdout=self.status_callback)
|
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
|
# lk: first pass, verify with the current manifest
|
||||||
# TODO: somehow detect the error and offer a dialog in which case `verify_games` is
|
repair_mode = False
|
||||||
# TODO: re-run with `repair_mode` and `repair_online`
|
|
||||||
# FIXME: This will crash in offline mode. Offline mode needs a re-thinking in general.
|
|
||||||
result = self.cli.verify_game(
|
result = self.cli.verify_game(
|
||||||
args, print_command=False, repair_mode=True, repair_online=True)
|
args, print_command=False, repair_mode=repair_mode, repair_online=not self.args.offline
|
||||||
# success, failed, missing = self.cli.verify_game(args, print_command=False)
|
)
|
||||||
if result:
|
if result is None:
|
||||||
self.signals.result.emit(self.app_name, not any(result), *result)
|
# lk: second pass with the latest manifest
|
||||||
else:
|
# lk: this happens if the manifest was not found and repair_mode was not requested
|
||||||
self.signals.error.emit(self.app_name, status.message)
|
# 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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue