2011-08-29 00:59:18 +02:00
|
|
|
/* 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 "spotifysearchprovider.h"
|
2011-08-29 01:32:45 +02:00
|
|
|
#include "core/logging.h"
|
2011-08-29 00:59:18 +02:00
|
|
|
#include "internet/internetmodel.h"
|
|
|
|
#include "internet/spotifyserver.h"
|
|
|
|
#include "internet/spotifyservice.h"
|
2011-08-29 04:26:59 +02:00
|
|
|
#include "playlist/songmimedata.h"
|
|
|
|
#include "spotifyblob/common/spotifymessagehandler.h"
|
2011-08-29 00:59:18 +02:00
|
|
|
|
|
|
|
SpotifySearchProvider::SpotifySearchProvider(QObject* parent)
|
2011-08-29 01:13:36 +02:00
|
|
|
: SearchProvider(parent),
|
2011-08-29 00:59:18 +02:00
|
|
|
server_(NULL),
|
|
|
|
service_(NULL)
|
|
|
|
{
|
2011-09-17 18:42:14 +02:00
|
|
|
Init("Spotify", "spotify", QIcon(":icons/svg/spotify.svg"), true, true);
|
2011-08-29 00:59:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SpotifyServer* SpotifySearchProvider::server() {
|
|
|
|
if (server_)
|
|
|
|
return server_;
|
|
|
|
|
|
|
|
if (!service_)
|
|
|
|
service_ = InternetModel::Service<SpotifyService>();
|
|
|
|
|
|
|
|
if (service_->login_state() != SpotifyService::LoginState_LoggedIn)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
server_ = service_->server();
|
2011-08-29 03:00:59 +02:00
|
|
|
connect(server_, SIGNAL(SearchResults(spotify_pb::SearchResponse)),
|
|
|
|
SLOT(SearchFinishedSlot(spotify_pb::SearchResponse)));
|
2011-08-29 00:59:18 +02:00
|
|
|
connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
|
|
|
|
SLOT(ArtLoadedSlot(QString,QImage)));
|
2011-08-29 04:26:59 +02:00
|
|
|
connect(server_, SIGNAL(AlbumBrowseResults(spotify_pb::BrowseAlbumResponse)),
|
|
|
|
SLOT(AlbumBrowseResponse(spotify_pb::BrowseAlbumResponse)));
|
2011-08-29 00:59:18 +02:00
|
|
|
connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));
|
|
|
|
|
|
|
|
return service_->server();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpotifySearchProvider::ServerDestroyed() {
|
|
|
|
server_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpotifySearchProvider::SearchAsync(int id, const QString& query) {
|
|
|
|
SpotifyServer* s = server();
|
|
|
|
if (!s) {
|
|
|
|
emit SearchFinished(id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PendingState state;
|
|
|
|
state.orig_id_ = id;
|
|
|
|
state.tokens_ = TokenizeQuery(query);
|
|
|
|
|
|
|
|
const QString query_string = state.tokens_.join(" ");
|
2011-08-29 03:00:59 +02:00
|
|
|
s->Search(query_string, 5, 5);
|
2011-08-29 00:59:18 +02:00
|
|
|
queries_[query_string] = state;
|
|
|
|
}
|
|
|
|
|
2011-08-29 03:00:59 +02:00
|
|
|
void SpotifySearchProvider::SearchFinishedSlot(const spotify_pb::SearchResponse& response) {
|
2011-08-29 00:59:18 +02:00
|
|
|
QString query_string = QString::fromUtf8(response.request().query().c_str());
|
|
|
|
QMap<QString, PendingState>::iterator it = queries_.find(query_string);
|
|
|
|
if (it == queries_.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
PendingState state = it.value();
|
|
|
|
queries_.erase(it);
|
|
|
|
|
|
|
|
ResultList ret;
|
2011-08-29 03:00:59 +02:00
|
|
|
for (int i=0; i < response.result_size() ; ++i) {
|
|
|
|
const spotify_pb::Track& track = response.result(i);
|
2011-08-29 00:59:18 +02:00
|
|
|
|
|
|
|
Result result(this);
|
|
|
|
result.type_ = Result::Type_Track;
|
|
|
|
SpotifyService::SongFromProtobuf(track, &result.metadata_);
|
|
|
|
result.match_quality_ = MatchQuality(state.tokens_, result.metadata_.title());
|
|
|
|
|
|
|
|
ret << result;
|
|
|
|
}
|
|
|
|
|
2011-08-29 03:00:59 +02:00
|
|
|
for (int i=0 ; i<response.album_size() ; ++i) {
|
2011-09-18 01:06:07 +02:00
|
|
|
const spotify_pb::Album& album = response.album(i);
|
2011-08-29 03:00:59 +02:00
|
|
|
|
|
|
|
Result result(this);
|
|
|
|
result.type_ = Result::Type_Album;
|
2011-09-18 01:06:07 +02:00
|
|
|
SpotifyService::SongFromProtobuf(album.metadata(), &result.metadata_);
|
2011-08-29 03:00:59 +02:00
|
|
|
result.match_quality_ =
|
|
|
|
qMin(MatchQuality(state.tokens_, result.metadata_.album()),
|
|
|
|
MatchQuality(state.tokens_, result.metadata_.artist()));
|
2011-09-18 01:06:07 +02:00
|
|
|
result.album_size_ = album.metadata().track();
|
|
|
|
|
|
|
|
for (int j=0; j < album.track_size() ; ++j) {
|
|
|
|
Song track_song;
|
|
|
|
SpotifyService::SongFromProtobuf(album.track(j), &track_song);
|
|
|
|
result.album_songs_ << track_song;
|
|
|
|
}
|
|
|
|
|
2011-08-29 03:00:59 +02:00
|
|
|
ret << result;
|
|
|
|
}
|
|
|
|
|
2011-08-29 00:59:18 +02:00
|
|
|
emit ResultsAvailable(state.orig_id_, ret);
|
|
|
|
emit SearchFinished(state.orig_id_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpotifySearchProvider::LoadArtAsync(int id, const Result& result) {
|
|
|
|
SpotifyServer* s = server();
|
|
|
|
if (!s) {
|
|
|
|
emit ArtLoaded(id, QImage());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-29 02:24:32 +02:00
|
|
|
QString image_id = QUrl(result.metadata_.art_automatic()).path();
|
2011-08-29 00:59:18 +02:00
|
|
|
if (image_id.startsWith('/'))
|
|
|
|
image_id.remove(0, 1);
|
|
|
|
|
|
|
|
pending_art_[image_id] = id;
|
|
|
|
s->LoadImage(image_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpotifySearchProvider::ArtLoadedSlot(const QString& id, const QImage& image) {
|
|
|
|
QMap<QString, int>::iterator it = pending_art_.find(id);
|
|
|
|
if (it == pending_art_.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const int orig_id = it.value();
|
|
|
|
pending_art_.erase(it);
|
|
|
|
|
|
|
|
emit ArtLoaded(orig_id, ScaleAndPad(image));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) {
|
2011-08-29 04:26:59 +02:00
|
|
|
switch (result.type_) {
|
|
|
|
case Result::Type_Track: {
|
|
|
|
SongMimeData* mime_data = new SongMimeData;
|
|
|
|
mime_data->songs = SongList() << result.metadata_;
|
|
|
|
emit TracksLoaded(id, mime_data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Result::Type_Album: {
|
|
|
|
SpotifyServer* s = server();
|
|
|
|
if (!s) {
|
|
|
|
emit TracksLoaded(id, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString uri = result.metadata_.url().toString();
|
|
|
|
|
|
|
|
pending_tracks_[uri] = id;
|
|
|
|
s->AlbumBrowse(uri);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpotifySearchProvider::AlbumBrowseResponse(const spotify_pb::BrowseAlbumResponse& response) {
|
|
|
|
QString uri = QStringFromStdString(response.uri());
|
|
|
|
QMap<QString, int>::iterator it = pending_tracks_.find(uri);
|
|
|
|
if (it == pending_tracks_.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const int orig_id = it.value();
|
|
|
|
pending_tracks_.erase(it);
|
|
|
|
|
|
|
|
SongMimeData* mime_data = new SongMimeData;
|
|
|
|
|
|
|
|
for (int i=0 ; i<response.track_size() ; ++i) {
|
|
|
|
Song song;
|
|
|
|
SpotifyService::SongFromProtobuf(response.track(i), &song);
|
|
|
|
mime_data->songs << song;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit TracksLoaded(orig_id, mime_data);
|
2011-08-29 00:59:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|