Use desktopauth instead of mobileauth for last.fm

It now uses an oauth like authentication process so the user isn't required to enter the last.fm password in Clementine but rather authenticate through the last.fm website.

Updates #5028
This commit is contained in:
Andreas 2016-02-03 15:33:46 +01:00
parent ac0aff5e81
commit 6c726e3e38
5 changed files with 97 additions and 57 deletions

View File

@ -74,6 +74,7 @@ const char* LastFMService::kSettingsGroup = "Last.fm";
const char* LastFMService::kAudioscrobblerClientId = "tng";
const char* LastFMService::kApiKey = "75d20fb472be99275392aefa2760ea09";
const char* LastFMService::kSecret = "d3072b60ae626be12be69448f5c46e70";
const char* LastFMService::kAuthLoginUrl = "http://www.last.fm/api/auth/?api_key=%1&token=%2";
LastFMService::LastFMService(Application* app, QObject* parent)
: Scrobbler(parent),
@ -82,6 +83,8 @@ LastFMService::LastFMService(Application* app, QObject* parent)
scrobbling_enabled_(false),
connection_problems_(false),
app_(app) {
lastfm::ws::setScheme(lastfm::ws::Https);
ReloadSettings();
// we emit the signal the first time to be sure the buttons are in the right
@ -127,13 +130,32 @@ bool LastFMService::IsSubscriber() const {
return settings.value("Subscriber", false).toBool();
}
void LastFMService::Authenticate(const QString& username,
const QString& password) {
void LastFMService::GetToken() {
QMap<QString, QString> params;
params["method"] = "auth.getMobileSession";
params["username"] = username;
params["authToken"] =
lastfm::md5((username + lastfm::md5(password.toUtf8())).toUtf8());
params["method"] = "auth.getToken";
QNetworkReply* reply = lastfm::ws::post(params);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(GetTokenReplyFinished(QNetworkReply*)), reply);
}
void LastFMService::GetTokenReplyFinished(QNetworkReply* reply) {
reply->deleteLater();
// Parse the reply
lastfm::XmlQuery lfm(lastfm::compat::EmptyXmlQuery());
if (lastfm::compat::ParseQuery(reply->readAll(), &lfm)) {
QString token = lfm["token"].text();
emit TokenReceived(true, token);
} else {
emit TokenReceived(false, lfm["error"].text().trimmed());
}
}
void LastFMService::Authenticate(const QString& token) {
QMap<QString, QString> params;
params["method"] = "auth.getSession";
params["token"] = token;
QNetworkReply* reply = lastfm::ws::post(params);
NewClosure(reply, SIGNAL(finished()), this,
@ -141,17 +163,6 @@ void LastFMService::Authenticate(const QString& username,
// If we need more detailed error reporting, handle error(NetworkError) signal
}
void LastFMService::SignOut() {
lastfm::ws::Username.clear();
lastfm::ws::SessionKey.clear();
QSettings settings;
settings.beginGroup(kSettingsGroup);
settings.setValue("Username", QString());
settings.setValue("Session", QString());
}
void LastFMService::AuthenticateReplyFinished(QNetworkReply* reply) {
reply->deleteLater();
@ -181,6 +192,17 @@ void LastFMService::AuthenticateReplyFinished(QNetworkReply* reply) {
emit AuthenticationComplete(true, QString());
}
void LastFMService::SignOut() {
lastfm::ws::Username.clear();
lastfm::ws::SessionKey.clear();
QSettings settings;
settings.beginGroup(kSettingsGroup);
settings.setValue("Username", QString());
settings.setValue("Session", QString());
}
void LastFMService::UpdateSubscriberStatus() {
QMap<QString, QString> params;
params["method"] = "user.getInfo";

View File

@ -54,6 +54,7 @@ class LastFMService : public Scrobbler {
static const char* kAudioscrobblerClientId;
static const char* kApiKey;
static const char* kSecret;
static const char* kAuthLoginUrl;
void ReloadSettings();
@ -68,7 +69,8 @@ class LastFMService : public Scrobbler {
bool PreferAlbumArtist() const { return prefer_albumartist_; }
bool HasConnectionProblems() const { return connection_problems_; }
void Authenticate(const QString& username, const QString& password);
void GetToken();
void Authenticate(const QString& token);
void SignOut();
void UpdateSubscriberStatus();
@ -81,6 +83,7 @@ class LastFMService : public Scrobbler {
void ToggleScrobbling();
signals:
void TokenReceived(bool success, const QString& token);
void AuthenticationComplete(bool success, const QString& error_message);
void ScrobblingEnabledChanged(bool value);
void ButtonVisibilityChanged(bool value);
@ -94,6 +97,7 @@ class LastFMService : public Scrobbler {
void SavedItemsChanged();
private slots:
void GetTokenReplyFinished(QNetworkReply* reply);
void AuthenticateReplyFinished(QNetworkReply* reply);
void UpdateSubscriberStatusFinished(QNetworkReply* reply);

View File

@ -24,6 +24,7 @@
#include <lastfm/ws.h>
#include <QDesktopServices>
#include <QMessageBox>
#include <QSettings>
@ -42,17 +43,16 @@ LastFMSettingsPage::LastFMSettingsPage(SettingsDialog* dialog)
// Icons
setWindowIcon(IconLoader::Load("lastfm", IconLoader::Provider));
connect(service_, SIGNAL(TokenReceived(bool,QString)),
SLOT(TokenReceived(bool,QString)));
connect(service_, SIGNAL(AuthenticationComplete(bool, QString)),
SLOT(AuthenticationComplete(bool, QString)));
connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(Logout()));
connect(ui_->login_state, SIGNAL(LoginClicked()), SLOT(Login()));
connect(ui_->login, SIGNAL(clicked()), SLOT(Login()));
ui_->login_state->AddCredentialField(ui_->username);
ui_->login_state->AddCredentialField(ui_->password);
ui_->login_state->AddCredentialGroup(ui_->groupBox);
ui_->login_state->AddCredentialGroup(ui_->login_container);
ui_->username->setMinimumWidth(QFontMetrics(QFont()).width("WWWWWWWWWWWW"));
resize(sizeHint());
}
@ -62,7 +62,22 @@ void LastFMSettingsPage::Login() {
waiting_for_auth_ = true;
ui_->login_state->SetLoggedIn(LoginStateWidget::LoginInProgress);
service_->Authenticate(ui_->username->text(), ui_->password->text());
service_->GetToken();
}
void LastFMSettingsPage::TokenReceived(bool success, const QString &token) {
if (!success) {
QMessageBox::warning(this, tr("Last.fm authentication failed"), token);
return;
}
QString url = QString(LastFMService::kAuthLoginUrl).arg(LastFMService::kApiKey, token);
QDesktopServices::openUrl(QUrl(url));
QMessageBox::information(this, tr("Last.fm authentication"),
tr("Click Ok once you authenticated Clementine in your last.fm account."));
service_->Authenticate(token);
}
void LastFMSettingsPage::AuthenticationComplete(bool success,
@ -72,8 +87,6 @@ void LastFMSettingsPage::AuthenticationComplete(bool success,
waiting_for_auth_ = false;
if (success) {
// Clear password just to be sure
ui_->password->clear();
// Save settings
Save();
} else {
@ -109,8 +122,6 @@ void LastFMSettingsPage::Save() {
}
void LastFMSettingsPage::Logout() {
ui_->username->clear();
ui_->password->clear();
RefreshControls(false);
service_->SignOut();

View File

@ -38,6 +38,7 @@ class LastFMSettingsPage : public SettingsPage {
private slots:
void Login();
void TokenReceived(bool success, const QString& token);
void AuthenticationComplete(bool success, const QString& error_message);
void Logout();

View File

@ -18,26 +18,19 @@
<widget class="LoginStateWidget" name="login_state" native="true"/>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Account details</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
<widget class="QWidget" name="login_container" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>28</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last.fm username</string>
</property>
</widget>
</item>
<item row="1" column="1">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="username"/>
</item>
<item>
<widget class="QPushButton" name="login">
<property name="text">
@ -45,19 +38,28 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last.fm password</string>
<string>Clicking the Login button will open a web browser. You should return to Clementine after you have logged in.</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
@ -112,6 +114,9 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
@ -131,9 +136,6 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>username</tabstop>
<tabstop>password</tabstop>
<tabstop>login</tabstop>
<tabstop>scrobble</tabstop>
<tabstop>love_ban_</tabstop>
<tabstop>scrobble_button</tabstop>