From 5029921b09599dc4378d3c4d1b250a2c7d5631b8 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Wed, 7 Sep 2022 15:35:51 +0300
Subject: [PATCH 1/9] Move a bunch of class attributes to instance attributes
---
rare/app.py | 2 +-
rare/components/dialogs/install_dialog.py | 3 +++
rare/components/dialogs/launch_dialog.py | 2 +-
rare/components/dialogs/login/__init__.py | 2 +-
rare/components/tabs/games/__init__.py | 10 ++++------
rare/shared/image_manager.py | 21 ++++++++-------------
6 files changed, 18 insertions(+), 22 deletions(-)
diff --git a/rare/app.py b/rare/app.py
index efd10a64..8320c228 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -71,6 +71,7 @@ class App(RareApp):
# set Application name for settings
self.mainwindow: Optional[MainWindow] = None
self.launch_dialog: Optional[LaunchDialog] = None
+ self.timer = QTimer()
# launch app
self.launch_dialog = LaunchDialog(parent=None)
@@ -84,7 +85,6 @@ class App(RareApp):
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1])
dt_now = datetime.utcnow()
td = abs(dt_exp - dt_now)
- self.timer = QTimer()
self.timer.timeout.connect(self.re_login)
self.timer.start(int(td.total_seconds() - 60) * 1000)
diff --git a/rare/components/dialogs/install_dialog.py b/rare/components/dialogs/install_dialog.py
index ca58ecb6..2e288747 100644
--- a/rare/components/dialogs/install_dialog.py
+++ b/rare/components/dialogs/install_dialog.py
@@ -309,6 +309,9 @@ class InstallDialog(QDialog):
self.show()
def error_box(self, label: str = "", message: str = ""):
+ if message.startswith("403 Client Error: Forbidden for url:"):
+ message = self.tr("403 Client Error: Wait a few seconds and try Verify again")
+ self.options_changed = True
self.ui.warn_label.setVisible(bool(label))
self.ui.warn_label.setText(label)
self.ui.warn_message.setVisible(bool(message))
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index 91c507aa..59e1a5d8 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -11,7 +11,7 @@ from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSi
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
from rare.utils.misc import CloudWorker
-logger = getLogger("LoginDialog")
+logger = getLogger("LaunchDialog")
class LaunchWorker(QRunnable):
diff --git a/rare/components/dialogs/login/__init__.py b/rare/components/dialogs/login/__init__.py
index eb0399e6..66a1f346 100644
--- a/rare/components/dialogs/login/__init__.py
+++ b/rare/components/dialogs/login/__init__.py
@@ -12,7 +12,7 @@ from rare.widgets.sliding_stack import SlidingStackedWidget
from .browser_login import BrowserLogin
from .import_login import ImportLogin
-logger = getLogger("Login")
+logger = getLogger("LoginDialog")
@dataclass
diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py
index dfbafa2b..835c1289 100644
--- a/rare/components/tabs/games/__init__.py
+++ b/rare/components/tabs/games/__init__.py
@@ -1,16 +1,16 @@
from logging import getLogger
-from typing import Tuple, Dict, Union, List
+from typing import Tuple, Dict, Union, List, Set
from PyQt5.QtCore import QSettings, Qt, pyqtSlot
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
from legendary.models.game import InstalledGame, Game
-from rare.shared import ImageManagerSingleton
from rare.shared import (
LegendaryCoreSingleton,
GlobalSignalsSingleton,
ArgumentsSingleton,
ApiResultsSingleton,
+ ImageManagerSingleton,
)
from rare.widgets.library_layout import LibraryLayout
from rare.widgets.sliding_stack import SlidingStackedWidget
@@ -32,10 +32,6 @@ logger = getLogger("GamesTab")
class GamesTab(QStackedWidget):
-
- updates = set()
- active_filter = 0
-
def __init__(self, parent=None):
super(GamesTab, self).__init__(parent=parent)
self.core = LegendaryCoreSingleton()
@@ -47,6 +43,8 @@ class GamesTab(QStackedWidget):
self.widgets: Dict[str, Tuple[
Union[InstalledIconWidget, UninstalledIconWidget], Union[InstalledListWidget, UninstalledListWidget]]] = {}
+ self.updates: Set = set()
+ self.active_filter: int = 0
self.uninstalled_games: List[Game] = []
self.game_list: List[Game] = self.api_results.game_list
diff --git a/rare/shared/image_manager.py b/rare/shared/image_manager.py
index a64cb62f..c36751b8 100644
--- a/rare/shared/image_manager.py
+++ b/rare/shared/image_manager.py
@@ -38,17 +38,13 @@ logger = getLogger("ImageManager")
class ImageSize:
class Preset:
- __img_factor = 67
- __size: QSize
- __divisor: float = 1.0
- __pixel_ratio: float = 1.0
- # lk: for prettier images set this to true
- __smooth_transform: bool = False
-
def __init__(self, divisor: float, pixel_ratio: float):
- self.__pixel_ratio = pixel_ratio
+ self.__img_factor = 67
self.__divisor = divisor
+ self.__pixel_ratio = pixel_ratio
self.__size = QSize(self.__img_factor * 3, self.__img_factor * 4) * pixel_ratio / divisor
+ # lk: for prettier images set this to true
+ self.__smooth_transform: bool = False
if divisor > 2:
self.__smooth_transform = False
@@ -107,12 +103,11 @@ class ImageManager(QObject):
logger.debug(f" Emitting singal for game {self.game.app_name} - {self.game.app_title}")
self.signals.completed.emit(self.game.app_name)
- # lk: the ordering in __img_types matters for the order of fallbacks
- __img_types: List = ["DieselGameBoxTall", "Thumbnail", "DieselGameBoxLogo"]
- __dl_retries = 1
- __worker_app_names: List[str] = list()
-
def __init__(self, signals: GlobalSignals, core: LegendaryCore):
+ # lk: the ordering in __img_types matters for the order of fallbacks
+ self.__img_types: Tuple = ("DieselGameBoxTall", "Thumbnail", "DieselGameBoxLogo")
+ self.__dl_retries = 1
+ self.__worker_app_names: List[str] = []
super(QObject, self).__init__()
self.signals = signals
self.core = core
From 6a2af0be7c95cbe0badca80d3d3900c2388eec55 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Wed, 7 Sep 2022 19:19:14 +0300
Subject: [PATCH 2/9] Quote executable path for Windows
---
rare/utils/misc.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/rare/utils/misc.py b/rare/utils/misc.py
index a6826571..f3c6cf12 100644
--- a/rare/utils/misc.py
+++ b/rare/utils/misc.py
@@ -284,10 +284,9 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if not for_rare:
arguments.extend(["launch", app_name])
- shortcut.Targetpath = executable
- shortcut.Arguments = shlex.join(arguments)
# Maybe there is a better solution, but windows does not accept single quotes (Windows is weird)
- shortcut.Arguments = shortcut.Arguments.replace("'", '"')
+ shortcut.Targetpath = shlex.quote(executable).replace("'", '"')
+ shortcut.Arguments = shlex.join(arguments).replace("'", '"')
if for_rare:
shortcut.WorkingDirectory = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)
From ea383578f9cd4111fe4a0e508e88e5b218dfa0c2 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Wed, 7 Sep 2022 19:22:50 +0300
Subject: [PATCH 3/9] workflows: Quote python version in pylint
---
.github/workflows/tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 45dcb680..89e72c2b 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -14,7 +14,7 @@ jobs:
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
- python-version: 3.10
+ python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
From 4b5b458fdb18a6abff2875f6e89466a707fc0bb2 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Wed, 7 Sep 2022 19:33:01 +0300
Subject: [PATCH 4/9] workflows: explicitly install pypresence
---
.github/workflows/tests.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 89e72c2b..d1bb2d88 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -20,6 +20,7 @@ jobs:
python -m pip install --upgrade pip
pip install pylint
pip install -r requirements.txt
+ pip install pypresence
- name: Analysing the code with pylint
run: |
pylint -E rare --disable=E0611,E1123,E1120 --ignore=ui,singleton.py --extension-pkg-whitelist=PyQt5
From 377fd486dc98ecb19420968fcaea3964862fbaed Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Wed, 7 Sep 2022 19:42:07 +0300
Subject: [PATCH 5/9] stupid quotes
---
.github/workflows/tests.yml | 4 +++-
rare/__main__.py | 3 +--
rare/utils/misc.py | 5 ++++-
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index d1bb2d88..dde4f957 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -77,7 +77,6 @@ jobs:
name: Rare.AppImage
path: Rare.AppImage
-
cx_freeze:
runs-on: "windows-latest"
steps:
@@ -91,6 +90,8 @@ jobs:
run: pip3 install -r requirements.txt
- name: cx_freeze
run: pip3 install --upgrade cx_freeze wheel
+ - name: pypresence
+ run: pip3 install pypresence
- name: Build
run: python freeze.py bdist_msi
@@ -98,6 +99,7 @@ jobs:
with:
name: Rare-Windows.msi
path: dist/*.msi
+
mac_os:
runs-on: macos-latest
steps:
diff --git a/rare/__main__.py b/rare/__main__.py
index cba7a615..7d4f1748 100644
--- a/rare/__main__.py
+++ b/rare/__main__.py
@@ -1,3 +1,4 @@
+import multiprocessing
import os
import pathlib
import sys
@@ -6,8 +7,6 @@ from argparse import ArgumentParser
def main():
# fix cx_freeze
- import multiprocessing
-
multiprocessing.freeze_support()
# insert legendary for installed via pip/setup.py submodule to path
diff --git a/rare/utils/misc.py b/rare/utils/misc.py
index f3c6cf12..be8ee9a5 100644
--- a/rare/utils/misc.py
+++ b/rare/utils/misc.py
@@ -165,7 +165,7 @@ def get_size(b: Union[int, float]) -> str:
def get_rare_executable() -> List[str]:
- # lk: detech if nuitka
+ # lk: detect if nuitka
if "__compiled__" in globals():
executable = [sys.executable]
elif platform.system() == "Linux" or platform.system() == "Darwin":
@@ -285,7 +285,10 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
arguments.extend(["launch", app_name])
# Maybe there is a better solution, but windows does not accept single quotes (Windows is weird)
+ logger.warning(executable)
+ logger.warning(shlex.quote(executable).replace("'", '"'))
shortcut.Targetpath = shlex.quote(executable).replace("'", '"')
+ logger.warning(shlex.join(arguments).replace("'", '"'))
shortcut.Arguments = shlex.join(arguments).replace("'", '"')
if for_rare:
shortcut.WorkingDirectory = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)
From d5d795ce794548eab10cfb6917eaa4c8ebe951b4 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Thu, 8 Sep 2022 01:27:37 +0300
Subject: [PATCH 6/9] Paths: Query paths after the `OrganizationName` and
`ApplicationName` have been set
At the point they were evaluated, `OrganizationName` and `ApplicationName` are unset
resulting in wrong paths. As a quick fix, explicitly set them to their later values
Per OS examples:
Windows:
before:
data: C:\Users\\AppData\Local
cache: C:\Users\\AppData\Local\cache
after:
data: C:\Users\\AppData\Local\Rare\Rare
cache: C:\Users\\AppData\Local\Rare\Rare\cache
---
rare/__main__.py | 4 +-
rare/app.py | 71 +++++++++++-----------
rare/components/main_window.py | 4 +-
rare/components/tabs/downloads/__init__.py | 4 +-
rare/components/tabs/settings/rare.py | 16 +++--
rare/components/tabs/shop/__init__.py | 2 +-
rare/game_launch_helper/__init__.py | 8 +--
rare/lgndr/cli.py | 2 +-
rare/shared/image_manager.py | 2 +-
rare/utils/extra_widgets.py | 2 +-
rare/utils/meta.py | 4 +-
rare/utils/misc.py | 2 +-
rare/utils/paths.py | 53 +++++++++++++---
rare/utils/steam_grades.py | 15 +++--
rare/widgets/rare_app.py | 6 +-
15 files changed, 117 insertions(+), 78 deletions(-)
diff --git a/rare/__main__.py b/rare/__main__.py
index 7d4f1748..84e1fc87 100644
--- a/rare/__main__.py
+++ b/rare/__main__.py
@@ -94,9 +94,9 @@ def main():
me = singleton.SingleInstance()
except singleton.SingleInstanceException:
print("Rare is already running")
- from rare.utils.paths import data_dir
+ from rare.utils.paths import lock_file
- with open(os.path.join(data_dir, "lockfile"), "w") as file:
+ with open(lock_file(), "w") as file:
file.write("show")
file.close()
return
diff --git a/rare/app.py b/rare/app.py
index 8320c228..d423e848 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -24,14 +24,9 @@ from rare.shared import (
ArgumentsSingleton,
)
from rare.shared.rare_core import RareCore
-from rare.utils import legendary_utils, config_helper
-from rare.utils.paths import cache_dir, tmp_dir
+from rare.utils import legendary_utils, config_helper, paths
from rare.widgets.rare_app import RareApp
-start_time = time.strftime("%y-%m-%d--%H-%M") # year-month-day-hour-minute
-file_name = os.path.join(cache_dir, "logs", f"Rare_{start_time}.log")
-if not os.path.exists(os.path.dirname(file_name)):
- os.makedirs(os.path.dirname(file_name))
logger = logging.getLogger("Rare")
@@ -57,7 +52,39 @@ def excepthook(exc_type, exc_value, exc_tb):
class App(RareApp):
def __init__(self, args: Namespace):
- super(App, self).__init__()
+ super(App, self).__init__(args)
+
+ paths.create_dirs()
+ start_time = time.strftime("%y-%m-%d--%H-%M") # year-month-day-hour-minute
+ file_name = os.path.join(paths.log_dir(), f"Rare_{start_time}.log")
+
+ # configure logging
+ if args.debug:
+ logging.basicConfig(
+ format="[%(name)s] %(levelname)s: %(message)s", level=logging.DEBUG
+ )
+ logging.getLogger().setLevel(level=logging.DEBUG)
+ # keep requests, asyncio and pillow quiet
+ logging.getLogger("requests").setLevel(logging.WARNING)
+ logging.getLogger("urllib3").setLevel(logging.WARNING)
+ logging.getLogger("asyncio").setLevel(logging.WARNING)
+ logger.info(
+ f"Launching Rare version {rare.__version__} Codename: {rare.code_name}\n"
+ f" - Using Legendary {legendary.__version__} Codename: {legendary.__codename__} as backend\n"
+ f" - Operating System: {platform.system()}, Python version: {platform.python_version()}\n"
+ f" - Running {sys.executable} {' '.join(sys.argv)}\n"
+ f" - Qt version: {QT_VERSION_STR}, PyQt version: {PYQT_VERSION_STR}"
+ )
+ else:
+ print(file_name)
+ logging.basicConfig(
+ format="[%(name)s] %(levelname)s: %(message)s",
+ level=logging.INFO,
+ filename=file_name,
+ )
+ logger.info(f"Launching Rare version {rare.__version__}")
+ logger.info(f"Operating System: {platform.system()}")
+
self.rare_core = RareCore(args=args)
self.args = ArgumentsSingleton()
self.signals = GlobalSignalsSingleton()
@@ -142,8 +169,8 @@ class App(RareApp):
self.rare_core.deleteLater()
del self.rare_core
self.processEvents()
- shutil.rmtree(tmp_dir)
- os.makedirs(tmp_dir)
+ shutil.rmtree(paths.tmp_dir())
+ os.makedirs(paths.tmp_dir())
self.exit(exit_code)
@@ -152,32 +179,6 @@ def start(args):
# set excepthook to show dialog with exception
sys.excepthook = excepthook
- # configure logging
- if args.debug:
- logging.basicConfig(
- format="[%(name)s] %(levelname)s: %(message)s", level=logging.DEBUG
- )
- logging.getLogger().setLevel(level=logging.DEBUG)
- # keep requests, asyncio and pillow quiet
- logging.getLogger("requests").setLevel(logging.WARNING)
- logging.getLogger("urllib3").setLevel(logging.WARNING)
- logging.getLogger("asyncio").setLevel(logging.WARNING)
- logger.info(
- f"Launching Rare version {rare.__version__} Codename: {rare.code_name}\n"
- f" - Using Legendary {legendary.__version__} Codename: {legendary.__codename__} as backend\n"
- f" - Operating System: {platform.system()}, Python version: {platform.python_version()}\n"
- f" - Running {sys.executable} {' '.join(sys.argv)}\n"
- f" - Qt version: {QT_VERSION_STR}, PyQt version: {PYQT_VERSION_STR}"
- )
- else:
- logging.basicConfig(
- format="[%(name)s] %(levelname)s: %(message)s",
- level=logging.INFO,
- filename=file_name,
- )
- logger.info(f"Launching Rare version {rare.__version__}")
- logger.info(f"Operating System: {platform.system()}")
-
while True:
app = App(args)
exit_code = app.exec_()
diff --git a/rare/components/main_window.py b/rare/components/main_window.py
index b5e50942..60759be6 100644
--- a/rare/components/main_window.py
+++ b/rare/components/main_window.py
@@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QMainWindow, QApplication, QStatusBar, QScrollArea,
from rare.components.tabs import TabWidget
from rare.components.tray_icon import TrayIcon
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
-from rare.utils.paths import data_dir
+from rare.utils.paths import lock_file
logger = getLogger("MainWindow")
@@ -125,7 +125,7 @@ class MainWindow(QMainWindow):
self.hide()
def timer_finished(self):
- file_path = os.path.join(data_dir, "lockfile")
+ file_path = lock_file()
if os.path.exists(file_path):
file = open(file_path, "r")
action = file.read()
diff --git a/rare/components/tabs/downloads/__init__.py b/rare/components/tabs/downloads/__init__.py
index 26739a26..11400817 100644
--- a/rare/components/tabs/downloads/__init__.py
+++ b/rare/components/tabs/downloads/__init__.py
@@ -1,6 +1,6 @@
import datetime
from logging import getLogger
-from typing import List, Dict, Union
+from typing import List, Dict, Union, Set
from PyQt5.QtCore import QThread, pyqtSignal, QSettings, pyqtSlot
from PyQt5.QtWidgets import (
@@ -31,7 +31,7 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
dl_queue: List[InstallQueueItemModel] = []
dl_status = pyqtSignal(int)
- def __init__(self, updates: list):
+ def __init__(self, updates: Set):
super(DownloadsTab, self).__init__()
self.setupUi(self)
self.core = LegendaryCoreSingleton()
diff --git a/rare/components/tabs/settings/rare.py b/rare/components/tabs/settings/rare.py
index 48bdc573..c7a5fd1b 100644
--- a/rare/components/tabs/settings/rare.py
+++ b/rare/components/tabs/settings/rare.py
@@ -10,7 +10,7 @@ from PyQt5.QtWidgets import QWidget, QMessageBox
from rare.shared import LegendaryCoreSingleton
from rare.components.tabs.settings.widgets.rpc import RPCSettings
from rare.ui.components.tabs.settings.rare import Ui_RareSettings
-from rare.utils.paths import cache_dir
+from rare.utils.paths import log_dir
from rare.utils.misc import (
get_translations,
get_color_schemes,
@@ -51,7 +51,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.settings = QSettings()
language = self.settings.value("language", self.core.language_code, type=str)
- self.logdir = os.path.join(cache_dir, "logs")
# Select lang
self.lang_select.addItems([i[1] for i in languages])
@@ -143,19 +142,18 @@ class RareSettings(QWidget, Ui_RareSettings):
self.log_dir_open_button.clicked.connect(self.open_dir)
self.log_dir_clean_button.clicked.connect(self.clean_logdir)
- logdir = os.path.join(cache_dir, "logs")
# get size of logdir
size = 0
- for i in os.listdir(logdir):
- size += os.path.getsize(os.path.join(logdir, i))
+ for i in os.listdir(log_dir()):
+ size += os.path.getsize(os.path.join(log_dir(), i))
self.log_dir_size_label.setText(get_size(size))
# self.log_dir_clean_button.setVisible(False)
# self.log_dir_size_label.setVisible(False)
def clean_logdir(self):
- for i in os.listdir(os.path.join(cache_dir, "logs")):
- os.remove(os.path.join(cache_dir, f"logs/{i}"))
+ for i in os.listdir(log_dir()):
+ os.remove(os.path.join(log_dir(), f"{i}"))
self.log_dir_size_label.setText("0KB")
def create_start_menu_link(self):
@@ -216,10 +214,10 @@ class RareSettings(QWidget, Ui_RareSettings):
def open_dir(self):
if platform.system() == "Windows":
- os.startfile(self.logdir) # pylint: disable=E1101
+ os.startfile(log_dir()) # pylint: disable=E1101
else:
opener = "open" if sys.platform == "darwin" else "xdg-open"
- subprocess.Popen([opener, self.logdir])
+ subprocess.Popen([opener, log_dir()])
def save_window_size(self):
self.settings.setValue("save_size", self.save_size.isChecked())
diff --git a/rare/components/tabs/shop/__init__.py b/rare/components/tabs/shop/__init__.py
index 53be94ba..543c754b 100644
--- a/rare/components/tabs/shop/__init__.py
+++ b/rare/components/tabs/shop/__init__.py
@@ -23,7 +23,7 @@ class Shop(QStackedWidget):
self.core.country_code,
)
- self.shop = ShopWidget(cache_dir, self.core, self.api_core)
+ self.shop = ShopWidget(cache_dir(), self.core, self.api_core)
self.wishlist_widget = Wishlist(self.api_core)
self.store_tabs = QTabWidget()
diff --git a/rare/game_launch_helper/__init__.py b/rare/game_launch_helper/__init__.py
index 35a13e3f..5dbabefc 100644
--- a/rare/game_launch_helper/__init__.py
+++ b/rare/game_launch_helper/__init__.py
@@ -64,10 +64,10 @@ class GameProcessApp(RareApp):
console: Console = None
success: bool = True
- def __init__(self, app_name: str):
- super(GameProcessApp, self).__init__()
+ def __init__(self, args: Namespace):
+ super(GameProcessApp, self).__init__(args)
self.game_process = QProcess()
- self.app_name = app_name
+ self.app_name = args.app_name
self.logger = getLogger(self.app_name)
self.core = LegendaryCore()
@@ -211,7 +211,7 @@ def start_game(args: Namespace):
level=logging.INFO,
)
- app = GameProcessApp(args.app_name)
+ app = GameProcessApp(args)
app.setQuitOnLastWindowClosed(True)
def excepthook(exc_type, exc_value, exc_tb):
diff --git a/rare/lgndr/cli.py b/rare/lgndr/cli.py
index 667b19a3..45ad327d 100644
--- a/rare/lgndr/cli.py
+++ b/rare/lgndr/cli.py
@@ -30,7 +30,7 @@ class LegendaryCLI(LegendaryCLIReal):
# noinspection PyMissingConstructor
def __init__(self, core: LegendaryCore):
self.core = core
- self.logger = logging.getLogger('cli')
+ self.logger = logging.getLogger('Api')
self.logging_queue = None
self.ql = self.setup_threaded_logging()
diff --git a/rare/shared/image_manager.py b/rare/shared/image_manager.py
index c36751b8..1412a96e 100644
--- a/rare/shared/image_manager.py
+++ b/rare/shared/image_manager.py
@@ -112,7 +112,7 @@ class ImageManager(QObject):
self.signals = signals
self.core = core
- self.image_dir = Path(image_dir)
+ self.image_dir: Path = image_dir()
if not self.image_dir.is_dir():
self.image_dir.mkdir()
logger.info(f"Created image directory at {self.image_dir}")
diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py
index a6ef5db2..0dc72160 100644
--- a/rare/utils/extra_widgets.py
+++ b/rare/utils/extra_widgets.py
@@ -418,7 +418,7 @@ class ImageLabel(QLabel):
def __init__(self):
super(ImageLabel, self).__init__()
- self.path = tmp_dir
+ self.path = tmp_dir()
self.manager = QtRequestManager("bytes")
def update_image(self, url, name="", size: tuple = (240, 320)):
diff --git a/rare/utils/meta.py b/rare/utils/meta.py
index 3b120392..54431754 100644
--- a/rare/utils/meta.py
+++ b/rare/utils/meta.py
@@ -34,7 +34,7 @@ class RareGameMeta:
def __init__(self):
meta_data = {}
- if os.path.exists(p := os.path.join(data_dir, "game_meta.json")):
+ if os.path.exists(p := os.path.join(data_dir(), "game_meta.json")):
try:
meta_data = json.load(open(p))
except json.JSONDecodeError:
@@ -59,6 +59,6 @@ class RareGameMeta:
def save_file(self):
json.dump(
{app_name: data.__dict__() for app_name, data in self._meta.items()},
- open(os.path.join(data_dir, "game_meta.json"), "w"),
+ open(os.path.join(data_dir(), "game_meta.json"), "w"),
indent=4
)
diff --git a/rare/utils/misc.py b/rare/utils/misc.py
index be8ee9a5..4599ba8d 100644
--- a/rare/utils/misc.py
+++ b/rare/utils/misc.py
@@ -195,7 +195,7 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if not for_rare:
igame = core.get_installed_game(app_name)
- icon = os.path.join(os.path.join(image_dir, igame.app_name, "installed.png"))
+ icon = os.path.join(os.path.join(image_dir(), igame.app_name, "installed.png"))
icon = icon.replace(".png", "")
if platform.system() == "Linux":
diff --git a/rare/utils/paths.py b/rare/utils/paths.py
index ef9284d0..8f3a162d 100644
--- a/rare/utils/paths.py
+++ b/rare/utils/paths.py
@@ -1,13 +1,52 @@
+import os
+import shutil
from pathlib import Path
from PyQt5.QtCore import QStandardPaths
resources_path = Path(__file__).absolute().parent.parent.joinpath("resources")
-data_dir = Path(QStandardPaths.writableLocation(QStandardPaths.DataLocation), "rare")
-cache_dir = Path(QStandardPaths.writableLocation(QStandardPaths.CacheLocation), "rare")
-image_dir = data_dir.joinpath("images")
-tmp_dir = cache_dir.joinpath("tmp")
-for path in (data_dir, cache_dir, image_dir, tmp_dir):
- if not path.exists():
- path.mkdir(parents=True)
+# lk: delete old Rare directories
+for old_dir in [
+ Path(QStandardPaths.writableLocation(QStandardPaths.CacheLocation), "rare").joinpath("tmp"),
+ Path(QStandardPaths.writableLocation(QStandardPaths.DataLocation), "rare").joinpath("images"),
+ Path(QStandardPaths.writableLocation(QStandardPaths.CacheLocation), "rare"),
+ Path(QStandardPaths.writableLocation(QStandardPaths.DataLocation), "rare"),
+]:
+ if old_dir.exists():
+ # lk: case-sensitive matching on Winblows
+ if old_dir.stem in os.listdir(old_dir.parent):
+ print(old_dir)
+ shutil.rmtree(old_dir, ignore_errors=True)
+
+
+# lk: TempLocation doesn't depend on OrganizationName or ApplicationName
+# lk: so it is fine to use it before initializing the QApplication
+def lock_file() -> Path:
+ return Path(QStandardPaths.writableLocation(QStandardPaths.TempLocation), "Rare.lock")
+
+
+def data_dir() -> Path:
+ return Path(QStandardPaths.writableLocation(QStandardPaths.DataLocation))
+
+
+def cache_dir() -> Path:
+ return Path(QStandardPaths.writableLocation(QStandardPaths.CacheLocation))
+
+
+def image_dir() -> Path:
+ return data_dir().joinpath("images")
+
+
+def log_dir() -> Path:
+ return cache_dir().joinpath("logs")
+
+
+def tmp_dir() -> Path:
+ return cache_dir().joinpath("tmp")
+
+
+def create_dirs() -> None:
+ for path in (data_dir(), cache_dir(), image_dir(), log_dir(), tmp_dir()):
+ if not path.exists():
+ path.mkdir(parents=True)
diff --git a/rare/utils/steam_grades.py b/rare/utils/steam_grades.py
index 3403d40c..172e233e 100644
--- a/rare/utils/steam_grades.py
+++ b/rare/utils/steam_grades.py
@@ -6,13 +6,11 @@ from datetime import date
import requests
from PyQt5.QtCore import pyqtSignal, QRunnable, QObject, QCoreApplication
-from legendary.core import LegendaryCore
+from rare.lgndr.core import LegendaryCore
from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton
from rare.utils.paths import data_dir, cache_dir
replace_chars = ",;.:-_ "
-
-file = os.path.join(cache_dir, "game_list.json")
url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"
@@ -20,7 +18,7 @@ class SteamWorker(QRunnable):
class Signals(QObject):
rating_signal = pyqtSignal(str)
- app_name:str = ""
+ app_name: str = ""
def __init__(self, core: LegendaryCore):
super(SteamWorker, self).__init__()
@@ -55,7 +53,7 @@ def get_rating(app_name: str):
args = ArgumentsSingleton()
global __grades_json
if __grades_json is None:
- if os.path.exists(p := os.path.join(data_dir, "steam_ids.json")):
+ if os.path.exists(p := os.path.join(data_dir(), "steam_ids.json")):
grades = json.loads(open(p).read())
__grades_json = grades
else:
@@ -72,7 +70,7 @@ def get_rating(app_name: str):
steam_id = get_steam_id(game.app_title)
grade = get_grade(steam_id)
grades[app_name] = {"steam_id": steam_id, "grade": grade}
- with open(os.path.join(data_dir, "steam_ids.json"), "w") as f:
+ with open(os.path.join(data_dir(), "steam_ids.json"), "w") as f:
f.write(json.dumps(grades))
f.close()
return grade
@@ -96,8 +94,8 @@ def get_grade(steam_code):
def load_json() -> dict:
+ file = os.path.join(cache_dir(), "game_list.json")
if not os.path.exists(file):
-
response = requests.get(url)
steam_ids = json.loads(response.text)["applist"]["apps"]
ids = {}
@@ -113,6 +111,7 @@ def load_json() -> dict:
def get_steam_id(title: str):
+ file = os.path.join(cache_dir(), "game_list.json")
# workarounds for satisfactory
title = title.replace("Early Access", "").replace("Experimental", "").strip()
global __steam_ids_json
@@ -146,7 +145,7 @@ def get_steam_id(title: str):
def check_time(): # this function check if it's time to update
- global file
+ file = os.path.join(cache_dir(), "game_list.json")
json_table = json.loads(open(file, "r").read())
today = date.today()
diff --git a/rare/widgets/rare_app.py b/rare/widgets/rare_app.py
index 1b03cabc..53f39754 100644
--- a/rare/widgets/rare_app.py
+++ b/rare/widgets/rare_app.py
@@ -1,8 +1,10 @@
import os
import sys
+from argparse import Namespace
from logging import getLogger
+from pathlib import Path
-from PyQt5.QtCore import Qt, QSettings, QTranslator
+from PyQt5.QtCore import Qt, QSettings, QTranslator, QStandardPaths
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication
@@ -17,7 +19,7 @@ from rare.utils.misc import set_color_pallete, set_style_sheet
class RareApp(QApplication):
logger = getLogger("RareApp")
- def __init__(self):
+ def __init__(self, args: Namespace):
super(RareApp, self).__init__(sys.argv)
self.setQuitOnLastWindowClosed(False)
if hasattr(Qt, "AA_UseHighDpiPixmaps"):
From 7ebeee0d1e0d0df829cc28474c587431857f0407 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Thu, 8 Sep 2022 02:13:10 +0300
Subject: [PATCH 7/9] App: Log both to file and to stderr
---
rare/app.py | 16 +++++++++++++---
rare/utils/paths.py | 1 -
rare/widgets/rare_app.py | 10 +++++-----
3 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/rare/app.py b/rare/app.py
index d423e848..4c2887a1 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -54,15 +54,24 @@ class App(RareApp):
def __init__(self, args: Namespace):
super(App, self).__init__(args)
- paths.create_dirs()
start_time = time.strftime("%y-%m-%d--%H-%M") # year-month-day-hour-minute
file_name = os.path.join(paths.log_dir(), f"Rare_{start_time}.log")
+ for handler in logging.root.handlers[:]:
+ logging.root.removeHandler(handler)
+
+ stream_handler = logging.StreamHandler(sys.stderr)
+ stream_handler.setFormatter(fmt=logging.Formatter("[%(name)s] %(levelname)s: %(message)s"))
+
# configure logging
if args.debug:
logging.basicConfig(
- format="[%(name)s] %(levelname)s: %(message)s", level=logging.DEBUG
+ format="[%(name)s] %(levelname)s: %(message)s",
+ level=logging.DEBUG,
+ filename=file_name,
)
+ stream_handler.setLevel(logging.DEBUG)
+ logging.root.addHandler(stream_handler)
logging.getLogger().setLevel(level=logging.DEBUG)
# keep requests, asyncio and pillow quiet
logging.getLogger("requests").setLevel(logging.WARNING)
@@ -76,12 +85,13 @@ class App(RareApp):
f" - Qt version: {QT_VERSION_STR}, PyQt version: {PYQT_VERSION_STR}"
)
else:
- print(file_name)
logging.basicConfig(
format="[%(name)s] %(levelname)s: %(message)s",
level=logging.INFO,
filename=file_name,
)
+ stream_handler.setLevel(logging.INFO)
+ logging.root.addHandler(stream_handler)
logger.info(f"Launching Rare version {rare.__version__}")
logger.info(f"Operating System: {platform.system()}")
diff --git a/rare/utils/paths.py b/rare/utils/paths.py
index 8f3a162d..ba342ec7 100644
--- a/rare/utils/paths.py
+++ b/rare/utils/paths.py
@@ -16,7 +16,6 @@ for old_dir in [
if old_dir.exists():
# lk: case-sensitive matching on Winblows
if old_dir.stem in os.listdir(old_dir.parent):
- print(old_dir)
shutil.rmtree(old_dir, ignore_errors=True)
diff --git a/rare/widgets/rare_app.py b/rare/widgets/rare_app.py
index 53f39754..7d1bed82 100644
--- a/rare/widgets/rare_app.py
+++ b/rare/widgets/rare_app.py
@@ -2,9 +2,8 @@ import os
import sys
from argparse import Namespace
from logging import getLogger
-from pathlib import Path
-from PyQt5.QtCore import Qt, QSettings, QTranslator, QStandardPaths
+from PyQt5.QtCore import Qt, QSettings, QTranslator
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication
@@ -12,7 +11,7 @@ from PyQt5.QtWidgets import QApplication
from legendary.core import LegendaryCore
import rare.resources.resources
-from rare.utils.paths import resources_path
+from rare.utils import paths
from rare.utils.misc import set_color_pallete, set_style_sheet
@@ -27,6 +26,7 @@ class RareApp(QApplication):
self.setApplicationName("Rare")
self.setOrganizationName("Rare")
+ paths.create_dirs()
self.settings = QSettings()
# Translator
@@ -53,7 +53,7 @@ class RareApp(QApplication):
self.setWindowIcon(QIcon(":/images/Rare.png"))
def load_translator(self, lang: str):
- if os.path.isfile(f := os.path.join(resources_path, "languages", f"{lang}.qm")):
+ if os.path.isfile(f := os.path.join(paths.resources_path, "languages", f"{lang}.qm")):
self.translator.load(f)
self.logger.info(f"Your language is supported: {lang}")
elif not lang == "en":
@@ -61,7 +61,7 @@ class RareApp(QApplication):
self.installTranslator(self.translator)
# translator for qt stuff
- if os.path.isfile(f := os.path.join(resources_path, f"qt_{lang}.qm")):
+ if os.path.isfile(f := os.path.join(paths.resources_path, f"qt_{lang}.qm")):
self.qt_translator = QTranslator()
self.qt_translator.load(f)
self.installTranslator(self.qt_translator)
From c6b9f5c64f5a50004042f12070c273e9c7e72228 Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Thu, 8 Sep 2022 13:16:15 +0300
Subject: [PATCH 8/9] Fix shortcut creation on windows
---
rare/app.py | 16 ++++++++--------
rare/utils/misc.py | 19 +++++++------------
2 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/rare/app.py b/rare/app.py
index 4c2887a1..ef48f817 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -60,18 +60,18 @@ class App(RareApp):
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
- stream_handler = logging.StreamHandler(sys.stderr)
- stream_handler.setFormatter(fmt=logging.Formatter("[%(name)s] %(levelname)s: %(message)s"))
+ file_handler = logging.FileHandler(filename=file_name, encoding="utf-8")
+ file_handler.setFormatter(fmt=logging.Formatter("[%(name)s] %(levelname)s: %(message)s"))
# configure logging
if args.debug:
logging.basicConfig(
format="[%(name)s] %(levelname)s: %(message)s",
level=logging.DEBUG,
- filename=file_name,
+ stream=sys.stderr,
)
- stream_handler.setLevel(logging.DEBUG)
- logging.root.addHandler(stream_handler)
+ file_handler.setLevel(logging.DEBUG)
+ logging.root.addHandler(file_handler)
logging.getLogger().setLevel(level=logging.DEBUG)
# keep requests, asyncio and pillow quiet
logging.getLogger("requests").setLevel(logging.WARNING)
@@ -88,10 +88,10 @@ class App(RareApp):
logging.basicConfig(
format="[%(name)s] %(levelname)s: %(message)s",
level=logging.INFO,
- filename=file_name,
+ stream=sys.stderr,
)
- stream_handler.setLevel(logging.INFO)
- logging.root.addHandler(stream_handler)
+ file_handler.setLevel(logging.INFO)
+ logging.root.addHandler(file_handler)
logger.info(f"Launching Rare version {rare.__version__}")
logger.info(f"Operating System: {platform.system()}")
diff --git a/rare/utils/misc.py b/rare/utils/misc.py
index 4599ba8d..15c563be 100644
--- a/rare/utils/misc.py
+++ b/rare/utils/misc.py
@@ -180,10 +180,12 @@ def get_rare_executable() -> List[str]:
elif platform.system() == "Windows":
executable = [sys.executable]
- if not sys.executable.endswith("Rare.exe"):
+ if sys.executable != os.path.abspath(sys.argv[0]):
+ executable.append(os.path.abspath(sys.argv[0]))
+
+ if executable[0].endswith("python.exe"):
# be sure to start consoleless then
executable[0] = executable[0].replace("python.exe", "pythonw.exe")
- executable.extend(["-m", "rare"])
else:
executable = [sys.executable]
@@ -208,6 +210,7 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if not os.path.exists(path):
return False
executable = get_rare_executable()
+ executable = shlex.join(executable)
if for_rare:
with open(os.path.join(path, "Rare.desktop"), "w") as desktop_file:
@@ -274,21 +277,13 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if len(executable) > 1:
arguments.extend(executable[1:])
- executable = executable[0]
-
- if not sys.executable.endswith("Rare.exe"):
- # be sure to start consoleless then
- executable = sys.executable.replace("python.exe", "pythonw.exe")
- arguments.append(os.path.abspath(sys.argv[0]))
+ executable = executable[0]
if not for_rare:
arguments.extend(["launch", app_name])
+ shortcut.Targetpath = executable
# Maybe there is a better solution, but windows does not accept single quotes (Windows is weird)
- logger.warning(executable)
- logger.warning(shlex.quote(executable).replace("'", '"'))
- shortcut.Targetpath = shlex.quote(executable).replace("'", '"')
- logger.warning(shlex.join(arguments).replace("'", '"'))
shortcut.Arguments = shlex.join(arguments).replace("'", '"')
if for_rare:
shortcut.WorkingDirectory = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)
From e4638c2fa38c16fb769974a826228f497026367a Mon Sep 17 00:00:00 2001
From: Stelios Tsampas
Date: Thu, 8 Sep 2022 13:33:46 +0300
Subject: [PATCH 9/9] Console: Center window on show()
---
rare/game_launch_helper/__init__.py | 2 +-
rare/game_launch_helper/console.py | 33 +++++++++++++++++++++++++----
2 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/rare/game_launch_helper/__init__.py b/rare/game_launch_helper/__init__.py
index 5dbabefc..ac97e272 100644
--- a/rare/game_launch_helper/__init__.py
+++ b/rare/game_launch_helper/__init__.py
@@ -61,7 +61,7 @@ class GameProcessApp(RareApp):
server: QLocalServer
socket: Optional[QLocalSocket] = None
exit_app = pyqtSignal()
- console: Console = None
+ console: Optional[Console] = None
success: bool = True
def __init__(self, args: Namespace):
diff --git a/rare/game_launch_helper/console.py b/rare/game_launch_helper/console.py
index c0c93139..1046ff6c 100644
--- a/rare/game_launch_helper/console.py
+++ b/rare/game_launch_helper/console.py
@@ -1,7 +1,7 @@
import platform
-from PyQt5.QtCore import QProcessEnvironment, pyqtSignal
-from PyQt5.QtGui import QTextCursor, QFont
+from PyQt5.QtCore import QProcessEnvironment, pyqtSignal, QSize
+from PyQt5.QtGui import QTextCursor, QFont, QCursor
from PyQt5.QtWidgets import (
QPlainTextEdit,
QDialog,
@@ -10,7 +10,7 @@ from PyQt5.QtWidgets import (
QVBoxLayout,
QHBoxLayout,
QSpacerItem,
- QSizePolicy, QTableWidgetItem, QHeaderView,
+ QSizePolicy, QTableWidgetItem, QHeaderView, QApplication,
)
from rare.ui.components.extra.console_env import Ui_ConsoleEnv
@@ -24,7 +24,7 @@ class Console(QDialog):
def __init__(self, parent=None):
super(Console, self).__init__(parent=parent)
self.setWindowTitle("Rare - Console")
- self.setGeometry(0, 0, 600, 400)
+ self.setGeometry(0, 0, 640, 480)
layout = QVBoxLayout()
self.console = ConsoleEdit(self)
@@ -63,6 +63,31 @@ class Console(QDialog):
self.env_variables = ConsoleEnv(self)
self.env_variables.hide()
+ def show(self) -> None:
+ super(Console, self).show()
+ self.center_window()
+
+ def center_window(self):
+ # get the margins of the decorated window
+ margins = self.windowHandle().frameMargins()
+ # get the screen the cursor is on
+ current_screen = QApplication.screenAt(QCursor.pos())
+ if not current_screen:
+ current_screen = QApplication.primaryScreen()
+ # get the available screen geometry (excludes panels/docks)
+ screen_rect = current_screen.availableGeometry()
+ decor_width = margins.left() + margins.right()
+ decor_height = margins.top() + margins.bottom()
+ window_size = QSize(self.width(), self.height()).boundedTo(
+ screen_rect.size() - QSize(decor_width, decor_height)
+ )
+
+ self.resize(window_size)
+ self.move(
+ screen_rect.center()
+ - self.rect().adjusted(0, 0, decor_width, decor_height).center()
+ )
+
def save(self):
file, ok = QFileDialog.getSaveFileName(
self, "Save output", "", "Log Files (*.log);;All Files (*)"