mirror of
https://github.com/strawberrymusicplayer/strawberry
synced 2024-12-17 11:10:31 +01:00
Make spotify refresh login
This commit is contained in:
parent
d7661f0964
commit
9210fdee0d
@ -29,6 +29,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
@ -47,6 +48,7 @@
|
|||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
|
#include "core/timeconstants.h"
|
||||||
#include "internet/localredirectserver.h"
|
#include "internet/localredirectserver.h"
|
||||||
#include "albumcoverfetcher.h"
|
#include "albumcoverfetcher.h"
|
||||||
#include "jsoncoverprovider.h"
|
#include "jsoncoverprovider.h"
|
||||||
@ -61,15 +63,26 @@ const char *SpotifyCoverProvider::kClientSecretB64 = "N2ZlMDMxODk1NTBlNDE3ZGI1ZW
|
|||||||
const char *SpotifyCoverProvider::kApiUrl = "https://api.spotify.com/v1";
|
const char *SpotifyCoverProvider::kApiUrl = "https://api.spotify.com/v1";
|
||||||
const int SpotifyCoverProvider::kLimit = 10;
|
const int SpotifyCoverProvider::kLimit = 10;
|
||||||
|
|
||||||
SpotifyCoverProvider::SpotifyCoverProvider(Application *app, QObject *parent) : JsonCoverProvider("Spotify", true, true, 2.5, true, true, app, parent), network_(new NetworkAccessManager(this)), server_(nullptr) {
|
SpotifyCoverProvider::SpotifyCoverProvider(Application *app, QObject *parent) : JsonCoverProvider("Spotify", true, true, 2.5, true, true, app, parent), network_(new NetworkAccessManager(this)), server_(nullptr), expires_in_(0), login_time_(0) {
|
||||||
|
|
||||||
|
refresh_login_timer_.setSingleShot(true);
|
||||||
|
connect(&refresh_login_timer_, SIGNAL(timeout()), SLOT(RequestAccessToken()));
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
if (s.contains("access_token")) {
|
|
||||||
access_token_ = s.value("access_token").toString();
|
access_token_ = s.value("access_token").toString();
|
||||||
}
|
refresh_token_ = s.value("refresh_token").toString();
|
||||||
|
expires_in_ = s.value("expires_in").toLongLong();
|
||||||
|
login_time_ = s.value("login_time").toLongLong();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
|
if (!refresh_token_.isEmpty()) {
|
||||||
|
qint64 time = expires_in_ - (QDateTime::currentDateTime().toTime_t() - login_time_);
|
||||||
|
if (time < 6) time = 6;
|
||||||
|
refresh_login_timer_.setInterval(time * kMsecPerSec);
|
||||||
|
refresh_login_timer_.start();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyCoverProvider::Authenticate() {
|
void SpotifyCoverProvider::Authenticate() {
|
||||||
@ -129,12 +142,20 @@ void SpotifyCoverProvider::Authenticate() {
|
|||||||
void SpotifyCoverProvider::Deauthenticate() {
|
void SpotifyCoverProvider::Deauthenticate() {
|
||||||
|
|
||||||
access_token_.clear();
|
access_token_.clear();
|
||||||
|
refresh_token_.clear();
|
||||||
|
expires_in_ = 0;
|
||||||
|
login_time_ = 0;
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.remove("access_token");
|
s.remove("access_token");
|
||||||
|
s.remove("refresh_token");
|
||||||
|
s.remove("expires_in");
|
||||||
|
s.remove("login_time");
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
|
refresh_login_timer_.stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyCoverProvider::RedirectArrived() {
|
void SpotifyCoverProvider::RedirectArrived() {
|
||||||
@ -148,13 +169,16 @@ void SpotifyCoverProvider::RedirectArrived() {
|
|||||||
if (url_query.hasQueryItem("error")) {
|
if (url_query.hasQueryItem("error")) {
|
||||||
AuthError(QUrlQuery(url).queryItemValue("error"));
|
AuthError(QUrlQuery(url).queryItemValue("error"));
|
||||||
}
|
}
|
||||||
else if (url_query.hasQueryItem("code")) {
|
else if (url_query.hasQueryItem("code") && url_query.hasQueryItem("state")) {
|
||||||
|
qLog(Debug) << "Spotify: Authorization URL Received" << url;
|
||||||
|
QString code = url_query.queryItemValue("code");
|
||||||
|
QString state = url_query.queryItemValue("state");
|
||||||
QUrl redirect_url(kOAuthRedirectUrl);
|
QUrl redirect_url(kOAuthRedirectUrl);
|
||||||
redirect_url.setPort(server_->url().port());
|
redirect_url.setPort(server_->url().port());
|
||||||
RequestAccessToken(url, redirect_url);
|
RequestAccessToken(code, redirect_url);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AuthError(tr("Redirect missing token code!"));
|
AuthError(tr("Redirect missing token code or state!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -171,22 +195,25 @@ void SpotifyCoverProvider::RedirectArrived() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyCoverProvider::RequestAccessToken(const QUrl &url, const QUrl &redirect_url) {
|
void SpotifyCoverProvider::RequestAccessToken(const QString code, const QUrl redirect_url) {
|
||||||
|
|
||||||
qLog(Debug) << "Spotify: Authorization URL Received" << url;
|
refresh_login_timer_.stop();
|
||||||
|
|
||||||
QUrlQuery url_query(url);
|
ParamList params = ParamList() << Param("client_id", QByteArray::fromBase64(kClientIDB64))
|
||||||
|
<< Param("client_secret", QByteArray::fromBase64(kClientSecretB64));
|
||||||
|
|
||||||
if (url.hasQuery() && url_query.hasQueryItem("code") && url_query.hasQueryItem("state")) {
|
if (!code.isEmpty() && !redirect_url.isEmpty()) {
|
||||||
|
params << Param("grant_type", "authorization_code");
|
||||||
QString code = url_query.queryItemValue("code");
|
params << Param("code", code);
|
||||||
QString state = url_query.queryItemValue("state");
|
params << Param("redirect_uri", redirect_url.toString());
|
||||||
|
}
|
||||||
const ParamList params = ParamList() << Param("client_id", QByteArray::fromBase64(kClientIDB64))
|
else if (!refresh_token_.isEmpty() && is_enabled()) {
|
||||||
<< Param("client_secret", QByteArray::fromBase64(kClientSecretB64))
|
params << Param("grant_type", "refresh_token");
|
||||||
<< Param("grant_type", "authorization_code")
|
params << Param("refresh_token", refresh_token_);
|
||||||
<< Param("code", code)
|
}
|
||||||
<< Param("redirect_uri", redirect_url.toString());
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QUrlQuery new_url_query;
|
QUrlQuery new_url_query;
|
||||||
for (const Param ¶m : params) {
|
for (const Param ¶m : params) {
|
||||||
@ -206,13 +233,6 @@ void SpotifyCoverProvider::RequestAccessToken(const QUrl &url, const QUrl &redir
|
|||||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandleLoginSSLErrors(QList<QSslError>)));
|
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandleLoginSSLErrors(QList<QSslError>)));
|
||||||
connect(reply, &QNetworkReply::finished, [=] { AccessTokenRequestFinished(reply); });
|
connect(reply, &QNetworkReply::finished, [=] { AccessTokenRequestFinished(reply); });
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
AuthError(tr("Redirect from Spotify is missing query items code or state."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyCoverProvider::HandleLoginSSLErrors(QList<QSslError> ssl_errors) {
|
void SpotifyCoverProvider::HandleLoginSSLErrors(QList<QSslError> ssl_errors) {
|
||||||
@ -260,7 +280,6 @@ void SpotifyCoverProvider::AccessTokenRequestFinished(QNetworkReply *reply) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray data = reply->readAll();
|
QByteArray data = reply->readAll();
|
||||||
qLog(Debug) << data;
|
|
||||||
|
|
||||||
QJsonParseError json_error;
|
QJsonParseError json_error;
|
||||||
QJsonDocument json_doc = QJsonDocument::fromJson(data, &json_error);
|
QJsonDocument json_doc = QJsonDocument::fromJson(data, &json_error);
|
||||||
@ -286,19 +305,32 @@ void SpotifyCoverProvider::AccessTokenRequestFinished(QNetworkReply *reply) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_obj.contains("access_token")) {
|
if (!json_obj.contains("access_token") || !json_obj.contains("expires_in")) {
|
||||||
AuthError("Authentication reply from server is missing access token.", json_obj);
|
AuthError("Authentication reply from server is missing access token or expires in.", json_obj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
access_token_ = json_obj["access_token"].toString();
|
access_token_ = json_obj["access_token"].toString();
|
||||||
|
if (json_obj.contains("refresh_token")) {
|
||||||
|
refresh_token_ = json_obj["refresh_token"].toString();
|
||||||
|
}
|
||||||
|
expires_in_ = json_obj["expires_in"].toInt();
|
||||||
|
login_time_ = QDateTime::currentDateTime().toTime_t();
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
s.setValue("access_token", access_token_);
|
s.setValue("access_token", access_token_);
|
||||||
|
s.setValue("refresh_token", refresh_token_);
|
||||||
|
s.setValue("expires_in", expires_in_);
|
||||||
|
s.setValue("login_time", login_time_);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
qLog(Debug) << "Spotify: Authentication was successful, got access token" << access_token_;
|
if (expires_in_ > 0) {
|
||||||
|
refresh_login_timer_.setInterval(expires_in_ * kMsecPerSec);
|
||||||
|
refresh_login_timer_.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
qLog(Debug) << "Spotify: Authentication was successful, got access token" << access_token_ << "expires in" << expires_in_;
|
||||||
|
|
||||||
emit AuthenticationComplete(true);
|
emit AuthenticationComplete(true);
|
||||||
emit AuthenticationSuccess();
|
emit AuthenticationSuccess();
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <QSslError>
|
#include <QSslError>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include "jsoncoverprovider.h"
|
#include "jsoncoverprovider.h"
|
||||||
|
|
||||||
@ -55,11 +56,11 @@ class SpotifyCoverProvider : public JsonCoverProvider {
|
|||||||
private slots:
|
private slots:
|
||||||
void HandleLoginSSLErrors(QList<QSslError> ssl_errors);
|
void HandleLoginSSLErrors(QList<QSslError> ssl_errors);
|
||||||
void RedirectArrived();
|
void RedirectArrived();
|
||||||
|
void RequestAccessToken(const QString code = QString(), const QUrl redirect_url = QUrl());
|
||||||
void AccessTokenRequestFinished(QNetworkReply *reply);
|
void AccessTokenRequestFinished(QNetworkReply *reply);
|
||||||
void HandleSearchReply(QNetworkReply *reply, const int id, const QString &extract);
|
void HandleSearchReply(QNetworkReply *reply, const int id, const QString &extract);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RequestAccessToken(const QUrl &url, const QUrl &redirect_url);
|
|
||||||
QByteArray GetReplyData(QNetworkReply *reply);
|
QByteArray GetReplyData(QNetworkReply *reply);
|
||||||
void AuthError(const QString &error = QString(), const QVariant &debug = QVariant());
|
void AuthError(const QString &error = QString(), const QVariant &debug = QVariant());
|
||||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||||
@ -83,6 +84,10 @@ class SpotifyCoverProvider : public JsonCoverProvider {
|
|||||||
QString code_verifier_;
|
QString code_verifier_;
|
||||||
QString code_challenge_;
|
QString code_challenge_;
|
||||||
QString access_token_;
|
QString access_token_;
|
||||||
|
QString refresh_token_;
|
||||||
|
quint64 expires_in_;
|
||||||
|
quint64 login_time_;
|
||||||
|
QTimer refresh_login_timer_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user