Many optimizations, bug fixes and other small fixes
This commit is contained in:
parent
f3f9fa3e1d
commit
b0125ba020
|
@ -179,9 +179,7 @@ def start(args):
|
|||
# keep requests, asyncio and pillow quiet
|
||||
logging.getLogger('requests').setLevel(logging.WARNING)
|
||||
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
||||
logging.getLogger("PIL.TiffImagePlugin").setLevel(logging.WARNING)
|
||||
logging.getLogger("asyncio").setLevel(logging.WARNING)
|
||||
logging.getLogger("PIL.PngImagePlugin").setLevel(logging.WARNING)
|
||||
else:
|
||||
logging.basicConfig(
|
||||
format='[%(name)s] %(levelname)s: %(message)s',
|
||||
|
|
|
@ -176,7 +176,7 @@ class DownloadTab(QWidget):
|
|||
self.analysis = None
|
||||
|
||||
def statistics(self, ui_update: UIUpdate):
|
||||
self.prog_bar.setValue(ui_update.progress)
|
||||
self.prog_bar.setValue(int(ui_update.progress))
|
||||
self.dl_speed.setText(self.tr("Download speed") + f": {get_size(ui_update.download_speed)}/s")
|
||||
self.cache_used.setText(
|
||||
self.tr("Cache used") + f": {get_size(ui_update.cache_usage) if ui_update.cache_usage > 1023 else '0KB'}")
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QSettings, QObjectCleanupHandler
|
||||
from PyQt5.QtGui import QImage, QPixmap
|
||||
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget
|
||||
from legendary.models.game import Game, InstalledGame
|
||||
|
||||
import rare.shared as shared
|
||||
from legendary.models.game import Game, InstalledGame
|
||||
from rare.components.dialogs.uninstall_dialog import UninstallDialog
|
||||
from rare.ui.components.tabs.games.games_tab import Ui_GamesTab
|
||||
from rare.utils import legendary_utils
|
||||
from rare.utils.extra_widgets import FlowLayout
|
||||
from rare.utils.utils import get_pixmap, download_image, get_uninstalled_pixmap
|
||||
from rare.utils.utils import get_pixmap, download_image
|
||||
from .game_info import GameInfoTabs
|
||||
from .game_info.uninstalled_info import UninstalledInfoTabs
|
||||
from .game_widgets.base_installed_widget import BaseInstalledWidget
|
||||
|
@ -152,7 +153,7 @@ class GamesTab(QStackedWidget, Ui_GamesTab):
|
|||
|
||||
# add installed games
|
||||
for igame in self.installed:
|
||||
icon_widget, list_widget = self.add_installed_widget(self.core.get_game(igame.app_name))
|
||||
icon_widget, list_widget = self.add_installed_widget(self.core.get_game(igame.app_name, update_meta=False))
|
||||
self.icon_view.layout().addWidget(icon_widget)
|
||||
self.list_view.layout().addWidget(list_widget)
|
||||
|
||||
|
@ -207,11 +208,17 @@ class GamesTab(QStackedWidget, Ui_GamesTab):
|
|||
return icon_widget, list_widget
|
||||
|
||||
def add_uninstalled_widget(self, game):
|
||||
pixmap = get_uninstalled_pixmap(game.app_name)
|
||||
pixmap = get_pixmap(game.app_name)
|
||||
img = pixmap.toImage()
|
||||
img = img.convertToFormat(QImage.Format_Grayscale8)
|
||||
pixmap = QPixmap.fromImage(img)
|
||||
if pixmap.isNull():
|
||||
logger.info(game.app_title + " has a corrupt image. Reloading...")
|
||||
logger.warning(game.app_title + " has a corrupt image. Reloading...")
|
||||
download_image(game, force=True)
|
||||
pixmap = get_uninstalled_pixmap(game.app_name)
|
||||
pixmap = get_pixmap(game.app_name)
|
||||
img = pixmap.toImage()
|
||||
img = img.convertToFormat(QImage.Format_Grayscale8)
|
||||
pixmap = QPixmap.fromImage(img)
|
||||
|
||||
icon_widget = IconWidgetUninstalled(game, self.core, pixmap)
|
||||
icon_widget.show_uninstalled_info.connect(self.show_uninstalled_info)
|
||||
|
|
|
@ -88,7 +88,7 @@ class GameDlcWidget(QFrame, Ui_GameDlcWidget):
|
|||
self.dlc = dlc
|
||||
|
||||
pixmap = get_pixmap(dlc.app_name)
|
||||
self.image.setPixmap(pixmap.scaledToHeight(pixmap.height() * 0.5))
|
||||
self.image.setPixmap(pixmap.scaledToHeight(int(pixmap.height() * 0.5)))
|
||||
|
||||
self.dlc_name.setText(dlc.app_title)
|
||||
self.version.setText(dlc.app_version)
|
||||
|
|
|
@ -7,7 +7,7 @@ from PyQt5.QtWidgets import QWidget, QMessageBox
|
|||
from legendary.models.game import Game, InstalledGame
|
||||
from rare import shared
|
||||
from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo
|
||||
from rare.utils.legendary_utils import VerifyThread
|
||||
from rare.utils.legendary_utils import VerifyWorker
|
||||
from rare.utils.models import InstallOptionsModel
|
||||
from rare.utils.steam_grades import SteamWorker
|
||||
from rare.utils.utils import get_size, get_pixmap
|
||||
|
@ -42,6 +42,8 @@ class GameInfo(QWidget, Ui_GameInfo):
|
|||
self.verify_button.clicked.connect(self.verify)
|
||||
self.repair_button.clicked.connect(self.repair)
|
||||
|
||||
self.thread_pool = QThreadPool.globalInstance()
|
||||
|
||||
def repair(self):
|
||||
repair_file = os.path.join(self.core.lgd.get_tmp_path(), f'{self.game.app_name}.repair')
|
||||
if not os.path.exists(repair_file):
|
||||
|
@ -53,18 +55,17 @@ class GameInfo(QWidget, Ui_GameInfo):
|
|||
|
||||
def verify(self):
|
||||
self.verify_widget.setCurrentIndex(1)
|
||||
verify_thread = VerifyThread(self.core, self.game.app_name)
|
||||
verify_thread.status.connect(self.verify_staistics)
|
||||
verify_thread.summary.connect(self.finish_verify)
|
||||
verify_thread.finished.connect(verify_thread.deleteLater)
|
||||
verify_thread.start()
|
||||
verify_worker = VerifyWorker(self.core, self.game.app_name)
|
||||
verify_worker.signals.status.connect(self.verify_staistics)
|
||||
verify_worker.signals.summary.connect(self.finish_verify)
|
||||
self.thread_pool.start(verify_worker)
|
||||
self.verify_progress.setValue(0)
|
||||
self.verify_threads[self.game.app_name] = verify_thread
|
||||
self.verify_threads[self.game.app_name] = verify_worker
|
||||
|
||||
def verify_staistics(self, progress):
|
||||
# checked, max, app_name
|
||||
if progress[2] == self.game.app_name:
|
||||
self.verify_progress.setValue(progress[0] * 100 / progress[1])
|
||||
self.verify_progress.setValue(progress[0] * 100 // progress[1])
|
||||
|
||||
def finish_verify(self, failed, missing, app_name):
|
||||
if failed == missing == 0:
|
||||
|
|
|
@ -63,7 +63,7 @@ class PaintWidget(QWidget):
|
|||
painter.begin(self)
|
||||
painter.drawPixmap(self.rect(), self.image)
|
||||
|
||||
w = self.image.width() * (1 - self.status / 100)
|
||||
w = self.image.width() * (1 - self.status // 100)
|
||||
painter.drawPixmap(self.image.width() - w, 0, w, self.image.height(),
|
||||
self.new_image.copy(QRect(self.image.width() - w, 0, w, self.image.height())))
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ import platform
|
|||
from logging import getLogger
|
||||
from typing import Tuple, Iterable
|
||||
|
||||
from PyQt5.QtCore import Qt, QThreadPool, QRunnable, pyqtSlot, QFileSystemWatcher
|
||||
from PyQt5.QtWidgets import QGroupBox, QListWidgetItem, QFileDialog, QMessageBox, QErrorMessage
|
||||
from PyQt5.QtCore import Qt, QThreadPool, QRunnable, pyqtSlot
|
||||
from PyQt5.QtWidgets import QGroupBox, QListWidgetItem, QFileDialog, QMessageBox
|
||||
|
||||
import rare.shared as shared
|
||||
from rare.ui.components.tabs.games.import_sync.egl_sync_group import Ui_EGLSyncGroup
|
||||
|
@ -25,14 +25,17 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
|
|||
|
||||
self.core = shared.core
|
||||
self.threadpool = QThreadPool.globalInstance()
|
||||
if not self.core.egl.programdata_path:
|
||||
if platform.system() == 'Windows':
|
||||
self.egl_path_info.setText(os.path.expandvars(PathSpec.egl_programdata))
|
||||
else:
|
||||
self.egl_path_info.setText(self.tr('Updating...'))
|
||||
wine_resolver = WineResolver(PathSpec.egl_programdata, 'default', shared.core)
|
||||
wine_resolver.signals.result_ready.connect(self.wine_resolver_cb)
|
||||
self.threadpool.start(wine_resolver)
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
self.egl_path_info.setText(os.path.expandvars(PathSpec.egl_programdata))
|
||||
else:
|
||||
self.egl_path_info.setText(self.tr('Updating...'))
|
||||
wine_resolver = WineResolver(PathSpec.egl_programdata, 'default', shared.core)
|
||||
wine_resolver.signals.result_ready.connect(self.wine_resolver_cb)
|
||||
self.threadpool.start(wine_resolver)
|
||||
self.egl_path_info.setText(self.core.egl.programdata_path)
|
||||
|
||||
egl_path = shared.core.egl.programdata_path
|
||||
if egl_path is None:
|
||||
|
@ -73,10 +76,14 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
|
|||
|
||||
def wine_resolver_cb(self, path):
|
||||
self.egl_path_info.setText(path)
|
||||
if not path:
|
||||
if not path or not os.path.exists(path):
|
||||
self.egl_path_info.setText(
|
||||
self.tr('Default Wine prefix is unset, or path does not exist. '
|
||||
'Create it or configure it in Settings -> Linux'))
|
||||
elif os.path.exists(path):
|
||||
self.core.egl.programdata_path = path
|
||||
self.core.lgd.config.set("Legendary", "egl_programdata", path)
|
||||
self.core.lgd.save_config()
|
||||
|
||||
@staticmethod
|
||||
def egl_path_edit_cb(path) -> Tuple[bool, str]:
|
||||
|
@ -95,7 +102,7 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
|
|||
|
||||
@staticmethod
|
||||
def egl_path_save_cb(path):
|
||||
if not path:
|
||||
if not path or not os.path.exists(path):
|
||||
# This is the same as "--unlink"
|
||||
shared.core.egl.programdata_path = None
|
||||
shared.core.lgd.config.remove_option('Legendary', 'egl_programdata')
|
||||
|
@ -107,6 +114,7 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
|
|||
else:
|
||||
shared.core.egl.programdata_path = path
|
||||
shared.core.lgd.config.set("Legendary", "egl_programdata", path)
|
||||
|
||||
shared.core.lgd.save_config()
|
||||
|
||||
def egl_path_changed(self, path):
|
||||
|
|
|
@ -37,7 +37,7 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
self.wishlist = []
|
||||
|
||||
def handle_wishlist_update(self, data):
|
||||
if data[0] == "error":
|
||||
if data and data[0] == "error":
|
||||
return
|
||||
self.wishlist = [i["offer"]["title"] for i in data]
|
||||
if self.title_str in self.wishlist:
|
||||
|
@ -88,6 +88,8 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
# init API request
|
||||
if slug:
|
||||
self.api_core.get_game(slug, is_bundle, self.data_received)
|
||||
else:
|
||||
self.data_received({})
|
||||
|
||||
def add_to_wishlist(self):
|
||||
if not self.in_wishlist:
|
||||
|
@ -108,15 +110,17 @@ class ShopGameInfo(QWidget, Ui_shop_info):
|
|||
self.price.setText("Error")
|
||||
self.req_group_box.setVisible(False)
|
||||
for img in self.data.get("keyImages"):
|
||||
if img["type"] in ["DieselStoreFrontWide", "OfferImageWide", "VaultClosed", "ProductLogo"]:
|
||||
if img["type"] in ["DieselStoreFrontWide", "OfferImageTall", "VaultClosed", "ProductLogo"]:
|
||||
self.image.update_image(img["url"], size=(240, 320))
|
||||
self.image_stack.setCurrentIndex(0)
|
||||
break
|
||||
else:
|
||||
self.image_stack.setCurrentIndex(2)
|
||||
self.price.setText("")
|
||||
self.discount_price.setText("")
|
||||
self.social_link_gb.setVisible(False)
|
||||
self.tags.setText("")
|
||||
self.dev.setText(self.data.get("seller", {}).get("name", ""))
|
||||
return
|
||||
self.title.setText(self.game.title)
|
||||
self.price.setFont(QFont())
|
||||
|
|
|
@ -3,7 +3,7 @@ import logging
|
|||
import random
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QGroupBox, QScrollArea, QCheckBox, QVBoxLayout, QLabel, QPushButton
|
||||
from PyQt5.QtWidgets import QGroupBox, QScrollArea, QCheckBox, QVBoxLayout, QLabel, QPushButton, QHBoxLayout
|
||||
|
||||
from legendary.core import LegendaryCore
|
||||
from rare.components.tabs.shop import ShopApiCore
|
||||
|
@ -107,7 +107,7 @@ class ShopWidget(QScrollArea, Ui_ShopWidget):
|
|||
if item:
|
||||
item.widget().deleteLater()
|
||||
|
||||
if free_games[0] == "error":
|
||||
if free_games and free_games[0] == "error":
|
||||
self.free_widget.layout().addWidget(QLabel(self.tr("Failed to fetch free games: ") + free_games[1]))
|
||||
btn = QPushButton(self.tr("Reload"))
|
||||
self.free_widget.layout().addWidget(btn)
|
||||
|
@ -116,11 +116,11 @@ class ShopWidget(QScrollArea, Ui_ShopWidget):
|
|||
return
|
||||
|
||||
self.free_games_now = QGroupBox(self.tr("Now Free"))
|
||||
self.free_games_now.setLayout(FlowLayout())
|
||||
self.free_games_now.setLayout(QHBoxLayout())
|
||||
self.free_widget.layout().addWidget(self.free_games_now)
|
||||
|
||||
self.coming_free_games = QGroupBox(self.tr("Free Games next week"))
|
||||
self.coming_free_games.setLayout(FlowLayout())
|
||||
self.coming_free_games.setLayout(QHBoxLayout())
|
||||
self.free_widget.layout().addWidget(self.coming_free_games)
|
||||
|
||||
date = datetime.datetime.now()
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Form implementation generated from reading ui file 'rare/ui/components/tabs/store/store.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.4
|
||||
# Created by: PyQt5 UI code generator 5.15.6
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
@ -44,14 +44,7 @@ class Ui_ShopWidget(object):
|
|||
self.free_stack = QtWidgets.QStackedWidget(self.free_game_group_box)
|
||||
self.free_stack.setObjectName("free_stack")
|
||||
self.free_widget = QtWidgets.QWidget()
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.free_widget.sizePolicy().hasHeightForWidth())
|
||||
self.free_widget.setSizePolicy(sizePolicy)
|
||||
self.free_widget.setObjectName("free_widget")
|
||||
self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.free_widget)
|
||||
self.verticalLayout_8.setObjectName("verticalLayout_8")
|
||||
self.free_stack.addWidget(self.free_widget)
|
||||
self.verticalLayout_3.addWidget(self.free_stack)
|
||||
self.verticalLayout.addWidget(self.free_game_group_box)
|
||||
|
|
|
@ -48,17 +48,7 @@
|
|||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="free_stack">
|
||||
<widget class="QWidget" name="free_widget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred"
|
||||
vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout"
|
||||
name="verticalLayout_8"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="free_widget"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import io
|
||||
import os
|
||||
from logging import getLogger
|
||||
from typing import Callable, Tuple
|
||||
|
||||
import PIL
|
||||
from PIL import Image
|
||||
from PyQt5.QtCore import Qt, QCoreApplication, QRect, QSize, QPoint, pyqtSignal, QFileInfo
|
||||
from PyQt5.QtGui import QMovie, QPixmap, QFontMetrics
|
||||
from PyQt5.QtGui import QMovie, QPixmap, QFontMetrics, QImage
|
||||
from PyQt5.QtWidgets import QLayout, QStyle, QSizePolicy, QLabel, QFileDialog, QHBoxLayout, QWidget, QPushButton, \
|
||||
QStyleOptionTab, QStylePainter, QTabBar, QLineEdit, QToolButton, QTabWidget, QCompleter, QFileSystemModel, \
|
||||
QStyledItemDelegate, QFileIconProvider
|
||||
|
@ -436,18 +433,12 @@ class ImageLabel(QLabel):
|
|||
self.setPixmap(QPixmap())
|
||||
except Exception:
|
||||
logger.warning("C++ object already removed, when image ready")
|
||||
try:
|
||||
image: Image.Image = Image.open(io.BytesIO(data))
|
||||
except PIL.UnidentifiedImageError:
|
||||
return
|
||||
image = image.resize((self.img_size[:2]))
|
||||
byte_array = io.BytesIO()
|
||||
image.save(byte_array, format="PNG")
|
||||
# pixmap = QPixmap.fromImage(ImageQt(image))
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(byte_array.getvalue())
|
||||
# pixmap = QPixmap.fromImage(ImageQt.ImageQt(image))
|
||||
pixmap = pixmap.scaled(*self.img_size[:2], Qt.KeepAspectRatioByExpanding)
|
||||
image = QImage()
|
||||
image.loadFromData(data)
|
||||
image = image.scaled(*self.img_size[:2], Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation)
|
||||
|
||||
pixmap = QPixmap().fromImage(image)
|
||||
self.setPixmap(pixmap)
|
||||
|
||||
def show_image(self):
|
||||
|
@ -479,5 +470,5 @@ class ButtonLineEdit(QLineEdit):
|
|||
buttonSize = self.button.sizeHint()
|
||||
frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
|
||||
self.button.move(self.rect().right() - frameWidth - buttonSize.width(),
|
||||
(self.rect().bottom() - buttonSize.height() + 1) / 2)
|
||||
(self.rect().bottom() - buttonSize.height() + 1) // 2)
|
||||
super(ButtonLineEdit, self).resizeEvent(event)
|
||||
|
|
|
@ -3,7 +3,7 @@ import platform
|
|||
import shutil
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QProcess, QProcessEnvironment, QThread, pyqtSignal
|
||||
from PyQt5.QtCore import QProcess, QProcessEnvironment, pyqtSignal, QRunnable, QObject, QCoreApplication
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
from legendary.core import LegendaryCore
|
||||
|
@ -119,13 +119,18 @@ def update_manifest(app_name: str, core: LegendaryCore):
|
|||
version=new_manifest.meta.build_version)
|
||||
|
||||
|
||||
class VerifyThread(QThread):
|
||||
class VerifySignals(QObject):
|
||||
status = pyqtSignal(tuple)
|
||||
summary = pyqtSignal(int, int, str)
|
||||
|
||||
|
||||
class VerifyWorker(QRunnable):
|
||||
def __init__(self, core, app_name):
|
||||
super(VerifyThread, self).__init__()
|
||||
super(VerifyWorker, self).__init__()
|
||||
self.core, self.app_name = core, app_name
|
||||
self.signals = VerifySignals()
|
||||
self.tr = QCoreApplication.translate
|
||||
self.setAutoDelete(True)
|
||||
|
||||
def run(self):
|
||||
if not self.core.is_installed(self.app_name):
|
||||
|
@ -139,7 +144,7 @@ class VerifyThread(QThread):
|
|||
update_manifest(self.app_name, self.core)
|
||||
manifest_data, _ = self.core.get_installed_manifest(self.app_name)
|
||||
if not manifest_data:
|
||||
self.summary.emit(0, 0, self.app_name)
|
||||
self.signals.summary.emit(0, 0, self.app_name)
|
||||
return
|
||||
|
||||
manifest = self.core.load_manifest(manifest_data)
|
||||
|
@ -158,7 +163,7 @@ class VerifyThread(QThread):
|
|||
repair_file = []
|
||||
try:
|
||||
for result, path, result_hash in validate_files(igame.install_path, file_list):
|
||||
self.status.emit((self.num, self.total, self.app_name))
|
||||
self.signals.status.emit((self.num, self.total, self.app_name))
|
||||
self.num += 1
|
||||
|
||||
if result == VerifyResult.HASH_MATCH:
|
||||
|
@ -175,10 +180,10 @@ class VerifyThread(QThread):
|
|||
logger.error(f'Other failure (see log), treating file as missing: "{path}"')
|
||||
missing.append(path)
|
||||
except OSError as e:
|
||||
QMessageBox.warning(None, "Error", self.tr("Path does not exist"))
|
||||
QMessageBox.warning(None, "Error", self.tr("VerifyWorker", "Path does not exist"))
|
||||
logger.error(str(e))
|
||||
except ValueError as e:
|
||||
QMessageBox.warning(None, "Error", self.tr("No files to validate"))
|
||||
QMessageBox.warning(None, "Error", self.tr("VerifyWorker", "No files to validate"))
|
||||
logger.error(str(e))
|
||||
|
||||
# always write repair file, even if all match
|
||||
|
@ -190,11 +195,11 @@ class VerifyThread(QThread):
|
|||
|
||||
if not missing and not failed:
|
||||
logger.info('Verification finished successfully.')
|
||||
self.summary.emit(0, 0, self.app_name)
|
||||
self.signals.summary.emit(0, 0, self.app_name)
|
||||
|
||||
else:
|
||||
logger.error(f'Verification finished, {len(failed)} file(s) corrupted, {len(missing)} file(s) are missing.')
|
||||
self.summary.emit(len(failed), len(missing), self.app_name)
|
||||
self.signals.summary.emit(len(failed), len(missing), self.app_name)
|
||||
|
||||
|
||||
def import_game(core: LegendaryCore, app_name: str, path: str):
|
||||
|
|
|
@ -9,9 +9,8 @@ from logging import getLogger
|
|||
from typing import Tuple
|
||||
|
||||
import requests
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QRunnable, QSettings
|
||||
from PyQt5.QtGui import QPalette, QColor, QPixmap
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QRunnable, QSettings, Qt
|
||||
from PyQt5.QtGui import QPalette, QColor, QPixmap, QImage
|
||||
|
||||
from .models import PathSpec
|
||||
|
||||
|
@ -49,7 +48,7 @@ def download_images(signal: pyqtSignal, core: LegendaryCore):
|
|||
except json.decoder.JSONDecodeError:
|
||||
shutil.rmtree(f"{image_dir}/{game.app_name}")
|
||||
download_image(game)
|
||||
signal.emit(i / len(game_list) * 100)
|
||||
signal.emit(i * 100 // len(game_list))
|
||||
|
||||
|
||||
def download_image(game, force=False):
|
||||
|
@ -58,13 +57,12 @@ def download_image(game, force=False):
|
|||
if not os.path.isdir(f"{image_dir}/" + game.app_name):
|
||||
os.mkdir(f"{image_dir}/" + game.app_name)
|
||||
|
||||
# to git picture updates
|
||||
# to get picture updates
|
||||
if not os.path.isfile(f"{image_dir}/{game.app_name}/image.json"):
|
||||
json_data = {"DieselGameBoxTall": None, "DieselGameBoxLogo": None, "Thumbnail": None}
|
||||
else:
|
||||
json_data = json.load(open(f"{image_dir}/{game.app_name}/image.json", "r"))
|
||||
# Download
|
||||
download = False
|
||||
for image in game.metadata["keyImages"]:
|
||||
if image["type"] == "DieselGameBoxTall" or image["type"] == "DieselGameBoxLogo" or image["type"] == "Thumbnail":
|
||||
if image["type"] not in json_data.keys():
|
||||
|
@ -77,63 +75,11 @@ def download_image(game, force=False):
|
|||
json.dump(json_data, open(f"{image_dir}/{game.app_name}/image.json", "w"))
|
||||
logger.info(f"Download Image for Game: {game.app_title}")
|
||||
url = image["url"]
|
||||
with open(f"{image_dir}/{game.app_name}/{image['type']}.png", "wb") as f:
|
||||
f.write(requests.get(url).content)
|
||||
try:
|
||||
img = Image.open(f"{image_dir}/{game.app_name}/{image['type']}.png")
|
||||
img = img.resize((200, int(200 * 4 / 3)))
|
||||
img.save(f"{image_dir}/{game.app_name}/{image['type']}.png")
|
||||
download = True
|
||||
except UnidentifiedImageError as e:
|
||||
logger.warning(e)
|
||||
|
||||
# scale and grey
|
||||
uninstalled_image = os.path.join(image_dir, game.app_name + '/UninstalledArt.png')
|
||||
if download and os.path.exists(uninstalled_image):
|
||||
os.remove(uninstalled_image)
|
||||
elif os.path.exists(uninstalled_image):
|
||||
return
|
||||
|
||||
if os.path.exists(os.path.join(image_dir, f"{game.app_name}/DieselGameBoxTall.png")):
|
||||
# finalArt = Image.open(f'{image_dir}/' + game.app_name + '/DieselGameBoxTall.png')
|
||||
# finalArt.save(f'{image_dir}/{game.app_name}/FinalArt.png')
|
||||
# And same with the grayscale one
|
||||
try:
|
||||
bg = Image.open(os.path.join(image_dir, f"{game.app_name}/DieselGameBoxTall.png"))
|
||||
except UnidentifiedImageError:
|
||||
logger.warning("Reload image for " + game.app_title)
|
||||
# avoid endless recursion
|
||||
if not force:
|
||||
download_image(game, True)
|
||||
return
|
||||
uninstalledArt = bg.convert('L')
|
||||
uninstalledArt = uninstalledArt.resize((200, int(200 * 4 / 3)))
|
||||
uninstalledArt.save(f'{image_dir}/{game.app_name}/UninstalledArt.png')
|
||||
|
||||
elif os.path.isfile(f"{image_dir}/{game.app_name}/DieselGameBoxLogo.png"):
|
||||
bg: Image.Image = Image.open(f"{image_dir}/{game.app_name}/DieselGameBoxLogo.png")
|
||||
bg = bg.resize((int(bg.size[1] * 3 / 4), bg.size[1]))
|
||||
logo = Image.open(f'{image_dir}/{game.app_name}/DieselGameBoxLogo.png').convert('RGBA')
|
||||
wpercent = ((bg.size[0] * (3 / 4)) / float(logo.size[0]))
|
||||
hsize = int((float(logo.size[1]) * float(wpercent)))
|
||||
logo = logo.resize((int(bg.size[0] * (3 / 4)), hsize), Image.ANTIALIAS)
|
||||
# Calculate where the image has to be placed
|
||||
pasteX = int((bg.size[0] - logo.size[0]) / 2)
|
||||
pasteY = int((bg.size[1] - logo.size[1]) / 2)
|
||||
# And finally copy the background and paste in the image
|
||||
# finalArt = bg.copy()
|
||||
# finalArt.paste(logo, (pasteX, pasteY), logo)
|
||||
# Write out the file
|
||||
# finalArt.save(f'{image_dir}/' + game.app_name + '/FinalArt.png')
|
||||
logoCopy = logo.copy()
|
||||
logoCopy.putalpha(int(256 * 3 / 4))
|
||||
logo.paste(logoCopy, logo)
|
||||
uninstalledArt = bg.copy()
|
||||
uninstalledArt.paste(logo, (pasteX, pasteY), logo)
|
||||
uninstalledArt = uninstalledArt.convert('L')
|
||||
uninstalledArt.save(f'{image_dir}/' + game.app_name + '/UninstalledArt.png')
|
||||
else:
|
||||
logger.warning(f"File {image_dir}/{game.app_name}/DieselGameBoxTall.png doesn't exist")
|
||||
resp = requests.get(url)
|
||||
img = QImage()
|
||||
img.loadFromData(resp.content)
|
||||
img = img.scaled(200, 200 * 4 // 3, Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation)
|
||||
img.save(os.path.join(image_dir, game.app_name, image["type"] + ".png"), format="PNG")
|
||||
|
||||
|
||||
color_role_map = {
|
||||
|
@ -359,7 +305,8 @@ def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop") -
|
|||
|
||||
# Icon
|
||||
if not os.path.exists(icon + ".ico"):
|
||||
img = Image.open(icon + ".png")
|
||||
img = QImage()
|
||||
img.load(icon + ".png")
|
||||
img.save(icon + ".ico")
|
||||
logger.info("Create Icon")
|
||||
shortcut.IconLocation = os.path.join(icon + ".ico")
|
||||
|
@ -398,7 +345,7 @@ def optimal_text_background(image: list) -> Tuple[int, int, int]:
|
|||
containing RGB tuples, ranging from 0 to 255.
|
||||
"""
|
||||
# cursed, I know
|
||||
average = map(lambda value: value / len(image), map(sum, zip(*image)))
|
||||
average = map(lambda value: value // len(image), map(sum, zip(*image)))
|
||||
inverted = map(lambda value: 255 - value, average)
|
||||
return tuple(inverted)
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
requests
|
||||
Pillow
|
||||
PyQt5
|
||||
QtAwesome
|
||||
psutil
|
||||
|
|
Loading…
Reference in a new issue