1
0
Fork 0
mirror of synced 2024-05-19 03:52:47 +12:00

Ubisoft: Update Ubisoft redemption widget to use RareCore

* Load and populate Ubisoft information when the page is shown instead of startup.
* List all Ubisoft games, and differentiate based on whether they been redeemed.
This commit is contained in:
loathingKernel 2023-09-04 21:05:40 +03:00
parent 05070919f3
commit c0ac23b21d
No known key found for this signature in database
GPG key ID: CE0C72D0B53821FD
5 changed files with 179 additions and 107 deletions

View file

@ -36,8 +36,8 @@ class IntegrationsTabs(SideTabWidget):
)
self.ubisoft_group = UbisoftGroup(self.eos_ubisoft)
self.eos_group = EOSGroup(self.eos_ubisoft)
self.eos_ubisoft.addWidget(self.ubisoft_group)
self.eos_ubisoft.addWidget(self.eos_group)
self.eos_ubisoft.addWidget(self.ubisoft_group)
self.eos_ubisoft_index = self.addTab(self.eos_ubisoft, self.tr("Epic Overlay and Ubisoft"))
self.setCurrentIndex(self.import_index)

View file

@ -1,14 +1,28 @@
import time
import webbrowser
from logging import getLogger
from typing import Optional
from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSize
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QPushButton, QGroupBox, QVBoxLayout
from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSize, pyqtSlot, Qt
from PyQt5.QtGui import QShowEvent
from PyQt5.QtWidgets import (
QFrame,
QLabel,
QHBoxLayout,
QSizePolicy,
QPushButton,
QGroupBox,
QVBoxLayout,
)
from legendary.models.game import Game
from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton
from rare.lgndr.core import LegendaryCore
from rare.shared import RareCore
from rare.shared.workers.worker import Worker
from rare.utils.metrics import timelogger
from rare.utils.misc import icon
from rare.widgets.elide_label import ElideLabel
from rare.widgets.loading_widget import LoadingWidget
logger = getLogger("Ubisoft")
@ -17,15 +31,16 @@ class UbiGetInfoWorker(Worker):
class Signals(QObject):
worker_finished = pyqtSignal(set, set, str)
def __init__(self):
def __init__(self, core: LegendaryCore):
super(UbiGetInfoWorker, self).__init__()
self.signals = UbiGetInfoWorker.Signals()
self.setAutoDelete(True)
self.core = LegendaryCoreSingleton()
self.core = core
def run_real(self) -> None:
try:
external_auths = self.core.egs.get_external_auths()
with timelogger(logger, "Request external auths"):
external_auths = self.core.egs.get_external_auths()
for ext_auth in external_auths:
if ext_auth["type"] != "ubisoft":
continue
@ -35,12 +50,17 @@ class UbiGetInfoWorker(Worker):
self.signals.worker_finished.emit(set(), set(), "")
return
uplay_keys = self.core.egs.store_get_uplay_codes()
with timelogger(logger, "Request uplay codes"):
uplay_keys = self.core.egs.store_get_uplay_codes()
key_list = uplay_keys["data"]["PartnerIntegration"]["accountUplayCodes"]
redeemed = {k["gameId"] for k in key_list if k["redeemedOnUplay"]}
entitlements = self.core.egs.get_user_entitlements()
if (entitlements := self.core.lgd.entitlements) is None:
with timelogger(logger, "Request entitlements"):
entitlements = self.core.egs.get_user_entitlements()
self.core.lgd.entitlements = entitlements
entitlements = {i["entitlementName"] for i in entitlements}
self.signals.worker_finished.emit(redeemed, entitlements, ubi_account_id)
except Exception as e:
logger.error(str(e))
@ -51,11 +71,11 @@ class UbiConnectWorker(Worker):
class Signals(QObject):
linked = pyqtSignal(str)
def __init__(self, ubi_account_id, partner_link_id):
def __init__(self, core: LegendaryCore, ubi_account_id, partner_link_id):
super(UbiConnectWorker, self).__init__()
self.signals = UbiConnectWorker.Signals()
self.setAutoDelete(True)
self.core = LegendaryCoreSingleton()
self.core = core
self.ubi_account_id = ubi_account_id
self.partner_link_id = partner_link_id
@ -65,9 +85,7 @@ class UbiConnectWorker(Worker):
self.signals.linked.emit("")
return
try:
self.core.egs.store_claim_uplay_code(
self.ubi_account_id, self.partner_link_id
)
self.core.egs.store_claim_uplay_code(self.ubi_account_id, self.partner_link_id)
self.core.egs.store_redeem_uplay_codes(self.ubi_account_id)
except Exception as e:
self.signals.linked.emit(str(e))
@ -76,55 +94,58 @@ class UbiConnectWorker(Worker):
self.signals.linked.emit("")
class UbiLinkWidget(QWidget):
def __init__(self, game: Game, ubi_account_id):
super(UbiLinkWidget, self).__init__()
self.args = ArgumentsSingleton()
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
class UbiLinkWidget(QFrame):
def __init__(self, game: Game, ubi_account_id, activated: bool = False, parent=None):
super(UbiLinkWidget, self).__init__(parent=parent)
self.setFrameShape(QFrame.StyledPanel)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.args = RareCore.instance().args()
self.game = game
self.ubi_account_id = ubi_account_id
self.title_label = QLabel(game.app_title)
layout.addWidget(self.title_label, stretch=1)
self.ok_indicator = QLabel()
self.ok_indicator.setPixmap(icon("fa.info-circle", color="grey").pixmap(20, 20))
self.ok_indicator = QLabel(parent=self)
self.ok_indicator.setPixmap(icon("fa.circle-o", color="grey").pixmap(20, 20))
self.ok_indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
layout.addWidget(self.ok_indicator)
self.link_button = QPushButton(
self.tr("Redeem to Ubisoft") + ": Test" if self.args.debug else ""
)
layout.addWidget(self.link_button)
self.title_label = ElideLabel(game.app_title, parent=self)
self.link_button = QPushButton(self.tr("Redeem in Ubisoft"), parent=self)
self.link_button.setMinimumWidth(150)
self.link_button.clicked.connect(self.activate)
self.setLayout(layout)
if activated:
self.link_button.setText(self.tr("Already activated"))
self.link_button.setDisabled(True)
self.ok_indicator.setPixmap(icon("fa.check-circle-o", color="green").pixmap(QSize(20, 20)))
layout = QHBoxLayout(self)
layout.setContentsMargins(-1, 0, 0, 0)
layout.addWidget(self.ok_indicator)
layout.addWidget(self.title_label, stretch=1)
layout.addWidget(self.link_button)
def activate(self):
self.link_button.setDisabled(True)
# self.ok_indicator.setPixmap(icon("mdi.loading", color="grey").pixmap(20, 20))
self.ok_indicator.setPixmap(
icon("mdi.transit-connection-horizontal", color="grey").pixmap(20, 20)
)
self.ok_indicator.setPixmap(icon("mdi.transit-connection-horizontal", color="grey").pixmap(20, 20))
if self.args.debug:
worker = UbiConnectWorker(None, None)
worker = UbiConnectWorker(RareCore.instance().core(), None, None)
else:
worker = UbiConnectWorker(self.ubi_account_id, self.game.partner_link_id)
worker = UbiConnectWorker(
RareCore.instance().core(), self.ubi_account_id, self.game.partner_link_id
)
worker.signals.linked.connect(self.worker_finished)
QThreadPool.globalInstance().start(worker)
def worker_finished(self, error):
if not error:
self.ok_indicator.setPixmap(
icon("ei.ok-circle", color="green").pixmap(QSize(20, 20))
)
self.ok_indicator.setPixmap(icon("fa.check-circle-o", color="green").pixmap(QSize(20, 20)))
self.link_button.setDisabled(True)
self.link_button.setText(self.tr("Already activated"))
else:
self.ok_indicator.setPixmap(
icon("fa.info-circle", color="red").pixmap(QSize(20, 20))
)
self.ok_indicator.setPixmap(icon("fa.times-circle-o", color="red").pixmap(QSize(20, 20)))
self.ok_indicator.setToolTip(error)
self.link_button.setText(self.tr("Try again"))
self.link_button.setDisabled(False)
@ -134,86 +155,120 @@ class UbisoftGroup(QGroupBox):
def __init__(self, parent=None):
super(UbisoftGroup, self).__init__(parent=parent)
self.setTitle(self.tr("Link Ubisoft Games"))
self.setLayout(QVBoxLayout())
self.core = LegendaryCoreSingleton()
self.args = ArgumentsSingleton()
self.rcore = RareCore.instance()
self.core = RareCore.instance().core()
self.args = RareCore.instance().args()
self.thread_pool = QThreadPool.globalInstance()
worker = UbiGetInfoWorker()
worker.signals.worker_finished.connect(self.show_ubi_games)
self.thread_pool.start(worker)
self.worker: Optional[UbiGetInfoWorker] = None
self.info_label = QLabel(parent=self)
self.info_label.setText(self.tr("Getting information about your redeemable Ubisoft games."))
self.browser_button = QPushButton(self.tr("Link Ubisoft acccount"), parent=self)
self.browser_button.setMinimumWidth(140)
self.browser_button.clicked.connect(
lambda: webbrowser.open("https://www.epicgames.com/id/link/ubisoft")
)
self.browser_button.setEnabled(False)
self.loading_widget = LoadingWidget(self)
self.loading_widget.stop()
header_layout = QHBoxLayout()
header_layout.addWidget(self.info_label, stretch=1)
header_layout.addWidget(self.browser_button)
layout = QVBoxLayout(self)
layout.addLayout(header_layout)
layout.addWidget(self.loading_widget)
def showEvent(self, a0: QShowEvent) -> None:
if a0.spontaneous():
return super().showEvent(a0)
if self.worker is not None:
return
for widget in self.findChildren(UbiLinkWidget, options=Qt.FindDirectChildrenOnly):
widget.deleteLater()
self.loading_widget.start()
self.worker = UbiGetInfoWorker(self.core)
self.worker.signals.worker_finished.connect(self.show_ubi_games)
self.thread_pool.start(self.worker)
super().showEvent(a0)
@pyqtSlot(set, set, str)
def show_ubi_games(self, redeemed: set, entitlements: set, ubi_account_id: str):
self.worker = None
if not redeemed and ubi_account_id != "error":
logger.error(
"No linked ubisoft account found! Link your accounts via your browser and try again."
)
self.layout().addWidget(
QLabel(
self.tr(
"Your account is not linked with Ubisoft. Please link your account first"
)
)
self.info_label.setText(
self.tr("Your account is not linked with Ubisoft. Please link your account and try again.")
)
open_browser_button = QPushButton(self.tr("Open link page"))
open_browser_button.clicked.connect(
lambda: webbrowser.open("https://www.epicgames.com/id/link/ubisoft")
)
self.layout().addWidget(open_browser_button)
return
self.browser_button.setEnabled(True)
elif ubi_account_id == "error":
self.layout().addWidget(QLabel(self.tr("An error occurred")))
return
self.info_label.setText(
self.tr("An error has occurred while requesting your account's Ubisoft information.")
)
self.browser_button.setEnabled(True)
else:
self.browser_button.setEnabled(False)
games = self.core.get_game_list(False)
uplay_games = []
activated = 0
for game in games:
for dlc_data in game.metadata.get("dlcItemList", []):
if dlc_data["entitlementName"] not in entitlements:
uplay_games = []
activated = 0
for rgame in self.rcore.ubisoft_games:
game = rgame.game
for dlc_data in game.metadata.get("dlcItemList", []):
if dlc_data["entitlementName"] not in entitlements:
continue
try:
app_name = dlc_data["releaseInfo"][0]["appId"]
except (IndexError, KeyError):
app_name = "unknown"
dlc_game = Game(app_name=app_name, app_title=dlc_data["title"], metadata=dlc_data)
if dlc_game.partner_link_type != "ubisoft":
continue
if dlc_game.partner_link_id in redeemed:
continue
uplay_games.append(dlc_game)
if game.partner_link_type != "ubisoft":
continue
if game.partner_link_id in redeemed:
activated += 1
uplay_games.append(game)
try:
app_name = dlc_data["releaseInfo"][0]["appId"]
except (IndexError, KeyError):
app_name = "unknown"
dlc_game = Game(
app_name=app_name, app_title=dlc_data["title"], metadata=dlc_data
)
if dlc_game.partner_link_type != "ubisoft":
continue
if dlc_game.partner_link_id in redeemed:
continue
uplay_games.append(dlc_game)
if game.partner_link_type != "ubisoft":
continue
if game.partner_link_id in redeemed:
activated += 1
continue
uplay_games.append(game)
if not uplay_games:
if activated >= 1:
self.layout().addWidget(
QLabel(
self.tr("All your Ubisoft games have already been activated")
)
)
if not uplay_games:
self.info_label.setText(self.tr("You don't own any Ubisoft games."))
else:
self.layout().addWidget(
QLabel(self.tr("You don't own any Ubisoft games"))
)
if self.args.debug:
if activated == len(uplay_games):
self.info_label.setText(self.tr("All your Ubisoft games have already been activated."))
else:
self.info_label.setText(
self.tr("You have <b>{}</b> games available to redeem.").format(
len(uplay_games) - activated
)
)
logger.info(f"Found {len(uplay_games) - activated} game(s) to redeem.")
self.loading_widget.stop()
for game in uplay_games:
widget = UbiLinkWidget(
Game(app_name="Test", app_title="This is a test game"),
ubi_account_id,
game, ubi_account_id, activated=game.partner_link_id in redeemed, parent=self
)
self.layout().addWidget(widget)
return
logger.info(f"Found {len(uplay_games)} game(s) to redeem")
for game in uplay_games:
widget = UbiLinkWidget(game, ubi_account_id)
self.layout().addWidget(widget)
if self.args.debug:
widget = UbiLinkWidget(
Game(app_name="RareTestGame", app_title="Super Fake Super Rare Super Test (Super?) Game"),
ubi_account_id,
activated=False,
parent=self,
)
self.layout().addWidget(widget)
self.browser_button.setEnabled(True)

View file

@ -372,6 +372,10 @@ class RareCore(QObject):
def origin_games(self) -> Iterator[RareGame]:
return self.__filter_games(lambda game: game.is_origin and not game.is_dlc)
@property
def ubisoft_games(self) -> Iterator[RareGame]:
return self.__filter_games(lambda game: game.is_ubisoft and not game.is_dlc)
@property
def game_list(self) -> Iterator[Game]:
for game in self.games:

10
rare/utils/metrics.py Normal file
View file

@ -0,0 +1,10 @@
import time
from contextlib import contextmanager
from logging import Logger
@contextmanager
def timelogger(logger: Logger, title: str):
start = time.perf_counter()
yield
logger.debug("%s: %s seconds", title, time.perf_counter() - start)

View file

@ -32,7 +32,10 @@ class LoadingWidget(QLabel):
return super().event(e)
def showEvent(self, a0: QShowEvent) -> None:
if a0.spontaneous():
return super().showEvent(a0)
self.__center_on_parent()
super().showEvent(a0)
def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
if a0 is self.parent() and a1.type() == QEvent.Resize: