Add basics of last.fm suggester and library resolver.

This commit is contained in:
John Maguire 2011-05-31 14:36:28 +00:00
parent a65dab7bad
commit 41e79bea0e
5 changed files with 198 additions and 0 deletions

View File

@ -185,6 +185,8 @@ set(SOURCES
radio/somafmservice.cpp
radio/somafmurlhandler.cpp
resolvers/libraryresolver.cpp
scripting/installscriptdialog.cpp
scripting/languageengine.cpp
scripting/script.cpp
@ -222,6 +224,8 @@ set(SOURCES
songinfo/ultimatelyricsprovider.cpp
songinfo/ultimatelyricsreader.cpp
suggesters/lastfmsuggester.cpp
transcoder/transcodedialog.cpp
transcoder/transcoder.cpp
transcoder/transcoderoptionsaac.cpp
@ -397,6 +401,8 @@ set(HEADERS
radio/somafmservice.h
radio/somafmurlhandler.h
resolvers/libraryresolver.h
scripting/installscriptdialog.h
scripting/languageengine.h
scripting/scriptdialog.h
@ -428,6 +434,8 @@ set(HEADERS
songinfo/ultimatelyricsprovider.h
songinfo/ultimatelyricsreader.h
suggesters/lastfmsuggester.h
transcoder/transcodedialog.h
transcoder/transcoder.h
transcoder/transcoderoptionsdialog.h

View File

@ -0,0 +1,62 @@
#include "libraryresolver.h"
#include <QtConcurrentRun>
#include <boost/scoped_ptr.hpp>
#include "core/boundfuturewatcher.h"
#include "core/song.h"
#include "library/librarybackend.h"
#include "library/libraryquery.h"
#include "library/sqlrow.h"
using boost::scoped_ptr;
LibraryResolver::LibraryResolver(LibraryBackendInterface* backend, QObject* parent)
: QObject(parent),
backend_(backend) {
}
int LibraryResolver::ResolveSong(const Song& song) {
LibraryQuery* query = new LibraryQuery;
query->AddWhere("artist", song.artist());
query->AddWhere("title", song.title());
QFuture<bool> future = QtConcurrent::run(
backend_, &LibraryBackendInterface::ExecQuery, query);
BoundFutureWatcher<bool, LibraryQuery*>* watcher =
new BoundFutureWatcher<bool, LibraryQuery*>(query);
watcher->setFuture(future);
connect(watcher, SIGNAL(finished()), SLOT(QueryFinished()));
int id = next_id_++;
queries_[query] = id;
return id;
}
void LibraryResolver::QueryFinished() {
BoundFutureWatcher<bool, LibraryQuery*>* watcher =
static_cast<BoundFutureWatcher<bool, LibraryQuery*>*>(sender());
scoped_ptr<LibraryQuery> query(watcher->data());
watcher->deleteLater();
QMap<LibraryQuery*, int>::iterator it = queries_.find(query.get());
if (it == queries_.end()) {
return;
}
int id = it.value();
queries_.erase(it);
SongList songs;
if (watcher->result() && query->Next()) {
do {
Song song;
song.InitFromQuery(*query);
songs << song;
} while (query->Next());
}
emit ResolveFinished(id, songs);
}

View File

@ -0,0 +1,32 @@
#ifndef LIBRARYRESOLVER_H
#define LIBRARYRESOLVER_H
#include <QMap>
#include <QObject>
#include "core/song.h"
class QNetworkReply;
class LibraryBackendInterface;
class LibraryQuery;
class LibraryResolver : public QObject {
Q_OBJECT
public:
LibraryResolver(LibraryBackendInterface* backend, QObject* parent = 0);
int ResolveSong(const Song& song);
signals:
void ResolveFinished(int id, SongList songs);
private slots:
void QueryFinished();
private:
LibraryBackendInterface* backend_;
QMap<LibraryQuery*, int> queries_;
int next_id_;
};
#endif // LIBRARYRESOLVER_H

View File

@ -0,0 +1,66 @@
#include "lastfmsuggester.h"
#include <lastfm/XmlQuery>
#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);
try {
lastfm::XmlQuery const lfm = lastfm::ws::parse(reply);
#ifdef Q_OS_WIN32
if (lastfm::ws::last_parse_error != lastfm::ws::NoError)
throw std::runtime_error("");
#endif
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);
} catch (std::runtime_error& e) {
qLog(Error) << e.what();
emit SuggestSongsFinished(id, SongList());
}
}

View File

@ -0,0 +1,30 @@
#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