mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-27 17:49:19 +01:00
Spotify: add the ability to add/remove tracks to/from Starred playlist
This commit is contained in:
parent
53279ebc66
commit
7039c2a2bf
@ -372,6 +372,7 @@ void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc,
|
||||
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
|
||||
|
||||
// Install callbacks on all the playlists
|
||||
sp_playlist_add_callbacks(sp_session_starred_create(me->session_), &me->get_playlists_callbacks_, me);
|
||||
const int count = sp_playlistcontainer_num_playlists(pc);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
sp_playlist* playlist = sp_playlistcontainer_playlist(pc, i);
|
||||
@ -611,11 +612,10 @@ void SpotifyClient::PlaylistStateChangedForGetPlaylists(sp_playlist* pl,
|
||||
void SpotifyClient::AddTracksToPlaylist(
|
||||
const pb::spotify::AddTracksToPlaylistRequest& req) {
|
||||
// Get the playlist we want to update
|
||||
int playlist_index = req.playlist_index();
|
||||
sp_playlist* playlist =
|
||||
GetPlaylist(pb::spotify::UserPlaylist, playlist_index);
|
||||
sp_playlist* playlist = GetPlaylist(req.playlist_type(), req.playlist_index());
|
||||
if (!playlist) {
|
||||
qLog(Error) << "Playlist " << playlist_index << "not found";
|
||||
qLog(Error) << "Playlist " << req.playlist_type() << "," <<
|
||||
req.playlist_index() << "not found";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -650,11 +650,11 @@ void SpotifyClient::AddTracksToPlaylist(
|
||||
void SpotifyClient::RemoveTracksFromPlaylist(
|
||||
const pb::spotify::RemoveTracksFromPlaylistRequest& req) {
|
||||
// Get the playlist we want to update
|
||||
int playlist_index = req.playlist_index();
|
||||
sp_playlist* playlist =
|
||||
GetPlaylist(pb::spotify::UserPlaylist, playlist_index);
|
||||
GetPlaylist(req.playlist_type(), req.playlist_index());
|
||||
if (!playlist) {
|
||||
qLog(Error) << "Playlist " << playlist_index << "not found";
|
||||
qLog(Error) << "Playlist " << req.playlist_type() << "," <<
|
||||
req.playlist_index() << "not found";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -664,6 +664,15 @@ void SpotifyClient::RemoveTracksFromPlaylist(
|
||||
tracks_indices_array[i] = req.track_index(i);
|
||||
}
|
||||
|
||||
// WTF: sp_playlist_remove_tracks indexes start from the end for starred
|
||||
// playlist, not from the beginning like other playlists: reverse them
|
||||
if (req.playlist_type() == pb::spotify::Starred) {
|
||||
int num_tracks = sp_playlist_num_tracks(playlist);
|
||||
for (int i = 0; i < req.track_index_size(); i++) {
|
||||
tracks_indices_array[i] = num_tracks - tracks_indices_array[i] - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sp_playlist_remove_tracks(playlist, tracks_indices_array.get(),
|
||||
req.track_index_size()) != SP_ERROR_OK) {
|
||||
qLog(Error) << "Error when removing tracks!";
|
||||
|
@ -193,13 +193,15 @@ message PauseRequest {
|
||||
}
|
||||
|
||||
message AddTracksToPlaylistRequest {
|
||||
required int64 playlist_index = 1;
|
||||
repeated string track_uri = 2;
|
||||
required PlaylistType playlist_type = 1;
|
||||
optional int64 playlist_index = 2; // Used if playlist_index == UserPlaylist
|
||||
repeated string track_uri = 3;
|
||||
}
|
||||
|
||||
message RemoveTracksFromPlaylistRequest {
|
||||
required int64 playlist_index = 1;
|
||||
repeated int64 track_index = 2;
|
||||
required PlaylistType playlist_type = 1;
|
||||
optional int64 playlist_index = 2; // Used if playlist_index == UserPlaylist
|
||||
repeated int64 track_index = 3;
|
||||
}
|
||||
|
||||
// NEXT_ID: 25
|
||||
|
@ -210,11 +210,22 @@ void SpotifyServer::LoadUserPlaylist(int index) {
|
||||
LoadPlaylist(pb::spotify::UserPlaylist, index);
|
||||
}
|
||||
|
||||
void SpotifyServer::AddSongsToPlaylist(int playlist_index,
|
||||
const QList<QUrl>& songs_urls) {
|
||||
void SpotifyServer::AddSongsToStarred(const QList<QUrl>& songs_urls) {
|
||||
AddSongsToPlaylist(pb::spotify::Starred, songs_urls);
|
||||
}
|
||||
|
||||
void SpotifyServer::AddSongsToUserPlaylist(int playlist_index,
|
||||
const QList<QUrl>& songs_urls) {
|
||||
AddSongsToPlaylist(pb::spotify::UserPlaylist, songs_urls, playlist_index);
|
||||
}
|
||||
|
||||
void SpotifyServer::AddSongsToPlaylist(const pb::spotify::PlaylistType playlist_type,
|
||||
const QList<QUrl>& songs_urls,
|
||||
int playlist_index) {
|
||||
pb::spotify::Message message;
|
||||
pb::spotify::AddTracksToPlaylistRequest* req =
|
||||
message.mutable_add_tracks_to_playlist();
|
||||
req->set_playlist_type(playlist_type);
|
||||
req->set_playlist_index(playlist_index);
|
||||
for (const QUrl& song_url : songs_urls) {
|
||||
req->add_track_uri(DataCommaSizeFromQString(song_url.toString()));
|
||||
@ -222,12 +233,25 @@ void SpotifyServer::AddSongsToPlaylist(int playlist_index,
|
||||
SendOrQueueMessage(message);
|
||||
}
|
||||
|
||||
void SpotifyServer::RemoveSongsFromStarred(const QList<int>& songs_indices_to_remove) {
|
||||
RemoveSongsFromPlaylist(pb::spotify::Starred, songs_indices_to_remove);
|
||||
}
|
||||
|
||||
void SpotifyServer::RemoveSongsFromUserPlaylist(int playlist_index,
|
||||
const QList<int>& songs_indices_to_remove) {
|
||||
RemoveSongsFromPlaylist(pb::spotify::UserPlaylist, songs_indices_to_remove, playlist_index);
|
||||
}
|
||||
|
||||
void SpotifyServer::RemoveSongsFromPlaylist(
|
||||
int playlist_index, const QList<int>& songs_indices_to_remove) {
|
||||
const pb::spotify::PlaylistType playlist_type,
|
||||
const QList<int>& songs_indices_to_remove, int playlist_index) {
|
||||
pb::spotify::Message message;
|
||||
pb::spotify::RemoveTracksFromPlaylistRequest* req =
|
||||
message.mutable_remove_tracks_from_playlist();
|
||||
req->set_playlist_index(playlist_index);
|
||||
req->set_playlist_type(playlist_type);
|
||||
if (playlist_type == pb::spotify::UserPlaylist) {
|
||||
req->set_playlist_index(playlist_index);
|
||||
}
|
||||
for (int song_index : songs_indices_to_remove) {
|
||||
req->add_track_index(song_index);
|
||||
}
|
||||
|
@ -47,9 +47,11 @@ class SpotifyServer : public AbstractMessageHandler<pb::spotify::Message> {
|
||||
void SyncInbox();
|
||||
void LoadUserPlaylist(int index);
|
||||
void SyncUserPlaylist(int index);
|
||||
void AddSongsToPlaylist(int playlist_index, const QList<QUrl>& songs_urls);
|
||||
void RemoveSongsFromPlaylist(int playlist_index,
|
||||
const QList<int>& songs_indices_to_remove);
|
||||
void AddSongsToStarred(const QList<QUrl>& songs_urls);
|
||||
void AddSongsToUserPlaylist(int playlist_index, const QList<QUrl>& songs_urls);
|
||||
void RemoveSongsFromUserPlaylist(int playlist_index,
|
||||
const QList<int>& songs_indices_to_remove);
|
||||
void RemoveSongsFromStarred(const QList<int>& songs_indices_to_remove);
|
||||
void StartPlaybackLater(const QString& uri, quint16 port);
|
||||
void Search(const QString& text, int limit, int limit_album = 0);
|
||||
void LoadImage(const QString& id);
|
||||
@ -89,6 +91,14 @@ class SpotifyServer : public AbstractMessageHandler<pb::spotify::Message> {
|
||||
private:
|
||||
void LoadPlaylist(pb::spotify::PlaylistType type, int index = -1);
|
||||
void SyncPlaylist(pb::spotify::PlaylistType type, int index, bool offline);
|
||||
void AddSongsToPlaylist(const pb::spotify::PlaylistType playlist_type,
|
||||
const QList<QUrl>& songs_urls,
|
||||
// Used iff type is user_playlist
|
||||
int playlist_index = -1);
|
||||
void RemoveSongsFromPlaylist(const pb::spotify::PlaylistType playlist_type,
|
||||
const QList<int>& songs_indices_to_remove,
|
||||
// Used iff type is user_playlist
|
||||
int playlist_index = -1);
|
||||
void SendOrQueueMessage(const pb::spotify::Message& message);
|
||||
|
||||
QTcpServer* server_;
|
||||
|
@ -374,15 +374,24 @@ void SpotifyService::InstallBlob() {
|
||||
|
||||
void SpotifyService::BlobDownloadFinished() { EnsureServerCreated(); }
|
||||
|
||||
void SpotifyService::AddCurrentSongToPlaylist(QAction* action) {
|
||||
void SpotifyService::AddCurrentSongToUserPlaylist(QAction* action) {
|
||||
int playlist_index = action->data().toInt();
|
||||
AddSongsToPlaylist(playlist_index, QList<QUrl>() << current_song_url_);
|
||||
AddSongsToUserPlaylist(playlist_index, QList<QUrl>() << current_song_url_);
|
||||
}
|
||||
|
||||
void SpotifyService::AddSongsToPlaylist(int playlist_index,
|
||||
void SpotifyService::AddSongsToUserPlaylist(int playlist_index,
|
||||
const QList<QUrl>& songs_urls) {
|
||||
EnsureServerCreated();
|
||||
server_->AddSongsToPlaylist(playlist_index, songs_urls);
|
||||
server_->AddSongsToUserPlaylist(playlist_index, songs_urls);
|
||||
}
|
||||
|
||||
void SpotifyService::AddCurrentSongToStarredPlaylist() {
|
||||
AddSongsToStarred(QList<QUrl>() << current_song_url_);
|
||||
}
|
||||
|
||||
void SpotifyService::AddSongsToStarred(const QList<QUrl>& songs_urls) {
|
||||
EnsureMenuCreated();
|
||||
server_->AddSongsToStarred(songs_urls);
|
||||
}
|
||||
|
||||
void SpotifyService::PlaylistsUpdated(const pb::spotify::Playlists& response) {
|
||||
@ -407,6 +416,7 @@ void SpotifyService::PlaylistsUpdated(const pb::spotify::Playlists& response) {
|
||||
starred_->setData(true, InternetModel::Role_CanLazyLoad);
|
||||
starred_->setData(InternetModel::PlayBehaviour_MultipleItems,
|
||||
InternetModel::Role_PlayBehaviour);
|
||||
starred_->setData(true, InternetModel::Role_CanBeModified);
|
||||
|
||||
inbox_ = new QStandardItem(IconLoader::Load("mail-message"), tr("Inbox"));
|
||||
inbox_->setData(Type_InboxPlaylist, InternetModel::Role_Type);
|
||||
@ -424,6 +434,12 @@ void SpotifyService::PlaylistsUpdated(const pb::spotify::Playlists& response) {
|
||||
root_->appendRow(toplist_);
|
||||
root_->appendRow(starred_);
|
||||
root_->appendRow(inbox_);
|
||||
} else {
|
||||
// Always reset starred playlist
|
||||
// TODO: might be improved by including starred playlist in the response,
|
||||
// and reloading it only when needed, like other playlists.
|
||||
starred_->removeRows(0, starred_->rowCount());
|
||||
LazyPopulate(starred_);
|
||||
}
|
||||
|
||||
// Don't do anything if the playlists haven't changed since last time.
|
||||
@ -589,6 +605,12 @@ QList<QAction*> SpotifyService::playlistitem_actions(const Song& song) {
|
||||
delete action;
|
||||
}
|
||||
|
||||
QAction* add_to_starred = new QAction(QIcon(":/star-on.png"),
|
||||
tr("Add to Spotify starred"), this);
|
||||
connect(add_to_starred, SIGNAL(triggered()),
|
||||
SLOT(AddCurrentSongToStarredPlaylist()));
|
||||
playlistitem_actions_.append(add_to_starred);
|
||||
|
||||
// Create a menu with 'add to playlist' actions for each Spotify playlist
|
||||
QAction* add_to_playlists = new QAction(IconLoader::Load("list-add"),
|
||||
tr("Add to Spotify playlists"), this);
|
||||
@ -602,7 +624,7 @@ QList<QAction*> SpotifyService::playlistitem_actions(const Song& song) {
|
||||
playlists_menu->addAction(add_to_playlist);
|
||||
}
|
||||
connect(playlists_menu, SIGNAL(triggered(QAction*)),
|
||||
SLOT(AddCurrentSongToPlaylist(QAction*)));
|
||||
SLOT(AddCurrentSongToUserPlaylist(QAction*)));
|
||||
add_to_playlists->setMenu(playlists_menu);
|
||||
playlistitem_actions_.append(add_to_playlists);
|
||||
|
||||
@ -823,7 +845,7 @@ void SpotifyService::DropMimeData(const QMimeData* data,
|
||||
}
|
||||
if (!q_playlist_index.isValid()) return;
|
||||
|
||||
AddSongsToPlaylist(q_playlist_index.toInt(), data->urls());
|
||||
AddSongsToUserPlaylist(q_playlist_index.toInt(), data->urls());
|
||||
}
|
||||
|
||||
void SpotifyService::LoadImage(const QString& id) {
|
||||
@ -885,10 +907,16 @@ void SpotifyService::ShowConfig() {
|
||||
void SpotifyService::RemoveCurrentFromPlaylist() {
|
||||
const QModelIndexList& indexes(model()->selected_indexes());
|
||||
QMap<int, QList<int>> playlists_songs_indices;
|
||||
QList<int> starred_songs_indices;
|
||||
|
||||
for (const QModelIndex& index : indexes) {
|
||||
if (index.parent().data(InternetModel::Role_Type).toInt() !=
|
||||
bool is_starred = false;
|
||||
if (index.parent().data(InternetModel::Role_Type).toInt() ==
|
||||
Type_StarredPlaylist) {
|
||||
is_starred = true;
|
||||
} else if (index.parent().data(InternetModel::Role_Type).toInt() !=
|
||||
InternetModel::Type_UserPlaylist) {
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index.data(InternetModel::Role_Type).toInt() !=
|
||||
@ -896,21 +924,33 @@ void SpotifyService::RemoveCurrentFromPlaylist() {
|
||||
continue;
|
||||
}
|
||||
|
||||
int playlist_index = index.parent().data(Role_UserPlaylistIndex).toInt();
|
||||
int song_index = index.row();
|
||||
playlists_songs_indices[playlist_index] << song_index;
|
||||
if (is_starred) {
|
||||
starred_songs_indices << song_index;
|
||||
} else {
|
||||
int playlist_index = index.parent().data(Role_UserPlaylistIndex).toInt();
|
||||
playlists_songs_indices[playlist_index] << song_index;
|
||||
}
|
||||
}
|
||||
|
||||
for (QMap<int, QList<int>>::const_iterator it =
|
||||
playlists_songs_indices.constBegin();
|
||||
it != playlists_songs_indices.constEnd(); ++it) {
|
||||
RemoveSongsFromPlaylist(it.key(), it.value());
|
||||
RemoveSongsFromUserPlaylist(it.key(), it.value());
|
||||
}
|
||||
if (!starred_songs_indices.isEmpty()) {
|
||||
RemoveSongsFromStarred(starred_songs_indices);
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifyService::RemoveSongsFromPlaylist(
|
||||
void SpotifyService::RemoveSongsFromUserPlaylist(
|
||||
int playlist_index, const QList<int>& songs_indices_to_remove) {
|
||||
server_->RemoveSongsFromPlaylist(playlist_index, songs_indices_to_remove);
|
||||
server_->RemoveSongsFromUserPlaylist(playlist_index, songs_indices_to_remove);
|
||||
}
|
||||
|
||||
void SpotifyService::RemoveSongsFromStarred(
|
||||
const QList<int>& songs_indices_to_remove) {
|
||||
server_->RemoveSongsFromStarred(songs_indices_to_remove);
|
||||
}
|
||||
|
||||
void SpotifyService::Logout() {
|
||||
|
@ -112,7 +112,8 @@ class SpotifyService : public InternetService {
|
||||
const google::protobuf::RepeatedPtrField<pb::spotify::Track>& tracks);
|
||||
void FillPlaylist(QStandardItem* item,
|
||||
const pb::spotify::LoadPlaylistResponse& response);
|
||||
void AddSongsToPlaylist(int playlist_index, const QList<QUrl>& songs_urls);
|
||||
void AddSongsToUserPlaylist(int playlist_index, const QList<QUrl>& songs_urls);
|
||||
void AddSongsToStarred(const QList<QUrl>& songs_urls);
|
||||
void EnsureMenuCreated();
|
||||
// Create a new "show config" action. The caller is responsible for deleting
|
||||
// the pointer (or adding it to menu or anything else that will take ownership
|
||||
@ -129,9 +130,11 @@ class SpotifyService : public InternetService {
|
||||
void BlobProcessError(QProcess::ProcessError error);
|
||||
void LoginCompleted(bool success, const QString& error,
|
||||
pb::spotify::LoginResponse_Error error_code);
|
||||
void AddCurrentSongToPlaylist(QAction* action);
|
||||
void RemoveSongsFromPlaylist(int playlist_index,
|
||||
void AddCurrentSongToUserPlaylist(QAction* action);
|
||||
void AddCurrentSongToStarredPlaylist();
|
||||
void RemoveSongsFromUserPlaylist(int playlist_index,
|
||||
const QList<int>& songs_indices_to_remove);
|
||||
void RemoveSongsFromStarred(const QList<int>& songs_indices_to_remove);
|
||||
void PlaylistsUpdated(const pb::spotify::Playlists& response);
|
||||
void InboxLoaded(const pb::spotify::LoadPlaylistResponse& response);
|
||||
void StarredLoaded(const pb::spotify::LoadPlaylistResponse& response);
|
||||
|
Loading…
x
Reference in New Issue
Block a user