diff --git a/rare/components/tabs/games/game_info/game_info.py b/rare/components/tabs/games/game_info/game_info.py
index b51afabc..c11f8f79 100644
--- a/rare/components/tabs/games/game_info/game_info.py
+++ b/rare/components/tabs/games/game_info/game_info.py
@@ -59,7 +59,6 @@ class GameInfo(QWidget):
self.rgame: Optional[RareGame] = None
self.game: Optional[Game] = None
self.igame: Optional[InstalledGame] = None
- self.verify_threads: Dict[str, QRunnable] = {}
self.image = ImageWidget(self)
self.image.setFixedSize(ImageSize.Display)
@@ -127,99 +126,95 @@ class GameInfo(QWidget):
@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")
+ repair_file = os.path.join(self.core.lgd.get_tmp_path(), f"{self.rgame.app_name}.repair")
if not os.path.exists(repair_file):
QMessageBox.warning(
self,
- self.tr("Error - {}").format(self.igame.title),
+ self.tr("Error - {}").format(self.rgame.title),
self.tr(
"Repair file does not exist or game does not need a repair. Please verify game first"
),
)
return
- self.repair_game(self.igame)
+ self.repair_game(self.rgame)
- def repair_game(self, igame: InstalledGame):
- game = self.core.get_game(igame.app_name)
+ def repair_game(self, rgame: RareGame):
+ rgame.update_game()
ans = False
- if igame.version != game.app_version(igame.platform):
+ if rgame.has_update:
ans = QMessageBox.question(
self,
self.tr("Repair and update?"),
self.tr(
"There is an update for {} from {} to {}. "
"Do you want to update the game while repairing it?"
- ).format(igame.title, igame.version, game.app_version(igame.platform)),
+ ).format(rgame.title, rgame.version, rgame.remote_version),
) == QMessageBox.Yes
self.signals.game.install.emit(
InstallOptionsModel(
- app_name=igame.app_name, repair_mode=True, repair_and_update=ans, update=True
+ app_name=rgame.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(f"Installation path {self.igame.install_path} for {self.igame.title} does not exist")
+ if not os.path.exists(self.rgame.igame.install_path):
+ logger.error(f"Installation path {self.rgame.igame.install_path} for {self.rgame.title} does not exist")
QMessageBox.warning(
self,
- self.tr("Error - {}").format(self.igame.title),
- self.tr("Installation path for {} does not exist. Cannot continue.").format(self.igame.title),
+ self.tr("Error - {}").format(self.rgame.title),
+ self.tr("Installation path for {} does not exist. Cannot continue.").format(self.rgame.title),
)
return
- self.verify_game(self.igame)
+ self.verify_game(self.rgame)
- def verify_game(self, igame: InstalledGame):
+ def verify_game(self, rgame: RareGame):
self.ui.verify_widget.setCurrentIndex(1)
- verify_worker = VerifyWorker(igame.app_name)
+ verify_worker = VerifyWorker(rgame, self.core, self.args)
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.ui.verify_progress.setValue(0)
- self.verify_threads[igame.app_name] = verify_worker
+ self.rgame.active_thread = verify_worker
self.verify_pool.start(verify_worker)
self.ui.move_button.setEnabled(False)
- def verify_cleanup(self, app_name: str):
+ def verify_cleanup(self, rgame: RareGame):
self.ui.verify_widget.setCurrentIndex(0)
- self.verify_threads.pop(app_name)
+ rgame.active_thread = None
self.ui.move_button.setEnabled(True)
self.ui.verify_button.setEnabled(True)
- @pyqtSlot(str, str)
- def verify_error(self, app_name, message):
- self.verify_cleanup(app_name)
- igame = self.core.get_installed_game(app_name)
+ @pyqtSlot(RareGame, str)
+ def verify_error(self, rgame: RareGame, message):
+ self.verify_cleanup(rgame)
QMessageBox.warning(
self,
- self.tr("Error - {}").format(igame.title),
+ self.tr("Error - {}").format(rgame.title),
message
)
- @pyqtSlot(str, int, int, float, float)
- def verify_status(self, app_name, num, total, percentage, speed):
- # checked, max, app_name
- if app_name == self.game.app_name:
- self.ui.verify_progress.setValue(num * 100 // total)
+ @pyqtSlot(RareGame, int, int, float, float)
+ def verify_status(self, rgame: RareGame, num, total, percentage, speed):
+ self.ui.verify_progress.setValue(num * 100 // total)
- @pyqtSlot(str, bool, int, int)
- def verify_result(self, app_name, success, failed, missing):
- self.verify_cleanup(app_name)
+ @pyqtSlot(RareGame, bool, int, int)
+ def verify_result(self, rgame: RareGame, success, failed, missing):
+ self.verify_cleanup(rgame)
self.ui.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("Summary - {}").format(rgame.title),
self.tr("{} has been verified successfully. "
- "No missing or corrupt files found").format(igame.title),
+ "No missing or corrupt files found").format(rgame.title),
)
- self.verification_finished.emit(igame)
+ self.verification_finished.emit(rgame.igame)
else:
ans = QMessageBox.question(
self,
- self.tr("Summary - {}").format(igame.title),
+ self.tr("Summary - {}").format(rgame.title),
self.tr(
"Verification failed, {} file(s) corrupted, {} file(s) are missing. "
"Do you want to repair them?"
@@ -228,7 +223,7 @@ class GameInfo(QWidget):
QMessageBox.Yes,
)
if ans == QMessageBox.Yes:
- self.repair_game(igame)
+ self.repair_game(rgame)
@pyqtSlot(str)
def move_game(self, dest_path):
@@ -325,8 +320,22 @@ class GameInfo(QWidget):
self.ui.move_button.showMenu()
def update_game(self, rgame: RareGame):
- # FIXME: Use RareGame for the rest of the code
+ if self.rgame is not None:
+ if worker:= self.rgame.active_thread is not None:
+ if isinstance(worker, VerifyWorker):
+ try:
+ worker.signals.status.disconnect(self.verify_status)
+ except TypeError as e:
+ logger.warning(f"{self.rgame.app_title} verify worker: {e}")
self.rgame = rgame
+ if worker:= self.rgame.active_thread is not None:
+ if isinstance(worker, VerifyWorker):
+ self.ui.verify_widget.setCurrentIndex(1)
+ self.ui.verify_progress.setValue(self.rgame.progress)
+ worker.signals.status.connect(self.verify_status)
+ else:
+ self.ui.verify_widget.setCurrentIndex(0)
+ # FIXME: Use RareGame for the rest of the code
self.game = rgame.game
self.igame = rgame.igame
self.title.setTitle(self.game.app_title)
@@ -386,17 +395,17 @@ class GameInfo(QWidget):
self.steam_worker.set_app_name(self.game.app_name)
QThreadPool.globalInstance().start(self.steam_worker)
- if len(self.verify_threads.keys()) == 0 or not self.verify_threads.get(self.game.app_name):
- self.ui.verify_widget.setCurrentIndex(0)
- elif self.verify_threads.get(self.game.app_name):
- self.ui.verify_widget.setCurrentIndex(1)
- self.ui.verify_progress.setValue(
- int(
- self.verify_threads[self.game.app_name].num
- / self.verify_threads[self.game.app_name].total
- * 100
- )
- )
+ # if len(self.verify_threads.keys()) == 0 or not self.verify_threads.get(self.game.app_name):
+ # self.ui.verify_widget.setCurrentIndex(0)
+ # elif self.verify_threads.get(self.game.app_name):
+ # self.ui.verify_widget.setCurrentIndex(1)
+ # self.ui.verify_progress.setValue(
+ # int(
+ # self.verify_threads[self.game.app_name].num
+ # / self.verify_threads[self.game.app_name].total
+ # * 100
+ # )
+ # )
# If the game that is currently moving matches with the current app_name, we show the progressbar.
# Otherwhise, we show the move tool button.
@@ -409,7 +418,7 @@ class GameInfo(QWidget):
self.ui.move_stack.setCurrentIndex(index)
# If a game is verifying or moving, disable both verify and moving buttons.
- if len(self.verify_threads):
+ if rgame.active_thread is not None:
self.ui.verify_button.setEnabled(False)
self.ui.move_button.setEnabled(False)
if self.is_moving:
diff --git a/rare/models/game.py b/rare/models/game.py
index e1a8b9ad..c2b7bba3 100644
--- a/rare/models/game.py
+++ b/rare/models/game.py
@@ -1,6 +1,6 @@
import json
import os
-from dataclasses import dataclass
+from dataclasses import dataclass, field
from datetime import datetime
from enum import IntEnum
from logging import getLogger
@@ -18,18 +18,21 @@ from rare.utils.paths import data_dir
logger = getLogger("RareGame")
-class RareGameState(IntEnum):
- IDLE = 0,
- RUNNING = 1,
-
-
class RareGame(QObject):
+ class State(IntEnum):
+ IDLE = 0
+ RUNNING = 1
+ DOWNLOADING = 2
+ VERIFYING = 3
+ MOVING = 4
+
@dataclass
class Metadata:
queued: bool = False
queue_pos: Optional[int] = None
last_played: Optional[datetime] = None
+ tags: List[str] = field(default_factory=list)
@classmethod
def from_dict(cls, data: Dict):
@@ -37,6 +40,7 @@ class RareGame(QObject):
queued=data.get("queued", False),
queue_pos=data.get("queue_pos", None),
last_played=datetime.strptime(data.get("last_played", "None"), "%Y-%m-%dT%H:%M:%S.%f"),
+ tags=data.get("tags", []),
)
def as_dict(self):
@@ -44,6 +48,7 @@ class RareGame(QObject):
queued=self.queued,
queue_pos=self.queue_pos,
last_played=self.last_played.strftime("%Y-%m-%dT%H:%M:%S.%f"),
+ tags=self.tags,
)
def __bool__(self):
@@ -123,6 +128,18 @@ class RareGame(QObject):
with open(os.path.join(data_dir(), "game_meta.json"), "w") as metadata_json:
json.dump(metadata, metadata_json, indent=2)
+ def update_game(self):
+ self.game = self.core.get_game(
+ self.app_name, update_meta=True, platform=self.igame.platform if self.igame else "Windows"
+ )
+
+ def update_igame(self):
+ self.igame = self.core.get_installed_game(self.app_name)
+
+ def update_rgame(self):
+ self.update_igame()
+ self.update_game()
+
@property
def app_name(self) -> str:
return self.igame.app_name if self.igame is not None else self.game.app_name
@@ -346,11 +363,6 @@ class RareGame(QObject):
"""
return not self.game.asset_infos
- def install(self):
- self.signals.game.install.emit(
- InstallOptionsModel(app_name=self.game.app_name)
- )
-
@property
def is_origin(self) -> bool:
return self.game.metadata.get("customAttributes", {}).get("ThirdPartyManagedApp", {}).get("value") == "Origin"
@@ -387,3 +399,9 @@ class RareGame(QObject):
def finish_progress(self, fail: bool, miss: int, app: str):
self.set_installed(True)
self.signals.progress.finish.emit(fail)
+
+ def install(self):
+ self.signals.game.install.emit(
+ InstallOptionsModel(app_name=self.game.app_name)
+ )
+
diff --git a/rare/shared/workers/verify.py b/rare/shared/workers/verify.py
index dca52349..1a9bb1eb 100644
--- a/rare/shared/workers/verify.py
+++ b/rare/shared/workers/verify.py
@@ -1,41 +1,47 @@
import os
+import sys
+from argparse import Namespace
from logging import getLogger
from PyQt5.QtCore import pyqtSignal, QObject, QRunnable
from rare.lgndr.cli import LegendaryCLI
+from rare.lgndr.core import LegendaryCore
from rare.lgndr.glue.arguments import LgndrVerifyGameArgs
from rare.lgndr.glue.monkeys import LgndrIndirectStatus
-from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton
+from rare.models.game import RareGame
logger = getLogger("VerificationWorker")
class VerifyWorker(QRunnable):
class Signals(QObject):
- status = pyqtSignal(str, int, int, float, float)
- result = pyqtSignal(str, bool, int, int)
- error = pyqtSignal(str, str)
+ status = pyqtSignal(RareGame, int, int, float, float)
+ result = pyqtSignal(RareGame, bool, int, int)
+ error = pyqtSignal(RareGame, str)
num: int = 0
total: int = 1 # set default to 1 to avoid DivisionByZero before it is initialized
- def __init__(self, app_name):
+ def __init__(self, rgame: RareGame, core: LegendaryCore, args: Namespace):
+ sys.excepthook = sys.__excepthook__
super(VerifyWorker, self).__init__()
self.signals = VerifyWorker.Signals()
self.setAutoDelete(True)
- self.core = LegendaryCoreSingleton()
- self.args = ArgumentsSingleton()
- self.app_name = app_name
+ self.core = core
+ self.args = args
+ self.rgame = rgame
def status_callback(self, num: int, total: int, percentage: float, speed: float):
- self.signals.status.emit(self.app_name, num, total, percentage, speed)
+ self.rgame.signals.progress.update.emit(num * 100 // total)
+ self.signals.status.emit(self.rgame, num, total, percentage, speed)
def run(self):
+ self.rgame.signals.progress.start.emit()
cli = LegendaryCLI(self.core)
status = LgndrIndirectStatus()
args = LgndrVerifyGameArgs(
- app_name=self.app_name, indirect_status=status, verify_stdout=self.status_callback
+ app_name=self.rgame.app_name, indirect_status=status, verify_stdout=self.status_callback
)
# lk: first pass, verify with the current manifest
@@ -57,16 +63,18 @@ class VerifyWorker(QRunnable):
if result is None:
raise ValueError
except ValueError:
- self.signals.error.emit(self.app_name, status.message)
+ self.rgame.signals.progress.finish.emit(True)
+ self.signals.error.emit(self.rgame, 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")
- cli.install_game_cleanup(game=game, igame=igame, repair_mode=True, repair_file=repair_file)
+ repair_file = os.path.join(self.core.lgd.get_tmp_path(), f"{self.rgame.app_name}.repair")
+ cli.install_game_cleanup(game=self.rgame.game, igame=self.rgame.igame, repair_mode=True, repair_file=repair_file)
+ self.rgame.update_rgame()
+
+ self.rgame.signals.progress.finish.emit(False)
+ self.signals.result.emit(self.rgame, success, *result)
- self.signals.result.emit(self.app_name, success, *result)