diff --git a/Rare/Components/Launch/LaunchDialog.py b/Rare/Components/Launch/LaunchDialog.py index f50e70fb..502db0d4 100644 --- a/Rare/Components/Launch/LaunchDialog.py +++ b/Rare/Components/Launch/LaunchDialog.py @@ -20,7 +20,7 @@ class LaunchThread(QThread): def run(self): self.action.emit("Login") - self.action.emit("Downloading Images") + self.action.emit(self.tr("Downloading Images")) download_images(self.download_progess, self.core) self.action.emit("finish") diff --git a/Rare/Components/Tabs/Downloads/DownloadTab.py b/Rare/Components/Tabs/Downloads/DownloadTab.py index 944732e7..bad38222 100644 --- a/Rare/Components/Tabs/Downloads/DownloadTab.py +++ b/Rare/Components/Tabs/Downloads/DownloadTab.py @@ -158,9 +158,6 @@ class DownloadTab(QWidget): self.layout.addLayout(self.mini_layout) - self.installing_game_widget = QLabel(self.tr("No active Download")) - self.layout.addWidget(self.installing_game_widget) - self.update_title = QLabel(f"

{self.tr('Updates')}

") self.update_title.setStyleSheet(""" QLabel{ diff --git a/Rare/Components/Tabs/Games/GameList.py b/Rare/Components/Tabs/Games/GameList.py index f25b356b..695f50cf 100644 --- a/Rare/Components/Tabs/Games/GameList.py +++ b/Rare/Components/Tabs/Games/GameList.py @@ -5,10 +5,10 @@ from PyQt5.QtCore import Qt, pyqtSignal, QSettings from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import * -from Rare.Components.Tabs.Games.GameWidgets.UninstalledListWidget import ListWidgetUninstalled -from Rare.Components.Tabs.Games.GameWidgets.UninstalledIconWidget import IconWidgetUninstalled from Rare.Components.Tabs.Games.GameWidgets.InstalledIconWidget import GameWidgetInstalled from Rare.Components.Tabs.Games.GameWidgets.InstalledListWidget import InstalledListWidget +from Rare.Components.Tabs.Games.GameWidgets.UninstalledIconWidget import IconWidgetUninstalled +from Rare.Components.Tabs.Games.GameWidgets.UninstalledListWidget import ListWidgetUninstalled from Rare.utils.Models import InstallOptions from Rare.utils.QtExtensions import FlowLayout from Rare.utils.utils import download_image @@ -42,8 +42,16 @@ class GameList(QStackedWidget): self.list_scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) + self.info_text = self.tr("Installed Games: {} Available Games: {}").format( + len(self.core.get_installed_list()), + len(self.core.get_game_list(update_assets=True))) + + self.icon_parent_layout = QVBoxLayout() + self.icon_parent_layout.addWidget(QLabel(self.info_text)) + self.icon_layout = FlowLayout() self.list_layout = QVBoxLayout() + self.list_layout.addWidget(QLabel(self.info_text)) IMAGE_DIR = self.settings.value("img_dir", os.path.expanduser("~/.cache/rare"), str) self.updates = [] @@ -117,8 +125,10 @@ class GameList(QStackedWidget): self.widgets[game.app_name] = (icon_widget, list_widget) + self.icon_parent_layout.addLayout(self.icon_layout) + self.icon_parent_layout.addStretch(1) self.list_layout.addStretch(1) - self.icon_widget.setLayout(self.icon_layout) + self.icon_widget.setLayout(self.icon_parent_layout) self.list_widget.setLayout(self.list_layout) self.icon_scrollarea.setWidget(self.icon_widget) diff --git a/Rare/Components/Tabs/Games/ImportWidget.py b/Rare/Components/Tabs/Games/ImportWidget.py index 90021591..1a5bd4b6 100644 --- a/Rare/Components/Tabs/Games/ImportWidget.py +++ b/Rare/Components/Tabs/Games/ImportWidget.py @@ -4,11 +4,12 @@ import string from logging import getLogger from PyQt5.QtCore import pyqtSignal -from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QPushButton, QVBoxLayout, QFileDialog, QMessageBox +from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QPushButton, QVBoxLayout, QFileDialog, QMessageBox, QLineEdit from qtawesome import icon from Rare.utils import LegendaryApi from Rare.utils.QtExtensions import PathEdit +from custom_legendary.core import LegendaryCore logger = getLogger("Import") @@ -16,9 +17,11 @@ logger = getLogger("Import") class ImportWidget(QWidget): update_list = pyqtSignal() - def __init__(self, core): + def __init__(self, core: LegendaryCore): super(ImportWidget, self).__init__() self.core = core + self.game_list = [i.app_name for i in self.core.get_game_list()] + self.main_layout = QHBoxLayout() self.back_button = QPushButton(icon("mdi.keyboard-backspace", color="white"), self.tr("Back")) self.right_layout = QVBoxLayout() @@ -31,15 +34,31 @@ class ImportWidget(QWidget): self.title = QLabel("

Import Game{self.tr('Import existing game')}

") + self.import_one_game = QLabel(f"

{self.tr('Import existing game from Epic Games Launcher')}

") self.layout.addWidget(self.import_one_game) self.import_game_info = QLabel(self.tr("Select path to game")) self.layout.addWidget(self.import_game_info) + self.override_app_name_label = QLabel(self.tr("Override app name (Only if imported game from legendary or the app could not find the app name)")) + self.app_name_input = QLineEdit() + self.app_name_input.setFixedHeight(32) + minilayout = QHBoxLayout() + minilayout.addStretch(1) + self.indicator_label = QLabel("") + minilayout.addWidget(self.indicator_label) + self.app_name_input.setLayout(minilayout) + self.app_name_input.textChanged.connect(self.app_name_changed) + self.path_edit = PathEdit(os.path.expanduser("~"), QFileDialog.DirectoryOnly) + self.path_edit.text_edit.textChanged.connect(self.path_changed) self.layout.addWidget(self.path_edit) + self.layout.addWidget(self.override_app_name_label) + self.layout.addWidget(self.app_name_input) + + self.info_label = QLabel("") + self.layout.addWidget(self.info_label) self.import_button = QPushButton(self.tr("Import Game")) self.layout.addWidget(self.import_button) self.import_button.clicked.connect(self.import_game) @@ -57,24 +76,48 @@ class ImportWidget(QWidget): # self.main_layout.addStretch(1) self.setLayout(self.main_layout) - def import_game(self, path=None): - if not path: - path = self.path_edit.text() - if not path.endswith("/"): - path = path + "/" + def app_name_changed(self, text): + if text in self.game_list: + self.indicator_label.setPixmap(icon("ei.ok-sign", color="green").pixmap(16,16)) + else: + self.indicator_label.setPixmap(icon("ei.remove-sign", color="red").pixmap(16,16)) + def path_changed(self, path): + if os.path.exists(path): + if os.path.exists(os.path.join(path, ".egstore")): + self.app_name_input.setText(self.find_app_name(path)) + + def find_app_name(self, path): + if not os.path.exists(os.path.join(path, ".egstore")): + return None for i in os.listdir(os.path.join(path, ".egstore")): if i.endswith(".mancpn"): - file = path + ".egstore/" + i + file = os.path.join(path, ".egstore", i) break else: logger.warning("File was not found") - return - app_name = json.load(open(file, "r"))["AppName"] + return None + return json.load(open(file, "r"))["AppName"] + + def import_game(self, path=None): + app_name = self.app_name_input.text() + if not path: + path = self.path_edit.text() + if not app_name: + if a_n := self.find_app_name(path): + app_name = a_n + else: + self.info_label.setText(self.tr("Could not find app name")) + return + if LegendaryApi.import_game(self.core, app_name=app_name, path=path): + self.info_label.setText(self.tr("Successfully imported {}. Reload library").format(self.core.get_installed_game(app_name).title)) + self.app_name_input.setText("") + self.update_list.emit() else: logger.warning("Failed to import" + app_name) + self.info_label.setText(self.tr("Failed to import {}").format(app_name)) return def auto_import_games(self, game_path): @@ -85,17 +128,17 @@ class ImportWidget(QWidget): logger.info(f"No Games found in {game_path}") return 0 for path in os.listdir(game_path): - json_path = game_path + path + "/.egstore" - print(json_path) + json_path = game_path + path if not os.path.isdir(json_path): logger.info(f"Game at {game_path + path} doesn't exist") continue + app_name = self.find_app_name(json_path) + if not app_name: + logger.warning("Could not find app name") + continue - for file in os.listdir(json_path): - if file.endswith(".mancpn"): - app_name = json.load(open(os.path.join(json_path, file)))["AppName"] - if LegendaryApi.import_game(self.core, app_name, game_path + path): - imported += 1 + if LegendaryApi.import_game(self.core, app_name, game_path + path): + imported += 1 return imported def import_games_prepare(self): @@ -109,12 +152,11 @@ class ImportWidget(QWidget): imported += self.auto_import_games(path) else: - possible_wineprefixes = [os.path.expanduser("~/.wine/"), os.path.expanduser("~/Games/epic-games-store/")] + possible_wineprefixes = [os.path.expanduser("~/.wine"), os.path.expanduser("~/Games/epic-games-store")] for wine_prefix in possible_wineprefixes: - imported += self.auto_import_games(f"{wine_prefix}drive_c/Program Files/Epic Games/") + imported += self.auto_import_games(os.path.join(wine_prefix, "drive_c/Program Files/Epic Games/")) if imported > 0: - QMessageBox.information(self, "Imported Games", self.tr("Successfully imported {} Games").format(imported)) + QMessageBox.information(self, "Imported Games", self.tr("Successfully imported {} Games. Reloading Library").format(imported)) self.update_list.emit() - logger.info("Restarting app to import games") else: QMessageBox.information(self, "Imported Games", "No Games were found") diff --git a/Rare/Components/Tabs/Settings/Legendary.py b/Rare/Components/Tabs/Settings/Legendary.py index 82d5880e..fcc2c428 100644 --- a/Rare/Components/Tabs/Settings/Legendary.py +++ b/Rare/Components/Tabs/Settings/Legendary.py @@ -1,7 +1,7 @@ from logging import getLogger from PyQt5.QtGui import QIntValidator -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QFileDialog, QPushButton, QLineEdit +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QFileDialog, QPushButton, QLineEdit, QGroupBox, QMessageBox from Rare.Components.Tabs.Settings.SettingsWidget import SettingsWidget from Rare.utils.QtExtensions import PathEdit @@ -37,6 +37,21 @@ class LegendarySettings(QWidget): self.max_worker_select) self.layout.addWidget(self.max_worker_widget) + #cleanup + self.clean_layout = QVBoxLayout() + self.cleanup_widget = QGroupBox() + self.cleanup_widget.setTitle(self.tr("Cleanup")) + self.clean_button = QPushButton(self.tr("Remove everything")) + self.clean_button.clicked.connect(lambda: self.cleanup(False)) + self.clean_layout.addWidget(self.clean_button) + + self.clean_button_without_manifests = QPushButton(self.tr("Clean, but keep manifests")) + self.clean_button_without_manifests.clicked.connect(lambda: self.cleanup(True)) + self.clean_layout.addWidget(self.clean_button_without_manifests) + + self.cleanup_widget.setLayout(self.clean_layout) + self.layout.addWidget(self.cleanup_widget) + self.layout.addStretch(1) self.setLayout(self.layout) @@ -59,3 +74,25 @@ class LegendarySettings(QWidget): self.core.lgd.config["Legendary"].pop("max_workers") logger.info("Updating config for max_workers") self.core.lgd.save_config() + + def cleanup(self, keep_manifests): + before = self.core.lgd.get_dir_size() + logger.debug('Removing app metadata...') + app_names = set(g.app_name for g in self.core.get_assets(update_assets=False)) + self.core.lgd.clean_metadata(app_names) + + if not keep_manifests: + logger.debug('Removing manifests...') + installed = [(ig.app_name, ig.version) for ig in self.core.get_installed_list()] + installed.extend((ig.app_name, ig.version) for ig in self.core.get_installed_dlc_list()) + self.core.lgd.clean_manifests(installed) + + logger.debug('Removing tmp data') + self.core.lgd.clean_tmp_data() + + after = self.core.lgd.get_dir_size() + logger.info(f'Cleanup complete! Removed {(before - after) / 1024 / 1024:.02f} MiB.') + if cleaned := (before-after) != 0: + QMessageBox.information(self, "Cleanup", self.tr("Cleanup complete! Successfully removed {} MB").format(round(cleaned / 1024 / 1024, 3))) + else: + QMessageBox.information(self, "Cleanup", "Nothing to clean") diff --git a/Rare/languages/de.qm b/Rare/languages/de.qm index edb5d143..c3cc547d 100644 Binary files a/Rare/languages/de.qm and b/Rare/languages/de.qm differ diff --git a/Rare/languages/de.ts b/Rare/languages/de.ts index 386b5986..04d4deed 100644 --- a/Rare/languages/de.ts +++ b/Rare/languages/de.ts @@ -16,7 +16,20 @@ This is a beta version, so you can get bugs. If you get a bug, please report it by creating a Issue on <a href='https://github.com/Dummerle/Rare/issues'>Github</a>. You can also contact me on Discord (Dummerle#7419). If you have a feature request, please contact me - Dies ist eine beta version, also können Bugs entstehen. Wenn du einen Bug bemerkst, kontaktiere mich, indem du einen Issue auf <a href='https://github.com/Dummerle/Rare/issues'>Github</a> erstellst oder mir auf Discord eine Nachricht schickst. Ebenso bei einem Wunsch für Features + Dies ist eine beta version, also können Bugs entstehen. Wenn du einen Bug bemerkst, kontaktiere mich, indem du einen Issue auf <a href='https://github.com/Dummerle/Rare/issues'>Github</a> erstellst oder mir auf Discord eine Nachricht schickst. Ebenso bei einem Wunsch für Features + + + + This is a beta version, so you can get bugs. If you get a bug, please report it by creating a Issue on <a href='https://github.com/Dummerle/Rare/issues'>Github</a>. You can also contact me on Discord (Dummerle#7419). Or you can join the <a href='https://discord.gg/YvmABK9YSk'>Discord server</a> + Dies ist eine Betaversion, also können Bugs und andere Unschönheiten auftreten. Falls ein Bug auftritt, bitte auf <a href='https://github.com/Dummerle/Rare/issues'>Github</a> melden, indem du einen Issue erstellst oder auf Discord. (Dummerle#7419). Ein Rare <a href='https://discord.gg/YvmABK9YSk'>Discord server</a> existiert ebenfalls + + + + BaseInstalledWidget + + + Do you want to launch {} + Möchtest du {} starten @@ -45,7 +58,7 @@ DownloadTab - + No active Download Kein aktiver Download @@ -55,56 +68,94 @@ Download anhalten - + No updates available Keine Updates verfügbar - + Error preparing download Fehler beim Vorbereiten des Downloads - + Download size is 0. Game already exists Die Größe des Downloads ist 0. Spiel existiert bereits - + Installation finished Installation abgeschlossen - + Installing Game: No active download Installierendes Spiel: Kein aktiver Download - + Download speed Geschwindigkeit - + Cache used Benutzter Cache - + Downloaded Runtergeladen - + Time left: Zeit übrig: - + Finished Download of game {} Downlaod von {} abgeschlossen + + DxvkWidget + + + GPU usage + GPU nutzung + + + + Used Memory + Benutzter Speicher + + + + Device info + Geräteinfo + + + + DXVK version + DXVK Version + + + + D3D Level of application + D3D Level des Spiels + + + + Frame time graph + Graph über die Frametime + + + + dxvk settings + DXVK Einstellungen + + GameActions @@ -174,15 +225,20 @@ GameList - + Launch Starten - + Game running Spiel läuft + + + Installed Games: {} Available Games: {} + Installierte Spiele: {} Verfügbare Spiele: {} + GameListHeadBar @@ -215,7 +271,7 @@ Überprüfung nach Updates beim Start überspringen - + Save Speichern @@ -230,17 +286,17 @@ Proton Version - + Proton prefix Protonprefix - + No permission to create folder Keine Berechtigung den Ordner zu erstellen - + Please select path for proton prefix Bitte wähle den Pfad zum Protonprefix @@ -304,29 +360,54 @@ Keine valide Session gefunden - + Back Zurück - + Select path to game Wähle den Pfad zum Spiel - + Import Game Spiel importieren - + Import all games from Epic Games Launcher Alle Spiele aus dem Epic Games Launcher importieren Successfully imported {} Games - {} Spiele erfolgreich importiert + {} Spiele erfolgreich importiert + + + + Override app name (Only if imported game from legendary or the app could not find the app name) + App Name überschreiben (Nur falls das Spiel von Legendary importiert wird oder der App Name nicht gefunden wird + + + + Could not find app name + Konnte den Appnamen nicht finden + + + + Successfully imported {}. Reload library + Erfolgreich {} importiert. Spiele neu laden + + + + Failed to import {} + {} Konnte nicht importiert werden + + + + Successfully imported {} Games. Reloading Library + Erfolgreich {} Spiele importiert. Spiele neu laden @@ -411,6 +492,14 @@ Installationsgröße: {} GB Starten... + + LaunchThread + + + Downloading Images + Bilder runterladen + + LegendarySettings @@ -428,19 +517,44 @@ Installationsgröße: {} GB Max workers for Download (Less: slower download)(0: Default) Maximale Anzahl Downloadprozesse (Weniger: langsamer)(Standard: 0) + + + Cleanup + Aufräumen + + + + Remove everything + Alles aufräumen + + + + Clean, but keep manifests + Aufräumen, aber Manifests behalten + + + + Cleanup complete! Successfully removed {} MB + Fertig! Es wurden {} MB entfernt + LinuxSettings - + Default Wine Prefix Standard Wineprefix - + Default Wine executable Standard Wine + + + Linux settings + Linux Einstellungen + ListWidgetUninstalled @@ -535,10 +649,15 @@ Installationsgröße: {} GB Sprache - + Restart Application to activate changes Starte die App neu um die Änderungen zu aktivieren + + + Confirm launch of game + Start des Spiels bestätigen + SyncSaves @@ -682,7 +801,7 @@ Installationsgröße: {} GB UpdateWidget - + Update Game Spiel updaten