mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Add --disable-audio-cache startup parameter (#204)
Disable caching of downloaded audio files at runtime. Comes in handy when running librespot on a small device with SD card or other small storage.
This commit is contained in:
parent
c070f6b0db
commit
67deb07250
3 changed files with 13 additions and 108 deletions
101
src/cache/default_cache.rs
vendored
101
src/cache/default_cache.rs
vendored
|
@ -1,101 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use util::{SpotifyId, FileId, ReadSeek, mkdir_existing};
|
|
||||||
use authentication::Credentials;
|
|
||||||
use audio_key::AudioKey;
|
|
||||||
|
|
||||||
use super::Cache;
|
|
||||||
|
|
||||||
pub struct DefaultCache {
|
|
||||||
environment: lmdb::Environment,
|
|
||||||
root: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DefaultCache {
|
|
||||||
pub fn new(location: PathBuf) -> Result<DefaultCache, ()> {
|
|
||||||
let env = lmdb::EnvBuilder::new().max_dbs(5).open(&location.join("db"), 0o755).unwrap();
|
|
||||||
|
|
||||||
mkdir_existing(&location).unwrap();
|
|
||||||
mkdir_existing(&location.join("files")).unwrap();
|
|
||||||
|
|
||||||
Ok(DefaultCache {
|
|
||||||
environment: env,
|
|
||||||
root: location
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn audio_keys(&self) -> MdbResult<lmdb::DbHandle> {
|
|
||||||
self.environment.create_db("audio-keys", lmdb::DbFlags::empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_path(&self, file: FileId) -> PathBuf {
|
|
||||||
let name = file.to_base16();
|
|
||||||
self.root.join("files").join(&name[0..2]).join(&name[2..])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn credentials_path(&self) -> PathBuf {
|
|
||||||
self.root.join("credentials.json")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cache for DefaultCache {
|
|
||||||
fn get_audio_key(&self, track: SpotifyId, file: FileId) -> Option<AudioKey> {
|
|
||||||
let reader = self.environment.get_reader().unwrap();
|
|
||||||
let handle = self.audio_keys().unwrap();
|
|
||||||
let db = reader.bind(&handle);
|
|
||||||
|
|
||||||
let mut key = Vec::new();
|
|
||||||
key.extend_from_slice(&track.to_raw());
|
|
||||||
key.extend_from_slice(&file.0);
|
|
||||||
|
|
||||||
let value : Option<Vec<_>> = db.get(&key).ok();
|
|
||||||
value.and_then(|value| if value.len() == 16 {
|
|
||||||
let mut result = [0u8; 16];
|
|
||||||
result.clone_from_slice(&value);
|
|
||||||
Some(AudioKey(result))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_audio_key(&self, track: SpotifyId, file: FileId, audio_key: AudioKey) {
|
|
||||||
let xact = self.environment.new_transaction().unwrap();
|
|
||||||
let handle = self.audio_keys().unwrap();
|
|
||||||
|
|
||||||
{
|
|
||||||
let db = xact.bind(&handle);
|
|
||||||
|
|
||||||
let mut key = Vec::new();
|
|
||||||
key.extend_from_slice(&track.to_raw());
|
|
||||||
key.extend_from_slice(&file.0);
|
|
||||||
|
|
||||||
db.set(&key, &audio_key.0.as_ref()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
xact.commit().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_credentials(&self) -> Option<Credentials> {
|
|
||||||
let path = self.credentials_path();
|
|
||||||
Credentials::from_file(path)
|
|
||||||
}
|
|
||||||
fn put_credentials(&self, cred: &Credentials) {
|
|
||||||
let path = self.credentials_path();
|
|
||||||
cred.save_to_file(&path);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file(&self, file: FileId) -> Option<Box<ReadSeek>> {
|
|
||||||
File::open(self.file_path(file)).ok().map(|f| Box::new(f) as Box<ReadSeek>)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_file(&self, file: FileId, contents: &mut Read) {
|
|
||||||
let path = self.file_path(file);
|
|
||||||
|
|
||||||
mkdir_existing(path.parent().unwrap()).unwrap();
|
|
||||||
|
|
||||||
let mut cache_file = File::create(path).unwrap();
|
|
||||||
::std::io::copy(contents, &mut cache_file).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
16
src/cache/mod.rs
vendored
16
src/cache/mod.rs
vendored
|
@ -8,15 +8,17 @@ use authentication::Credentials;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Cache {
|
pub struct Cache {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
|
use_audio_cache: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cache {
|
impl Cache {
|
||||||
pub fn new(location: PathBuf) -> Cache {
|
pub fn new(location: PathBuf, use_audio_cache: bool) -> Cache {
|
||||||
mkdir_existing(&location).unwrap();
|
mkdir_existing(&location).unwrap();
|
||||||
mkdir_existing(&location.join("files")).unwrap();
|
mkdir_existing(&location.join("files")).unwrap();
|
||||||
|
|
||||||
Cache {
|
Cache {
|
||||||
root: location
|
root: location,
|
||||||
|
use_audio_cache: use_audio_cache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,11 +50,13 @@ impl Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_file(&self, file: FileId, contents: &mut Read) {
|
pub fn save_file(&self, file: FileId, contents: &mut Read) {
|
||||||
let path = self.file_path(file);
|
if self.use_audio_cache {
|
||||||
|
let path = self.file_path(file);
|
||||||
|
|
||||||
mkdir_existing(path.parent().unwrap()).unwrap();
|
mkdir_existing(path.parent().unwrap()).unwrap();
|
||||||
|
|
||||||
let mut cache_file = File::create(path).unwrap();
|
let mut cache_file = File::create(path).unwrap();
|
||||||
::std::io::copy(contents, &mut cache_file).unwrap();
|
::std::io::copy(contents, &mut cache_file).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct Setup {
|
||||||
fn setup(args: &[String]) -> Setup {
|
fn setup(args: &[String]) -> Setup {
|
||||||
let mut opts = getopts::Options::new();
|
let mut opts = getopts::Options::new();
|
||||||
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
|
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
|
||||||
|
.optflag("", "disable-audio-cache", "Disable caching of the audio data.")
|
||||||
.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")
|
||||||
.optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
|
.optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
|
||||||
|
@ -133,9 +134,10 @@ fn setup(args: &[String]) -> Setup {
|
||||||
|
|
||||||
let name = matches.opt_str("name").unwrap();
|
let name = matches.opt_str("name").unwrap();
|
||||||
let device_id = librespot::session::device_id(&name);
|
let device_id = librespot::session::device_id(&name);
|
||||||
|
let use_audio_cache = !matches.opt_present("disable-audio-cache");
|
||||||
|
|
||||||
let cache = matches.opt_str("c").map(|cache_location| {
|
let cache = matches.opt_str("c").map(|cache_location| {
|
||||||
Cache::new(PathBuf::from(cache_location))
|
Cache::new(PathBuf::from(cache_location), use_audio_cache)
|
||||||
});
|
});
|
||||||
|
|
||||||
let cached_credentials = cache.as_ref().and_then(Cache::credentials);
|
let cached_credentials = cache.as_ref().and_then(Cache::credentials);
|
||||||
|
|
Loading…
Reference in a new issue