1
0
Fork 0
mirror of synced 2024-05-13 17:12:49 +12:00

Many optimizations, bug fixes and other small fixes

This commit is contained in:
Dummerle 2021-11-10 22:07:28 +01:00
parent f3f9fa3e1d
commit b0125ba020
No known key found for this signature in database
GPG key ID: AB68CC59CA39F2F1
16 changed files with 88 additions and 146 deletions

View file

@ -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',

View file

@ -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'}")

View file

@ -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)

View file

@ -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)

View file

@ -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:

View file

@ -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())))

View file

@ -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):

View file

@ -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())

View file

@ -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()

View file

@ -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)

View file

@ -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>

View file

@ -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)

View file

@ -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):

View file

@ -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)

View file

@ -1,5 +1,4 @@
requests
Pillow
PyQt5
QtAwesome
psutil

View file

@ -9,7 +9,6 @@ with open("README.md", "r") as fh:
requirements = [
"requests<3.0",
"pillow",
"setuptools",
"wheel",
"PyQt5",