diff --git a/Cargo.toml b/Cargo.toml index 6b1c0126..134a641c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ maintenance = { status = "experimental" } [dependencies] crossbeam-channel = "0.3.8" +directories = "1.0" failure = "0.1.3" futures = "0.1" log = "0.4.0" @@ -25,7 +26,6 @@ tokio-core = "0.1" tokio-timer = "0.2" unicode-width = "0.1.5" dbus = { version = "0.6.4", optional = true } -xdg = "^2.1" [dependencies.rspotify] git = "https://github.com/hrkfdn/rspotify.git" diff --git a/src/config.rs b/src/config.rs index 7e07fd6d..6355a761 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,8 @@ use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; + +use directories::ProjectDirs; pub const CLIENT_ID: &str = "d420a117a32841c2b3474932e49fb54b"; @@ -8,3 +12,25 @@ pub struct Config { pub password: String, pub keybindings: Option>, } + +pub fn config_path() -> PathBuf { + let dirs = directories::BaseDirs::new().expect("can't determine config path"); + PathBuf::from(format!( + "{0}/ncspot", + dirs.config_dir() + .to_str() + .expect("can't convert path to string") + )) +} + +pub fn cache_path() -> PathBuf { + let proj_dirs = + ProjectDirs::from("org", "affekt", "ncspot").expect("can't determine project paths"); + let cache_dir = proj_dirs.cache_dir(); + if !cache_dir.exists() { + fs::create_dir(cache_dir).expect("can't create cache folder"); + } + let mut pb = proj_dirs.cache_dir().to_path_buf(); + pb.push("playlists.db"); + pb +} diff --git a/src/main.rs b/src/main.rs index 00273667..c1b74205 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ extern crate crossbeam_channel; #[macro_use] extern crate cursive; +extern crate directories; extern crate failure; extern crate futures; extern crate librespot; @@ -9,7 +10,6 @@ extern crate tokio; extern crate tokio_core; extern crate tokio_timer; extern crate unicode_width; -extern crate xdg; #[cfg(feature = "mpris")] extern crate dbus; @@ -22,8 +22,6 @@ extern crate toml; #[macro_use] extern crate log; -use std::env; -use std::path::PathBuf; use std::process; use std::sync::Arc; use std::thread; @@ -57,13 +55,7 @@ fn main() { // Things here may cause the process to abort; we must do them before creating curses windows // otherwise the error message will not be seen by a user - let path = match env::var_os("HOME") { - None => { - eprintln!("$HOME not set"); - process::exit(1); - } - Some(path) => PathBuf::from(format!("{0}/.config/ncspot", path.into_string().unwrap())), - }; + let path = config::config_path(); let cfg: config::Config = { let contents = std::fs::read_to_string(&path).unwrap_or_else(|_| { diff --git a/src/playlists.rs b/src/playlists.rs index f17eb029..df55a2fc 100644 --- a/src/playlists.rs +++ b/src/playlists.rs @@ -1,9 +1,11 @@ use std::iter::Iterator; use std::ops::Deref; +use std::path::PathBuf; use std::sync::{Arc, RwLock}; use rspotify::spotify::model::playlist::SimplifiedPlaylist; +use config; use events::EventManager; use queue::Queue; use spotify::Spotify; @@ -21,6 +23,7 @@ pub struct Playlists { pub store: Arc>>, ev: EventManager, spotify: Arc, + cache_path: PathBuf, } impl ListItem for Playlist { @@ -51,43 +54,38 @@ impl Playlists { store: Arc::new(RwLock::new(Vec::new())), ev: ev.clone(), spotify: spotify.clone(), + cache_path: config::cache_path(), } } pub fn load_cache(&self) { - let xdg_dirs = xdg::BaseDirectories::with_prefix("ncspot").unwrap(); - if let Ok(cache_path) = xdg_dirs.place_cache_file("playlists.db") { - if let Ok(contents) = std::fs::read_to_string(&cache_path) { - debug!( - "loading playlist cache from {}", - cache_path.to_str().unwrap() - ); - let parsed: Result, _> = serde_json::from_str(&contents); - match parsed { - Ok(cache) => { - debug!("playlist cache loaded ({} lists)", cache.len()); - let mut store = self.store.write().expect("can't writelock playlist store"); - store.clear(); - store.extend(cache); - - // force refresh of UI (if visible) - self.ev.trigger(); - } - Err(e) => { - error!("can't parse playlist cache: {}", e); - } + if let Ok(contents) = std::fs::read_to_string(&self.cache_path) { + debug!( + "loading playlist cache from {}", + self.cache_path.to_str().unwrap() + ); + let parsed: Result, _> = serde_json::from_str(&contents); + match parsed { + Ok(cache) => { + debug!("playlist cache loaded ({} lists)", cache.len()); + let mut store = self.store.write().expect("can't writelock playlist store"); + store.clear(); + store.extend(cache); + + // force refresh of UI (if visible) + self.ev.trigger(); + } + Err(e) => { + error!("can't parse playlist cache: {}", e); } } } } pub fn save_cache(&self) { - let xdg_dirs = xdg::BaseDirectories::with_prefix("ncspot").unwrap(); - if let Ok(cache_path) = xdg_dirs.place_cache_file("playlists.db") { - match serde_json::to_string(&self.store.deref()) { - Ok(contents) => std::fs::write(cache_path, contents).unwrap(), - Err(e) => error!("could not write playlist cache: {:?}", e), - } + match serde_json::to_string(&self.store.deref()) { + Ok(contents) => std::fs::write(&self.cache_path, contents).unwrap(), + Err(e) => error!("could not write playlist cache: {:?}", e), } } @@ -108,8 +106,11 @@ impl Playlists { tracks_result = match tracks.next { Some(_) => { debug!("requesting tracks again.."); - spotify - .user_playlist_tracks(&id, 100, tracks.offset + tracks.items.len() as u32) + spotify.user_playlist_tracks( + &id, + 100, + tracks.offset + tracks.items.len() as u32, + ) } None => None, }