diff --git a/rare/components/__init__.py b/rare/components/__init__.py index 8d0e4fd4..684a1133 100644 --- a/rare/components/__init__.py +++ b/rare/components/__init__.py @@ -45,8 +45,6 @@ class Rare(RareApp): self.signals = RareCore.instance().signals() self.core = RareCore.instance().core() - config_helper.init_config_handler(self.core) - lang = self.settings.value("language", self.core.language_code, type=str) self.load_translator(lang) diff --git a/rare/components/tabs/games/game_info/game_info.py b/rare/components/tabs/games/game_info/game_info.py index 0fd1d7d4..44e5b691 100644 --- a/rare/components/tabs/games/game_info/game_info.py +++ b/rare/components/tabs/games/game_info/game_info.py @@ -284,7 +284,9 @@ class GameInfo(QWidget, SideTabContents): ) self.ui.platform.setText( - self.rgame.igame.platform if self.rgame.is_installed and not self.rgame.is_non_asset else "Windows" + self.rgame.igame.platform + if self.rgame.is_installed and not self.rgame.is_non_asset + else self.core.default_platform ) self.ui.lbl_grade.setDisabled( diff --git a/rare/components/tabs/games/integrations/ubisoft_group.py b/rare/components/tabs/games/integrations/ubisoft_group.py index eddd303d..008912be 100644 --- a/rare/components/tabs/games/integrations/ubisoft_group.py +++ b/rare/components/tabs/games/integrations/ubisoft_group.py @@ -74,7 +74,6 @@ class UbiConnectWorker(Worker): def __init__(self, core: LegendaryCore, ubi_account_id, partner_link_id): super(UbiConnectWorker, self).__init__() self.signals = UbiConnectWorker.Signals() - self.setAutoDelete(True) self.core = core self.ubi_account_id = ubi_account_id self.partner_link_id = partner_link_id diff --git a/rare/components/tabs/settings/legendary.py b/rare/components/tabs/settings/legendary.py index ec132120..5559b3df 100644 --- a/rare/components/tabs/settings/legendary.py +++ b/rare/components/tabs/settings/legendary.py @@ -1,7 +1,7 @@ -import platform +import platform as pf import re from logging import getLogger -from typing import Tuple +from typing import Tuple, List from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSettings from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox @@ -19,14 +19,21 @@ class RefreshGameMetaWorker(Worker): class Signals(QObject): finished = pyqtSignal() - def __init__(self): + def __init__(self, platforms: List[str], include_unreal: bool): super(RefreshGameMetaWorker, self).__init__() self.signals = RefreshGameMetaWorker.Signals() - self.setAutoDelete(True) self.core = LegendaryCoreSingleton() + if platforms: + self.platforms = platforms + else: + self.platforms = ["Windows"] + self.skip_ue = not include_unreal def run_real(self) -> None: - self.core.get_game_and_dlc_list(True, force_refresh=True) + for platform in self.platforms: + self.core.get_game_and_dlc_list( + True, platform=platform, force_refresh=True, skip_ue=self.skip_ue + ) self.signals.finished.emit() @@ -34,7 +41,7 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): def __init__(self, parent=None): super(LegendarySettings, self).__init__(parent=parent) self.setupUi(self) - self.settings = QSettings() + self.settings = QSettings(self) self.core = LegendaryCoreSingleton() @@ -82,20 +89,36 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): ) self.locale_layout.addWidget(self.locale_edit) - self.win32_cb.setChecked(self.settings.value("win32_meta", False, bool)) - self.win32_cb.stateChanged.connect(lambda: self.settings.setValue("win32_meta", self.win32_cb.isChecked())) + self.fetch_win32_check.setChecked(self.settings.value("win32_meta", False, bool)) + self.fetch_win32_check.stateChanged.connect( + lambda: self.settings.setValue("win32_meta", self.fetch_win32_check.isChecked()) + ) - self.mac_cb.setChecked(self.settings.value("mac_meta", platform.system() == "Darwin", bool)) - self.mac_cb.stateChanged.connect(lambda: self.settings.setValue("mac_meta", self.mac_cb.isChecked())) + self.fetch_macos_check.setChecked(self.settings.value("macos_meta", pf.system() == "Darwin", bool)) + self.fetch_macos_check.stateChanged.connect( + lambda: self.settings.setValue("macos_meta", self.fetch_macos_check.isChecked()) + ) + self.fetch_macos_check.setDisabled(pf.system() == "Darwin") - self.refresh_game_meta_btn.clicked.connect(self.refresh_game_meta) + self.fetch_unreal_check.setChecked(self.settings.value("unreal_meta", False, bool)) + self.fetch_unreal_check.stateChanged.connect( + lambda: self.settings.setValue("unreal_meta", self.fetch_unreal_check.isChecked()) + ) - def refresh_game_meta(self): - self.refresh_game_meta_btn.setDisabled(True) - self.refresh_game_meta_btn.setText(self.tr("Loading")) - worker = RefreshGameMetaWorker() - worker.signals.finished.connect(lambda: self.refresh_game_meta_btn.setDisabled(False)) - worker.signals.finished.connect(lambda: self.refresh_game_meta_btn.setText(self.tr("Refresh game meta"))) + self.refresh_metadata_button.clicked.connect(self.refresh_metadata) + # FIXME: Disable the button for now because it interferes with RareCore + self.refresh_metadata_button.setEnabled(False) + self.refresh_metadata_button.setVisible(False) + + def refresh_metadata(self): + self.refresh_metadata_button.setDisabled(True) + platforms = [] + if self.fetch_win32_check.isChecked(): + platforms.append("Win32") + if self.fetch_macos_check.isChecked(): + platforms.append("Mac") + worker = RefreshGameMetaWorker(platforms, self.fetch_unreal_check.isChecked()) + worker.signals.finished.connect(lambda: self.refresh_metadata_button.setDisabled(False)) QThreadPool.globalInstance().start(worker) @staticmethod diff --git a/rare/lgndr/core.py b/rare/lgndr/core.py index 478d3128..ba6eaeb0 100644 --- a/rare/lgndr/core.py +++ b/rare/lgndr/core.py @@ -3,6 +3,7 @@ import json import logging import os from multiprocessing import Queue +from sys import platform as sys_platform from uuid import uuid4 # On Windows the monkeypatching of `run_real` below doesn't work like on Linux @@ -17,8 +18,8 @@ from legendary.models.game import Game, InstalledGame from legendary.models.manifest import ManifestMeta from rare.lgndr.downloader.mp.manager import DLManager -from rare.lgndr.lfs.lgndry import LGDLFS from rare.lgndr.glue.exception import LgndrException, LgndrLogHandler +from rare.lgndr.lfs.lgndry import LGDLFS legendary.core.DLManager = DLManager legendary.core.LGDLFS = LGDLFS @@ -50,6 +51,11 @@ class LegendaryCore(LegendaryCoreReal): return ret return unlock + @property + def default_platform(self) -> str: + os_default = "Mac" if sys_platform == "darwin" else "Windows" + return self.lgd.config.get("Legendary", "default_platform", fallback=os_default) + # skip_sync defaults to false but since Rare is persistent, skip by default # def get_installed_game(self, app_name, skip_sync=True) -> InstalledGame: # return super(LegendaryCore, self).get_installed_game(app_name, skip_sync) diff --git a/rare/models/game.py b/rare/models/game.py index 3d54eeef..0bca4d91 100644 --- a/rare/models/game.py +++ b/rare/models/game.py @@ -166,7 +166,8 @@ class RareGame(RareGameSlim): def update_game(self): self.game = self.core.get_game( - self.app_name, update_meta=False, platform=self.igame.platform if self.igame else "Windows" + self.app_name, update_meta=False, + platform=self.igame.platform if self.igame else self.core.default_platform ) def update_igame(self): @@ -228,7 +229,7 @@ class RareGame(RareGameSlim): if self.igame is not None: return self.game.app_version(self.igame.platform) else: - return self.game.app_version() + return self.game.app_version(self.core.default_platform) @property def has_update(self) -> bool: diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py index abc68247..101ace50 100644 --- a/rare/shared/rare_core.py +++ b/rare/shared/rare_core.py @@ -1,5 +1,6 @@ import configparser import os +import platform import time from argparse import Namespace from itertools import chain @@ -25,6 +26,7 @@ from .workers import ( ) from .workers.uninstall import uninstall_game from .workers.worker import QueueWorkerInfo, QueueWorkerState +from rare.utils import config_helper logger = getLogger("RareCore") @@ -54,9 +56,10 @@ class RareCore(QObject): self.args(args) self.signals(init=True) self.core(init=True) + config_helper.init_config_handler(self.__core) self.image_manager(init=True) - self.settings = QSettings() + self.settings = QSettings(self) self.queue_workers: List[QueueWorker] = [] self.queue_threadpool = QThreadPool() @@ -140,6 +143,9 @@ class RareCore(QObject): for section in ["Legendary", "default", "default.env"]: if section not in self.__core.lgd.config.sections(): self.__core.lgd.config.add_section(section) + # Set some platform defaults + self.__core.lgd.config.set("Legendary", "default_platform", self.__core.default_platform) + self.__core.lgd.config.set("Legendary", "install_platform_fallback", False) # workaround if egl sync enabled, but no programdata_path # programdata_path might be unset if logging in through the browser if self.__core.egl_sync_enabled: @@ -357,7 +363,7 @@ class RareCore(QObject): yield game.game @property - def dlcs(self) -> Dict[str, Game]: + def dlcs(self) -> Dict[str, set[RareGame]]: """! RareGames that ARE DLCs themselves """ diff --git a/rare/shared/workers/fetch.py b/rare/shared/workers/fetch.py index 701e1890..3df8189a 100644 --- a/rare/shared/workers/fetch.py +++ b/rare/shared/workers/fetch.py @@ -1,9 +1,10 @@ +import platform import time from argparse import Namespace from enum import IntEnum from logging import getLogger -from PyQt5.QtCore import QObject, pyqtSignal +from PyQt5.QtCore import QObject, pyqtSignal, QSettings from requests.exceptions import ConnectionError, HTTPError from rare.lgndr.core import LegendaryCore @@ -27,19 +28,54 @@ class FetchWorker(Worker): self.signals = FetchWorker.Signals() self.core = core self.args = args + self.settings = QSettings() def run_real(self): # Fetch regular EGL games with assets - self.signals.progress.emit(0, self.signals.tr("Updating game metadata")) start_time = time.time() + + want_unreal = self.settings.value("unreal_meta", False, bool) or self.args.debug + want_win32 = self.settings.value("win32_meta", False, bool) + want_macos = self.settings.value("macos_meta", False, bool) + need_macos = platform.system() == "Darwin" + need_windows = not any([want_win32, want_macos, need_macos, self.args.debug]) + + if want_win32 or self.args.debug: + logger.info( + "Requesting Win32 metadata due to %s, %s Unreal engine", + "settings" if want_win32 else "debug", + "with" if want_unreal else "without" + ) + self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows")) + self.core.get_game_and_dlc_list( + update_assets=not self.args.offline, platform="Win32", skip_ue=not want_unreal + ) + + if need_macos or want_macos or self.args.debug: + logger.info( + "Requesting MacOS metadata due to %s, %s Unreal engine", + platform if need_macos else "settings" if want_macos else "debug", + "with" if want_unreal else "without" + ) + self.signals.progress.emit(15, self.signals.tr("Updating game metadata for MacOS")) + self.core.get_game_and_dlc_list( + update_assets=not self.args.offline, platform="Mac", skip_ue=not want_unreal + ) + + if need_windows: + self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows")) + logger.info( + "Requesting Windows metadata, %s Unreal engine", + "with" if want_unreal else "without" + ) games, dlc_dict = self.core.get_game_and_dlc_list( - update_assets=not self.args.offline, platform="Windows", skip_ue=False + update_assets=need_windows, platform="Windows", skip_ue=not want_unreal ) logger.debug(f"Games {len(games)}, games with DLCs {len(dlc_dict)}") logger.debug(f"Request games: {time.time() - start_time} seconds") # Fetch non-asset games - self.signals.progress.emit(10, self.signals.tr("Updating non-asset metadata")) + self.signals.progress.emit(30, self.signals.tr("Updating non-asset game metadata")) start_time = time.time() try: na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False) diff --git a/rare/ui/components/tabs/settings/legendary.py b/rare/ui/components/tabs/settings/legendary.py index 634f5efa..f2e71e87 100644 --- a/rare/ui/components/tabs/settings/legendary.py +++ b/rare/ui/components/tabs/settings/legendary.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.ui' # -# Created by: PyQt5 UI code generator 5.15.7 +# Created by: PyQt5 UI code generator 5.15.10 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. @@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_LegendarySettings(object): def setupUi(self, LegendarySettings): LegendarySettings.setObjectName("LegendarySettings") - LegendarySettings.resize(595, 334) + LegendarySettings.resize(681, 456) LegendarySettings.setWindowTitle("LegendarySettings") self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings) self.legendary_layout.setObjectName("legendary_layout") @@ -125,21 +125,30 @@ class Ui_LegendarySettings(object): self.clean_button = QtWidgets.QPushButton(self.cleanup_group) self.clean_button.setObjectName("clean_button") self.cleanup_layout.addWidget(self.clean_button) - self.right_layout.addWidget(self.cleanup_group, 0, QtCore.Qt.AlignTop) - self.meta_group = QtWidgets.QGroupBox(LegendarySettings) - self.meta_group.setObjectName("meta_group") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.meta_group) + self.right_layout.addWidget(self.cleanup_group) + self.metadata_group = QtWidgets.QGroupBox(LegendarySettings) + self.metadata_group.setObjectName("metadata_group") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.metadata_group) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.win32_cb = QtWidgets.QCheckBox(self.meta_group) - self.win32_cb.setObjectName("win32_cb") - self.verticalLayout_2.addWidget(self.win32_cb) - self.mac_cb = QtWidgets.QCheckBox(self.meta_group) - self.mac_cb.setObjectName("mac_cb") - self.verticalLayout_2.addWidget(self.mac_cb) - self.refresh_game_meta_btn = QtWidgets.QPushButton(self.meta_group) - self.refresh_game_meta_btn.setObjectName("refresh_game_meta_btn") - self.verticalLayout_2.addWidget(self.refresh_game_meta_btn) - self.right_layout.addWidget(self.meta_group) + self.fetch_win32_check = QtWidgets.QCheckBox(self.metadata_group) + self.fetch_win32_check.setObjectName("fetch_win32_check") + self.verticalLayout_2.addWidget(self.fetch_win32_check) + self.fetch_macos_check = QtWidgets.QCheckBox(self.metadata_group) + self.fetch_macos_check.setObjectName("fetch_macos_check") + self.verticalLayout_2.addWidget(self.fetch_macos_check) + self.fetch_unreal_check = QtWidgets.QCheckBox(self.metadata_group) + self.fetch_unreal_check.setObjectName("fetch_unreal_check") + self.verticalLayout_2.addWidget(self.fetch_unreal_check) + self.metadata_info = QtWidgets.QLabel(self.metadata_group) + font = QtGui.QFont() + font.setItalic(True) + self.metadata_info.setFont(font) + self.metadata_info.setObjectName("metadata_info") + self.verticalLayout_2.addWidget(self.metadata_info) + self.refresh_metadata_button = QtWidgets.QPushButton(self.metadata_group) + self.refresh_metadata_button.setObjectName("refresh_metadata_button") + self.verticalLayout_2.addWidget(self.refresh_metadata_button) + self.right_layout.addWidget(self.metadata_group) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.right_layout.addItem(spacerItem1) self.legendary_layout.addLayout(self.right_layout) @@ -162,10 +171,12 @@ class Ui_LegendarySettings(object): self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup")) self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests")) self.clean_button.setText(_translate("LegendarySettings", "Remove everything")) - self.meta_group.setTitle(_translate("LegendarySettings", "Game metadata")) - self.win32_cb.setText(_translate("LegendarySettings", "Load 32bit data")) - self.mac_cb.setText(_translate("LegendarySettings", "Load MacOS data")) - self.refresh_game_meta_btn.setText(_translate("LegendarySettings", "Refresh game meta")) + self.metadata_group.setTitle(_translate("LegendarySettings", "Platforms")) + self.fetch_win32_check.setText(_translate("LegendarySettings", "Include Win32 games")) + self.fetch_macos_check.setText(_translate("LegendarySettings", "Include MacOS games")) + self.fetch_unreal_check.setText(_translate("LegendarySettings", "Include Unreal engine")) + self.metadata_info.setText(_translate("LegendarySettings", "Restart Rare to apply")) + self.refresh_metadata_button.setText(_translate("LegendarySettings", "Refresh metadata")) if __name__ == "__main__": diff --git a/rare/ui/components/tabs/settings/legendary.ui b/rare/ui/components/tabs/settings/legendary.ui index a69ef823..b87929da 100644 --- a/rare/ui/components/tabs/settings/legendary.ui +++ b/rare/ui/components/tabs/settings/legendary.ui @@ -6,8 +6,8 @@ 0 0 - 595 - 334 + 681 + 456 @@ -200,7 +200,7 @@ - + Cleanup @@ -227,29 +227,48 @@ - + - Game metadata + Platforms - + - Load 32bit data + Include Win32 games - + - Load MacOS data + Include MacOS games - + - Refresh game meta + Include Unreal engine + + + + + + + + true + + + + Restart Rare to apply + + + + + + + Refresh metadata