Add a compatibility header so liblastfm and liblastfm1 can both be used with the same source.

This commit is contained in:
David Sansome 2012-06-28 17:41:51 +01:00
parent 769baa5c16
commit abe8d10b9c
14 changed files with 248 additions and 161 deletions

View File

@ -82,6 +82,11 @@ endif (WIN32)
find_library(LASTFM_LIBRARIES lastfm)
find_path(LASTFM_INCLUDE_DIRS lastfm/ws.h)
find_path(LASTFM1_INCLUDE_DIRS lastfm/Track.h)
if(LASTFM_INCLUDE_DIRS AND LASTFM1_INCLUDE_DIRS)
set(HAVE_LIBLASTFM1 ON)
endif()
if (APPLE)
find_library(GROWL Growl)

View File

@ -744,6 +744,7 @@ optional_source(HAVE_LIBLASTFM
covers/lastfmcoverprovider.cpp
globalsearch/lastfmsearchprovider.cpp
internet/fixlastfm.cpp
internet/lastfmcompat.cpp
internet/lastfmservice.cpp
internet/lastfmsettingspage.cpp
internet/lastfmstationdialog.cpp
@ -752,7 +753,6 @@ optional_source(HAVE_LIBLASTFM
songinfo/echonesttags.cpp
songinfo/lastfmtrackinfoprovider.cpp
songinfo/tagwidget.cpp
suggesters/lastfmsuggester.cpp
HEADERS
covers/lastfmcoverprovider.h
internet/lastfmservice.h
@ -762,7 +762,6 @@ optional_source(HAVE_LIBLASTFM
songinfo/echonesttags.h
songinfo/lastfmtrackinfoprovider.h
songinfo/tagwidget.h
suggesters/lastfmsuggester.h
UI
internet/lastfmsettingspage.ui
internet/lastfmstationdialog.ui

View File

@ -31,6 +31,7 @@
#cmakedefine HAVE_LIBGPOD
#cmakedefine HAVE_LIBINDICATE
#cmakedefine HAVE_LIBLASTFM
#cmakedefine HAVE_LIBLASTFM1
#cmakedefine HAVE_LIBMTP
#cmakedefine HAVE_MOODBAR
#cmakedefine HAVE_QCA

View File

@ -26,7 +26,11 @@
#ifdef HAVE_LIBLASTFM
#include "internet/fixlastfm.h"
#include <lastfm/Track.h>
#ifdef HAVE_LIBLASTFM1
#include <lastfm/Track.h>
#else
#include <lastfm/Track>
#endif
#endif
#include <QFile>

View File

@ -18,10 +18,7 @@
#include "albumcoverfetcher.h"
#include "coverprovider.h"
#include "lastfmcoverprovider.h"
#include <lastfm/Artist.h>
#include <lastfm/XmlQuery.h>
#include <lastfm/ws.h>
#include "internet/lastfmcompat.h"
#include <QNetworkReply>
@ -52,8 +49,8 @@ void LastFmCoverProvider::QueryFinished() {
CoverSearchResults results;
lastfm::XmlQuery query;
if (query.parse(reply->readAll())) {
lastfm::XmlQuery query(lastfm::compat::EmptyXmlQuery());
if (lastfm::compat::ParseQuery(reply->readAll(), &query)) {
// parse the list of search results
QList<lastfm::XmlQuery> elements = query["results"]["albummatches"].children("album");

View File

@ -0,0 +1,110 @@
/* This file is part of Clementine.
Copyright 2012, 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 "lastfmcompat.h"
#include "core/logging.h"
namespace lastfm {
namespace compat {
#ifdef HAVE_LIBLASTFM1
XmlQuery EmptyXmlQuery() {
return XmlQuery();
}
bool ParseQuery(const QByteArray& data, XmlQuery* query, bool* connection_problems) {
const bool ret = query->parse(data);
if (connection_problems) {
*connection_problems =
!ret && query->parseError().enumValue() == lastfm::ws::MalformedResponse;
}
return ret;
}
bool ParseUserList(QNetworkReply* reply, QList<User>* users) {
lastfm::XmlQuery lfm;
if (!lfm.parse(reply->readAll())) {
return false;
}
*users = lastfm::UserList(lfm).users();
return true;
}
uint ScrobbleTimeMin() {
return lastfm::ScrobblePoint::scrobbleTimeMin();
}
#else // HAVE_LIBLASTFM1
XmlQuery EmptyXmlQuery() {
QByteArray dummy;
return XmlQuery(dummy);
}
bool ParseQuery(const QByteArray& data, XmlQuery* query, bool* connection_problems) {
try {
*query = lastfm::XmlQuery(data);
#ifdef Q_OS_WIN32
if (lastfm::ws::last_parse_error != lastfm::ws::NoError) {
return false;
}
#endif // Q_OS_WIN32
} catch (lastfm::ws::ParseError e) {
qLog(Error) << "Last.fm parse error: " << e.enumValue();
if (connection_problems) {
*connection_problems = e.enumValue() == lastfm::ws::MalformedResponse;
}
return false;
} catch(std::runtime_error& e) {
qLog(Error) << e.what();
return false;
}
if (connection_problems) {
*connection_problems = false;
}
return true;
}
bool ParseUserList(QNetworkReply* reply, QList<User>* users) {
try {
*users = lastfm::User::list(reply);
#ifdef Q_OS_WIN32
if (lastfm::ws::last_parse_error != lastfm::ws::NoError) {
return false;
}
#endif // Q_OS_WIN32
} catch(std::runtime_error& e) {
qLog(Error) << e.what();
return false;
}
return true;
}
uint ScrobbleTimeMin() {
return ScrobblePoint::kScrobbleMinLength;
}
#endif // HAVE_LIBLASTFM1
}
}

View File

@ -0,0 +1,65 @@
/* This file is part of Clementine.
Copyright 2012, 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 LASTFMCOMPAT_H
#define LASTFMCOMPAT_H
#include "config.h"
#include "fixlastfm.h"
#ifdef HAVE_LIBLASTFM1
#include <lastfm/Audioscrobbler.h>
#include <lastfm/misc.h>
#include <lastfm/ScrobbleCache.h>
#include <lastfm/ScrobblePoint.h>
#include <lastfm/User.h>
#include <lastfm/ws.h>
#include <lastfm/XmlQuery.h>
#else
#include <lastfm/Audioscrobbler>
#include <lastfm/misc.h>
#include <lastfm/ScrobbleCache>
#include <lastfm/ScrobblePoint>
#include <lastfm/User>
#include <lastfm/ws.h>
#include <lastfm/XmlQuery>
#endif
namespace lastfm {
namespace compat {
lastfm::XmlQuery EmptyXmlQuery();
bool ParseQuery(const QByteArray& data, lastfm::XmlQuery* query,
bool* connection_problems = NULL);
bool ParseUserList(QNetworkReply* reply, QList<lastfm::User>* users);
uint ScrobbleTimeMin();
#ifdef HAVE_LIBLASTFM1
typedef lastfm::ScrobbleCache ScrobbleCache;
typedef lastfm::User AuthenticatedUser;
#else
typedef ::ScrobbleCache ScrobbleCache;
typedef lastfm::AuthenticatedUser AuthenticatedUser;
#endif
}
}
#endif // LASTFMCOMPAT_H

View File

@ -31,6 +31,8 @@
#endif // QT_VERSION >= 0x040600
#include "lastfmservice.h"
#include "lastfmcompat.h"
#include "lastfmstationdialog.h"
#include "lastfmurlhandler.h"
#include "internetmodel.h"
@ -49,17 +51,15 @@
#include <boost/scoped_ptr.hpp>
#include <lastfm/Audioscrobbler.h>
#include <lastfm/misc.h>
#include <lastfm/RadioStation.h>
#include <lastfm/ScrobbleCache.h>
#include <lastfm/ScrobblePoint.h>
#include <lastfm/ws.h>
#include <lastfm/XmlQuery.h>
#include <QMenu>
#include <QSettings>
#ifdef HAVE_LIBLASTFM1
#include <lastfm/RadioStation.h>
#else
#include <lastfm/RadioStation>
#endif
using boost::scoped_ptr;
using lastfm::XmlQuery;
@ -316,8 +316,8 @@ void LastFMService::AuthenticateReplyFinished() {
reply->deleteLater();
// Parse the reply
lastfm::XmlQuery lfm;
if (lfm.parse(reply->readAll())) {
lastfm::XmlQuery lfm(lastfm::compat::EmptyXmlQuery());
if (lastfm::compat::ParseQuery(reply->readAll(), &lfm)) {
lastfm::ws::Username = lfm["session"]["name"].text();
lastfm::ws::SessionKey = lfm["session"]["key"].text();
QString subscribed = lfm["session"]["subscriber"].text();
@ -330,7 +330,6 @@ void LastFMService::AuthenticateReplyFinished() {
settings.setValue("Session", lastfm::ws::SessionKey);
settings.setValue("Subscriber", is_subscriber);
} else {
qLog(Error) << lfm.parseError().message();
emit AuthenticationComplete(false);
return;
}
@ -358,9 +357,8 @@ void LastFMService::UpdateSubscriberStatusFinished() {
bool is_subscriber = false;
lastfm::XmlQuery lfm;
if (lfm.parse(reply->readAll())) {
connection_problems_ = false;
lastfm::XmlQuery lfm(lastfm::compat::EmptyXmlQuery());
if (lastfm::compat::ParseQuery(reply->readAll(), &lfm, &connection_problems_)) {
QString subscriber = lfm["user"]["subscriber"].text();
is_subscriber = (subscriber.toInt() == 1);
@ -368,9 +366,6 @@ void LastFMService::UpdateSubscriberStatusFinished() {
settings.beginGroup(kSettingsGroup);
settings.setValue("Subscriber", is_subscriber);
qLog(Info) << lastfm::ws::Username << "Subscriber status:" << is_subscriber;
} else {
qLog(Error) << "Last.fm parse error: " << lfm.parseError().message();
connection_problems_ = lfm.parseError().enumValue() == lastfm::ws::MalformedResponse;
}
emit UpdatedSubscriberStatus(is_subscriber);
@ -473,11 +468,28 @@ bool LastFMService::InitScrobbler() {
scrobbler_ = new lastfm::Audioscrobbler(kAudioscrobblerClientId);
//reemit the signal since the sender is private
#ifdef HAVE_LIBLASTFM1
connect(scrobbler_, SIGNAL(scrobblesSubmitted(QList<lastfm::Track>)), SIGNAL(ScrobbleSubmitted()));
connect(scrobbler_, SIGNAL(nowPlayingError(int,QString)), SIGNAL(ScrobbleError(int)));
#else
connect(scrobbler_, SIGNAL(status(int)), SIGNAL(ScrobblerStatus(int)));
#endif
return true;
}
void LastFMService::ScrobblerStatus(int value) {
switch (value) {
case 2:
case 3:
emit ScrobbleSubmitted();
break;
default:
emit ScrobbleError(value);
break;
}
}
lastfm::Track LastFMService::TrackFromSong(const Song &song) const {
if (song.title() == last_track_.title() &&
song.artist() == last_track_.artist() &&
@ -502,7 +514,7 @@ void LastFMService::NowPlaying(const Song &song) {
if (!last_track_.isNull() &&
last_track_.source() == lastfm::Track::NonPersonalisedBroadcast) {
const int duration_secs = last_track_.timestamp().secsTo(QDateTime::currentDateTime());
if (duration_secs >= lastfm::ScrobblePoint::scrobbleTimeMin()) {
if (duration_secs >= lastfm::compat::ScrobbleTimeMin()) {
lastfm::MutableTrack mtrack(last_track_);
mtrack.setDuration(duration_secs);
@ -519,16 +531,18 @@ void LastFMService::NowPlaying(const Song &song) {
already_scrobbled_ = false;
last_track_ = mtrack;
// TODO: validity was removed from liblastfm1 but might reappear, it should have
// no impact as we get a different error when actually trying to scrobble.
// //check immediately if the song is valid
// Scrobble::Invalidity invalidity;
//
// if (!lastfm::Scrobble(last_track_).isValid( &invalidity )) {
// //for now just notify this, we can also see the cause
// emit ScrobbleError(-1);
// return;
// }
#ifndef HAVE_LIBLASTFM1
// Check immediately if the song is valid
Scrobble::Invalidity invalidity;
if (!lastfm::Scrobble(last_track_).isValid( &invalidity )) {
//for now just notify this, we can also see the cause
emit ScrobbleError(-1);
return;
}
#else
// TODO: validity was removed from liblastfm1 but might reappear, it should have
// no impact as we get a different error when actually trying to scrobble.
#endif
scrobbler_->nowPlaying(mtrack);
}
@ -537,7 +551,7 @@ void LastFMService::Scrobble() {
if (!InitScrobbler())
return;
lastfm::ScrobbleCache cache(lastfm::ws::Username);
lastfm::compat::ScrobbleCache cache(lastfm::ws::Username);
qLog(Debug) << "There are" << cache.tracks().count() << "tracks in the last.fm cache.";
scrobbler_->cache(last_track_);
@ -646,7 +660,7 @@ void LastFMService::RefreshFriends(bool force) {
return;
}
lastfm::User user;
lastfm::compat::AuthenticatedUser user;
QNetworkReply* reply = user.getFriends();
connect(reply, SIGNAL(finished()), SLOT(RefreshFriendsFinished()));
}
@ -655,7 +669,7 @@ void LastFMService::RefreshNeighbours() {
if (!neighbours_list_ || !IsAuthenticated())
return;
lastfm::User user;
lastfm::compat::AuthenticatedUser user;
QNetworkReply* reply = user.getNeighbours();
connect(reply, SIGNAL(finished()), SLOT(RefreshNeighboursFinished()));
}
@ -666,12 +680,7 @@ void LastFMService::RefreshFriendsFinished() {
return;
QList<lastfm::User> friends;
lastfm::XmlQuery lfm;
if (lfm.parse(reply->readAll())) {
friends = lastfm::UserList(lfm).users();
} else {
qLog(Error) << lfm.parseError().message();
if (!lastfm::compat::ParseUserList(reply, &friends)) {
return;
}
@ -710,12 +719,7 @@ void LastFMService::RefreshNeighboursFinished() {
return;
QList<lastfm::User> neighbours;
lastfm::XmlQuery lfm;
if (lfm.parse(reply->readAll())) {
neighbours = lastfm::UserList(lfm).users();
} else {
qLog(Error) << lfm.parseError().message();
if (!lastfm::compat::ParseUserList(reply, &neighbours)) {
return;
}
@ -866,8 +870,8 @@ void LastFMService::FetchMoreTracksFinished() {
app_->task_manager()->SetTaskFinished(tune_task_id_);
tune_task_id_ = 0;
XmlQuery query;
if (query.parse(reply->readAll())) {
lastfm::XmlQuery query(lastfm::compat::EmptyXmlQuery());
if (lastfm::compat::ParseQuery(reply->readAll(), &query)) {
const XmlQuery& playlist = query["playlist"];
foreach (const XmlQuery& q, playlist["trackList"].children("track")) {
lastfm::MutableTrack t;
@ -883,8 +887,7 @@ void LastFMService::FetchMoreTracksFinished() {
playlist_ << t;
}
} else {
emit StreamError(tr("Couldn't load the last.fm radio station")
.arg(query.parseError().message()));
emit StreamError(tr("Couldn't load the last.fm radio station"));
return;
}

View File

@ -26,10 +26,7 @@ class Track;
#include <QtGlobal>
uint qHash(const lastfm::Track& track);
#include "fixlastfm.h"
#include <lastfm/Audioscrobbler.h>
#include <lastfm/Track.h>
#include <lastfm/ws.h>
#include "lastfmcompat.h"
#include "internetmodel.h"
#include "internetservice.h"
@ -150,6 +147,7 @@ class LastFMService : public InternetService {
void TunerTrackAvailable();
void TunerError(lastfm::ws::Error error);
void ScrobblerStatus(int value);
void AddArtistRadio();
void AddTagRadio();

View File

@ -19,11 +19,9 @@
#include "songinfotextview.h"
#include "songplaystats.h"
#include "tagwidget.h"
#include "internet/lastfmcompat.h"
#include "ui/iconloader.h"
#include <lastfm/ws.h>
#include <lastfm/XmlQuery.h>
void LastfmTrackInfoProvider::FetchInfo(int id, const Song& metadata) {
QMap<QString, QString> params;
params["method"] = "track.getInfo";
@ -50,13 +48,13 @@ void LastfmTrackInfoProvider::RequestFinished() {
return;
}
lastfm::XmlQuery query;
if (query.parse(reply->readAll())) {
lastfm::XmlQuery query(lastfm::compat::EmptyXmlQuery());
if (lastfm::compat::ParseQuery(reply->readAll(), &query)) {
GetPlayCounts(id, query);
GetWiki(id, query);
GetTags(id, query);
}
emit Finished(id);
}

View File

@ -1,61 +0,0 @@
#include "lastfmsuggester.h"
#include <lastfm/XmlQuery.h>
#include "core/logging.h"
#include "core/timeconstants.h"
using lastfm::XmlQuery;
LastFMSuggester::LastFMSuggester(QObject* parent)
: QObject(parent),
next_id_(0) {
}
int LastFMSuggester::SuggestSongs(const Song& song) {
QMap<QString, QString> params;
params["method"] = "track.getsimilar";
params["track"] = song.title();
params["artist"] = song.artist();
params["limit"] = "25";
QNetworkReply* reply = lastfm::ws::get(params);
connect(reply, SIGNAL(finished()), SLOT(RequestFinished()));
int id = next_id_++;
replies_[reply] = id;
return id;
}
void LastFMSuggester::RequestFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
Q_ASSERT(reply);
reply->deleteLater();
QMap<QNetworkReply*, int>::iterator it = replies_.find(reply);
if (it == replies_.end()) {
return;
}
int id = it.value();
replies_.erase(it);
lastfm::XmlQuery lfm;
if (lfm.parse(reply->readAll())) {
const QList<XmlQuery> tracks = lfm["similartracks"].children("track");
SongList songs;
foreach (const XmlQuery& q, tracks) {
Song song;
song.Init(
q["name"].text(),
q["artist"]["name"].text(),
QString::null,
QString(q["duration"].text()).toInt() * kNsecPerMsec);
songs << song;
}
qLog(Debug) << songs.length() << "suggested songs from Last.fm";
emit SuggestSongsFinished(id, songs);
} else {
qLog(Error) << lfm.parseError().message();
emit SuggestSongsFinished(id, SongList());
}
}

View File

@ -1,30 +0,0 @@
#ifndef LASTFMSUGGESTER_H
#define LASTFMSUGGESTER_H
#include <QMap>
#include <QObject>
#include <lastfm/ws.h>
#include "core/song.h"
class LastFMSuggester : public QObject {
Q_OBJECT
public:
LastFMSuggester(QObject* parent = 0);
public slots:
int SuggestSongs(const Song& song);
signals:
void SuggestSongsFinished(int id, const SongList& songs);
private slots:
void RequestFinished();
private:
QMap<QNetworkReply*, int> replies_;
int next_id_;
};
#endif // LASTFMSUGGESTER_H

View File

@ -21,8 +21,7 @@
#include "playlist/playlistmanager.h"
#include "playlist/playlistsequence.h"
#ifdef HAVE_LIBLASTFM
#include "internet/fixlastfm.h"
#include <lastfm/Track.h>
#include "internet/lastfmcompat.h"
#endif
#include "gmock/gmock.h"

View File

@ -19,8 +19,7 @@
#include "core/encoding.h"
#include "core/song.h"
#ifdef HAVE_LIBLASTFM
#include "internet/fixlastfm.h"
#include <lastfm/Track.h>
#include "internet/lastfmcompat.h"
#endif
#include "gmock/gmock.h"