1 /****************************************************************************************
2  * Copyright (c) 2007 Shane King <kde@dontletsstart.com>                                *
3  * Copyright (c) 2013 Vedant Agarwala <vedant.kota@gmail.com>                           *
4  *                                                                                      *
5  * This program is free software; you can redistribute it and/or modify it under        *
6  * the terms of the GNU General Public License as published by the Free Software        *
7  * Foundation; either version 2 of the License, or (at your option) any later           *
8  * version.                                                                             *
9  *                                                                                      *
10  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
12  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
13  *                                                                                      *
14  * You should have received a copy of the GNU General Public License along with         *
15  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
16  ****************************************************************************************/
17 
18 #define DEBUG_PREFIX "LastFmServiceSettings"
19 
20 #include "LastFmServiceSettings.h"
21 
22 #include "core/collections/QueryMaker.h"
23 #include "core/meta/Meta.h"
24 #include "core/support/Amarok.h"
25 #include "core/support/Debug.h"
26 #include "core-impl/collections/support/CollectionManager.h"
27 #include "network/NetworkAccessManagerProxy.h"
28 #include "ui_LastFmConfigWidget.h"
29 
30 #include <KMessageBox>
31 #include <KPluginFactory>
32 
33 #include <QCryptographicHash>
34 #include <QRegExpValidator>
35 
36 #include <XmlQuery.h>
37 
38 K_PLUGIN_FACTORY_WITH_JSON( LastFmServiceSettingsFactory, "amarok_service_lastfm_config.json", registerPlugin<LastFmServiceSettings>(); )
39 
LastFmServiceSettings(QWidget * parent,const QVariantList & args)40 LastFmServiceSettings::LastFmServiceSettings( QWidget *parent, const QVariantList &args )
41     : KCModule( parent, args )
42     , m_config( LastFmServiceConfig::instance() )
43 {
44     m_configDialog = new Ui::LastFmConfigWidget;
45     m_configDialog->setupUi( this );
46 
47     connect( m_config.data(), &LastFmServiceConfig::updated, this, &LastFmServiceSettings::onConfigUpdated );
48 
49     connect( m_configDialog->kcfg_ScrobblerUsername, &QLineEdit::textChanged, this, &LastFmServiceSettings::settingsChanged );
50     connect( m_configDialog->kcfg_ScrobblerPassword, &QLineEdit::textChanged, this, &LastFmServiceSettings::settingsChanged );
51     connect( m_configDialog->kcfg_SubmitPlayedSongs, &QCheckBox::stateChanged, this, &LastFmServiceSettings::settingsChanged );
52     connect( m_configDialog->kcfg_RetrieveSimilarArtists, &QCheckBox::stateChanged, this, &LastFmServiceSettings::settingsChanged );
53     connect( m_configDialog->kcfg_ScrobbleComposer, &QCheckBox::stateChanged, this, &LastFmServiceSettings::settingsChanged );
54     connect( m_configDialog->kcfg_UseFancyRatingTags, &QCheckBox::stateChanged, this, &LastFmServiceSettings::settingsChanged );
55     connect( m_configDialog->kcfg_AnnounceCorrections, &QCheckBox::stateChanged, this, &LastFmServiceSettings::settingsChanged );
56     connect( m_configDialog->kcfg_FilterByLabel, &QCheckBox::stateChanged, this, &LastFmServiceSettings::settingsChanged );
57     connect( m_configDialog->kcfg_FilteredLabel, QOverload<const QString&>::of( &QComboBox::currentIndexChanged ), this, &LastFmServiceSettings::settingsChanged );
58     connect( m_configDialog->testLogin, &QPushButton::clicked, this, &LastFmServiceSettings::testLogin );
59 
60     using namespace Collections;
61 
62     QueryMaker *query = CollectionManager::instance()->queryMaker();
63     query->setQueryType( QueryMaker::Label );
64     connect( query, &QueryMaker::newLabelsReady, this, &LastFmServiceSettings::addNewLabels );
65     query->setAutoDelete( true );
66     query->run();
67 }
68 
~LastFmServiceSettings()69 LastFmServiceSettings::~LastFmServiceSettings()
70 {
71     delete m_configDialog;
72 }
73 
74 void
save()75 LastFmServiceSettings::save()
76 {
77     QString dialogUser = m_configDialog->kcfg_ScrobblerUsername->text();
78     QString dialogPass = m_configDialog->kcfg_ScrobblerPassword->text();
79 
80     // clear the session key if credentials changed
81     if( m_config->username() != dialogUser || m_config->password() != dialogPass )
82         m_config->setSessionKey( QString() );
83 
84     m_config->setUsername( dialogUser );
85     m_config->setPassword( dialogPass );
86     m_config->setScrobble( m_configDialog->kcfg_SubmitPlayedSongs->isChecked() );
87     m_config->setFetchSimilar( m_configDialog->kcfg_RetrieveSimilarArtists->isChecked() );
88     m_config->setScrobbleComposer( m_configDialog->kcfg_ScrobbleComposer->isChecked() );
89     m_config->setUseFancyRatingTags( m_configDialog->kcfg_UseFancyRatingTags->isChecked() );
90     m_config->setAnnounceCorrections( m_configDialog->kcfg_AnnounceCorrections->isChecked() );
91     m_config->setFilterByLabel( m_configDialog->kcfg_FilterByLabel->isChecked() );
92     m_config->setFilteredLabel( m_configDialog->kcfg_FilteredLabel->currentText() );
93     m_config->save();
94 
95     KCModule::save();
96 }
97 
98 void
testLogin()99 LastFmServiceSettings::testLogin()
100 {
101     m_configDialog->testLogin->setEnabled( false );
102     m_configDialog->testLogin->setText( i18n( "Testing..." ) );
103     // set the global static Lastfm::Ws stuff
104     lastfm::ws::ApiKey = Amarok::lastfmApiKey();
105     lastfm::ws::SharedSecret = Amarok::lastfmApiSharedSecret();
106     lastfm::ws::setScheme(lastfm::ws::Https);
107     if( lastfm::nam() != The::networkAccessManager() )
108         lastfm::setNetworkAccessManager( The::networkAccessManager() );
109 
110     debug() << "username:" << QString( QUrl::toPercentEncoding( m_configDialog->kcfg_ScrobblerUsername->text().toUtf8() ) );
111 
112     QMap<QString, QString> query;
113 
114     query[ "method" ] = "auth.getMobileSession";
115     query[ "password" ] = m_configDialog->kcfg_ScrobblerPassword->text().toUtf8();
116     query[ "username" ] = m_configDialog->kcfg_ScrobblerUsername->text().toUtf8();
117     m_authQuery = lastfm::ws::post( query );
118 
119     connect( m_authQuery, &QNetworkReply::finished, this, &LastFmServiceSettings::onAuthenticated );
120     connect( m_authQuery, QOverload<QNetworkReply::NetworkError>::of( &QNetworkReply::error ),
121              this, &LastFmServiceSettings::onError );
122 }
123 
124 void
onAuthenticated()125 LastFmServiceSettings::onAuthenticated()
126 {
127     lastfm::XmlQuery lfm;
128     lfm.parse( m_authQuery->readAll() );
129 
130     switch( m_authQuery->error() )
131     {
132         case QNetworkReply::NoError:
133              debug() << "NoError";
134              if( lfm.children( "error" ).size() > 0 )
135              {
136                  debug() << "ERROR from last.fm:" << lfm.text();
137                  m_configDialog->testLogin->setText( i18nc( "The operation was rejected by the server", "Failed" ) );
138                  m_configDialog->testLogin->setEnabled( true );
139 
140              } else
141              {
142                  m_configDialog->testLogin->setText( i18nc( "The operation completed as expected", "Success" ) );
143                  m_configDialog->testLogin->setEnabled( false );
144                  m_configDialog->kcfg_SubmitPlayedSongs->setEnabled( true );
145              }
146              break;
147 
148         case QNetworkReply::AuthenticationRequiredError:
149             debug() << "AuthenticationFailed";
150             KMessageBox::error( this, i18n( "Either the username or the password is incorrect, please correct and try again" ), i18n( "Failed" ) );
151             m_configDialog->testLogin->setText( i18n( "Test Login" ) );
152             m_configDialog->testLogin->setEnabled( true );
153             break;
154 
155         default:
156             debug() << "Unhandled QNetworkReply state, probably not important";
157     }
158     m_authQuery->deleteLater();
159 }
160 
161 void
onError(QNetworkReply::NetworkError code)162 LastFmServiceSettings::onError( QNetworkReply::NetworkError code )
163 {
164     if( code == QNetworkReply::NoError )
165         return;
166 
167     if( code == QNetworkReply::AuthenticationRequiredError )
168     {
169         onAuthenticated();
170         return;
171     }
172 
173     KMessageBox::error( this, i18n( "Unable to connect to Last.fm service." ), i18n( "Failed" ) );
174     m_configDialog->testLogin->setText( i18n( "Test Login" ) );
175     m_configDialog->testLogin->setEnabled( true );
176 
177     debug() << "Error occurred during network request: " << m_authQuery->errorString();
178     m_authQuery->deleteLater();
179 }
180 
181 void
onConfigUpdated()182 LastFmServiceSettings::onConfigUpdated()
183 {
184     load();
185 }
186 
187 void
load()188 LastFmServiceSettings::load()
189 {
190     m_configDialog->kcfg_ScrobblerUsername->setText( m_config->username() );
191     m_configDialog->kcfg_ScrobblerPassword->setText( m_config->password() );
192     m_configDialog->kcfg_SubmitPlayedSongs->setChecked( m_config->scrobble() );
193     m_configDialog->kcfg_RetrieveSimilarArtists->setChecked( m_config->fetchSimilar() );
194     m_configDialog->kcfg_ScrobbleComposer->setChecked( m_config->scrobbleComposer() );
195     m_configDialog->kcfg_UseFancyRatingTags->setChecked( m_config->useFancyRatingTags() );
196     m_configDialog->kcfg_AnnounceCorrections->setChecked( m_config->announceCorrections() );
197     m_configDialog->kcfg_FilterByLabel->setChecked( m_config->filterByLabel() );
198     m_configDialog->kcfg_FilteredLabel->setCurrentIndex( filteredLabelComboIndex( m_config->filteredLabel() ) );
199 
200     if( !m_config->username().isEmpty() && !m_config->password().isEmpty() )
201         m_configDialog->kcfg_SubmitPlayedSongs->setEnabled( true );
202 
203     KCModule::load();
204 }
205 
206 void
defaults()207 LastFmServiceSettings::defaults()
208 {
209     m_configDialog->kcfg_SubmitPlayedSongs->setChecked( m_config->defaultScrobble() );
210     m_configDialog->kcfg_RetrieveSimilarArtists->setChecked( m_config->defaultFetchSimilar() );
211     m_configDialog->kcfg_ScrobbleComposer->setChecked( m_config->defaultScrobbleComposer() );
212     m_configDialog->kcfg_UseFancyRatingTags->setChecked( m_config->defaultUseFancyRatingTags() );
213     m_configDialog->kcfg_AnnounceCorrections->setChecked( m_config->defaultAnnounceCorrections() );
214     m_configDialog->kcfg_FilterByLabel->setChecked( m_config->defaultFilterByLabel() );
215     m_configDialog->kcfg_FilteredLabel->setCurrentIndex( filteredLabelComboIndex( m_config->defaultFilteredLabel() ) );
216 }
217 
218 void
settingsChanged()219 LastFmServiceSettings::settingsChanged()
220 {
221     //TODO: Make pretty validation for username and password
222     //with error reporting
223 
224     m_configDialog->testLogin->setText( i18n( "&Test Login" ) );
225     m_configDialog->testLogin->setEnabled( true );
226 
227     emit changed( true );
228 }
229 
230 void
addNewLabels(const Meta::LabelList & labels)231 LastFmServiceSettings::addNewLabels( const Meta::LabelList &labels )
232 {
233     foreach( const Meta::LabelPtr &label , labels )
234         m_configDialog->kcfg_FilteredLabel->addItem( label->name() );
235 }
236 
237 int
filteredLabelComboIndex(const QString & label)238 LastFmServiceSettings::filteredLabelComboIndex( const QString &label )
239 {
240     int index = m_configDialog->kcfg_FilteredLabel->findText( label );
241     if( index == -1)
242     {
243         m_configDialog->kcfg_FilteredLabel->addItem( label );
244         return m_configDialog->kcfg_FilteredLabel->findText( label );
245     }
246     else
247         return index;
248 }
249 
250 #include "LastFmServiceSettings.moc"
251