RareCore: Manage initialization in RareCore instead of LaunchDialog
This is the last change of the `backend_refactor` branch. This makes `RareCore` the centerpiece of Rare by moving initialization before the UI is brought up. RareCore is now in control of creating and querying `RareGame` objects, re-introducing the ability (incomplete) to refresh the games library. As a result, ApiResults has been removed. Signed-off-by: loathingKernel <142770+loathingKernel@users.noreply.github.com>
This commit is contained in:
parent
9d4e0995fd
commit
5748d0e6ee
|
@ -130,5 +130,3 @@ def start(args):
|
|||
del app
|
||||
if exit_code != -133742:
|
||||
break
|
||||
|
||||
|
||||
|
|
|
@ -1,167 +1,21 @@
|
|||
import os
|
||||
import platform
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QRunnable, QObject, QThreadPool, QSettings, pyqtSlot
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import QDialog, QApplication
|
||||
from legendary.models.game import Game
|
||||
from requests.exceptions import ConnectionError, HTTPError
|
||||
|
||||
from rare.components.dialogs.login import LoginDialog
|
||||
from rare.models.apiresults import ApiResults
|
||||
from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSingleton, ImageManagerSingleton
|
||||
from rare.shared.workers.uninstall import uninstall_game
|
||||
from rare.shared import RareCore
|
||||
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
|
||||
from rare.utils.misc import CloudWorker
|
||||
from rare.widgets.elide_label import ElideLabel
|
||||
|
||||
logger = getLogger("LaunchDialog")
|
||||
|
||||
|
||||
class LaunchWorker(QRunnable):
|
||||
class Signals(QObject):
|
||||
progress = pyqtSignal(int, str)
|
||||
result = pyqtSignal(object, str)
|
||||
finished = pyqtSignal()
|
||||
|
||||
def __init__(self):
|
||||
super(LaunchWorker, self).__init__()
|
||||
self.setAutoDelete(True)
|
||||
self.signals = LaunchWorker.Signals()
|
||||
self.core = LegendaryCoreSingleton()
|
||||
|
||||
def run_real(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
self.run_real()
|
||||
self.signals.deleteLater()
|
||||
|
||||
|
||||
class ImageWorker(LaunchWorker):
|
||||
# FIXME: this is a middle-ground solution for concurrent downloads
|
||||
class DownloadSlot(QObject):
|
||||
def __init__(self, signals: LaunchWorker.Signals):
|
||||
super(ImageWorker.DownloadSlot, self).__init__()
|
||||
self.signals = signals
|
||||
self.counter = 0
|
||||
self.length = 0
|
||||
|
||||
@pyqtSlot(object)
|
||||
def counter_inc(self, game: Game):
|
||||
self.signals.progress.emit(
|
||||
int(self.counter / self.length * 75),
|
||||
self.tr("Downloading image for <b>{}</b>").format(game.app_title)
|
||||
)
|
||||
self.counter += 1
|
||||
|
||||
def __init__(self):
|
||||
super(ImageWorker, self).__init__()
|
||||
# FIXME: this is a middle-ground solution for concurrent downloads
|
||||
self.dl_slot = ImageWorker.DownloadSlot(self.signals)
|
||||
self.image_manager = ImageManagerSingleton()
|
||||
|
||||
def tr(self, t) -> str:
|
||||
return QApplication.instance().translate(self.__class__.__name__, t)
|
||||
|
||||
def run_real(self):
|
||||
# Download Images
|
||||
games, dlcs = self.core.get_game_and_dlc_list(update_assets=True, skip_ue=False)
|
||||
self.signals.result.emit((games, dlcs), "gamelist")
|
||||
dlc_list = [dlc[0] for dlc in dlcs.values()]
|
||||
|
||||
na_games, na_dlcs = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)
|
||||
self.signals.result.emit((na_games, na_dlcs), "no_assets")
|
||||
na_dlc_list = [dlc[0] for dlc in na_dlcs.values()]
|
||||
|
||||
game_list = games + dlc_list + na_games + na_dlc_list
|
||||
|
||||
self.dl_slot.length = len(game_list)
|
||||
for i, game in enumerate(game_list):
|
||||
if game.app_title == "Unreal Engine":
|
||||
game.app_title += f" {game.app_name.split('_')[-1]}"
|
||||
self.core.lgd.set_game_meta(game.app_name, game)
|
||||
# self.image_manager.download_image_blocking(game)
|
||||
self.image_manager.download_image(game, self.dl_slot.counter_inc, priority=0)
|
||||
# FIXME: this is a middle-ground solution for concurrent downloads
|
||||
while self.dl_slot.counter < len(game_list):
|
||||
QApplication.instance().processEvents()
|
||||
self.dl_slot.deleteLater()
|
||||
|
||||
igame_list = self.core.get_installed_list(include_dlc=True)
|
||||
|
||||
# FIXME: incorporate installed game status checking here for now, still slow
|
||||
for i, igame in enumerate(igame_list):
|
||||
# lk: do not check dlcs, they do not specify an executable
|
||||
if igame.is_dlc:
|
||||
continue
|
||||
|
||||
self.signals.progress.emit(
|
||||
int(i / len(igame_list) * 25) + 75,
|
||||
self.tr("Validating install for <b>{}</b>").format(igame.title)
|
||||
)
|
||||
if not os.path.exists(igame.install_path):
|
||||
# lk; since install_path is lost anyway, set keep_files to True
|
||||
# lk: to avoid spamming the log with "file not found" errors
|
||||
uninstall_game(self.core, igame.app_name, keep_files=True)
|
||||
logger.info(f"Uninstalled {igame.title}, because no game files exist")
|
||||
continue
|
||||
|
||||
# lk: games that don't have an override and can't find their executable due to case sensitivity
|
||||
# lk: will still erroneously require verification. This might need to be removed completely
|
||||
# lk: or be decoupled from the verification requirement
|
||||
if override_exe := self.core.lgd.config.get(igame.app_name, "override_exe", fallback=""):
|
||||
igame_executable = override_exe
|
||||
else:
|
||||
igame_executable = igame.executable
|
||||
# lk: Case-insensitive search for the game's executable (example: Brothers - A Tale of two Sons)
|
||||
executable_path = os.path.join(igame.install_path, igame_executable.replace("\\", "/").lstrip("/"))
|
||||
file_list = map(str.lower, os.listdir(os.path.dirname(executable_path)))
|
||||
if not os.path.basename(executable_path).lower() in file_list:
|
||||
igame.needs_verification = True
|
||||
self.core.lgd.set_installed_game(igame.app_name, igame)
|
||||
logger.info(f"{igame.title} needs verification")
|
||||
# FIXME: end
|
||||
|
||||
self.signals.progress.emit(100, self.tr("Launching Rare"))
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class ApiRequestWorker(LaunchWorker):
|
||||
def __init__(self):
|
||||
super(ApiRequestWorker, self).__init__()
|
||||
self.settings = QSettings()
|
||||
|
||||
def run_real(self) -> None:
|
||||
if self.settings.value("mac_meta", platform.system() == "Darwin", bool):
|
||||
try:
|
||||
result = self.core.get_game_and_dlc_list(update_assets=False, platform="Mac")
|
||||
except HTTPError:
|
||||
result = [], {}
|
||||
else:
|
||||
result = [], {}
|
||||
self.signals.result.emit(result, "mac")
|
||||
|
||||
if self.settings.value("win32_meta", False, bool):
|
||||
try:
|
||||
result = self.core.get_game_and_dlc_list(update_assets=False, platform="Win32")
|
||||
except HTTPError:
|
||||
result = [], {}
|
||||
else:
|
||||
result = [], {}
|
||||
self.signals.result.emit(result, "32bit")
|
||||
|
||||
try:
|
||||
# FIXME: Add this to RareCore
|
||||
self.core.lgd.entitlements = self.core.egs.get_user_entitlements()
|
||||
except HTTPError:
|
||||
logger.error("Failed to retrieve user entitlements")
|
||||
|
||||
|
||||
class LaunchDialog(QDialog):
|
||||
quit_app = pyqtSignal(int)
|
||||
start_app = pyqtSignal()
|
||||
completed = 0
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(LaunchDialog, self).__init__(parent=parent)
|
||||
|
@ -179,14 +33,17 @@ class LaunchDialog(QDialog):
|
|||
self.ui = Ui_LaunchDialog()
|
||||
self.ui.setupUi(self)
|
||||
|
||||
self.accept_close = False
|
||||
|
||||
self.progress_info = ElideLabel(parent=self)
|
||||
self.progress_info.setFixedHeight(False)
|
||||
self.ui.launch_layout.addWidget(self.progress_info)
|
||||
|
||||
self.core = LegendaryCoreSingleton()
|
||||
self.args = ArgumentsSingleton()
|
||||
self.thread_pool = QThreadPool().globalInstance()
|
||||
self.api_results = ApiResults()
|
||||
self.rcore = RareCore.instance()
|
||||
self.rcore.progress.connect(self.__on_progress)
|
||||
self.rcore.completed.connect(self.__on_completed)
|
||||
self.core = self.rcore.core()
|
||||
self.args = self.rcore.args()
|
||||
|
||||
self.login_dialog = LoginDialog(core=self.core, parent=parent)
|
||||
|
||||
|
@ -220,91 +77,22 @@ class LaunchDialog(QDialog):
|
|||
else:
|
||||
self.quit_app.emit(0)
|
||||
|
||||
def start_api_requests(self):
|
||||
# gamelist and no_asset games are from Image worker
|
||||
api_worker = ApiRequestWorker()
|
||||
api_worker.signals.result.connect(self.handle_api_worker_result)
|
||||
self.thread_pool.start(api_worker)
|
||||
|
||||
def launch(self):
|
||||
self.progress_info.setText(self.tr("Preparing Rare"))
|
||||
|
||||
if not self.args.offline:
|
||||
image_worker = ImageWorker()
|
||||
image_worker.signals.result.connect(self.handle_api_worker_result)
|
||||
image_worker.signals.progress.connect(self.update_progress)
|
||||
# lk: start the api requests worker after the manifests have been downloaded
|
||||
# lk: to avoid force updating the assets twice and causing inconsistencies
|
||||
image_worker.signals.finished.connect(self.start_api_requests)
|
||||
image_worker.signals.finished.connect(self.finish)
|
||||
self.thread_pool.start(image_worker)
|
||||
|
||||
# cloud save from another worker, because it is used in cloud_save_utils too
|
||||
cloud_worker = CloudWorker(self.core)
|
||||
cloud_worker.signals.result_ready.connect(lambda x: self.handle_api_worker_result(x, "saves"))
|
||||
self.thread_pool.start(cloud_worker)
|
||||
|
||||
else:
|
||||
self.completed = 2
|
||||
if self.core.lgd.assets:
|
||||
self.api_results.games, self.api_results.dlcs = self.core.get_game_and_dlc_list(
|
||||
update_assets=False, skip_ue=False
|
||||
)
|
||||
self.api_results.bit32_games = list(
|
||||
map(lambda i: i.app_name, self.core.get_game_list(False, "Win32"))
|
||||
)
|
||||
self.api_results.mac_games = list(
|
||||
map(lambda i: i.app_name, self.core.get_game_list(False, "Mac"))
|
||||
)
|
||||
else:
|
||||
logger.warning("No assets found. Falling back to empty game lists")
|
||||
self.api_results.games, self.api_results.dlcs = [], {}
|
||||
self.api_results.mac_games, self.api_results.bit32_games = [], []
|
||||
self.api_results.na_games, self.api_results.na_dlcs = [], {}
|
||||
self.api_results.saves = []
|
||||
self.finish()
|
||||
|
||||
def handle_api_worker_result(self, result, text):
|
||||
logger.debug(f"Api Request got from {text}")
|
||||
if text == "gamelist":
|
||||
if result:
|
||||
self.api_results.games, self.api_results.dlcs = result
|
||||
else:
|
||||
self.api_results.games, self.api_results.dlcs = self.core.get_game_and_dlc_list(
|
||||
update_assets=False, skip_ue=False
|
||||
)
|
||||
elif text == "no_assets":
|
||||
if result:
|
||||
self.api_results.na_games, self.api_results.na_dlcs = result
|
||||
else:
|
||||
self.api_results.na_games, self.api_results.na_dlcs = self.core.get_non_asset_library_items(
|
||||
force_refresh=False, skip_ue=False
|
||||
)
|
||||
elif text == "32bit":
|
||||
self.api_results.bit32_games = [i.app_name for i in result[0]] if result else []
|
||||
elif text == "mac":
|
||||
self.api_results.mac_games = [i.app_name for i in result[0]] if result else []
|
||||
elif text == "saves":
|
||||
self.api_results.saves = result
|
||||
|
||||
if self.api_results:
|
||||
self.finish()
|
||||
self.rcore.fetch()
|
||||
|
||||
@pyqtSlot(int, str)
|
||||
def update_progress(self, i: int, m: str):
|
||||
def __on_progress(self, i: int, m: str):
|
||||
self.ui.progress_bar.setValue(i)
|
||||
self.progress_info.setText(m)
|
||||
|
||||
def finish(self):
|
||||
self.completed += 1
|
||||
if self.completed >= 2:
|
||||
logger.info("App starting")
|
||||
ApiResultsSingleton(self.api_results)
|
||||
self.completed += 1
|
||||
self.start_app.emit()
|
||||
def __on_completed(self):
|
||||
logger.info("App starting")
|
||||
self.accept_close = True
|
||||
self.start_app.emit()
|
||||
|
||||
def reject(self) -> None:
|
||||
if self.completed >= 3:
|
||||
if self.accept_close:
|
||||
super(LaunchDialog, self).reject()
|
||||
else:
|
||||
pass
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import Qt, QSettings, QTimer, QSize, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCloseEvent, QCursor
|
||||
from PyQt5.QtGui import QCloseEvent, QCursor, QShowEvent
|
||||
from PyQt5.QtWidgets import (
|
||||
QMainWindow,
|
||||
QApplication,
|
||||
|
@ -107,8 +107,9 @@ class MainWindow(QMainWindow):
|
|||
logger.warning("Discord RPC module not found")
|
||||
|
||||
self.timer = QTimer()
|
||||
self.timer.setInterval(1000)
|
||||
self.timer.timeout.connect(self.timer_finished)
|
||||
self.timer.start(1000)
|
||||
self.timer.start()
|
||||
|
||||
self.tray_icon: TrayIcon = TrayIcon(self)
|
||||
self.tray_icon.exit_app.connect(self.on_exit_app)
|
||||
|
@ -142,6 +143,15 @@ class MainWindow(QMainWindow):
|
|||
self.resize(window_size)
|
||||
self.move(screen_rect.center() - self.rect().adjusted(0, 0, decor_width, decor_height).center())
|
||||
|
||||
# lk: For the gritty details see `RareCore.load_pixmaps()` method
|
||||
# Just before the window is shown, fire a timer to load game icons
|
||||
# This is by nature a little iffy because we don't really know if the
|
||||
# has been shown, and it might make the window delay as widgets being are updated.
|
||||
# Still better than showing a hanged window frame for a few seconds.
|
||||
def showEvent(self, a0: QShowEvent) -> None:
|
||||
if not self._window_launched:
|
||||
QTimer.singleShot(100, self.rcore.load_pixmaps)
|
||||
|
||||
@pyqtSlot()
|
||||
def show(self) -> None:
|
||||
super(MainWindow, self).show()
|
||||
|
@ -198,7 +208,7 @@ class MainWindow(QMainWindow):
|
|||
if action.startswith("show"):
|
||||
self.show()
|
||||
os.remove(file_path)
|
||||
self.timer.start(1000)
|
||||
self.timer.start()
|
||||
|
||||
@pyqtSlot()
|
||||
@pyqtSlot(int)
|
||||
|
|
|
@ -2,14 +2,12 @@ from logging import getLogger
|
|||
|
||||
from PyQt5.QtCore import QSettings, Qt, pyqtSlot
|
||||
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
|
||||
from legendary.models.game import Game
|
||||
|
||||
from rare.models.game import RareGame
|
||||
from rare.shared import (
|
||||
LegendaryCoreSingleton,
|
||||
GlobalSignalsSingleton,
|
||||
ArgumentsSingleton,
|
||||
ApiResultsSingleton,
|
||||
ImageManagerSingleton,
|
||||
)
|
||||
from rare.shared import RareCore
|
||||
|
@ -32,7 +30,6 @@ class GamesTab(QStackedWidget):
|
|||
self.core = LegendaryCoreSingleton()
|
||||
self.signals = GlobalSignalsSingleton()
|
||||
self.args = ArgumentsSingleton()
|
||||
self.api_results = ApiResultsSingleton()
|
||||
self.image_manager = ImageManagerSingleton()
|
||||
self.settings = QSettings()
|
||||
|
||||
|
@ -142,37 +139,18 @@ class GamesTab(QStackedWidget):
|
|||
@pyqtSlot()
|
||||
def update_count_games_label(self):
|
||||
self.head_bar.set_games_count(
|
||||
len(self.core.get_installed_list()), len(self.api_results.games + self.api_results.na_games)
|
||||
len([game for game in self.rcore.games if game.is_installed]),
|
||||
len([game for game in self.rcore.games])
|
||||
)
|
||||
|
||||
# FIXME: Remove this when RareCore is in place
|
||||
def __create_game_with_dlcs(self, game: Game) -> RareGame:
|
||||
rgame = RareGame(self.core, self.image_manager, game)
|
||||
rgame.saves = [save for save in self.api_results.saves if save.app_name == game.app_name]
|
||||
for dlc_dict in [self.api_results.dlcs, self.api_results.na_dlcs]:
|
||||
if game_dlcs := dlc_dict.get(rgame.game.catalog_item_id, False):
|
||||
for dlc in game_dlcs:
|
||||
rdlc = RareGame(self.core, self.image_manager, dlc)
|
||||
self.rcore.add_game(rdlc)
|
||||
# lk: plug dlc progress signals to the game's
|
||||
rdlc.signals.progress.start.connect(rgame.signals.progress.start)
|
||||
rdlc.signals.progress.update.connect(rgame.signals.progress.update)
|
||||
rdlc.signals.progress.finish.connect(rgame.signals.progress.finish)
|
||||
rdlc.set_pixmap()
|
||||
rgame.owned_dlcs.append(rdlc)
|
||||
return rgame
|
||||
|
||||
def setup_game_list(self):
|
||||
for game in self.api_results.games + self.api_results.na_games:
|
||||
rgame = self.__create_game_with_dlcs(game)
|
||||
self.rcore.add_game(rgame)
|
||||
for rgame in self.rcore.games:
|
||||
icon_widget, list_widget = self.add_library_widget(rgame)
|
||||
if not icon_widget or not list_widget:
|
||||
logger.warning(f"Excluding {rgame.app_name} from the game list")
|
||||
continue
|
||||
self.icon_view.layout().addWidget(icon_widget)
|
||||
self.list_view.layout().addWidget(list_widget)
|
||||
rgame.set_pixmap()
|
||||
self.filter_games(self.active_filter)
|
||||
self.update_count_games_label()
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from typing import Tuple, List, Union
|
||||
from typing import Tuple, List, Union, Optional
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSlot
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.apiresults import ApiResults
|
||||
from rare.models.game import RareGame
|
||||
from rare.models.signals import GlobalSignals
|
||||
from rare.shared import RareCore
|
||||
|
@ -20,7 +19,6 @@ class LibraryWidgetController(QObject):
|
|||
self.rcore = RareCore.instance()
|
||||
self.core: LegendaryCore = self.rcore.core()
|
||||
self.signals: GlobalSignals = self.rcore.signals()
|
||||
self.api_results: ApiResults = self.rcore.api_results()
|
||||
|
||||
self.signals.game.installed.connect(self.sort_list)
|
||||
self.signals.game.uninstalled.connect(self.sort_list)
|
||||
|
@ -115,7 +113,7 @@ class LibraryWidgetController(QObject):
|
|||
list_widgets = self._list_container.findChildren(ListGameWidget)
|
||||
icon_app_names = set([iw.rgame.app_name for iw in icon_widgets])
|
||||
list_app_names = set([lw.rgame.app_name for lw in list_widgets])
|
||||
games = self.api_results.games + self.api_results.na_games
|
||||
games = list(self.rcore.games)
|
||||
game_app_names = set([g.app_name for g in games])
|
||||
new_icon_app_names = game_app_names.difference(icon_app_names)
|
||||
new_list_app_names = game_app_names.difference(list_app_names)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from PyQt5.QtCore import QSettings, pyqtSignal
|
||||
from PyQt5.QtCore import QSettings, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QLabel,
|
||||
QPushButton,
|
||||
|
@ -8,7 +8,7 @@ from PyQt5.QtWidgets import (
|
|||
)
|
||||
from qtawesome import IconWidget
|
||||
|
||||
from rare.shared import ApiResultsSingleton
|
||||
from rare.shared import RareCore
|
||||
from rare.utils.extra_widgets import SelectViewWidget, ButtonLineEdit
|
||||
from rare.utils.misc import icon
|
||||
|
||||
|
@ -21,7 +21,7 @@ class GameListHeadBar(QWidget):
|
|||
|
||||
def __init__(self, parent=None):
|
||||
super(GameListHeadBar, self).__init__(parent=parent)
|
||||
self.api_results = ApiResultsSingleton()
|
||||
self.rcore = RareCore.instance()
|
||||
self.settings = QSettings()
|
||||
|
||||
self.filter = QComboBox()
|
||||
|
@ -38,15 +38,15 @@ class GameListHeadBar(QWidget):
|
|||
"installed",
|
||||
"offline",
|
||||
]
|
||||
if self.api_results.bit32_games:
|
||||
if self.rcore.bit32_games:
|
||||
self.filter.addItem(self.tr("32 Bit Games"))
|
||||
self.available_filters.append("32bit")
|
||||
|
||||
if self.api_results.mac_games:
|
||||
if self.rcore.mac_games:
|
||||
self.filter.addItem(self.tr("Mac games"))
|
||||
self.available_filters.append("mac")
|
||||
|
||||
if self.api_results.na_games:
|
||||
if self.rcore.no_asset_games:
|
||||
self.filter.addItem(self.tr("Exclude Origin"))
|
||||
self.available_filters.append("installable")
|
||||
|
||||
|
@ -107,6 +107,7 @@ class GameListHeadBar(QWidget):
|
|||
|
||||
self.refresh_list = QPushButton()
|
||||
self.refresh_list.setIcon(icon("fa.refresh")) # Reload icon
|
||||
self.refresh_list.clicked.connect(self.rcore.fetch)
|
||||
|
||||
layout = QHBoxLayout()
|
||||
layout.setContentsMargins(0, 5, 0, 5)
|
||||
|
@ -130,6 +131,11 @@ class GameListHeadBar(QWidget):
|
|||
self.installed_label.setText(str(inst))
|
||||
self.available_label.setText(str(avail))
|
||||
|
||||
def filter_changed(self, i):
|
||||
@pyqtSlot()
|
||||
def refresh_clicked(self):
|
||||
self.rcore.fetch()
|
||||
|
||||
@pyqtSlot(int)
|
||||
def filter_changed(self, i: int):
|
||||
self.filterChanged.emit(self.available_filters[i])
|
||||
self.settings.setValue("filter", i)
|
||||
|
|
|
@ -162,16 +162,9 @@ class ImportGroup(QGroupBox):
|
|||
self.ui.setupUi(self)
|
||||
self.rcore = RareCore.instance()
|
||||
self.core = RareCore.instance().core()
|
||||
self.api_results = RareCore.instance().api_results()
|
||||
|
||||
#self.app_name_list = [rgame.app_name for rgame in self.rcore.games]
|
||||
self.app_name_list = [game.app_name for game in self.api_results.games]
|
||||
#self.install_dir_list = [rgame.folder_name for rgame in self.rcore.games if not rgame.is_dlc]
|
||||
self.install_dir_list = [
|
||||
game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value", game.app_name)
|
||||
for game in self.api_results.games
|
||||
if not game.is_dlc
|
||||
]
|
||||
self.app_name_list = [rgame.app_name for rgame in self.rcore.games]
|
||||
self.install_dir_list = [rgame.folder_name for rgame in self.rcore.games if not rgame.is_dlc]
|
||||
|
||||
self.path_edit = PathEdit(
|
||||
self.core.get_default_install_dir(),
|
||||
|
@ -185,8 +178,8 @@ class ImportGroup(QGroupBox):
|
|||
self.app_name_edit = IndicatorLineEdit(
|
||||
placeholder=self.tr("Use in case the app name was not found automatically"),
|
||||
completer=AppNameCompleter(
|
||||
# app_names=[(rgame.app_name, rgame.app_title) for rgame in self.rcore.games]
|
||||
app_names = [(i.app_name, i.app_title) for i in self.api_results.games]),
|
||||
app_names=[(rgame.app_name, rgame.app_title) for rgame in self.rcore.games],
|
||||
),
|
||||
edit_func=self.app_name_edit_callback,
|
||||
parent=self,
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from PyQt5.QtWidgets import QStackedWidget, QTabWidget
|
||||
from legendary.core import LegendaryCore
|
||||
|
||||
from rare.shared import ApiResultsSingleton
|
||||
from rare.shared.rare_core import RareCore
|
||||
from rare.utils.paths import cache_dir
|
||||
from .game_info import ShopGameInfo
|
||||
from .search_results import SearchResults
|
||||
|
@ -16,7 +16,7 @@ class Shop(QStackedWidget):
|
|||
def __init__(self, core: LegendaryCore):
|
||||
super(Shop, self).__init__()
|
||||
self.core = core
|
||||
self.api_results = ApiResultsSingleton()
|
||||
self.rcore = RareCore.instance()
|
||||
self.api_core = ShopApiCore(
|
||||
self.core.egs.session.headers["Authorization"],
|
||||
self.core.language_code,
|
||||
|
@ -36,7 +36,7 @@ class Shop(QStackedWidget):
|
|||
self.addWidget(self.search_results)
|
||||
self.search_results.show_info.connect(self.show_game_info)
|
||||
self.info = ShopGameInfo(
|
||||
[i.asset_infos["Windows"].namespace for i in self.api_results.games],
|
||||
[i.asset_infos["Windows"].namespace for i in self.rcore.game_list if bool(i.asset_infos)],
|
||||
self.api_core,
|
||||
)
|
||||
self.addWidget(self.info)
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
from legendary.models.game import Game, SaveGameFile
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApiResults:
|
||||
games: Optional[List[Game]] = None
|
||||
dlcs: Optional[Dict[str, List[Game]]] = None
|
||||
bit32_games: Optional[List] = None
|
||||
mac_games: Optional[List] = None
|
||||
na_games: Optional[List[Game]] = None
|
||||
na_dlcs: Optional[Dict[str, List[Game]]] = None
|
||||
saves: Optional[List[SaveGameFile]] = None
|
||||
|
||||
def __bool__(self):
|
||||
return (
|
||||
self.games is not None
|
||||
and self.dlcs is not None
|
||||
and self.bit32_games is not None
|
||||
and self.mac_games is not None
|
||||
and self.na_games is not None
|
||||
and self.na_dlcs is not None
|
||||
and self.saves is not None
|
||||
)
|
|
@ -10,7 +10,6 @@ from argparse import Namespace
|
|||
from typing import Optional
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.apiresults import ApiResults
|
||||
from rare.models.signals import GlobalSignals
|
||||
from .image_manager import ImageManager
|
||||
from .rare_core import RareCore
|
||||
|
@ -32,7 +31,3 @@ def LegendaryCoreSingleton() -> LegendaryCore:
|
|||
|
||||
def ImageManagerSingleton() -> ImageManager:
|
||||
return RareCore.instance().image_manager()
|
||||
|
||||
|
||||
def ApiResultsSingleton(res: ApiResults = None) -> Optional[ApiResults]:
|
||||
return RareCore.instance().api_results(res)
|
||||
|
|
|
@ -387,11 +387,11 @@ class ImageManager(QObject):
|
|||
return data
|
||||
|
||||
def download_image(
|
||||
self, game: Game, load_callback: Callable[[Game], None], priority: int, force: bool = False
|
||||
self, game: Game, load_callback: Callable[[], None], priority: int, force: bool = False
|
||||
) -> None:
|
||||
updates, json_data = self.__prepare_download(game, force)
|
||||
if not updates:
|
||||
load_callback(game)
|
||||
load_callback()
|
||||
return
|
||||
if updates and game.app_name not in self.__worker_app_names:
|
||||
image_worker = ImageManager.Worker(self.__download, updates, json_data, game)
|
||||
|
|
|
@ -1,26 +1,43 @@
|
|||
import configparser
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
from argparse import Namespace
|
||||
from itertools import chain
|
||||
from logging import getLogger
|
||||
from typing import Optional, Dict, Iterator, Callable, List, Union
|
||||
from typing import Dict, Iterator, Callable, Tuple, Optional, List, Union
|
||||
|
||||
from PyQt5.QtCore import QObject, QThreadPool
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QSettings, pyqtSlot, QThreadPool
|
||||
from legendary.lfs.eos import EOSOverlayApp
|
||||
from legendary.models.game import Game, SaveGameFile
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.apiresults import ApiResults
|
||||
from rare.models.game import RareGame, RareEosOverlay
|
||||
from rare.models.signals import GlobalSignals
|
||||
from .workers import QueueWorker, VerifyWorker, MoveWorker
|
||||
from .image_manager import ImageManager
|
||||
from .workers import (
|
||||
QueueWorker,
|
||||
VerifyWorker,
|
||||
MoveWorker,
|
||||
SavesWorker,
|
||||
GamesWorker,
|
||||
NonAssetWorker,
|
||||
EntitlementsWorker,
|
||||
Win32Worker,
|
||||
MacOSWorker,
|
||||
FetchWorker,
|
||||
)
|
||||
from .workers.uninstall import uninstall_game
|
||||
from .workers.worker import QueueWorkerInfo, QueueWorkerState
|
||||
|
||||
logger = getLogger("RareCore")
|
||||
|
||||
|
||||
class RareCore(QObject):
|
||||
progress = pyqtSignal(int, str)
|
||||
completed = pyqtSignal()
|
||||
|
||||
# lk: special case class attribute, this has to be here
|
||||
__instance: Optional['RareCore'] = None
|
||||
|
||||
def __init__(self, args: Namespace):
|
||||
|
@ -31,13 +48,21 @@ class RareCore(QObject):
|
|||
self.__signals: Optional[GlobalSignals] = None
|
||||
self.__core: Optional[LegendaryCore] = None
|
||||
self.__image_manager: Optional[ImageManager] = None
|
||||
self.__api_results: Optional[ApiResults] = None
|
||||
|
||||
self.__games_fetched: bool = False
|
||||
self.__non_asset_fetched: bool = False
|
||||
self.__win32_fetched: bool = False
|
||||
self.__macos_fetched: bool = False
|
||||
self.__saves_fetched: bool = False
|
||||
self.__entitlements_fetched: bool = False
|
||||
|
||||
self.args(args)
|
||||
self.signals(init=True)
|
||||
self.core(init=True)
|
||||
self.image_manager(init=True)
|
||||
|
||||
self.settings = QSettings()
|
||||
|
||||
self.queue_workers: List[QueueWorker] = []
|
||||
self.queue_threadpool = QThreadPool()
|
||||
self.queue_threadpool.setMaxThreadCount(2)
|
||||
|
@ -142,19 +167,7 @@ class RareCore(QObject):
|
|||
self.__image_manager = ImageManager(self.signals(), self.core())
|
||||
return self.__image_manager
|
||||
|
||||
def api_results(self, res: ApiResults = None) -> Optional[ApiResults]:
|
||||
if self.__api_results is None and res is None:
|
||||
raise RuntimeError("Uninitialized use of ApiResultsSingleton")
|
||||
if self.__api_results is not None and res is not None:
|
||||
raise RuntimeError("ApiResults already initialized")
|
||||
if res is not None:
|
||||
self.__api_results = res
|
||||
return self.__api_results
|
||||
|
||||
def deleteLater(self) -> None:
|
||||
del self.__api_results
|
||||
self.__api_results = None
|
||||
|
||||
self.__image_manager.deleteLater()
|
||||
del self.__image_manager
|
||||
self.__image_manager = None
|
||||
|
@ -174,12 +187,51 @@ class RareCore(QObject):
|
|||
|
||||
super(RareCore, self).deleteLater()
|
||||
|
||||
def __validate_installed(self):
|
||||
filter_lambda = lambda rg: rg.is_installed and not (rg.is_dlc or rg.is_non_asset)
|
||||
length = len(list(self.__filter_games(filter_lambda)))
|
||||
for i, rgame in enumerate(self.__filter_games(filter_lambda)):
|
||||
self.progress.emit(
|
||||
int(i / length * 25) + 75,
|
||||
self.tr("Validating install for <b>{}</b>").format(rgame.app_title)
|
||||
)
|
||||
if not os.path.exists(rgame.igame.install_path):
|
||||
# lk: since install_path is lost anyway, set keep_files to True
|
||||
# lk: to avoid spamming the log with "file not found" errors
|
||||
for dlc in rgame.owned_dlcs:
|
||||
if dlc.is_installed:
|
||||
logger.info(f'Uninstalling DLC "{dlc.app_name}" ({dlc.app_title})...')
|
||||
uninstall_game(self.__core, dlc.app_name, keep_files=True)
|
||||
dlc.igame = None
|
||||
logger.info(
|
||||
f'Removing "{rgame.app_title}" because "{rgame.igame.install_path}" does not exist...'
|
||||
)
|
||||
uninstall_game(self.__core, rgame.app_name, keep_files=True)
|
||||
logger.info(f"Uninstalled {rgame.app_title}, because no game files exist")
|
||||
rgame.igame = None
|
||||
continue
|
||||
# lk: games that don't have an override and can't find their executable due to case sensitivity
|
||||
# lk: will still erroneously require verification. This might need to be removed completely
|
||||
# lk: or be decoupled from the verification requirement
|
||||
if override_exe := self.__core.lgd.config.get(rgame.app_name, "override_exe", fallback=""):
|
||||
igame_executable = override_exe
|
||||
else:
|
||||
igame_executable = rgame.igame.executable
|
||||
# lk: Case-insensitive search for the game's executable (example: Brothers - A Tale of two Sons)
|
||||
executable_path = os.path.join(rgame.igame.install_path, igame_executable.replace("\\", "/").lstrip("/"))
|
||||
file_list = map(str.lower, os.listdir(os.path.dirname(executable_path)))
|
||||
if not os.path.basename(executable_path).lower() in file_list:
|
||||
rgame.igame.needs_verification = True
|
||||
self.__core.lgd.set_installed_game(rgame.app_name, rgame.igame)
|
||||
rgame.update_igame()
|
||||
logger.info(f"{rgame.app_title} needs verification")
|
||||
|
||||
def get_game(self, app_name: str) -> Union[RareEosOverlay, RareGame]:
|
||||
if app_name == EOSOverlayApp.app_name:
|
||||
return self.__eos_overlay_rgame
|
||||
return self.__games[app_name]
|
||||
|
||||
def add_game(self, rgame: RareGame) -> None:
|
||||
def __add_game(self, rgame: RareGame) -> None:
|
||||
rgame.signals.download.enqueue.connect(self.__signals.download.enqueue)
|
||||
rgame.signals.download.dequeue.connect(self.__signals.download.dequeue)
|
||||
rgame.signals.game.install.connect(self.__signals.game.install)
|
||||
|
@ -193,6 +245,146 @@ class RareCore(QObject):
|
|||
def __filter_games(self, condition: Callable[[RareGame], bool]) -> Iterator[RareGame]:
|
||||
return filter(condition, self.__games.values())
|
||||
|
||||
def __create_or_update_rgame(self, game: Game) -> RareGame:
|
||||
if rgame := self.__games.get(game.app_name, False):
|
||||
logger.warning(f"{rgame.app_name} already present in {type(self).__name__}")
|
||||
logger.info(f"Updating Game for {rgame.app_name}")
|
||||
rgame.update_rgame()
|
||||
else:
|
||||
rgame = RareGame(self.__core, self.__image_manager, game)
|
||||
return rgame
|
||||
|
||||
def __add_games_and_dlcs(self, games: List[Game], dlcs_dict: Dict[str, List]) -> None:
|
||||
for game in games:
|
||||
rgame = self.__create_or_update_rgame(game)
|
||||
if game_dlcs := dlcs_dict.get(rgame.game.catalog_item_id, False):
|
||||
for dlc in game_dlcs:
|
||||
rdlc = self.__create_or_update_rgame(dlc)
|
||||
# lk: plug dlc progress signals to the game's
|
||||
rdlc.signals.progress.start.connect(rgame.signals.progress.start)
|
||||
rdlc.signals.progress.update.connect(rgame.signals.progress.update)
|
||||
rdlc.signals.progress.finish.connect(rgame.signals.progress.finish)
|
||||
rgame.owned_dlcs.append(rdlc)
|
||||
self.__add_game(rdlc)
|
||||
self.__add_game(rgame)
|
||||
|
||||
@pyqtSlot(object, int)
|
||||
def handle_result(self, result: Tuple, res_type: int):
|
||||
status = ""
|
||||
if res_type == FetchWorker.Result.GAMES:
|
||||
games, dlc_dict = result
|
||||
self.__add_games_and_dlcs(games, dlc_dict)
|
||||
self.__games_fetched = True
|
||||
status = "Loaded games for Windows"
|
||||
if res_type == FetchWorker.Result.NON_ASSET:
|
||||
games, dlc_dict = result
|
||||
self.__add_games_and_dlcs(games, dlc_dict)
|
||||
self.__non_asset_fetched = True
|
||||
status = "Loaded games without assets"
|
||||
if res_type == FetchWorker.Result.WIN32:
|
||||
self.__win32_fetched = True
|
||||
status = "Loaded games for Windows (32bit)"
|
||||
if res_type == FetchWorker.Result.MACOS:
|
||||
self.__macos_fetched = True
|
||||
status = "Loaded games for MacOS"
|
||||
if res_type == FetchWorker.Result.SAVES:
|
||||
saves, _ = result
|
||||
for save in saves:
|
||||
self.__games[save.app_name].saves.append(save)
|
||||
self.__saves_fetched = True
|
||||
status = "Loaded save games"
|
||||
if res_type == FetchWorker.Result.ENTITLEMENTS:
|
||||
self.__core.lgd.entitlements = result
|
||||
self.__entitlements_fetched = True
|
||||
status = "Loaded game entitlements"
|
||||
logger.debug(f"Got API results for {FetchWorker.Result(res_type).name}")
|
||||
|
||||
fetched = [
|
||||
self.__games_fetched,
|
||||
self.__non_asset_fetched,
|
||||
self.__win32_fetched,
|
||||
self.__macos_fetched,
|
||||
self.__saves_fetched,
|
||||
self.__entitlements_fetched,
|
||||
]
|
||||
|
||||
self.progress.emit(sum(fetched) * 10, status)
|
||||
|
||||
if all(fetched):
|
||||
self.progress.emit(75, self.tr("Validating game installations"))
|
||||
self.__validate_installed()
|
||||
self.progress.emit(100, self.tr("Launching Rare"))
|
||||
logger.debug(f"Fetch time {time.time() - self.start_time} seconds")
|
||||
self.completed.emit()
|
||||
|
||||
def fetch(self):
|
||||
self.__games_fetched: bool = False
|
||||
self.__non_asset_fetched: bool = False
|
||||
self.__win32_fetched: bool = False
|
||||
self.__macos_fetched: bool = False
|
||||
self.__saves_fetched: bool = False
|
||||
self.__entitlements_fetched: bool = False
|
||||
|
||||
self.start_time = time.time()
|
||||
games_worker = GamesWorker(self.__core, self.__args)
|
||||
games_worker.signals.result.connect(self.handle_result)
|
||||
games_worker.signals.finished.connect(self.fetch_saves)
|
||||
games_worker.signals.finished.connect(self.fetch_extra)
|
||||
QThreadPool.globalInstance().start(games_worker)
|
||||
|
||||
def fetch_saves(self):
|
||||
if not self.__args.offline:
|
||||
saves_worker = SavesWorker(self.__core, self.__args)
|
||||
saves_worker.signals.result.connect(self.handle_result)
|
||||
QThreadPool.globalInstance().start(saves_worker)
|
||||
else:
|
||||
self.__saves_fetched = True
|
||||
|
||||
def fetch_extra(self):
|
||||
non_asset_worker = NonAssetWorker(self.__core, self.__args)
|
||||
non_asset_worker.signals.result.connect(self.handle_result)
|
||||
QThreadPool.globalInstance().start(non_asset_worker)
|
||||
|
||||
entitlements_worker = EntitlementsWorker(self.__core, self.__args)
|
||||
entitlements_worker.signals.result.connect(self.handle_result)
|
||||
QThreadPool.globalInstance().start(entitlements_worker)
|
||||
|
||||
if self.settings.value("win32_meta", False, bool) and not self.__win32_fetched:
|
||||
win32_worker = Win32Worker(self.__core, self.__args)
|
||||
win32_worker.signals.result.connect(self.handle_result)
|
||||
QThreadPool.globalInstance().start(win32_worker)
|
||||
else:
|
||||
self.__win32_fetched = True
|
||||
|
||||
if self.settings.value("mac_meta", platform.system() == "Darwin", bool) and not self.__macos_fetched:
|
||||
macos_worker = MacOSWorker(self.__core, self.__args)
|
||||
macos_worker.signals.result.connect(self.handle_result)
|
||||
QThreadPool.globalInstance().start(macos_worker)
|
||||
else:
|
||||
self.__macos_fetched = True
|
||||
|
||||
def load_pixmaps(self) -> None:
|
||||
"""
|
||||
Load pixmaps for all games
|
||||
|
||||
This exists here solely to fight signal and possibly threading issues.
|
||||
The initial image loading at startup should not be done in the RareGame class
|
||||
for two reasons. It will delay startup due to widget updates and the image
|
||||
might become availabe before the UI is brought up. In case of the second, we
|
||||
will get both a long queue of signals to be serviced and some of them might
|
||||
be not connected yet so the widget won't be updated. So do the loading here
|
||||
by calling this after the MainWindow has finished initializing.
|
||||
|
||||
@return: None
|
||||
"""
|
||||
QThreadPool.globalInstance().start(self.__load_pixmaps)
|
||||
|
||||
def __load_pixmaps(self) -> None:
|
||||
# time.sleep(0.1)
|
||||
for rgame in self.__games.values():
|
||||
rgame.set_pixmap()
|
||||
# time.sleep(0.0001)
|
||||
|
||||
@property
|
||||
def games_and_dlcs(self) -> Iterator[RareGame]:
|
||||
for app_name in self.__games:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .fetch import FetchWorker, GamesWorker, NonAssetWorker, EntitlementsWorker, Win32Worker, MacOSWorker, SavesWorker
|
||||
from .install_info import InstallInfoWorker
|
||||
from .move import MoveWorker
|
||||
from .uninstall import UninstallWorker
|
||||
|
|
104
rare/shared/workers/fetch.py
Normal file
104
rare/shared/workers/fetch.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
import time
|
||||
from argparse import Namespace
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
from requests.exceptions import ConnectionError, HTTPError
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from .worker import Worker
|
||||
|
||||
logger = getLogger("FetchWorker")
|
||||
|
||||
|
||||
class FetchWorker(Worker):
|
||||
class Result(IntEnum):
|
||||
GAMES = 1
|
||||
NON_ASSET = 2
|
||||
WIN32 = 3
|
||||
MACOS = 4
|
||||
SAVES = 5
|
||||
ENTITLEMENTS = 6
|
||||
|
||||
class Signals(QObject):
|
||||
result = pyqtSignal(object, int)
|
||||
finished = pyqtSignal()
|
||||
|
||||
def __init__(self, core: LegendaryCore, args: Namespace):
|
||||
super(Worker, self).__init__()
|
||||
self.signals = FetchWorker.Signals()
|
||||
self.core = core
|
||||
self.args = args
|
||||
|
||||
|
||||
class GamesWorker(FetchWorker):
|
||||
def run_real(self):
|
||||
start_time = time.time()
|
||||
result = self.core.get_game_and_dlc_list(update_assets=not self.args.offline, platform="Windows", skip_ue=False)
|
||||
self.signals.result.emit(result, FetchWorker.Result.GAMES)
|
||||
logger.debug(f"Games: {len(result[0])}, DLCs {len(result[1])}")
|
||||
logger.debug(f"Request Games: {time.time() - start_time} seconds")
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class NonAssetWorker(FetchWorker):
|
||||
def run_real(self):
|
||||
start_time = time.time()
|
||||
try:
|
||||
result = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.warning(f"Exception while fetching non asset games from EGS: {e}")
|
||||
result = ([], {})
|
||||
self.signals.result.emit(result, FetchWorker.Result.NON_ASSET)
|
||||
logger.debug(f"Non asset: {len(result[0])}, DLCs {len(result[1])}")
|
||||
logger.debug(f"Request Non Asset: {time.time() - start_time} seconds")
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class EntitlementsWorker(FetchWorker):
|
||||
def run_real(self):
|
||||
start_time = time.time()
|
||||
try:
|
||||
entitlements = self.core.egs.get_user_entitlements()
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.error(f"Failed to retrieve user entitlements from EGS: {e}")
|
||||
entitlements = {}
|
||||
self.signals.result.emit(entitlements, FetchWorker.Result.ENTITLEMENTS)
|
||||
logger.debug(f"Entitlements: {len(list(entitlements))}")
|
||||
logger.debug(f"Request Entitlements: {time.time() - start_time} seconds")
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class Win32Worker(FetchWorker):
|
||||
def run_real(self):
|
||||
start_time = time.time()
|
||||
result = self.core.get_game_and_dlc_list(update_assets=False, platform="Win32")
|
||||
self.signals.result.emit(([], {}), FetchWorker.Result.WIN32)
|
||||
logger.debug(f"Win32: {len(result[0])}, DLCs {len(result[1])}")
|
||||
logger.debug(f"Request Win32: {time.time() - start_time} seconds")
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class MacOSWorker(FetchWorker):
|
||||
def run_real(self):
|
||||
start_time = time.time()
|
||||
result = self.core.get_game_and_dlc_list(update_assets=False, platform="Mac")
|
||||
self.signals.result.emit(([], {}), FetchWorker.Result.MACOS)
|
||||
logger.debug(f"MacOS: {len(result[0])}, DLCs {len(result[1])}")
|
||||
logger.debug(f"Request MacOS: {time.time() - start_time} seconds")
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class SavesWorker(FetchWorker):
|
||||
def run_real(self):
|
||||
start_time = time.time()
|
||||
try:
|
||||
result = self.core.get_save_games()
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.warning(f"Exception while fetching saves fromt EGS: {e}")
|
||||
result = list()
|
||||
self.signals.result.emit((result, {}), FetchWorker.Result.SAVES)
|
||||
logger.debug(f"Saves: {len(result)}")
|
||||
logger.debug(f"Request saves: {time.time() - start_time} seconds")
|
||||
self.signals.finished.emit()
|
|
@ -21,7 +21,6 @@ from legendary.core import LegendaryCore
|
|||
from legendary.models.game import Game
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
from rare.models.apiresults import ApiResults
|
||||
from rare.utils.paths import resources_path
|
||||
|
||||
logger = getLogger("Utils")
|
||||
|
@ -194,13 +193,6 @@ def get_raw_save_path(game: Game):
|
|||
)
|
||||
|
||||
|
||||
def get_default_platform(app_name, api_results: ApiResults):
|
||||
if platform.system() != "Darwin" or app_name not in api_results.mac_games:
|
||||
return "Windows"
|
||||
else:
|
||||
return "Mac"
|
||||
|
||||
|
||||
def icon(icn_str: str, fallback: str = None, **kwargs):
|
||||
try:
|
||||
return qtawesome.icon(icn_str, **kwargs)
|
||||
|
|
Loading…
Reference in a new issue