✨ Backend and GUI changed to device login. Login dialog needs to be threaded / non blocking.

This commit is contained in:
Robert Honz
2024-11-12 19:15:33 +01:00
parent 4cef07b08f
commit 618b16257b
5 changed files with 104 additions and 59 deletions
+3 -3
View File
@@ -168,9 +168,9 @@ class Tidal(BaseConfig, metaclass=SingletonMeta):
fn_print("You either do not have a token or your token is invalid.")
fn_print("No worries, we will handle this...")
# Login method: Device linking
# self.session.login_oauth_simple(fn_print)
# Login method: PKCE authorization (enables HiRes streaming)
self.session.login_pkce(fn_print)
self.session.login_oauth_simple(fn_print)
# Login method: PKCE authorization (was necessary for HI_RES_LOSSLESS streaming earlier)
# self.session.login_pkce(fn_print)
is_login = self.login_finalize()
+7 -5
View File
@@ -1,6 +1,7 @@
import os.path
import shutil
import webbrowser
import datetime
from enum import Enum, StrEnum
from pathlib import Path
@@ -83,24 +84,25 @@ class DialogLogin(QtWidgets.QDialog):
ui: Ui_DialogLogin
url_redirect: str
return_code: int
def __init__(self, url_login: str, hint: str, parent=None):
def __init__(self, url_login: str, hint: str, expires_in: int, parent=None):
super().__init__(parent)
datetime_current: datetime.datetime = datetime.datetime.now()
datetime_expires: datetime.datetime = datetime_current + datetime.timedelta(0, expires_in)
# Create an instance of the GUI
self.ui = Ui_DialogLogin()
# Run the .setupUi() method to show the GUI
self.ui.setupUi(self)
# Set data.
self.ui.tb_url_login.setText(f'<a href="{url_login}">{url_login}</a>')
self.ui.tb_url_login.setText(f'<a href="https://{url_login}">https://{url_login}</a>')
self.ui.l_hint.setText(hint)
self.ui.l_expires_date_time.setText(datetime_expires.strftime("%Y-%m-%d %H:%M"))
# Show
self.return_code = self.exec()
self.url_redirect = self.ui.te_url_redirect.toPlainText()
class DialogPreferences(QtWidgets.QDialog):
"""Preferences dialog."""
+6 -4
View File
@@ -128,14 +128,16 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
result = self.tidal.login_token()
if not result:
hint: str = "Watiting for user input."
hint: str = "After you have finished the TIDAL login via web browser click the 'OK' button."
while not result:
url_login = self.tidal.session.pkce_login_url()
d_login: DialogLogin = DialogLogin(url_login=url_login, hint=hint, parent=self)
url_redirect: str = d_login.url_redirect
login, future = self.tidal.session.login_oauth()
d_login: DialogLogin = DialogLogin(url_login=login.verification_uri_complete, hint=hint, expires_in=login.expires_in, parent=self)
if d_login.return_code == 1:
try:
future.result()
token: dict[str, str | int] = self.tidal.session.pkce_get_auth_token(url_redirect)
self.tidal.session.process_auth_token(token)
self.tidal.login_finalize()
+54 -38
View File
@@ -1,42 +1,51 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'dialog_login.ui'
##
## Created by: Qt User Interface Compiler version 6.6.1
## Created by: Qt User Interface Compiler version 6.8.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import QCoreApplication, QMetaObject, QRect, Qt
from PySide6.QtGui import QFont
from PySide6.QtWidgets import QDialogButtonBox, QLabel, QSizePolicy, QTextBrowser, QTextEdit, QVBoxLayout, QWidget
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox,
QHBoxLayout, QLabel, QSizePolicy, QTextBrowser,
QVBoxLayout, QWidget)
class Ui_DialogLogin:
class Ui_DialogLogin(object):
def setupUi(self, DialogLogin):
if not DialogLogin.objectName():
DialogLogin.setObjectName("DialogLogin")
DialogLogin.setObjectName(u"DialogLogin")
DialogLogin.resize(451, 400)
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(DialogLogin.sizePolicy().hasHeightForWidth())
DialogLogin.setSizePolicy(sizePolicy)
self.bb_dialog = QDialogButtonBox(DialogLogin)
self.bb_dialog.setObjectName("bb_dialog")
self.bb_dialog.setObjectName(u"bb_dialog")
self.bb_dialog.setGeometry(QRect(20, 350, 411, 32))
sizePolicy.setHeightForWidth(self.bb_dialog.sizePolicy().hasHeightForWidth())
self.bb_dialog.setSizePolicy(sizePolicy)
self.bb_dialog.setStyleSheet("")
self.bb_dialog.setOrientation(Qt.Horizontal)
self.bb_dialog.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
self.bb_dialog.setLayoutDirection(Qt.LayoutDirection.LeftToRight)
self.bb_dialog.setStyleSheet(u"")
self.bb_dialog.setOrientation(Qt.Orientation.Horizontal)
self.bb_dialog.setStandardButtons(QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Ok)
self.verticalLayoutWidget = QWidget(DialogLogin)
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget")
self.verticalLayoutWidget.setGeometry(QRect(20, 20, 411, 325))
self.lv_main = QVBoxLayout(self.verticalLayoutWidget)
self.lv_main.setObjectName("lv_main")
self.lv_main.setObjectName(u"lv_main")
self.lv_main.setContentsMargins(0, 0, 0, 0)
self.l_header = QLabel(self.verticalLayoutWidget)
self.l_header.setObjectName("l_header")
self.l_header.setObjectName(u"l_header")
sizePolicy.setHeightForWidth(self.l_header.sizePolicy().hasHeightForWidth())
self.l_header.setSizePolicy(sizePolicy)
font = QFont()
@@ -47,7 +56,7 @@ class Ui_DialogLogin:
self.lv_main.addWidget(self.l_header)
self.l_description = QLabel(self.verticalLayoutWidget)
self.l_description.setObjectName("l_description")
self.l_description.setObjectName(u"l_description")
sizePolicy.setHeightForWidth(self.l_description.sizePolicy().hasHeightForWidth())
self.l_description.setSizePolicy(sizePolicy)
font1 = QFont()
@@ -58,47 +67,54 @@ class Ui_DialogLogin:
self.lv_main.addWidget(self.l_description)
self.tb_url_login = QTextBrowser(self.verticalLayoutWidget)
self.tb_url_login.setObjectName("tb_url_login")
self.tb_url_login.setObjectName(u"tb_url_login")
self.tb_url_login.setOpenExternalLinks(True)
self.lv_main.addWidget(self.tb_url_login)
self.te_url_redirect = QTextEdit(self.verticalLayoutWidget)
self.te_url_redirect.setObjectName("te_url_redirect")
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.l_expires_description = QLabel(self.verticalLayoutWidget)
self.l_expires_description.setObjectName(u"l_expires_description")
self.lv_main.addWidget(self.te_url_redirect)
self.horizontalLayout.addWidget(self.l_expires_description)
self.l_expires_date_time = QLabel(self.verticalLayoutWidget)
self.l_expires_date_time.setObjectName(u"l_expires_date_time")
font2 = QFont()
font2.setBold(True)
self.l_expires_date_time.setFont(font2)
self.l_expires_date_time.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
self.horizontalLayout.addWidget(self.l_expires_date_time)
self.lv_main.addLayout(self.horizontalLayout)
self.l_hint = QLabel(self.verticalLayoutWidget)
self.l_hint.setObjectName("l_hint")
self.l_hint.setObjectName(u"l_hint")
sizePolicy.setHeightForWidth(self.l_hint.sizePolicy().hasHeightForWidth())
self.l_hint.setSizePolicy(sizePolicy)
self.l_hint.setFont(font1)
self.l_hint.setWordWrap(True)
self.lv_main.addWidget(self.l_hint)
self.retranslateUi(DialogLogin)
self.bb_dialog.accepted.connect(DialogLogin.accept)
self.bb_dialog.rejected.connect(DialogLogin.reject)
QMetaObject.connectSlotsByName(DialogLogin)
# setupUi
def retranslateUi(self, DialogLogin):
DialogLogin.setWindowTitle(QCoreApplication.translate("DialogLogin", "Dialog", None))
self.l_header.setText(QCoreApplication.translate("DialogLogin", "TIDAL PKCE Login", None))
self.l_description.setText(
QCoreApplication.translate(
"DialogLogin",
'Click the link below and login with your TIDAL credentials. You will be redirected to an "Ooops" page'
' after a successful login. Copy the URL of this "Ooops" page and post it in the box below.',
None,
)
)
self.tb_url_login.setPlaceholderText(QCoreApplication.translate("DialogLogin", "Copy this login URL...", None))
self.te_url_redirect.setPlaceholderText(
QCoreApplication.translate("DialogLogin", "Copy and paste the redirect URL after login here...", None)
)
self.l_hint.setText(QCoreApplication.translate("DialogLogin", "Waiting...", None))
DialogLogin.setWindowTitle(QCoreApplication.translate("DialogLogin", u"Dialog", None))
self.l_header.setText(QCoreApplication.translate("DialogLogin", u"TIDAL Login (as Device)", None))
self.l_description.setText(QCoreApplication.translate("DialogLogin", u"Click the link below and login with your TIDAL credentials. TIDAL will ask you, if you like to add this app as a new device. You need to confirm this.", None))
self.tb_url_login.setPlaceholderText(QCoreApplication.translate("DialogLogin", u"Copy this login URL...", None))
self.l_expires_description.setText(QCoreApplication.translate("DialogLogin", u"This link expires at:", None))
self.l_expires_date_time.setText(QCoreApplication.translate("DialogLogin", u"COMPUTING", None))
self.l_hint.setText(QCoreApplication.translate("DialogLogin", u"Waiting...", None))
# retranslateUi
+32 -7
View File
@@ -34,14 +34,17 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
@@ -69,7 +72,7 @@
</font>
</property>
<property name="text">
<string>TIDAL PKCE Login</string>
<string>TIDAL Login (as Device)</string>
</property>
</widget>
</item>
@@ -87,7 +90,7 @@
</font>
</property>
<property name="text">
<string>Click the link below and login with your TIDAL credentials. You will be redirected to an &quot;Ooops&quot; page after a successful login. Copy the URL of this &quot;Ooops&quot; page and post it in the box below.</string>
<string>Click the link below and login with your TIDAL credentials. TIDAL will ask you, if you like to add this app as a new device. You need to confirm this.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -105,12 +108,31 @@
</widget>
</item>
<item>
<widget class="QTextEdit" name="te_url_redirect">
<property name="placeholderText">
<string>Copy and paste the redirect URL after login here...</string>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="l_expires_description">
<property name="text">
<string>This link expires at:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="l_expires_date_time">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>COMPUTING</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="l_hint">
<property name="sizePolicy">
@@ -127,6 +149,9 @@
<property name="text">
<string>Waiting...</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>