import json import logging import os from PyQt5 import QtGui from PyQt5.QtCore import pyqtSignal, QSettings, Qt, QUrl, QJsonParseError, QJsonDocument from PyQt5.QtGui import QPixmap from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel from rare.utils.extra_widgets import ImageLabel from rare.utils.utils import get_lang logger = logging.getLogger("GameWidgets") class GameWidget(QWidget): show_info = pyqtSignal(dict) def __init__(self, path, json_info=None, width=300): super(GameWidget, self).__init__() self.manager = QNetworkAccessManager() self.width = width if json_info: self.init_ui(json_info, path) self.path = path def init_ui(self, json_info, path): self.path = path self.layout = QVBoxLayout() self.image = ImageLabel() self.json_info = json_info self.slug = json_info["productSlug"] self.title = json_info["title"] for img in json_info["keyImages"]: if img["type"] in ["DieselStoreFrontWide", "OfferImageWide", "VaultClosed"]: if img["type"] == "VaultClosed" and self.title != "Mystery Game": continue self.image.update_image(img["url"], json_info["title"], (self.width, int(self.width * 9 / 16))) break else: logger.info(", ".join([img["type"] for img in json_info["keyImages"]])) # print(json_info["keyImages"]) save = QSettings().value("cache_images", True, bool) if os.path.exists(p := os.path.join(self.path, f"{json_info['title']}_wide.png")) and save: self.image.setPixmap(QPixmap(p) .scaled(self.width, int(self.width * 9 / 16), transformMode=Qt.SmoothTransformation)) else: for img in json_info["keyImages"]: if img["type"] in ["DieselStoreFrontWide", "VaultClosed"]: if img["type"] == "VaultClosed" and self.title != "Mystery Game": continue self.image_request = self.manager.get(QNetworkRequest(QUrl(img["url"]))) self.image_request.finished.connect(lambda: self.image_ready(save)) break else: # No image found logger.error(f"No image found for {self.title}") self.layout.addWidget(self.image) self.title_label = QLabel(json_info["title"]) self.title_label.setWordWrap(True) self.layout.addWidget(self.title_label) self.setLayout(self.layout) def image_ready(self, save: bool): if self.image_request: if self.image_request.error() == QNetworkReply.NoError: data = self.image_request.readAll().data() if save: with open(os.path.join(self.path, f"{self.title}_wide.png"), "wb") as file: file.write(data) file.close() pixmap = QPixmap() pixmap.loadFromData(data) self.image.setPixmap(pixmap.scaled(self.width, int(self.width * 9 / 16), transformMode=Qt.SmoothTransformation)) def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None: self.show_info.emit(self.json_info) @classmethod def from_request(cls, name, path): c = cls(path) c.manager = QNetworkAccessManager() c.request = c.manager.get(QNetworkRequest()) locale = get_lang() payload = json.dumps({ "query": query, "variables": {"category": "games/edition/base|bundles/games|editors|software/edition/base", "count": 1, "country": "DE", "keywords": name, "locale": locale, "sortDir": "DESC", "allowCountries": locale.upper(), "start": 0, "tag": "", "withMapping": False, "withPrice": True} }).encode() request = QNetworkRequest(QUrl("https://www.epicgames.com/graphql")) request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") c.search_request = c.manager.post(request, payload) c.search_request.finished.connect(lambda: c.handle_response(path)) return c def handle_response(self, path): if self.search_request: if self.search_request.error() == QNetworkReply.NoError: error = QJsonParseError() json_data = QJsonDocument.fromJson(self.search_request.readAll().data(), error) if QJsonParseError.NoError == error.error: data = json.loads(json_data.toJson().data().decode())["data"]["Catalog"]["searchStore"][ "elements"][0] self.init_ui(data, path) else: logging.error(error.errorString()) return else: return else: return query = "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, " \ "$keywords: String, $locale: String, $namespace: String, $withMapping: Boolean = false, $itemNs: String, " \ "$sortBy: String, $sortDir: String, $start: Int, $tag: String, $releaseDate: String, $withPrice: Boolean = " \ "false, $withPromotions: Boolean = false, $priceRange: String, $freeGame: Boolean, $onSale: Boolean, " \ "$effectiveDate: String) {\n Catalog {\n searchStore(\n allowCountries: $allowCountries\n " \ "category: $category\n count: $count\n country: $country\n keywords: $keywords\n locale: " \ "$locale\n namespace: $namespace\n itemNs: $itemNs\n sortBy: $sortBy\n sortDir: " \ "$sortDir\n releaseDate: $releaseDate\n start: $start\n tag: $tag\n priceRange: " \ "$priceRange\n freeGame: $freeGame\n onSale: $onSale\n effectiveDate: $effectiveDate\n ) {" \ "\n elements {\n title\n id\n namespace\n description\n " \ "effectiveDate\n keyImages {\n type\n url\n }\n currentPrice\n " \ "seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n " \ " tags {\n id\n }\n items {\n id\n namespace\n }\n " \ "customAttributes {\n key\n value\n }\n categories {\n path\n " \ "}\n catalogNs @include(if: $withMapping) {\n mappings(pageType: \"productHome\") {\n " \ " pageSlug\n pageType\n }\n }\n offerMappings @include(if: $withMapping) " \ "{\n pageSlug\n pageType\n }\n price(country: $country) @include(if: " \ "$withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n " \ "voucherDiscount\n discount\n currencyCode\n currencyInfo {\n " \ "decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n " \ "discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n " \ " appliedRules {\n id\n endDate\n discountSetting {\n " \ "discountType\n }\n }\n }\n }\n promotions(category: " \ "$category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n " \ " startDate\n endDate\n discountSetting {\n " \ "discountType\n discountPercentage\n }\n }\n }\n " \ "upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n " \ "endDate\n discountSetting {\n discountType\n discountPercentage\n " \ " }\n }\n }\n }\n }\n paging {\n count\n " \ "total\n }\n }\n }\n}\n "