1
0
Fork 0
mirror of synced 2024-06-27 02:30:31 +12:00

Merge pull request #239 from loathingKernel/fixups

Fix logging, application paths and shortcuts
This commit is contained in:
Dummerle 2022-09-08 12:40:18 +02:00 committed by GitHub
commit 0c45bd918c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 190 additions and 122 deletions

View file

@ -14,12 +14,13 @@ jobs:
- name: Set up Python 3.10 - name: Set up Python 3.10
uses: actions/setup-python@v2 uses: actions/setup-python@v2
with: with:
python-version: 3.10 python-version: '3.10'
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install pylint pip install pylint
pip install -r requirements.txt pip install -r requirements.txt
pip install pypresence
- name: Analysing the code with pylint - name: Analysing the code with pylint
run: | run: |
pylint -E rare --disable=E0611,E1123,E1120 --ignore=ui,singleton.py --extension-pkg-whitelist=PyQt5 pylint -E rare --disable=E0611,E1123,E1120 --ignore=ui,singleton.py --extension-pkg-whitelist=PyQt5
@ -76,7 +77,6 @@ jobs:
name: Rare.AppImage name: Rare.AppImage
path: Rare.AppImage path: Rare.AppImage
cx_freeze: cx_freeze:
runs-on: "windows-latest" runs-on: "windows-latest"
steps: steps:
@ -90,6 +90,8 @@ jobs:
run: pip3 install -r requirements.txt run: pip3 install -r requirements.txt
- name: cx_freeze - name: cx_freeze
run: pip3 install --upgrade cx_freeze wheel run: pip3 install --upgrade cx_freeze wheel
- name: pypresence
run: pip3 install pypresence
- name: Build - name: Build
run: python freeze.py bdist_msi run: python freeze.py bdist_msi
@ -97,6 +99,7 @@ jobs:
with: with:
name: Rare-Windows.msi name: Rare-Windows.msi
path: dist/*.msi path: dist/*.msi
mac_os: mac_os:
runs-on: macos-latest runs-on: macos-latest
steps: steps:

View file

@ -1,3 +1,4 @@
import multiprocessing
import os import os
import pathlib import pathlib
import sys import sys
@ -6,8 +7,6 @@ from argparse import ArgumentParser
def main(): def main():
# fix cx_freeze # fix cx_freeze
import multiprocessing
multiprocessing.freeze_support() multiprocessing.freeze_support()
# insert legendary for installed via pip/setup.py submodule to path # insert legendary for installed via pip/setup.py submodule to path
@ -95,9 +94,9 @@ def main():
me = singleton.SingleInstance() me = singleton.SingleInstance()
except singleton.SingleInstanceException: except singleton.SingleInstanceException:
print("Rare is already running") 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.write("show")
file.close() file.close()
return return

View file

@ -24,14 +24,9 @@ from rare.shared import (
ArgumentsSingleton, ArgumentsSingleton,
) )
from rare.shared.rare_core import RareCore from rare.shared.rare_core import RareCore
from rare.utils import legendary_utils, config_helper from rare.utils import legendary_utils, config_helper, paths
from rare.utils.paths import cache_dir, tmp_dir
from rare.widgets.rare_app import RareApp 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") logger = logging.getLogger("Rare")
@ -57,7 +52,49 @@ def excepthook(exc_type, exc_value, exc_tb):
class App(RareApp): class App(RareApp):
def __init__(self, args: Namespace): def __init__(self, args: Namespace):
super(App, self).__init__() super(App, self).__init__(args)
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)
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,
stream=sys.stderr,
)
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)
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,
stream=sys.stderr,
)
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()}")
self.rare_core = RareCore(args=args) self.rare_core = RareCore(args=args)
self.args = ArgumentsSingleton() self.args = ArgumentsSingleton()
self.signals = GlobalSignalsSingleton() self.signals = GlobalSignalsSingleton()
@ -71,6 +108,7 @@ class App(RareApp):
# set Application name for settings # set Application name for settings
self.mainwindow: Optional[MainWindow] = None self.mainwindow: Optional[MainWindow] = None
self.launch_dialog: Optional[LaunchDialog] = None self.launch_dialog: Optional[LaunchDialog] = None
self.timer = QTimer()
# launch app # launch app
self.launch_dialog = LaunchDialog(parent=None) self.launch_dialog = LaunchDialog(parent=None)
@ -84,7 +122,6 @@ class App(RareApp):
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1]) dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1])
dt_now = datetime.utcnow() dt_now = datetime.utcnow()
td = abs(dt_exp - dt_now) td = abs(dt_exp - dt_now)
self.timer = QTimer()
self.timer.timeout.connect(self.re_login) self.timer.timeout.connect(self.re_login)
self.timer.start(int(td.total_seconds() - 60) * 1000) self.timer.start(int(td.total_seconds() - 60) * 1000)
@ -142,8 +179,8 @@ class App(RareApp):
self.rare_core.deleteLater() self.rare_core.deleteLater()
del self.rare_core del self.rare_core
self.processEvents() self.processEvents()
shutil.rmtree(tmp_dir) shutil.rmtree(paths.tmp_dir())
os.makedirs(tmp_dir) os.makedirs(paths.tmp_dir())
self.exit(exit_code) self.exit(exit_code)
@ -152,32 +189,6 @@ def start(args):
# set excepthook to show dialog with exception # set excepthook to show dialog with exception
sys.excepthook = excepthook 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: while True:
app = App(args) app = App(args)
exit_code = app.exec_() exit_code = app.exec_()

View file

@ -309,6 +309,9 @@ class InstallDialog(QDialog):
self.show() self.show()
def error_box(self, label: str = "", message: str = ""): 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 <b>Verify</b> again")
self.options_changed = True
self.ui.warn_label.setVisible(bool(label)) self.ui.warn_label.setVisible(bool(label))
self.ui.warn_label.setText(label) self.ui.warn_label.setText(label)
self.ui.warn_message.setVisible(bool(message)) self.ui.warn_message.setVisible(bool(message))

View file

@ -11,7 +11,7 @@ from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSi
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
from rare.utils.misc import CloudWorker from rare.utils.misc import CloudWorker
logger = getLogger("LoginDialog") logger = getLogger("LaunchDialog")
class LaunchWorker(QRunnable): class LaunchWorker(QRunnable):

View file

@ -12,7 +12,7 @@ from rare.widgets.sliding_stack import SlidingStackedWidget
from .browser_login import BrowserLogin from .browser_login import BrowserLogin
from .import_login import ImportLogin from .import_login import ImportLogin
logger = getLogger("Login") logger = getLogger("LoginDialog")
@dataclass @dataclass

View file

@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QMainWindow, QApplication, QStatusBar, QScrollArea,
from rare.components.tabs import TabWidget from rare.components.tabs import TabWidget
from rare.components.tray_icon import TrayIcon from rare.components.tray_icon import TrayIcon
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
from rare.utils.paths import data_dir from rare.utils.paths import lock_file
logger = getLogger("MainWindow") logger = getLogger("MainWindow")
@ -125,7 +125,7 @@ class MainWindow(QMainWindow):
self.hide() self.hide()
def timer_finished(self): def timer_finished(self):
file_path = os.path.join(data_dir, "lockfile") file_path = lock_file()
if os.path.exists(file_path): if os.path.exists(file_path):
file = open(file_path, "r") file = open(file_path, "r")
action = file.read() action = file.read()

View file

@ -1,6 +1,6 @@
import datetime import datetime
from logging import getLogger 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.QtCore import QThread, pyqtSignal, QSettings, pyqtSlot
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
@ -31,7 +31,7 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
dl_queue: List[InstallQueueItemModel] = [] dl_queue: List[InstallQueueItemModel] = []
dl_status = pyqtSignal(int) dl_status = pyqtSignal(int)
def __init__(self, updates: list): def __init__(self, updates: Set):
super(DownloadsTab, self).__init__() super(DownloadsTab, self).__init__()
self.setupUi(self) self.setupUi(self)
self.core = LegendaryCoreSingleton() self.core = LegendaryCoreSingleton()

View file

@ -1,16 +1,16 @@
from logging import getLogger 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.QtCore import QSettings, Qt, pyqtSlot
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
from legendary.models.game import InstalledGame, Game from legendary.models.game import InstalledGame, Game
from rare.shared import ImageManagerSingleton
from rare.shared import ( from rare.shared import (
LegendaryCoreSingleton, LegendaryCoreSingleton,
GlobalSignalsSingleton, GlobalSignalsSingleton,
ArgumentsSingleton, ArgumentsSingleton,
ApiResultsSingleton, ApiResultsSingleton,
ImageManagerSingleton,
) )
from rare.widgets.library_layout import LibraryLayout from rare.widgets.library_layout import LibraryLayout
from rare.widgets.sliding_stack import SlidingStackedWidget from rare.widgets.sliding_stack import SlidingStackedWidget
@ -32,10 +32,6 @@ logger = getLogger("GamesTab")
class GamesTab(QStackedWidget): class GamesTab(QStackedWidget):
updates = set()
active_filter = 0
def __init__(self, parent=None): def __init__(self, parent=None):
super(GamesTab, self).__init__(parent=parent) super(GamesTab, self).__init__(parent=parent)
self.core = LegendaryCoreSingleton() self.core = LegendaryCoreSingleton()
@ -47,6 +43,8 @@ class GamesTab(QStackedWidget):
self.widgets: Dict[str, Tuple[ self.widgets: Dict[str, Tuple[
Union[InstalledIconWidget, UninstalledIconWidget], Union[InstalledListWidget, UninstalledListWidget]]] = {} Union[InstalledIconWidget, UninstalledIconWidget], Union[InstalledListWidget, UninstalledListWidget]]] = {}
self.updates: Set = set()
self.active_filter: int = 0
self.uninstalled_games: List[Game] = [] self.uninstalled_games: List[Game] = []
self.game_list: List[Game] = self.api_results.game_list self.game_list: List[Game] = self.api_results.game_list

View file

@ -10,7 +10,7 @@ from PyQt5.QtWidgets import QWidget, QMessageBox
from rare.shared import LegendaryCoreSingleton from rare.shared import LegendaryCoreSingleton
from rare.components.tabs.settings.widgets.rpc import RPCSettings from rare.components.tabs.settings.widgets.rpc import RPCSettings
from rare.ui.components.tabs.settings.rare import Ui_RareSettings 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 ( from rare.utils.misc import (
get_translations, get_translations,
get_color_schemes, get_color_schemes,
@ -51,7 +51,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.settings = QSettings() self.settings = QSettings()
language = self.settings.value("language", self.core.language_code, type=str) language = self.settings.value("language", self.core.language_code, type=str)
self.logdir = os.path.join(cache_dir, "logs")
# Select lang # Select lang
self.lang_select.addItems([i[1] for i in languages]) 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_open_button.clicked.connect(self.open_dir)
self.log_dir_clean_button.clicked.connect(self.clean_logdir) self.log_dir_clean_button.clicked.connect(self.clean_logdir)
logdir = os.path.join(cache_dir, "logs")
# get size of logdir # get size of logdir
size = 0 size = 0
for i in os.listdir(logdir): for i in os.listdir(log_dir()):
size += os.path.getsize(os.path.join(logdir, i)) size += os.path.getsize(os.path.join(log_dir(), i))
self.log_dir_size_label.setText(get_size(size)) self.log_dir_size_label.setText(get_size(size))
# self.log_dir_clean_button.setVisible(False) # self.log_dir_clean_button.setVisible(False)
# self.log_dir_size_label.setVisible(False) # self.log_dir_size_label.setVisible(False)
def clean_logdir(self): def clean_logdir(self):
for i in os.listdir(os.path.join(cache_dir, "logs")): for i in os.listdir(log_dir()):
os.remove(os.path.join(cache_dir, f"logs/{i}")) os.remove(os.path.join(log_dir(), f"{i}"))
self.log_dir_size_label.setText("0KB") self.log_dir_size_label.setText("0KB")
def create_start_menu_link(self): def create_start_menu_link(self):
@ -216,10 +214,10 @@ class RareSettings(QWidget, Ui_RareSettings):
def open_dir(self): def open_dir(self):
if platform.system() == "Windows": if platform.system() == "Windows":
os.startfile(self.logdir) # pylint: disable=E1101 os.startfile(log_dir()) # pylint: disable=E1101
else: else:
opener = "open" if sys.platform == "darwin" else "xdg-open" opener = "open" if sys.platform == "darwin" else "xdg-open"
subprocess.Popen([opener, self.logdir]) subprocess.Popen([opener, log_dir()])
def save_window_size(self): def save_window_size(self):
self.settings.setValue("save_size", self.save_size.isChecked()) self.settings.setValue("save_size", self.save_size.isChecked())

View file

@ -23,7 +23,7 @@ class Shop(QStackedWidget):
self.core.country_code, 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.wishlist_widget = Wishlist(self.api_core)
self.store_tabs = QTabWidget() self.store_tabs = QTabWidget()

View file

@ -61,13 +61,13 @@ class GameProcessApp(RareApp):
server: QLocalServer server: QLocalServer
socket: Optional[QLocalSocket] = None socket: Optional[QLocalSocket] = None
exit_app = pyqtSignal() exit_app = pyqtSignal()
console: Console = None console: Optional[Console] = None
success: bool = True success: bool = True
def __init__(self, app_name: str): def __init__(self, args: Namespace):
super(GameProcessApp, self).__init__() super(GameProcessApp, self).__init__(args)
self.game_process = QProcess() self.game_process = QProcess()
self.app_name = app_name self.app_name = args.app_name
self.logger = getLogger(self.app_name) self.logger = getLogger(self.app_name)
self.core = LegendaryCore() self.core = LegendaryCore()
@ -211,7 +211,7 @@ def start_game(args: Namespace):
level=logging.INFO, level=logging.INFO,
) )
app = GameProcessApp(args.app_name) app = GameProcessApp(args)
app.setQuitOnLastWindowClosed(True) app.setQuitOnLastWindowClosed(True)
def excepthook(exc_type, exc_value, exc_tb): def excepthook(exc_type, exc_value, exc_tb):

View file

@ -1,7 +1,7 @@
import platform import platform
from PyQt5.QtCore import QProcessEnvironment, pyqtSignal from PyQt5.QtCore import QProcessEnvironment, pyqtSignal, QSize
from PyQt5.QtGui import QTextCursor, QFont from PyQt5.QtGui import QTextCursor, QFont, QCursor
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QPlainTextEdit, QPlainTextEdit,
QDialog, QDialog,
@ -10,7 +10,7 @@ from PyQt5.QtWidgets import (
QVBoxLayout, QVBoxLayout,
QHBoxLayout, QHBoxLayout,
QSpacerItem, QSpacerItem,
QSizePolicy, QTableWidgetItem, QHeaderView, QSizePolicy, QTableWidgetItem, QHeaderView, QApplication,
) )
from rare.ui.components.extra.console_env import Ui_ConsoleEnv from rare.ui.components.extra.console_env import Ui_ConsoleEnv
@ -24,7 +24,7 @@ class Console(QDialog):
def __init__(self, parent=None): def __init__(self, parent=None):
super(Console, self).__init__(parent=parent) super(Console, self).__init__(parent=parent)
self.setWindowTitle("Rare - Console") self.setWindowTitle("Rare - Console")
self.setGeometry(0, 0, 600, 400) self.setGeometry(0, 0, 640, 480)
layout = QVBoxLayout() layout = QVBoxLayout()
self.console = ConsoleEdit(self) self.console = ConsoleEdit(self)
@ -63,6 +63,31 @@ class Console(QDialog):
self.env_variables = ConsoleEnv(self) self.env_variables = ConsoleEnv(self)
self.env_variables.hide() 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): def save(self):
file, ok = QFileDialog.getSaveFileName( file, ok = QFileDialog.getSaveFileName(
self, "Save output", "", "Log Files (*.log);;All Files (*)" self, "Save output", "", "Log Files (*.log);;All Files (*)"

View file

@ -30,7 +30,7 @@ class LegendaryCLI(LegendaryCLIReal):
# noinspection PyMissingConstructor # noinspection PyMissingConstructor
def __init__(self, core: LegendaryCore): def __init__(self, core: LegendaryCore):
self.core = core self.core = core
self.logger = logging.getLogger('cli') self.logger = logging.getLogger('Api')
self.logging_queue = None self.logging_queue = None
self.ql = self.setup_threaded_logging() self.ql = self.setup_threaded_logging()

View file

@ -38,17 +38,13 @@ logger = getLogger("ImageManager")
class ImageSize: class ImageSize:
class Preset: 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): def __init__(self, divisor: float, pixel_ratio: float):
self.__pixel_ratio = pixel_ratio self.__img_factor = 67
self.__divisor = divisor self.__divisor = divisor
self.__pixel_ratio = pixel_ratio
self.__size = QSize(self.__img_factor * 3, self.__img_factor * 4) * pixel_ratio / divisor 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: if divisor > 2:
self.__smooth_transform = False self.__smooth_transform = False
@ -107,17 +103,16 @@ class ImageManager(QObject):
logger.debug(f" Emitting singal for game {self.game.app_name} - {self.game.app_title}") logger.debug(f" Emitting singal for game {self.game.app_name} - {self.game.app_title}")
self.signals.completed.emit(self.game.app_name) 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): 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__() super(QObject, self).__init__()
self.signals = signals self.signals = signals
self.core = core self.core = core
self.image_dir = Path(image_dir) self.image_dir: Path = image_dir()
if not self.image_dir.is_dir(): if not self.image_dir.is_dir():
self.image_dir.mkdir() self.image_dir.mkdir()
logger.info(f"Created image directory at {self.image_dir}") logger.info(f"Created image directory at {self.image_dir}")

View file

@ -418,7 +418,7 @@ class ImageLabel(QLabel):
def __init__(self): def __init__(self):
super(ImageLabel, self).__init__() super(ImageLabel, self).__init__()
self.path = tmp_dir self.path = tmp_dir()
self.manager = QtRequestManager("bytes") self.manager = QtRequestManager("bytes")
def update_image(self, url, name="", size: tuple = (240, 320)): def update_image(self, url, name="", size: tuple = (240, 320)):

View file

@ -34,7 +34,7 @@ class RareGameMeta:
def __init__(self): def __init__(self):
meta_data = {} 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: try:
meta_data = json.load(open(p)) meta_data = json.load(open(p))
except json.JSONDecodeError: except json.JSONDecodeError:
@ -59,6 +59,6 @@ class RareGameMeta:
def save_file(self): def save_file(self):
json.dump( json.dump(
{app_name: data.__dict__() for app_name, data in self._meta.items()}, {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 indent=4
) )

View file

@ -165,7 +165,7 @@ def get_size(b: Union[int, float]) -> str:
def get_rare_executable() -> List[str]: def get_rare_executable() -> List[str]:
# lk: detech if nuitka # lk: detect if nuitka
if "__compiled__" in globals(): if "__compiled__" in globals():
executable = [sys.executable] executable = [sys.executable]
elif platform.system() == "Linux" or platform.system() == "Darwin": elif platform.system() == "Linux" or platform.system() == "Darwin":
@ -180,10 +180,12 @@ def get_rare_executable() -> List[str]:
elif platform.system() == "Windows": elif platform.system() == "Windows":
executable = [sys.executable] 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 # be sure to start consoleless then
executable[0] = executable[0].replace("python.exe", "pythonw.exe") executable[0] = executable[0].replace("python.exe", "pythonw.exe")
executable.extend(["-m", "rare"])
else: else:
executable = [sys.executable] executable = [sys.executable]
@ -195,7 +197,7 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if not for_rare: if not for_rare:
igame = core.get_installed_game(app_name) 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", "") icon = icon.replace(".png", "")
if platform.system() == "Linux": if platform.system() == "Linux":
@ -208,6 +210,7 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if not os.path.exists(path): if not os.path.exists(path):
return False return False
executable = get_rare_executable() executable = get_rare_executable()
executable = shlex.join(executable)
if for_rare: if for_rare:
with open(os.path.join(path, "Rare.desktop"), "w") as desktop_file: with open(os.path.join(path, "Rare.desktop"), "w") as desktop_file:
@ -274,20 +277,14 @@ def create_desktop_link(app_name=None, core: LegendaryCore = None, type_of_link=
if len(executable) > 1: if len(executable) > 1:
arguments.extend(executable[1:]) arguments.extend(executable[1:])
executable = executable[0] 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]))
if not for_rare: if not for_rare:
arguments.extend(["launch", app_name]) arguments.extend(["launch", app_name])
shortcut.Targetpath = executable shortcut.Targetpath = executable
shortcut.Arguments = shlex.join(arguments)
# Maybe there is a better solution, but windows does not accept single quotes (Windows is weird) # Maybe there is a better solution, but windows does not accept single quotes (Windows is weird)
shortcut.Arguments = shortcut.Arguments.replace("'", '"') shortcut.Arguments = shlex.join(arguments).replace("'", '"')
if for_rare: if for_rare:
shortcut.WorkingDirectory = QStandardPaths.writableLocation(QStandardPaths.HomeLocation) shortcut.WorkingDirectory = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)

View file

@ -1,13 +1,51 @@
import os
import shutil
from pathlib import Path from pathlib import Path
from PyQt5.QtCore import QStandardPaths from PyQt5.QtCore import QStandardPaths
resources_path = Path(__file__).absolute().parent.parent.joinpath("resources") 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): # lk: delete old Rare directories
if not path.exists(): for old_dir in [
path.mkdir(parents=True) 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):
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)

View file

@ -6,13 +6,11 @@ from datetime import date
import requests import requests
from PyQt5.QtCore import pyqtSignal, QRunnable, QObject, QCoreApplication 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.shared import LegendaryCoreSingleton, ArgumentsSingleton
from rare.utils.paths import data_dir, cache_dir from rare.utils.paths import data_dir, cache_dir
replace_chars = ",;.:-_ " replace_chars = ",;.:-_ "
file = os.path.join(cache_dir, "game_list.json")
url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/" url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"
@ -20,7 +18,7 @@ class SteamWorker(QRunnable):
class Signals(QObject): class Signals(QObject):
rating_signal = pyqtSignal(str) rating_signal = pyqtSignal(str)
app_name:str = "" app_name: str = ""
def __init__(self, core: LegendaryCore): def __init__(self, core: LegendaryCore):
super(SteamWorker, self).__init__() super(SteamWorker, self).__init__()
@ -55,7 +53,7 @@ def get_rating(app_name: str):
args = ArgumentsSingleton() args = ArgumentsSingleton()
global __grades_json global __grades_json
if __grades_json is None: 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.loads(open(p).read())
__grades_json = grades __grades_json = grades
else: else:
@ -72,7 +70,7 @@ def get_rating(app_name: str):
steam_id = get_steam_id(game.app_title) steam_id = get_steam_id(game.app_title)
grade = get_grade(steam_id) grade = get_grade(steam_id)
grades[app_name] = {"steam_id": steam_id, "grade": grade} 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.write(json.dumps(grades))
f.close() f.close()
return grade return grade
@ -96,8 +94,8 @@ def get_grade(steam_code):
def load_json() -> dict: def load_json() -> dict:
file = os.path.join(cache_dir(), "game_list.json")
if not os.path.exists(file): if not os.path.exists(file):
response = requests.get(url) response = requests.get(url)
steam_ids = json.loads(response.text)["applist"]["apps"] steam_ids = json.loads(response.text)["applist"]["apps"]
ids = {} ids = {}
@ -113,6 +111,7 @@ def load_json() -> dict:
def get_steam_id(title: str): def get_steam_id(title: str):
file = os.path.join(cache_dir(), "game_list.json")
# workarounds for satisfactory # workarounds for satisfactory
title = title.replace("Early Access", "").replace("Experimental", "").strip() title = title.replace("Early Access", "").replace("Experimental", "").strip()
global __steam_ids_json 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 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()) json_table = json.loads(open(file, "r").read())
today = date.today() today = date.today()

View file

@ -1,5 +1,6 @@
import os import os
import sys import sys
from argparse import Namespace
from logging import getLogger from logging import getLogger
from PyQt5.QtCore import Qt, QSettings, QTranslator from PyQt5.QtCore import Qt, QSettings, QTranslator
@ -10,14 +11,14 @@ from PyQt5.QtWidgets import QApplication
from legendary.core import LegendaryCore from legendary.core import LegendaryCore
import rare.resources.resources 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 from rare.utils.misc import set_color_pallete, set_style_sheet
class RareApp(QApplication): class RareApp(QApplication):
logger = getLogger("RareApp") logger = getLogger("RareApp")
def __init__(self): def __init__(self, args: Namespace):
super(RareApp, self).__init__(sys.argv) super(RareApp, self).__init__(sys.argv)
self.setQuitOnLastWindowClosed(False) self.setQuitOnLastWindowClosed(False)
if hasattr(Qt, "AA_UseHighDpiPixmaps"): if hasattr(Qt, "AA_UseHighDpiPixmaps"):
@ -25,6 +26,7 @@ class RareApp(QApplication):
self.setApplicationName("Rare") self.setApplicationName("Rare")
self.setOrganizationName("Rare") self.setOrganizationName("Rare")
paths.create_dirs()
self.settings = QSettings() self.settings = QSettings()
# Translator # Translator
@ -51,7 +53,7 @@ class RareApp(QApplication):
self.setWindowIcon(QIcon(":/images/Rare.png")) self.setWindowIcon(QIcon(":/images/Rare.png"))
def load_translator(self, lang: str): 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.translator.load(f)
self.logger.info(f"Your language is supported: {lang}") self.logger.info(f"Your language is supported: {lang}")
elif not lang == "en": elif not lang == "en":
@ -59,7 +61,7 @@ class RareApp(QApplication):
self.installTranslator(self.translator) self.installTranslator(self.translator)
# translator for qt stuff # 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 = QTranslator()
self.qt_translator.load(f) self.qt_translator.load(f)
self.installTranslator(self.qt_translator) self.installTranslator(self.qt_translator)