commit
85b9fac065
|
@ -2,8 +2,6 @@
|
|||
|
||||
## What you can do
|
||||
|
||||
To Contribute first fork the repository
|
||||
|
||||
### Add translations
|
||||
|
||||
1. Execute ```pylupdate5 $(find -name "*.py") -ts Rare/languages/{your lang (two letters)}.ts``` in project directrory
|
||||
|
@ -21,4 +19,7 @@ exmples:
|
|||
Select one Card of the project and implement it or make other changes
|
||||
|
||||
|
||||
If you made your changes, create a pull request
|
||||
##Git crash-course
|
||||
To contribute fork the repository and clone **your** repo. Then make your changes, add it to git with `git add .` and upload it to Github with `git commit -m "message"` and `git push` or with your IDE.
|
||||
|
||||
If you uploaded your changes, create a pull request
|
||||
|
|
|
@ -69,6 +69,8 @@ There are more options to contribute.
|
|||
- If you are a designer, you can add Stylesheets or create a logo or a banner
|
||||
- You can translate the application
|
||||
|
||||
**Note:** Pull Requests please to "dev" branch
|
||||
|
||||
More Information is in CONTRIBUTING.md
|
||||
|
||||
## Images
|
||||
|
|
|
@ -88,12 +88,15 @@ class ImportWidget(QWidget):
|
|||
if os.name != "nt":
|
||||
self.core.egl.appdata_path = os.path.join(self.data_path,
|
||||
f"drive_c/users/{getuser()}/Local Settings/Application Data/EpicGamesLauncher/Saved/Config/Windows")
|
||||
try:
|
||||
if self.core.auth_import():
|
||||
logger.info(f"Logged in as {self.core.lgd.userdata['displayName']}")
|
||||
self.success.emit()
|
||||
else:
|
||||
logger.warning("Failed to import existing session")
|
||||
except Exception as e:
|
||||
logger.warning(e)
|
||||
|
||||
if self.core.auth_import():
|
||||
logger.info(f"Logged in as {self.core.lgd.userdata['displayName']}")
|
||||
self.success.emit()
|
||||
else:
|
||||
print("Lol")
|
||||
logger.warning("Error: No valid session found")
|
||||
self.login_text.setText(self.tr("Error: No valid session found"))
|
||||
self.import_button.setText(self.tr("Import"))
|
||||
|
|
44
Rare/Components/Dialogs/UninstallDialog.py
Normal file
44
Rare/Components/Dialogs/UninstallDialog.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
from PyQt5.QtWidgets import QDialog, QLabel, QVBoxLayout, QCheckBox, QFormLayout, QHBoxLayout, QPushButton
|
||||
from qtawesome import icon
|
||||
|
||||
from custom_legendary.models.game import Game
|
||||
|
||||
|
||||
class UninstallDialog(QDialog):
|
||||
def __init__(self, game: Game):
|
||||
super(UninstallDialog, self).__init__()
|
||||
self.setWindowTitle("Uninstall Game")
|
||||
self.info = 0
|
||||
self.layout = QVBoxLayout()
|
||||
self.info_text = QLabel(self.tr("Do you really want to uninstall {}").format(game.app_title))
|
||||
self.layout.addWidget(self.info_text)
|
||||
self.keep_files = QCheckBox(self.tr("Keep Files"))
|
||||
self.form = QFormLayout()
|
||||
self.form.setContentsMargins(0, 10, 0, 10)
|
||||
self.form.addRow(QLabel(self.tr("Do you want to keep files?")), self.keep_files)
|
||||
self.layout.addLayout(self.form)
|
||||
|
||||
self.button_layout = QHBoxLayout()
|
||||
self.ok_button = QPushButton(icon("ei.remove-circle", color="red"), self.tr("Uninstall"))
|
||||
self.ok_button.clicked.connect(self.ok)
|
||||
|
||||
self.cancel_button = QPushButton(self.tr("Cancel"))
|
||||
self.cancel_button.clicked.connect(self.cancel)
|
||||
|
||||
self.button_layout.addStretch(1)
|
||||
self.button_layout.addWidget(self.ok_button)
|
||||
self.button_layout.addWidget(self.cancel_button)
|
||||
self.layout.addLayout(self.button_layout)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def get_information(self):
|
||||
self.exec_()
|
||||
return self.info
|
||||
|
||||
def ok(self):
|
||||
self.info = {"keep_files": self.keep_files.isChecked()}
|
||||
self.close()
|
||||
|
||||
def cancel(self):
|
||||
self.info = 0
|
||||
self.close()
|
|
@ -1,4 +1,6 @@
|
|||
from PyQt5.QtWidgets import QMainWindow
|
||||
from PyQt5.QtCore import QSettings
|
||||
from PyQt5.QtGui import QCloseEvent
|
||||
from PyQt5.QtWidgets import QMainWindow, QMessageBox
|
||||
|
||||
from Rare.Components.TabWidget import TabWidget
|
||||
|
||||
|
@ -8,5 +10,15 @@ class MainWindow(QMainWindow):
|
|||
super(MainWindow, self).__init__()
|
||||
self.setGeometry(0, 0, 1200, 800)
|
||||
self.setWindowTitle("Rare - GUI for legendary")
|
||||
self.setCentralWidget(TabWidget(core))
|
||||
self.tab_widget = TabWidget(core)
|
||||
self.setCentralWidget(self.tab_widget)
|
||||
self.show()
|
||||
|
||||
def closeEvent(self, e: QCloseEvent):
|
||||
if QSettings().value("sys_tray", True, bool):
|
||||
self.hide()
|
||||
e.ignore()
|
||||
elif self.tab_widget.downloadTab.active_game is not None and QMessageBox.question(self, "Close", self.tr("There is a download active. Do you really want to exit app?"), QMessageBox.Yes, QMessageBox.No) == QMessageBox.Yes:
|
||||
e.accept()
|
||||
else:
|
||||
e.accept()
|
||||
|
|
|
@ -3,10 +3,10 @@ from PyQt5.QtWidgets import QTabWidget, QWidget
|
|||
from qtawesome import icon
|
||||
|
||||
from Rare.Components.TabUtils import TabBar, TabButtonWidget
|
||||
from Rare.Components.Tabs.CloudSaves.CloudSaves import SyncSaves
|
||||
from Rare.Components.Tabs.CloudSaves import SyncSaves
|
||||
from Rare.Components.Tabs.Downloads.DownloadTab import DownloadTab
|
||||
from Rare.Components.Tabs.Games.GamesTab import GameTab
|
||||
from Rare.Components.Tabs.Settings.SettingsTab import SettingsTab
|
||||
from Rare.Components.Tabs.Games import GameTab
|
||||
from Rare.Components.Tabs.Settings import SettingsTab
|
||||
from Rare.utils.Models import InstallOptions
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
|
@ -23,7 +23,7 @@ class TabWidget(QTabWidget):
|
|||
self.addTab(self.game_list, self.tr("Games"))
|
||||
self.downloadTab = DownloadTab(core, updates)
|
||||
self.addTab(self.downloadTab, "Downloads" + (" (" + str(len(updates)) + ")" if len(updates) != 0 else ""))
|
||||
self.downloadTab.finished.connect(self.game_list.default_widget.game_list.update_list)
|
||||
self.downloadTab.finished.connect(self.dl_finished)
|
||||
self.game_list.default_widget.game_list.install_game.connect(lambda x: self.downloadTab.install_game(x))
|
||||
|
||||
self.game_list.game_info.info.verify_game.connect(lambda app_name: self.downloadTab.install_game(
|
||||
|
@ -31,7 +31,6 @@ class TabWidget(QTabWidget):
|
|||
|
||||
self.tabBarClicked.connect(lambda x: self.game_list.layout.setCurrentIndex(0) if x == 0 else None)
|
||||
|
||||
# Commented, because it is not finished
|
||||
self.cloud_saves = SyncSaves(core)
|
||||
self.addTab(self.cloud_saves, "Cloud Saves")
|
||||
|
||||
|
@ -43,10 +42,15 @@ class TabWidget(QTabWidget):
|
|||
self.addTab(self.account, "")
|
||||
self.setTabEnabled(disabled_tab + 1, False)
|
||||
# self.settings = SettingsTab(core)
|
||||
self.addTab(self.settings, icon("fa.gear", color='white'), None)
|
||||
|
||||
self.addTab(self.settings, icon("fa.gear", color='white'), "(!)" if self.settings.about.update_available else "")
|
||||
self.setIconSize(QSize(25, 25))
|
||||
self.tabBar().setTabButton(3, self.tabBar().RightSide, TabButtonWidget(core))
|
||||
|
||||
def dl_finished(self):
|
||||
self.game_list.default_widget.game_list.update_list()
|
||||
self.setTabText(1, "Downloads")
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self.tabBar().setMinimumWidth(self.width())
|
||||
super(TabWidget, self).resizeEvent(event)
|
||||
|
|
|
@ -12,15 +12,16 @@ class MiniWidget(QWidget):
|
|||
self.layout = QVBoxLayout()
|
||||
self.core = core
|
||||
self.layout.addWidget(QLabel("Account"))
|
||||
username = str(self.core.lgd.userdata.get("display_name"))
|
||||
username = self.core.lgd.userdata.get("display_name")
|
||||
if not username:
|
||||
self.core.login()
|
||||
username = str(self.core.lgd.userdata.get("display_name"))
|
||||
username = self.core.lgd.userdata.get("display_name")
|
||||
|
||||
self.layout.addWidget(QLabel(self.tr("Logged in as ") + username))
|
||||
self.layout.addWidget(QLabel(self.tr("Logged in as ") + str(username)))
|
||||
|
||||
self.open_browser = QPushButton(self.tr("Account settings"))
|
||||
self.open_browser.clicked.connect(self.open_account)
|
||||
self.open_browser.clicked.connect(
|
||||
lambda: webbrowser.open("https://www.epicgames.com/account/personal?productName=epicgames"))
|
||||
self.layout.addWidget(self.open_browser)
|
||||
|
||||
self.logout_button = QPushButton(self.tr("Logout"))
|
||||
|
@ -35,7 +36,5 @@ class MiniWidget(QWidget):
|
|||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.core.lgd.invalidate_userdata()
|
||||
QCoreApplication.exit()
|
||||
|
||||
def open_account(self):
|
||||
webbrowser.open("https://www.epicgames.com/account/personal?productName=epicgames")
|
||||
# restart app
|
||||
QCoreApplication.instance().exit_action(-133742) # restart exit code
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from Rare.Components.Dialogs.PathInputDialog import PathInputDialog
|
||||
from Rare.Components.Tabs.CloudSaves.SyncWidget import SyncWidget
|
||||
from Rare.utils.QtExtensions import WaitingSpinner
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import SaveGameStatus
|
||||
|
||||
logger = getLogger("Sync Saves")
|
||||
|
||||
|
||||
class LoadThread(QThread):
|
||||
signal = pyqtSignal(list)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(LoadThread, self).__init__()
|
||||
self.core = core
|
||||
|
||||
def run(self) -> None:
|
||||
saves = self.core.get_save_games()
|
||||
self.signal.emit(saves)
|
||||
|
||||
|
||||
class SyncSaves(QScrollArea):
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(SyncSaves, self).__init__()
|
||||
self.core = core
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.load_saves()
|
||||
|
||||
def load_saves(self):
|
||||
self.widget = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(WaitingSpinner())
|
||||
layout.addWidget(QLabel("<h4>Loading Cloud Saves</h4>"))
|
||||
layout.addStretch()
|
||||
self.widget.setLayout(layout)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
self.start_thread = LoadThread(self.core)
|
||||
self.start_thread.signal.connect(self.setup_ui)
|
||||
self.start_thread.start()
|
||||
self.igames = self.core.get_installed_list()
|
||||
|
||||
def setup_ui(self, saves: list):
|
||||
self.start_thread.disconnect()
|
||||
|
||||
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.title = QLabel(
|
||||
f"<h1>" + self.tr("Cloud Saves") + "</h1>\n" + self.tr("Found Saves for folowing Games"))
|
||||
|
||||
self.main_layout.addWidget(self.title)
|
||||
|
||||
saves_games = []
|
||||
for i in saves:
|
||||
if not i.app_name in saves_games and self.core.is_installed(i.app_name):
|
||||
saves_games.append(i.app_name)
|
||||
if len(saves_games) == 0:
|
||||
# QMessageBox.information(self.tr("No Games Found"), self.tr("Your games don't support cloud save"))
|
||||
self.title.setText(
|
||||
f"<h1>" + self.tr("Cloud Saves") + "</h1>\n" + self.tr("Your games does not support Cloud Saves"))
|
||||
self.setWidget(self.title)
|
||||
return
|
||||
|
||||
self.sync_all_button = QPushButton(self.tr("Sync all games"))
|
||||
self.sync_all_button.clicked.connect(self.sync_all)
|
||||
self.main_layout.addWidget(self.sync_all_button)
|
||||
|
||||
latest_save = {}
|
||||
for i in sorted(saves, key=lambda a: a.datetime):
|
||||
latest_save[i.app_name] = i
|
||||
|
||||
logger.info(f'Got {len(latest_save)} remote save game(s)')
|
||||
|
||||
self.widgets = []
|
||||
|
||||
for igame in self.igames:
|
||||
game = self.core.get_game(igame.app_name)
|
||||
if not game.supports_cloud_saves:
|
||||
continue
|
||||
if latest_save.get(igame.app_name):
|
||||
sync_widget = SyncWidget(igame, latest_save[igame.app_name], self.core)
|
||||
else:
|
||||
continue
|
||||
sync_widget.reload.connect(self.reload)
|
||||
self.main_layout.addWidget(sync_widget)
|
||||
self.widgets.append(sync_widget)
|
||||
|
||||
self.widget = QWidget()
|
||||
self.widget.setLayout(self.main_layout)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
def reload(self):
|
||||
self.setWidget(QWidget())
|
||||
self.load_saves()
|
||||
self.update()
|
||||
|
||||
def sync_all(self):
|
||||
logger.info("Sync all Games")
|
||||
for w in self.widgets:
|
||||
if not w.igame.save_path:
|
||||
save_path = self.core.get_save_path(w.igame.app_name)
|
||||
if '%' in save_path or '{' in save_path:
|
||||
self.logger.info_label("Could not find save_path")
|
||||
save_path = PathInputDialog(self.tr("Found no savepath"),
|
||||
self.tr("No save path was found. Please select path or skip"))
|
||||
if save_path == "":
|
||||
continue
|
||||
else:
|
||||
w.igame.save_path = save_path
|
||||
if w.res == SaveGameStatus.SAME_AGE:
|
||||
continue
|
||||
if w.res == SaveGameStatus.REMOTE_NEWER:
|
||||
logger.info("Download")
|
||||
w.download()
|
||||
elif w.res == SaveGameStatus.LOCAL_NEWER:
|
||||
logger.info("Upload")
|
||||
w.upload()
|
|
@ -1,8 +1,8 @@
|
|||
import os
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QHBoxLayout, QLabel
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QLabel, QGroupBox
|
||||
|
||||
from Rare.Components.Dialogs.PathInputDialog import PathInputDialog
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
@ -37,12 +37,14 @@ class _DownloadThread(QThread):
|
|||
self.core.download_saves(self.app_name, self.latest_save.manifest_name, self.save_path, clean_dir=True)
|
||||
|
||||
|
||||
class SyncWidget(QWidget):
|
||||
class SyncWidget(QGroupBox):
|
||||
reload = pyqtSignal()
|
||||
|
||||
def __init__(self, igame: InstalledGame, save, core: LegendaryCore):
|
||||
super(SyncWidget, self).__init__()
|
||||
super(SyncWidget, self).__init__(igame.title)
|
||||
self.setObjectName("group")
|
||||
self.layout = QVBoxLayout()
|
||||
self.setContentsMargins(10, 20, 10, 20)
|
||||
self.thr = None
|
||||
self.core = core
|
||||
self.save = save
|
||||
|
@ -70,7 +72,7 @@ class SyncWidget(QWidget):
|
|||
self.logger.info('No cloud or local savegame found.')
|
||||
return
|
||||
|
||||
game_title = QLabel(f"<h2>{igame.title}</h2>")
|
||||
# game_title = QLabel(f"<h2>{igame.title}</h2>")
|
||||
|
||||
if self.dt_local:
|
||||
local_save_date = QLabel(
|
||||
|
@ -124,14 +126,16 @@ class SyncWidget(QWidget):
|
|||
self.upload_button.clicked.connect(self.upload)
|
||||
self.download_button.clicked.connect(self.download)
|
||||
self.info_text = QLabel(status)
|
||||
self.layout.addWidget(game_title)
|
||||
# self.layout.addWidget(game_title)
|
||||
self.layout.addWidget(local_save_date)
|
||||
self.layout.addWidget(cloud_save_date)
|
||||
|
||||
save_path_layout = QHBoxLayout()
|
||||
self.save_path_text = QLabel(igame.save_path)
|
||||
self.save_path_text.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
self.save_path_text.setWordWrap(True)
|
||||
self.change_save_path = QPushButton(self.tr("Change path"))
|
||||
self.change_save_path.setFixedWidth(100)
|
||||
self.change_save_path.clicked.connect(self.change_path)
|
||||
save_path_layout.addWidget(self.save_path_text)
|
||||
save_path_layout.addWidget(self.change_save_path)
|
||||
|
@ -141,7 +145,7 @@ class SyncWidget(QWidget):
|
|||
button_layout.addWidget(self.upload_button)
|
||||
button_layout.addWidget(self.download_button)
|
||||
self.layout.addLayout(button_layout)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def change_path(self):
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from Rare.Components.Dialogs.PathInputDialog import PathInputDialog
|
||||
from Rare.Components.Tabs.CloudSaves.SyncWidget import SyncWidget
|
||||
from Rare.utils.QtExtensions import WaitingSpinner
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import SaveGameStatus
|
||||
|
||||
logger = getLogger("Sync Saves")
|
||||
|
||||
|
||||
class LoadThread(QThread):
|
||||
signal = pyqtSignal(list)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(LoadThread, self).__init__()
|
||||
self.core = core
|
||||
|
||||
def run(self) -> None:
|
||||
saves = self.core.get_save_games()
|
||||
self.signal.emit(saves)
|
||||
|
||||
|
||||
class SyncSaves(QScrollArea):
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(SyncSaves, self).__init__()
|
||||
self.core = core
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.load_saves()
|
||||
|
||||
def load_saves(self):
|
||||
self.widget = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(WaitingSpinner())
|
||||
layout.addWidget(QLabel("<h4>Loading Cloud Saves</h4>"))
|
||||
layout.addStretch()
|
||||
self.widget.setLayout(layout)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
self.start_thread = LoadThread(self.core)
|
||||
self.start_thread.signal.connect(self.setup_ui)
|
||||
self.start_thread.start()
|
||||
self.igames = self.core.get_installed_list()
|
||||
|
||||
def setup_ui(self, saves: list):
|
||||
self.start_thread.disconnect()
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.title = QLabel(
|
||||
f"<h1>" + self.tr("Cloud Saves") + "</h1>\n" + self.tr("Found Saves for folowing Games"))
|
||||
self.main_layout.addWidget(self.title)
|
||||
|
||||
saves_games = []
|
||||
for i in saves:
|
||||
if not i.app_name in saves_games and self.core.is_installed(i.app_name):
|
||||
saves_games.append(i.app_name)
|
||||
if len(saves_games) == 0:
|
||||
# QMessageBox.information(self.tr("No Games Found"), self.tr("Your games don't support cloud save"))
|
||||
self.title.setText(
|
||||
f"<h1>" + self.tr("Cloud Saves") + "</h1>\n" + self.tr("Your games does not support Cloud Saves"))
|
||||
self.setWidget(self.title)
|
||||
return
|
||||
|
||||
self.sync_all_button = QPushButton(self.tr("Sync all games"))
|
||||
self.sync_all_button.clicked.connect(self.sync_all)
|
||||
self.main_layout.addWidget(self.sync_all_button)
|
||||
|
||||
latest_save = {}
|
||||
for i in sorted(saves, key=lambda a: a.datetime):
|
||||
latest_save[i.app_name] = i
|
||||
|
||||
logger.info(f'Got {len(latest_save)} remote save game(s)')
|
||||
|
||||
self.widgets = []
|
||||
for igame in self.igames:
|
||||
game = self.core.get_game(igame.app_name)
|
||||
if not game.supports_cloud_saves:
|
||||
continue
|
||||
if latest_save.get(igame.app_name):
|
||||
sync_widget = SyncWidget(igame, latest_save[igame.app_name], self.core)
|
||||
else:
|
||||
continue
|
||||
sync_widget.reload.connect(self.reload)
|
||||
self.main_layout.addWidget(sync_widget)
|
||||
self.widgets.append(sync_widget)
|
||||
|
||||
self.widget = QWidget()
|
||||
self.main_layout.addStretch(1)
|
||||
self.widget.setLayout(self.main_layout)
|
||||
self.setWidgetResizable(True)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
def reload(self):
|
||||
self.setWidget(QWidget())
|
||||
self.load_saves()
|
||||
self.update()
|
||||
|
||||
def sync_all(self):
|
||||
logger.info("Sync all Games")
|
||||
for w in self.widgets:
|
||||
if not w.igame.save_path:
|
||||
save_path = self.core.get_save_path(w.igame.app_name)
|
||||
if '%' in save_path or '{' in save_path:
|
||||
self.logger.info_label("Could not find save_path")
|
||||
save_path = PathInputDialog(self.tr("Found no savepath"),
|
||||
self.tr("No save path was found. Please select path or skip"))
|
||||
if save_path == "":
|
||||
continue
|
||||
else:
|
||||
w.igame.save_path = save_path
|
||||
if w.res == SaveGameStatus.SAME_AGE:
|
||||
continue
|
||||
if w.res == SaveGameStatus.REMOTE_NEWER:
|
||||
logger.info("Download")
|
||||
w.download()
|
||||
elif w.res == SaveGameStatus.LOCAL_NEWER:
|
||||
logger.info("Upload")
|
||||
w.upload()
|
131
Rare/Components/Tabs/Downloads/DlQueueWidget.py
Normal file
131
Rare/Components/Tabs/Downloads/DlQueueWidget.py
Normal file
|
@ -0,0 +1,131 @@
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QGroupBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QWidget
|
||||
from qtawesome import icon
|
||||
|
||||
logger = getLogger("QueueWidget")
|
||||
|
||||
|
||||
class DlWidget(QWidget):
|
||||
move_up = pyqtSignal(str) # app_name
|
||||
move_down = pyqtSignal(str) # app_name
|
||||
remove = pyqtSignal(str) # app_name
|
||||
|
||||
def __init__(self, index, item):
|
||||
super(DlWidget, self).__init__()
|
||||
self.app_name = item[1].app_name
|
||||
self.layout = QHBoxLayout()
|
||||
|
||||
self.left_layout = QVBoxLayout()
|
||||
self.move_up_button = QPushButton(icon("fa.arrow-up", color="white"), "")
|
||||
if index == 0:
|
||||
self.move_up_button.setDisabled(True)
|
||||
self.move_up_button.clicked.connect(lambda: self.move_up.emit(self.app_name))
|
||||
self.move_up_button.setFixedWidth(20)
|
||||
self.left_layout.addWidget(self.move_up_button)
|
||||
|
||||
self.move_down_buttton = QPushButton(icon("fa.arrow-down", color="white"), "")
|
||||
self.move_down_buttton.clicked.connect(lambda: self.move_down.emit(self.app_name))
|
||||
self.left_layout.addWidget(self.move_down_buttton)
|
||||
self.move_down_buttton.setFixedWidth(20)
|
||||
|
||||
self.layout.addLayout(self.left_layout)
|
||||
|
||||
self.right_layout = QVBoxLayout()
|
||||
self.title = QLabel(item[1].app_title)
|
||||
self.right_layout.addWidget(self.title)
|
||||
|
||||
dl_size = item[-1].dl_size
|
||||
install_size = item[-1].install_size
|
||||
|
||||
self.size = QHBoxLayout()
|
||||
|
||||
self.size.addWidget(QLabel(self.tr("Download size: {} GB").format(dl_size / 1024 ** 3)))
|
||||
self.size.addWidget(QLabel(self.tr("Install size: {} GB").format(install_size / 1024 ** 3)))
|
||||
self.right_layout.addLayout(self.size)
|
||||
|
||||
self.delete = QPushButton(self.tr("Remove Download"))
|
||||
self.delete.clicked.connect(lambda: self.remove.emit(self.app_name))
|
||||
self.right_layout.addWidget(self.delete)
|
||||
|
||||
self.layout.addLayout(self.right_layout)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
|
||||
class DlQueueWidget(QGroupBox):
|
||||
update_list = pyqtSignal(list)
|
||||
dl_queue = []
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(DlQueueWidget, self).__init__()
|
||||
self.setTitle(self.tr("Download Queue"))
|
||||
self.layout = QVBoxLayout()
|
||||
self.setObjectName("group")
|
||||
self.text = QLabel(self.tr("No downloads in queue"))
|
||||
self.layout.addWidget(self.text)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def update_queue(self, dl_queue: list):
|
||||
logger.info("Update Queue " + ", ".join(i[1].app_title for i in dl_queue))
|
||||
self.dl_queue = dl_queue
|
||||
self.setLayout(QVBoxLayout())
|
||||
QWidget().setLayout(self.layout)
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
if len(dl_queue) == 0:
|
||||
self.layout.addWidget(QLabel(self.tr("No downloads in queue")))
|
||||
self.setLayout(self.layout)
|
||||
return
|
||||
|
||||
for index, item in enumerate(dl_queue):
|
||||
widget = DlWidget(index, item)
|
||||
widget.remove.connect(self.remove)
|
||||
widget.move_up.connect(self.move_up)
|
||||
widget.move_down.connect(self.move_down)
|
||||
self.layout.addWidget(widget)
|
||||
if index + 1 == len(dl_queue):
|
||||
widget.move_down_buttton.setDisabled(True)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def remove(self, app_name):
|
||||
for index, i in enumerate(self.dl_queue):
|
||||
if i[1].app_name == app_name:
|
||||
self.dl_queue.pop(index)
|
||||
break
|
||||
else:
|
||||
logger.warning("BUG! ", app_name)
|
||||
return
|
||||
self.update_list.emit(self.dl_queue)
|
||||
self.update_queue(self.dl_queue)
|
||||
|
||||
def move_up(self, app_name):
|
||||
index: int
|
||||
|
||||
for i, item in enumerate(self.dl_queue):
|
||||
if item[1].app_name == app_name:
|
||||
index = i
|
||||
break
|
||||
else:
|
||||
logger.warning("Could not find appname" + app_name)
|
||||
return
|
||||
self.dl_queue.insert(index - 1, self.dl_queue.pop(index))
|
||||
self.update_list.emit(self.dl_queue)
|
||||
self.update_queue(self.dl_queue)
|
||||
|
||||
def move_down(self, app_name):
|
||||
index: int
|
||||
|
||||
for i, item in enumerate(self.dl_queue):
|
||||
if item[1].app_name == app_name:
|
||||
index = i
|
||||
break
|
||||
else:
|
||||
logger.warning("Could not find appname" + app_name)
|
||||
return
|
||||
self.dl_queue.insert(index + 1, self.dl_queue.pop(index))
|
||||
self.update_list.emit(self.dl_queue)
|
||||
self.update_queue(self.dl_queue)
|
|
@ -1,19 +1,16 @@
|
|||
import datetime
|
||||
import os
|
||||
import queue
|
||||
import subprocess
|
||||
import time
|
||||
from logging import getLogger
|
||||
from multiprocessing import Queue as MPQueue
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton, QDialog, \
|
||||
QListWidget, QHBoxLayout
|
||||
QListWidget, QHBoxLayout, QGroupBox
|
||||
|
||||
from Rare.Components.Dialogs.InstallDialog import InstallInfoDialog, InstallDialog
|
||||
from Rare.utils.Models import InstallOptions, KillDownloadException
|
||||
from Rare.Components.Tabs.Downloads.DlQueueWidget import DlQueueWidget
|
||||
from Rare.Components.Tabs.Downloads.DownloadThread import DownloadThread
|
||||
from Rare.utils.Models import InstallOptions
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.downloader.manager import DLManager
|
||||
from custom_legendary.models.downloading import UIUpdate
|
||||
from custom_legendary.models.game import Game, InstalledGame
|
||||
from custom_legendary.utils.selective_dl import games
|
||||
|
@ -21,108 +18,10 @@ from custom_legendary.utils.selective_dl import games
|
|||
logger = getLogger("Download")
|
||||
|
||||
|
||||
class DownloadThread(QThread):
|
||||
status = pyqtSignal(str)
|
||||
statistics = pyqtSignal(UIUpdate)
|
||||
kill = False
|
||||
|
||||
def __init__(self, dlm: DLManager, core: LegendaryCore, status_queue: MPQueue, igame, repair=False,
|
||||
repair_file=None):
|
||||
super(DownloadThread, self).__init__()
|
||||
self.dlm = dlm
|
||||
self.core = core
|
||||
self.status_queue = status_queue
|
||||
self.igame = igame
|
||||
self.repair = repair
|
||||
self.repair_file = repair_file
|
||||
|
||||
def run(self):
|
||||
start_time = time.time()
|
||||
try:
|
||||
|
||||
self.dlm.start()
|
||||
time.sleep(1)
|
||||
while self.dlm.is_alive():
|
||||
if self.kill:
|
||||
# raise KillDownloadException()
|
||||
# TODO kill download queue, workers
|
||||
pass
|
||||
try:
|
||||
self.statistics.emit(self.status_queue.get(timeout=1))
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
self.dlm.join()
|
||||
|
||||
except KillDownloadException:
|
||||
self.status.emit("stop")
|
||||
logger.info("Downlaod can be continued later")
|
||||
self.dlm.kill()
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Installation failed after {time.time() - start_time:.02f} seconds: {e}")
|
||||
self.status.emit("error")
|
||||
return
|
||||
|
||||
else:
|
||||
self.status.emit("dl_finished")
|
||||
end_t = time.time()
|
||||
|
||||
game = self.core.get_game(self.igame.app_name)
|
||||
postinstall = self.core.install_game(self.igame)
|
||||
if postinstall:
|
||||
self._handle_postinstall(postinstall, self.igame)
|
||||
|
||||
dlcs = self.core.get_dlc_for_game(self.igame.app_name)
|
||||
if dlcs:
|
||||
print('The following DLCs are available for this game:')
|
||||
for dlc in dlcs:
|
||||
print(f' - {dlc.app_title} (App name: {dlc.app_name}, version: {dlc.app_version})')
|
||||
print('Manually installing DLCs works the same; just use the DLC app name instead.')
|
||||
|
||||
# install_dlcs = QMessageBox.question(self, "", "Do you want to install the prequisites", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes
|
||||
# TODO
|
||||
if game.supports_cloud_saves and not game.is_dlc:
|
||||
logger.info('This game supports cloud saves, syncing is handled by the "sync-saves" command.')
|
||||
logger.info(f'To download saves for this game run "legendary sync-saves {game.app_name}"')
|
||||
old_igame = self.core.get_installed_game(game.app_name)
|
||||
if old_igame and self.repair and os.path.exists(self.repair_file):
|
||||
if old_igame.needs_verification:
|
||||
old_igame.needs_verification = False
|
||||
self.core.install_game(old_igame)
|
||||
|
||||
logger.debug('Removing repair file.')
|
||||
os.remove(self.repair_file)
|
||||
if old_igame and old_igame.install_tags != self.igame.install_tags:
|
||||
old_igame.install_tags = self.igame.install_tags
|
||||
self.logger.info('Deleting now untagged files.')
|
||||
self.core.uninstall_tag(old_igame)
|
||||
self.core.install_game(old_igame)
|
||||
|
||||
self.status.emit("finish")
|
||||
|
||||
def _handle_postinstall(self, postinstall, igame):
|
||||
print('This game lists the following prequisites to be installed:')
|
||||
print(f'- {postinstall["name"]}: {" ".join((postinstall["path"], postinstall["args"]))}')
|
||||
if os.name == 'nt':
|
||||
if QMessageBox.question(self, "", "Do you want to install the prequisites",
|
||||
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
self.core.prereq_installed(igame.app_name)
|
||||
req_path, req_exec = os.path.split(postinstall['path'])
|
||||
work_dir = os.path.join(igame.install_path, req_path)
|
||||
fullpath = os.path.join(work_dir, req_exec)
|
||||
subprocess.call([fullpath, postinstall['args']], cwd=work_dir)
|
||||
else:
|
||||
self.core.prereq_installed(self.igame.app_name)
|
||||
|
||||
else:
|
||||
logger.info('Automatic installation not available on Linux.')
|
||||
|
||||
|
||||
class DownloadTab(QWidget):
|
||||
finished = pyqtSignal()
|
||||
thread: QThread
|
||||
dl_queue = []
|
||||
|
||||
def __init__(self, core: LegendaryCore, updates: list):
|
||||
super(DownloadTab, self).__init__()
|
||||
|
@ -146,7 +45,6 @@ class DownloadTab(QWidget):
|
|||
self.layout.addLayout(self.info_layout)
|
||||
|
||||
self.mini_layout = QHBoxLayout()
|
||||
|
||||
self.prog_bar = QProgressBar()
|
||||
self.prog_bar.setMaximum(100)
|
||||
self.mini_layout.addWidget(self.prog_bar)
|
||||
|
@ -158,33 +56,39 @@ class DownloadTab(QWidget):
|
|||
|
||||
self.layout.addLayout(self.mini_layout)
|
||||
|
||||
self.update_title = QLabel(f"<h2>{self.tr('Updates')}</h2>")
|
||||
self.update_title.setStyleSheet("""
|
||||
QLabel{
|
||||
margin-top: 20px;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(self.update_title)
|
||||
self.update_widgets = {}
|
||||
if not updates:
|
||||
self.update_text = QLabel(self.tr("No updates available"))
|
||||
self.layout.addWidget(self.update_text)
|
||||
else:
|
||||
for igame in updates:
|
||||
widget = UpdateWidget(core, igame)
|
||||
self.update_widgets[igame.app_name] = widget
|
||||
self.layout.addWidget(widget)
|
||||
widget.update.connect(self.update_game)
|
||||
self.queue_widget = DlQueueWidget()
|
||||
self.layout.addWidget(self.queue_widget)
|
||||
self.queue_widget.update_list.connect(self.update_dl_queue)
|
||||
|
||||
self.updates = QGroupBox(self.tr("Updates"))
|
||||
self.updates.setObjectName("group")
|
||||
self.update_layout = QVBoxLayout()
|
||||
self.update_widgets = {}
|
||||
|
||||
self.update_text = QLabel(self.tr("No updates available"))
|
||||
self.update_text.setVisible(len(updates) == 0)
|
||||
self.update_layout.addWidget(self.update_text)
|
||||
|
||||
for igame in updates:
|
||||
widget = UpdateWidget(core, igame)
|
||||
self.update_widgets[igame.app_name] = widget
|
||||
self.update_layout.addWidget(widget)
|
||||
widget.update.connect(self.update_game)
|
||||
|
||||
self.updates.setLayout(self.update_layout)
|
||||
self.layout.addWidget(self.updates)
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def update_dl_queue(self, dl_queue):
|
||||
self.dl_queue = dl_queue
|
||||
|
||||
def stop_download(self):
|
||||
self.thread.kill = True
|
||||
|
||||
def install_game(self, options: InstallOptions):
|
||||
game = self.core.get_game(options.app_name, update_meta=True)
|
||||
|
||||
status_queue = MPQueue()
|
||||
try:
|
||||
dlm, analysis, game, igame, repair, repair_file = self.core.prepare_download(
|
||||
|
@ -221,21 +125,27 @@ class DownloadTab(QWidget):
|
|||
if not analysis.dl_size:
|
||||
QMessageBox.information(self, "Warning", self.tr("Download size is 0. Game already exists"))
|
||||
return
|
||||
|
||||
# Information
|
||||
|
||||
if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept():
|
||||
return
|
||||
|
||||
if self.active_game is None:
|
||||
self.start_installation(dlm, game, status_queue, igame, repair_file, options, analysis)
|
||||
else:
|
||||
self.dl_queue.append((dlm, game, status_queue, igame, repair_file, options, analysis))
|
||||
self.queue_widget.update_queue(self.dl_queue)
|
||||
|
||||
def start_installation(self, dlm, game, status_queue, igame, repair_file, options: InstallOptions, analysis):
|
||||
print("start installation", game.app_title)
|
||||
self.active_game = game
|
||||
self.installing_game_widget.setText(self.tr("Installing game: ")+self.active_game.app_title)
|
||||
self.thread = DownloadThread(dlm, self.core, status_queue, igame, options.repair, repair_file)
|
||||
self.thread.status.connect(self.status)
|
||||
self.thread.statistics.connect(self.statistics)
|
||||
self.thread.start()
|
||||
self.kill_button.setDisabled(False)
|
||||
self.installing_game.setText("Installing Game: " + self.active_game.app_title)
|
||||
|
||||
for i in self.update_widgets.values():
|
||||
i.update_button.setDisabled(True)
|
||||
self.installing_game.setText(self.tr("Installing Game: ") + self.active_game.app_title)
|
||||
|
||||
def sdl_prompt(self, app_name: str = '', title: str = '') -> list:
|
||||
sdl = QDialog()
|
||||
|
@ -279,6 +189,8 @@ class DownloadTab(QWidget):
|
|||
if text == "dl_finished":
|
||||
pass
|
||||
elif text == "finish":
|
||||
self.installing_game.setText(self.tr("Download finished. Reload library"))
|
||||
|
||||
try:
|
||||
from notifypy import Notify
|
||||
except ModuleNotFoundError:
|
||||
|
@ -290,30 +202,43 @@ class DownloadTab(QWidget):
|
|||
notification.send()
|
||||
# QMessageBox.information(self, "Info", "Download finished")
|
||||
logger.info("Download finished: " + self.active_game.app_title)
|
||||
|
||||
if self.dl_queue:
|
||||
if self.dl_queue[0][1] == self.active_game.app_name:
|
||||
self.dl_queue.pop(0)
|
||||
self.queue_widget.update_queue(self.dl_queue)
|
||||
|
||||
if self.active_game.app_name in self.update_widgets.keys():
|
||||
self.update_widgets[self.active_game.app_name].setVisible(False)
|
||||
self.update_widgets.pop(self.active_game.app_name)
|
||||
|
||||
self.active_game = None
|
||||
|
||||
for i in self.update_widgets.values():
|
||||
i.update_button.setDisabled(False)
|
||||
|
||||
self.finished.emit()
|
||||
self.installing_game.setText(self.tr("Installing Game: No active download"))
|
||||
self.prog_bar.setValue(0)
|
||||
self.reset_infos()
|
||||
|
||||
if len(self.dl_queue) != 0:
|
||||
self.start_installation(*self.dl_queue[0])
|
||||
else:
|
||||
self.queue_widget.update_queue(self.dl_queue)
|
||||
|
||||
self.dl_speed.setText("")
|
||||
self.cache_used.setText("")
|
||||
self.downloaded.setText("")
|
||||
elif text == "error":
|
||||
QMessageBox.warning(self, "warn", "Download error")
|
||||
|
||||
elif text == "stop":
|
||||
self.kill_button.setDisabled(True)
|
||||
self.installing_game.setText(self.tr("Installing Game: No active download"))
|
||||
self.prog_bar.setValue(0)
|
||||
self.dl_speed.setText("")
|
||||
self.cache_used.setText("")
|
||||
self.downloaded.setText("")
|
||||
self.reset_infos()
|
||||
|
||||
def reset_infos(self):
|
||||
self.kill_button.setDisabled(True)
|
||||
self.installing_game.setText(self.tr("Installing Game: No active download"))
|
||||
self.prog_bar.setValue(0)
|
||||
self.dl_speed.setText("")
|
||||
self.time_left.setText("")
|
||||
self.cache_used.setText("")
|
||||
self.downloaded.setText("")
|
||||
|
||||
def statistics(self, ui_update: UIUpdate):
|
||||
self.prog_bar.setValue(ui_update.progress)
|
||||
|
@ -326,23 +251,19 @@ class DownloadTab(QWidget):
|
|||
return str(datetime.timedelta(seconds=seconds))
|
||||
|
||||
def update_game(self, app_name: str):
|
||||
print("Update ", app_name)
|
||||
logger.info("Update " + app_name)
|
||||
infos = InstallDialog(app_name, self.core, True).get_information()
|
||||
if infos != 0:
|
||||
path, max_workers, force, ignore_free_space = infos
|
||||
self.install_game(InstallOptions(app_name=app_name, max_workers=max_workers, path=path,
|
||||
force=force, ignore_free_space=ignore_free_space))
|
||||
|
||||
def repair(self):
|
||||
pass
|
||||
|
||||
|
||||
class UpdateWidget(QWidget):
|
||||
update = pyqtSignal(str)
|
||||
|
||||
def __init__(self, core: LegendaryCore, game: InstalledGame):
|
||||
super(UpdateWidget, self).__init__()
|
||||
print(game)
|
||||
self.core = core
|
||||
self.game = game
|
||||
|
||||
|
|
117
Rare/Components/Tabs/Downloads/DownloadThread.py
Normal file
117
Rare/Components/Tabs/Downloads/DownloadThread.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
import os
|
||||
import queue
|
||||
import subprocess
|
||||
import time
|
||||
from logging import getLogger
|
||||
from multiprocessing import Queue as MPQueue
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
from Rare.utils.Models import KillDownloadException
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.downloader.manager import DLManager
|
||||
from custom_legendary.models.downloading import UIUpdate
|
||||
|
||||
logger = getLogger("Download")
|
||||
|
||||
|
||||
class DownloadThread(QThread):
|
||||
status = pyqtSignal(str)
|
||||
statistics = pyqtSignal(UIUpdate)
|
||||
kill = False
|
||||
|
||||
def __init__(self, dlm: DLManager, core: LegendaryCore, status_queue: MPQueue, igame, repair=False,
|
||||
repair_file=None):
|
||||
super(DownloadThread, self).__init__()
|
||||
self.dlm = dlm
|
||||
self.core = core
|
||||
self.status_queue = status_queue
|
||||
self.igame = igame
|
||||
self.repair = repair
|
||||
self.repair_file = repair_file
|
||||
|
||||
def run(self):
|
||||
start_time = time.time()
|
||||
try:
|
||||
|
||||
self.dlm.start()
|
||||
time.sleep(1)
|
||||
while self.dlm.is_alive():
|
||||
if self.kill:
|
||||
# raise KillDownloadException()
|
||||
# TODO kill download queue, workers
|
||||
pass
|
||||
try:
|
||||
self.statistics.emit(self.status_queue.get(timeout=1))
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
self.dlm.join()
|
||||
|
||||
except KillDownloadException:
|
||||
self.status.emit("stop")
|
||||
logger.info("Downlaod can be continued later")
|
||||
self.dlm.kill()
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Installation failed after {time.time() - start_time:.02f} seconds: {e}")
|
||||
self.status.emit("error")
|
||||
return
|
||||
|
||||
else:
|
||||
self.status.emit("dl_finished")
|
||||
end_t = time.time()
|
||||
|
||||
game = self.core.get_game(self.igame.app_name)
|
||||
postinstall = self.core.install_game(self.igame)
|
||||
if postinstall:
|
||||
self._handle_postinstall(postinstall, self.igame)
|
||||
|
||||
dlcs = self.core.get_dlc_for_game(self.igame.app_name)
|
||||
if dlcs:
|
||||
print('The following DLCs are available for this game:')
|
||||
for dlc in dlcs:
|
||||
print(f' - {dlc.app_title} (App name: {dlc.app_name}, version: {dlc.app_version})')
|
||||
print('Manually installing DLCs works the same; just use the DLC app name instead.')
|
||||
|
||||
# install_dlcs = QMessageBox.question(self, "", "Do you want to install the prequisites", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes
|
||||
# TODO
|
||||
if game.supports_cloud_saves and not game.is_dlc:
|
||||
logger.info('This game supports cloud saves, syncing is handled by the "sync-saves" command.')
|
||||
logger.info(f'To download saves for this game run "legendary sync-saves {game.app_name}"')
|
||||
old_igame = self.core.get_installed_game(game.app_name)
|
||||
if old_igame and self.repair and os.path.exists(self.repair_file):
|
||||
if old_igame.needs_verification:
|
||||
old_igame.needs_verification = False
|
||||
self.core.install_game(old_igame)
|
||||
|
||||
logger.debug('Removing repair file.')
|
||||
os.remove(self.repair_file)
|
||||
if old_igame and old_igame.install_tags != self.igame.install_tags:
|
||||
old_igame.install_tags = self.igame.install_tags
|
||||
self.logger.info('Deleting now untagged files.')
|
||||
self.core.uninstall_tag(old_igame)
|
||||
self.core.install_game(old_igame)
|
||||
|
||||
self.status.emit("finish")
|
||||
|
||||
def _handle_postinstall(self, postinstall, igame):
|
||||
print('This game lists the following prequisites to be installed:')
|
||||
print(f'- {postinstall["name"]}: {" ".join((postinstall["path"], postinstall["args"]))}')
|
||||
if os.name == 'nt':
|
||||
if QMessageBox.question(self, "", "Do you want to install the prequisites",
|
||||
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
self.core.prereq_installed(igame.app_name)
|
||||
req_path, req_exec = os.path.split(postinstall['path'])
|
||||
work_dir = os.path.join(igame.install_path, req_path)
|
||||
fullpath = os.path.join(work_dir, req_exec)
|
||||
subprocess.call([fullpath, postinstall['args']], cwd=work_dir)
|
||||
else:
|
||||
self.core.prereq_installed(self.igame.app_name)
|
||||
|
||||
else:
|
||||
logger.info('Automatic installation not available on Linux.')
|
||||
|
|
@ -6,6 +6,7 @@ from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, QLabel, QHBoxLayo
|
|||
QProgressBar, QStackedWidget, QGroupBox
|
||||
from qtawesome import icon
|
||||
|
||||
from Rare.Components.Dialogs.UninstallDialog import UninstallDialog
|
||||
from Rare.Components.Tabs.Games.GameInfo.GameSettings import GameSettings
|
||||
from Rare.utils import LegendaryApi
|
||||
from Rare.utils.LegendaryApi import VerifyThread
|
||||
|
@ -65,6 +66,7 @@ class GameInfo(QWidget):
|
|||
right_layout.addWidget(self.game_title)
|
||||
|
||||
self.dev = QLabel("Error")
|
||||
self.dev.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
right_layout.addWidget(self.dev)
|
||||
|
||||
self.app_name = QLabel("Error")
|
||||
|
@ -72,12 +74,14 @@ class GameInfo(QWidget):
|
|||
right_layout.addWidget(self.app_name)
|
||||
|
||||
self.version = QLabel("Error")
|
||||
self.version.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
right_layout.addWidget(self.version)
|
||||
|
||||
self.install_size = QLabel("Error")
|
||||
right_layout.addWidget(self.install_size)
|
||||
|
||||
self.install_path = QLabel("Error")
|
||||
self.install_path.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
right_layout.addWidget(self.install_path)
|
||||
|
||||
top_layout.addLayout(right_layout)
|
||||
|
@ -95,10 +99,13 @@ class GameInfo(QWidget):
|
|||
self.setLayout(self.layout)
|
||||
|
||||
def uninstall(self):
|
||||
if QMessageBox.question(self, "Uninstall", self.tr("Are you sure to uninstall {}").format(self.game.app_title),
|
||||
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
LegendaryApi.uninstall(self.game.app_name, self.core)
|
||||
self.update_list.emit()
|
||||
infos = UninstallDialog(self.game).get_information()
|
||||
if infos == 0:
|
||||
print("Cancel Uninstall")
|
||||
return
|
||||
|
||||
LegendaryApi.uninstall(self.game.app_name, self.core, infos)
|
||||
self.update_list.emit()
|
||||
|
||||
def repair(self):
|
||||
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f'{self.game.app_name}.repair')
|
||||
|
|
|
@ -40,6 +40,7 @@ class GameList(QStackedWidget):
|
|||
self.icon_scrollarea.setWidgetResizable(True)
|
||||
self.icon_scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
|
||||
self.list_scrollarea.setWidgetResizable(True)
|
||||
self.list_scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
|
||||
self.info_text = self.tr("Installed Games: {} Available Games: {}").format(
|
||||
|
@ -53,7 +54,7 @@ class GameList(QStackedWidget):
|
|||
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)
|
||||
IMAGE_DIR = self.settings.value("img_dir", os.path.expanduser("~/.cache/rare/images"), str)
|
||||
self.updates = []
|
||||
self.widgets = {}
|
||||
|
||||
|
@ -80,7 +81,7 @@ class GameList(QStackedWidget):
|
|||
icon_widget.show_info.connect(self.show_game_info.emit)
|
||||
list_widget.show_info.connect(self.show_game_info.emit)
|
||||
|
||||
icon_widget.launch_signal.connect(self.launch)
|
||||
icon_widget.finish_signal.connect(self.launch)
|
||||
icon_widget.finish_signal.connect(self.finished)
|
||||
list_widget.launch_signal.connect(self.launch)
|
||||
list_widget.finish_signal.connect(self.finished)
|
||||
|
@ -100,6 +101,7 @@ class GameList(QStackedWidget):
|
|||
if not game.app_name in installed:
|
||||
uninstalled_games.append(game)
|
||||
|
||||
# add uninstalled games
|
||||
for game in uninstalled_games:
|
||||
if os.path.exists(f"{IMAGE_DIR}/{game.app_name}/UninstalledArt.png"):
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
|
||||
|
@ -110,15 +112,15 @@ class GameList(QStackedWidget):
|
|||
pixmap = QPixmap(f"{IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
|
||||
|
||||
else:
|
||||
logger.warning(f"No Image found: {self.game.app_title}")
|
||||
logger.warning(f"No Image found: {game.app_title}")
|
||||
download_image(game, force=True)
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
|
||||
|
||||
icon_widget = IconWidgetUninstalled(game, self.core, pixmap)
|
||||
icon_widget.install_game.connect(self.install_game.emit)
|
||||
icon_widget.install_game.connect(self.install)
|
||||
|
||||
list_widget = ListWidgetUninstalled(self.core, game, pixmap)
|
||||
list_widget.install_game.connect(self.install_game.emit)
|
||||
list_widget.install_game.connect(self.install)
|
||||
|
||||
self.icon_layout.addWidget(icon_widget)
|
||||
self.list_layout.addWidget(list_widget)
|
||||
|
@ -143,6 +145,14 @@ class GameList(QStackedWidget):
|
|||
if self.settings.value("installed_only", False, bool):
|
||||
self.installed_only(True)
|
||||
|
||||
def install(self, options: InstallOptions):
|
||||
icon_widget, list_widget = self.widgets[options.app_name]
|
||||
icon_widget.mousePressEvent = lambda e: None
|
||||
icon_widget.installing = True
|
||||
list_widget.install_button.setDisabled(True)
|
||||
list_widget.installing = True
|
||||
self.install_game.emit(options)
|
||||
|
||||
def finished(self, app_name):
|
||||
self.widgets[app_name][0].info_text = ""
|
||||
self.widgets[app_name][0].info_label.setText("")
|
||||
|
|
|
@ -25,6 +25,8 @@ class BaseInstalledWidget(QGroupBox):
|
|||
self.game_running = False
|
||||
self.update_available = self.core.get_asset(self.game.app_name, True).build_version != igame.version
|
||||
|
||||
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# self.setStyleSheet("border-radius: 5px")
|
||||
|
|
|
@ -17,6 +17,7 @@ class BaseUninstalledWidget(QGroupBox):
|
|||
self.game = game
|
||||
self.core = core
|
||||
self.pixmap = pixmap
|
||||
self.installing = False
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class GameWidgetInstalled(BaseInstalledWidget):
|
|||
|
||||
if self.pixmap:
|
||||
w = 200
|
||||
self.pixmap = self.pixmap.scaled(w, int(w * 4 / 3))
|
||||
self.pixmap = self.pixmap.scaled(w, int(w * 4 / 3), transformMode=Qt.SmoothTransformation)
|
||||
self.image = ClickableLabel()
|
||||
self.image.setObjectName("game_widget")
|
||||
self.image.setPixmap(self.pixmap)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QProcess, pyqtSignal
|
||||
from PyQt5.QtCore import QProcess, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QStyle, QVBoxLayout
|
||||
from qtawesome import icon
|
||||
|
||||
|
@ -30,7 +30,7 @@ class InstalledListWidget(BaseInstalledWidget):
|
|||
self.childLayout = QVBoxLayout()
|
||||
|
||||
if self.pixmap:
|
||||
self.pixmap = self.pixmap.scaled(180, 240)
|
||||
self.pixmap = self.pixmap.scaled(180, 240, transformMode=Qt.SmoothTransformation)
|
||||
self.image = QLabel()
|
||||
self.image.setPixmap(self.pixmap)
|
||||
self.layout.addWidget(self.image)
|
||||
|
|
|
@ -18,7 +18,7 @@ class IconWidgetUninstalled(BaseUninstalledWidget):
|
|||
def __init__(self, game: Game, core: LegendaryCore, pixmap):
|
||||
super(IconWidgetUninstalled, self).__init__(game, core, pixmap)
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.setObjectName("game_widget_icon")
|
||||
if self.pixmap:
|
||||
w = 200
|
||||
self.pixmap = self.pixmap.scaled(w, int(w * 4 / 3))
|
||||
|
@ -37,10 +37,17 @@ class IconWidgetUninstalled(BaseUninstalledWidget):
|
|||
self.setFixedWidth(self.sizeHint().width())
|
||||
|
||||
def mousePressEvent(self, e) -> None:
|
||||
self.install()
|
||||
if not self.installing:
|
||||
self.install()
|
||||
|
||||
def enterEvent(self, e):
|
||||
self.info_label.setText(self.tr("Install Game"))
|
||||
if not self.installing:
|
||||
self.info_label.setText(self.tr("Install Game"))
|
||||
else:
|
||||
self.info_label.setText(self.tr("Installation running"))
|
||||
|
||||
def leaveEvent(self, e):
|
||||
self.info_label.setText("")
|
||||
if self.installing:
|
||||
self.info_label.setText("Installation...")
|
||||
else:
|
||||
self.info_label.setText("")
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
from PyQt5.QtCore import QSettings, QSize
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineEdit, QPushButton, QStackedLayout, QLabel
|
||||
from qtawesome import icon
|
||||
|
||||
from Rare.Components.Tabs.Games.GameInfo.GameInfo import InfoTabs
|
||||
from Rare.Components.Tabs.Games.GameList import GameList
|
||||
from Rare.Components.Tabs.Games.ImportWidget import ImportWidget
|
||||
from Rare.utils.QtExtensions import SelectViewWidget
|
||||
|
||||
|
||||
class GameTab(QWidget):
|
||||
def __init__(self, core):
|
||||
super(GameTab, self).__init__()
|
||||
self.layout = QStackedLayout()
|
||||
self.default_widget = Games(core)
|
||||
self.default_widget.game_list.show_game_info.connect(self.show_info)
|
||||
self.default_widget.head_bar.import_game.clicked.connect(lambda: self.layout.setCurrentIndex(2))
|
||||
self.layout.addWidget(self.default_widget)
|
||||
self.game_info = InfoTabs(core)
|
||||
self.game_info.info.update_list.connect(self.update_list)
|
||||
self.layout.addWidget(self.game_info)
|
||||
|
||||
self.default_widget.head_bar.refresh_list.clicked.connect(self.update_list)
|
||||
|
||||
self.import_widget = ImportWidget(core)
|
||||
self.layout.addWidget(self.import_widget)
|
||||
self.import_widget.back_button.clicked.connect(lambda: self.layout.setCurrentIndex(0))
|
||||
self.import_widget.update_list.connect(self.update_list)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def update_list(self):
|
||||
self.default_widget.game_list.update_list(not self.default_widget.head_bar.view.isChecked())
|
||||
self.layout.setCurrentIndex(0)
|
||||
|
||||
def show_info(self, app_name):
|
||||
self.game_info.update_game(app_name)
|
||||
self.game_info.setCurrentIndex(1)
|
||||
self.layout.setCurrentIndex(1)
|
||||
|
||||
|
||||
class Games(QWidget):
|
||||
def __init__(self, core):
|
||||
super(Games, self).__init__()
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.head_bar = GameListHeadBar()
|
||||
self.head_bar.setObjectName("head_bar")
|
||||
|
||||
self.game_list = GameList(core)
|
||||
|
||||
self.head_bar.search_bar.textChanged.connect(
|
||||
lambda: self.game_list.filter(self.head_bar.search_bar.text()))
|
||||
|
||||
self.head_bar.installed_only.stateChanged.connect(lambda:
|
||||
self.game_list.installed_only(
|
||||
self.head_bar.installed_only.isChecked()))
|
||||
self.layout.addWidget(self.head_bar)
|
||||
self.layout.addWidget(self.game_list)
|
||||
# self.layout.addStretch(1)
|
||||
self.head_bar.view.toggled.connect(self.toggle_view)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def toggle_view(self):
|
||||
self.game_list.setCurrentIndex(1 if self.head_bar.view.isChecked() else 0)
|
||||
settings = QSettings()
|
||||
settings.setValue("icon_view", not self.head_bar.view.isChecked())
|
||||
|
||||
|
||||
class GameListHeadBar(QWidget):
|
||||
def __init__(self):
|
||||
super(GameListHeadBar, self).__init__()
|
||||
self.layout = QHBoxLayout()
|
||||
self.installed_only = QCheckBox(self.tr("Installed only"))
|
||||
self.settings = QSettings()
|
||||
self.installed_only.setChecked(self.settings.value("installed_only", False, bool))
|
||||
self.layout.addWidget(self.installed_only)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.import_game = QPushButton(icon("mdi.import", color="white"), self.tr("Import Game"))
|
||||
self.layout.addWidget(self.import_game)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.search_bar = QLineEdit()
|
||||
self.search_bar.setObjectName("search_bar")
|
||||
self.search_bar.setFrame(False)
|
||||
icon_label = QLabel()
|
||||
icon_label.setPixmap(icon("fa.search", color="white").pixmap(QSize(20, 20)))
|
||||
self.layout.addWidget(icon_label)
|
||||
self.search_bar.setMinimumWidth(200)
|
||||
self.search_bar.setPlaceholderText(self.tr("Search Game"))
|
||||
self.layout.addWidget(self.search_bar)
|
||||
|
||||
self.layout.addStretch(2)
|
||||
|
||||
checked = QSettings().value("icon_view", True, bool)
|
||||
|
||||
self.view = SelectViewWidget(checked)
|
||||
self.layout.addWidget(self.view)
|
||||
self.layout.addStretch(1)
|
||||
self.refresh_list = QPushButton()
|
||||
self.refresh_list.setIcon(icon("fa.refresh", color="white")) # Reload icon
|
||||
self.layout.addWidget(self.refresh_list)
|
||||
|
||||
self.setLayout(self.layout)
|
|
@ -4,7 +4,8 @@ import string
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QPushButton, QVBoxLayout, QFileDialog, QMessageBox, QLineEdit
|
||||
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QPushButton, QVBoxLayout, QFileDialog, QMessageBox, QLineEdit, \
|
||||
QGroupBox
|
||||
from qtawesome import icon
|
||||
|
||||
from Rare.utils import LegendaryApi
|
||||
|
@ -34,11 +35,13 @@ class ImportWidget(QWidget):
|
|||
self.title = QLabel("<h2>Import Game</h2")
|
||||
self.layout.addWidget(self.title)
|
||||
|
||||
self.import_one_game = QLabel(f"<h3>{self.tr('Import existing game from Epic Games Launcher')}</h3>")
|
||||
self.layout.addWidget(self.import_one_game)
|
||||
# self.import_one_game = QLabel(f"<h3>{self.tr('Import existing game from Epic Games Launcher')}</h3>")
|
||||
self.import_one_game = QGroupBox(self.tr('Import existing game from Epic Games Launcher'))
|
||||
self.import_one_game.setObjectName("group")
|
||||
self.gb_layout = QVBoxLayout()
|
||||
|
||||
self.import_game_info = QLabel(self.tr("Select path to game"))
|
||||
self.layout.addWidget(self.import_game_info)
|
||||
self.gb_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()
|
||||
|
@ -52,17 +55,21 @@ class ImportWidget(QWidget):
|
|||
|
||||
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.gb_layout.addWidget(self.path_edit)
|
||||
|
||||
self.layout.addWidget(self.override_app_name_label)
|
||||
self.layout.addWidget(self.app_name_input)
|
||||
self.gb_layout.addWidget(self.override_app_name_label)
|
||||
self.gb_layout.addWidget(self.app_name_input)
|
||||
|
||||
self.info_label = QLabel("")
|
||||
self.layout.addWidget(self.info_label)
|
||||
self.gb_layout.addWidget(self.info_label)
|
||||
self.import_button = QPushButton(self.tr("Import Game"))
|
||||
self.layout.addWidget(self.import_button)
|
||||
self.gb_layout.addWidget(self.import_button)
|
||||
self.import_button.clicked.connect(self.import_game)
|
||||
|
||||
self.import_one_game.setLayout(self.gb_layout)
|
||||
|
||||
self.layout.addWidget(self.import_one_game)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.auto_import = QLabel(f"<h3>{self.tr('Auto import all existing games')}</h3>")
|
||||
|
@ -104,6 +111,7 @@ class ImportWidget(QWidget):
|
|||
if not path:
|
||||
path = self.path_edit.text()
|
||||
if not app_name:
|
||||
# try to find app name
|
||||
if a_n := self.find_app_name(path):
|
||||
app_name = a_n
|
||||
else:
|
||||
|
@ -134,7 +142,7 @@ class ImportWidget(QWidget):
|
|||
continue
|
||||
app_name = self.find_app_name(json_path)
|
||||
if not app_name:
|
||||
logger.warning("Could not find app name")
|
||||
logger.warning("Could not find app name at " + game_path)
|
||||
continue
|
||||
|
||||
if LegendaryApi.import_game(self.core, app_name, game_path + path):
|
||||
|
@ -159,4 +167,4 @@ class ImportWidget(QWidget):
|
|||
QMessageBox.information(self, "Imported Games", self.tr("Successfully imported {} Games. Reloading Library").format(imported))
|
||||
self.update_list.emit()
|
||||
else:
|
||||
QMessageBox.information(self, "Imported Games", "No Games were found")
|
||||
QMessageBox.information(self, "Imported Games", self.tr("No Games were found"))
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
from PyQt5.QtCore import QSettings, QSize
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineEdit, QPushButton, QStackedLayout, QLabel
|
||||
from qtawesome import icon
|
||||
|
||||
from Rare.Components.Tabs.Games.GameInfo.GameInfo import InfoTabs
|
||||
from Rare.Components.Tabs.Games.GameList import GameList
|
||||
from Rare.Components.Tabs.Games.ImportWidget import ImportWidget
|
||||
from Rare.utils.QtExtensions import SelectViewWidget
|
||||
|
||||
|
||||
class GameTab(QWidget):
|
||||
def __init__(self, core):
|
||||
super(GameTab, self).__init__()
|
||||
self.layout = QStackedLayout()
|
||||
self.default_widget = Games(core)
|
||||
self.default_widget.game_list.show_game_info.connect(self.show_info)
|
||||
self.default_widget.head_bar.import_game.clicked.connect(lambda: self.layout.setCurrentIndex(2))
|
||||
self.layout.addWidget(self.default_widget)
|
||||
self.game_info = InfoTabs(core)
|
||||
self.game_info.info.update_list.connect(self.update_list)
|
||||
self.layout.addWidget(self.game_info)
|
||||
|
||||
self.default_widget.head_bar.refresh_list.clicked.connect(self.update_list)
|
||||
|
||||
self.import_widget = ImportWidget(core)
|
||||
self.layout.addWidget(self.import_widget)
|
||||
self.import_widget.back_button.clicked.connect(lambda: self.layout.setCurrentIndex(0))
|
||||
self.import_widget.update_list.connect(self.update_list)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def update_list(self):
|
||||
self.default_widget.game_list.update_list(self.default_widget.head_bar.view.isChecked())
|
||||
self.layout.setCurrentIndex(0)
|
||||
|
||||
def show_info(self, app_name):
|
||||
self.game_info.update_game(app_name)
|
||||
self.game_info.setCurrentIndex(1)
|
||||
self.layout.setCurrentIndex(1)
|
||||
|
||||
|
||||
class Games(QWidget):
|
||||
def __init__(self, core):
|
||||
super(Games, self).__init__()
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.head_bar = GameListHeadBar()
|
||||
self.head_bar.setObjectName("head_bar")
|
||||
|
||||
self.game_list = GameList(core)
|
||||
|
||||
self.head_bar.search_bar.textChanged.connect(
|
||||
lambda: self.game_list.filter(self.head_bar.search_bar.text()))
|
||||
|
||||
self.head_bar.installed_only.stateChanged.connect(lambda:
|
||||
self.game_list.installed_only(
|
||||
self.head_bar.installed_only.isChecked()))
|
||||
self.layout.addWidget(self.head_bar)
|
||||
self.layout.addWidget(self.game_list)
|
||||
# self.layout.addStretch(1)
|
||||
self.head_bar.view.toggled.connect(self.toggle_view)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def toggle_view(self):
|
||||
self.game_list.setCurrentIndex(1 if self.head_bar.view.isChecked() else 0)
|
||||
settings = QSettings()
|
||||
settings.setValue("icon_view", not self.head_bar.view.isChecked())
|
||||
|
||||
|
||||
class GameListHeadBar(QWidget):
|
||||
def __init__(self):
|
||||
super(GameListHeadBar, self).__init__()
|
||||
self.layout = QHBoxLayout()
|
||||
self.installed_only = QCheckBox(self.tr("Installed only"))
|
||||
self.settings = QSettings()
|
||||
self.installed_only.setChecked(self.settings.value("installed_only", False, bool))
|
||||
self.layout.addWidget(self.installed_only)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.import_game = QPushButton(icon("mdi.import", color="white"), self.tr("Import Game"))
|
||||
self.layout.addWidget(self.import_game)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.search_bar = QLineEdit()
|
||||
self.search_bar.setObjectName("search_bar")
|
||||
self.search_bar.setFrame(False)
|
||||
icon_label = QLabel()
|
||||
icon_label.setPixmap(icon("fa.search", color="white").pixmap(QSize(20, 20)))
|
||||
self.layout.addWidget(icon_label)
|
||||
self.search_bar.setMinimumWidth(200)
|
||||
self.search_bar.setPlaceholderText(self.tr("Search Game"))
|
||||
self.layout.addWidget(self.search_bar)
|
||||
|
||||
self.layout.addStretch(2)
|
||||
|
||||
checked = QSettings().value("icon_view", True, bool)
|
||||
|
||||
self.view = SelectViewWidget(checked)
|
||||
self.layout.addWidget(self.view)
|
||||
self.layout.addStretch(1)
|
||||
self.refresh_list = QPushButton()
|
||||
self.refresh_list.setIcon(icon("fa.refresh", color="white")) # Reload icon
|
||||
self.layout.addWidget(self.refresh_list)
|
||||
|
||||
self.setLayout(self.layout)
|
|
@ -1,6 +1,9 @@
|
|||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel
|
||||
import webbrowser
|
||||
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton
|
||||
|
||||
from Rare import __version__
|
||||
from Rare.utils.utils import get_latest_version
|
||||
|
||||
|
||||
class About(QWidget):
|
||||
|
@ -13,6 +16,15 @@ class About(QWidget):
|
|||
|
||||
self.version = QLabel("Version: " + __version__)
|
||||
self.layout.addWidget(self.version)
|
||||
latest_tag = get_latest_version()
|
||||
self.update_available = latest_tag != __version__
|
||||
if latest_tag != __version__:
|
||||
print(f"Update available: {__version__} -> {latest_tag}")
|
||||
self.update_available = QLabel(self.tr("Update available: {} -> {}").format(__version__, latest_tag))
|
||||
self.layout.addWidget(self.update_available)
|
||||
self.open_browser = QPushButton(self.tr("Download latest release"))
|
||||
self.layout.addWidget(self.open_browser)
|
||||
self.open_browser.clicked.connect(lambda: webbrowser.open("https://github.com/Dummerle/Rare/releases/latest"))
|
||||
|
||||
self.dev = QLabel(self.tr("Developer:") + "<a href='https://github.com/Dummerle'>Dummerle</a>")
|
||||
self.dev.setToolTip("Github")
|
||||
|
|
|
@ -41,8 +41,10 @@ class DxvkWidget(QGroupBox):
|
|||
self.more_settings.setPopupMode(QToolButton.InstantPopup)
|
||||
self.more_settings.setMenu(QMenu())
|
||||
self.more_settings.setText("More DXVK settings")
|
||||
|
||||
action = QWidgetAction(self)
|
||||
self.more_settings_widget = DxvkMoreSettingsWidget(self.dxvk_settings, self.core)
|
||||
self.more_settings_widget.show_dxvk.connect(lambda x: self.show_dxvk.setChecked(x))
|
||||
action.setDefaultWidget(self.more_settings_widget)
|
||||
self.more_settings.menu().addAction(action)
|
||||
|
||||
|
@ -71,7 +73,8 @@ class DxvkWidget(QGroupBox):
|
|||
def update_dxvk_active(self):
|
||||
if self.show_dxvk.isChecked():
|
||||
if not f"{self.name}.env" in self.core.lgd.config.sections():
|
||||
self.core.lgd.config[f"{self.name}.env"] = {}
|
||||
print("add section dxvk")
|
||||
self.core.lgd.config.add_section(f"{self.name}.env")
|
||||
self.more_settings.setDisabled(False)
|
||||
|
||||
for i in self.more_settings_widget.settings:
|
||||
|
@ -93,11 +96,11 @@ class DxvkWidget(QGroupBox):
|
|||
self.core.lgd.config.remove_option(f"{self.name}.env", "DXVK_HUD")
|
||||
if not self.core.lgd.config[f"{self.name}.env"]:
|
||||
self.core.lgd.config.remove_section(f"{self.name}.env")
|
||||
print("Remove Section DXVK_HUD")
|
||||
self.core.lgd.save_config()
|
||||
|
||||
|
||||
class DxvkMoreSettingsWidget(QWidget):
|
||||
show_dxvk = pyqtSignal(bool)
|
||||
def __init__(self, settings: dict, core: LegendaryCore):
|
||||
super(DxvkMoreSettingsWidget, self).__init__()
|
||||
self.layout = QVBoxLayout()
|
||||
|
@ -118,16 +121,22 @@ class DxvkMoreSettingsWidget(QWidget):
|
|||
y = list(self.settings[tag])
|
||||
y[0] = checked
|
||||
self.settings[tag] = tuple(y)
|
||||
# print(self.settings)
|
||||
|
||||
sett = []
|
||||
logger.debug(self.settings)
|
||||
for i in self.settings:
|
||||
check, _ = self.settings[i]
|
||||
if check:
|
||||
sett.append(i)
|
||||
if sett:
|
||||
self.core.lgd.config[f"{self.name}.env"]["DXVK_HUD"] = ",".join(sett)
|
||||
self.core.lgd.save_config()
|
||||
if len(sett) != 0:
|
||||
self.core.lgd.config.set(f"{self.name}.env", "DXVK_HUD", ",".join(sett))
|
||||
|
||||
else:
|
||||
self.core.lgd.config.remove_option(f"{self.name}.env", "DXVK_HUD")
|
||||
self.show_dxvk.emit(False)
|
||||
if not self.core.lgd.config.options(f"{self.name}.env"):
|
||||
self.core.lgd.config.remove_section(f"{self.name}.env")
|
||||
self.core.lgd.save_config()
|
||||
|
||||
|
||||
class CheckBox(QCheckBox):
|
||||
|
|
|
@ -10,14 +10,15 @@ from custom_legendary.core import LegendaryCore
|
|||
logger = getLogger("LegendarySettings")
|
||||
|
||||
|
||||
class LegendarySettings(QWidget):
|
||||
class LegendarySettings(QGroupBox):
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(LegendarySettings, self).__init__()
|
||||
self.setTitle(self.tr("Legendary settings"))
|
||||
self.layout = QVBoxLayout()
|
||||
self.core = core
|
||||
self.title = QLabel("<h2>" + self.tr("Legendary settings") + "</h2>")
|
||||
self.layout.addWidget(self.title)
|
||||
|
||||
#self.title = QLabel("<h2>" + self.tr("Legendary settings") + "</h2>")
|
||||
#self.layout.addWidget(self.title)
|
||||
self.setObjectName("group")
|
||||
# Default installation directory
|
||||
self.select_path = PathEdit(core.get_default_install_dir(), type_of_file=QFileDialog.DirectoryOnly,
|
||||
infotext="Default")
|
||||
|
@ -39,8 +40,7 @@ class LegendarySettings(QWidget):
|
|||
|
||||
#cleanup
|
||||
self.clean_layout = QVBoxLayout()
|
||||
self.cleanup_widget = QGroupBox()
|
||||
self.cleanup_widget.setTitle(self.tr("Cleanup"))
|
||||
self.cleanup_widget = QGroupBox(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)
|
||||
|
@ -59,20 +59,20 @@ class LegendarySettings(QWidget):
|
|||
self.core.lgd.config["Legendary"]["install_dir"] = self.select_path.text()
|
||||
if self.select_path.text() == "" and "install_dir" in self.core.lgd.config["Legendary"].keys():
|
||||
self.core.lgd.config["Legendary"].pop("install_dir")
|
||||
logger.info("Remove install_dir section")
|
||||
else:
|
||||
logger.info("Set config install_dir to " + self.select_path.text())
|
||||
self.core.lgd.save_config()
|
||||
|
||||
def max_worker_save(self, num_workers: str):
|
||||
self.core.lgd.config["Legendary"]["max_workers"] = num_workers
|
||||
if num_workers == "":
|
||||
self.core.lgd.config["Legendary"].pop("max_workers")
|
||||
self.core.lgd.config.remove_option("Legendary", "max_workers")
|
||||
self.core.lgd.save_config()
|
||||
return
|
||||
num_workers = int(num_workers)
|
||||
if num_workers == 0:
|
||||
self.core.lgd.config["Legendary"].pop("max_workers")
|
||||
logger.info("Updating config for max_workers")
|
||||
self.core.lgd.config.remove_option("Legendary", "max_workers")
|
||||
else:
|
||||
self.core.lgd.config.set("Legendary", "max_workers", str(num_workers))
|
||||
self.core.lgd.save_config()
|
||||
|
||||
def cleanup(self, keep_manifests):
|
||||
|
@ -92,7 +92,7 @@ class LegendarySettings(QWidget):
|
|||
|
||||
after = self.core.lgd.get_dir_size()
|
||||
logger.info(f'Cleanup complete! Removed {(before - after) / 1024 / 1024:.02f} MiB.')
|
||||
if cleaned := (before-after) != 0:
|
||||
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")
|
||||
|
|
|
@ -3,7 +3,7 @@ import shutil
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QSettings
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QFileDialog, QComboBox, QPushButton, QCheckBox
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QFileDialog, QComboBox, QPushButton, QCheckBox, QGroupBox
|
||||
|
||||
from Rare.Components.Tabs.Settings.SettingsWidget import SettingsWidget
|
||||
from Rare.utils.QtExtensions import PathEdit
|
||||
|
@ -12,21 +12,16 @@ from Rare.utils.utils import get_lang, get_possible_langs
|
|||
logger = getLogger("RareSettings")
|
||||
|
||||
|
||||
class RareSettings(QWidget):
|
||||
class RareSettings(QGroupBox):
|
||||
def __init__(self):
|
||||
super(RareSettings, self).__init__()
|
||||
self.setTitle(self.tr("Rare settings"))
|
||||
self.setObjectName("group")
|
||||
self.layout = QVBoxLayout()
|
||||
self.title = QLabel("<h2>" + self.tr("Rare settings") + "</h2>")
|
||||
self.layout.addWidget(self.title)
|
||||
settings = QSettings()
|
||||
img_dir = settings.value("img_dir", type=str)
|
||||
language = settings.value("language", type=str)
|
||||
# default settings
|
||||
if not img_dir:
|
||||
settings.setValue("img_dir", os.path.expanduser("~/.cache/rare/"))
|
||||
if not language:
|
||||
settings.setValue("language", get_lang())
|
||||
del settings
|
||||
img_dir = settings.value("img_dir", os.path.expanduser("~/.cache/rare/images/"), type=str)
|
||||
language = settings.value("language", get_lang(), type=str)
|
||||
|
||||
# select Image dir
|
||||
self.select_path = PathEdit(img_dir, type_of_file=QFileDialog.DirectoryOnly)
|
||||
self.select_path.text_edit.textChanged.connect(lambda t: self.save_path_button.setDisabled(False))
|
||||
|
@ -37,19 +32,27 @@ class RareSettings(QWidget):
|
|||
|
||||
# Select lang
|
||||
self.select_lang = QComboBox()
|
||||
languages = ["English", "Deutsch"]
|
||||
languages = ["English", "Deutsch", "Français"]
|
||||
self.select_lang.addItems(languages)
|
||||
if language in get_possible_langs():
|
||||
if language == "de":
|
||||
self.select_lang.setCurrentIndex(1)
|
||||
elif language == "en":
|
||||
self.select_lang.setCurrentIndex(0)
|
||||
elif language == "fr":
|
||||
self.select_lang.setCurrentIndex(2)
|
||||
else:
|
||||
self.select_lang.setCurrentIndex(0)
|
||||
self.lang_widget = SettingsWidget(self.tr("Language"), self.select_lang)
|
||||
self.select_lang.currentIndexChanged.connect(self.update_lang)
|
||||
self.layout.addWidget(self.lang_widget)
|
||||
|
||||
self.exit_to_sys_tray = QCheckBox(self.tr("Hide to System Tray Icon"))
|
||||
self.exit_to_sys_tray.setChecked(settings.value("sys_tray", True, bool))
|
||||
self.exit_to_sys_tray.stateChanged.connect(self.update_sys_tray)
|
||||
self.sys_tray_widget = SettingsWidget(self.tr("Exit to System Tray Icon"), self.exit_to_sys_tray)
|
||||
self.layout.addWidget(self.sys_tray_widget)
|
||||
|
||||
self.game_start_accept = QCheckBox(self.tr("Confirm launch of game"))
|
||||
self.game_start_accept.stateChanged.connect(self.update_start_confirm)
|
||||
self.game_start_accept_widget = SettingsWidget(self.tr("Confirm launch of game"), self.game_start_accept)
|
||||
|
@ -59,6 +62,10 @@ class RareSettings(QWidget):
|
|||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def update_sys_tray(self):
|
||||
settings = QSettings()
|
||||
settings.setValue("sys_tray", self.exit_to_sys_tray.isChecked())
|
||||
|
||||
def update_start_confirm(self):
|
||||
settings = QSettings()
|
||||
settings.setValue("confirm_start", self.game_start_accept.isChecked())
|
||||
|
@ -73,7 +80,8 @@ class RareSettings(QWidget):
|
|||
settings.setValue("language", "en")
|
||||
elif i == 1:
|
||||
settings.setValue("language", "de")
|
||||
del settings
|
||||
elif i == 2:
|
||||
settings.setValue("language", "fr")
|
||||
self.lang_widget.info_text.setText(self.tr("Restart Application to activate changes"))
|
||||
|
||||
def update_path(self):
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import os
|
||||
|
||||
from PyQt5.QtWidgets import QTabWidget
|
||||
|
||||
from Rare.Components.Tabs.Settings.About import About
|
||||
from Rare.Components.Tabs.Settings.Legendary import LegendarySettings
|
||||
from Rare.Components.Tabs.Settings.Linux import LinuxSettings
|
||||
from Rare.Components.Tabs.Settings.Rare import RareSettings
|
||||
from Rare.utils.QtExtensions import SideTabBar
|
||||
|
||||
|
||||
class SettingsTab(QTabWidget):
|
||||
def __init__(self, core):
|
||||
super(SettingsTab, self).__init__()
|
||||
self.core = core
|
||||
self.setTabBar(SideTabBar())
|
||||
self.setTabPosition(QTabWidget.West)
|
||||
self.addTab(RareSettings(), "Rare")
|
||||
self.addTab(LegendarySettings(core), "Legendary")
|
||||
if os.name != "nt":
|
||||
self.addTab(LinuxSettings(core), "Linux")
|
||||
self.addTab(About(), "About")
|
|
@ -0,0 +1,24 @@
|
|||
import os
|
||||
|
||||
from PyQt5.QtWidgets import QTabWidget
|
||||
|
||||
from Rare.Components.Tabs.Settings.About import About
|
||||
from Rare.Components.Tabs.Settings.Legendary import LegendarySettings
|
||||
from Rare.Components.Tabs.Settings.Linux import LinuxSettings
|
||||
from Rare.Components.Tabs.Settings.Rare import RareSettings
|
||||
from Rare.utils.QtExtensions import SideTabBar
|
||||
|
||||
|
||||
class SettingsTab(QTabWidget):
|
||||
def __init__(self, core):
|
||||
super(SettingsTab, self).__init__()
|
||||
self.core = core
|
||||
self.setTabBar(SideTabBar())
|
||||
self.setTabPosition(QTabWidget.West)
|
||||
self.addTab(RareSettings(), "Rare")
|
||||
self.addTab(LegendarySettings(core), "Legendary")
|
||||
if os.name != "nt":
|
||||
self.addTab(LinuxSettings(core), "Linux")
|
||||
self.about = About()
|
||||
|
||||
self.addTab(self.about, "About (!)" if self.about.update_available else "About")
|
22
Rare/Components/TrayIcon.py
Normal file
22
Rare/Components/TrayIcon.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from PyQt5.QtCore import QCoreApplication
|
||||
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QAction
|
||||
from qtawesome import icon
|
||||
|
||||
|
||||
class TrayIcon(QSystemTrayIcon):
|
||||
def __init__(self, parent):
|
||||
super(TrayIcon, self).__init__(parent)
|
||||
self.setIcon(icon("ei.cogs", color="white"))
|
||||
self.setVisible(True)
|
||||
self.setToolTip("Rare")
|
||||
|
||||
self.menu = QMenu()
|
||||
|
||||
self.start_rare = QAction("Rare")
|
||||
self.menu.addAction(self.start_rare)
|
||||
|
||||
self.exit_action = QAction(self.tr("Exit"))
|
||||
self.menu.addSeparator()
|
||||
self.menu.addAction(self.exit_action)
|
||||
|
||||
self.setContextMenu(self.menu)
|
41
Rare/Main.py
41
Rare/Main.py
|
@ -2,21 +2,30 @@ import configparser
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from PyQt5.QtCore import QSettings, QTranslator
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon
|
||||
|
||||
from Rare import lang_path, style_path
|
||||
from Rare.Components.Launch.LaunchDialog import LaunchDialog
|
||||
from Rare.Components.MainWindow import MainWindow
|
||||
from Rare.Components.TrayIcon import TrayIcon
|
||||
from Rare.utils.utils import get_lang
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
start_time = time.strftime('%y-%m-%d--%H:%M') # year-month-day-hour-minute
|
||||
file_name = os.path.expanduser(f"~/.cache/rare/logs/Rare_{start_time}.log")
|
||||
if not os.path.exists(os.path.dirname(file_name)):
|
||||
os.makedirs(os.path.dirname(file_name))
|
||||
|
||||
logging.basicConfig(
|
||||
format='[%(name)s] %(levelname)s: %(message)s',
|
||||
level=logging.INFO
|
||||
)
|
||||
level=logging.INFO,
|
||||
filename=file_name,
|
||||
filemode="w"
|
||||
)
|
||||
logger = logging.getLogger("Rare")
|
||||
|
||||
|
||||
|
@ -40,6 +49,7 @@ class App(QApplication):
|
|||
self.core.lgd.save_config()
|
||||
|
||||
# set Application name for settings
|
||||
self.mainwindow = None
|
||||
self.setApplicationName("Rare")
|
||||
self.setOrganizationName("Rare")
|
||||
settings = QSettings()
|
||||
|
@ -58,6 +68,8 @@ class App(QApplication):
|
|||
self.setStyleSheet(open(style_path + "RareStyle.qss").read())
|
||||
self.setWindowIcon(QIcon(style_path + "Logo.png"))
|
||||
|
||||
# tray icon
|
||||
|
||||
# launch app
|
||||
self.launch_dialog = LaunchDialog(self.core)
|
||||
self.launch_dialog.start_app.connect(self.start_app)
|
||||
|
@ -65,10 +77,27 @@ class App(QApplication):
|
|||
|
||||
def start_app(self):
|
||||
self.mainwindow = MainWindow(self.core)
|
||||
# close launch dialog after app widgets were created
|
||||
self.tray_icon = TrayIcon(self)
|
||||
self.tray_icon.exit_action.triggered.connect(lambda: exit(0))
|
||||
self.tray_icon.start_rare.triggered.connect(self.mainwindow.show)
|
||||
self.tray_icon.activated.connect(self.tray)
|
||||
self.mainwindow.tab_widget.downloadTab.finished.connect(lambda: self.tray_icon.showMessage(
|
||||
self.tr("Download finished"), self.tr("Download finished. Game is playable now"),
|
||||
QSystemTrayIcon.Information, 4000))
|
||||
self.launch_dialog.close()
|
||||
|
||||
def tray(self, reason):
|
||||
if reason == QSystemTrayIcon.DoubleClick:
|
||||
self.mainwindow.show()
|
||||
logger.info("Show App")
|
||||
|
||||
|
||||
def start():
|
||||
app = App()
|
||||
app.exec_()
|
||||
while True:
|
||||
app = App()
|
||||
exit_code = app.exec_()
|
||||
# if not restart
|
||||
if exit_code != -133742:
|
||||
break
|
||||
# restart app
|
||||
del app
|
||||
|
|
|
@ -30,8 +30,23 @@ QTabBar::tab:hover#main_tab_bar {
|
|||
|
||||
}
|
||||
|
||||
QGroupBox{
|
||||
padding: 4px;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
QGroupBox#game_widget_icon{
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
QGroupBox#group{
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
border: 1px solid white;
|
||||
margin-top: 10px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
QTabBar::tab:disabled {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
|
||||
__version__ = "0.9.8.3"
|
||||
__version__ = "0.9.9"
|
||||
style_path = os.path.join(os.path.dirname(__file__), "Styles/")
|
||||
lang_path = os.path.join(os.path.dirname(__file__), "languages/")
|
||||
|
|
|
@ -14,20 +14,3 @@ def main():
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
"""
|
||||
tray = QSystemTrayIcon()
|
||||
tray.setIcon(icon("fa.gamepad", color="white"))
|
||||
tray.setVisible(True)
|
||||
menu = QMenu()
|
||||
option1 = QAction("Geeks for Geeks")
|
||||
option1.triggered.connect(lambda: app.exec_())
|
||||
option2 = QAction("GFG")
|
||||
menu.addAction(option1)
|
||||
menu.addAction(option2)
|
||||
# To quit the app
|
||||
quit = QAction("Quit")
|
||||
quit.triggered.connect(app.quit)
|
||||
menu.addAction(quit)
|
||||
# Adding options to the System Tray
|
||||
tray.setContextMenu(menu)"""
|
||||
|
|
Binary file not shown.
|
@ -4,12 +4,12 @@
|
|||
<context>
|
||||
<name>About</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="17"/>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="29"/>
|
||||
<source>Developer:</source>
|
||||
<translation>Entwickler:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="22"/>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="34"/>
|
||||
<source>Legendary developer:</source>
|
||||
<translation>Legendary Entwickler:</translation>
|
||||
</message>
|
||||
|
@ -19,15 +19,38 @@
|
|||
<translation type="obsolete">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</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="28"/>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="40"/>
|
||||
<source>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></source>
|
||||
<translation>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</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="23"/>
|
||||
<source>Update available: {} -> {}</source>
|
||||
<translation>Update verfügbar: {} -> {}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="25"/>
|
||||
<source>Download latest release</source>
|
||||
<translation>Neueste Version herunterladen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>App</name>
|
||||
<message>
|
||||
<location filename="../Main.py" line="84"/>
|
||||
<source>Download finished</source>
|
||||
<translation>Download abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Main.py" line="84"/>
|
||||
<source>Download finished. Game is playable now</source>
|
||||
<translation>Downlaod abgeschlossen. Spiel kann jetzt gespielt werden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BaseInstalledWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/BaseInstalledWidget.py" line="34"/>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/BaseInstalledWidget.py" line="36"/>
|
||||
<source>Do you want to launch {}</source>
|
||||
<translation>Möchtest du {} starten</translation>
|
||||
</message>
|
||||
|
@ -55,68 +78,129 @@
|
|||
<translation>Laden...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DlQueueWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DlQueueWidget.py" line="63"/>
|
||||
<source>Download Queue</source>
|
||||
<translation>Eingereihte Downloads</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DlQueueWidget.py" line="79"/>
|
||||
<source>No downloads in queue</source>
|
||||
<translation>Keine eingereihten Downloads</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DlWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DlQueueWidget.py" line="44"/>
|
||||
<source>Download size: {} GB</source>
|
||||
<translation>Download Größe: {} GB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DlQueueWidget.py" line="45"/>
|
||||
<source>Install size: {} GB</source>
|
||||
<translation>Installierte Größe: {} GB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DlQueueWidget.py" line="48"/>
|
||||
<source>Remove Download</source>
|
||||
<translation>Download löschen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DownloadTab</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="133"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="32"/>
|
||||
<source>No active Download</source>
|
||||
<translation>Kein aktiver Download</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="154"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="53"/>
|
||||
<source>Stop Download</source>
|
||||
<translation>Download anhalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="170"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="69"/>
|
||||
<source>No updates available</source>
|
||||
<translation>Keine Updates verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="217"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="122"/>
|
||||
<source>Error preparing download</source>
|
||||
<translation>Fehler beim Vorbereiten des Downloads</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="222"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="127"/>
|
||||
<source>Download size is 0. Game already exists</source>
|
||||
<translation>Die Größe des Downloads ist 0. Spiel existiert bereits</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="287"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="201"/>
|
||||
<source>Installation finished</source>
|
||||
<translation>Installation abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="311"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="240"/>
|
||||
<source>Installing Game: No active download</source>
|
||||
<translation>Installierendes Spiel: Kein aktiver Download</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="319"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="248"/>
|
||||
<source>Download speed</source>
|
||||
<translation>Geschwindigkeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="320"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="249"/>
|
||||
<source>Cache used</source>
|
||||
<translation>Benutzter Cache</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="321"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="250"/>
|
||||
<source>Downloaded</source>
|
||||
<translation>Runtergeladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="322"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="251"/>
|
||||
<source>Time left: </source>
|
||||
<translation>Zeit übrig: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="288"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="202"/>
|
||||
<source>Finished Download of game {}</source>
|
||||
<translation>Downlaod von {} abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="193"/>
|
||||
<source>Download finished. Reload library</source>
|
||||
<translation>Download abgeschlossen. Spiele neu laden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="332"/>
|
||||
<source>Download queue: Empty</source>
|
||||
<translation type="obsolete">Anschließende Downloads: Keine</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="238"/>
|
||||
<source>Download queue: </source>
|
||||
<translation type="obsolete">Anschließende Downloads: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="238"/>
|
||||
<source>Empty</source>
|
||||
<translation type="obsolete">Keine</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="149"/>
|
||||
<source>Installing Game: </source>
|
||||
<translation>Installierendes Spiel: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="64"/>
|
||||
<source>Updates</source>
|
||||
<translation>Updates</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DxvkWidget</name>
|
||||
|
@ -159,32 +243,32 @@
|
|||
<context>
|
||||
<name>GameActions</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="182"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="189"/>
|
||||
<source>Uninstall game</source>
|
||||
<translation>Spiel deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="184"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="191"/>
|
||||
<source>Uninstall</source>
|
||||
<translation>Deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="190"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="197"/>
|
||||
<source>Verify Game</source>
|
||||
<translation>Spieldateien überprüfen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="195"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="202"/>
|
||||
<source>Verify</source>
|
||||
<translation>Überprüfen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="204"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="211"/>
|
||||
<source>Repair Game</source>
|
||||
<translation>Spiel reparieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="206"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="213"/>
|
||||
<source>Repair</source>
|
||||
<translation>Reparieren</translation>
|
||||
</message>
|
||||
|
@ -192,50 +276,50 @@
|
|||
<context>
|
||||
<name>GameInfo</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="106"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="113"/>
|
||||
<source>Repair file does not exist or game does not need a repair. Please verify game first</source>
|
||||
<translation>Reparationsdatei existiert nicht oder das Spiel braucht keine Reperatur. Bitte das spiel zuerst überprüfen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="131"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="138"/>
|
||||
<source>Verification failed, {} file(s) corrupted, {} file(s) are missing. Do you want to repair them?</source>
|
||||
<translation>Überprüfung fehlgeschlagen, {} Datei(en) fehlerhaft, {} Datei(en) fehlen. Willst du das Spiel reparieren?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="160"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="167"/>
|
||||
<source>Developer: </source>
|
||||
<translation>Entwickler: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="161"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="168"/>
|
||||
<source>Install size: </source>
|
||||
<translation>Größe: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="163"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="170"/>
|
||||
<source>Install path: </source>
|
||||
<translation>Installationsordner: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="98"/>
|
||||
<source>Are you sure to uninstall {}</source>
|
||||
<translation>Möchtest du {} wirklich deinstallieren</translation>
|
||||
<translation type="obsolete">Möchtest du {} wirklich deinstallieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameList</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="148"/>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="160"/>
|
||||
<source>Launch</source>
|
||||
<translation>Starten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="153"/>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="165"/>
|
||||
<source>Game running</source>
|
||||
<translation>Spiel läuft</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="45"/>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="46"/>
|
||||
<source>Installed Games: {} Available Games: {}</source>
|
||||
<translation>Installierte Spiele: {} Verfügbare Spiele: {}</translation>
|
||||
</message>
|
||||
|
@ -243,17 +327,17 @@
|
|||
<context>
|
||||
<name>GameListHeadBar</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GamesTab.py" line="74"/>
|
||||
<location filename="../Components/Tabs/Games/__init__.py" line="74"/>
|
||||
<source>Installed only</source>
|
||||
<translation>Nur Installierte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GamesTab.py" line="81"/>
|
||||
<location filename="../Components/Tabs/Games/__init__.py" line="81"/>
|
||||
<source>Import Game</source>
|
||||
<translation>Spiel importieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GamesTab.py" line="93"/>
|
||||
<location filename="../Components/Tabs/Games/__init__.py" line="93"/>
|
||||
<source>Search Game</source>
|
||||
<translation>Spiel suchen</translation>
|
||||
</message>
|
||||
|
@ -322,15 +406,20 @@
|
|||
<context>
|
||||
<name>IconWidgetUninstalled</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/UninstalledIconWidget.py" line="43"/>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/UninstalledIconWidget.py" line="45"/>
|
||||
<source>Install Game</source>
|
||||
<translation>Spiel installieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/UninstalledIconWidget.py" line="47"/>
|
||||
<source>Installation running</source>
|
||||
<translation>Installation läuft</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImportWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="99"/>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="102"/>
|
||||
<source>Import</source>
|
||||
<translation>Importieren</translation>
|
||||
</message>
|
||||
|
@ -355,27 +444,27 @@
|
|||
<translation>Laden...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="98"/>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="101"/>
|
||||
<source>Error: No valid session found</source>
|
||||
<translation>Keine valide Session gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="26"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="27"/>
|
||||
<source>Back</source>
|
||||
<translation>Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="40"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="43"/>
|
||||
<source>Select path to game</source>
|
||||
<translation>Wähle den Pfad zum Spiel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="62"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="65"/>
|
||||
<source>Import Game</source>
|
||||
<translation>Spiel importieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="70"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="77"/>
|
||||
<source>Import all games from Epic Games Launcher</source>
|
||||
<translation>Alle Spiele aus dem Epic Games Launcher importieren</translation>
|
||||
</message>
|
||||
|
@ -385,45 +474,55 @@
|
|||
<translation type="obsolete">{} Spiele erfolgreich importiert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="43"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="46"/>
|
||||
<source>Override app name (Only if imported game from legendary or the app could not find the app name)</source>
|
||||
<translation>App Name überschreiben (Nur falls das Spiel von Legendary importiert wird oder der App Name nicht gefunden wird</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="110"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="118"/>
|
||||
<source>Could not find app name</source>
|
||||
<translation>Konnte den Appnamen nicht finden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="114"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="122"/>
|
||||
<source>Successfully imported {}. Reload library</source>
|
||||
<translation>Erfolgreich {} importiert. Spiele neu laden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="120"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="128"/>
|
||||
<source>Failed to import {}</source>
|
||||
<translation>{} Konnte nicht importiert werden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="159"/>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="167"/>
|
||||
<source>Successfully imported {} Games. Reloading Library</source>
|
||||
<translation>Erfolgreich {} Spiele importiert. Spiele neu laden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="39"/>
|
||||
<source>Import existing game from Epic Games Launcher</source>
|
||||
<translation>Ein bereits existierendes Spiel aus dem Epic Games Launcher importieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="170"/>
|
||||
<source>No Games were found</source>
|
||||
<translation>Keine Spiele wurden gefunden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InfoTabs</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="26"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="27"/>
|
||||
<source>Back</source>
|
||||
<translation>Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="30"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="31"/>
|
||||
<source>Game Info</source>
|
||||
<translation>Spielinfo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="32"/>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="33"/>
|
||||
<source>Settings</source>
|
||||
<translation>Einstellungen</translation>
|
||||
</message>
|
||||
|
@ -431,27 +530,42 @@
|
|||
<context>
|
||||
<name>InstallDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="22"/>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="29"/>
|
||||
<source>Max workers (0: Default)</source>
|
||||
<translation>Maximale Anzahl Downloadprozessen(Standard: 0)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="20"/>
|
||||
<source><h3>Install {}</h3></source>
|
||||
<translation><h3>Installiere {}</h3></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="33"/>
|
||||
<source>Force download</source>
|
||||
<translation>Download erzwingen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="37"/>
|
||||
<source>Ignore free space (Warning!)</source>
|
||||
<translation>Freien Speicherplatz ignorieren (Achtung!)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InstallInfoDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="55"/>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="70"/>
|
||||
<source>Download size: {}GB
|
||||
Install size: {}GB</source>
|
||||
<translation>Downloadgröße: {}GB
|
||||
Installationsgröße: {} GB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="61"/>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="76"/>
|
||||
<source>Install</source>
|
||||
<translation>Installieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="63"/>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="78"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Abbruch</translation>
|
||||
</message>
|
||||
|
@ -503,17 +617,17 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>LegendarySettings</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="18"/>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="16"/>
|
||||
<source>Legendary settings</source>
|
||||
<translation>Legendary Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="27"/>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="28"/>
|
||||
<source>Default installation directory</source>
|
||||
<translation>Standardordner für Installationen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="36"/>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="37"/>
|
||||
<source>Max workers for Download (Less: slower download)(0: Default)</source>
|
||||
<translation>Maximale Anzahl Downloadprozesse (Weniger: langsamer)(Standard: 0)</translation>
|
||||
</message>
|
||||
|
@ -582,6 +696,14 @@ Installationsgröße: {} GB</translation>
|
|||
<translation>Dies öffnet den Browser, Einloggen und den Text kopieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../Components/MainWindow.py" line="21"/>
|
||||
<source>There is a download active. Do you really want to exit app?</source>
|
||||
<translation>Ein Download läuft noch. Möchtest du die App wirklich beenden?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MiniWidget</name>
|
||||
<message>
|
||||
|
@ -595,12 +717,12 @@ Installationsgröße: {} GB</translation>
|
|||
<translation>Accounteinstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="26"/>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="27"/>
|
||||
<source>Logout</source>
|
||||
<translation>Ausloggen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="32"/>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="33"/>
|
||||
<source>Do you really want to logout</source>
|
||||
<translation>Willst du dich wirklich abmelden</translation>
|
||||
</message>
|
||||
|
@ -629,65 +751,75 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>RareSettings</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="19"/>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="18"/>
|
||||
<source>Rare settings</source>
|
||||
<translation>Rare Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="33"/>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="28"/>
|
||||
<source>Save</source>
|
||||
<translation>Speichern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="35"/>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="30"/>
|
||||
<source>Image Directory</source>
|
||||
<translation>Ordner für Bilder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="49"/>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="44"/>
|
||||
<source>Language</source>
|
||||
<translation>Sprache</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="77"/>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="82"/>
|
||||
<source>Restart Application to activate changes</source>
|
||||
<translation>Starte die App neu um die Änderungen zu aktivieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="55"/>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="56"/>
|
||||
<source>Confirm launch of game</source>
|
||||
<translation>Start des Spiels bestätigen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="51"/>
|
||||
<source>Exit to System Tray Icon</source>
|
||||
<translation>Beim verlassen auf das System Tray Icon minimieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="48"/>
|
||||
<source>Hide to System Tray Icon</source>
|
||||
<translation>In das System Tray Icon minimieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SyncSaves</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="65"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/__init__.py" line="62"/>
|
||||
<source>Cloud Saves</source>
|
||||
<translation>Cloud Speicherstände</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="54"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/__init__.py" line="52"/>
|
||||
<source>Found Saves for folowing Games</source>
|
||||
<translation>Spielstände für folgende Spiele gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="65"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/__init__.py" line="62"/>
|
||||
<source>Your games does not support Cloud Saves</source>
|
||||
<translation>Deine Spiele unterstützen keine Online Speicherstände</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="70"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/__init__.py" line="67"/>
|
||||
<source>Sync all games</source>
|
||||
<translation>Alle Spiele synchronisieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="110"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/__init__.py" line="108"/>
|
||||
<source>Found no savepath</source>
|
||||
<translation>Kein Speicherort gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="110"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/__init__.py" line="108"/>
|
||||
<source>No save path was found. Please select path or skip</source>
|
||||
<translation>Kein Speicherort wurde gefunden. Wähle einen Ordner oder überspringe</translation>
|
||||
</message>
|
||||
|
@ -695,97 +827,97 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>SyncWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="60"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="62"/>
|
||||
<source>Path not found</source>
|
||||
<translation>Ordner nicht gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="76"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="78"/>
|
||||
<source>Local Save date: </source>
|
||||
<translation>Lokales Speicherdatum: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="79"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="81"/>
|
||||
<source>No Local Save files</source>
|
||||
<translation>Keine Lokalen Dateien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="81"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="83"/>
|
||||
<source>Cloud save date: </source>
|
||||
<translation>Online Speicherdatum: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="83"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="85"/>
|
||||
<source>No Cloud saves</source>
|
||||
<translation>Keine Online Speicherstände</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="87"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="89"/>
|
||||
<source>Game is up to date</source>
|
||||
<translation>Spiel ist aktuell</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="88"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="90"/>
|
||||
<source>Upload anyway</source>
|
||||
<translation>Trotzdem hochladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="89"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="91"/>
|
||||
<source>Download anyway</source>
|
||||
<translation>Trotzdem herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="91"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="93"/>
|
||||
<source>Cloud save is newer</source>
|
||||
<translation>Online Speicherstand ist aktueller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="92"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="94"/>
|
||||
<source>Download Cloud saves</source>
|
||||
<translation>Online Speicherstand herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="96"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="98"/>
|
||||
<source>Upload Saves</source>
|
||||
<translation>Spielstände hochladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="107"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="109"/>
|
||||
<source>Local save is newer</source>
|
||||
<translation>Lokaler Speicher ist aktueller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="108"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="110"/>
|
||||
<source>Upload saves</source>
|
||||
<translation>Spielstände hochladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="112"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="114"/>
|
||||
<source>Download saves</source>
|
||||
<translation>Spielstand herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="134"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="137"/>
|
||||
<source>Change path</source>
|
||||
<translation>Pfad ändern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="159"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="162"/>
|
||||
<source>Uploading...</source>
|
||||
<translation>Hochladen...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="167"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="170"/>
|
||||
<source>Upload finished</source>
|
||||
<translation>Hochladen abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="177"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="180"/>
|
||||
<source>Downloading...</source>
|
||||
<translation>Runterladen...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="183"/>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="186"/>
|
||||
<source>Download finished</source>
|
||||
<translation>Download abgeschlossen</translation>
|
||||
</message>
|
||||
|
@ -798,10 +930,46 @@ Installationsgröße: {} GB</translation>
|
|||
<translation>Spiele</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TrayIcon</name>
|
||||
<message>
|
||||
<location filename="../Components/TrayIcon.py" line="18"/>
|
||||
<source>Exit</source>
|
||||
<translation>Schließen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UninstallDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/UninstallDialog.py" line="13"/>
|
||||
<source>Do you really want to uninstall {}</source>
|
||||
<translation>Möchtest du wirklich {} deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/UninstallDialog.py" line="15"/>
|
||||
<source>Keep Files</source>
|
||||
<translation>Dateien behalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/UninstallDialog.py" line="18"/>
|
||||
<source>Do you want to keep files?</source>
|
||||
<translation>Willst du die Dateien behalten?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/UninstallDialog.py" line="22"/>
|
||||
<source>Uninstall</source>
|
||||
<translation>Deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/UninstallDialog.py" line="25"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Abbruch</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UpdateWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="349"/>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="277"/>
|
||||
<source>Update Game</source>
|
||||
<translation>Spiel updaten</translation>
|
||||
</message>
|
||||
|
|
BIN
Rare/languages/fr.qm
Normal file
BIN
Rare/languages/fr.qm
Normal file
Binary file not shown.
818
Rare/languages/fr.ts
Normal file
818
Rare/languages/fr.ts
Normal file
|
@ -0,0 +1,818 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS><TS version="2.0">
|
||||
<context>
|
||||
<name>About</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="17"/>
|
||||
<source>Developer:</source>
|
||||
<translation>Développeur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="22"/>
|
||||
<source>Legendary developer:</source>
|
||||
<translation>Legendary Développeur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/About.py" line="28"/>
|
||||
<source>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></source>
|
||||
<translation>Il s'agit d'une version bêta, vous pouvez donc rencontrer des bogues. Si vous rencontrez un bug, veuillez le signaler en créant un Issue sur <a href='https://github.com/Dummerle/Rare/issues'>Github</a>. Vous pouvez également me contacter sur Discord (Dummerle#7419). Ou vous pouvez rejoindre le <a href='https://discord.gg/YvmABK9YSk'>serveur Discord</a></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BaseInstalledWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/BaseInstalledWidget.py" line="34"/>
|
||||
<source>Do you want to launch {}</source>
|
||||
<translation>Voulez-vous lancer {}</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BrowserLogin</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/BrowserLogin.py" line="24"/>
|
||||
<source>Opens a browser. You login and copy the json code in the field below. Click <a href='{}'>here</a> to open Browser</source>
|
||||
<translation>Ouvre un navigateur. Vous vous connectez et copiez le code json dans le champ ci-dessous. Cliquez <a href='{}'>here</a> pour ouvrir un navigateur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/BrowserLogin.py" line="32"/>
|
||||
<source>Insert SID here</source>
|
||||
<translation>Insérer le SID ici</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/BrowserLogin.py" line="37"/>
|
||||
<source>Login</source>
|
||||
<translation>Login</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/BrowserLogin.py" line="44"/>
|
||||
<source>Loading...</source>
|
||||
<translation>charge...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DownloadTab</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="133"/>
|
||||
<source>No active Download</source>
|
||||
<translation>Aucun téléchargement actif</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="154"/>
|
||||
<source>Stop Download</source>
|
||||
<translation>Stop Télécharger</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="170"/>
|
||||
<source>No updates available</source>
|
||||
<translation>Aucune mise à jour disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="217"/>
|
||||
<source>Error preparing download</source>
|
||||
<translation>Erreur lors de la préparation du téléchargement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="222"/>
|
||||
<source>Download size is 0. Game already exists</source>
|
||||
<translation>La taille du téléchargement est de 0. Le jeu existe déjà</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="229"/>
|
||||
<source>Installing game: </source>
|
||||
<translation>Installation du jeu: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="288"/>
|
||||
<source>Installation finished</source>
|
||||
<translation>Installation terminée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="289"/>
|
||||
<source>Finished Download of game {}</source>
|
||||
<translation>Fin du téléchargement du jeu {}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="312"/>
|
||||
<source>Installing Game: No active download</source>
|
||||
<translation>Installation du jeu: Aucun téléchargement actif</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="320"/>
|
||||
<source>Download speed</source>
|
||||
<translation>Vitesse de téléchargement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="321"/>
|
||||
<source>Cache used</source>
|
||||
<translation>Cache utilisé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="322"/>
|
||||
<source>Downloaded</source>
|
||||
<translation>Téléchargé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="323"/>
|
||||
<source>Time left: </source>
|
||||
<translation>Il reste du temps: </translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DxvkWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="18"/>
|
||||
<source>GPU usage</source>
|
||||
<translation>GPU Utilisation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="19"/>
|
||||
<source>Used Memory</source>
|
||||
<translation>utilisé Memory</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="20"/>
|
||||
<source>Device info</source>
|
||||
<translation>Info sur le dispositif</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="21"/>
|
||||
<source>DXVK version</source>
|
||||
<translation>DXVK version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="22"/>
|
||||
<source>D3D Level of application</source>
|
||||
<translation>D3D Niveau d'application</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="23"/>
|
||||
<source>Frame time graph</source>
|
||||
<translation>Graphique de temps de trame</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Dxvk.py" line="28"/>
|
||||
<source>dxvk settings</source>
|
||||
<translation>dxvk paramètres</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameActions</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="182"/>
|
||||
<source>Uninstall game</source>
|
||||
<translation>Désinstaller le jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="184"/>
|
||||
<source>Uninstall</source>
|
||||
<translation>Désinstaller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="190"/>
|
||||
<source>Verify Game</source>
|
||||
<translation>Vérifier le jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="195"/>
|
||||
<source>Verify</source>
|
||||
<translation>Vérifier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="204"/>
|
||||
<source>Repair Game</source>
|
||||
<translation>Jeu de réparation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="206"/>
|
||||
<source>Repair</source>
|
||||
<translation>Réparation</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameInfo</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="98"/>
|
||||
<source>Are you sure to uninstall {}</source>
|
||||
<translation>Etes-vous sûr de désinstaller {}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="106"/>
|
||||
<source>Repair file does not exist or game does not need a repair. Please verify game first</source>
|
||||
<translation>Le fichier de réparation n'existe pas ou le jeu ne nécessite pas de réparation. Veuillez d'abord vérifier le jeu.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="131"/>
|
||||
<source>Verification failed, {} file(s) corrupted, {} file(s) are missing. Do you want to repair them?</source>
|
||||
<translation>La vérification a échoué, {} fichier(s) corrompu(s), {} fichier(s) manquant(s). Voulez-vous les réparer ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="160"/>
|
||||
<source>Developer: </source>
|
||||
<translation>Développeur: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="161"/>
|
||||
<source>Install size: </source>
|
||||
<translation>Taille d'installation: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="163"/>
|
||||
<source>Install path: </source>
|
||||
<translation>Chemin d'installation:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameList</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="45"/>
|
||||
<source>Installed Games: {} Available Games: {}</source>
|
||||
<translation>Jeux installés: {} Jeux disponibles: {}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="150"/>
|
||||
<source>Launch</source>
|
||||
<translation>Lancer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameList.py" line="155"/>
|
||||
<source>Game running</source>
|
||||
<translation>Jeu en cours</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameListHeadBar</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GamesTab.py" line="74"/>
|
||||
<source>Installed only</source>
|
||||
<translation>Installé uniquement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GamesTab.py" line="81"/>
|
||||
<source>Import Game</source>
|
||||
<translation>Jeu d'importation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GamesTab.py" line="93"/>
|
||||
<source>Search Game</source>
|
||||
<translation>Rechercher un jeu</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameSettings</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="27"/>
|
||||
<source>Launch Game offline</source>
|
||||
<translation>Lancer le jeu hors ligne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="32"/>
|
||||
<source>Skip update check before launching</source>
|
||||
<translation>Sauter la vérification de la mise à jour avant le lancement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="65"/>
|
||||
<source>Save</source>
|
||||
<translation>Sauvez</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="41"/>
|
||||
<source>Wrapper (e.g. optirun)</source>
|
||||
<translation>Wrapper (p.e. optirun)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="61"/>
|
||||
<source>Proton Wrapper</source>
|
||||
<translation>Enveloppeur de Proton</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="67"/>
|
||||
<source>Proton prefix</source>
|
||||
<translation>Préfixe du proton</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="173"/>
|
||||
<source>No permission to create folder</source>
|
||||
<translation>Pas de permission pour créer un dossier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameSettings.py" line="218"/>
|
||||
<source>Please select path for proton prefix</source>
|
||||
<translation>Veuillez sélectionner le chemin pour le préfixe proton</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameWidgetInstalled</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/InstalledIconWidget.py" line="36"/>
|
||||
<source>Update available</source>
|
||||
<translation>Mise à jour disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/InstalledIconWidget.py" line="86"/>
|
||||
<source>Start game without version check</source>
|
||||
<translation>Démarrer le jeu sans vérifier la version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/InstalledIconWidget.py" line="94"/>
|
||||
<source>Game running</source>
|
||||
<translation>Jeu en cours</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>IconWidgetUninstalled</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/UninstalledIconWidget.py" line="43"/>
|
||||
<source>Install Game</source>
|
||||
<translation>Installer le jeu</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImportWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="99"/>
|
||||
<source>Import</source>
|
||||
<translation>Importer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="39"/>
|
||||
<source>Could not find EGL program data</source>
|
||||
<translation>Impossible de trouver les données du programme EGL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="42"/>
|
||||
<source>Found EGL program Data. Do you want to import them?</source>
|
||||
<translation>Les données du programme EGL ont été trouvées. Voulez-vous les importer ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="51"/>
|
||||
<source>Could not find any Epic Games login data</source>
|
||||
<translation>Impossible de trouver les données de connexion d'Epic Games</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="86"/>
|
||||
<source>Loading...</source>
|
||||
<translation>Chargement...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/ImportWidget.py" line="98"/>
|
||||
<source>Error: No valid session found</source>
|
||||
<translation>Erreur : Aucune session valide n'a été trouvée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="26"/>
|
||||
<source>Back</source>
|
||||
<translation>Dos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="40"/>
|
||||
<source>Select path to game</source>
|
||||
<translation>Sélectionnez le chemin vers le jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="43"/>
|
||||
<source>Override app name (Only if imported game from legendary or the app could not find the app name)</source>
|
||||
<translation>Remplacer le nom de l'application (uniquement si le jeu a été importé depuis le légendaire ou si l'application n'a pas pu trouver le nom de l'application)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="62"/>
|
||||
<source>Import Game</source>
|
||||
<translation>Import jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="70"/>
|
||||
<source>Import all games from Epic Games Launcher</source>
|
||||
<translation>Importer tous les jeux du Epic Games Launcher</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="110"/>
|
||||
<source>Could not find app name</source>
|
||||
<translation>Impossible de trouver le nom de l'application</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="114"/>
|
||||
<source>Successfully imported {}. Reload library</source>
|
||||
<translation>Importation réussie de {}. Recharger la bibliothèque</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="120"/>
|
||||
<source>Failed to import {}</source>
|
||||
<translation>Impossible d'importer {}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/ImportWidget.py" line="159"/>
|
||||
<source>Successfully imported {} Games. Reloading Library</source>
|
||||
<translation>Importation réussie de {} Jeux. Bibliothèque de rechargement</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InfoTabs</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="26"/>
|
||||
<source>Back</source>
|
||||
<translation>Dos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="30"/>
|
||||
<source>Game Info</source>
|
||||
<translation>Info de jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameInfo/GameInfo.py" line="32"/>
|
||||
<source>Settings</source>
|
||||
<translation>Paramètres</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InstallDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="20"/>
|
||||
<source><h3>Install {}</h3></source>
|
||||
<translation><h3>Installer {}</h3></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="29"/>
|
||||
<source>Max workers (0: Default)</source>
|
||||
<translation>Travailleurs maximum (0: Par défaut)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="33"/>
|
||||
<source>Force download</source>
|
||||
<translation>Téléchargement forcé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="37"/>
|
||||
<source>Ignore free space (Warning!)</source>
|
||||
<translation>Ignorer l'espace libre (Attention!)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InstallInfoDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="70"/>
|
||||
<source>Download size: {}GB
|
||||
Install size: {}GB</source>
|
||||
<translation>Taille du téléchargement: {}GB
|
||||
Taille de l'installation: {}GB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="76"/>
|
||||
<source>Install</source>
|
||||
<translation>Installer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/InstallDialog.py" line="78"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Annuler</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InstalledListWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/InstalledListWidget.py" line="41"/>
|
||||
<source>Launch</source>
|
||||
<translation>Lancer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/InstalledListWidget.py" line="52"/>
|
||||
<source>Developer: </source>
|
||||
<translation>Développeur: </translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LaunchDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Launch/LaunchDialog.py" line="60"/>
|
||||
<source>Launching Rare</source>
|
||||
<translation>Lancer Rare</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Launch/LaunchDialog.py" line="62"/>
|
||||
<source>Logging in</source>
|
||||
<translation>Se connecter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Launch/LaunchDialog.py" line="80"/>
|
||||
<source>Downloading Images</source>
|
||||
<translation>Téléchargement d'images</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Launch/LaunchDialog.py" line="91"/>
|
||||
<source>Starting...</source>
|
||||
<translation>Démarrage...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LaunchThread</name>
|
||||
<message>
|
||||
<location filename="../Components/Launch/LaunchDialog.py" line="23"/>
|
||||
<source>Downloading Images</source>
|
||||
<translation>Téléchargement d'images</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LegendarySettings</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="18"/>
|
||||
<source>Legendary settings</source>
|
||||
<translation>Legendary paramètres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="27"/>
|
||||
<source>Default installation directory</source>
|
||||
<translation>Répertoire d'installation par défaut</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="36"/>
|
||||
<source>Max workers for Download (Less: slower download)(0: Default)</source>
|
||||
<translation>Nombre maximum de travailleurs pour le téléchargement (Moins: téléchargement plus lent)(0: Défaut)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="43"/>
|
||||
<source>Cleanup</source>
|
||||
<translation>Nettoyage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="44"/>
|
||||
<source>Remove everything</source>
|
||||
<translation>Enlever tout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="48"/>
|
||||
<source>Clean, but keep manifests</source>
|
||||
<translation>Nettoyer, mais garder les manifestes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Legendary.py" line="96"/>
|
||||
<source>Cleanup complete! Successfully removed {} MB</source>
|
||||
<translation>Nettoyage terminé ! J'ai réussi à supprimer {} MB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LinuxSettings</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Linux.py" line="19"/>
|
||||
<source>Linux settings</source>
|
||||
<translation>Linux paramètres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Linux.py" line="28"/>
|
||||
<source>Default Wine Prefix</source>
|
||||
<translation>Défaut Wine Prefix</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Linux.py" line="36"/>
|
||||
<source>Default Wine executable</source>
|
||||
<translation>Défaut Wine exécutable</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ListWidgetUninstalled</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Games/GameWidgets/UninstalledListWidget.py" line="29"/>
|
||||
<source>Install</source>
|
||||
<translation>Installer</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LoginDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/LoginDialog.py" line="30"/>
|
||||
<source>Select one option to Login</source>
|
||||
<translation>Sélectionnez une option pour vous connecter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/LoginDialog.py" line="33"/>
|
||||
<source>Use Browser</source>
|
||||
<translation>Utiliser le navigateur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/Login/LoginDialog.py" line="33"/>
|
||||
<source>This opens your default browser. Login and copy the text</source>
|
||||
<translation>Cela ouvre votre navigateur par défaut. Connectez-vous et copiez le texte</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MiniWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="20"/>
|
||||
<source>Logged in as </source>
|
||||
<translation>Connecté en tant que </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="22"/>
|
||||
<source>Account settings</source>
|
||||
<translation>paramètres du compte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="26"/>
|
||||
<source>Logout</source>
|
||||
<translation>Déconnexion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Account/AccountWidget.py" line="32"/>
|
||||
<source>Do you really want to logout</source>
|
||||
<translation>Voulez-vous vraiment vous déconnecter?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PathEdit</name>
|
||||
<message>
|
||||
<location filename="../utils/QtExtensions.py" line="133"/>
|
||||
<source>Select Path</source>
|
||||
<translation>Sélectionner le chemin</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../utils/QtExtensions.py" line="146"/>
|
||||
<source>Choose Path</source>
|
||||
<translation>Choisir le chemin</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PathInputDialog</name>
|
||||
<message>
|
||||
<location filename="../Components/Dialogs/PathInputDialog.py" line="24"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Annuler</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RareSettings</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="19"/>
|
||||
<source>Rare settings</source>
|
||||
<translation>Rare paramètres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="33"/>
|
||||
<source>Save</source>
|
||||
<translation>Sauvez</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="35"/>
|
||||
<source>Image Directory</source>
|
||||
<translation>Répertoire d'images</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="49"/>
|
||||
<source>Language</source>
|
||||
<translation>Langue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="55"/>
|
||||
<source>Confirm launch of game</source>
|
||||
<translation>Confirmation du lancement du jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Settings/Rare.py" line="77"/>
|
||||
<source>Restart Application to activate changes</source>
|
||||
<translation>Redémarrez l'application pour activer les changements</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SyncSaves</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="65"/>
|
||||
<source>Cloud Saves</source>
|
||||
<translation>Cloud Saves</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="54"/>
|
||||
<source>Found Saves for folowing Games</source>
|
||||
<translation>Sauvegardes trouvées pour les jeux suivants</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="65"/>
|
||||
<source>Your games does not support Cloud Saves</source>
|
||||
<translation>Vos jeux ne prennent pas en charge les sauvegardes en nuage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="70"/>
|
||||
<source>Sync all games</source>
|
||||
<translation>Sync tous les jeux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="110"/>
|
||||
<source>Found no savepath</source>
|
||||
<translation>Pas de chemin de sauvegarde trouvé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/CloudSaves.py" line="110"/>
|
||||
<source>No save path was found. Please select path or skip</source>
|
||||
<translation>Aucun chemin de sauvegarde n'a été trouvé. Veuillez sélectionner le chemin ou passer</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SyncWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="60"/>
|
||||
<source>Path not found</source>
|
||||
<translation>Chemin non trouvé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="76"/>
|
||||
<source>Local Save date: </source>
|
||||
<translation>Local Save date: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="79"/>
|
||||
<source>No Local Save files</source>
|
||||
<translation>Pas de fichiers de sauvegarde locaux</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="81"/>
|
||||
<source>Cloud save date: </source>
|
||||
<translation>Cloud save date: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="83"/>
|
||||
<source>No Cloud saves</source>
|
||||
<translation>Pas Cloud saves</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="87"/>
|
||||
<source>Game is up to date</source>
|
||||
<translation>Le jeu est à jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="88"/>
|
||||
<source>Upload anyway</source>
|
||||
<translation>Télécharger quand même</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="89"/>
|
||||
<source>Download anyway</source>
|
||||
<translation>Télécharger en tout cas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="91"/>
|
||||
<source>Cloud save is newer</source>
|
||||
<translation>La sauvegarde en nuage est plus récente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="92"/>
|
||||
<source>Download Cloud saves</source>
|
||||
<translation>Télécharger Cloud saves</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="96"/>
|
||||
<source>Upload Saves</source>
|
||||
<translation>Upload Saves</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="107"/>
|
||||
<source>Local save is newer</source>
|
||||
<translation>La sauvegarde locale est plus récente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="108"/>
|
||||
<source>Upload saves</source>
|
||||
<translation>Upload Saves</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="112"/>
|
||||
<source>Download saves</source>
|
||||
<translation>Télécharger les sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="134"/>
|
||||
<source>Change path</source>
|
||||
<translation>Changement de trajectoire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="158"/>
|
||||
<source>Uploading...</source>
|
||||
<translation>Téléchargement...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="166"/>
|
||||
<source>Upload finished</source>
|
||||
<translation>Téléchargement terminé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="176"/>
|
||||
<source>Downloading...</source>
|
||||
<translation>Téléchargement...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/CloudSaves/SyncWidget.py" line="182"/>
|
||||
<source>Download finished</source>
|
||||
<translation>Téléchargement terminé</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/TabWidget.py" line="23"/>
|
||||
<source>Games</source>
|
||||
<translation>Jeus</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UpdateWidget</name>
|
||||
<message>
|
||||
<location filename="../Components/Tabs/Downloads/DownloadTab.py" line="353"/>
|
||||
<source>Update Game</source>
|
||||
<translation>Jeu de mise à jour</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -47,7 +47,9 @@ def launch_game(core, app_name: str, offline: bool = False, skip_version_check:
|
|||
return process, params
|
||||
|
||||
|
||||
def uninstall(app_name: str, core):
|
||||
def uninstall(app_name: str, core, options=None):
|
||||
if not options:
|
||||
options = {"keep_files": False}
|
||||
igame = core.get_installed_game(app_name)
|
||||
try:
|
||||
# Remove DLC first so directory is empty when game uninstall runs
|
||||
|
@ -55,12 +57,13 @@ def uninstall(app_name: str, core):
|
|||
for dlc in dlcs:
|
||||
if (idlc := core.get_installed_game(dlc.app_name)) is not None:
|
||||
logger.info(f'Uninstalling DLC "{dlc.app_name}"...')
|
||||
core.uninstall_game(idlc, delete_files=True)
|
||||
core.uninstall_game(idlc, delete_files=not options["keep_files"])
|
||||
|
||||
logger.info(f'Removing "{igame.title}" from "{igame.install_path}"...')
|
||||
core.uninstall_game(igame, delete_files=True, delete_root_directory=True)
|
||||
core.uninstall_game(igame, delete_files=not options["keep_files"], delete_root_directory=True)
|
||||
logger.info('Game has been uninstalled.')
|
||||
shutil.rmtree(igame.install_path)
|
||||
if not options["keep_files"]:
|
||||
shutil.rmtree(igame.install_path)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f'Removing game failed: {e!r}, please remove {igame.install_path} manually.')
|
||||
|
|
|
@ -4,15 +4,15 @@ import shutil
|
|||
from logging import getLogger
|
||||
|
||||
import requests
|
||||
from PIL import Image
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from PyQt5.QtCore import pyqtSignal, QLocale, QSettings
|
||||
|
||||
from Rare import lang_path
|
||||
from Rare import lang_path, __version__
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
logger = getLogger("Utils")
|
||||
s = QSettings("Rare", "Rare")
|
||||
IMAGE_DIR = s.value("img_dir", os.path.expanduser("~/.cache/rare"), type=str)
|
||||
IMAGE_DIR = s.value("img_dir", os.path.expanduser("~/.cache/rare/images"), type=str)
|
||||
logger.info("IMAGE DIRECTORY: " + IMAGE_DIR)
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@ def download_image(game, force=False):
|
|||
if not os.path.isdir(f"{IMAGE_DIR}/" + game.app_name):
|
||||
os.mkdir(f"{IMAGE_DIR}/" + game.app_name)
|
||||
|
||||
# to git picture updates
|
||||
if not os.path.isfile(f"{IMAGE_DIR}/{game.app_name}/image.json"):
|
||||
json_data = {"DieselGameBoxTall": None, "DieselGameBoxLogo": None}
|
||||
else:
|
||||
|
@ -56,7 +57,13 @@ def download_image(game, force=False):
|
|||
url = image["url"]
|
||||
with open(f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png", "wb") as f:
|
||||
f.write(requests.get(url).content)
|
||||
f.close()
|
||||
try:
|
||||
img = Image.open(f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png")
|
||||
img = img.resize((200, int(200*4/3)))
|
||||
img.save(f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png")
|
||||
except UnidentifiedImageError as e:
|
||||
logger.warning(e)
|
||||
|
||||
# scale and grey
|
||||
if not os.path.isfile(f'{IMAGE_DIR}/' + game.app_name + '/UninstalledArt.png'):
|
||||
|
||||
|
@ -67,6 +74,7 @@ def download_image(game, force=False):
|
|||
|
||||
bg = Image.open(f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxTall.png")
|
||||
uninstalledArt = bg.convert('L')
|
||||
uninstalledArt = uninstalledArt.resize((200, int(200*4/3)))
|
||||
uninstalledArt.save(f'{IMAGE_DIR}/{game.app_name}/UninstalledArt.png')
|
||||
elif os.path.isfile(f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png"):
|
||||
bg: Image.Image = Image.open(f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png")
|
||||
|
@ -91,7 +99,7 @@ def download_image(game, force=False):
|
|||
uninstalledArt = uninstalledArt.convert('L')
|
||||
uninstalledArt.save(f'{IMAGE_DIR}/' + game.app_name + '/UninstalledArt.png')
|
||||
else:
|
||||
logger.warning(f"File {IMAGE_DIR}/{game.app_name}/DieselGameBoxTall.png dowsn't exist")
|
||||
logger.warning(f"File {IMAGE_DIR}/{game.app_name}/DieselGameBoxTall.png doesn't exist")
|
||||
|
||||
|
||||
def get_lang():
|
||||
|
@ -110,3 +118,9 @@ def get_possible_langs():
|
|||
if i.endswith(".qm"):
|
||||
langs.append(i.split(".")[0])
|
||||
return langs
|
||||
|
||||
|
||||
def get_latest_version():
|
||||
resp = requests.get("https://api.github.com/repos/Dummerle/Rare/releases/latest")
|
||||
tag = json.loads(resp.content.decode("utf-8"))["tag_name"]
|
||||
return tag
|
||||
|
|
Loading…
Reference in a new issue