From e5419dae2da385f8d06cb71796b8d9cc72b09acf Mon Sep 17 00:00:00 2001 From: Thomas Storey Date: Wed, 1 Jul 2020 14:52:39 -0400 Subject: [PATCH] add methods and api usage to delete track from playlist (#211) * wip: add methods and api usage to delete track from playlist * enh: add ability to remove track from playlist with immediate visual feedback * minor cosmetic changes Co-authored-by: Henrik Friedrichsen --- src/playlist.rs | 10 ++++++++++ src/spotify.rs | 23 +++++++++++++++++++++++ src/ui/listview.rs | 5 +++++ src/ui/playlist.rs | 26 ++++++++++++++++++++++++-- 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/playlist.rs b/src/playlist.rs index 8b46dc9..46f9c25 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -51,6 +51,16 @@ impl Playlist { self.tracks = Some(collected_tracks); } + + pub fn delete_tracks(&mut self, track_pos_pairs: &[(Track, usize)], spotify: Arc) { + if spotify.delete_tracks(&self.id, track_pos_pairs) { + if let Some(tracks) = &mut self.tracks { + for (_track, pos) in track_pos_pairs { + tracks.remove(*pos); + } + } + } + } } impl From<&SimplifiedPlaylist> for Playlist { diff --git a/src/spotify.rs b/src/spotify.rs index 5bf0f7d..580852a 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -24,6 +24,8 @@ use rspotify::spotify::model::search::{ use rspotify::spotify::model::track::{FullTrack, SavedTrack}; use rspotify::spotify::model::user::PrivateUser; +use serde_json::json; + use failure::Error; use futures_01::future::Future as v01_Future; @@ -566,6 +568,27 @@ impl Spotify { .is_some() } + pub fn delete_tracks(&self, playlist_id: &str, track_pos_pairs: &[(Track, usize)]) -> bool { + let mut tracks = Vec::new(); + for (track, pos) in track_pos_pairs { + let track_occurrence = json!({ + "uri": format!("spotify:track:{}", track.id.clone().unwrap()), + "positions": [pos] + }); + let track_occurrence_object = track_occurrence.as_object(); + tracks.push(track_occurrence_object.unwrap().clone()); + } + self.api_with_retry(|api| { + api.user_playlist_remove_specific_occurrenes_of_tracks( + self.user.as_ref().unwrap(), + playlist_id, + tracks.clone(), + None, + ) + }) + .is_some() + } + pub fn overwrite_playlist(&self, id: &str, tracks: &[Track]) { // extract only track IDs let mut tracks: Vec = tracks diff --git a/src/ui/listview.rs b/src/ui/listview.rs index 4d7c54d..9a1ab74 100644 --- a/src/ui/listview.rs +++ b/src/ui/listview.rs @@ -154,6 +154,11 @@ impl ListView { false } } + + pub fn remove(&self, index: usize) { + let mut c = self.content.write().unwrap(); + c.remove(index); + } } impl View for ListView { diff --git a/src/ui/playlist.rs b/src/ui/playlist.rs index 573896a..ece9a15 100644 --- a/src/ui/playlist.rs +++ b/src/ui/playlist.rs @@ -8,6 +8,7 @@ use crate::commands::CommandResult; use crate::library::Library; use crate::playlist::Playlist; use crate::queue::Queue; +use crate::spotify::Spotify; use crate::track::Track; use crate::traits::ViewExt; use crate::ui::listview::ListView; @@ -15,12 +16,12 @@ use crate::ui::listview::ListView; pub struct PlaylistView { playlist: Playlist, list: ListView, + spotify: Arc, } impl PlaylistView { pub fn new(queue: Arc, library: Arc, playlist: &Playlist) -> Self { let mut playlist = playlist.clone(); - playlist.load_tracks(queue.get_spotify()); let tracks = if let Some(t) = playlist.tracks.as_ref() { @@ -29,9 +30,14 @@ impl PlaylistView { Vec::new() }; + let spotify = queue.get_spotify(); let list = ListView::new(Arc::new(RwLock::new(tracks)), queue, library); - Self { playlist, list } + Self { + playlist, + list, + spotify, + } } } @@ -45,6 +51,22 @@ impl ViewExt for PlaylistView { } fn on_command(&mut self, s: &mut Cursive, cmd: &Command) -> Result { + if let Command::Delete = cmd { + let pos = self.list.get_selected_index(); + let tracks = if let Some(t) = self.playlist.tracks.as_ref() { + t.clone() + } else { + Vec::new() + }; + let track = tracks.get(pos); + if let Some(t) = track { + self.playlist + .delete_tracks(&[(t.clone(), pos)], self.spotify.clone()); + self.list.remove(pos); + } + return Ok(CommandResult::Consumed(None)); + } + self.list.on_command(s, cmd) } }