1 /*
2  * Cantata
3  *
4  * Copyright (c) 2011-2020 Craig Drummond <craig.p.drummond@gmail.com>
5  *
6  * ----
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; see the file COPYING.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #include "soundcloudservice.h"
25 #include "gui/apikeys.h"
26 #include "network/networkaccessmanager.h"
27 #include "mpd-interface/mpdconnection.h"
28 #include "support/utils.h"
29 #include "support/monoicon.h"
30 #include <QUrl>
31 #include <QUrlQuery>
32 #include <QJsonDocument>
33 
34 static const QLatin1String constName("soundcloud");
35 static const QLatin1String constUrl("https://api.soundcloud.com/tracks");
36 
SoundCloudService(QObject * p)37 SoundCloudService::SoundCloudService(QObject *p)
38     : OnlineSearchService(p)
39 {
40     icn=MonoIcon::icon(FontAwesome::soundcloud, Utils::monoIconColor());
41 }
42 
name() const43 QString SoundCloudService::name() const
44 {
45     return constName;
46 }
47 
title() const48 QString SoundCloudService::title() const
49 {
50     return QLatin1String("SoundCloud");
51 }
52 
descr() const53 QString SoundCloudService::descr() const
54 {
55     return tr("Search for tracks from soundcloud.com");
56 }
57 
search(const QString & key,const QString & value)58 void SoundCloudService::search(const QString &key, const QString &value)
59 {
60     Q_UNUSED(key);
61 
62     if (value==currentValue) {
63         return;
64     }
65 
66     clear();
67     cancel();
68 
69     currentValue=value;
70 
71     if (currentValue.isEmpty()) {
72         return;
73     }
74 
75     QUrl searchUrl(constUrl);
76     QUrlQuery query;
77     ApiKeys::self()->addKey(query, ApiKeys::SoundCloud);
78     query.addQueryItem("q", currentValue);
79     query.addQueryItem("limit", QString::number(200));
80     searchUrl.setQuery(query);
81 
82     QNetworkRequest req(searchUrl);
83     req.setRawHeader("Accept", "application/json");
84     job=NetworkAccessManager::self()->get(req);
85     connect(job, SIGNAL(finished()), this, SLOT(jobFinished()));
86     emit searching();
87     emit dataChanged(QModelIndex(), QModelIndex());
88 }
89 
jobFinished()90 void SoundCloudService::jobFinished()
91 {
92     NetworkJob *j=dynamic_cast<NetworkJob *>(sender());
93     if (!j || j!=job) {
94         return;
95     }
96 
97     j->deleteLater();
98     QList<Song> songs;
99 
100     if (j->ok()) {
101         QVariant result=QJsonDocument::fromJson(j->readAll()).toVariant();
102         if (result.isValid()) {
103             QVariantList list = result.toList();
104             for (const QVariant &item: list) {
105                 QVariantMap details=item.toMap();
106                 if (details["title"].toString().isEmpty()) {
107                     continue;
108                 }
109                 Song song;
110                 QUrl url = details["stream_url"].toUrl();
111                 QUrlQuery query;
112                 ApiKeys::self()->addKey(query, ApiKeys::SoundCloud);
113                 url.setQuery(query);
114                 // MPD does not seem to support https :-(
115                 if (QLatin1String("https")==url.scheme() && !MPDConnection::self()->urlHandlers().contains(QLatin1String("https"))) {
116                     url.setScheme(QLatin1String("http"));
117                 }
118                 song.file=url.toString();
119                 // We don't have a real artist name, but username is the most similar thing we have
120                 song.artist=details["user"].toMap()["username"].toString();
121                 song.title=details["title"].toString();
122                 song.genres[0]=details["genre"].toString();
123                 song.year=details["release_year"].toInt();
124                 song.time=details["duration"].toUInt()/1000;
125                 song.fillEmptyFields();
126                 songs.append(song);
127             }
128         }
129     } else {
130         ApiKeys::self()->isLimitReached(j->actualJob(), ApiKeys::SoundCloud);
131     }
132     results(songs);
133     job=nullptr;
134     emit dataChanged(QModelIndex(), QModelIndex());
135 }
136 
137 #include "moc_soundcloudservice.cpp"
138