From e2fe157e136e482fa8aad4a80199f71d7d017a6b Mon Sep 17 00:00:00 2001 From: Dummerle <44114474+Dummerle@users.noreply.github.com> Date: Sun, 12 Dec 2021 01:46:38 +0100 Subject: [PATCH 1/4] Add Ubisoft activation in legendary settings --- AppImageBuilder.yml | 43 ++--- rare/components/tabs/settings/legendary.py | 164 +++++++++++++++++- rare/legendary | 2 +- rare/ui/components/tabs/settings/legendary.py | 76 ++++---- rare/ui/components/tabs/settings/legendary.ui | 135 +++++++------- 5 files changed, 291 insertions(+), 129 deletions(-) diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml index 5b55af69..78236951 100644 --- a/AppImageBuilder.yml +++ b/AppImageBuilder.yml @@ -22,27 +22,28 @@ AppDir: version: 1.7.0 exec: usr/bin/python3 exec_args: $APPDIR/usr/src/__main__.py $@ - apt:d - arch: amd64 - allow_unauthenticated: true - sources: - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy main restricted - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-updates main restricted - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy universe - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-updates universe - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy multiverse - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-updates multiverse - - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-backports main restricted - universe multiverse - - sourceline: deb http://security.ubuntu.com/ubuntu groovy-security main restricted - - sourceline: deb http://security.ubuntu.com/ubuntu groovy-security universe - - sourceline: deb http://security.ubuntu.com/ubuntu groovy-security multiverse - include: - - python3 - - python3-distutils - - python3-pyqt5 - - python3-psutil - - python3-requests + apt: + arch: amd64 + allow_unauthenticated: true + sources: + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy main restricted + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-updates main restricted + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy universe + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-updates universe + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy multiverse + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-updates multiverse + - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ groovy-backports main restricted + universe multiverse + - sourceline: deb http://security.ubuntu.com/ubuntu groovy-security main restricted + - sourceline: deb http://security.ubuntu.com/ubuntu groovy-security universe + - sourceline: deb http://security.ubuntu.com/ubuntu groovy-security multiverse + + include: + - python3 + - python3-distutils + - python3-pyqt5 + - python3-psutil + - python3-requests runtime: env: diff --git a/rare/components/tabs/settings/legendary.py b/rare/components/tabs/settings/legendary.py index a9da54bc..dc3e4782 100644 --- a/rare/components/tabs/settings/legendary.py +++ b/rare/components/tabs/settings/legendary.py @@ -1,10 +1,15 @@ import re +import webbrowser from logging import getLogger from typing import Tuple -from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox +from PyQt5.QtCore import QThreadPool, QRunnable, QObject, pyqtSignal, QSize +from PyQt5.QtGui import QPixmap +from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox, QLabel, QPushButton, QHBoxLayout +from qtawesome import icon import rare.shared as shared +from legendary.models.game import Game from rare.ui.components.tabs.settings.legendary import Ui_LegendarySettings from rare.utils.extra_widgets import PathEdit, IndicatorLineEdit from rare.utils.utils import get_size @@ -12,6 +17,102 @@ from rare.utils.utils import get_size logger = getLogger("LegendarySettings") +class Signals(QObject): + worker_finished = pyqtSignal(set, set, str) + connected = pyqtSignal(str) + +class UbiGetInfoWorker(QRunnable): + def __init__(self): + super(UbiGetInfoWorker, self).__init__() + self.signals = Signals() + self.setAutoDelete(True) + + def run(self) -> None: + try: + external_auths = shared.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 = shared.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 = shared.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 UbiConnectWorker(QRunnable): + def __init__(self, ubi_account_id, partner_link_id): + super(UbiConnectWorker, self).__init__() + self.signals = Signals() + self.setAutoDelete(True) + self.ubi_account_id = ubi_account_id + self.partner_link_id = partner_link_id + + def run(self) -> None: + try: + shared.core.egs.store_claim_uplay_code(self.ubi_account_id, self.partner_link_id) + shared.core.egs.store_redeem_uplay_codes(self.ubi_account_id) + except Exception as e: + self.signals.connected.emit(str(e)) + return + else: + self.signals.connected.emit("") + + +class UbiLinkWidget(QWidget): + def __init__(self, game: Game, ubi_account_id): + super(UbiLinkWidget, self).__init__() + self.setLayout(QHBoxLayout()) + self.game = game + self.ubi_account_id = ubi_account_id + + self.ok_indicator = QLabel() + self.ok_indicator.setVisible(False) + self.ok_indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) + self.layout().addWidget(self.ok_indicator) + + self.title_label = QLabel(game.app_title) + self.layout().addWidget(self.title_label) + if not shared.args.debug: + self.link_button = QPushButton(self.tr("Redeem to Ubisoft")) + self.layout().addWidget(self.link_button) + self.link_button.clicked.connect(self.activate) + else: + btn = QPushButton(self.tr("Test: error")) + self.layout().addWidget(btn) + btn.clicked.connect(lambda: self.worker_finished("Any Error")) + + ok_button = QPushButton(self.tr("Test: Ok")) + self.layout().addWidget(ok_button) + ok_button.clicked.connect(lambda: self.worker_finished("")) + + def activate(self): + if shared.args.debug: + self.worker_finished("Connection Error") + return + worker = UbiConnectWorker(self.ubi_account_id, self.game.partner_link_id) + worker.signals.worker_finished.connect(self.worker_finished) + QThreadPool.globalInstance().start(worker) + + def worker_finished(self, error): + self.ok_indicator.setVisible(True) + if not error: + self.ok_indicator.setPixmap(icon("ei.ok-circle", color="green").pixmap(QSize(20, 20))) + else: + self.ok_indicator.setPixmap(icon("fa.info-circle", color="red").pixmap(QSize(20, 20))) + self.ok_indicator.setToolTip(error) + + class LegendarySettings(QWidget, Ui_LegendarySettings): def __init__(self, parent=None): super(LegendarySettings, self).__init__(parent=parent) @@ -59,6 +160,67 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): ) self.locale_layout.addWidget(self.locale_edit) + 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.ubisoft_gb.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.ubisoft_gb.layout().addWidget(open_browser_button) + return + elif ubi_account_id == "error": + self.ubisoft_gb.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.ubisoft_gb.layout().addWidget(QLabel(self.tr("All your Ubisoft games have already been activated"))) + else: + self.ubisoft_gb.layout().addWidget(QLabel(self.tr("You don't own any Ubisoft games"))) + if shared.args.debug: + widget = UbiLinkWidget(Game(app_name="Test", app_title="Test Game"), ubi_account_id) + self.ubisoft_gb.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.ubisoft_gb.layout().addWidget(widget) + + @staticmethod def locale_edit_cb(text: str) -> Tuple[bool, str]: if text: diff --git a/rare/legendary b/rare/legendary index ab7d209d..d371c0b3 160000 --- a/rare/legendary +++ b/rare/legendary @@ -1 +1 @@ -Subproject commit ab7d209d5318f862d20081724383f523b6de4c7b +Subproject commit d371c0b3c48a422ff7e6c966af649a1502300c2d diff --git a/rare/ui/components/tabs/settings/legendary.py b/rare/ui/components/tabs/settings/legendary.py index 5a0d388e..30e57e98 100644 --- a/rare/ui/components/tabs/settings/legendary.py +++ b/rare/ui/components/tabs/settings/legendary.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.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. @@ -14,10 +14,39 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_LegendarySettings(object): def setupUi(self, LegendarySettings): LegendarySettings.setObjectName("LegendarySettings") - LegendarySettings.resize(552, 268) + LegendarySettings.resize(564, 374) LegendarySettings.setWindowTitle("LegendarySettings") - self.settings_layout = QtWidgets.QHBoxLayout(LegendarySettings) - self.settings_layout.setObjectName("settings_layout") + self.gridLayout = QtWidgets.QGridLayout(LegendarySettings) + self.gridLayout.setObjectName("gridLayout") + self.right_layout = QtWidgets.QVBoxLayout() + self.right_layout.setObjectName("right_layout") + self.locale_group = QtWidgets.QGroupBox(LegendarySettings) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.locale_group.sizePolicy().hasHeightForWidth()) + self.locale_group.setSizePolicy(sizePolicy) + self.locale_group.setObjectName("locale_group") + self.locale_layout = QtWidgets.QVBoxLayout(self.locale_group) + self.locale_layout.setObjectName("locale_layout") + self.right_layout.addWidget(self.locale_group) + self.cleanup_group = QtWidgets.QGroupBox(LegendarySettings) + self.cleanup_group.setObjectName("cleanup_group") + self.cleanup_layout = QtWidgets.QVBoxLayout(self.cleanup_group) + self.cleanup_layout.setObjectName("cleanup_layout") + self.clean_keep_manifests_button = QtWidgets.QPushButton(self.cleanup_group) + self.clean_keep_manifests_button.setObjectName("clean_keep_manifests_button") + self.cleanup_layout.addWidget(self.clean_keep_manifests_button) + self.clean_button = QtWidgets.QPushButton(self.cleanup_group) + self.clean_button.setObjectName("clean_button") + self.cleanup_layout.addWidget(self.clean_button) + self.right_layout.addWidget(self.cleanup_group) + self.gridLayout.addLayout(self.right_layout, 0, 1, 1, 1) + self.ubisoft_gb = QtWidgets.QGroupBox(LegendarySettings) + self.ubisoft_gb.setObjectName("ubisoft_gb") + self.verticalLayout = QtWidgets.QVBoxLayout(self.ubisoft_gb) + self.verticalLayout.setObjectName("verticalLayout") + self.gridLayout.addWidget(self.ubisoft_gb, 1, 0, 1, 2) self.left_layout = QtWidgets.QVBoxLayout() self.left_layout.setObjectName("left_layout") self.install_dir_group = QtWidgets.QGroupBox(LegendarySettings) @@ -96,41 +125,20 @@ class Ui_LegendarySettings(object): self.disable_https_check.setObjectName("disable_https_check") self.download_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.disable_https_check) self.left_layout.addWidget(self.download_group) + self.gridLayout.addLayout(self.left_layout, 0, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.left_layout.addItem(spacerItem) - self.settings_layout.addLayout(self.left_layout) - self.right_layout = QtWidgets.QVBoxLayout() - self.right_layout.setObjectName("right_layout") - self.locale_group = QtWidgets.QGroupBox(LegendarySettings) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.locale_group.sizePolicy().hasHeightForWidth()) - self.locale_group.setSizePolicy(sizePolicy) - self.locale_group.setObjectName("locale_group") - self.locale_layout = QtWidgets.QVBoxLayout(self.locale_group) - self.locale_layout.setObjectName("locale_layout") - self.right_layout.addWidget(self.locale_group) - self.cleanup_group = QtWidgets.QGroupBox(LegendarySettings) - self.cleanup_group.setObjectName("cleanup_group") - self.cleanup_layout = QtWidgets.QVBoxLayout(self.cleanup_group) - self.cleanup_layout.setObjectName("cleanup_layout") - self.clean_keep_manifests_button = QtWidgets.QPushButton(self.cleanup_group) - self.clean_keep_manifests_button.setObjectName("clean_keep_manifests_button") - self.cleanup_layout.addWidget(self.clean_keep_manifests_button) - self.clean_button = QtWidgets.QPushButton(self.cleanup_group) - self.clean_button.setObjectName("clean_button") - self.cleanup_layout.addWidget(self.clean_button) - self.right_layout.addWidget(self.cleanup_group) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.right_layout.addItem(spacerItem1) - self.settings_layout.addLayout(self.right_layout) + self.gridLayout.addItem(spacerItem, 2, 0, 1, 2) self.retranslateUi(LegendarySettings) QtCore.QMetaObject.connectSlotsByName(LegendarySettings) def retranslateUi(self, LegendarySettings): _translate = QtCore.QCoreApplication.translate + self.locale_group.setTitle(_translate("LegendarySettings", "Locale")) + self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup")) + self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests")) + self.clean_button.setText(_translate("LegendarySettings", "Remove everything")) + self.ubisoft_gb.setTitle(_translate("LegendarySettings", "Link Ubisoft Games")) self.install_dir_group.setTitle(_translate("LegendarySettings", "Default Installation Directory")) self.download_group.setTitle(_translate("LegendarySettings", "Download Settings")) self.max_workers_label.setText(_translate("LegendarySettings", "Max Workers")) @@ -141,10 +149,6 @@ class Ui_LegendarySettings(object): self.preferred_cdn_label.setText(_translate("LegendarySettings", "Preferred CDN")) self.preferred_cdn_line.setPlaceholderText(_translate("LegendarySettings", "Default")) self.disable_https_label.setText(_translate("LegendarySettings", "Disable HTTPS")) - self.locale_group.setTitle(_translate("LegendarySettings", "Locale")) - self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup")) - self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests")) - self.clean_button.setText(_translate("LegendarySettings", "Remove everything")) if __name__ == "__main__": diff --git a/rare/ui/components/tabs/settings/legendary.ui b/rare/ui/components/tabs/settings/legendary.ui index d379885e..f604b949 100644 --- a/rare/ui/components/tabs/settings/legendary.ui +++ b/rare/ui/components/tabs/settings/legendary.ui @@ -6,15 +6,64 @@ 0 0 - 552 - 268 + 564 + 374 LegendarySettings - - + + + + + + + + 0 + 0 + + + + Locale + + + + + + + + Cleanup + + + + + + Clean, but keep manifests + + + + + + + Remove everything + + + + + + + + + + + + Link Ubisoft Games + + + + + @@ -160,74 +209,20 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - 0 - 0 - - - - Locale - - - - - - - - Cleanup - - - - - - Clean, but keep manifests - - - - - - - Remove everything - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + Qt::Vertical + + + + 20 + 40 + + + From cc95d231b6d3639e4f538515246bdca3f60691b1 Mon Sep 17 00:00:00 2001 From: Dummerle <44114474+Dummerle@users.noreply.github.com> Date: Mon, 13 Dec 2021 20:53:21 +0100 Subject: [PATCH 2/4] Move Ubisoft logic to external class --- rare/components/tabs/settings/legendary.py | 167 +---------------- .../tabs/settings/ubisoft_activation.py | 173 ++++++++++++++++++ 2 files changed, 177 insertions(+), 163 deletions(-) create mode 100644 rare/components/tabs/settings/ubisoft_activation.py diff --git a/rare/components/tabs/settings/legendary.py b/rare/components/tabs/settings/legendary.py index dc3e4782..faadb13d 100644 --- a/rare/components/tabs/settings/legendary.py +++ b/rare/components/tabs/settings/legendary.py @@ -1,15 +1,11 @@ import re -import webbrowser from logging import getLogger from typing import Tuple -from PyQt5.QtCore import QThreadPool, QRunnable, QObject, pyqtSignal, QSize -from PyQt5.QtGui import QPixmap -from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox, QLabel, QPushButton, QHBoxLayout -from qtawesome import icon +from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox import rare.shared as shared -from legendary.models.game import Game +from rare.components.tabs.settings.ubisoft_activation import UbiActivationHelper from rare.ui.components.tabs.settings.legendary import Ui_LegendarySettings from rare.utils.extra_widgets import PathEdit, IndicatorLineEdit from rare.utils.utils import get_size @@ -17,102 +13,6 @@ from rare.utils.utils import get_size logger = getLogger("LegendarySettings") -class Signals(QObject): - worker_finished = pyqtSignal(set, set, str) - connected = pyqtSignal(str) - -class UbiGetInfoWorker(QRunnable): - def __init__(self): - super(UbiGetInfoWorker, self).__init__() - self.signals = Signals() - self.setAutoDelete(True) - - def run(self) -> None: - try: - external_auths = shared.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 = shared.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 = shared.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 UbiConnectWorker(QRunnable): - def __init__(self, ubi_account_id, partner_link_id): - super(UbiConnectWorker, self).__init__() - self.signals = Signals() - self.setAutoDelete(True) - self.ubi_account_id = ubi_account_id - self.partner_link_id = partner_link_id - - def run(self) -> None: - try: - shared.core.egs.store_claim_uplay_code(self.ubi_account_id, self.partner_link_id) - shared.core.egs.store_redeem_uplay_codes(self.ubi_account_id) - except Exception as e: - self.signals.connected.emit(str(e)) - return - else: - self.signals.connected.emit("") - - -class UbiLinkWidget(QWidget): - def __init__(self, game: Game, ubi_account_id): - super(UbiLinkWidget, self).__init__() - self.setLayout(QHBoxLayout()) - self.game = game - self.ubi_account_id = ubi_account_id - - self.ok_indicator = QLabel() - self.ok_indicator.setVisible(False) - self.ok_indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) - self.layout().addWidget(self.ok_indicator) - - self.title_label = QLabel(game.app_title) - self.layout().addWidget(self.title_label) - if not shared.args.debug: - self.link_button = QPushButton(self.tr("Redeem to Ubisoft")) - self.layout().addWidget(self.link_button) - self.link_button.clicked.connect(self.activate) - else: - btn = QPushButton(self.tr("Test: error")) - self.layout().addWidget(btn) - btn.clicked.connect(lambda: self.worker_finished("Any Error")) - - ok_button = QPushButton(self.tr("Test: Ok")) - self.layout().addWidget(ok_button) - ok_button.clicked.connect(lambda: self.worker_finished("")) - - def activate(self): - if shared.args.debug: - self.worker_finished("Connection Error") - return - worker = UbiConnectWorker(self.ubi_account_id, self.game.partner_link_id) - worker.signals.worker_finished.connect(self.worker_finished) - QThreadPool.globalInstance().start(worker) - - def worker_finished(self, error): - self.ok_indicator.setVisible(True) - if not error: - self.ok_indicator.setPixmap(icon("ei.ok-circle", color="green").pixmap(QSize(20, 20))) - else: - self.ok_indicator.setPixmap(icon("fa.info-circle", color="red").pixmap(QSize(20, 20))) - self.ok_indicator.setToolTip(error) - - class LegendarySettings(QWidget, Ui_LegendarySettings): def __init__(self, parent=None): super(LegendarySettings, self).__init__(parent=parent) @@ -160,66 +60,7 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): ) self.locale_layout.addWidget(self.locale_edit) - 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.ubisoft_gb.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.ubisoft_gb.layout().addWidget(open_browser_button) - return - elif ubi_account_id == "error": - self.ubisoft_gb.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.ubisoft_gb.layout().addWidget(QLabel(self.tr("All your Ubisoft games have already been activated"))) - else: - self.ubisoft_gb.layout().addWidget(QLabel(self.tr("You don't own any Ubisoft games"))) - if shared.args.debug: - widget = UbiLinkWidget(Game(app_name="Test", app_title="Test Game"), ubi_account_id) - self.ubisoft_gb.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.ubisoft_gb.layout().addWidget(widget) - + self.ubi_helper = UbiActivationHelper(self.ubisoft_gb) @staticmethod def locale_edit_cb(text: str) -> Tuple[bool, str]: @@ -273,7 +114,7 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): self.core.lgd.config.set("Legendary", "disable_https", str(bool(checked)).lower()) self.core.lgd.save_config() - def cleanup(self, keep_manifests): + def cleanup(self, keep_manifests: bool): before = self.core.lgd.get_dir_size() logger.debug('Removing app metadata...') app_names = set(g.app_name for g in self.core.get_assets(update_assets=False)) diff --git a/rare/components/tabs/settings/ubisoft_activation.py b/rare/components/tabs/settings/ubisoft_activation.py new file mode 100644 index 00000000..0c903b84 --- /dev/null +++ b/rare/components/tabs/settings/ubisoft_activation.py @@ -0,0 +1,173 @@ +import webbrowser +from logging import getLogger + +from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool, QSize +from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QPushButton +from qtawesome import icon + +from legendary.models.game import Game +from rare import shared + +logger = getLogger("Ubisoft") + + +class Signals(QObject): + worker_finished = pyqtSignal(set, set, str) + connected = pyqtSignal(str) + + +class UbiGetInfoWorker(QRunnable): + def __init__(self): + super(UbiGetInfoWorker, self).__init__() + self.signals = Signals() + self.setAutoDelete(True) + + def run(self) -> None: + try: + external_auths = shared.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 = shared.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 = shared.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 UbiConnectWorker(QRunnable): + def __init__(self, ubi_account_id, partner_link_id): + super(UbiConnectWorker, self).__init__() + self.signals = Signals() + self.setAutoDelete(True) + self.ubi_account_id = ubi_account_id + self.partner_link_id = partner_link_id + + def run(self) -> None: + try: + shared.core.egs.store_claim_uplay_code(self.ubi_account_id, self.partner_link_id) + shared.core.egs.store_redeem_uplay_codes(self.ubi_account_id) + except Exception as e: + self.signals.connected.emit(str(e)) + return + else: + self.signals.connected.emit("") + + +class UbiLinkWidget(QWidget): + def __init__(self, game: Game, ubi_account_id): + super(UbiLinkWidget, self).__init__() + self.setLayout(QHBoxLayout()) + self.game = game + self.ubi_account_id = ubi_account_id + + self.ok_indicator = QLabel() + self.ok_indicator.setVisible(False) + self.ok_indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) + self.layout().addWidget(self.ok_indicator) + + self.title_label = QLabel(game.app_title) + self.layout().addWidget(self.title_label) + if not shared.args.debug: + self.link_button = QPushButton(self.tr("Redeem to Ubisoft")) + self.layout().addWidget(self.link_button) + self.link_button.clicked.connect(self.activate) + else: + btn = QPushButton("Redeem to ubisoft: Test") + self.layout().addWidget(btn) + btn.clicked.connect(lambda: self.worker_finished("Any Error")) + + def activate(self): + if shared.args.debug: + self.worker_finished("Connection Error") + return + worker = UbiConnectWorker(self.ubi_account_id, self.game.partner_link_id) + worker.signals.worker_finished.connect(self.worker_finished) + QThreadPool.globalInstance().start(worker) + + def worker_finished(self, error): + self.ok_indicator.setVisible(True) + if not error: + self.ok_indicator.setPixmap(icon("ei.ok-circle", color="green").pixmap(QSize(20, 20))) + else: + self.ok_indicator.setPixmap(icon("fa.info-circle", color="red").pixmap(QSize(20, 20))) + self.ok_indicator.setToolTip(error) + + +class UbiActivationHelper(QObject): + def __init__(self, widget: QWidget): + super(UbiActivationHelper, self).__init__() + self.widget = widget + self.core = shared.core + + 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.widget.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.widget.layout().addWidget(open_browser_button) + return + elif ubi_account_id == "error": + self.widget.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.widget.layout().addWidget( + QLabel(self.tr("All your Ubisoft games have already been activated"))) + else: + self.widget.layout().addWidget(QLabel(self.tr("You don't own any Ubisoft games"))) + if shared.args.debug: + widget = UbiLinkWidget(Game(app_name="Test", app_title="This is a test game"), ubi_account_id) + self.widget.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.widget.layout().addWidget(widget) From b9253d0971a9c5fcccf897c3eb60596fb309cc47 Mon Sep 17 00:00:00 2001 From: Dummerle <44114474+Dummerle@users.noreply.github.com> Date: Mon, 13 Dec 2021 21:57:21 +0100 Subject: [PATCH 3/4] Small fixes --- .../tabs/settings/ubisoft_activation.py | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/rare/components/tabs/settings/ubisoft_activation.py b/rare/components/tabs/settings/ubisoft_activation.py index 0c903b84..5e81420a 100644 --- a/rare/components/tabs/settings/ubisoft_activation.py +++ b/rare/components/tabs/settings/ubisoft_activation.py @@ -1,3 +1,4 @@ +import time import webbrowser from logging import getLogger @@ -13,7 +14,7 @@ logger = getLogger("Ubisoft") class Signals(QObject): worker_finished = pyqtSignal(set, set, str) - connected = pyqtSignal(str) + linked = pyqtSignal(str) class UbiGetInfoWorker(QRunnable): @@ -55,14 +56,18 @@ class UbiConnectWorker(QRunnable): 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: shared.core.egs.store_claim_uplay_code(self.ubi_account_id, self.partner_link_id) shared.core.egs.store_redeem_uplay_codes(self.ubi_account_id) except Exception as e: - self.signals.connected.emit(str(e)) + self.signals.linked.emit(str(e)) return else: - self.signals.connected.emit("") + self.signals.linked.emit("") class UbiLinkWidget(QWidget): @@ -72,37 +77,40 @@ class UbiLinkWidget(QWidget): self.game = game self.ubi_account_id = ubi_account_id + self.title_label = QLabel(game.app_title) + self.layout().addWidget(self.title_label) + self.ok_indicator = QLabel() - self.ok_indicator.setVisible(False) + self.ok_indicator.setPixmap(icon("fa.info-circle", color="grey").pixmap(20, 20)) self.ok_indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) self.layout().addWidget(self.ok_indicator) - self.title_label = QLabel(game.app_title) - self.layout().addWidget(self.title_label) - if not shared.args.debug: - self.link_button = QPushButton(self.tr("Redeem to Ubisoft")) - self.layout().addWidget(self.link_button) - self.link_button.clicked.connect(self.activate) - else: - btn = QPushButton("Redeem to ubisoft: Test") - self.layout().addWidget(btn) - btn.clicked.connect(lambda: self.worker_finished("Any Error")) + self.link_button = QPushButton(self.tr("Redeem to Ubisoft") + ": Test" if shared.args.debug else "") + self.layout().addWidget(self.link_button) + self.link_button.clicked.connect(self.activate) 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 shared.args.debug: - self.worker_finished("Connection Error") - return - worker = UbiConnectWorker(self.ubi_account_id, self.game.partner_link_id) - worker.signals.worker_finished.connect(self.worker_finished) + 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): - self.ok_indicator.setVisible(True) 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 UbiActivationHelper(QObject): From df885bafa64b2c0b6626e118f61b8e2902539b02 Mon Sep 17 00:00:00 2001 From: Dummerle <44114474+Dummerle@users.noreply.github.com> Date: Mon, 13 Dec 2021 22:05:05 +0100 Subject: [PATCH 4/4] Fix run from source --- rare/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rare/__main__.py b/rare/__main__.py index 03a0feea..c4c7a118 100644 --- a/rare/__main__.py +++ b/rare/__main__.py @@ -78,6 +78,6 @@ if __name__ == '__main__': # insert raw legendary submodule sys.path.insert(0, os.path.join(pathlib.Path(__file__).parent.absolute(), "legendary")) # insert source directory - sys.path.insert(0, str(pathlib.Path(__file__).parents[2].absolute())) + sys.path.insert(0, str(pathlib.Path(__file__).parents[1].absolute())) main()