mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-16 19:31:02 +01:00
Support for playing tracks from Spotify
This commit is contained in:
parent
c1041ed6d4
commit
5aca9b7984
@ -224,6 +224,8 @@ void SpotifyClient::HandleMessage(const spotify_pb::SpotifyMessage& message) {
|
|||||||
LoadImage(QStringFromStdString(message.image_request().id()));
|
LoadImage(QStringFromStdString(message.image_request().id()));
|
||||||
} else if (message.has_sync_playlist_request()) {
|
} else if (message.has_sync_playlist_request()) {
|
||||||
SyncPlaylist(message.sync_playlist_request());
|
SyncPlaylist(message.sync_playlist_request());
|
||||||
|
} else if (message.has_browse_album_request()) {
|
||||||
|
BrowseAlbum(QStringFromStdString(message.browse_album_request().uri()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,3 +858,45 @@ void SpotifyClient::ImageLoaded(sp_image* image, void* userdata) {
|
|||||||
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
|
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
|
||||||
me->TryImageAgain(image);
|
me->TryImageAgain(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpotifyClient::BrowseAlbum(const QString& uri) {
|
||||||
|
// Get a link object from the URI
|
||||||
|
sp_link* link = sp_link_create_from_string(uri.toStdString().c_str());
|
||||||
|
if (!link) {
|
||||||
|
SendPlaybackError("Invalid Album URI");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the track from the link
|
||||||
|
sp_album* album = sp_link_as_album(link);
|
||||||
|
if (!album) {
|
||||||
|
SendPlaybackError("Spotify URI was not an album");
|
||||||
|
sp_link_release(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp_albumbrowse* browse =
|
||||||
|
sp_albumbrowse_create(session_, album, &AlbumBrowseComplete, this);
|
||||||
|
pending_album_browses_[browse] = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result, void* userdata) {
|
||||||
|
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
|
||||||
|
|
||||||
|
if (!me->pending_album_browses_.contains(result))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString uri = me->pending_album_browses_.take(result);
|
||||||
|
|
||||||
|
spotify_pb::SpotifyMessage message;
|
||||||
|
spotify_pb::BrowseAlbumResponse* msg = message.mutable_browse_album_response();
|
||||||
|
|
||||||
|
msg->set_uri(DataCommaSizeFromQString(uri));
|
||||||
|
|
||||||
|
const int count = sp_albumbrowse_num_tracks(result);
|
||||||
|
for (int i=0 ; i<count ; ++i) {
|
||||||
|
me->ConvertTrack(sp_albumbrowse_track(result, i), msg->add_track());
|
||||||
|
}
|
||||||
|
|
||||||
|
me->handler_->SendMessage(message);
|
||||||
|
}
|
||||||
|
@ -92,6 +92,9 @@ private:
|
|||||||
// Spotify image callbacks.
|
// Spotify image callbacks.
|
||||||
static void SP_CALLCONV ImageLoaded(sp_image* image, void* userdata);
|
static void SP_CALLCONV ImageLoaded(sp_image* image, void* userdata);
|
||||||
|
|
||||||
|
// Spotify album browse callbacks.
|
||||||
|
static void SP_CALLCONV AlbumBrowseComplete(sp_albumbrowse* result, void* userdata);
|
||||||
|
|
||||||
// Request handlers.
|
// Request handlers.
|
||||||
void Login(const QString& username, const QString& password);
|
void Login(const QString& username, const QString& password);
|
||||||
void Search(const spotify_pb::SearchRequest& req);
|
void Search(const spotify_pb::SearchRequest& req);
|
||||||
@ -99,6 +102,7 @@ private:
|
|||||||
void SyncPlaylist(const spotify_pb::SyncPlaylistRequest& req);
|
void SyncPlaylist(const spotify_pb::SyncPlaylistRequest& req);
|
||||||
void StartPlayback(const spotify_pb::PlaybackRequest& req);
|
void StartPlayback(const spotify_pb::PlaybackRequest& req);
|
||||||
void LoadImage(const QString& id_b64);
|
void LoadImage(const QString& id_b64);
|
||||||
|
void BrowseAlbum(const QString& uri);
|
||||||
|
|
||||||
void SendPlaylistList();
|
void SendPlaylistList();
|
||||||
|
|
||||||
@ -158,6 +162,7 @@ private:
|
|||||||
QList<PendingImageRequest> pending_image_requests_;
|
QList<PendingImageRequest> pending_image_requests_;
|
||||||
QMap<sp_image*, int> image_callbacks_registered_;
|
QMap<sp_image*, int> image_callbacks_registered_;
|
||||||
QMap<sp_search*, spotify_pb::SearchRequest> pending_searches_;
|
QMap<sp_search*, spotify_pb::SearchRequest> pending_searches_;
|
||||||
|
QMap<sp_albumbrowse*, QString> pending_album_browses_;
|
||||||
|
|
||||||
int media_length_msec_;
|
int media_length_msec_;
|
||||||
};
|
};
|
||||||
|
@ -128,6 +128,15 @@ message ImageResponse {
|
|||||||
optional bytes data = 2;
|
optional bytes data = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message BrowseAlbumRequest {
|
||||||
|
required string uri = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BrowseAlbumResponse {
|
||||||
|
required string uri = 1;
|
||||||
|
repeated Track track = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message SpotifyMessage {
|
message SpotifyMessage {
|
||||||
optional LoginRequest login_request = 1;
|
optional LoginRequest login_request = 1;
|
||||||
optional LoginResponse login_response = 2;
|
optional LoginResponse login_response = 2;
|
||||||
@ -142,4 +151,6 @@ message SpotifyMessage {
|
|||||||
optional ImageResponse image_response = 11;
|
optional ImageResponse image_response = 11;
|
||||||
optional SyncPlaylistRequest sync_playlist_request = 12;
|
optional SyncPlaylistRequest sync_playlist_request = 12;
|
||||||
optional SyncPlaylistProgress sync_playlist_progress = 13;
|
optional SyncPlaylistProgress sync_playlist_progress = 13;
|
||||||
|
optional BrowseAlbumRequest browse_album_request = 14;
|
||||||
|
optional BrowseAlbumResponse browse_album_response = 15;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include "internet/internetmodel.h"
|
#include "internet/internetmodel.h"
|
||||||
#include "internet/spotifyserver.h"
|
#include "internet/spotifyserver.h"
|
||||||
#include "internet/spotifyservice.h"
|
#include "internet/spotifyservice.h"
|
||||||
|
#include "playlist/songmimedata.h"
|
||||||
|
#include "spotifyblob/common/spotifymessagehandler.h"
|
||||||
|
|
||||||
SpotifySearchProvider::SpotifySearchProvider(QObject* parent)
|
SpotifySearchProvider::SpotifySearchProvider(QObject* parent)
|
||||||
: SearchProvider(parent),
|
: SearchProvider(parent),
|
||||||
@ -44,6 +46,8 @@ SpotifyServer* SpotifySearchProvider::server() {
|
|||||||
SLOT(SearchFinishedSlot(spotify_pb::SearchResponse)));
|
SLOT(SearchFinishedSlot(spotify_pb::SearchResponse)));
|
||||||
connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
|
connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
|
||||||
SLOT(ArtLoadedSlot(QString,QImage)));
|
SLOT(ArtLoadedSlot(QString,QImage)));
|
||||||
|
connect(server_, SIGNAL(AlbumBrowseResults(spotify_pb::BrowseAlbumResponse)),
|
||||||
|
SLOT(AlbumBrowseResponse(spotify_pb::BrowseAlbumResponse)));
|
||||||
connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));
|
connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));
|
||||||
|
|
||||||
return service_->server();
|
return service_->server();
|
||||||
@ -134,7 +138,48 @@ void SpotifySearchProvider::ArtLoadedSlot(const QString& id, const QImage& image
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) {
|
void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) {
|
||||||
emit TracksLoaded(id, NULL);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ private slots:
|
|||||||
void SearchFinishedSlot(const spotify_pb::SearchResponse& response);
|
void SearchFinishedSlot(const spotify_pb::SearchResponse& response);
|
||||||
void ArtLoadedSlot(const QString& id, const QImage& image);
|
void ArtLoadedSlot(const QString& id, const QImage& image);
|
||||||
|
|
||||||
|
void AlbumBrowseResponse(const spotify_pb::BrowseAlbumResponse& response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PendingState {
|
struct PendingState {
|
||||||
int orig_id_;
|
int orig_id_;
|
||||||
@ -54,6 +56,7 @@ private:
|
|||||||
|
|
||||||
QMap<QString, PendingState> queries_;
|
QMap<QString, PendingState> queries_;
|
||||||
QMap<QString, int> pending_art_;
|
QMap<QString, int> pending_art_;
|
||||||
|
QMap<QString, int> pending_tracks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SPOTIFYSEARCHPROVIDER_H
|
#endif // SPOTIFYSEARCHPROVIDER_H
|
||||||
|
@ -134,6 +134,8 @@ void SpotifyServer::HandleMessage(const spotify_pb::SpotifyMessage& message) {
|
|||||||
}
|
}
|
||||||
} else if (message.has_sync_playlist_progress()) {
|
} else if (message.has_sync_playlist_progress()) {
|
||||||
emit SyncPlaylistProgress(message.sync_playlist_progress());
|
emit SyncPlaylistProgress(message.sync_playlist_progress());
|
||||||
|
} else if (message.has_browse_album_response()) {
|
||||||
|
emit AlbumBrowseResults(message.browse_album_response());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,3 +216,11 @@ void SpotifyServer::LoadImage(const QString& id) {
|
|||||||
req->set_id(DataCommaSizeFromQString(id));
|
req->set_id(DataCommaSizeFromQString(id));
|
||||||
SendMessage(message);
|
SendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpotifyServer::AlbumBrowse(const QString& uri) {
|
||||||
|
spotify_pb::SpotifyMessage message;
|
||||||
|
spotify_pb::BrowseAlbumRequest* req = message.mutable_browse_album_request();
|
||||||
|
|
||||||
|
req->set_uri(DataCommaSizeFromQString(uri));
|
||||||
|
SendMessage(message);
|
||||||
|
}
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
void StartPlayback(const QString& uri, quint16 port);
|
void StartPlayback(const QString& uri, quint16 port);
|
||||||
void Search(const QString& text, int limit, int limit_album = 0);
|
void Search(const QString& text, int limit, int limit_album = 0);
|
||||||
void LoadImage(const QString& id);
|
void LoadImage(const QString& id);
|
||||||
|
void AlbumBrowse(const QString& uri);
|
||||||
|
|
||||||
int server_port() const;
|
int server_port() const;
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ signals:
|
|||||||
void SearchResults(const spotify_pb::SearchResponse& response);
|
void SearchResults(const spotify_pb::SearchResponse& response);
|
||||||
void ImageLoaded(const QString& id, const QImage& image);
|
void ImageLoaded(const QString& id, const QImage& image);
|
||||||
void SyncPlaylistProgress(const spotify_pb::SyncPlaylistProgress& progress);
|
void SyncPlaylistProgress(const spotify_pb::SyncPlaylistProgress& progress);
|
||||||
|
void AlbumBrowseResults(const spotify_pb::BrowseAlbumResponse& response);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void NewConnection();
|
void NewConnection();
|
||||||
|
Loading…
Reference in New Issue
Block a user