Remove echonest and update songkick concert fetcher.

#5416
This commit is contained in:
John Maguire 2016-06-27 14:45:40 +01:00
parent f13288876f
commit a8a0f2e4fd
12 changed files with 36 additions and 491 deletions

View File

@ -364,9 +364,6 @@ else (USE_SYSTEM_QXT)
endif (NOT APPLE)
endif (USE_SYSTEM_QXT)
find_path(ECHONEST_INCLUDE_DIRS echonest/echonest_export.h)
find_library(ECHONEST_LIBRARIES echonest)
# Use system gmock if it's available
# We need to look for both gmock and gtest
find_path(GMOCK_INCLUDE_DIRS gmock/gmock.h)

View File

@ -35,7 +35,6 @@ include_directories(${LIBPROJECTM_INCLUDE_DIRS})
include_directories(${QTSINGLEAPPLICATION_INCLUDE_DIRS})
include_directories(${QTIOCOMPRESSOR_INCLUDE_DIRS})
include_directories(${QXT_INCLUDE_DIRS})
include_directories(${ECHONEST_INCLUDE_DIRS})
include_directories(${SHA2_INCLUDE_DIRS})
include_directories(${CHROMAPRINT_INCLUDE_DIRS})
include_directories(${MYGPOQT_INCLUDE_DIRS})
@ -301,7 +300,6 @@ set(SOURCES
songinfo/artistinfoview.cpp
songinfo/collapsibleinfoheader.cpp
songinfo/collapsibleinfopane.cpp
songinfo/echonestbiographies.cpp
songinfo/songinfobase.cpp
songinfo/songinfofetcher.cpp
songinfo/songinfoprovider.cpp
@ -593,7 +591,6 @@ set(HEADERS
songinfo/artistinfoview.h
songinfo/collapsibleinfoheader.h
songinfo/collapsibleinfopane.h
songinfo/echonestbiographies.h
songinfo/songinfobase.h
songinfo/songinfofetcher.h
songinfo/songinfoprovider.h
@ -830,16 +827,12 @@ optional_source(HAVE_LIBLASTFM
internet/lastfm/lastfmcompat.cpp
internet/lastfm/lastfmservice.cpp
internet/lastfm/lastfmsettingspage.cpp
songinfo/echonestsimilarartists.cpp
songinfo/echonesttags.cpp
songinfo/lastfmtrackinfoprovider.cpp
songinfo/tagwidget.cpp
HEADERS
covers/lastfmcoverprovider.h
internet/lastfm/lastfmservice.h
internet/lastfm/lastfmsettingspage.h
songinfo/echonestsimilarartists.h
songinfo/echonesttags.h
songinfo/lastfmtrackinfoprovider.h
songinfo/tagwidget.h
UI
@ -1254,7 +1247,6 @@ target_link_libraries(clementine_lib
${TAGLIB_LIBRARIES}
${MYGPOQT_LIBRARIES}
${CHROMAPRINT_LIBRARIES}
${ECHONEST_LIBRARIES}
${GOBJECT_LIBRARIES}
${GLIB_LIBRARIES}
${GIO_LIBRARIES}

View File

@ -73,8 +73,6 @@
#include <glib.h>
#include <gst/gst.h>
#include <echonest/Config.h>
#ifdef Q_OS_DARWIN
#include <sys/resource.h>
#include <sys/sysctl.h>
@ -398,8 +396,8 @@ int main(int argc, char* argv[]) {
// Add root CA cert for SoundCloud, whose certificate is missing on OS X.
QSslSocket::addDefaultCaCertificates(
QSslCertificate::fromPath(":/soundcloud-ca.pem", QSsl::Pem));
QSslSocket::addDefaultCaCertificates(
QSslCertificate::fromPath(":/Equifax_Secure_Certificate_Authority.pem", QSsl::Pem));
QSslSocket::addDefaultCaCertificates(QSslCertificate::fromPath(
":/Equifax_Secure_Certificate_Authority.pem", QSsl::Pem));
// Has the user forced a different language?
QString override_language = options.language();
@ -437,10 +435,6 @@ int main(int argc, char* argv[]) {
Application app;
app.set_language_name(language);
Echonest::Config::instance()->setAPIKey("DFLFLJBUF4EGTXHIG");
Echonest::Config::instance()->setNetworkAccessManager(
new NetworkAccessManager);
// Network proxy
QNetworkProxyFactory::setApplicationProxyFactory(
NetworkProxyFactory::Instance());

View File

@ -17,25 +17,14 @@
#include "artistinfoview.h"
#include "songinfo/echonestbiographies.h"
#include "songinfo/songinfofetcher.h"
#include "songinfo/songkickconcerts.h"
#include "songinfo/spotifyimages.h"
#include "widgets/prettyimageview.h"
#ifdef HAVE_LIBLASTFM
#include "echonestsimilarartists.h"
#include "echonesttags.h"
#endif
ArtistInfoView::ArtistInfoView(QWidget* parent) : SongInfoBase(parent) {
fetcher_->AddProvider(new EchoNestBiographies);
fetcher_->AddProvider(new SongkickConcerts);
fetcher_->AddProvider(new SpotifyImages);
#ifdef HAVE_LIBLASTFM
fetcher_->AddProvider(new EchoNestSimilarArtists);
fetcher_->AddProvider(new EchoNestTags);
#endif
}
ArtistInfoView::~ArtistInfoView() {}

View File

@ -1,123 +0,0 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonestbiographies.h"
#include <memory>
#include <echonest/Artist.h>
#include "songinfotextview.h"
#include "core/logging.h"
#include "ui/iconloader.h"
struct EchoNestBiographies::Request {
Request(int id) : id_(id), artist_(new Echonest::Artist) {}
int id_;
std::unique_ptr<Echonest::Artist> artist_;
};
EchoNestBiographies::EchoNestBiographies() {
site_relevance_["wikipedia"] = 100;
site_relevance_["lastfm"] = 60;
site_relevance_["amazon"] = 30;
site_icons_["amazon"] = IconLoader::Load("amazon", IconLoader::Provider);
site_icons_["aol"] = IconLoader::Load("aol", IconLoader::Provider);
site_icons_["cdbaby"] = IconLoader::Load("cdbaby", IconLoader::Provider);
site_icons_["lastfm"] = IconLoader::Load("as", IconLoader::Lastfm);
site_icons_["mog"] = IconLoader::Load("mog", IconLoader::Provider);
site_icons_["mtvmusic"] = IconLoader::Load("mtvmusic", IconLoader::Provider);
site_icons_["myspace"] = IconLoader::Load("myspace", IconLoader::Provider);
site_icons_["wikipedia"] = IconLoader::Load("wikipedia", IconLoader::Provider);
}
void EchoNestBiographies::FetchInfo(int id, const Song& metadata) {
std::shared_ptr<Request> request(new Request(id));
request->artist_->setName(metadata.artist());
QNetworkReply* reply = request->artist_->fetchBiographies();
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = request;
}
void EchoNestBiographies::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply)) return;
reply->deleteLater();
RequestPtr request = requests_.take(reply);
try {
request->artist_->parseProfile(reply);
}
catch (Echonest::ParseError e) {
qLog(Warning) << "Error parsing echonest reply:" << e.errorType()
<< e.what();
}
QSet<QString> already_seen;
for (const Echonest::Biography& bio : request->artist_->biographies()) {
QString canonical_site = bio.site().toLower();
canonical_site.replace(QRegExp("[^a-z]"), "");
if (already_seen.contains(canonical_site)) continue;
already_seen.insert(canonical_site);
CollapsibleInfoPane::Data data;
data.id_ = "echonest/bio/" + bio.site();
data.title_ = tr("Biography from %1").arg(bio.site());
data.type_ = CollapsibleInfoPane::Data::Type_Biography;
if (site_relevance_.contains(canonical_site))
data.relevance_ = site_relevance_[canonical_site];
if (site_icons_.contains(canonical_site))
data.icon_ = site_icons_[canonical_site];
SongInfoTextView* editor = new SongInfoTextView;
QString text;
// Add a link to the bio webpage at the top if we have one
if (!bio.url().isEmpty()) {
QString bio_url = bio.url().toEncoded();
if (bio.site() == "facebook") {
bio_url.replace("graph.facebook.com", "www.facebook.com");
}
text += "<p><a href=\"" + bio_url + "\">" +
tr("Open in your browser") + "</a></p>";
}
text += bio.text();
if (bio.site() == "last.fm") {
// Echonest lost formatting and it seems there is currently no plans on
// Echonest side for changing this.
// But with last.fm, we can guess newlines: " " corresponds to a newline
// (this seems to be because on last.fm' website, extra blank is inserted
// before <br /> tag, and this blank is kept).
// This is tricky, but this make the display nicer for last.fm
// biographies.
text.replace(" ", "<p>");
}
editor->SetHtml(text);
data.contents_ = editor;
emit InfoReady(request->id_, data);
}
emit Finished(request->id_);
}

View File

@ -1,48 +0,0 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTBIOGRAPHIES_H
#define ECHONESTBIOGRAPHIES_H
#include <memory>
#include "songinfoprovider.h"
class QNetworkReply;
class EchoNestBiographies : public SongInfoProvider {
Q_OBJECT
public:
EchoNestBiographies();
void FetchInfo(int id, const Song& metadata);
private slots:
void RequestFinished();
private:
QMap<QString, int> site_relevance_;
QMap<QString, QIcon> site_icons_;
struct Request;
typedef std::shared_ptr<Request> RequestPtr;
QMap<QNetworkReply*, RequestPtr> requests_;
};
#endif // ECHONESTBIOGRAPHIES_H

View File

@ -1,76 +0,0 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonestsimilarartists.h"
#include "tagwidget.h"
#include "core/logging.h"
#include "ui/iconloader.h"
#include <echonest/Artist.h>
Q_DECLARE_METATYPE(QVector<QString>);
void EchoNestSimilarArtists::FetchInfo(int id, const Song& metadata) {
using Echonest::Artist;
Artist::SearchParams params;
params << Artist::SearchParamEntry(Artist::Name, metadata.artist());
params << Artist::SearchParamEntry(Artist::MinHotttnesss, 0.5);
QNetworkReply* reply = Echonest::Artist::fetchSimilar(params);
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = id;
}
void EchoNestSimilarArtists::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply)) return;
reply->deleteLater();
int id = requests_.take(reply);
Echonest::Artists artists;
try {
artists = Echonest::Artist::parseSimilar(reply);
}
catch (Echonest::ParseError e) {
qLog(Warning) << "Error parsing echonest reply:" << e.errorType()
<< e.what();
}
if (!artists.isEmpty()) {
CollapsibleInfoPane::Data data;
data.id_ = "echonest/similarartists";
data.title_ = tr("Similar artists");
data.type_ = CollapsibleInfoPane::Data::Type_Similar;
data.icon_ = IconLoader::Load("echonest", IconLoader::Provider);
TagWidget* widget = new TagWidget(TagWidget::Type_Artists);
data.contents_ = widget;
widget->SetIcon(IconLoader::Load("x-clementine-artist", IconLoader::Base));
for (const Echonest::Artist& artist : artists) {
widget->AddTag(artist.name());
if (widget->count() >= 10) break;
}
emit InfoReady(id, data);
}
emit Finished(id);
}

View File

@ -1,38 +0,0 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTSIMILARARTISTS_H
#define ECHONESTSIMILARARTISTS_H
#include "songinfoprovider.h"
class QNetworkReply;
class EchoNestSimilarArtists : public SongInfoProvider {
Q_OBJECT
public:
void FetchInfo(int id, const Song& metadata);
private slots:
void RequestFinished();
private:
QMap<QNetworkReply*, int> requests_;
};
#endif // ECHONESTSIMILARARTISTS_H

View File

@ -1,80 +0,0 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "echonesttags.h"
#include <memory>
#include <echonest/Artist.h>
#include "tagwidget.h"
#include "core/logging.h"
#include "ui/iconloader.h"
struct EchoNestTags::Request {
Request(int id) : id_(id), artist_(new Echonest::Artist) {}
int id_;
std::unique_ptr<Echonest::Artist> artist_;
};
void EchoNestTags::FetchInfo(int id, const Song& metadata) {
std::shared_ptr<Request> request(new Request(id));
request->artist_->setName(metadata.artist());
QNetworkReply* reply = request->artist_->fetchTerms();
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
requests_[reply] = request;
}
void EchoNestTags::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if (!reply || !requests_.contains(reply)) return;
reply->deleteLater();
RequestPtr request = requests_.take(reply);
try {
request->artist_->parseProfile(reply);
}
catch (Echonest::ParseError e) {
qLog(Warning) << "Error parsing echonest reply:" << e.errorType()
<< e.what();
}
if (!request->artist_->terms().isEmpty()) {
CollapsibleInfoPane::Data data;
data.id_ = "echonest/artisttags";
data.title_ = tr("Artist tags");
data.type_ = CollapsibleInfoPane::Data::Type_Tags;
data.icon_ = IconLoader::Load("icon_tag", IconLoader::Lastfm);
TagWidget* widget = new TagWidget(TagWidget::Type_Tags);
data.contents_ = widget;
widget->SetIcon(data.icon_);
for (const Echonest::Term& term : request->artist_->terms()) {
widget->AddTag(term.name());
if (widget->count() >= 10) break;
}
emit InfoReady(request->id_, data);
}
emit Finished(request->id_);
}

View File

@ -1,43 +0,0 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ECHONESTTAGS_H
#define ECHONESTTAGS_H
#include <memory>
#include "songinfoprovider.h"
class QNetworkReply;
class EchoNestTags : public SongInfoProvider {
Q_OBJECT
public:
void FetchInfo(int id, const Song& metadata);
private slots:
void RequestFinished();
private:
struct Request;
typedef std::shared_ptr<Request> RequestPtr;
QMap<QNetworkReply*, RequestPtr> requests_;
};
#endif // ECHONESTTAGS_H

View File

@ -21,9 +21,6 @@
#include <QVBoxLayout>
#include <QXmlStreamWriter>
#include <echonest/Artist.h>
#include <echonest/TypeInformation.h>
#include <qjson/parser.h>
#include "core/closure.h"
@ -31,77 +28,64 @@
#include "songkickconcertwidget.h"
#include "ui/iconloader.h"
const char* SongkickConcerts::kSongkickArtistBucket = "songkick";
const char* SongkickConcerts::kSongkickArtistCalendarUrl =
"https://api.songkick.com/api/3.0/artists/%1/calendar.json?"
"per_page=5&"
"apikey=8rgKfy1WU6IlJFfN";
namespace {
const char* kSongkickArtistCalendarUrl =
"https://api.songkick.com/api/3.0/artists/%1/calendar.json";
const char* kSongkickArtistSearchUrl =
"https://api.songkick.com/api/3.0/search/artists.json";
const char* kSongkickApiKey = "8rgKfy1WU6IlJFfN";
} // namespace
SongkickConcerts::SongkickConcerts() {
Geolocator* geolocator = new Geolocator;
geolocator->Geolocate();
connect(geolocator, SIGNAL(Finished(Geolocator::LatLng)),
SLOT(GeolocateFinished(Geolocator::LatLng)));
NewClosure(geolocator, SIGNAL(Finished(Geolocator::LatLng)), geolocator,
SLOT(deleteLater()));
connect(geolocator, SIGNAL(Finished(Geolocator::LatLng)), geolocator,
SLOT(deleteLater()));
}
void SongkickConcerts::FetchInfo(int id, const Song& metadata) {
Echonest::Artist::SearchParams params;
params.push_back(
qMakePair(Echonest::Artist::Name, QVariant(metadata.artist())));
qLog(Debug) << "Params:" << params;
QNetworkReply* reply = Echonest::Artist::search(
params,
Echonest::ArtistInformation(Echonest::ArtistInformation::NoInformation,
QStringList() << kSongkickArtistBucket));
qLog(Debug) << reply->request().url();
if (metadata.artist().isEmpty()) {
emit Finished(id);
return;
}
QUrl url(kSongkickArtistSearchUrl);
url.addQueryItem("apikey", kSongkickApiKey);
url.addQueryItem("query", metadata.artist());
QNetworkRequest request(url);
QNetworkReply* reply = network_.get(request);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(ArtistSearchFinished(QNetworkReply*, int)), reply, id);
}
void SongkickConcerts::ArtistSearchFinished(QNetworkReply* reply, int id) {
reply->deleteLater();
try {
Echonest::Artists artists = Echonest::Artist::parseSearch(reply);
if (artists.isEmpty()) {
qLog(Debug) << "Failed to find artist in echonest";
emit Finished(id);
return;
}
const Echonest::Artist& artist = artists[0];
const Echonest::ForeignIds& foreign_ids = artist.foreignIds();
QString songkick_id;
for (const Echonest::ForeignId& id : foreign_ids) {
if (id.catalog == "songkick") {
songkick_id = id.foreign_id;
break;
}
}
QJson::Parser parser;
QVariantMap json = parser.parse(reply).toMap();
if (songkick_id.isEmpty()) {
qLog(Debug) << "Failed to fetch songkick foreign id for artist";
emit Finished(id);
return;
}
QVariantMap results_page = json["resultsPage"].toMap();
QVariantMap results = results_page["results"].toMap();
QVariantList artists = results["artist"].toList();
QStringList split = songkick_id.split(':');
if (split.count() != 3) {
qLog(Error) << "Weird songkick id";
emit Finished(id);
return;
}
FetchSongkickCalendar(split[2], id);
} catch (Echonest::ParseError& e) {
qLog(Error) << "Error parsing echonest reply:" << e.errorType() << e.what();
if (artists.isEmpty()) {
emit Finished(id);
return;
}
QVariantMap artist = artists.first().toMap();
QString artist_id = artist["id"].toString();
FetchSongkickCalendar(artist_id, id);
}
void SongkickConcerts::FetchSongkickCalendar(const QString& artist_id, int id) {
QUrl url(QString(kSongkickArtistCalendarUrl).arg(artist_id));
url.addQueryItem("per_page", "5");
url.addQueryItem("apikey", kSongkickApiKey);
qLog(Debug) << url;
QNetworkReply* reply = network_.get(QNetworkRequest(url));
NewClosure(reply, SIGNAL(finished()), this,

View File

@ -44,9 +44,6 @@ class SongkickConcerts : public SongInfoProvider {
NetworkAccessManager network_;
Geolocator::LatLng latlng_;
static const char* kSongkickArtistBucket;
static const char* kSongkickArtistCalendarUrl;
};
#endif