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] 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 + + +