Merge branch 'main' into dev
This commit is contained in:
commit
9edfd302bd
20 changed files with 478 additions and 188 deletions
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
|
@ -46,7 +46,7 @@ jobs:
|
||||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
commit_message: Update AUR package
|
commit_message: Update AUR package
|
||||||
|
|
||||||
pyinstaller-windows:
|
cx-freeze-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
@ -55,25 +55,18 @@ jobs:
|
||||||
python-version: '3.8'
|
python-version: '3.8'
|
||||||
- name: Install python deps
|
- name: Install python deps
|
||||||
run: |
|
run: |
|
||||||
pip3 install pyinstaller setuptools wheel
|
pip3 install cx_Freeze setuptools wheel
|
||||||
pip3 install -r requirements.txt
|
pip3 install -r requirements.txt
|
||||||
- name: Prepare
|
|
||||||
run: cp rare/__main__.py ./
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: pyinstaller
|
run: python3 freeze.py bdist_msi
|
||||||
--icon=rare/styles/Logo.ico
|
- name: Copy File
|
||||||
--onefile
|
run: cp dist/*.msi Rare.msi
|
||||||
--name Rare
|
|
||||||
--add-data="Rare/languages/*;Rare/languages"
|
|
||||||
--add-data="Rare/Styles/*;Rare/Styles"
|
|
||||||
--windowed
|
|
||||||
__main__.py
|
|
||||||
- name: Upload files to GitHub
|
- name: Upload files to GitHub
|
||||||
uses: svenstaro/upload-release-action@2.2.1
|
uses: svenstaro/upload-release-action@2.2.1
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: dist/Rare.exe
|
file: Rare.msi
|
||||||
asset_name: Rare.exe
|
asset_name: Rare.msi
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -6,5 +6,7 @@ __pycache__
|
||||||
/.vscode
|
/.vscode
|
||||||
/build
|
/build
|
||||||
/dist
|
/dist
|
||||||
|
/deb_dist
|
||||||
|
*.tar.gz
|
||||||
/Rare.egg-info/
|
/Rare.egg-info/
|
||||||
/venv
|
/venv
|
||||||
|
|
10
README.md
10
README.md
|
@ -41,12 +41,14 @@ Install via `pip`.
|
||||||
|
|
||||||
## Run from source
|
## Run from source
|
||||||
1. Run `pip install -r requirements.txt` to get dependencies. If you use `pacman` you can run `sudo pacman --needed -S python-wheel python-setuptools python-pyqt5 python-qtawesome python-requests python-pillow`
|
1. Run `pip install -r requirements.txt` to get dependencies. If you use `pacman` you can run `sudo pacman --needed -S python-wheel python-setuptools python-pyqt5 python-qtawesome python-requests python-pillow`
|
||||||
2. For unix operating systems run `sh start.sh`. For windows run `set PYTHONPATH=%CD% && python Rare`
|
2. For unix operating systems run `sh start.sh`. For windows run `set PYTHONPATH=%CD% && python rare`
|
||||||
|
|
||||||
## Why Rare?
|
## Why Rare?
|
||||||
|
|
||||||
- Rare uses much less RAM than electron based apps such as [HeroicGL](https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher) and EpicGL which allows the games to run better.
|
- Rare only uses ~50MB of RAM which is much less than the electron based [HeroicGamesLauncher](https://github.com/Heroic-Games-Launcher/HeroicGamesLauncher) uses.
|
||||||
- Rare supports all major platforms (Windows, Linux, macOS) unlike the alternatives.
|
- Rare supports all major platforms (Windows, Linux, Mac) unlike the alternatives.
|
||||||
|
|
||||||
|
**Note** Mac should work too, but I have no Mac and I can't test it.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ Install via `pip`.
|
||||||
## Planned Features
|
## Planned Features
|
||||||
- More Translations (Need help)
|
- More Translations (Need help)
|
||||||
- More Information about Games
|
- More Information about Games
|
||||||
More planned features are in projects
|
More planned features are in [projects](https://github.com/Dummerle/Rare/projects/1)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
There are more options to contribute.
|
There are more options to contribute.
|
||||||
|
|
74
freeze.py
Normal file
74
freeze.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cx_Freeze import setup, Executable
|
||||||
|
|
||||||
|
from rare import __version__
|
||||||
|
|
||||||
|
# Packages to include
|
||||||
|
python_packages = []
|
||||||
|
|
||||||
|
# Modules to include
|
||||||
|
python_modules = []
|
||||||
|
|
||||||
|
base = None
|
||||||
|
name = None
|
||||||
|
build_options = {}
|
||||||
|
build_exe_options = {}
|
||||||
|
shortcutName = None
|
||||||
|
shortcutDir = None
|
||||||
|
bdist_msi_options = None
|
||||||
|
src_files = []
|
||||||
|
external_so_files = []
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
base = 'Win32GUI'
|
||||||
|
name = 'Rare.exe'
|
||||||
|
shortcut_table = [
|
||||||
|
('DesktopShortcut', # Shortcut
|
||||||
|
'DesktopFolder', # Directory
|
||||||
|
'Rare', # Name
|
||||||
|
'TARGETDIR', # Component
|
||||||
|
'[TARGETDIR]'+name, # Target
|
||||||
|
None, # Arguments
|
||||||
|
'A gui for Legendary.', # Description
|
||||||
|
None, # Hotkey
|
||||||
|
None, # Icon
|
||||||
|
None, # IconIndex
|
||||||
|
None, # ShowCmd
|
||||||
|
'TARGETDIR' # Working Directory
|
||||||
|
)]
|
||||||
|
msi_data = {"Shortcut": shortcut_table}
|
||||||
|
bdist_msi_options = {'data': msi_data, "all_users": True}
|
||||||
|
build_options["bdist_msi"] = bdist_msi_options
|
||||||
|
else:
|
||||||
|
name = 'Rare'
|
||||||
|
|
||||||
|
src_files += [
|
||||||
|
'LICENSE',
|
||||||
|
'README.md',
|
||||||
|
'rare/styles/Logo.ico',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Dependencies are automatically detected, but it might need fine tuning.
|
||||||
|
build_exe_options["packages"] = python_packages
|
||||||
|
build_exe_options["include_files"] = src_files + external_so_files
|
||||||
|
build_exe_options["includes"] = python_modules
|
||||||
|
build_exe_options["excludes"] = ["setuptools", "tkinter", "pkg_resources"]
|
||||||
|
|
||||||
|
# Set options
|
||||||
|
build_options["build_exe"] = build_exe_options
|
||||||
|
|
||||||
|
setup(name = 'Rare',
|
||||||
|
version = __version__,
|
||||||
|
description = 'A gui for Legendary.',
|
||||||
|
options = build_options,
|
||||||
|
executables = [
|
||||||
|
Executable('rare/__main__.py',
|
||||||
|
targetName=name,
|
||||||
|
icon='rare/styles/Logo.ico',
|
||||||
|
base=base,
|
||||||
|
shortcutName=shortcutName,
|
||||||
|
shortcutDir=shortcutDir,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
|
@ -1,5 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
__version__ = "1.3.0"
|
__version__ = "1.4.1"
|
||||||
style_path = os.path.join(os.path.dirname(__file__), "styles/")
|
style_path = os.path.join(os.path.dirname(__file__), "styles/")
|
||||||
lang_path = os.path.join(os.path.dirname(__file__), "languages/")
|
lang_path = os.path.join(os.path.dirname(__file__), "languages/")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import configparser
|
import configparser
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -16,7 +15,7 @@ from rare.components.main_window import MainWindow
|
||||||
from rare.components.tray_icon import TrayIcon
|
from rare.components.tray_icon import TrayIcon
|
||||||
from rare.utils.utils import get_lang, load_color_scheme
|
from rare.utils.utils import get_lang, load_color_scheme
|
||||||
|
|
||||||
start_time = time.strftime('%y-%m-%d--%H:%M') # year-month-day-hour-minute
|
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")
|
file_name = os.path.expanduser(f"~/.cache/rare/logs/Rare_{start_time}.log")
|
||||||
if not os.path.exists(os.path.dirname(file_name)):
|
if not os.path.exists(os.path.dirname(file_name)):
|
||||||
os.makedirs(os.path.dirname(file_name))
|
os.makedirs(os.path.dirname(file_name))
|
||||||
|
|
|
@ -3,9 +3,14 @@ import webbrowser
|
||||||
from PyQt5.QtCore import QSize, pyqtSignal
|
from PyQt5.QtCore import QSize, pyqtSignal
|
||||||
from PyQt5.QtWidgets import QMenu, QTabWidget, QWidget, QWidgetAction
|
from PyQt5.QtWidgets import QMenu, QTabWidget, QWidget, QWidgetAction
|
||||||
from qtawesome import icon
|
from qtawesome import icon
|
||||||
|
from rare.utils import legendary_utils
|
||||||
|
|
||||||
from custom_legendary.core import LegendaryCore
|
from custom_legendary.core import LegendaryCore
|
||||||
|
|
||||||
from rare.components.dialogs.install_dialog import InstallDialog
|
from rare.components.dialogs.install_dialog import InstallDialog
|
||||||
|
|
||||||
|
from rare.components.dialogs.uninstall_dialog import UninstallDialog
|
||||||
|
|
||||||
from rare.components.tab_utils import TabBar, TabButtonWidget
|
from rare.components.tab_utils import TabBar, TabButtonWidget
|
||||||
from rare.components.tabs.account import MiniWidget
|
from rare.components.tabs.account import MiniWidget
|
||||||
from rare.components.tabs.cloud_saves import SyncSaves
|
from rare.components.tabs.cloud_saves import SyncSaves
|
||||||
|
@ -64,6 +69,12 @@ class TabWidget(QTabWidget):
|
||||||
# open download tab
|
# open download tab
|
||||||
self.games_tab.default_widget.game_list.update_game.connect(lambda: self.setCurrentIndex(1))
|
self.games_tab.default_widget.game_list.update_game.connect(lambda: self.setCurrentIndex(1))
|
||||||
|
|
||||||
|
# uninstall
|
||||||
|
self.games_tab.game_info.info.uninstall_game.connect(self.uninstall_game)
|
||||||
|
|
||||||
|
# imported
|
||||||
|
self.games_tab.import_widget.update_list.connect(self.game_imported)
|
||||||
|
|
||||||
if not offline:
|
if not offline:
|
||||||
# Download finished
|
# Download finished
|
||||||
self.downloadTab.finished.connect(self.dl_finished)
|
self.downloadTab.finished.connect(self.dl_finished)
|
||||||
|
@ -87,6 +98,7 @@ class TabWidget(QTabWidget):
|
||||||
self.tabBarClicked.connect(lambda x: self.games_tab.layout.setCurrentIndex(0) if x == 0 else None)
|
self.tabBarClicked.connect(lambda x: self.games_tab.layout.setCurrentIndex(0) if x == 0 else None)
|
||||||
self.setIconSize(QSize(25, 25))
|
self.setIconSize(QSize(25, 25))
|
||||||
|
|
||||||
|
|
||||||
def install_game(self, app_name, disable_path=False):
|
def install_game(self, app_name, disable_path=False):
|
||||||
|
|
||||||
infos = InstallDialog(app_name, self.core, disable_path).get_information()
|
infos = InstallDialog(app_name, self.core, disable_path).get_information()
|
||||||
|
@ -102,16 +114,38 @@ class TabWidget(QTabWidget):
|
||||||
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
||||||
self.downloadTab.install_game(options)
|
self.downloadTab.install_game(options)
|
||||||
|
|
||||||
|
def game_imported(self, app_name: str):
|
||||||
|
igame = self.core.get_installed_game(app_name)
|
||||||
|
if self.core.get_asset(app_name, True).build_version != igame.version:
|
||||||
|
self.downloadTab.add_update(igame)
|
||||||
|
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys())
|
||||||
|
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
||||||
|
self.games_tab.default_widget.game_list.update_list(app_name)
|
||||||
|
self.games_tab.layout.setCurrentIndex(0)
|
||||||
|
|
||||||
# Sync game and delete dc rpc
|
# Sync game and delete dc rpc
|
||||||
def game_finished(self, app_name):
|
def game_finished(self, app_name):
|
||||||
self.delete_presence.emit()
|
self.delete_presence.emit()
|
||||||
if self.core.get_game(app_name).supports_cloud_saves:
|
if self.core.get_game(app_name).supports_cloud_saves:
|
||||||
self.cloud_saves.sync_game(app_name, True)
|
self.cloud_saves.sync_game(app_name, True)
|
||||||
|
|
||||||
|
def uninstall_game(self, app_name):
|
||||||
|
game = self.core.get_game(app_name)
|
||||||
|
infos = UninstallDialog(game).get_information()
|
||||||
|
if infos == 0:
|
||||||
|
return
|
||||||
|
legendary_utils.uninstall(game.app_name, self.core, infos)
|
||||||
|
if app_name in self.downloadTab.update_widgets.keys():
|
||||||
|
self.downloadTab.update_layout.removeWidget(self.downloadTab.update_widgets[app_name])
|
||||||
|
self.downloadTab.update_widgets.pop(app_name)
|
||||||
|
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys())
|
||||||
|
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
||||||
|
self.downloadTab.update_text.setVisible(len(self.downloadTab.update_widgets) == 0)
|
||||||
# Update gamelist and set text of Downlaods to "Downloads"
|
# Update gamelist and set text of Downlaods to "Downloads"
|
||||||
|
|
||||||
def dl_finished(self, update_list):
|
def dl_finished(self, update_list):
|
||||||
if update_list:
|
if update_list[0]:
|
||||||
self.games_tab.default_widget.game_list.update_list()
|
self.games_tab.default_widget.game_list.update_list(update_list[1])
|
||||||
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys())
|
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys())
|
||||||
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else ""))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
|
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QSettings
|
||||||
from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QLabel, QGroupBox
|
from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QLabel, QGroupBox
|
||||||
|
|
||||||
from custom_legendary.core import LegendaryCore
|
from custom_legendary.core import LegendaryCore
|
||||||
|
@ -167,6 +167,11 @@ class SyncWidget(QGroupBox):
|
||||||
self.layout.addStretch(1)
|
self.layout.addStretch(1)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
if self.res == SaveGameStatus.REMOTE_NEWER:
|
||||||
|
settings = QSettings()
|
||||||
|
if settings.value(f"{igame.app_name}/auto_sync_cloud", False, bool):
|
||||||
|
self.download()
|
||||||
|
|
||||||
def change_path(self):
|
def change_path(self):
|
||||||
path = PathInputDialog("Select directory", "Select savepath. Warning: Do not change if you are not sure",
|
path = PathInputDialog("Select directory", "Select savepath. Warning: Do not change if you are not sure",
|
||||||
self.igame.save_path).get_path()
|
self.igame.save_path).get_path()
|
||||||
|
|
|
@ -20,7 +20,7 @@ logger = getLogger("Download")
|
||||||
|
|
||||||
|
|
||||||
class DownloadTab(QWidget):
|
class DownloadTab(QWidget):
|
||||||
finished = pyqtSignal(bool)
|
finished = pyqtSignal(tuple)
|
||||||
thread: QThread
|
thread: QThread
|
||||||
dl_queue = []
|
dl_queue = []
|
||||||
|
|
||||||
|
@ -75,18 +75,22 @@ class DownloadTab(QWidget):
|
||||||
self.update_text.setVisible(len(updates) == 0)
|
self.update_text.setVisible(len(updates) == 0)
|
||||||
|
|
||||||
for igame in updates:
|
for igame in updates:
|
||||||
widget = UpdateWidget(core, igame, self)
|
|
||||||
self.update_layout.addWidget(widget)
|
self.add_update(igame)
|
||||||
self.update_widgets[igame.app_name] = widget
|
|
||||||
widget.update_signal.connect(self.update_game)
|
|
||||||
if QSettings().value("auto_update", False, bool):
|
|
||||||
self.update_game(igame.app_name, True)
|
|
||||||
widget.update_button.setDisabled(True)
|
|
||||||
|
|
||||||
self.layout.addStretch(1)
|
self.layout.addStretch(1)
|
||||||
|
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
def add_update(self, igame: InstalledGame):
|
||||||
|
widget = UpdateWidget(self.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)
|
||||||
|
|
||||||
def update_dl_queue(self, dl_queue):
|
def update_dl_queue(self, dl_queue):
|
||||||
self.dl_queue = dl_queue
|
self.dl_queue = dl_queue
|
||||||
|
|
||||||
|
@ -135,7 +139,7 @@ class DownloadTab(QWidget):
|
||||||
# Information
|
# Information
|
||||||
if not from_update:
|
if not from_update:
|
||||||
if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept():
|
if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept():
|
||||||
self.finished.emit(False)
|
self.finished.emit(False, None)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.active_game is None:
|
if self.active_game is None:
|
||||||
|
@ -213,23 +217,25 @@ class DownloadTab(QWidget):
|
||||||
# QMessageBox.information(self, "Info", "Download finished")
|
# QMessageBox.information(self, "Info", "Download finished")
|
||||||
logger.info("Download finished: " + self.active_game.app_title)
|
logger.info("Download finished: " + self.active_game.app_title)
|
||||||
|
|
||||||
|
app_name = self.active_game.app_name
|
||||||
|
self.active_game = None
|
||||||
|
|
||||||
if self.dl_queue:
|
if self.dl_queue:
|
||||||
if self.dl_queue[0][1] == self.active_game.app_name:
|
if self.dl_queue[0][1] == app_name:
|
||||||
self.dl_queue.pop(0)
|
self.dl_queue.pop(0)
|
||||||
self.queue_widget.update_queue(self.dl_queue)
|
self.queue_widget.update_queue(self.dl_queue)
|
||||||
|
|
||||||
if self.active_game.app_name in self.update_widgets.keys():
|
if app_name in self.update_widgets.keys():
|
||||||
self.update_widgets[self.active_game.app_name].setVisible(False)
|
self.update_widgets[app_name].setVisible(False)
|
||||||
self.update_widgets.pop(self.active_game.app_name)
|
self.update_widgets.pop(app_name)
|
||||||
if len(self.update_widgets) == 0:
|
if len(self.update_widgets) == 0:
|
||||||
self.update_text.setVisible(True)
|
self.update_text.setVisible(True)
|
||||||
|
|
||||||
self.active_game = None
|
|
||||||
|
|
||||||
for i in self.update_widgets.values():
|
for i in self.update_widgets.values():
|
||||||
i.update_button.setDisabled(False)
|
i.update_button.setDisabled(False)
|
||||||
|
|
||||||
self.finished.emit(True)
|
self.finished.emit((True, app_name))
|
||||||
|
|
||||||
self.reset_infos()
|
self.reset_infos()
|
||||||
|
|
||||||
if len(self.dl_queue) != 0:
|
if len(self.dl_queue) != 0:
|
||||||
|
@ -243,7 +249,7 @@ class DownloadTab(QWidget):
|
||||||
elif text == "stop":
|
elif text == "stop":
|
||||||
self.reset_infos()
|
self.reset_infos()
|
||||||
self.active_game = None
|
self.active_game = None
|
||||||
self.finished.emit(False)
|
self.finished.emit((False, None))
|
||||||
if self.dl_queue:
|
if self.dl_queue:
|
||||||
self.start_installation(*self.dl_queue[0])
|
self.start_installation(*self.dl_queue[0])
|
||||||
|
|
||||||
|
@ -302,6 +308,7 @@ class UpdateWidget(QWidget):
|
||||||
self.update_with_settings.clicked.connect(lambda: self.update_game(False))
|
self.update_with_settings.clicked.connect(lambda: self.update_game(False))
|
||||||
self.layout.addWidget(self.update_button)
|
self.layout.addWidget(self.update_button)
|
||||||
self.layout.addWidget(self.update_with_settings)
|
self.layout.addWidget(self.update_with_settings)
|
||||||
|
self.layout.addWidget(QLabel(self.tr("Version: ") + self.game.version + " -> " + self.core.get_asset(self.game.app_name, True).build_version))
|
||||||
|
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from PyQt5.QtCore import QSettings, QSize
|
from PyQt5.QtCore import QSettings, QSize, pyqtSignal
|
||||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineEdit, QPushButton, QStackedLayout, QLabel
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QStackedLayout, \
|
||||||
|
QLabel, QComboBox
|
||||||
from qtawesome import icon
|
from qtawesome import icon
|
||||||
|
|
||||||
from rare.components.tabs.games.game_info import InfoTabs
|
from rare.components.tabs.games.game_info import InfoTabs
|
||||||
|
@ -36,8 +37,8 @@ class GameTab(QWidget):
|
||||||
|
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
def update_list(self):
|
def update_list(self, app_name=None):
|
||||||
self.default_widget.game_list.update_list(self.default_widget.head_bar.view.isChecked())
|
self.default_widget.game_list.update_list(app_name)
|
||||||
self.layout.setCurrentIndex(0)
|
self.layout.setCurrentIndex(0)
|
||||||
|
|
||||||
def show_uninstalled(self, app_name):
|
def show_uninstalled(self, app_name):
|
||||||
|
@ -62,11 +63,10 @@ class Games(QWidget):
|
||||||
self.game_list = GameList(core, self, offline)
|
self.game_list = GameList(core, self, offline)
|
||||||
|
|
||||||
self.head_bar.search_bar.textChanged.connect(
|
self.head_bar.search_bar.textChanged.connect(
|
||||||
lambda: self.game_list.filter(self.head_bar.search_bar.text()))
|
lambda: self.game_list.search(self.head_bar.search_bar.text()))
|
||||||
|
|
||||||
|
self.head_bar.filter_changed_signal.connect(self.game_list.filter)
|
||||||
|
|
||||||
self.head_bar.installed_only.stateChanged.connect(lambda:
|
|
||||||
self.game_list.installed_only(
|
|
||||||
self.head_bar.installed_only.isChecked()))
|
|
||||||
self.layout.addWidget(self.head_bar)
|
self.layout.addWidget(self.head_bar)
|
||||||
self.layout.addWidget(self.game_list)
|
self.layout.addWidget(self.game_list)
|
||||||
# self.layout.addStretch(1)
|
# self.layout.addStretch(1)
|
||||||
|
@ -81,14 +81,23 @@ class Games(QWidget):
|
||||||
|
|
||||||
|
|
||||||
class GameListHeadBar(QWidget):
|
class GameListHeadBar(QWidget):
|
||||||
|
filter_changed_signal = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super(GameListHeadBar, self).__init__(parent=parent)
|
super(GameListHeadBar, self).__init__(parent=parent)
|
||||||
self.layout = QHBoxLayout()
|
self.layout = QHBoxLayout()
|
||||||
self.installed_only = QCheckBox(self.tr("Installed only"))
|
# self.installed_only = QCheckBox(self.tr("Installed only"))
|
||||||
self.settings = QSettings()
|
self.settings = QSettings()
|
||||||
self.installed_only.setChecked(self.settings.value("installed_only", False, bool))
|
# self.installed_only.setChecked(self.settings.value("installed_only", False, bool))
|
||||||
self.layout.addWidget(self.installed_only)
|
# self.layout.addWidget(self.installed_only)
|
||||||
|
|
||||||
|
self.filter = QComboBox()
|
||||||
|
self.filter.addItems([self.tr("All"),
|
||||||
|
self.tr("Installed only"),
|
||||||
|
self.tr("Offline Games"),
|
||||||
|
self.tr("32 Bit Games")])
|
||||||
|
self.filter.currentIndexChanged.connect(self.filter_changed)
|
||||||
|
self.layout.addWidget(self.filter)
|
||||||
self.layout.addStretch(1)
|
self.layout.addStretch(1)
|
||||||
|
|
||||||
self.import_game = QPushButton(icon("mdi.import", color="white"), self.tr("Import Game"))
|
self.import_game = QPushButton(icon("mdi.import", color="white"), self.tr("Import Game"))
|
||||||
|
@ -118,3 +127,6 @@ class GameListHeadBar(QWidget):
|
||||||
self.layout.addWidget(self.refresh_list)
|
self.layout.addWidget(self.refresh_list)
|
||||||
|
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
def filter_changed(self, i):
|
||||||
|
self.filter_changed_signal.emit(["", "installed", "offline", "32bit"][i])
|
||||||
|
|
|
@ -59,7 +59,8 @@ class InfoTabs(QTabWidget):
|
||||||
class GameInfo(QWidget, Ui_GameInfo):
|
class GameInfo(QWidget, Ui_GameInfo):
|
||||||
igame: InstalledGame
|
igame: InstalledGame
|
||||||
game: Game
|
game: Game
|
||||||
update_list = pyqtSignal()
|
uninstall_game = pyqtSignal(str)
|
||||||
|
update_list = pyqtSignal(str)
|
||||||
verify_game = pyqtSignal(str)
|
verify_game = pyqtSignal(str)
|
||||||
verify_threads = {}
|
verify_threads = {}
|
||||||
|
|
||||||
|
@ -87,12 +88,8 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
self.repair_button.clicked.connect(self.repair)
|
self.repair_button.clicked.connect(self.repair)
|
||||||
|
|
||||||
def uninstall(self):
|
def uninstall(self):
|
||||||
infos = UninstallDialog(self.game).get_information()
|
self.uninstall_game.emit(self.game.app_name)
|
||||||
if infos == 0:
|
self.update_list.emit(self.game.app_name)
|
||||||
print("Cancel Uninstall")
|
|
||||||
return
|
|
||||||
legendary_utils.uninstall(self.game.app_name, self.core, infos)
|
|
||||||
self.update_list.emit()
|
|
||||||
|
|
||||||
def repair(self):
|
def repair(self):
|
||||||
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f'{self.game.app_name}.repair')
|
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f'{self.game.app_name}.repair')
|
||||||
|
|
|
@ -4,9 +4,10 @@ from logging import getLogger
|
||||||
import psutil
|
import psutil
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal, QSettings, QTimer
|
from PyQt5.QtCore import Qt, pyqtSignal, QSettings, QTimer
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import QScrollArea, QWidget, QLabel, QVBoxLayout, QStackedWidget
|
||||||
|
|
||||||
from custom_legendary.core import LegendaryCore
|
from custom_legendary.core import LegendaryCore
|
||||||
|
from rare.components.tabs.games.game_widgets.base_installed_widget import BaseInstalledWidget
|
||||||
from rare.components.tabs.games.game_widgets.installed_icon_widget import GameWidgetInstalled
|
from rare.components.tabs.games.game_widgets.installed_icon_widget import GameWidgetInstalled
|
||||||
from rare.components.tabs.games.game_widgets.installed_list_widget import InstalledListWidget
|
from rare.components.tabs.games.game_widgets.installed_list_widget import InstalledListWidget
|
||||||
from rare.components.tabs.games.game_widgets.uninstalled_icon_widget import IconWidgetUninstalled
|
from rare.components.tabs.games.game_widgets.uninstalled_icon_widget import IconWidgetUninstalled
|
||||||
|
@ -63,93 +64,36 @@ class GameList(QStackedWidget):
|
||||||
self.list_layout = QVBoxLayout()
|
self.list_layout = QVBoxLayout()
|
||||||
self.list_layout.addWidget(QLabel(self.info_text))
|
self.list_layout.addWidget(QLabel(self.info_text))
|
||||||
|
|
||||||
IMAGE_DIR = self.settings.value("img_dir", os.path.expanduser("~/.cache/rare/images"), str)
|
self.IMAGE_DIR = self.settings.value("img_dir", os.path.expanduser("~/.cache/rare/images"), str)
|
||||||
self.updates = []
|
self.updates = []
|
||||||
self.widgets = {}
|
self.widgets = {}
|
||||||
|
|
||||||
|
self.bit32 = [i.app_name for i in self.core.get_game_and_dlc_list(True, "Win32")[0]]
|
||||||
|
self.mac_games = [i.app_name for i in self.core.get_game_and_dlc_list(True, "Mac")[0]]
|
||||||
self.installed = sorted(self.core.get_installed_list(), key=lambda x: x.title)
|
self.installed = sorted(self.core.get_installed_list(), key=lambda x: x.title)
|
||||||
|
|
||||||
# Installed Games
|
# Installed Games
|
||||||
for igame in self.installed:
|
for igame in self.installed:
|
||||||
if os.path.exists(f"{IMAGE_DIR}/{igame.app_name}/FinalArt.png"):
|
icon_widget, list_widget = self.add_installed_widget(igame)
|
||||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/FinalArt.png")
|
|
||||||
elif os.path.exists(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png"):
|
|
||||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
|
|
||||||
elif os.path.exists(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxLogo.png"):
|
|
||||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxLogo.png")
|
|
||||||
else:
|
|
||||||
logger.warning(f"No Image found: {igame.title}")
|
|
||||||
pixmap = None
|
|
||||||
|
|
||||||
if pixmap.isNull():
|
|
||||||
logger.info(igame.title + " has a corrupt image.")
|
|
||||||
download_image(igame, force=True)
|
|
||||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
|
|
||||||
|
|
||||||
icon_widget = GameWidgetInstalled(igame, self.core, pixmap, self.offline)
|
|
||||||
self.icon_layout.addWidget(icon_widget)
|
self.icon_layout.addWidget(icon_widget)
|
||||||
|
|
||||||
list_widget = InstalledListWidget(igame, self.core, pixmap, self.offline)
|
|
||||||
self.list_layout.addWidget(list_widget)
|
self.list_layout.addWidget(list_widget)
|
||||||
|
|
||||||
icon_widget.show_info.connect(self.show_game_info.emit)
|
self.uninstalled_names = []
|
||||||
list_widget.show_info.connect(self.show_game_info.emit)
|
|
||||||
|
|
||||||
icon_widget.launch_signal.connect(self.launch)
|
|
||||||
icon_widget.finish_signal.connect(self.finished)
|
|
||||||
icon_widget.update_list.connect(lambda: self.update_list(self.settings.value("icon_view", True, bool)))
|
|
||||||
list_widget.launch_signal.connect(self.launch)
|
|
||||||
list_widget.finish_signal.connect(self.finished)
|
|
||||||
list_widget.update_list.connect(lambda: self.update_list(self.settings.value("icon_view", True, bool)))
|
|
||||||
|
|
||||||
if icon_widget.update_available:
|
|
||||||
self.updates.append(igame)
|
|
||||||
|
|
||||||
self.widgets[igame.app_name] = (icon_widget, list_widget)
|
|
||||||
active, pid = self.check_for_active_game(igame)
|
|
||||||
if active:
|
|
||||||
# Only one game works: Workaround for Satisfactory EA and Exp.
|
|
||||||
self.launch(igame.app_name)
|
|
||||||
icon_widget.game_running = True
|
|
||||||
list_widget.game_running = True
|
|
||||||
self.active_game = (igame.app_name, pid)
|
|
||||||
self.timer = QTimer()
|
|
||||||
self.timer.timeout.connect(self.is_finished)
|
|
||||||
self.timer.start(10000)
|
|
||||||
|
|
||||||
self.uninstalled_games = []
|
|
||||||
installed = [i.app_name for i in self.core.get_installed_list()]
|
installed = [i.app_name for i in self.core.get_installed_list()]
|
||||||
# get Uninstalled games
|
# get Uninstalled games
|
||||||
games, self.dlcs = self.core.get_game_and_dlc_list()
|
games, self.dlcs = self.core.get_game_and_dlc_list()
|
||||||
for game in sorted(games, key=lambda x: x.app_title):
|
for game in sorted(games, key=lambda x: x.app_title):
|
||||||
if not game.app_name in installed:
|
if not game.app_name in installed:
|
||||||
self.uninstalled_games.append(game)
|
self.uninstalled_names.append(game)
|
||||||
|
|
||||||
# add uninstalled games
|
# add 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")
|
|
||||||
|
|
||||||
if pixmap.isNull():
|
for game in self.uninstalled_games:
|
||||||
logger.info(igame.app_title + " has a corrupt image.")
|
icon_widget, list_widget = self.add_uninstalled_widget(game)
|
||||||
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)
|
|
||||||
pixmap = QPixmap(f"{IMAGE_DIR}/{igame.app_name}/UninstalledArt.png")
|
|
||||||
|
|
||||||
icon_widget = IconWidgetUninstalled(igame, self.core, pixmap)
|
|
||||||
icon_widget.show_uninstalled_info.connect(self.install)
|
|
||||||
|
|
||||||
list_widget = ListWidgetUninstalled(self.core, igame, pixmap)
|
|
||||||
list_widget.show_uninstalled_info.connect(self.install)
|
|
||||||
|
|
||||||
self.icon_layout.addWidget(icon_widget)
|
self.icon_layout.addWidget(icon_widget)
|
||||||
self.list_layout.addWidget(list_widget)
|
self.list_layout.addWidget(list_widget)
|
||||||
|
|
||||||
self.widgets[igame.app_name] = (icon_widget, list_widget)
|
|
||||||
|
|
||||||
self.icon_parent_layout.addLayout(self.icon_layout)
|
self.icon_parent_layout.addLayout(self.icon_layout)
|
||||||
self.icon_parent_layout.addStretch(1)
|
self.icon_parent_layout.addStretch(1)
|
||||||
self.list_layout.addStretch(1)
|
self.list_layout.addStretch(1)
|
||||||
|
@ -165,8 +109,81 @@ class GameList(QStackedWidget):
|
||||||
if not icon_view:
|
if not icon_view:
|
||||||
self.setCurrentIndex(1)
|
self.setCurrentIndex(1)
|
||||||
|
|
||||||
if self.settings.value("installed_only", False, bool):
|
if filter_games := self.settings.value("filter", "", str):
|
||||||
self.installed_only(True)
|
self.filter(filter_games)
|
||||||
|
|
||||||
|
def add_uninstalled_widget(self, game):
|
||||||
|
if os.path.exists(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png"):
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
|
||||||
|
|
||||||
|
if pixmap.isNull():
|
||||||
|
logger.info(game.app_title + " has a corrupt image.")
|
||||||
|
download_image(game, force=True)
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
|
||||||
|
else:
|
||||||
|
logger.warning(f"No Image found: {game.app_title}")
|
||||||
|
download_image(game, force=True)
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{game.app_name}/UninstalledArt.png")
|
||||||
|
|
||||||
|
icon_widget = IconWidgetUninstalled(game, self.core, pixmap)
|
||||||
|
icon_widget.install_game.connect(self.install)
|
||||||
|
|
||||||
|
list_widget = ListWidgetUninstalled(self.core, game, pixmap)
|
||||||
|
list_widget.install_game.connect(self.install)
|
||||||
|
|
||||||
|
self.widgets[game.app_name] = (icon_widget, list_widget)
|
||||||
|
|
||||||
|
return icon_widget, list_widget
|
||||||
|
|
||||||
|
def add_installed_widget(self, igame):
|
||||||
|
if os.path.exists(f"{self.IMAGE_DIR}/{igame.app_name}/FinalArt.png"):
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/FinalArt.png")
|
||||||
|
elif os.path.exists(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png"):
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
|
||||||
|
elif os.path.exists(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxLogo.png"):
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxLogo.png")
|
||||||
|
else:
|
||||||
|
logger.warning(f"No Image found: {igame.title}")
|
||||||
|
pixmap = None
|
||||||
|
|
||||||
|
if pixmap.isNull():
|
||||||
|
logger.info(igame.title + " has a corrupt image.")
|
||||||
|
download_image(igame, force=True)
|
||||||
|
pixmap = QPixmap(f"{self.IMAGE_DIR}/{igame.app_name}/DieselGameBoxTall.png")
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.widgets[igame.app_name] = (icon_widget, list_widget)
|
||||||
|
|
||||||
|
icon_widget.show_info.connect(self.show_game_info.emit)
|
||||||
|
list_widget.show_info.connect(self.show_game_info.emit)
|
||||||
|
|
||||||
|
icon_widget.launch_signal.connect(self.launch)
|
||||||
|
icon_widget.finish_signal.connect(self.finished)
|
||||||
|
icon_widget.update_list.connect(self.update_list)
|
||||||
|
list_widget.launch_signal.connect(self.launch)
|
||||||
|
list_widget.finish_signal.connect(self.finished)
|
||||||
|
list_widget.update_list.connect(self.update_list)
|
||||||
|
|
||||||
|
if icon_widget.update_available:
|
||||||
|
self.updates.append(igame)
|
||||||
|
|
||||||
|
active, pid = self.check_for_active_game(igame)
|
||||||
|
if active:
|
||||||
|
# Only one game works: Workaround for Satisfactory EA and Exp.
|
||||||
|
self.launch(igame.app_name)
|
||||||
|
icon_widget.game_running = True
|
||||||
|
list_widget.game_running = True
|
||||||
|
self.active_game = (igame.app_name, pid)
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.timeout.connect(self.is_finished)
|
||||||
|
self.timer.start(10000)
|
||||||
|
|
||||||
|
return icon_widget, list_widget
|
||||||
|
|
||||||
def is_finished(self):
|
def is_finished(self):
|
||||||
if psutil.pid_exists(self.active_game[1]):
|
if psutil.pid_exists(self.active_game[1]):
|
||||||
|
@ -226,7 +243,7 @@ class GameList(QStackedWidget):
|
||||||
self.widgets[app_name][1].launch_button.setDisabled(True)
|
self.widgets[app_name][1].launch_button.setDisabled(True)
|
||||||
self.widgets[app_name][1].launch_button.setText(self.tr("Game running"))
|
self.widgets[app_name][1].launch_button.setText(self.tr("Game running"))
|
||||||
|
|
||||||
def filter(self, text: str):
|
def search(self, text: str):
|
||||||
for t in self.widgets.values():
|
for t in self.widgets.values():
|
||||||
for w in t:
|
for w in t:
|
||||||
if text.lower() in w.game.app_title.lower() + w.game.app_name.lower():
|
if text.lower() in w.game.app_title.lower() + w.game.app_name.lower():
|
||||||
|
@ -234,31 +251,151 @@ class GameList(QStackedWidget):
|
||||||
else:
|
else:
|
||||||
w.setVisible(False)
|
w.setVisible(False)
|
||||||
|
|
||||||
def installed_only(self, i_o: bool):
|
def filter(self, filter="installed"):
|
||||||
for t in self.widgets.values():
|
for t in self.widgets.values():
|
||||||
for w in t:
|
for w in t:
|
||||||
w.setVisible(not (not self.core.is_installed(w.game.app_name) and i_o))
|
if filter == "installed":
|
||||||
self.settings.setValue("installed_only", i_o)
|
w.setVisible(self.core.is_installed(w.game.app_name))
|
||||||
|
elif filter == "offline":
|
||||||
|
if self.core.is_installed(w.game.app_name):
|
||||||
|
w.setVisible(w.igame.can_run_offline)
|
||||||
|
else:
|
||||||
|
w.setVisible(False)
|
||||||
|
elif filter == "32bit":
|
||||||
|
w.setVisible(w.game.app_name in self.bit32)
|
||||||
|
elif filter == "mac":
|
||||||
|
w.setVisible(w.game.app_name in self.mac_games)
|
||||||
|
else:
|
||||||
|
# All visible
|
||||||
|
w.setVisible(True)
|
||||||
|
self.settings.setValue("filter", filter)
|
||||||
|
|
||||||
def update_list(self, icon_view=True):
|
def update_list(self, app_name=None):
|
||||||
self.settings.setValue("icon_view", icon_view)
|
# self.settings.setValue("icon_view", icon_view)
|
||||||
|
if app_name:
|
||||||
|
if widgets := self.widgets.get(app_name):
|
||||||
|
|
||||||
uninstalled_games = []
|
# from update
|
||||||
installed = [i.app_name for i in self.core.get_installed_list()]
|
if self.core.is_installed(widgets[0].game.app_name) and isinstance(widgets[0], BaseInstalledWidget):
|
||||||
# get Uninstalled games
|
igame = self.core.get_installed_game(app_name)
|
||||||
games = self.core.get_game_list(True)
|
for w in widgets:
|
||||||
for game in sorted(games, key=lambda x: x.app_title):
|
w.igame = igame
|
||||||
if not game.app_name in installed:
|
w.update_available = self.core.get_asset(w.game.app_name, True).build_version != igame.version
|
||||||
uninstalled_games.append(game.app_name)
|
widgets[0].info_label.setText("")
|
||||||
|
widgets[0].info_text = ""
|
||||||
|
# new installed
|
||||||
|
elif self.core.is_installed(widgets[0].game.app_name) and not isinstance(widgets[0], BaseInstalledWidget):
|
||||||
|
self.widgets.pop(widgets[0].game.app_name)
|
||||||
|
|
||||||
# get new uninstalled/ installed games that changed
|
# QWidget().setLayout(self.icon_layout)
|
||||||
new_installed_games = list(set(installed) - set([i.app_name for i in self.installed]))
|
icon_layout = FlowLayout()
|
||||||
new_uninstalled_games = list(set(uninstalled_games) - set([i.app_name for i in self.uninstalled_games]))
|
|
||||||
|
# QWidget().setLayout(self.list_layout)
|
||||||
|
list_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
igame = self.core.get_installed_game(app_name)
|
||||||
|
self.add_installed_widget(igame)
|
||||||
|
|
||||||
|
for igame in sorted(self.core.get_installed_list(), key=lambda x: x.title):
|
||||||
|
i_widget, l_widget = self.widgets[igame.app_name]
|
||||||
|
icon_layout.addWidget(i_widget)
|
||||||
|
list_layout.addWidget(l_widget)
|
||||||
|
|
||||||
|
self.uninstalled_names = []
|
||||||
|
installed_names = [i.app_name for i in self.core.get_installed_list()]
|
||||||
|
# get Uninstalled games
|
||||||
|
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_names:
|
||||||
|
self.uninstalled_names.append(game)
|
||||||
|
for game in self.uninstalled_names:
|
||||||
|
i_widget, list_widget = self.widgets[game.app_name]
|
||||||
|
icon_layout.addWidget(i_widget)
|
||||||
|
list_layout.addWidget(list_widget)
|
||||||
|
|
||||||
|
QWidget().setLayout(self.icon_layout)
|
||||||
|
QWidget().setLayout(self.list_layout)
|
||||||
|
|
||||||
|
self.icon_widget = QWidget()
|
||||||
|
self.list_widget = QWidget()
|
||||||
|
|
||||||
|
self.icon_widget.setLayout(icon_layout)
|
||||||
|
self.list_widget.setLayout(list_layout)
|
||||||
|
|
||||||
|
self.list_scrollarea.setWidget(QWidget())
|
||||||
|
self.icon_scrollarea.setWidget(QWidget())
|
||||||
|
|
||||||
|
self.icon_scrollarea.setWidget(self.icon_widget)
|
||||||
|
self.list_scrollarea.setWidget(self.list_widget)
|
||||||
|
|
||||||
|
self.icon_layout = icon_layout
|
||||||
|
self.list_layout = list_layout
|
||||||
|
|
||||||
|
self.icon_widget.setLayout(self.icon_layout)
|
||||||
|
self.list_widget.setLayout(self.list_layout)
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
# uninstalled
|
||||||
|
elif not self.core.is_installed(widgets[0].game.app_name) and isinstance(widgets[0], BaseInstalledWidget):
|
||||||
|
self.list_layout.removeWidget(widgets[1])
|
||||||
|
self.icon_layout.removeWidget(widgets[0])
|
||||||
|
|
||||||
|
self.widgets.pop(app_name)
|
||||||
|
|
||||||
|
game = self.core.get_game(app_name, True)
|
||||||
|
self.add_uninstalled_widget(game)
|
||||||
|
|
||||||
|
self.icon_layout.addWidget(self.widgets[app_name][0])
|
||||||
|
self.list_layout.addWidget(self.widgets[app_name][1])
|
||||||
|
else:
|
||||||
|
installed_names = [i.app_name for i in self.core.get_installed_list()]
|
||||||
|
# get Uninstalled games
|
||||||
|
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_names:
|
||||||
|
uninstalled_games.append(game.app_name)
|
||||||
|
|
||||||
|
new_installed_games = list(set(installed_names) - 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_names]))
|
||||||
|
|
||||||
|
if (not new_uninstalled_games) and (not new_installed_games):
|
||||||
|
return
|
||||||
|
|
||||||
|
if new_installed_games:
|
||||||
|
for name in new_installed_games:
|
||||||
|
self.icon_layout.removeWidget(self.widgets[app_name][0])
|
||||||
|
self.list_layout.removeWidget(self.widgets[app_name][1])
|
||||||
|
|
||||||
|
self.widgets.pop(name)
|
||||||
|
|
||||||
|
igame = self.core.get_installed_game(name)
|
||||||
|
self.add_installed_widget(igame)
|
||||||
|
|
||||||
|
for name in new_uninstalled_games:
|
||||||
|
self.icon_layout.removeWidget(self.widgets[app_name][0])
|
||||||
|
self.list_layout.removeWidget(self.widgets[app_name][1])
|
||||||
|
|
||||||
|
self.widgets.pop(name)
|
||||||
|
|
||||||
|
game = self.core.get_game(name, True)
|
||||||
|
self.add_uninstalled_widget(game)
|
||||||
|
|
||||||
|
for igame in sorted(self.core.get_installed_list(), key=lambda x: x.title):
|
||||||
|
i_widget, list_widget = self.widgets[igame.app_name]
|
||||||
|
|
||||||
|
self.icon_layout.addWidget(i_widget)
|
||||||
|
self.list_layout.addWidget(list_widget)
|
||||||
|
|
||||||
|
# get Uninstalled games
|
||||||
|
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_names:
|
||||||
|
self.uninstalled_names.append(game)
|
||||||
|
for name in uninstalled_games:
|
||||||
|
i_widget, list_widget = self.widgets[name]
|
||||||
|
self.icon_layout.addWidget(i_widget)
|
||||||
|
self.list_layout.addWidget(list_widget)
|
||||||
|
|
||||||
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)
|
|
||||||
self.update()
|
|
||||||
|
|
|
@ -147,4 +147,4 @@ class BaseInstalledWidget(QGroupBox):
|
||||||
print("Cancel Uninstall")
|
print("Cancel Uninstall")
|
||||||
return
|
return
|
||||||
legendary_utils.uninstall(self.game.app_name, self.core, infos)
|
legendary_utils.uninstall(self.game.app_name, self.core, infos)
|
||||||
self.update_list.emit()
|
self.update_list.emit(self.game.app_name)
|
||||||
|
|
|
@ -14,7 +14,7 @@ logger = getLogger("GameWidgetInstalled")
|
||||||
|
|
||||||
|
|
||||||
class GameWidgetInstalled(BaseInstalledWidget):
|
class GameWidgetInstalled(BaseInstalledWidget):
|
||||||
update_list = pyqtSignal()
|
update_list = pyqtSignal(str)
|
||||||
show_info = pyqtSignal(str)
|
show_info = pyqtSignal(str)
|
||||||
update_game = pyqtSignal()
|
update_game = pyqtSignal()
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ logger = getLogger("Import")
|
||||||
|
|
||||||
|
|
||||||
class ImportWidget(QWidget):
|
class ImportWidget(QWidget):
|
||||||
update_list = pyqtSignal()
|
update_list = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, core: LegendaryCore, parent):
|
def __init__(self, core: LegendaryCore, parent):
|
||||||
super(ImportWidget, self).__init__(parent=parent)
|
super(ImportWidget, self).__init__(parent=parent)
|
||||||
|
@ -119,7 +119,7 @@ class ImportWidget(QWidget):
|
||||||
self.core.get_installed_game(app_name).title))
|
self.core.get_installed_game(app_name).title))
|
||||||
self.app_name_input.setText("")
|
self.app_name_input.setText("")
|
||||||
|
|
||||||
self.update_list.emit()
|
self.update_list.emit(app_name)
|
||||||
else:
|
else:
|
||||||
logger.warning("Failed to import" + app_name)
|
logger.warning("Failed to import" + app_name)
|
||||||
self.info_label.setText(self.tr("Failed to import {}").format(app_name))
|
self.info_label.setText(self.tr("Failed to import {}").format(app_name))
|
||||||
|
|
|
@ -1362,82 +1362,83 @@ Installationsgröße: {} GB</translation>
|
||||||
<context>
|
<context>
|
||||||
<name>RareSettings</name>
|
<name>RareSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="25"/>
|
<location filename="../components/tabs/settings/rare.py" line="27"/>
|
||||||
<source>Rare settings</source>
|
<source>Rare settings</source>
|
||||||
<translation type="obsolete">Rare Einstellungen</translation>
|
<translation type="obsolete">Rare Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="48"/>
|
<location filename="../components/tabs/settings/rare.py" line="51"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation type="obsolete">Speichern</translation>
|
<translation type="obsolete">Speichern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="50"/>
|
<location filename="../components/tabs/settings/rare.py" line="53"/>
|
||||||
<source>Image Directory</source>
|
<source>Image Directory</source>
|
||||||
<translation type="obsolete">Ordner für Bilder</translation>
|
<translation type="obsolete">Ordner für Bilder</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
|
||||||
<location filename="../ui/components/tabs/settings/rare.py" line="119"/>
|
<location filename="../ui/components/tabs/settings/rare.py" line="119"/>
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation>Sprache</translation>
|
<translation>Sprache</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="87"/>
|
<location filename="../components/tabs/settings/rare.py" line="102"/>
|
||||||
<source>Restart Application to activate changes</source>
|
<source>Restart Application to activate changes</source>
|
||||||
<translation type="obsolete">Starte die App neu um die Änderungen zu aktivieren</translation>
|
<translation type="obsolete">Starte die App neu um die Änderungen zu aktivieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="33"/>
|
<location filename="../components/tabs/settings/rare.py" line="36"/>
|
||||||
<source>Confirm launch of game</source>
|
<source>Confirm launch of game</source>
|
||||||
<translation type="obsolete">Start des Spiels bestätigen</translation>
|
<translation type="obsolete">Start des Spiels bestätigen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="30"/>
|
<location filename="../components/tabs/settings/rare.py" line="33"/>
|
||||||
<source>Exit to System Tray Icon</source>
|
<source>Exit to System Tray Icon</source>
|
||||||
<translation type="obsolete">Beim verlassen auf das System Tray Icon minimieren</translation>
|
<translation type="obsolete">Beim verlassen auf das System Tray Icon minimieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="30"/>
|
<location filename="../components/tabs/settings/rare.py" line="33"/>
|
||||||
<source>Hide to System Tray Icon</source>
|
<source>Hide to System Tray Icon</source>
|
||||||
<translation type="obsolete">In das System Tray Icon minimieren</translation>
|
<translation type="obsolete">In das System Tray Icon minimieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="35"/>
|
<location filename="../components/tabs/settings/rare.py" line="38"/>
|
||||||
<source>Auto sync with cloud</source>
|
<source>Auto sync with cloud</source>
|
||||||
<translation type="obsolete">Speicherstände automatisch mit der Cloud synchronisieren</translation>
|
<translation type="obsolete">Speicherstände automatisch mit der Cloud synchronisieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="35"/>
|
<location filename="../components/tabs/settings/rare.py" line="38"/>
|
||||||
<source>Sync with cloud</source>
|
<source>Sync with cloud</source>
|
||||||
<translation type="obsolete">Automatisch Synchronisieren</translation>
|
<translation type="obsolete">Automatisch Synchronisieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="38"/>
|
<location filename="../components/tabs/settings/rare.py" line="41"/>
|
||||||
<source>Save size</source>
|
<source>Save size</source>
|
||||||
<translation type="obsolete">Größe Speichern</translation>
|
<translation type="obsolete">Größe Speichern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="38"/>
|
<location filename="../components/tabs/settings/rare.py" line="41"/>
|
||||||
<source>Save size of window after restart</source>
|
<source>Save size of window after restart</source>
|
||||||
<translation type="obsolete">Die Fenstergröße nach dem Beenden speichern</translation>
|
<translation type="obsolete">Die Fenstergröße nach dem Beenden speichern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="31"/>
|
<location filename="../components/tabs/settings/rare.py" line="34"/>
|
||||||
<source>Automatically update Games on startup</source>
|
<source>Automatically update Games on startup</source>
|
||||||
<translation type="obsolete">Spiele automatisch updaten</translation>
|
<translation type="obsolete">Spiele automatisch updaten</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="31"/>
|
<location filename="../components/tabs/settings/rare.py" line="34"/>
|
||||||
<source>Auto updates</source>
|
<source>Auto updates</source>
|
||||||
<translation type="obsolete">Automatische Updates</translation>
|
<translation type="obsolete">Automatische Updates</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="36"/>
|
<location filename="../components/tabs/settings/rare.py" line="39"/>
|
||||||
<source>Show Notifications after Downloads</source>
|
<source>Show Notifications after Downloads</source>
|
||||||
<translation type="obsolete">Benachrichtigung nach Abschluss des Downloads anzeigen</translation>
|
<translation type="obsolete">Benachrichtigung nach Abschluss des Downloads anzeigen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/settings/rare.py" line="36"/>
|
<location filename="../components/tabs/settings/rare.py" line="39"/>
|
||||||
<source>Show notification</source>
|
<source>Show notification</source>
|
||||||
<translation type="obsolete">Benachrichtigung anzeigen</translation>
|
<translation type="obsolete">Benachrichtigung anzeigen</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -1526,6 +1527,11 @@ Installationsgröße: {} GB</translation>
|
||||||
<source>Behavior</source>
|
<source>Behavior</source>
|
||||||
<translation>Optionen</translation>
|
<translation>Optionen</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../components/tabs/settings/rare.py" line="76"/>
|
||||||
|
<source>Open Log directory</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SyncSaves</name>
|
<name>SyncSaves</name>
|
||||||
|
@ -1643,22 +1649,22 @@ Installationsgröße: {} GB</translation>
|
||||||
<translation>Pfad ändern</translation>
|
<translation>Pfad ändern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="181"/>
|
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="186"/>
|
||||||
<source>Uploading...</source>
|
<source>Uploading...</source>
|
||||||
<translation>Hochladen...</translation>
|
<translation>Hochladen...</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="189"/>
|
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="194"/>
|
||||||
<source>Upload finished</source>
|
<source>Upload finished</source>
|
||||||
<translation>Hochladen abgeschlossen</translation>
|
<translation>Hochladen abgeschlossen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="199"/>
|
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="204"/>
|
||||||
<source>Downloading...</source>
|
<source>Downloading...</source>
|
||||||
<translation>Runterladen...</translation>
|
<translation>Runterladen...</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="205"/>
|
<location filename="../components/tabs/cloud_saves/sync_widget.py" line="210"/>
|
||||||
<source>Download finished</source>
|
<source>Download finished</source>
|
||||||
<translation>Download abgeschlossen</translation>
|
<translation>Download abgeschlossen</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -61,6 +61,12 @@ def uninstall(app_name: str, core: LegendaryCore, options=None):
|
||||||
if os.path.exists(os.path.expanduser(f"~/.local/share/applications/{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"))
|
os.remove(os.path.expanduser(f"~/.local/share/applications/{igame.title}.desktop"))
|
||||||
|
|
||||||
|
elif os.name == "nt":
|
||||||
|
if os.path.exists(os.path.expanduser(f"~/Desktop/{igame.title.split(':')[0]}.lnk")):
|
||||||
|
os.remove(os.path.expanduser(f"~/Desktop/{igame.title.split(':')[0]}.lnk"))
|
||||||
|
elif os.path.exists(os.path.expandvars(f"%appdata%/Microsoft/Windows/Start Menu/{igame.title.split(':')[0]}.lnk")):
|
||||||
|
os.remove(os.path.expandvars(f"%appdata%/Microsoft/Windows/Start Menu/{igame.title.split(':')[0]}.lnk"))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Remove DLC first so directory is empty when game uninstall runs
|
# Remove DLC first so directory is empty when game uninstall runs
|
||||||
dlcs = core.get_dlc_for_game(app_name)
|
dlcs = core.get_dlc_for_game(app_name)
|
||||||
|
|
|
@ -14,12 +14,13 @@ if os.name == "nt":
|
||||||
from win32com.client import Dispatch
|
from win32com.client import Dispatch
|
||||||
|
|
||||||
from rare import lang_path, style_path
|
from rare import lang_path, style_path
|
||||||
|
# Mac not supported
|
||||||
|
|
||||||
from custom_legendary.core import LegendaryCore
|
from custom_legendary.core import LegendaryCore
|
||||||
|
|
||||||
logger = getLogger("Utils")
|
logger = getLogger("Utils")
|
||||||
s = QSettings("Rare", "Rare")
|
s = QSettings("Rare", "Rare")
|
||||||
IMAGE_DIR = s.value("img_dir", os.path.expanduser("~/.cache/rare/images"), type=str)
|
IMAGE_DIR = s.value("img_dir", os.path.expanduser("~/.cache/rare/images"), type=str)
|
||||||
logger.info("IMAGE DIRECTORY: " + IMAGE_DIR)
|
|
||||||
|
|
||||||
|
|
||||||
def download_images(signal: pyqtSignal, core: LegendaryCore):
|
def download_images(signal: pyqtSignal, core: LegendaryCore):
|
||||||
|
@ -246,7 +247,8 @@ def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop"):
|
||||||
"Terminal=false\n"
|
"Terminal=false\n"
|
||||||
"StartupWMClass=rare-game\n"
|
"StartupWMClass=rare-game\n"
|
||||||
)
|
)
|
||||||
os.chmod(os.path.expanduser(f"~/Desktop/{igame.title}.desktop"), 0o755)
|
desktop_file.close()
|
||||||
|
os.chmod(os.path.expanduser(f"{path}{igame.title}.desktop"), 0o755)
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
elif os.name == "nt":
|
elif os.name == "nt":
|
||||||
|
@ -261,7 +263,12 @@ def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop"):
|
||||||
target = os.path.abspath(sys.argv[0])
|
target = os.path.abspath(sys.argv[0])
|
||||||
|
|
||||||
# Name of link file
|
# Name of link file
|
||||||
linkName = igame.title + '.lnk'
|
|
||||||
|
linkName = igame.title
|
||||||
|
for c in r'<>?":|\/*':
|
||||||
|
linkName.replace(c, "")
|
||||||
|
|
||||||
|
linkName = linkName.strip() + '.lnk'
|
||||||
|
|
||||||
# Path to location of link file
|
# Path to location of link file
|
||||||
pathLink = os.path.join(target_folder, linkName)
|
pathLink = os.path.join(target_folder, linkName)
|
||||||
|
@ -279,4 +286,5 @@ def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop"):
|
||||||
img.save(icon + ".ico")
|
img.save(icon + ".ico")
|
||||||
logger.info("Create Icon")
|
logger.info("Create Icon")
|
||||||
shortcut.IconLocation = os.path.join(icon + ".ico")
|
shortcut.IconLocation = os.path.join(icon + ".ico")
|
||||||
|
|
||||||
shortcut.save()
|
shortcut.save()
|
||||||
|
|
|
@ -4,4 +4,5 @@ PyQt5
|
||||||
QtAwesome
|
QtAwesome
|
||||||
notify-py
|
notify-py
|
||||||
psutil
|
psutil
|
||||||
pypresence
|
pypresence
|
||||||
|
pywin32; platform_system == "Windows"
|
||||||
|
|
29
setup.py
29
setup.py
|
@ -1,3 +1,5 @@
|
||||||
|
import os
|
||||||
|
|
||||||
import setuptools
|
import setuptools
|
||||||
|
|
||||||
from rare import __version__ as version
|
from rare import __version__ as version
|
||||||
|
@ -5,6 +7,21 @@ from rare import __version__ as version
|
||||||
with open("README.md", "r") as fh:
|
with open("README.md", "r") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
|
requirements = [
|
||||||
|
"requests<3.0",
|
||||||
|
"pillow",
|
||||||
|
"setuptools",
|
||||||
|
"wheel",
|
||||||
|
"PyQt5",
|
||||||
|
"QtAwesome",
|
||||||
|
"notify-py",
|
||||||
|
"psutil",
|
||||||
|
"pypresence"
|
||||||
|
]
|
||||||
|
|
||||||
|
if os.name == "nt":
|
||||||
|
requirements.append("pywin32")
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="Rare",
|
name="Rare",
|
||||||
version=version,
|
version=version,
|
||||||
|
@ -25,15 +42,5 @@ setuptools.setup(
|
||||||
],
|
],
|
||||||
python_requires=">=3.8",
|
python_requires=">=3.8",
|
||||||
entry_points=dict(console_scripts=["rare=rare.__main__:main"]),
|
entry_points=dict(console_scripts=["rare=rare.__main__:main"]),
|
||||||
install_requires=[
|
install_requires=requirements,
|
||||||
"requests<3.0",
|
|
||||||
"pillow",
|
|
||||||
"setuptools",
|
|
||||||
"wheel",
|
|
||||||
"PyQt5",
|
|
||||||
"QtAwesome",
|
|
||||||
"notify-py",
|
|
||||||
"psutil",
|
|
||||||
"pypresence"
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue