import time import webbrowser from logging import getLogger from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool, QSize from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QPushButton, QGroupBox, QVBoxLayout from legendary.models.game import Game from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton from rare.utils.misc import icon logger = getLogger("Ubisoft") class UbiGetInfoSignals(QObject): worker_finished = pyqtSignal(set, set, str) class UbiGetInfoWorker(QRunnable): def __init__(self): super(UbiGetInfoWorker, self).__init__() self.signals = UbiGetInfoSignals() self.setAutoDelete(True) self.core = LegendaryCoreSingleton() def run(self) -> None: try: external_auths = self.core.egs.get_external_auths() for ext_auth in external_auths: if ext_auth["type"] != "ubisoft": continue ubi_account_id = ext_auth["externalAuthId"] break else: self.signals.worker_finished.emit(set(), set(), "") return 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() 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)) self.signals.worker_finished.emit(set(), set(), "error") class UbiConnectSignals(QObject): linked = pyqtSignal(str) class UbiConnectWorker(QRunnable): def __init__(self, ubi_account_id, partner_link_id): super(UbiConnectWorker, self).__init__() self.signals = UbiConnectSignals() self.setAutoDelete(True) self.core = LegendaryCoreSingleton() self.ubi_account_id = ubi_account_id self.partner_link_id = partner_link_id def run(self) -> None: if not self.ubi_account_id: # debug time.sleep(2) 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_redeem_uplay_codes(self.ubi_account_id) except Exception as e: self.signals.linked.emit(str(e)) return else: 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) 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.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.link_button.clicked.connect(self.activate) self.setLayout(layout) 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) ) if self.args.debug: worker = UbiConnectWorker(None, None) else: worker = UbiConnectWorker(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.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.setToolTip(error) self.link_button.setText(self.tr("Try again")) self.link_button.setDisabled(False) 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.thread_pool = QThreadPool.globalInstance() worker = UbiGetInfoWorker() worker.signals.worker_finished.connect(self.show_ubi_games) self.thread_pool.start(worker) def show_ubi_games(self, redeemed: set, entitlements: set, ubi_account_id: str): 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" ) ) ) 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 elif ubi_account_id == "error": self.layout().addWidget(QLabel(self.tr("An error occurred"))) return 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: 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 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") ) ) else: self.layout().addWidget( QLabel(self.tr("You don't own any Ubisoft games")) ) if self.args.debug: widget = UbiLinkWidget( Game(app_name="Test", app_title="This is a test game"), ubi_account_id, ) 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)