Add the ability to remove tracks from Spotify playlists

This commit is contained in:
Arnaud Bienner 2014-09-28 02:00:32 +02:00
parent af11f5551d
commit f81fa2d119
7 changed files with 119 additions and 8 deletions

View File

@ -298,6 +298,8 @@ void SpotifyClient::MessageArrived(const pb::spotify::Message& message) {
SetPaused(message.pause_request());
} else if (message.has_add_tracks_to_playlist()) {
AddTracksToPlaylist(message.add_tracks_to_playlist());
} else if (message.has_remove_tracks_from_playlist()) {
RemoveTracksFromPlaylist(message.remove_tracks_from_playlist());
}
}
@ -639,6 +641,31 @@ 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);
if (!playlist) {
qLog(Error) << "Playlist " << playlist_index << "not found";
return;
}
// Get the position of the tracks we want to remove
std::unique_ptr<int[]> tracks_indices_array (new int[req.track_index_size()]);
for (int i = 0; i < req.track_index_size(); ++i) {
tracks_indices_array[i] = req.track_index(i);
}
if (sp_playlist_remove_tracks(playlist, tracks_indices_array.get(),
req.track_index_size()) != SP_ERROR_OK) {
qLog(Error) << "Error when removing tracks!";
}
}
void SpotifyClient::ConvertTrack(sp_track* track, pb::spotify::Track* pb) {
sp_album* album = sp_track_album(track);

View File

@ -124,6 +124,7 @@ class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
void LoadPlaylist(const pb::spotify::LoadPlaylistRequest& req);
void SyncPlaylist(const pb::spotify::SyncPlaylistRequest& req);
void AddTracksToPlaylist(const pb::spotify::AddTracksToPlaylistRequest& req);
void RemoveTracksFromPlaylist(const pb::spotify::RemoveTracksFromPlaylistRequest& req);
void StartPlayback(const pb::spotify::PlaybackRequest& req);
void Seek(qint64 offset_nsec);
void LoadImage(const QString& id_b64);

View File

@ -199,7 +199,12 @@ message AddTracksToPlaylistRequest {
repeated string track_uri = 2;
}
// NEXT_ID: 24
message RemoveTracksFromPlaylistRequest {
required int64 playlist_index = 1;
repeated int64 track_index = 2;
}
// NEXT_ID: 25
message Message {
// Not currently used
optional int32 id = 18;
@ -226,4 +231,5 @@ message Message {
optional PauseRequest pause_request = 21;
optional SeekCompleted seek_completed = 22;
optional AddTracksToPlaylistRequest add_tracks_to_playlist = 23;
optional RemoveTracksFromPlaylistRequest remove_tracks_from_playlist = 24;
}

View File

@ -219,6 +219,18 @@ void SpotifyServer::AddSongsToPlaylist(int playlist_index,
SendOrQueueMessage(message);
}
void SpotifyServer::RemoveSongsFromPlaylist(
int playlist_index, const QList<int>& songs_indices_to_remove) {
pb::spotify::Message message;
pb::spotify::RemoveTracksFromPlaylistRequest* req =
message.mutable_remove_tracks_from_playlist();
req->set_playlist_index(playlist_index);
for (int song_index : songs_indices_to_remove) {
req->add_track_index(song_index);
}
SendOrQueueMessage(message);
}
void SpotifyServer::StartPlaybackLater(const QString& uri, quint16 port) {
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));

View File

@ -44,6 +44,8 @@ class SpotifyServer : public AbstractMessageHandler<pb::spotify::Message> {
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 StartPlaybackLater(const QString& uri, quint16 port);
void Search(const QString& text, int limit, int limit_album = 0);
void LoadImage(const QString& id);

View File

@ -53,6 +53,10 @@ SpotifyService::SpotifyService(Application* app, InternetModel* parent)
toplist_(nullptr),
login_task_id_(0),
context_menu_(nullptr),
playlist_context_menu_(nullptr),
song_context_menu_(nullptr),
playlist_sync_action_(nullptr),
remove_from_playlist_(nullptr),
search_box_(new SearchBoxWidget(this)),
search_delay_(new QTimer(this)),
login_state_(LoginState_OtherError),
@ -590,9 +594,7 @@ void SpotifyService::EnsureMenuCreated() {
if (context_menu_) return;
context_menu_ = new QMenu;
context_menu_->addAction(IconLoader::Load("configure"),
tr("Configure Spotify..."), this,
SLOT(ShowConfig()));
context_menu_->addAction(GetNewShowConfigAction());
playlist_context_menu_ = new QMenu;
playlist_context_menu_->addActions(GetPlaylistActions());
@ -601,9 +603,15 @@ void SpotifyService::EnsureMenuCreated() {
IconLoader::Load("view-refresh"), tr("Make playlist available offline"),
this, SLOT(SyncPlaylist()));
playlist_context_menu_->addSeparator();
playlist_context_menu_->addAction(IconLoader::Load("configure"),
tr("Configure Spotify..."), this,
SLOT(ShowConfig()));
playlist_context_menu_->addAction(GetNewShowConfigAction());
song_context_menu_ = new QMenu;
remove_from_playlist_ = song_context_menu_->addAction(
IconLoader::Load("list-remove"),
tr("Remove from playlist"), this,
SLOT(RemoveCurrentFromPlaylist()));
song_context_menu_->addAction(GetNewShowConfigAction());
}
void SpotifyService::ClearSearchResults() {
@ -728,6 +736,14 @@ void SpotifyService::ShowContextMenu(const QPoint& global_pos) {
playlist_sync_action_->setData(qVariantFromValue(item));
playlist_context_menu_->popup(global_pos);
return;
} else if (type == InternetModel::Type_Track) {
// Is this track contained in a playlist we can modify?
bool is_playlist_modifiable = item->parent() &&
item->parent()->data(Role_UserPlaylistIsMine).toBool();
remove_from_playlist_->setVisible(is_playlist_modifiable);
song_context_menu_->popup(global_pos);
return;
}
}
@ -791,10 +807,49 @@ void SpotifyService::SyncPlaylistProgress(
}
}
QAction* SpotifyService::GetNewShowConfigAction() {
QAction* action = new QAction(
IconLoader::Load("configure"),
tr("Configure Spotify..."), this);
connect(action, SIGNAL(triggered()), this, SLOT(ShowConfig()));
return action;
}
void SpotifyService::ShowConfig() {
app_->OpenSettingsDialogAtPage(SettingsDialog::Page_Spotify);
}
void SpotifyService::RemoveCurrentFromPlaylist() {
const QModelIndexList& indexes(model()->selected_indexes());
QMap<int, QList<int> > playlists_songs_indices;
for (const QModelIndex& index : indexes) {
if (index.parent().data(InternetModel::Role_Type).toInt() !=
InternetModel::Type_UserPlaylist) {
continue;
}
if (index.data(InternetModel::Role_Type).toInt() != InternetModel::Type_Track) {
continue;
}
int playlist_index = index.parent().data(Role_UserPlaylistIndex).toInt();
int song_index = index.row();
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());
}
}
void SpotifyService::RemoveSongsFromPlaylist(
int playlist_index, const QList<int>& songs_indices_to_remove) {
server_->RemoveSongsFromPlaylist(playlist_index, songs_indices_to_remove);
}
void SpotifyService::Logout() {
delete server_;
delete blob_process_;

View File

@ -25,7 +25,6 @@ class SpotifyService : public InternetService {
Type_SearchResults = InternetModel::TypeCount,
Type_StarredPlaylist,
Type_InboxPlaylist,
Type_Track,
Type_Toplist,
};
@ -84,6 +83,7 @@ signals:
public slots:
void Search(const QString& text, bool now = false);
void ShowConfig();
void RemoveCurrentFromPlaylist();
private:
void StartBlobProcess();
@ -94,6 +94,10 @@ signals:
const pb::spotify::LoadPlaylistResponse& response);
void AddSongsToPlaylist(int playlist_index, 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
// of it)
QAction* GetNewShowConfigAction();
void ClearSearchResults();
QStandardItem* PlaylistBySpotifyIndex(int index) const;
@ -106,6 +110,8 @@ signals:
void LoginCompleted(bool success, const QString& error,
pb::spotify::LoginResponse_Error error_code);
void AddCurrentSongToPlaylist(QAction* action);
void RemoveSongsFromPlaylist(int playlist_index,
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);
@ -139,8 +145,10 @@ signals:
QMenu* context_menu_;
QMenu* playlist_context_menu_;
QMenu* song_context_menu_;
QAction* playlist_sync_action_;
QList<QAction*> playlistitem_actions_;
QAction* remove_from_playlist_;
QUrl current_song_url_;
SearchBoxWidget* search_box_;