Merge branch 'main' into windows_desktop_shortcut
2
.github/workflows/release.yml
vendored
|
@ -90,7 +90,7 @@ jobs:
|
|||
uses: svenstaro/upload-release-action@2.2.1
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: rare.deb
|
||||
file: Rare.deb
|
||||
asset_name: Rare.deb
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
### Add translations
|
||||
|
||||
1. Execute ```pylupdate5 $(find -name "*.py") -ts Rare/languages/{your lang (two letters)}.ts``` in project directory
|
||||
1. Execute ```pylupdate5 $(find -name "*.py") -ts Rare/languages/de.ts``` in source directory. Replace *de* with your language code
|
||||
2. Modify the .ts file manually or in Qt Linguist
|
||||
3. Compile the file with ```lrelease Rare/languages/{lang}.ts```
|
||||
|
||||
If compilation fails, just push ts file. Then I will compile it
|
||||
|
||||
### Add Stylesheets
|
||||
|
||||
For this you can create a .qss file in Rare/Styles/ directory or modify the existing RareStyle.qss file. Here are some
|
||||
|
@ -16,11 +18,11 @@ examples:
|
|||
|
||||
### Add features
|
||||
|
||||
Select one Card of the project and implement it or make other changes
|
||||
Select one Card of the project and implement it, or if you want to add another feature ask me on Discord, or create an issue on GitHub
|
||||
|
||||
|
||||
## Git crash-course
|
||||
To contribute fork the repository and clone **your** repo. Then make your changes, add it to git with `git add File.xy` and upload it to GitHub with `git commit -m "message"` and `git push`.
|
||||
Some IDEs can do this automatically.
|
||||
|
||||
If you uploaded your changes, create a pull request to dev-branch
|
||||
If you uploaded your changes, create a pull request
|
||||
|
|
|
@ -21,7 +21,7 @@ Execute `pip install Rare` for all users Or `pip install Rare --user` for only o
|
|||
Download Rare.exe from the [releases page](https://github.com/Dummerle/Rare/releases) and execute it.
|
||||
|
||||
**Note:**
|
||||
Using the exe file could cause errors with Windows Defender or other Anti Virus
|
||||
Using the exe file could cause errors with Windows Defender or other Anti Virus. Sometimes it is not possible to download games and sometimes the app crashes. In this case please use pip
|
||||
|
||||
### Linux
|
||||
|
||||
|
@ -30,7 +30,6 @@ Using the exe file could cause errors with Windows Defender or other Anti Virus
|
|||
There are some AUR packages available:
|
||||
- [rare](https://aur.archlinux.org/packages/rare) - for stable releases
|
||||
- [rare-git](https://aur.archlinux.org/packages/rare-git) - for the latest features, which are not in a stable release
|
||||
- [rare-dev](https://aur.archlinux.org/packages/rare-dev) - dev branch: latest development features. This could be unstable
|
||||
|
||||
#### Debian based
|
||||
|
||||
|
@ -59,7 +58,6 @@ Install via `pip`.
|
|||
- Translations (English, German and French)
|
||||
|
||||
## Planned Features
|
||||
- Offline mode
|
||||
- More Translations (Need help)
|
||||
- More Information about Games
|
||||
More planned features are in projects
|
||||
|
@ -70,8 +68,6 @@ 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 in your language
|
||||
|
||||
**Note:** Pull Requests please to "dev" branch
|
||||
|
||||
More Information is in CONTRIBUTING.md
|
||||
|
||||
## Images
|
||||
|
@ -79,4 +75,4 @@ More Information is in CONTRIBUTING.md
|
|||
![alt text](https://github.com/Dummerle/Rare/blob/main/Screenshots/Rare.png?raw=true)
|
||||
![alt text](https://github.com/Dummerle/Rare/blob/main/Screenshots/GameInfo.png?raw=true)
|
||||
![alt text](https://github.com/Dummerle/Rare/blob/main/Screenshots/RareSettings.png?raw=true)
|
||||
|
||||
![alt text](https://github.com/Dummerle/Rare/blob/main/Screenshots/RareDownloads.png?raw=true)
|
||||
|
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 695 KiB After Width: | Height: | Size: 660 KiB |
BIN
Screenshots/RareDownloads.png
Normal file
After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 64 KiB |
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
|
||||
__version__ = "1.1.1"
|
||||
__version__ = "1.3.0"
|
||||
style_path = os.path.join(os.path.dirname(__file__), "styles/")
|
||||
lang_path = os.path.join(os.path.dirname(__file__), "languages/")
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import os
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from rare import __version__
|
||||
from rare.utils import singleton
|
||||
|
||||
|
@ -7,6 +9,7 @@ def main():
|
|||
parser = ArgumentParser()
|
||||
parser.add_argument("-V", "--version", action="store_true")
|
||||
parser.add_argument("-S", "--silent", action="store_true")
|
||||
parser.add_argument("--offline", action="store_true")
|
||||
subparsers = parser.add_subparsers(title="Commands", dest="subparser")
|
||||
|
||||
launch_parser = subparsers.add_parser("launch")
|
||||
|
@ -22,8 +25,19 @@ def main():
|
|||
me = singleton.SingleInstance()
|
||||
except singleton.SingleInstanceException:
|
||||
print("Rare is already running")
|
||||
|
||||
with open(os.path.expanduser("~/.cache/rare/lockfile"), "w") as file:
|
||||
if args.subparser == "launch":
|
||||
file.write("launch " + args.app_name)
|
||||
else:
|
||||
file.write("start")
|
||||
file.close()
|
||||
|
||||
exit(0)
|
||||
|
||||
if args.subparser == "launch":
|
||||
args.silent = True
|
||||
|
||||
from rare.app import start
|
||||
start(args)
|
||||
|
||||
|
|
34
rare/app.py
|
@ -1,6 +1,7 @@
|
|||
import configparser
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
@ -8,12 +9,12 @@ from PyQt5.QtCore import QSettings, QTranslator
|
|||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare import lang_path, style_path
|
||||
from rare.components.dialogs.launch_dialog import LaunchDialog
|
||||
from rare.components.main_window import MainWindow
|
||||
from rare.components.tray_icon 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")
|
||||
|
@ -24,16 +25,14 @@ logging.basicConfig(
|
|||
format='[%(name)s] %(levelname)s: %(message)s',
|
||||
level=logging.INFO,
|
||||
filename=file_name,
|
||||
filemode="w"
|
||||
)
|
||||
)
|
||||
logger = logging.getLogger("Rare")
|
||||
|
||||
|
||||
class App(QApplication):
|
||||
def __init__(self, args):
|
||||
super(App, self).__init__(sys.argv)
|
||||
self.args = args
|
||||
# add some options
|
||||
self.args = args # add some options
|
||||
|
||||
# init Legendary
|
||||
try:
|
||||
|
@ -62,7 +61,7 @@ class App(QApplication):
|
|||
lang = settings.value("language", get_lang(), type=str)
|
||||
if os.path.exists(lang_path + lang + ".qm"):
|
||||
self.translator.load(lang_path + lang + ".qm")
|
||||
logger.info("Your language is supported")
|
||||
logger.info("Your language is supported: " + lang)
|
||||
elif not lang == "en":
|
||||
logger.info("Your language is not supported")
|
||||
self.installTranslator(self.translator)
|
||||
|
@ -72,20 +71,27 @@ class App(QApplication):
|
|||
self.setWindowIcon(QIcon(style_path + "Logo.png"))
|
||||
|
||||
# launch app
|
||||
self.launch_dialog = LaunchDialog(self.core)
|
||||
self.launch_dialog = LaunchDialog(self.core, args.offline)
|
||||
self.launch_dialog.start_app.connect(self.start_app)
|
||||
self.launch_dialog.show()
|
||||
|
||||
def start_app(self):
|
||||
if not args.silent or args.subparser == "launch":
|
||||
self.launch_dialog.show()
|
||||
|
||||
def start_app(self, offline=False):
|
||||
self.args.offline = offline
|
||||
self.mainwindow = MainWindow(self.core, self.args)
|
||||
self.launch_dialog.close()
|
||||
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()
|
||||
if not offline:
|
||||
self.mainwindow.tab_widget.downloadTab.finished.connect(lambda update: self.tray_icon.showMessage(
|
||||
self.tr("Download finished"), self.tr("Download finished. Game is playable now"),
|
||||
QSystemTrayIcon.Information, 4000) if update else None)
|
||||
|
||||
if not self.args.silent:
|
||||
self.mainwindow.show()
|
||||
|
||||
def tray(self, reason):
|
||||
if reason == QSystemTrayIcon.DoubleClick:
|
||||
|
@ -101,4 +107,4 @@ def start(args):
|
|||
if exit_code != -133742:
|
||||
break
|
||||
# restart app
|
||||
del app
|
||||
del app
|
|
@ -3,8 +3,8 @@ import os
|
|||
from PyQt5.QtWidgets import QDialog, QFormLayout, QVBoxLayout, QSpinBox, QFileDialog, QLabel, QPushButton, QHBoxLayout, \
|
||||
QCheckBox
|
||||
|
||||
from rare.utils.extra_widgets import PathEdit
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.utils.extra_widgets import PathEdit
|
||||
|
||||
|
||||
class InstallDialog(QDialog):
|
||||
|
@ -18,14 +18,24 @@ class InstallDialog(QDialog):
|
|||
self.form = QFormLayout()
|
||||
self.update_game = update
|
||||
self.layout.addWidget(QLabel(self.tr("<h3>Install {}</h3>").format(self.game.app_title)))
|
||||
default_path = os.path.expanduser("~/legendary")
|
||||
|
||||
# TODO read from config
|
||||
if self.core.lgd.config.has_option("Legendary", "install_dir"):
|
||||
default_path = self.core.lgd.config.get("Legendary", "install_dir")
|
||||
else:
|
||||
default_path = os.path.expanduser("~/legendary")
|
||||
if not default_path:
|
||||
default_path = os.path.expanduser("~/legendary")
|
||||
if not update:
|
||||
self.install_path_field = PathEdit(text=default_path, type_of_file=QFileDialog.DirectoryOnly)
|
||||
self.form.addRow(QLabel("Install directory"), self.install_path_field)
|
||||
|
||||
if self.core.lgd.config.has_option("Legendary", "max_workers"):
|
||||
max_workers = self.core.lgd.config.get("Legendary", "max_workers")
|
||||
else:
|
||||
max_workers = 0
|
||||
|
||||
self.max_workes = QSpinBox()
|
||||
self.max_workes.setValue(int(max_workers))
|
||||
self.form.addRow(QLabel(self.tr("Max workers (0: Default)")), self.max_workes)
|
||||
|
||||
self.force = QCheckBox()
|
||||
|
@ -52,7 +62,9 @@ class InstallDialog(QDialog):
|
|||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def get_information(self):
|
||||
def get_information(self, path=None):
|
||||
if path:
|
||||
self.install_path_field.text_edit.setText(path)
|
||||
self.exec_()
|
||||
return self.infos
|
||||
|
||||
|
@ -95,4 +107,3 @@ class InstallInfoDialog(QDialog):
|
|||
def cancel(self):
|
||||
self.accept = False
|
||||
self.close()
|
||||
|
||||
|
|
|
@ -2,10 +2,11 @@ from logging import getLogger
|
|||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QDialog, QLabel, QProgressBar, QVBoxLayout
|
||||
from requests.exceptions import ConnectionError
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.components.dialogs.login import LoginDialog
|
||||
from rare.utils.utils import download_images
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
logger = getLogger("Login")
|
||||
|
||||
|
@ -27,7 +28,7 @@ class LaunchThread(QThread):
|
|||
|
||||
class LoginThread(QThread):
|
||||
login = pyqtSignal()
|
||||
start_app = pyqtSignal()
|
||||
start_app = pyqtSignal(bool) # offline
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(LoginThread, self).__init__()
|
||||
|
@ -38,24 +39,28 @@ class LoginThread(QThread):
|
|||
try:
|
||||
if self.core.login():
|
||||
logger.info("You are logged in")
|
||||
self.start_app.emit()
|
||||
self.start_app.emit(False)
|
||||
else:
|
||||
self.run()
|
||||
except ValueError:
|
||||
logger.info("You are not logged in. Open Login Window")
|
||||
self.login.emit()
|
||||
except ConnectionError as e:
|
||||
logger.warning(e)
|
||||
self.start_app.emit(True)
|
||||
|
||||
|
||||
class LaunchDialog(QDialog):
|
||||
start_app = pyqtSignal()
|
||||
start_app = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
def __init__(self, core: LegendaryCore, offline):
|
||||
super(LaunchDialog, self).__init__()
|
||||
self.core = core
|
||||
self.login_thread = LoginThread(core)
|
||||
self.login_thread.login.connect(self.login)
|
||||
self.login_thread.start_app.connect(self.launch)
|
||||
self.login_thread.start()
|
||||
if not offline:
|
||||
self.login_thread = LoginThread(core)
|
||||
self.login_thread.login.connect(self.login)
|
||||
self.login_thread.start_app.connect(self.launch)
|
||||
self.login_thread.start()
|
||||
|
||||
self.title = QLabel("<h3>" + self.tr("Launching Rare") + "</h3>")
|
||||
self.info_pb = QProgressBar()
|
||||
|
@ -68,6 +73,9 @@ class LaunchDialog(QDialog):
|
|||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
if offline:
|
||||
self.launch(offline)
|
||||
|
||||
def login(self):
|
||||
self.hide()
|
||||
if LoginDialog(core=self.core).login():
|
||||
|
@ -76,9 +84,9 @@ class LaunchDialog(QDialog):
|
|||
else:
|
||||
exit(0)
|
||||
|
||||
def launch(self):
|
||||
def launch(self, offline=False):
|
||||
# self.core = core
|
||||
self.pb_size = len(self.core.get_game_list())
|
||||
self.offline = offline
|
||||
self.info_text.setText(self.tr("Downloading Images"))
|
||||
self.thread = LaunchThread(self.core, self)
|
||||
self.thread.download_progess.connect(self.update_pb)
|
||||
|
@ -86,12 +94,12 @@ class LaunchDialog(QDialog):
|
|||
self.thread.start()
|
||||
|
||||
def update_pb(self, i: int):
|
||||
self.info_pb.setValue(i / self.pb_size * 100)
|
||||
self.info_pb.setValue(i)
|
||||
|
||||
def info(self, text: str):
|
||||
if text == "finish":
|
||||
self.info_text.setText(self.tr("Starting..."))
|
||||
self.info_pb.setValue(100)
|
||||
self.start_app.emit()
|
||||
self.start_app.emit(self.offline)
|
||||
else:
|
||||
self.info_text.setText(text)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QStackedLayout, QWidget, QPushButton
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
# Login Opportunities: Browser, Import
|
||||
from rare.components.dialogs.login.browser_login import BrowserLogin
|
||||
from rare.components.dialogs.login.import_widget import ImportWidget
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
|
||||
class LoginDialog(QDialog):
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import os
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QSettings
|
||||
from PyQt5.QtCore import QSettings, QTimer
|
||||
from PyQt5.QtGui import QCloseEvent
|
||||
from PyQt5.QtWidgets import QMainWindow, QMessageBox
|
||||
from PyQt5.QtWidgets import QMainWindow, QMessageBox, QApplication
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.components.tab_widget import TabWidget
|
||||
|
@ -17,30 +18,32 @@ class MainWindow(QMainWindow):
|
|||
super(MainWindow, self).__init__()
|
||||
self.settings = QSettings()
|
||||
self.core = core
|
||||
self.rpc = DiscordRPC(core)
|
||||
self.offline = args.offline
|
||||
width, height = 1200, 800
|
||||
if self.settings.value("save_size", False):
|
||||
width, height = self.settings.value("window_size", (1200, 800), tuple)
|
||||
|
||||
self.setGeometry(0, 0, width, height)
|
||||
self.setWindowTitle("Rare - GUI for legendary")
|
||||
self.tab_widget = TabWidget(core)
|
||||
self.setCentralWidget(self.tab_widget)
|
||||
desktop = QApplication.desktop()
|
||||
self.setGeometry((desktop.width() - width) / 2, (desktop.height() - height) / 2, width, height)
|
||||
|
||||
# Discord RPC on game launch
|
||||
self.tab_widget.games_tab.default_widget.game_list.game_started.connect(
|
||||
lambda: self.rpc.set_discord_rpc(self.tab_widget.games_tab.default_widget.game_list.running_games[0]))
|
||||
# Remove RPC
|
||||
self.tab_widget.delete_presence.connect(self.rpc.set_discord_rpc)
|
||||
# Show RPC on changed rare_settings
|
||||
self.tab_widget.settings.rare_settings.rpc.update_settings.connect(
|
||||
lambda: self.rpc.changed_settings(self.tab_widget.games_tab.default_widget.game_list.running_games))
|
||||
self.setWindowTitle("Rare - GUI for legendary")
|
||||
self.tab_widget = TabWidget(core, self, args.offline)
|
||||
self.setCentralWidget(self.tab_widget)
|
||||
if not args.offline:
|
||||
self.rpc = DiscordRPC(core)
|
||||
# Discord RPC on game launch
|
||||
self.tab_widget.games_tab.default_widget.game_list.game_started.connect(
|
||||
lambda: self.rpc.set_discord_rpc(self.tab_widget.games_tab.default_widget.game_list.running_games[0]))
|
||||
# Remove RPC
|
||||
self.tab_widget.delete_presence.connect(self.rpc.set_discord_rpc)
|
||||
# Show RPC on changed rare_settings
|
||||
self.tab_widget.settings.rare_settings.rpc.update_settings.connect(
|
||||
lambda: self.rpc.changed_settings(self.tab_widget.games_tab.default_widget.game_list.running_games))
|
||||
|
||||
game = self.tab_widget.games_tab.default_widget.game_list.active_game
|
||||
if game != ("", 0):
|
||||
self.set_discord_rpc(game[0]) # Appname
|
||||
if game != ("", 0) and not args.offline:
|
||||
self.rpc.set_discord_rpc(game[0]) # Appname
|
||||
|
||||
self.show()
|
||||
if args.subparser == "launch":
|
||||
logger.info("Launching " + self.core.get_installed_game(args.app_name).title)
|
||||
if args.app_name in self.tab_widget.games_tab.default_widget.game_list.widgets.keys():
|
||||
|
@ -48,11 +51,35 @@ class MainWindow(QMainWindow):
|
|||
else:
|
||||
logger.info(f"Could not find {args.app_name} in Games")
|
||||
|
||||
self.timer = QTimer()
|
||||
self.timer.timeout.connect(self.timer_finished)
|
||||
self.timer.start(1000)
|
||||
|
||||
def timer_finished(self):
|
||||
file_path = os.path.expanduser("~/.cache/rare/lockfile")
|
||||
if os.path.exists(file_path):
|
||||
file = open(file_path, "r")
|
||||
action = file.read()
|
||||
file.close()
|
||||
if action.startswith("launch"):
|
||||
game = action.replace("launch ", "").replace("\n", "")
|
||||
if game in self.tab_widget.games_tab.default_widget.game_list.widgets.keys():
|
||||
self.tab_widget.games_tab.default_widget.game_list.widgets[game][1].launch()
|
||||
else:
|
||||
logger.info(f"Could not find {game} in Games")
|
||||
|
||||
elif action.startswith("start"):
|
||||
self.show()
|
||||
os.remove(file_path)
|
||||
self.timer.start(1000)
|
||||
|
||||
def closeEvent(self, e: QCloseEvent):
|
||||
if self.settings.value("sys_tray", True, bool):
|
||||
self.hide()
|
||||
e.ignore()
|
||||
return
|
||||
elif self.offline:
|
||||
pass
|
||||
elif self.tab_widget.downloadTab.active_game is not None:
|
||||
if not QMessageBox.question(self, "Close",
|
||||
self.tr("There is a download active. Do you really want to exit app?"),
|
||||
|
|
|
@ -17,31 +17,33 @@ from rare.utils.models import InstallOptions
|
|||
class TabWidget(QTabWidget):
|
||||
delete_presence = pyqtSignal()
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(TabWidget, self).__init__()
|
||||
disabled_tab = 3
|
||||
def __init__(self, core: LegendaryCore, parent, offline):
|
||||
super(TabWidget, self).__init__(parent=parent)
|
||||
disabled_tab = 3 if not offline else 1
|
||||
self.core = core
|
||||
self.setTabBar(TabBar(disabled_tab))
|
||||
|
||||
# Generate Tabs
|
||||
self.games_tab = GameTab(core)
|
||||
updates = self.games_tab.default_widget.game_list.updates
|
||||
self.downloadTab = DownloadTab(core, updates)
|
||||
self.cloud_saves = SyncSaves(core)
|
||||
|
||||
self.settings = SettingsTab(core)
|
||||
|
||||
# add tabs
|
||||
self.games_tab = GameTab(core, self, offline)
|
||||
self.addTab(self.games_tab, self.tr("Games"))
|
||||
self.addTab(self.downloadTab, "Downloads" + (" (" + str(len(updates)) + ")" if len(updates) != 0 else ""))
|
||||
self.addTab(self.cloud_saves, "Cloud Saves")
|
||||
|
||||
if not offline:
|
||||
updates = self.games_tab.default_widget.game_list.updates
|
||||
self.downloadTab = DownloadTab(core, updates, self)
|
||||
self.addTab(self.downloadTab, "Downloads" + (" (" + str(len(updates)) + ")" if len(updates) != 0 else ""))
|
||||
|
||||
self.cloud_saves = SyncSaves(core, self)
|
||||
self.addTab(self.cloud_saves, "Cloud Saves")
|
||||
|
||||
self.settings = SettingsTab(core, self)
|
||||
|
||||
# Space Tab
|
||||
self.addTab(QWidget(), "")
|
||||
self.setTabEnabled(disabled_tab, False)
|
||||
# Buttons
|
||||
store_button = TabButtonWidget(core, 'fa.shopping-cart', 'Epic Games Store')
|
||||
store_button.pressed.connect(lambda: webbrowser.open("https://www.epicgames.com/store"))
|
||||
self.tabBar().setTabButton(3, self.tabBar().RightSide, store_button)
|
||||
self.tabBar().setTabButton(disabled_tab, self.tabBar().RightSide, store_button)
|
||||
|
||||
self.account = QWidget()
|
||||
self.addTab(self.account, "")
|
||||
|
@ -52,7 +54,7 @@ class TabWidget(QTabWidget):
|
|||
account_button = TabButtonWidget(core, 'mdi.account-circle', 'Account')
|
||||
account_button.setMenu(QMenu())
|
||||
account_button.menu().addAction(account_action)
|
||||
self.tabBar().setTabButton(4, self.tabBar().RightSide, account_button)
|
||||
self.tabBar().setTabButton(disabled_tab + 1, self.tabBar().RightSide, account_button)
|
||||
|
||||
self.addTab(self.settings, icon("fa.gear", color='white'),
|
||||
"(!)" if self.settings.about.update_available else "")
|
||||
|
@ -61,23 +63,25 @@ class TabWidget(QTabWidget):
|
|||
# open download tab
|
||||
self.games_tab.default_widget.game_list.update_game.connect(lambda: self.setCurrentIndex(1))
|
||||
|
||||
# Download finished
|
||||
self.downloadTab.finished.connect(self.dl_finished)
|
||||
# start download
|
||||
self.games_tab.default_widget.game_list.install_game.connect(self.start_download)
|
||||
if not offline:
|
||||
# Download finished
|
||||
self.downloadTab.finished.connect(self.dl_finished)
|
||||
# start download
|
||||
self.games_tab.default_widget.game_list.install_game.connect(self.start_download)
|
||||
# install dlc
|
||||
self.games_tab.game_info.dlc_tab.install_dlc.connect(self.start_download)
|
||||
|
||||
# repair game
|
||||
self.games_tab.game_info.info.verify_game.connect(lambda app_name: self.downloadTab.install_game(
|
||||
InstallOptions(app_name, core.get_installed_game(app_name).install_path, repair=True)))
|
||||
# repair game
|
||||
self.games_tab.game_info.info.verify_game.connect(lambda app_name: self.downloadTab.install_game(
|
||||
InstallOptions(app_name, core.get_installed_game(app_name).install_path, repair=True)))
|
||||
|
||||
# Finished sync
|
||||
self.cloud_saves.finished.connect(self.finished_sync)
|
||||
# Game finished
|
||||
self.games_tab.default_widget.game_list.game_exited.connect(self.game_finished)
|
||||
|
||||
# Open game list on click on Games tab button
|
||||
self.tabBarClicked.connect(lambda x: self.games_tab.layout.setCurrentIndex(0) if x == 0 else None)
|
||||
|
||||
# Finished sync
|
||||
self.cloud_saves.finished.connect(self.finished_sync)
|
||||
|
||||
self.games_tab.default_widget.game_list.game_exited.connect(self.game_finished)
|
||||
|
||||
self.setIconSize(QSize(25, 25))
|
||||
|
||||
# Sync game and delete dc rpc
|
||||
|
@ -93,10 +97,10 @@ class TabWidget(QTabWidget):
|
|||
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys())
|
||||
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
||||
|
||||
def start_download(self, app_name):
|
||||
self.downloadTab.install_game(app_name)
|
||||
def start_download(self, options):
|
||||
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys()) + 1
|
||||
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
||||
self.downloadTab.install_game(options)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self.tabBar().setMinimumWidth(self.width())
|
||||
|
|
|
@ -14,8 +14,11 @@ class MiniWidget(QWidget):
|
|||
self.layout.addWidget(QLabel("Account"))
|
||||
username = self.core.lgd.userdata.get("display_name")
|
||||
if not username:
|
||||
self.core.login()
|
||||
username = self.core.lgd.userdata.get("display_name")
|
||||
try:
|
||||
self.core.login()
|
||||
username = self.core.lgd.userdata.get("display_name")
|
||||
except Exception:
|
||||
username = "Offline"
|
||||
|
||||
self.layout.addWidget(QLabel(self.tr("Logged in as ") + str(username)))
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ class LoadThread(QThread):
|
|||
class SyncSaves(QScrollArea):
|
||||
finished = pyqtSignal(str)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(SyncSaves, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, parent):
|
||||
super(SyncSaves, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.load_saves()
|
||||
|
|
|
@ -4,9 +4,17 @@ from logging import getLogger
|
|||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QLabel, QGroupBox
|
||||
|
||||
from rare.components.dialogs.path_input_dialog import PathInputDialog
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import InstalledGame, SaveGameStatus
|
||||
from rare.components.dialogs.path_input_dialog import PathInputDialog
|
||||
|
||||
logger = getLogger("Sync")
|
||||
|
||||
|
||||
def get_raw_save_path(app_name, core):
|
||||
game = core.lgd.get_game_meta(app_name)
|
||||
save_path = game.metadata['customAttributes'].get('CloudSaveFolder', {}).get('value')
|
||||
return save_path
|
||||
|
||||
|
||||
class _UploadThread(QThread):
|
||||
|
@ -20,7 +28,10 @@ class _UploadThread(QThread):
|
|||
self.save_path = save_path
|
||||
|
||||
def run(self) -> None:
|
||||
self.core.upload_save(self.app_name, self.save_path, self.date_time)
|
||||
try:
|
||||
self.core.upload_save(self.app_name, self.save_path, self.date_time)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
class _DownloadThread(QThread):
|
||||
|
@ -34,7 +45,10 @@ class _DownloadThread(QThread):
|
|||
self.save_path = save_path
|
||||
|
||||
def run(self) -> None:
|
||||
self.core.download_saves(self.app_name, self.latest_save.manifest_name, self.save_path, clean_dir=True)
|
||||
try:
|
||||
self.core.download_saves(self.app_name, self.latest_save.manifest_name, self.save_path, clean_dir=True)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
class SyncWidget(QGroupBox):
|
||||
|
@ -131,6 +145,11 @@ class SyncWidget(QGroupBox):
|
|||
self.layout.addWidget(cloud_save_date)
|
||||
|
||||
save_path_layout = QHBoxLayout()
|
||||
|
||||
self.raw_path = QLabel("Raw path: " + get_raw_save_path(self.game.app_name, self.core))
|
||||
self.raw_path.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
self.layout.addWidget(self.raw_path)
|
||||
|
||||
self.save_path_text = QLabel(igame.save_path)
|
||||
self.save_path_text.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
self.save_path_text.setWordWrap(True)
|
||||
|
|
|
@ -6,14 +6,14 @@ from PyQt5.QtCore import QThread, pyqtSignal, Qt, QSettings
|
|||
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton, QDialog, \
|
||||
QListWidget, QHBoxLayout, QGroupBox
|
||||
|
||||
from rare.components.dialogs.install_dialog import InstallInfoDialog, InstallDialog
|
||||
from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget
|
||||
from rare.components.tabs.downloads.download_thread import DownloadThread
|
||||
from rare.utils.models import InstallOptions
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.downloading import UIUpdate
|
||||
from custom_legendary.models.game import Game, InstalledGame
|
||||
from custom_legendary.utils.selective_dl import games
|
||||
from rare.components.dialogs.install_dialog import InstallInfoDialog, InstallDialog
|
||||
from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget
|
||||
from rare.components.tabs.downloads.download_thread import DownloadThread
|
||||
from rare.utils.models import InstallOptions
|
||||
from rare.utils.utils import get_size
|
||||
|
||||
logger = getLogger("Download")
|
||||
|
@ -24,36 +24,36 @@ class DownloadTab(QWidget):
|
|||
thread: QThread
|
||||
dl_queue = []
|
||||
|
||||
def __init__(self, core: LegendaryCore, updates: list):
|
||||
super(DownloadTab, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, updates: list, parent):
|
||||
super(DownloadTab, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.layout = QVBoxLayout()
|
||||
self.active_game: Game = None
|
||||
|
||||
self.installing_game = QLabel(self.tr("No active Download"))
|
||||
self.dl_speed = QLabel()
|
||||
self.cache_used = QLabel()
|
||||
self.downloaded = QLabel()
|
||||
self.time_left = QLabel()
|
||||
|
||||
self.info_layout = QGridLayout()
|
||||
|
||||
self.installing_game = QLabel(self.tr("No active Download"))
|
||||
self.info_layout.addWidget(self.installing_game, 0, 0)
|
||||
self.dl_speed = QLabel()
|
||||
self.info_layout.addWidget(self.dl_speed, 0, 1)
|
||||
self.cache_used = QLabel()
|
||||
self.info_layout.addWidget(self.cache_used, 1, 0)
|
||||
self.downloaded = QLabel()
|
||||
self.info_layout.addWidget(self.downloaded, 1, 1)
|
||||
self.time_left = QLabel()
|
||||
self.info_layout.addWidget(self.time_left, 2, 0)
|
||||
|
||||
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)
|
||||
self.prog_bar.setMaximum(100)
|
||||
|
||||
self.kill_button = QPushButton(self.tr("Stop Download"))
|
||||
self.mini_layout.addWidget(self.kill_button)
|
||||
self.kill_button.setDisabled(True)
|
||||
self.kill_button.clicked.connect(self.stop_download)
|
||||
self.mini_layout.addWidget(self.kill_button)
|
||||
|
||||
self.layout.addLayout(self.mini_layout)
|
||||
|
||||
|
@ -62,24 +62,27 @@ class DownloadTab(QWidget):
|
|||
self.queue_widget.update_list.connect(self.update_dl_queue)
|
||||
|
||||
self.updates = QGroupBox(self.tr("Updates"))
|
||||
self.updates.setObjectName("group")
|
||||
self.layout.addWidget(self.updates)
|
||||
self.update_layout = QVBoxLayout()
|
||||
self.updates.setLayout(self.update_layout)
|
||||
|
||||
self.updates.setObjectName("group")
|
||||
|
||||
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)
|
||||
self.update_text.setVisible(len(updates) == 0)
|
||||
|
||||
for igame in updates:
|
||||
widget = UpdateWidget(core, igame)
|
||||
self.update_widgets[igame.app_name] = widget
|
||||
widget = UpdateWidget(core, igame, self)
|
||||
self.update_layout.addWidget(widget)
|
||||
self.update_widgets[igame.app_name] = widget
|
||||
widget.update.connect(self.update_game)
|
||||
if QSettings().value("auto_update", False, bool):
|
||||
self.update_game(igame.app_name, True)
|
||||
widget.update_button.setDisabled(True)
|
||||
|
||||
self.updates.setLayout(self.update_layout)
|
||||
self.layout.addWidget(self.updates)
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
@ -132,6 +135,7 @@ class DownloadTab(QWidget):
|
|||
# Information
|
||||
if not from_update:
|
||||
if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept():
|
||||
self.finished.emit(False)
|
||||
return
|
||||
|
||||
if self.active_game is None:
|
||||
|
@ -235,7 +239,7 @@ class DownloadTab(QWidget):
|
|||
self.queue_widget.update_queue(self.dl_queue)
|
||||
|
||||
elif text[:5] == "error":
|
||||
QMessageBox.warning(self, "warn", "Download error: "+text[6:])
|
||||
QMessageBox.warning(self, "warn", "Download error: " + text[6:])
|
||||
|
||||
elif text == "stop":
|
||||
self.reset_infos()
|
||||
|
@ -258,7 +262,8 @@ class DownloadTab(QWidget):
|
|||
self.prog_bar.setValue(ui_update.progress)
|
||||
self.dl_speed.setText(self.tr("Download speed") + f": {ui_update.download_speed / 1024 / 1024:.02f}MB/s")
|
||||
self.cache_used.setText(self.tr("Cache used") + f": {ui_update.cache_usage / 1024 / 1024:.02f}MB")
|
||||
self.downloaded.setText(self.tr("Downloaded") + f": {get_size(ui_update.total_downloaded)} / {get_size(self.analysis.dl_size)}")
|
||||
self.downloaded.setText(
|
||||
self.tr("Downloaded") + f": {get_size(ui_update.total_downloaded)} / {get_size(self.analysis.dl_size)}")
|
||||
self.time_left.setText(self.tr("Time left: ") + self.get_time(ui_update.estimated_time_left))
|
||||
|
||||
def get_time(self, seconds: int) -> str:
|
||||
|
@ -280,8 +285,8 @@ class DownloadTab(QWidget):
|
|||
class UpdateWidget(QWidget):
|
||||
update = pyqtSignal(str)
|
||||
|
||||
def __init__(self, core: LegendaryCore, game: InstalledGame):
|
||||
super(UpdateWidget, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, game: InstalledGame, parent):
|
||||
super(UpdateWidget, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.game = game
|
||||
|
||||
|
@ -297,4 +302,4 @@ class UpdateWidget(QWidget):
|
|||
|
||||
def update_game(self):
|
||||
self.update_button.setDisabled(True)
|
||||
self.update.emit(self.game.app_name)
|
||||
self.update.emit(self.game.app_name)
|
||||
|
|
|
@ -63,7 +63,8 @@ class DownloadThread(QThread):
|
|||
|
||||
# clean up all the queues, otherwise this process won't terminate properly
|
||||
for name, q in zip(('Download jobs', 'Writer jobs', 'Download results', 'Writer results'),
|
||||
(self.dlm.dl_worker_queue, self.dlm.writer_queue, self.dlm.dl_result_q, self.dlm.writer_result_q)):
|
||||
(self.dlm.dl_worker_queue, self.dlm.writer_queue, self.dlm.dl_result_q,
|
||||
self.dlm.writer_result_q)):
|
||||
logger.debug(f'Cleaning up queue "{name}"')
|
||||
try:
|
||||
while True:
|
||||
|
@ -111,7 +112,7 @@ class DownloadThread(QThread):
|
|||
|
||||
except Exception as e:
|
||||
logger.error(f"Installation failed after {time.time() - start_time:.02f} seconds: {e}")
|
||||
self.status.emit("error "+str(e))
|
||||
self.status.emit("error " + str(e))
|
||||
return
|
||||
|
||||
else:
|
||||
|
@ -172,4 +173,3 @@ class DownloadThread(QThread):
|
|||
|
||||
def kill(self):
|
||||
self._kill = True
|
||||
|
||||
|
|
|
@ -9,20 +9,22 @@ from rare.utils.extra_widgets import SelectViewWidget
|
|||
|
||||
|
||||
class GameTab(QWidget):
|
||||
def __init__(self, core):
|
||||
super(GameTab, self).__init__()
|
||||
def __init__(self, core, parent, offline):
|
||||
super(GameTab, self).__init__(parent=parent)
|
||||
self.layout = QStackedLayout()
|
||||
self.default_widget = Games(core)
|
||||
self.default_widget = Games(core, self, offline)
|
||||
# Signal to show info
|
||||
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 = InfoTabs(core, self)
|
||||
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.import_widget = ImportWidget(core, self)
|
||||
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)
|
||||
|
@ -33,20 +35,20 @@ class GameTab(QWidget):
|
|||
self.layout.setCurrentIndex(0)
|
||||
|
||||
def show_info(self, app_name):
|
||||
self.game_info.update_game(app_name)
|
||||
self.game_info.update_game(app_name, self.default_widget.game_list.dlcs)
|
||||
self.game_info.setCurrentIndex(1)
|
||||
self.layout.setCurrentIndex(1)
|
||||
|
||||
|
||||
class Games(QWidget):
|
||||
def __init__(self, core):
|
||||
super(Games, self).__init__()
|
||||
def __init__(self, core, parent, offline):
|
||||
super(Games, self).__init__(parent=parent)
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.head_bar = GameListHeadBar()
|
||||
self.head_bar = GameListHeadBar(self)
|
||||
self.head_bar.setObjectName("head_bar")
|
||||
|
||||
self.game_list = GameList(core)
|
||||
self.game_list = GameList(core, self, offline)
|
||||
|
||||
self.head_bar.search_bar.textChanged.connect(
|
||||
lambda: self.game_list.filter(self.head_bar.search_bar.text()))
|
||||
|
@ -68,8 +70,8 @@ class Games(QWidget):
|
|||
|
||||
|
||||
class GameListHeadBar(QWidget):
|
||||
def __init__(self):
|
||||
super(GameListHeadBar, self).__init__()
|
||||
def __init__(self, parent):
|
||||
super(GameListHeadBar, self).__init__(parent=parent)
|
||||
self.layout = QHBoxLayout()
|
||||
self.installed_only = QCheckBox(self.tr("Installed only"))
|
||||
self.settings = QSettings()
|
||||
|
|
|
@ -6,18 +6,20 @@ from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, QLabel, QHBoxLayo
|
|||
QProgressBar, QStackedWidget, QGroupBox, QScrollArea
|
||||
from qtawesome import icon
|
||||
|
||||
from rare import utils
|
||||
from rare.components.tabs.games.game_info.game_settings import GameSettings
|
||||
from rare.utils.legendary_utils import VerifyThread
|
||||
from rare.utils.extra_widgets import SideTabBar
|
||||
from rare.utils.utils import IMAGE_DIR, get_size, create_desktop_link
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import InstalledGame, Game
|
||||
from rare.components.dialogs.uninstall_dialog import UninstallDialog
|
||||
from rare.components.tabs.games.game_info.dlcs import DlcTab
|
||||
from rare.components.tabs.games.game_info.game_settings import GameSettings
|
||||
from rare.utils import legendary_utils
|
||||
from rare.utils.extra_widgets import SideTabBar
|
||||
from rare.utils.legendary_utils import VerifyThread
|
||||
from rare.utils.utils import IMAGE_DIR, get_size
|
||||
|
||||
|
||||
class InfoTabs(QTabWidget):
|
||||
def __init__(self, core):
|
||||
super(InfoTabs, self).__init__()
|
||||
def __init__(self, core, parent):
|
||||
super(InfoTabs, self).__init__(parent=parent)
|
||||
self.app_name = ""
|
||||
self.core = core
|
||||
self.setTabBar(SideTabBar())
|
||||
|
@ -26,16 +28,28 @@ class InfoTabs(QTabWidget):
|
|||
self.addTab(QWidget(), icon("mdi.keyboard-backspace", color="white"), self.tr("Back"))
|
||||
self.tabBarClicked.connect(lambda x: self.parent().layout.setCurrentIndex(0) if x == 0 else None)
|
||||
|
||||
self.info = GameInfo(core)
|
||||
self.info = GameInfo(core, self)
|
||||
self.addTab(self.info, self.tr("Game Info"))
|
||||
self.settings = GameSettings(core)
|
||||
|
||||
self.settings = GameSettings(core, self)
|
||||
self.addTab(self.settings, self.tr("Settings"))
|
||||
self.tabBar().setCurrentIndex(1)
|
||||
|
||||
def update_game(self, app_name):
|
||||
self.dlc_tab = DlcTab(core, self)
|
||||
self.addTab(self.dlc_tab, self.tr("DLCs"))
|
||||
|
||||
def update_game(self, app_name, dlcs: list):
|
||||
|
||||
self.info.update_game(app_name)
|
||||
self.settings.update_game(app_name)
|
||||
|
||||
# DLC Tab: Disable if no dlcs available
|
||||
if len(dlcs[self.core.get_game(app_name).asset_info.catalog_item_id]) == 0:
|
||||
self.setTabEnabled(3, False)
|
||||
else:
|
||||
self.setTabEnabled(3, True)
|
||||
self.dlc_tab.update_dlcs(app_name, dlcs)
|
||||
|
||||
def keyPressEvent(self, e: QKeyEvent):
|
||||
if e.key() == Qt.Key_Escape:
|
||||
self.parent().layout.setCurrentIndex(0)
|
||||
|
@ -47,10 +61,9 @@ class GameInfo(QScrollArea):
|
|||
update_list = pyqtSignal()
|
||||
verify_game = pyqtSignal(str)
|
||||
verify_threads = {}
|
||||
action = pyqtSignal(str)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(GameInfo, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, parent):
|
||||
super(GameInfo, self).__init__(parent=parent)
|
||||
self.widget = QWidget()
|
||||
self.core = core
|
||||
self.layout = QVBoxLayout()
|
||||
|
@ -84,13 +97,14 @@ class GameInfo(QScrollArea):
|
|||
|
||||
self.install_path = QLabel("Error")
|
||||
self.install_path.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
self.install_path.setWordWrap(True)
|
||||
right_layout.addWidget(self.install_path)
|
||||
|
||||
top_layout.addLayout(right_layout)
|
||||
top_layout.addStretch()
|
||||
self.game_actions = GameActions()
|
||||
|
||||
self.game_actions.uninstall_button.clicked.connect(lambda: self.action.emit("uninstall"))
|
||||
self.game_actions.uninstall_button.clicked.connect(self.uninstall)
|
||||
self.game_actions.verify_button.clicked.connect(self.verify)
|
||||
self.game_actions.repair_button.clicked.connect(self.repair)
|
||||
|
||||
|
@ -100,6 +114,14 @@ class GameInfo(QScrollArea):
|
|||
self.widget.setLayout(self.layout)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
def uninstall(self):
|
||||
infos = UninstallDialog(self.game).get_information()
|
||||
if infos == 0:
|
||||
print("Cancel Uninstall")
|
||||
return
|
||||
legendary_utils.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')
|
||||
if not os.path.exists(repair_file):
|
||||
|
|
147
rare/components/tabs/games/game_info/dlcs.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
import os
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QSettings
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QGroupBox, QHBoxLayout, QVBoxLayout, QScrollArea, QLabel, QPushButton, QMessageBox
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import Game
|
||||
from rare.components.dialogs.install_dialog import InstallDialog
|
||||
from rare.utils.models import InstallOptions
|
||||
from rare.utils.utils import download_image
|
||||
|
||||
|
||||
class DlcTab(QScrollArea):
|
||||
install_dlc = pyqtSignal(InstallOptions)
|
||||
game: Game
|
||||
|
||||
def __init__(self, core: LegendaryCore, parent):
|
||||
super(DlcTab, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.widget = QGroupBox("DLCs")
|
||||
self.widget.setObjectName("group")
|
||||
self.setWidgetResizable(True)
|
||||
self.layout = QVBoxLayout()
|
||||
self.installed_dlcs = [i.app_name for i in self.core.get_installed_dlc_list()]
|
||||
|
||||
self.installed_dlc_widget = QGroupBox(self.tr("Installed DLCs"))
|
||||
self.installed_layout = QVBoxLayout()
|
||||
self.available_dlcs = QGroupBox(self.tr("Available DLCs"))
|
||||
self.available_dlcs_layout = QVBoxLayout()
|
||||
|
||||
self.installed = []
|
||||
self.available = []
|
||||
|
||||
def update_dlcs(self, app_name, dlcs: list):
|
||||
self.installed_dlcs = [i.app_name for i in self.core.get_installed_dlc_list()]
|
||||
self.installed_dlc_widget = QGroupBox(self.tr("Installed DLCs"))
|
||||
self.installed_layout = QVBoxLayout()
|
||||
self.available_dlcs = QGroupBox(self.tr("Available DLCs"))
|
||||
self.available_dlcs_layout = QVBoxLayout()
|
||||
self.installed = []
|
||||
self.available = []
|
||||
QVBoxLayout().addWidget(self.widget)
|
||||
|
||||
self.game = self.core.get_game(app_name)
|
||||
|
||||
for dlc in sorted(dlcs[self.game.asset_info.catalog_item_id], key=lambda x: x.app_title):
|
||||
if dlc.app_name in self.installed_dlcs:
|
||||
w = DLCWidget(dlc, True)
|
||||
self.installed_layout.addWidget(w)
|
||||
self.installed.append(dlc)
|
||||
else:
|
||||
w = DLCWidget(dlc, False)
|
||||
w.install.connect(self.install)
|
||||
self.available_dlcs_layout.addWidget(w)
|
||||
self.available.append(dlc)
|
||||
if len(self.installed) == 0:
|
||||
self.installed_layout.addWidget(QLabel(self.tr("No DLCs are installed")))
|
||||
if len(self.available) == 0:
|
||||
self.available_dlcs_layout.addWidget(QLabel(self.tr("No DLCs are available")))
|
||||
|
||||
self.widget = QGroupBox("DLCs")
|
||||
self.layout = QVBoxLayout()
|
||||
self.installed_dlc_widget.setLayout(self.installed_layout)
|
||||
self.available_dlcs.setLayout(self.available_dlcs_layout)
|
||||
self.layout.addWidget(self.installed_dlc_widget)
|
||||
self.layout.addWidget(self.available_dlcs)
|
||||
self.layout.addStretch(1)
|
||||
self.widget.setLayout(self.layout)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
def install(self, app_name):
|
||||
if not self.core.is_installed(self.game.app_name):
|
||||
QMessageBox.warning(self, "Error", self.tr("Base Game is not installed. Please install {} first").format(
|
||||
self.game.app_title))
|
||||
return
|
||||
infos = InstallDialog(self.game.app_name, self.core, True).get_information()
|
||||
if infos != 0:
|
||||
path, max_workers, force, ignore_free_space = infos
|
||||
self.install_dlc.emit(
|
||||
InstallOptions(app_name=app_name, max_workers=max_workers, path=path, force=force,
|
||||
ignore_free_space=ignore_free_space))
|
||||
|
||||
|
||||
class DLCWidget(QGroupBox):
|
||||
install = pyqtSignal(str) # Appname
|
||||
|
||||
def __init__(self, dlc: Game, installed: bool):
|
||||
super(DLCWidget, self).__init__()
|
||||
self.main_layout = QHBoxLayout()
|
||||
self.dlc = dlc
|
||||
IMAGE_DIR = QSettings().value("img_dir", os.path.expanduser("~/.cache/rare/images"))
|
||||
if installed:
|
||||
|
||||
if os.path.exists(os.path.join(IMAGE_DIR, dlc.app_name, "FinalArt.png")):
|
||||
pixmap = QPixmap(os.path.join(IMAGE_DIR, dlc.app_name, "FinalArt.png"))
|
||||
elif os.path.exists(os.path.join(IMAGE_DIR, dlc.app_name, "DieselGameBoxTall.png")):
|
||||
pixmap = QPixmap(os.path.join(IMAGE_DIR, dlc.app_name, "DieselGameBoxTall.png"))
|
||||
elif os.path.exists(os.path.join(IMAGE_DIR, dlc.app_name, "DieselGameBoxLogo.png")):
|
||||
pixmap = QPixmap(os.path.join(IMAGE_DIR, dlc.app_name, "DieselGameBoxLogo.png"))
|
||||
else:
|
||||
print(f"No Image found: {dlc.app_title}")
|
||||
pixmap = None
|
||||
if not pixmap or pixmap.isNull():
|
||||
print(dlc.app_title + " has corrupt Image")
|
||||
download_image(dlc, force=True)
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{dlc.app_name}/UninstalledArt.png")
|
||||
else:
|
||||
if os.path.exists(f"{IMAGE_DIR}/{dlc.app_name}/UninstalledArt.png"):
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{dlc.app_name}/DieselGameBoxTall.png")
|
||||
|
||||
else:
|
||||
pixmap = None
|
||||
|
||||
if not pixmap or pixmap.isNull():
|
||||
print(dlc.app_title + " has corrupt Image")
|
||||
download_image(dlc, force=True)
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{dlc.app_name}/UninstalledArt.png")
|
||||
|
||||
image = QLabel()
|
||||
image.setPixmap(pixmap)
|
||||
self.main_layout.addWidget(image)
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.layout.addWidget(QLabel(dlc.app_title))
|
||||
self.layout.addWidget(QLabel("Version: " + str(dlc.app_version)))
|
||||
|
||||
self.layout.addWidget(QLabel("App Name: " + dlc.app_name))
|
||||
if not installed:
|
||||
self.install_button = QPushButton(self.tr("Install"))
|
||||
self.layout.addWidget(self.install_button)
|
||||
|
||||
self.install_button.clicked.connect(lambda: self.install.emit(dlc.app_name))
|
||||
else:
|
||||
self.layout.addWidget(QLabel(self.tr("Installed. Uninstalling DLCs is not supported")))
|
||||
|
||||
self.main_layout.addLayout(self.layout)
|
||||
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
def install_game(self):
|
||||
self.install_button.setDisabled(True)
|
||||
self.install_button.setText(self.tr("Installing"))
|
||||
self.install.emit(self.dlc.app_name)
|
|
@ -18,8 +18,8 @@ class GameSettings(QScrollArea):
|
|||
# variable to no update when changing game
|
||||
change = False
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(GameSettings, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, parent):
|
||||
super(GameSettings, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.widget = QWidget()
|
||||
self.settings = QSettings()
|
||||
|
@ -45,7 +45,8 @@ class GameSettings(QScrollArea):
|
|||
self.launch_params_widget = SettingsWidget(self.tr("Launch parameters"), self.launch_params,
|
||||
self.launch_params_accept_button)
|
||||
self.layout.addWidget(self.launch_params_widget)
|
||||
self.launch_params_accept_button.clicked.connect(lambda: self.save_line_edit("start_params", self.launch_params.text()))
|
||||
self.launch_params_accept_button.clicked.connect(
|
||||
lambda: self.save_line_edit("start_params", self.launch_params.text()))
|
||||
|
||||
self.cloud_sync = QCheckBox("Sync with cloud")
|
||||
self.cloud_sync_widget = SettingsWidget(self.tr("Auto sync with cloud"), self.cloud_sync)
|
||||
|
|
|
@ -28,10 +28,11 @@ class GameList(QStackedWidget):
|
|||
running_games = []
|
||||
active_game = ("", 0)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(GameList, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, parent, offline):
|
||||
super(GameList, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.setObjectName("list_widget")
|
||||
self.offline = offline
|
||||
|
||||
self.settings = QSettings()
|
||||
icon_view = self.settings.value("icon_view", True, bool)
|
||||
|
@ -39,10 +40,10 @@ class GameList(QStackedWidget):
|
|||
self.init_ui(icon_view)
|
||||
|
||||
def init_ui(self, icon_view=True):
|
||||
self.icon_scrollarea = QScrollArea()
|
||||
self.icon_widget = QWidget()
|
||||
self.list_scrollarea = QScrollArea()
|
||||
self.list_widget = QWidget()
|
||||
self.icon_scrollarea = QScrollArea(parent=self)
|
||||
self.icon_widget = QWidget(parent=self.icon_scrollarea)
|
||||
self.list_scrollarea = QScrollArea(parent=self)
|
||||
self.list_widget = QWidget(parent=self.list_scrollarea)
|
||||
|
||||
self.icon_scrollarea.setWidgetResizable(True)
|
||||
self.icon_scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
|
@ -65,8 +66,10 @@ class GameList(QStackedWidget):
|
|||
self.updates = []
|
||||
self.widgets = {}
|
||||
|
||||
self.installed = sorted(self.core.get_installed_list(), key=lambda x: x.title)
|
||||
|
||||
# Installed Games
|
||||
for igame in sorted(self.core.get_installed_list(), key=lambda x: x.title):
|
||||
for igame in self.installed:
|
||||
if os.path.exists(f"{IMAGE_DIR}/{igame.app_name}/FinalArt.png"):
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/FinalArt.png")
|
||||
elif os.path.exists(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png"):
|
||||
|
@ -82,8 +85,11 @@ class GameList(QStackedWidget):
|
|||
download_image(igame, force=True)
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
|
||||
|
||||
icon_widget = GameWidgetInstalled(igame, self.core, pixmap)
|
||||
list_widget = InstalledListWidget(igame, self.core, pixmap)
|
||||
icon_widget = GameWidgetInstalled(igame, self.core, pixmap, self.offline)
|
||||
self.icon_layout.addWidget(icon_widget)
|
||||
|
||||
list_widget = InstalledListWidget(igame, self.core, pixmap, self.offline)
|
||||
self.list_layout.addWidget(list_widget)
|
||||
|
||||
icon_widget.show_info.connect(self.show_game_info.emit)
|
||||
list_widget.show_info.connect(self.show_game_info.emit)
|
||||
|
@ -95,9 +101,6 @@ class GameList(QStackedWidget):
|
|||
list_widget.finish_signal.connect(self.finished)
|
||||
list_widget.update_list.connect(lambda: self.update_list(self.settings.value("icon_view", True, bool)))
|
||||
|
||||
self.icon_layout.addWidget(icon_widget)
|
||||
self.list_layout.addWidget(list_widget)
|
||||
|
||||
if icon_widget.update_available:
|
||||
self.updates.append(igame)
|
||||
|
||||
|
@ -113,15 +116,16 @@ class GameList(QStackedWidget):
|
|||
self.timer.timeout.connect(self.is_finished)
|
||||
self.timer.start(10000)
|
||||
|
||||
uninstalled_games = []
|
||||
self.uninstalled_games = []
|
||||
installed = [i.app_name for i in self.core.get_installed_list()]
|
||||
# get Uninstalled games
|
||||
for igame in sorted(self.core.get_game_list(), key=lambda x: x.app_title):
|
||||
if not igame.app_name in installed:
|
||||
uninstalled_games.append(igame)
|
||||
games, self.dlcs = self.core.get_game_and_dlc_list()
|
||||
for game in sorted(games, key=lambda x: x.app_title):
|
||||
if not game.app_name in installed:
|
||||
self.uninstalled_games.append(game)
|
||||
|
||||
# add uninstalled games
|
||||
for igame in uninstalled_games:
|
||||
for igame in self.uninstalled_games:
|
||||
if os.path.exists(f"{IMAGE_DIR}/{igame.app_name}/UninstalledArt.png"):
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/UninstalledArt.png")
|
||||
|
||||
|
@ -129,7 +133,6 @@ class GameList(QStackedWidget):
|
|||
logger.info(igame.app_title + " has a corrupt image.")
|
||||
download_image(igame, force=True)
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/UninstalledArt.png")
|
||||
|
||||
else:
|
||||
logger.warning(f"No Image found: {igame.app_title}")
|
||||
download_image(igame, force=True)
|
||||
|
@ -178,7 +181,7 @@ class GameList(QStackedWidget):
|
|||
|
||||
for i, pid in self.procs:
|
||||
if executable in i:
|
||||
# Workaround for Satisfactory
|
||||
# Workaround for Satisfactory: Check Cmdline args
|
||||
if igame.app_name in ["CrabEA", "CrabTest"]:
|
||||
p = psutil.Process(pid)
|
||||
if not igame.install_path.split("/")[-1].split("\\")[-1] in " ".join(p.cmdline()):
|
||||
|
@ -236,6 +239,22 @@ class GameList(QStackedWidget):
|
|||
|
||||
def update_list(self, icon_view=True):
|
||||
self.settings.setValue("icon_view", icon_view)
|
||||
|
||||
uninstalled_games = []
|
||||
installed = [i.app_name for i in self.core.get_installed_list()]
|
||||
# get Uninstalled games
|
||||
games = self.core.get_game_list(True)
|
||||
for game in sorted(games, key=lambda x: x.app_title):
|
||||
if not game.app_name in installed:
|
||||
uninstalled_games.append(game.app_name)
|
||||
|
||||
# get new uninstalled/ installed games that changed
|
||||
new_installed_games = list(set(installed) - set([i.app_name for i in self.installed]))
|
||||
new_uninstalled_games = list(set(uninstalled_games) - set([i.app_name for i in self.uninstalled_games]))
|
||||
|
||||
if not new_uninstalled_games and not new_installed_games:
|
||||
return
|
||||
|
||||
self.removeWidget(self.icon_scrollarea)
|
||||
self.removeWidget(self.list_scrollarea)
|
||||
self.init_ui(icon_view)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import logging
|
||||
import os
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QProcess, QSettings, Qt
|
||||
from PyQt5.QtCore import pyqtSignal, QProcess, QSettings, Qt, QByteArray
|
||||
from PyQt5.QtWidgets import QGroupBox, QMessageBox, QAction
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
@ -20,13 +21,14 @@ class BaseInstalledWidget(QGroupBox):
|
|||
update_list = pyqtSignal()
|
||||
proc: QProcess()
|
||||
|
||||
def __init__(self, igame: InstalledGame, core: LegendaryCore, pixmap):
|
||||
def __init__(self, igame: InstalledGame, core: LegendaryCore, pixmap, offline):
|
||||
super(BaseInstalledWidget, self).__init__()
|
||||
self.igame = igame
|
||||
self.core = core
|
||||
self.game = self.core.get_game(self.igame.app_name)
|
||||
self.pixmap = pixmap
|
||||
self.game_running = False
|
||||
self.offline = offline
|
||||
self.update_available = self.core.get_asset(self.game.app_name, True).build_version != igame.version
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
|
@ -36,7 +38,7 @@ class BaseInstalledWidget(QGroupBox):
|
|||
launch.triggered.connect(self.launch)
|
||||
self.addAction(launch)
|
||||
|
||||
if os.path.exists(os.path.expanduser(f"~/Desktop/{self.igame.title}.desktop"))\
|
||||
if os.path.exists(os.path.expanduser(f"~/Desktop/{self.igame.title}.desktop")) \
|
||||
or os.path.exists(os.path.expanduser(f"~/Desktop/{self.igame.title}.lnk")):
|
||||
self.create_desktop = QAction(self.tr("Remove Desktop link"))
|
||||
else:
|
||||
|
@ -65,7 +67,7 @@ class BaseInstalledWidget(QGroupBox):
|
|||
path = os.path.expanduser("~/.local/share/applications/")
|
||||
else:
|
||||
return
|
||||
if not (os.path.exists(os.path.expanduser(f"{path}{self.igame.title}.desktop"))\
|
||||
if not (os.path.exists(os.path.expanduser(f"{path}{self.igame.title}.desktop"))
|
||||
or os.path.exists(os.path.expanduser(f"{path}{self.igame.title}.lnk"))):
|
||||
create_desktop_link(self.igame.app_name, self.core, type_of_link)
|
||||
if type_of_link == "desktop":
|
||||
|
@ -90,17 +92,45 @@ class BaseInstalledWidget(QGroupBox):
|
|||
logger.info("Cancel Startup")
|
||||
return 1
|
||||
logger.info("Launching " + self.igame.title)
|
||||
self.proc, params = legendary_utils.launch_game(self.core, self.igame.app_name, offline,
|
||||
skip_version_check=skip_version_check)
|
||||
if offline or self.offline:
|
||||
if not self.igame.can_run_offline:
|
||||
QMessageBox.warning(self, "Offline",
|
||||
self.tr("Game cannot run offline. Please start game in Online mode"))
|
||||
return
|
||||
|
||||
try:
|
||||
self.proc, params = legendary_utils.launch_game(self.core, self.igame.app_name, offline,
|
||||
skip_version_check=skip_version_check)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
QMessageBox.warning(self, "Error",
|
||||
self.tr("An error occurred while starting game. Maybe game files are missing"))
|
||||
return
|
||||
|
||||
if not self.proc:
|
||||
logger.error("Could not start process")
|
||||
return 1
|
||||
self.game_logger = getLogger(self.game.app_name)
|
||||
|
||||
self.proc.finished.connect(self.finished)
|
||||
self.proc.readyReadStandardOutput.connect(self.stdout)
|
||||
self.proc.readyReadStandardError.connect(self.stderr)
|
||||
self.proc.start(params[0], params[1:])
|
||||
self.launch_signal.emit(self.igame.app_name)
|
||||
self.game_running = True
|
||||
self.data = QByteArray()
|
||||
return 0
|
||||
|
||||
def stdout(self):
|
||||
data = self.proc.readAllStandardOutput()
|
||||
stdout = bytes(data).decode("utf-8")
|
||||
self.game_logger.info(stdout)
|
||||
|
||||
def stderr(self):
|
||||
stderr = bytes(self.proc.readAllStandardError()).decode("utf-8")
|
||||
self.game_logger.error(stderr)
|
||||
QMessageBox.warning(self, "Warning", stderr + "\nSee ~/.cache/rare/logs/")
|
||||
|
||||
def finished(self, exit_code):
|
||||
logger.info("Game exited with exit code: " + str(exit_code))
|
||||
self.finish_signal.emit(self.game.app_name)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QGroupBox
|
||||
from PyQt5.QtWidgets import QGroupBox
|
||||
|
||||
from rare.components.dialogs.install_dialog import InstallDialog
|
||||
from rare.utils.models import InstallOptions
|
||||
|
@ -25,4 +25,6 @@ class BaseUninstalledWidget(QGroupBox):
|
|||
infos = InstallDialog(self.game.app_name, self.core).get_information()
|
||||
if infos != 0:
|
||||
path, max_workers, force, ignore_free_space = infos
|
||||
self.install_game.emit(InstallOptions(app_name=self.game.app_name, max_workers=max_workers, path=path, force=force, ignore_free_space=ignore_free_space))
|
||||
self.install_game.emit(
|
||||
InstallOptions(app_name=self.game.app_name, max_workers=max_workers, path=path, force=force,
|
||||
ignore_free_space=ignore_free_space))
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import os
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QEvent, pyqtSignal, QSettings, QSize, Qt
|
||||
from PyQt5.QtCore import QEvent, pyqtSignal, QSize, Qt
|
||||
from PyQt5.QtGui import QMouseEvent
|
||||
from PyQt5.QtWidgets import *
|
||||
from qtawesome import icon
|
||||
|
||||
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
|
||||
from rare.utils import legendary_utils
|
||||
from rare.utils.extra_widgets import ClickableLabel
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import InstalledGame
|
||||
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
|
||||
from rare.utils.extra_widgets import ClickableLabel
|
||||
|
||||
logger = getLogger("GameWidgetInstalled")
|
||||
|
||||
|
@ -20,8 +18,8 @@ class GameWidgetInstalled(BaseInstalledWidget):
|
|||
show_info = pyqtSignal(str)
|
||||
update_game = pyqtSignal()
|
||||
|
||||
def __init__(self, game: InstalledGame, core: LegendaryCore, pixmap):
|
||||
super(GameWidgetInstalled, self).__init__(game, core, pixmap)
|
||||
def __init__(self, game: InstalledGame, core: LegendaryCore, pixmap, offline):
|
||||
super(GameWidgetInstalled, self).__init__(game, core, pixmap, offline)
|
||||
self.setObjectName("game_widget_icon")
|
||||
|
||||
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||
|
@ -112,4 +110,4 @@ class GameWidgetInstalled(BaseInstalledWidget):
|
|||
desktop_link = menu.addAction("Add Desktop link")
|
||||
action = menu.exec_(self.mapToGlobal(event.pos()))
|
||||
if action == desktop_link:
|
||||
print("LOL")"""
|
||||
print("LOL")"""
|
||||
|
|
|
@ -2,12 +2,12 @@ import os
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QProcess, pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QStyle, QVBoxLayout, QAction
|
||||
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout
|
||||
from qtawesome import icon
|
||||
|
||||
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import InstalledGame
|
||||
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
|
||||
|
||||
logger = getLogger("GameWidget")
|
||||
|
||||
|
@ -17,14 +17,12 @@ class InstalledListWidget(BaseInstalledWidget):
|
|||
signal = pyqtSignal(str)
|
||||
update_game = pyqtSignal()
|
||||
|
||||
def __init__(self, game: InstalledGame, core: LegendaryCore, pixmap):
|
||||
super(InstalledListWidget, self).__init__(game, core, pixmap)
|
||||
def __init__(self, game: InstalledGame, core: LegendaryCore, pixmap, offline):
|
||||
super(InstalledListWidget, self).__init__(game, core, pixmap, offline)
|
||||
self.dev = core.get_game(self.igame.app_name).metadata["developer"]
|
||||
self.size = game.install_size
|
||||
self.launch_params = game.launch_parameters
|
||||
|
||||
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
|
||||
##Layout on the right
|
||||
|
@ -59,7 +57,7 @@ class InstalledListWidget(BaseInstalledWidget):
|
|||
self.childLayout.addWidget(self.app_name_label)
|
||||
self.childLayout.addWidget(self.developer_label)
|
||||
|
||||
#if os.name != "nt":
|
||||
# if os.name != "nt":
|
||||
# self.childLayout.addWidget(self.wine_rating)
|
||||
self.childLayout.addWidget(self.version_label)
|
||||
self.childLayout.addWidget(self.size_label)
|
||||
|
|
|
@ -3,11 +3,11 @@ from logging import getLogger
|
|||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QLabel
|
||||
|
||||
from rare.components.tabs.games.game_widgets.base_uninstalled_widget import BaseUninstalledWidget
|
||||
from rare.utils.models import InstallOptions
|
||||
from rare.utils.extra_widgets import ClickableLabel
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from custom_legendary.models.game import Game
|
||||
from rare.components.tabs.games.game_widgets.base_uninstalled_widget import BaseUninstalledWidget
|
||||
from rare.utils.extra_widgets import ClickableLabel
|
||||
from rare.utils.models import InstallOptions
|
||||
|
||||
logger = getLogger("Uninstalled")
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ from logging import getLogger
|
|||
|
||||
from PyQt5.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
|
||||
from rare.components.tabs.games.game_widgets.base_uninstalled_widget import BaseUninstalledWidget
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.components.tabs.games.game_widgets.base_uninstalled_widget import BaseUninstalledWidget
|
||||
|
||||
logger = getLogger("Game")
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QPushButton, QVBoxLayo
|
|||
QGroupBox
|
||||
from qtawesome import icon
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.utils import legendary_utils
|
||||
from rare.utils.extra_widgets import PathEdit
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
logger = getLogger("Import")
|
||||
|
||||
|
@ -18,8 +18,8 @@ logger = getLogger("Import")
|
|||
class ImportWidget(QWidget):
|
||||
update_list = pyqtSignal()
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(ImportWidget, self).__init__()
|
||||
def __init__(self, core: LegendaryCore, parent):
|
||||
super(ImportWidget, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.game_list = [i.app_name for i in self.core.get_game_list()]
|
||||
|
||||
|
@ -43,7 +43,8 @@ class ImportWidget(QWidget):
|
|||
self.import_game_info = QLabel(self.tr("Select path to game"))
|
||||
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.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.override_app_name_label.setWordWrap(True)
|
||||
self.app_name_input = QLineEdit()
|
||||
self.app_name_input.setFixedHeight(32)
|
||||
|
@ -86,9 +87,9 @@ class ImportWidget(QWidget):
|
|||
|
||||
def app_name_changed(self, text):
|
||||
if text in self.game_list:
|
||||
self.indicator_label.setPixmap(icon("ei.ok-sign", color="green").pixmap(16,16))
|
||||
self.indicator_label.setPixmap(icon("ei.ok-sign", color="green").pixmap(16, 16))
|
||||
else:
|
||||
self.indicator_label.setPixmap(icon("ei.remove-sign", color="red").pixmap(16,16))
|
||||
self.indicator_label.setPixmap(icon("ei.remove-sign", color="red").pixmap(16, 16))
|
||||
|
||||
def path_changed(self, path):
|
||||
if os.path.exists(path):
|
||||
|
@ -120,7 +121,8 @@ class ImportWidget(QWidget):
|
|||
return
|
||||
|
||||
if legendary_utils.import_game(self.core, app_name=app_name, path=path):
|
||||
self.info_label.setText(self.tr("Successfully imported {}. Reload library").format(self.core.get_installed_game(app_name).title))
|
||||
self.info_label.setText(self.tr("Successfully imported {}. Reload library").format(
|
||||
self.core.get_installed_game(app_name).title))
|
||||
self.app_name_input.setText("")
|
||||
|
||||
self.update_list.emit()
|
||||
|
@ -165,7 +167,8 @@ class ImportWidget(QWidget):
|
|||
for wine_prefix in possible_wineprefixes:
|
||||
imported += self.auto_import_games(os.path.join(wine_prefix, "drive_c/Program Files/Epic Games/"))
|
||||
if imported > 0:
|
||||
QMessageBox.information(self, "Imported Games", self.tr("Successfully imported {} Games. Reloading Library").format(imported))
|
||||
QMessageBox.information(self, "Imported Games",
|
||||
self.tr("Successfully imported {} Games. Reloading Library").format(imported))
|
||||
self.update_list.emit()
|
||||
else:
|
||||
QMessageBox.information(self, "Imported Games", self.tr("No Games were found"))
|
||||
|
|
|
@ -10,8 +10,8 @@ from rare.utils.extra_widgets import SideTabBar
|
|||
|
||||
|
||||
class SettingsTab(QTabWidget):
|
||||
def __init__(self, core):
|
||||
super(SettingsTab, self).__init__()
|
||||
def __init__(self, core, parent):
|
||||
super(SettingsTab, self).__init__(parent=parent)
|
||||
self.core = core
|
||||
self.setTabBar(SideTabBar())
|
||||
self.setTabPosition(QTabWidget.West)
|
||||
|
|
|
@ -2,12 +2,13 @@ from logging import getLogger
|
|||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QIntValidator
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QFileDialog, QPushButton, QLineEdit, QGroupBox, QMessageBox, \
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QFileDialog, QPushButton, QLineEdit, QGroupBox, QMessageBox, \
|
||||
QScrollArea
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.components.tabs.settings.settings_widget import SettingsWidget
|
||||
from rare.utils.extra_widgets import PathEdit
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.utils.utils import get_size
|
||||
|
||||
logger = getLogger("LegendarySettings")
|
||||
|
||||
|
@ -41,7 +42,7 @@ class LegendarySettings(QScrollArea):
|
|||
self.max_worker_select)
|
||||
self.layout.addWidget(self.max_worker_widget)
|
||||
|
||||
#cleanup
|
||||
# cleanup
|
||||
self.clean_layout = QVBoxLayout()
|
||||
self.cleanup_widget = QGroupBox(self.tr("Cleanup"))
|
||||
self.clean_button = QPushButton(self.tr("Remove everything"))
|
||||
|
@ -96,7 +97,8 @@ class LegendarySettings(QScrollArea):
|
|||
|
||||
after = self.core.lgd.get_dir_size()
|
||||
logger.info(f'Cleanup complete! Removed {(before - after) / 1024 / 1024:.02f} MiB.')
|
||||
if cleaned := (before-after) > 0:
|
||||
QMessageBox.information(self, "Cleanup", self.tr("Cleanup complete! Successfully removed {} MB").format(round(cleaned / 1024 / 1024, 3)))
|
||||
if (before - after) > 0:
|
||||
QMessageBox.information(self, "Cleanup", self.tr("Cleanup complete! Successfully removed {}").format(
|
||||
get_size(before - after)))
|
||||
else:
|
||||
QMessageBox.information(self, "Cleanup", "Nothing to clean")
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QFileDialog, QLineEdit, QGroupBox
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QFileDialog, QLineEdit, QGroupBox
|
||||
|
||||
from custom_legendary.core import LegendaryCore
|
||||
from rare.components.tabs.settings.dxvk import DxvkWidget
|
||||
from rare.components.tabs.settings.settings_widget import SettingsWidget
|
||||
from rare.utils.extra_widgets import PathEdit
|
||||
from custom_legendary.core import LegendaryCore
|
||||
|
||||
logger = getLogger("LinuxSettings")
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QSettings, Qt
|
||||
|
@ -27,13 +29,17 @@ class RareSettings(QScrollArea):
|
|||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setWidgetResizable(True)
|
||||
# (option_name, group_text, checkbox_text, default
|
||||
self.checkboxes = [("sys_tray", self.tr("Hide to System Tray Icon"), self.tr("Exit to System Tray Icon"), True),
|
||||
("auto_update", self.tr("Automatically update Games on startup"), self.tr("Auto updates"), False),
|
||||
("confirm_start", self.tr("Confirm launch of game"), self.tr("Confirm launch of game"), False),
|
||||
("auto_sync_cloud", self.tr("Auto sync with cloud"), self.tr("Sync with cloud"), True),
|
||||
("notification", self.tr("Show Notifications after Downloads"), self.tr("Show notification"), True),
|
||||
("save_size", self.tr("Save size of window after restart"), self.tr("Save size"), False)
|
||||
]
|
||||
self.checkboxes = [
|
||||
("sys_tray", self.tr("Hide to System Tray Icon"), self.tr("Exit to System Tray Icon"), True),
|
||||
("auto_update", self.tr("Automatically update Games on startup"), self.tr("Auto updates"),
|
||||
False),
|
||||
("confirm_start", self.tr("Confirm launch of game"), self.tr("Confirm launch of game"),
|
||||
False),
|
||||
("auto_sync_cloud", self.tr("Auto sync with cloud"), self.tr("Sync with cloud"), True),
|
||||
("notification", self.tr("Show Notifications after Downloads"), self.tr("Show notification"),
|
||||
True),
|
||||
("save_size", self.tr("Save size of window after restart"), self.tr("Save size"), False)
|
||||
]
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
self.settings = QSettings()
|
||||
|
@ -67,10 +73,22 @@ class RareSettings(QScrollArea):
|
|||
settings_widget = SettingsWidget(head_text, checkbox)
|
||||
self.layout.addWidget(settings_widget)
|
||||
|
||||
self.open_log_dir = QPushButton(self.tr("Open Log directory"))
|
||||
self.layout.addWidget(self.open_log_dir)
|
||||
self.open_log_dir.clicked.connect(self.open_dir)
|
||||
|
||||
self.layout.addStretch()
|
||||
self.widget.setLayout(self.layout)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
def open_dir(self):
|
||||
logdir = os.path.expanduser("~/.cache/rare/logs")
|
||||
if os.name == "nt":
|
||||
os.startfile(logdir)
|
||||
else:
|
||||
opener = "open" if sys.platform == "darwin" else "xdg-open"
|
||||
subprocess.Popen([opener, logdir])
|
||||
|
||||
def save_window_size(self):
|
||||
self.settings.setValue("save_size", self.save_size.isChecked())
|
||||
self.settings.remove("window_size")
|
||||
|
|
|
@ -38,4 +38,4 @@ class RPCSettings(QGroupBox):
|
|||
|
||||
def changed(self, i):
|
||||
self.settings.setValue("rpc_enable", i)
|
||||
self.update_settings.emit()
|
||||
self.update_settings.emit()
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QAction
|
||||
|
||||
from rare import style_path
|
||||
|
||||
|
||||
class TrayIcon(QSystemTrayIcon):
|
||||
def __init__(self, parent):
|
||||
super(TrayIcon, self).__init__(parent)
|
||||
self.setIcon(QIcon(style_path+"Logo.png"))
|
||||
self.setIcon(QIcon(style_path + "Logo.png"))
|
||||
self.setVisible(True)
|
||||
self.setToolTip("Rare")
|
||||
|
||||
|
|
|
@ -37,12 +37,12 @@
|
|||
<context>
|
||||
<name>App</name>
|
||||
<message>
|
||||
<location filename="../app.py" line="85"/>
|
||||
<location filename="../app.py" line="89"/>
|
||||
<source>Download finished</source>
|
||||
<translation>Download abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../app.py" line="85"/>
|
||||
<location filename="../app.py" line="89"/>
|
||||
<source>Download finished. Game is playable now</source>
|
||||
<translation>Downlaod abgeschlossen. Spiel kann jetzt gespielt werden</translation>
|
||||
</message>
|
||||
|
@ -50,10 +50,60 @@
|
|||
<context>
|
||||
<name>BaseInstalledWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="34"/>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="90"/>
|
||||
<source>Do you want to launch {}</source>
|
||||
<translation>Möchtest du {} starten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="37"/>
|
||||
<source>Launch</source>
|
||||
<translation>Starten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="74"/>
|
||||
<source>Remove Desktop link</source>
|
||||
<translation>Desktop Verknüpfung löschen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="84"/>
|
||||
<source>Create Desktop link</source>
|
||||
<translation>Desktopverknüpfung erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="52"/>
|
||||
<source>Remove start menu link</source>
|
||||
<translation>Startmenüverknüpfung löschen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="54"/>
|
||||
<source>Create start menu link</source>
|
||||
<translation>Startmenüverknüpfung erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="59"/>
|
||||
<source>Uninstall</source>
|
||||
<translation>Deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="76"/>
|
||||
<source>Remove Start menu link</source>
|
||||
<translation>Startmenüverknüpfung löschen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="86"/>
|
||||
<source>Create Start menu link</source>
|
||||
<translation>Startmenüverknüpfung erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="106"/>
|
||||
<source>An error occurred while starting game. Maybe game files are missing</source>
|
||||
<translation>Ein Fehler ist passiert. Vielleicht fehlen die Spieldateien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/base_installed_widget.py" line="97"/>
|
||||
<source>Game cannot run offline. Please start game in Online mode</source>
|
||||
<translation>Spiel kann nicht offline gestartet werden. Starte die App im Online Mode neu</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BrowserLogin</name>
|
||||
|
@ -78,6 +128,24 @@
|
|||
<translation>Laden...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DLCWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="131"/>
|
||||
<source>Install</source>
|
||||
<translation>Installieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="136"/>
|
||||
<source>Installed. Uninstalling DLCs is not supported</source>
|
||||
<translation>Installiert. Das Deinstallieren von DLCs wird nicht unterstützt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="146"/>
|
||||
<source>Installing</source>
|
||||
<translation>Installieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DlQueueWidget</name>
|
||||
<message>
|
||||
|
@ -109,10 +177,38 @@
|
|||
<translation>Download löschen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DlcTab</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="37"/>
|
||||
<source>Installed DLCs</source>
|
||||
<translation>Installierte DLCs</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="39"/>
|
||||
<source>Available DLCs</source>
|
||||
<translation>Verfügbare DLCs</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="58"/>
|
||||
<source>No DLCs are installed</source>
|
||||
<translation>Keine DLCs sind installiert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="60"/>
|
||||
<source>No DLCs are available</source>
|
||||
<translation>Keine weiteren DLCs verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/dlcs.py" line="74"/>
|
||||
<source>Base Game is not installed. Please install {} first</source>
|
||||
<translation>Basisspiel ist nicht installiert. Bitte installiere zuerst {}</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DownloadTab</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="33"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="35"/>
|
||||
<source>No active Download</source>
|
||||
<translation>Kein aktiver Download</translation>
|
||||
</message>
|
||||
|
@ -122,57 +218,57 @@
|
|||
<translation>Download anhalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="69"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="73"/>
|
||||
<source>No updates available</source>
|
||||
<translation>Keine Updates verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="124"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="127"/>
|
||||
<source>Error preparing download</source>
|
||||
<translation>Fehler beim Vorbereiten des Downloads</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="129"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="132"/>
|
||||
<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/__init__.py" line="207"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="211"/>
|
||||
<source>Installation finished</source>
|
||||
<translation>Installation abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="249"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="253"/>
|
||||
<source>Installing Game: No active download</source>
|
||||
<translation>Installierendes Spiel: Kein aktiver Download</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="259"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="263"/>
|
||||
<source>Download speed</source>
|
||||
<translation>Geschwindigkeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="260"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="264"/>
|
||||
<source>Cache used</source>
|
||||
<translation>Benutzter Cache</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="261"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="265"/>
|
||||
<source>Downloaded</source>
|
||||
<translation>Runtergeladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="262"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="267"/>
|
||||
<source>Time left: </source>
|
||||
<translation>Zeit übrig: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="208"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="212"/>
|
||||
<source>Finished Download of game {}</source>
|
||||
<translation>Download von {} abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="199"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="203"/>
|
||||
<source>Download finished. Reload library</source>
|
||||
<translation>Download abgeschlossen. Spiele neu laden</translation>
|
||||
</message>
|
||||
|
@ -192,7 +288,7 @@
|
|||
<translation type="obsolete">Keine</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="155"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="159"/>
|
||||
<source>Installing Game: </source>
|
||||
<translation>Installierendes Spiel: </translation>
|
||||
</message>
|
||||
|
@ -243,32 +339,32 @@
|
|||
<context>
|
||||
<name>GameActions</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="183"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="203"/>
|
||||
<source>Uninstall game</source>
|
||||
<translation>Spiel deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="185"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="205"/>
|
||||
<source>Uninstall</source>
|
||||
<translation>Deinstallieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="191"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="211"/>
|
||||
<source>Verify Game</source>
|
||||
<translation>Spieldateien überprüfen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="196"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="216"/>
|
||||
<source>Verify</source>
|
||||
<translation>Überprüfen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="205"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="225"/>
|
||||
<source>Repair Game</source>
|
||||
<translation>Spiel reparieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="207"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="227"/>
|
||||
<source>Repair</source>
|
||||
<translation>Reparieren</translation>
|
||||
</message>
|
||||
|
@ -276,27 +372,27 @@
|
|||
<context>
|
||||
<name>GameInfo</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="107"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="128"/>
|
||||
<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/game_info/__init__.py" line="132"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="153"/>
|
||||
<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/game_info/__init__.py" line="161"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="182"/>
|
||||
<source>Developer: </source>
|
||||
<translation>Entwickler: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="162"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="183"/>
|
||||
<source>Install size: </source>
|
||||
<translation>Größe: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="164"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="185"/>
|
||||
<source>Install path: </source>
|
||||
<translation>Installationsordner: </translation>
|
||||
</message>
|
||||
|
@ -309,22 +405,22 @@
|
|||
<context>
|
||||
<name>GameList</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_list.py" line="203"/>
|
||||
<location filename="../components/tabs/games/game_list.py" line="206"/>
|
||||
<source>Launch</source>
|
||||
<translation>Starten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_list.py" line="221"/>
|
||||
<location filename="../components/tabs/games/game_list.py" line="224"/>
|
||||
<source>Game running</source>
|
||||
<translation>Spiel läuft</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_list.py" line="53"/>
|
||||
<location filename="../components/tabs/games/game_list.py" line="54"/>
|
||||
<source>Installed Games: {} Available Games: {}</source>
|
||||
<translation>Installierte Spiele: {} Verfügbare Spiele: {}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_list.py" line="213"/>
|
||||
<location filename="../components/tabs/games/game_list.py" line="215"/>
|
||||
<source>Sync CLoud saves</source>
|
||||
<translation>Spielstand synchronisieren</translation>
|
||||
</message>
|
||||
|
@ -332,17 +428,17 @@
|
|||
<context>
|
||||
<name>GameListHeadBar</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/__init__.py" line="74"/>
|
||||
<location filename="../components/tabs/games/__init__.py" line="76"/>
|
||||
<source>Installed only</source>
|
||||
<translation>Nur Installierte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/__init__.py" line="81"/>
|
||||
<location filename="../components/tabs/games/__init__.py" line="83"/>
|
||||
<source>Import Game</source>
|
||||
<translation>Spiel importieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/__init__.py" line="93"/>
|
||||
<location filename="../components/tabs/games/__init__.py" line="95"/>
|
||||
<source>Search Game</source>
|
||||
<translation>Spiel suchen</translation>
|
||||
</message>
|
||||
|
@ -360,37 +456,37 @@
|
|||
<translation>Überprüfung nach Updates beim Start überspringen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="86"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="87"/>
|
||||
<source>Save</source>
|
||||
<translation>Speichern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="62"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="63"/>
|
||||
<source>Wrapper (e.g. optirun)</source>
|
||||
<translation>Wrapper (z.B. optirun)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="82"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="83"/>
|
||||
<source>Proton Wrapper</source>
|
||||
<translation>Proton Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="88"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="89"/>
|
||||
<source>Proton prefix</source>
|
||||
<translation>Protonprefix</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="178"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="179"/>
|
||||
<source>No permission to create folder</source>
|
||||
<translation>Keine Berechtigung den Ordner zu erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="222"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="223"/>
|
||||
<source>Please select path for proton prefix</source>
|
||||
<translation>Bitte wähle den Pfad zum Protonprefix</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="51"/>
|
||||
<location filename="../components/tabs/games/game_info/game_settings.py" line="52"/>
|
||||
<source>Auto sync with cloud</source>
|
||||
<translation>Speicherstände automatisch mit der Cloud synchronisieren</translation>
|
||||
</message>
|
||||
|
@ -408,17 +504,17 @@
|
|||
<context>
|
||||
<name>GameWidgetInstalled</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_icon_widget.py" line="36"/>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_icon_widget.py" line="34"/>
|
||||
<source>Update available</source>
|
||||
<translation>Update verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_icon_widget.py" line="88"/>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_icon_widget.py" line="86"/>
|
||||
<source>Start game without version check</source>
|
||||
<translation>Ohne Updateüberprüfung starten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_icon_widget.py" line="94"/>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_icon_widget.py" line="92"/>
|
||||
<source>Game running</source>
|
||||
<translation>Spiel läuft</translation>
|
||||
</message>
|
||||
|
@ -479,12 +575,12 @@
|
|||
<translation>Wähle den Pfad zum Spiel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="66"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="67"/>
|
||||
<source>Import Game</source>
|
||||
<translation>Spiel importieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="78"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="79"/>
|
||||
<source>Import all games from Epic Games Launcher</source>
|
||||
<translation>Alle Spiele aus dem Epic Games Launcher importieren</translation>
|
||||
</message>
|
||||
|
@ -499,22 +595,22 @@
|
|||
<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/import_widget.py" line="119"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="120"/>
|
||||
<source>Could not find app name</source>
|
||||
<translation>Konnte den Appnamen nicht finden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="123"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="124"/>
|
||||
<source>Successfully imported {}. Reload library</source>
|
||||
<translation>Erfolgreich {} importiert. Spiele neu laden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="129"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="131"/>
|
||||
<source>Failed to import {}</source>
|
||||
<translation>{} Konnte nicht importiert werden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="168"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="170"/>
|
||||
<source>Successfully imported {} Games. Reloading Library</source>
|
||||
<translation>Erfolgreich {} Spiele importiert. Spiele neu laden</translation>
|
||||
</message>
|
||||
|
@ -524,7 +620,7 @@
|
|||
<translation>Ein bereits existierendes Spiel aus dem Epic Games Launcher importieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="171"/>
|
||||
<location filename="../components/tabs/games/import_widget.py" line="174"/>
|
||||
<source>No Games were found</source>
|
||||
<translation>Keine Spiele wurden gefunden</translation>
|
||||
</message>
|
||||
|
@ -532,25 +628,30 @@
|
|||
<context>
|
||||
<name>InfoTabs</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="27"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="28"/>
|
||||
<source>Back</source>
|
||||
<translation>Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="31"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="32"/>
|
||||
<source>Game Info</source>
|
||||
<translation>Spielinfo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="33"/>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="35"/>
|
||||
<source>Settings</source>
|
||||
<translation>Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_info/__init__.py" line="39"/>
|
||||
<source>DLCs</source>
|
||||
<translation>DLCs</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InstallDialog</name>
|
||||
<message>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="29"/>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="39"/>
|
||||
<source>Max workers (0: Default)</source>
|
||||
<translation>Maximale Anzahl Downloadprozessen(Standard: 0)</translation>
|
||||
</message>
|
||||
|
@ -560,12 +661,12 @@
|
|||
<translation><h3>Installiere {}</h3></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="33"/>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="43"/>
|
||||
<source>Force download</source>
|
||||
<translation>Download erzwingen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="37"/>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="47"/>
|
||||
<source>Ignore free space (Warning!)</source>
|
||||
<translation>Freien Speicherplatz ignorieren (Achtung!)</translation>
|
||||
</message>
|
||||
|
@ -573,19 +674,19 @@
|
|||
<context>
|
||||
<name>InstallInfoDialog</name>
|
||||
<message>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="70"/>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="82"/>
|
||||
<source>Download size: {}GB
|
||||
Install size: {}GB</source>
|
||||
<translation>Downloadgröße: {}GB
|
||||
Installationsgröße: {} GB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="76"/>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="88"/>
|
||||
<source>Install</source>
|
||||
<translation>Installieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="78"/>
|
||||
<location filename="../components/dialogs/install_dialog.py" line="90"/>
|
||||
<source>Cancel</source>
|
||||
<translation>Abbruch</translation>
|
||||
</message>
|
||||
|
@ -593,40 +694,40 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>InstalledListWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_list_widget.py" line="49"/>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_list_widget.py" line="40"/>
|
||||
<source>Launch</source>
|
||||
<translation>Starten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_list_widget.py" line="60"/>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_list_widget.py" line="51"/>
|
||||
<source>Developer: </source>
|
||||
<translation>Entwickler: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/games/game_widgets/installed_list_widget.py" line="31"/>
|
||||
<source>Uninstall</source>
|
||||
<translation>Deinstallieren</translation>
|
||||
<translation type="obsolete">Deinstallieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>LaunchDialog</name>
|
||||
<message>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="60"/>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="65"/>
|
||||
<source>Launching Rare</source>
|
||||
<translation>Starte Rare</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="62"/>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="67"/>
|
||||
<source>Logging in</source>
|
||||
<translation>Einloggen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="82"/>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="90"/>
|
||||
<source>Downloading Images</source>
|
||||
<translation>Bilder runterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="93"/>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="101"/>
|
||||
<source>Starting...</source>
|
||||
<translation>Starten...</translation>
|
||||
</message>
|
||||
|
@ -634,7 +735,7 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>LaunchThread</name>
|
||||
<message>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="23"/>
|
||||
<location filename="../components/dialogs/launch_dialog.py" line="24"/>
|
||||
<source>Downloading Images</source>
|
||||
<translation>Bilder runterladen</translation>
|
||||
</message>
|
||||
|
@ -642,38 +743,43 @@ 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="19"/>
|
||||
<source>Legendary settings</source>
|
||||
<translation>Legendary Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="31"/>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="32"/>
|
||||
<source>Default installation directory</source>
|
||||
<translation>Standardordner für Installationen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="40"/>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="41"/>
|
||||
<source>Max workers for Download (Less: slower download)(0: Default)</source>
|
||||
<translation>Maximale Anzahl Downloadprozesse (Weniger: langsamer)(Standard: 0)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="46"/>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="47"/>
|
||||
<source>Cleanup</source>
|
||||
<translation>Aufräumen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="47"/>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="48"/>
|
||||
<source>Remove everything</source>
|
||||
<translation>Alles aufräumen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="51"/>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="52"/>
|
||||
<source>Clean, but keep manifests</source>
|
||||
<translation>Aufräumen, aber Manifests behalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="100"/>
|
||||
<source>Cleanup complete! Successfully removed {} MB</source>
|
||||
<translation type="obsolete">Fertig! Es wurden {} MB entfernt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/legendary.py" line="101"/>
|
||||
<source>Cleanup complete! Successfully removed {}</source>
|
||||
<translation>Fertig! Es wurden {} MB entfernt</translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -724,30 +830,48 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../components/main_window.py" line="48"/>
|
||||
<location filename="../components/main_window.py" line="82"/>
|
||||
<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>MangoSettings</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/mango_hud.py" line="7"/>
|
||||
<source>MangoHUD settings</source>
|
||||
<translation>MangoHUD Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/mango_hud.py" line="11"/>
|
||||
<source>CPU temperature</source>
|
||||
<translation>CPU Temperatur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/mango_hud.py" line="12"/>
|
||||
<source>GPU temperature</source>
|
||||
<translation>GPU Temperatur</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MiniWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/account/__init__.py" line="20"/>
|
||||
<location filename="../components/tabs/account/__init__.py" line="23"/>
|
||||
<source>Logged in as </source>
|
||||
<translation>Eingeloggt als </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/account/__init__.py" line="22"/>
|
||||
<location filename="../components/tabs/account/__init__.py" line="25"/>
|
||||
<source>Account settings</source>
|
||||
<translation>Accounteinstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/account/__init__.py" line="27"/>
|
||||
<location filename="../components/tabs/account/__init__.py" line="30"/>
|
||||
<source>Logout</source>
|
||||
<translation>Ausloggen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/account/__init__.py" line="33"/>
|
||||
<location filename="../components/tabs/account/__init__.py" line="36"/>
|
||||
<source>Do you really want to logout</source>
|
||||
<translation>Willst du dich wirklich abmelden</translation>
|
||||
</message>
|
||||
|
@ -819,27 +943,27 @@ Installationsgröße: {} GB</translation>
|
|||
<translation>Rare Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="45"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="48"/>
|
||||
<source>Save</source>
|
||||
<translation>Speichern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="47"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="50"/>
|
||||
<source>Image Directory</source>
|
||||
<translation>Ordner für Bilder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="58"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="61"/>
|
||||
<source>Language</source>
|
||||
<translation>Sprache</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="84"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="87"/>
|
||||
<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="32"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="33"/>
|
||||
<source>Confirm launch of game</source>
|
||||
<translation>Start des Spiels bestätigen</translation>
|
||||
</message>
|
||||
|
@ -854,22 +978,22 @@ Installationsgröße: {} GB</translation>
|
|||
<translation>In das System Tray Icon minimieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="33"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="35"/>
|
||||
<source>Auto sync with cloud</source>
|
||||
<translation>Speicherstände automatisch mit der Cloud synchronisieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="33"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="35"/>
|
||||
<source>Sync with cloud</source>
|
||||
<translation>Automatisch Synchronisieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="35"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="38"/>
|
||||
<source>Save size</source>
|
||||
<translation>Größe Speichern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="35"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="38"/>
|
||||
<source>Save size of window after restart</source>
|
||||
<translation>Die Fenstergröße nach dem Beenden speichern</translation>
|
||||
</message>
|
||||
|
@ -884,12 +1008,12 @@ Installationsgröße: {} GB</translation>
|
|||
<translation>Automatische Updates</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="34"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="36"/>
|
||||
<source>Show Notifications after Downloads</source>
|
||||
<translation>Benachrichtigung nach Abschluss des Downloads anzeigen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/settings/rare.py" line="34"/>
|
||||
<location filename="../components/tabs/settings/rare.py" line="36"/>
|
||||
<source>Show notification</source>
|
||||
<translation>Benachrichtigung anzeigen</translation>
|
||||
</message>
|
||||
|
@ -935,97 +1059,97 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>SyncWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="62"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="76"/>
|
||||
<source>Path not found</source>
|
||||
<translation>Ordner nicht gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="78"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="92"/>
|
||||
<source>Local Save date: </source>
|
||||
<translation>Lokales Speicherdatum: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="81"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="95"/>
|
||||
<source>No Local Save files</source>
|
||||
<translation>Keine Lokalen Dateien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="83"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="97"/>
|
||||
<source>Cloud save date: </source>
|
||||
<translation>Online Speicherdatum: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="85"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="99"/>
|
||||
<source>No Cloud saves</source>
|
||||
<translation>Keine Online Speicherstände</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="89"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="103"/>
|
||||
<source>Game is up to date</source>
|
||||
<translation>Spiel ist aktuell</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="90"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="104"/>
|
||||
<source>Upload anyway</source>
|
||||
<translation>Trotzdem hochladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="91"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="105"/>
|
||||
<source>Download anyway</source>
|
||||
<translation>Trotzdem herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="93"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="107"/>
|
||||
<source>Cloud save is newer</source>
|
||||
<translation>Online Speicherstand ist aktueller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="94"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="108"/>
|
||||
<source>Download Cloud saves</source>
|
||||
<translation>Online Speicherstand herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="98"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="112"/>
|
||||
<source>Upload Saves</source>
|
||||
<translation>Spielstände hochladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="109"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="123"/>
|
||||
<source>Local save is newer</source>
|
||||
<translation>Lokaler Speicher ist aktueller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="110"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="124"/>
|
||||
<source>Upload saves</source>
|
||||
<translation>Spielstände hochladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="114"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="128"/>
|
||||
<source>Download saves</source>
|
||||
<translation>Spielstand herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="137"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="156"/>
|
||||
<source>Change path</source>
|
||||
<translation>Pfad ändern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="162"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="181"/>
|
||||
<source>Uploading...</source>
|
||||
<translation>Hochladen...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="170"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="189"/>
|
||||
<source>Upload finished</source>
|
||||
<translation>Hochladen abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="180"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="199"/>
|
||||
<source>Downloading...</source>
|
||||
<translation>Runterladen...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="186"/>
|
||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="205"/>
|
||||
<source>Download finished</source>
|
||||
<translation>Download abgeschlossen</translation>
|
||||
</message>
|
||||
|
@ -1033,7 +1157,7 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>TabWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tab_widget.py" line="34"/>
|
||||
<location filename="../components/tab_widget.py" line="28"/>
|
||||
<source>Games</source>
|
||||
<translation>Spiele</translation>
|
||||
</message>
|
||||
|
@ -1041,7 +1165,7 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>TrayIcon</name>
|
||||
<message>
|
||||
<location filename="../components/tray_icon.py" line="18"/>
|
||||
<location filename="../components/tray_icon.py" line="19"/>
|
||||
<source>Exit</source>
|
||||
<translation>Schließen</translation>
|
||||
</message>
|
||||
|
@ -1077,7 +1201,7 @@ Installationsgröße: {} GB</translation>
|
|||
<context>
|
||||
<name>UpdateWidget</name>
|
||||
<message>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="288"/>
|
||||
<location filename="../components/tabs/downloads/__init__.py" line="297"/>
|
||||
<source>Update Game</source>
|
||||
<translation>Spiel updaten</translation>
|
||||
</message>
|
||||
|
|
|
@ -36,13 +36,10 @@ def launch_game(core, app_name: str, offline: bool = False, skip_version_check:
|
|||
if latest.build_version != game.version:
|
||||
print("Please update game")
|
||||
return None
|
||||
try:
|
||||
params, cwd, env = core.get_launch_parameters(app_name=app_name, offline=offline)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return 1
|
||||
params, cwd, env = core.get_launch_parameters(app_name=app_name, offline=offline)
|
||||
|
||||
process = QProcess()
|
||||
process.setProcessChannelMode(QProcess.MergedChannels)
|
||||
process.setWorkingDirectory(cwd)
|
||||
environment = QProcessEnvironment()
|
||||
for e in env:
|
||||
|
@ -52,10 +49,18 @@ def launch_game(core, app_name: str, offline: bool = False, skip_version_check:
|
|||
return process, params
|
||||
|
||||
|
||||
def uninstall(app_name: str, core, options=None):
|
||||
def uninstall(app_name: str, core: LegendaryCore, options=None):
|
||||
if not options:
|
||||
options = {"keep_files": False}
|
||||
igame = core.get_installed_game(app_name)
|
||||
|
||||
# remove shortcuts link
|
||||
if os.name == "posix":
|
||||
if os.path.exists(os.path.expanduser(f"~/Desktop/{igame.title}.desktop")):
|
||||
os.remove(os.path.expanduser(f"~/Desktop/{igame.title}.desktop"))
|
||||
if os.path.exists(os.path.expanduser(f"~/.local/share/applications/{igame.title}.desktop")):
|
||||
os.remove(os.path.expanduser(f"~/.local/share/applications/{igame.title}.desktop"))
|
||||
|
||||
try:
|
||||
# Remove DLC first so directory is empty when game uninstall runs
|
||||
dlcs = core.get_dlc_for_game(app_name)
|
||||
|
|
|
@ -2,6 +2,7 @@ import platform
|
|||
import time
|
||||
from logging import getLogger
|
||||
|
||||
import pypresence.exceptions
|
||||
from PyQt5.QtCore import QObject, QSettings
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from pypresence import Presence
|
||||
|
@ -60,10 +61,22 @@ class DiscordRPC(QObject):
|
|||
logger.warning("Discord is not active\n" + str(e))
|
||||
self.RPC = None
|
||||
return
|
||||
except FileNotFoundError as e:
|
||||
logger.warning("File not found error\n" + str(e))
|
||||
self.RPC = None
|
||||
return
|
||||
except pypresence.exceptions.InvalidPipe as e:
|
||||
logger.error("Is Discord running? \n" + str(e))
|
||||
self.RPC = None
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
self.RPC = None
|
||||
return
|
||||
self.update_rpc(app_name)
|
||||
|
||||
def update_rpc(self, app_name=None):
|
||||
if self.settings.value("rpc_enable", 0, int) == 2 or (app_name is None and self.settings.value("rpc_enable", 0) == 0):
|
||||
if self.settings.value("rpc_enable", 0, int) == 2 or (app_name is None and self.settings.value("rpc_enable", 0, int) == 0):
|
||||
self.remove_rpc()
|
||||
return
|
||||
title = None
|
||||
|
|
|
@ -28,18 +28,22 @@ def download_images(signal: pyqtSignal, core: LegendaryCore):
|
|||
logger.info("Create Image dir")
|
||||
|
||||
# Download Images
|
||||
for i, game in enumerate(sorted(core.get_game_list(), key=lambda x: x.app_title)):
|
||||
|
||||
games, dlcs = core.get_game_and_dlc_list()
|
||||
dlc_list = []
|
||||
for i in dlcs.values():
|
||||
dlc_list.append(i[0])
|
||||
game_list = games + dlc_list
|
||||
for i, game in enumerate(game_list):
|
||||
try:
|
||||
download_image(game)
|
||||
except json.decoder.JSONDecodeError:
|
||||
shutil.rmtree(f"{IMAGE_DIR}/{game.app_name}")
|
||||
download_image(game)
|
||||
signal.emit(i)
|
||||
signal.emit(i/len(game_list)*100)
|
||||
|
||||
|
||||
def download_image(game, force=False):
|
||||
if force:
|
||||
if force and os.path.exists(f"{IMAGE_DIR}/{game.app_name}"):
|
||||
shutil.rmtree(f"{IMAGE_DIR}/{game.app_name}")
|
||||
if not os.path.isdir(f"{IMAGE_DIR}/" + game.app_name):
|
||||
os.mkdir(f"{IMAGE_DIR}/" + game.app_name)
|
||||
|
@ -128,9 +132,12 @@ def get_possible_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
|
||||
try:
|
||||
resp = requests.get("https://api.github.com/repos/Dummerle/Rare/releases/latest")
|
||||
tag = json.loads(resp.content.decode("utf-8"))["tag_name"]
|
||||
return tag
|
||||
except requests.exceptions.ConnectionError:
|
||||
return "0.0.0"
|
||||
|
||||
|
||||
def get_size(b: int) -> str:
|
||||
|
|