From 53255a48af5f1f9bbb6c67dd1ee2fb21015562e7 Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Sat, 23 Mar 2019 18:37:15 +0100 Subject: [PATCH] implement playlist update on demand + prune stale playlists --- README.md | 1 + src/commands.rs | 25 +++++++++++++++++++------ src/main.rs | 18 ++++++++++-------- src/playlists.rs | 25 ++++++++++++++++++++++++- src/spotify.rs | 1 + 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index dfd333c..ef73e36 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ have them configurable. * Tracks and playlists can be played using `Return` and queued using `Space` * `Shift-p` toggles playback of a track * `Shift-s` stops a track +* `Shift-r` updates the playlist cache * `<` and `>` play the previous or next track, respectively * `q` quits ncspot diff --git a/src/commands.rs b/src/commands.rs index 37de3f5..402e6c3 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use cursive::event::{Event, Key}; use cursive::Cursive; -use playlists::Playlist; +use playlists::{Playlist, Playlists}; use queue::Queue; use spotify::Spotify; use track::Track; @@ -39,7 +39,12 @@ impl CommandManager { self.commands.insert(name, cb); } - pub fn register_all(&mut self, spotify: Arc, queue: Arc) { + pub fn register_all( + &mut self, + spotify: Arc, + queue: Arc, + playlists: Arc, + ) { self.register( "quit", vec!["q", "x"], @@ -120,10 +125,17 @@ impl CommandManager { self.register( "playlists", vec!["lists"], - Box::new(move |s, _args| { - s.call_on_id("main", |v: &mut Layout| { - v.set_view("playlists"); - }); + Box::new(move |s, args| { + if let Some(arg) = args.get(0) { + if arg == "update" { + playlists.fetch_playlists(); + playlists.save_cache(); + } + } else { + s.call_on_id("main", |v: &mut Layout| { + v.set_view("playlists"); + }); + } Ok(None) }), ); @@ -342,6 +354,7 @@ impl CommandManager { kb.insert("q".into(), "quit".into()); kb.insert("P".into(), "toggle".into()); + kb.insert("R".into(), "playlists update".into()); kb.insert("S".into(), "stop".into()); kb.insert("<".into(), "previous".into()); kb.insert(">".into(), "next".into()); diff --git a/src/main.rs b/src/main.rs index 996b42c..7571208 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ use std::process; use std::sync::Arc; use std::thread; -use clap::{Arg, App}; +use clap::{App, Arg}; use cursive::traits::Identifiable; use cursive::Cursive; @@ -80,12 +80,14 @@ fn main() { .version("0.1.0") .author("Henrik Friedrichsen ") .about("cross-platform ncurses Spotify client") - .arg(Arg::with_name("debug") - .short("d") - .long("debug") - .value_name("FILE") - .help("Enable debug logging to the specified file") - .takes_value(true)) + .arg( + Arg::with_name("debug") + .short("d") + .long("debug") + .value_name("FILE") + .help("Enable debug logging to the specified file") + .takes_value(true), + ) .get_matches(); if let Some(filename) = matches.value_of("debug") { @@ -181,7 +183,7 @@ fn main() { cursive.add_fullscreen_layer(layout.with_id("main")); let mut cmd_manager = CommandManager::new(); - cmd_manager.register_all(spotify.clone(), queue.clone()); + cmd_manager.register_all(spotify.clone(), queue.clone(), playlists.clone()); let cmd_manager = Arc::new(cmd_manager); CommandManager::register_keybindings(cmd_manager.clone(), &mut cursive, cfg.keybindings); diff --git a/src/playlists.rs b/src/playlists.rs index df55a2f..c707928 100644 --- a/src/playlists.rs +++ b/src/playlists.rs @@ -12,7 +12,7 @@ use spotify::Spotify; use track::Track; use traits::ListItem; -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Playlist { pub meta: SimplifiedPlaylist, pub tracks: Vec, @@ -144,9 +144,16 @@ impl Playlists { pub fn fetch_playlists(&self) { debug!("loading playlists"); + let mut stale_lists = self.store.read().unwrap().clone(); + let mut lists_result = self.spotify.current_user_playlist(50, 0); while let Some(ref lists) = lists_result.clone() { for remote in &lists.items { + // remove from stale playlists so we won't prune it later on + if let Some(index) = stale_lists.iter().position(|x| x.meta.id == remote.id) { + stale_lists.remove(index); + } + if self.needs_download(remote) { info!("updating playlist {}", remote.name); let playlist = Self::process_playlist(&remote, &self.spotify); @@ -166,5 +173,21 @@ impl Playlists { None => None, } } + + // remove stale playlists + for stale in stale_lists { + let index = self + .store + .read() + .unwrap() + .iter() + .position(|x| x.meta.id == stale.meta.id); + if let Some(index) = index { + debug!("removing stale list: {:?}", stale.meta.name); + self.store.write().unwrap().remove(index); + } + } + // trigger redraw + self.ev.trigger(); } } diff --git a/src/spotify.rs b/src/spotify.rs index 1dabf44..1f4a321 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -215,6 +215,7 @@ impl Spotify { fn create_session(core: &mut Core, credentials: Credentials) -> Session { let session_config = SessionConfig::default(); let handle = core.handle(); + debug!("opening spotify session"); core.run(Session::connect(session_config, credentials, None, handle)) .ok() .unwrap()