Make cache directory optional.

If the -c argument is omitted, librespot will run without a cache, and
download tracks overtime they are played.
This commit is contained in:
Paul Lietar 2016-03-14 22:56:50 +00:00
parent 0e911fbb59
commit a5453de572
3 changed files with 32 additions and 29 deletions

View file

@ -103,7 +103,7 @@ impl AudioFileLoading {
let bitmap = shared.bitmap.lock().unwrap(); let bitmap = shared.bitmap.lock().unwrap();
if bitmap.len() >= shared.chunk_count { if bitmap.len() >= shared.chunk_count {
drop(bitmap); drop(bitmap);
AudioFileLoading::store(session, &shared, &mut write_file); AudioFileLoading::persist_to_cache(session, &shared, &mut write_file);
break; break;
} }
@ -150,14 +150,14 @@ impl AudioFileLoading {
shared.cond.notify_all(); shared.cond.notify_all();
} }
fn store(session: &Session, shared: &AudioFileShared, write_file: &mut NamedTempFile) { fn persist_to_cache(session: &Session, shared: &AudioFileShared, write_file: &mut NamedTempFile) {
write_file.seek(SeekFrom::Start(0)).unwrap(); if let Some(path) = AudioFileManager::cache_path(session, shared.file_id) {
write_file.seek(SeekFrom::Start(0)).unwrap();
mkdir_existing(path.parent().unwrap()).unwrap();
mkdir_existing(&AudioFileManager::cache_dir(session, shared.file_id)).unwrap(); let mut cache_file = fs::File::create(path).unwrap();
io::copy(write_file, &mut cache_file).unwrap();
let mut f = fs::File::create(AudioFileManager::cache_path(session, shared.file_id)) }
.unwrap();
io::copy(write_file, &mut f).unwrap();
} }
} }
@ -217,20 +217,19 @@ impl AudioFileManager {
AudioFileManager AudioFileManager
} }
pub fn cache_dir(session: &Session, file_id: FileId) -> PathBuf { pub fn cache_path(session: &Session, file_id: FileId) -> Option<PathBuf> {
let name = file_id.to_base16(); session.config().cache_location.as_ref().map(|cache| {
session.config().cache_location.join(&name[0..2]) let name = file_id.to_base16();
} cache.join(&name[0..2]).join(&name[2..])
})
pub fn cache_path(session: &Session, file_id: FileId) -> PathBuf {
let name = file_id.to_base16();
AudioFileManager::cache_dir(session, file_id).join(&name[2..])
} }
pub fn request(&mut self, session: &Session, file_id: FileId) -> AudioFile { pub fn request(&mut self, session: &Session, file_id: FileId) -> AudioFile {
match fs::File::open(AudioFileManager::cache_path(session, file_id)) { let cache_path = AudioFileManager::cache_path(session, file_id);
Ok(f) => AudioFile::Direct(f), let cache_file = cache_path.and_then(|p| fs::File::open(p).ok());
Err(..) => AudioFile::Loading(AudioFileLoading::new(session, file_id)),
} cache_file.map(AudioFile::Direct).unwrap_or_else(|| {
AudioFile::Loading(AudioFileLoading::new(session, file_id))
})
} }
} }

View file

@ -33,7 +33,7 @@ fn main() {
opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY") opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY")
.optopt("u", "username", "Username to sign in with (optional)", "USERNAME") .optopt("u", "username", "Username to sign in with (optional)", "USERNAME")
.optopt("p", "password", "Password (optional)", "PASSWORD") .optopt("p", "password", "Password (optional)", "PASSWORD")
.reqopt("c", "cache", "Path to a directory where files will be cached.", "CACHE") .optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
.reqopt("n", "name", "Device name", "NAME") .reqopt("n", "name", "Device name", "NAME")
.optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE"); .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE");
@ -56,7 +56,7 @@ fn main() {
}; };
let username = matches.opt_str("u"); let username = matches.opt_str("u");
let cache_location = PathBuf::from(matches.opt_str("c").unwrap()); let cache_location = matches.opt_str("c").map(PathBuf::from);
let name = matches.opt_str("n").unwrap(); let name = matches.opt_str("n").unwrap();
let credentials = username.map(|u| { let credentials = username.map(|u| {
@ -91,21 +91,23 @@ fn main() {
let session = Session::new(config); let session = Session::new(config);
let credentials_path = cache_location.join("credentials.json"); let credentials_path = cache_location.map(|c| c.join("credentials.json"));
let credentials = credentials.map(|(username, password)| { let credentials = credentials.map(|(username, password)| {
Credentials::with_password(username, password) Credentials::with_password(username, password)
}).or_else(|| { }).or_else(|| {
File::open(&credentials_path).map(|file| { credentials_path.as_ref()
Credentials::from_reader(file) .and_then(|p| File::open(p).ok())
}).ok() .map(Credentials::from_reader)
}).unwrap_or_else(|| { }).unwrap_or_else(|| {
let mut discovery = DiscoveryManager::new(session.clone()); let mut discovery = DiscoveryManager::new(session.clone());
discovery.run() discovery.run()
}); });
let reusable_credentials = session.login(credentials).unwrap(); let reusable_credentials = session.login(credentials).unwrap();
reusable_credentials.save_to_file(credentials_path); if let Some(path) = credentials_path {
reusable_credentials.save_to_file(path);
}
let player = Player::new(session.clone(), || DefaultSink::open()); let player = Player::new(session.clone(), || DefaultSink::open());
let spirc = SpircManager::new(session.clone(), player); let spirc = SpircManager::new(session.clone(), player);

View file

@ -34,7 +34,7 @@ pub struct Config {
pub application_key: Vec<u8>, pub application_key: Vec<u8>,
pub user_agent: String, pub user_agent: String,
pub device_name: String, pub device_name: String,
pub cache_location: PathBuf, pub cache_location: Option<PathBuf>,
pub bitrate: Bitrate, pub bitrate: Bitrate,
} }
@ -62,7 +62,9 @@ pub struct Session(pub Arc<SessionInternal>);
impl Session { impl Session {
pub fn new(config: Config) -> Session { pub fn new(config: Config) -> Session {
mkdir_existing(&config.cache_location).unwrap(); if let Some(cache_location) = config.cache_location.as_ref() {
mkdir_existing(cache_location).unwrap();
}
let device_id = { let device_id = {
let mut h = Sha1::new(); let mut h = Sha1::new();