implement playlist update on demand + prune stale playlists
This commit is contained in:
@@ -42,6 +42,7 @@ have them configurable.
|
|||||||
* Tracks and playlists can be played using `Return` and queued using `Space`
|
* Tracks and playlists can be played using `Return` and queued using `Space`
|
||||||
* `Shift-p` toggles playback of a track
|
* `Shift-p` toggles playback of a track
|
||||||
* `Shift-s` stops a track
|
* `Shift-s` stops a track
|
||||||
|
* `Shift-r` updates the playlist cache
|
||||||
* `<` and `>` play the previous or next track, respectively
|
* `<` and `>` play the previous or next track, respectively
|
||||||
* `q` quits ncspot
|
* `q` quits ncspot
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||||||
use cursive::event::{Event, Key};
|
use cursive::event::{Event, Key};
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
|
||||||
use playlists::Playlist;
|
use playlists::{Playlist, Playlists};
|
||||||
use queue::Queue;
|
use queue::Queue;
|
||||||
use spotify::Spotify;
|
use spotify::Spotify;
|
||||||
use track::Track;
|
use track::Track;
|
||||||
@@ -39,7 +39,12 @@ impl CommandManager {
|
|||||||
self.commands.insert(name, cb);
|
self.commands.insert(name, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_all(&mut self, spotify: Arc<Spotify>, queue: Arc<Queue>) {
|
pub fn register_all(
|
||||||
|
&mut self,
|
||||||
|
spotify: Arc<Spotify>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
playlists: Arc<Playlists>,
|
||||||
|
) {
|
||||||
self.register(
|
self.register(
|
||||||
"quit",
|
"quit",
|
||||||
vec!["q", "x"],
|
vec!["q", "x"],
|
||||||
@@ -120,10 +125,17 @@ impl CommandManager {
|
|||||||
self.register(
|
self.register(
|
||||||
"playlists",
|
"playlists",
|
||||||
vec!["lists"],
|
vec!["lists"],
|
||||||
Box::new(move |s, _args| {
|
Box::new(move |s, args| {
|
||||||
s.call_on_id("main", |v: &mut Layout| {
|
if let Some(arg) = args.get(0) {
|
||||||
v.set_view("playlists");
|
if arg == "update" {
|
||||||
});
|
playlists.fetch_playlists();
|
||||||
|
playlists.save_cache();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.call_on_id("main", |v: &mut Layout| {
|
||||||
|
v.set_view("playlists");
|
||||||
|
});
|
||||||
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -342,6 +354,7 @@ impl CommandManager {
|
|||||||
|
|
||||||
kb.insert("q".into(), "quit".into());
|
kb.insert("q".into(), "quit".into());
|
||||||
kb.insert("P".into(), "toggle".into());
|
kb.insert("P".into(), "toggle".into());
|
||||||
|
kb.insert("R".into(), "playlists update".into());
|
||||||
kb.insert("S".into(), "stop".into());
|
kb.insert("S".into(), "stop".into());
|
||||||
kb.insert("<".into(), "previous".into());
|
kb.insert("<".into(), "previous".into());
|
||||||
kb.insert(">".into(), "next".into());
|
kb.insert(">".into(), "next".into());
|
||||||
|
|||||||
18
src/main.rs
18
src/main.rs
@@ -29,7 +29,7 @@ use std::process;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use clap::{Arg, App};
|
use clap::{App, Arg};
|
||||||
use cursive::traits::Identifiable;
|
use cursive::traits::Identifiable;
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
|
||||||
@@ -80,12 +80,14 @@ fn main() {
|
|||||||
.version("0.1.0")
|
.version("0.1.0")
|
||||||
.author("Henrik Friedrichsen <henrik@affekt.org>")
|
.author("Henrik Friedrichsen <henrik@affekt.org>")
|
||||||
.about("cross-platform ncurses Spotify client")
|
.about("cross-platform ncurses Spotify client")
|
||||||
.arg(Arg::with_name("debug")
|
.arg(
|
||||||
.short("d")
|
Arg::with_name("debug")
|
||||||
.long("debug")
|
.short("d")
|
||||||
.value_name("FILE")
|
.long("debug")
|
||||||
.help("Enable debug logging to the specified file")
|
.value_name("FILE")
|
||||||
.takes_value(true))
|
.help("Enable debug logging to the specified file")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
if let Some(filename) = matches.value_of("debug") {
|
if let Some(filename) = matches.value_of("debug") {
|
||||||
@@ -181,7 +183,7 @@ fn main() {
|
|||||||
cursive.add_fullscreen_layer(layout.with_id("main"));
|
cursive.add_fullscreen_layer(layout.with_id("main"));
|
||||||
|
|
||||||
let mut cmd_manager = CommandManager::new();
|
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);
|
let cmd_manager = Arc::new(cmd_manager);
|
||||||
CommandManager::register_keybindings(cmd_manager.clone(), &mut cursive, cfg.keybindings);
|
CommandManager::register_keybindings(cmd_manager.clone(), &mut cursive, cfg.keybindings);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use spotify::Spotify;
|
|||||||
use track::Track;
|
use track::Track;
|
||||||
use traits::ListItem;
|
use traits::ListItem;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Playlist {
|
pub struct Playlist {
|
||||||
pub meta: SimplifiedPlaylist,
|
pub meta: SimplifiedPlaylist,
|
||||||
pub tracks: Vec<Track>,
|
pub tracks: Vec<Track>,
|
||||||
@@ -144,9 +144,16 @@ impl Playlists {
|
|||||||
|
|
||||||
pub fn fetch_playlists(&self) {
|
pub fn fetch_playlists(&self) {
|
||||||
debug!("loading playlists");
|
debug!("loading playlists");
|
||||||
|
let mut stale_lists = self.store.read().unwrap().clone();
|
||||||
|
|
||||||
let mut lists_result = self.spotify.current_user_playlist(50, 0);
|
let mut lists_result = self.spotify.current_user_playlist(50, 0);
|
||||||
while let Some(ref lists) = lists_result.clone() {
|
while let Some(ref lists) = lists_result.clone() {
|
||||||
for remote in &lists.items {
|
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) {
|
if self.needs_download(remote) {
|
||||||
info!("updating playlist {}", remote.name);
|
info!("updating playlist {}", remote.name);
|
||||||
let playlist = Self::process_playlist(&remote, &self.spotify);
|
let playlist = Self::process_playlist(&remote, &self.spotify);
|
||||||
@@ -166,5 +173,21 @@ impl Playlists {
|
|||||||
None => None,
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ impl Spotify {
|
|||||||
fn create_session(core: &mut Core, credentials: Credentials) -> Session {
|
fn create_session(core: &mut Core, credentials: Credentials) -> Session {
|
||||||
let session_config = SessionConfig::default();
|
let session_config = SessionConfig::default();
|
||||||
let handle = core.handle();
|
let handle = core.handle();
|
||||||
|
debug!("opening spotify session");
|
||||||
core.run(Session::connect(session_config, credentials, None, handle))
|
core.run(Session::connect(session_config, credentials, None, handle))
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
Reference in New Issue
Block a user