mirror of
https://github.com/Dangoware/dmp-core.git
synced 2025-04-19 13:32:53 -05:00
Modified library.rs
to properly save with bincode, added new functions to it as well
This commit is contained in:
parent
097cc1147e
commit
e931c2b528
4 changed files with 80 additions and 74 deletions
|
@ -14,8 +14,7 @@ categories = []
|
|||
[dependencies]
|
||||
file-format = { version = "0.23.0", features = ["reader-asf", "reader-ebml", "reader-mp4", "reader-rm", "reader-txt", "reader-xml", "serde"] }
|
||||
lofty = "0.18.0"
|
||||
serde = { version = "1.0.191", features = ["derive"] }
|
||||
toml = "0.8.8"
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
walkdir = "2.4.0"
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
bincode = { version = "2.0.0-rc.3", features = ["serde"] }
|
||||
|
@ -23,10 +22,10 @@ unidecode = "0.3.0"
|
|||
rayon = "1.8.0"
|
||||
log = "0.4"
|
||||
base64 = "0.21.5"
|
||||
snap = "1.1.0"
|
||||
snap = "1"
|
||||
rcue = "0.1.3"
|
||||
gstreamer = "0.21.2"
|
||||
glib = "0.18.3"
|
||||
gstreamer = "0.21.3"
|
||||
glib = "0.18.5"
|
||||
crossbeam-channel = "0.5.8"
|
||||
crossbeam = "0.8.2"
|
||||
quick-xml = "0.31.0"
|
||||
|
|
|
@ -16,10 +16,25 @@ pub struct ConfigLibrary {
|
|||
pub uuid: Uuid
|
||||
}
|
||||
|
||||
impl ConfigLibrary {
|
||||
pub fn new() -> Self {
|
||||
ConfigLibrary::default()
|
||||
impl Default for ConfigLibrary {
|
||||
fn default() -> Self {
|
||||
ConfigLibrary {
|
||||
name: String::new(),
|
||||
path: PathBuf::from("library"),
|
||||
uuid: Uuid::new_v4(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigLibrary {
|
||||
pub fn new(path: PathBuf, name: String) -> Self {
|
||||
ConfigLibrary {
|
||||
name,
|
||||
path,
|
||||
uuid: Uuid::new_v4(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&self) -> Result<File, Error> {
|
||||
match File::open(self.path.as_path()) {
|
||||
Ok(ok) => Ok(ok),
|
||||
|
@ -28,19 +43,9 @@ impl ConfigLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for ConfigLibrary {
|
||||
fn default() -> Self {
|
||||
ConfigLibrary {
|
||||
name: String::default(),
|
||||
path: PathBuf::default(),
|
||||
uuid: Uuid::new_v4()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct ConfigLibraries {
|
||||
default_library: Uuid,
|
||||
pub default_library: Uuid,
|
||||
pub library_folder: PathBuf,
|
||||
pub libraries: Vec<ConfigLibrary>,
|
||||
}
|
||||
|
@ -83,7 +88,7 @@ impl ConfigLibraries {
|
|||
pub struct Config {
|
||||
pub path: PathBuf,
|
||||
pub libraries: ConfigLibraries,
|
||||
volume: f32,
|
||||
pub volume: f32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -92,9 +97,9 @@ fn config_test() {
|
|||
path: PathBuf::from("config_test.json"),
|
||||
libraries: ConfigLibraries {
|
||||
libraries: vec![
|
||||
ConfigLibrary::default(),
|
||||
ConfigLibrary::default(),
|
||||
ConfigLibrary::default()
|
||||
ConfigLibrary::new(PathBuf::from("library1"), String::from("library1")),
|
||||
ConfigLibrary::new(PathBuf::from("library2"), String::from("library2")),
|
||||
ConfigLibrary::new(PathBuf::from("library3"), String::from("library3"))
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -323,13 +323,15 @@ pub struct MusicLibrary {
|
|||
|
||||
#[test]
|
||||
fn library_init() {
|
||||
let uuidv4 = Uuid::new_v4();
|
||||
let a = MusicLibrary::init(Arc::new(RwLock::from(Config::new())), uuidv4).unwrap();
|
||||
let config = Config::read_file(PathBuf::from("config_test.json")).unwrap();
|
||||
let target_uuid = config.libraries.libraries[0].uuid;
|
||||
let a = MusicLibrary::init(Arc::new(RwLock::from(config)), target_uuid).unwrap();
|
||||
dbg!(a);
|
||||
}
|
||||
|
||||
impl MusicLibrary {
|
||||
pub fn new(name: String, uuid: Uuid) -> Self {
|
||||
/// Create a new library from a name and [Uuid]
|
||||
fn new(name: String, uuid: Uuid) -> Self {
|
||||
MusicLibrary {
|
||||
name,
|
||||
uuid,
|
||||
|
@ -337,18 +339,6 @@ impl MusicLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn with_uuid(uuid: Uuid, path: PathBuf) -> Result<Self, Box<dyn Error>> {
|
||||
MusicLibrary {
|
||||
name: String::new(),
|
||||
uuid,
|
||||
library: Vec::new(),
|
||||
};
|
||||
|
||||
todo!()
|
||||
}
|
||||
*/
|
||||
|
||||
/// Initialize the database
|
||||
///
|
||||
/// If the database file already exists, return the [MusicLibrary], otherwise create
|
||||
|
@ -357,7 +347,7 @@ impl MusicLibrary {
|
|||
pub fn init(config: Arc<RwLock<Config>>, uuid: Uuid) -> Result<Self, Box<dyn Error>> {
|
||||
let global_config = &*config.read().unwrap();
|
||||
|
||||
let library: MusicLibrary = match global_config.libraries.uuid_exists(&uuid) {
|
||||
let library: MusicLibrary = match global_config.libraries.get_library(&uuid)?.path.exists() {
|
||||
true => read_file(global_config.libraries.get_library(&uuid)?.path)?,
|
||||
false => {
|
||||
// If the library does not exist, re-create it
|
||||
|
@ -370,13 +360,24 @@ impl MusicLibrary {
|
|||
Ok(library)
|
||||
}
|
||||
|
||||
//#[cfg(debug_assertions)] // We probably wouldn't want to use this for real, but maybe it would have some utility?
|
||||
pub fn from_path(path: PathBuf) -> Result<Self, Box<dyn Error>> {
|
||||
let library: MusicLibrary = match path.exists() {
|
||||
true => read_file(path)?,
|
||||
false => {
|
||||
let lib = MusicLibrary::new(String::new(), Uuid::new_v4());
|
||||
write_file(&lib, path)?;
|
||||
lib
|
||||
}
|
||||
};
|
||||
Ok(library)
|
||||
}
|
||||
|
||||
/// Serializes the database out to the file specified in the config
|
||||
pub fn save(&self, config: &Config) -> Result<(), Box<dyn Error>> {
|
||||
let path = config.libraries.get_library(&self.uuid)?.path;
|
||||
match path.try_exists() {
|
||||
Ok(_) => {
|
||||
write_file(&self.library, path)?;
|
||||
}
|
||||
Ok(_) => write_file(self, path)?,
|
||||
Err(error) => return Err(error.into()),
|
||||
}
|
||||
|
||||
|
@ -384,12 +385,12 @@ impl MusicLibrary {
|
|||
}
|
||||
|
||||
/// Returns the library size in number of tracks
|
||||
pub fn size(&self) -> usize {
|
||||
pub fn len_tracks(&self) -> usize {
|
||||
self.library.len()
|
||||
}
|
||||
|
||||
/// Queries for a [Song] by its [URI], returning a single `Song`
|
||||
/// with the `URI` that matches
|
||||
/// with the `URI` that matches along with its position in the library
|
||||
pub fn query_uri(&self, path: &URI) -> Option<(&Song, usize)> {
|
||||
let result = self
|
||||
.library
|
||||
|
@ -408,7 +409,7 @@ impl MusicLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
/// Queries for a [Song] by its [PathBuf], returning a `Vec<Song>`
|
||||
/// Queries for a [Song] by its [PathBuf], returning a `Vec<&Song>`
|
||||
/// with matching `PathBuf`s
|
||||
fn query_path(&self, path: PathBuf) -> Option<Vec<&Song>> {
|
||||
let result: Arc<Mutex<Vec<&Song>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
|
@ -428,7 +429,6 @@ impl MusicLibrary {
|
|||
pub fn scan_folder(
|
||||
&mut self,
|
||||
target_path: &str,
|
||||
config: &Config,
|
||||
) -> Result<i32, Box<dyn std::error::Error>> {
|
||||
let mut total = 0;
|
||||
let mut errors = 0;
|
||||
|
@ -488,9 +488,6 @@ impl MusicLibrary {
|
|||
}
|
||||
}
|
||||
|
||||
// Save the database after scanning finishes
|
||||
self.save(config).unwrap();
|
||||
|
||||
println!("ERRORS: {}", errors);
|
||||
|
||||
Ok(total)
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
use file_format::{FileFormat, Kind};
|
||||
use std::fs::{File, self};
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{error::Error, fs};
|
||||
use std::error::Error;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use file_format::{FileFormat, Kind};
|
||||
use snap;
|
||||
|
||||
use super::library::{AlbumArt, URI};
|
||||
use unidecode::unidecode;
|
||||
|
||||
use super::library::{AlbumArt, URI};
|
||||
|
||||
pub(super) fn normalize(input_string: &str) -> String {
|
||||
// Normalize the string to latin characters... this needs a lot of work
|
||||
let mut normalized = unidecode(input_string);
|
||||
|
||||
// Remove non alphanumeric characters
|
||||
|
@ -19,25 +21,10 @@ pub(super) fn normalize(input_string: &str) -> String {
|
|||
normalized
|
||||
}
|
||||
|
||||
pub(super) fn read_file<T: for<'de> serde::Deserialize<'de>>(path: PathBuf) -> Result<T, Box<dyn Error>> {
|
||||
// Create a new snap reader over the database file
|
||||
let database = fs::File::open(path)?;
|
||||
let reader = BufReader::new(database);
|
||||
let mut d = snap::read::FrameDecoder::new(reader);
|
||||
|
||||
// Decode the library from the serialized data into the vec
|
||||
let library: T = bincode::serde::decode_from_std_read(
|
||||
&mut d,
|
||||
bincode::config::standard()
|
||||
.with_little_endian()
|
||||
.with_variable_int_encoding(),
|
||||
)?;
|
||||
|
||||
Ok(library)
|
||||
}
|
||||
|
||||
/// Write any data structure which implements [serde::Serialize]
|
||||
/// out to a [bincode] encoded file compressed using [snap]
|
||||
pub(super) fn write_file<T: serde::Serialize>(
|
||||
library: &T,
|
||||
library: T,
|
||||
path: PathBuf,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Create a temporary name for writing out
|
||||
|
@ -45,7 +32,7 @@ pub(super) fn write_file<T: serde::Serialize>(
|
|||
writer_name.set_extension("tmp");
|
||||
|
||||
// Create a new BufWriter on the file and a snap frame encoder
|
||||
let writer = BufWriter::new(fs::File::create(&writer_name)?);
|
||||
let writer = BufWriter::new(File::create(&writer_name)?);
|
||||
let mut e = snap::write::FrameEncoder::new(writer);
|
||||
|
||||
// Write out the data
|
||||
|
@ -61,6 +48,24 @@ pub(super) fn write_file<T: serde::Serialize>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Read a file serialized out with [write_file] and turn it into
|
||||
/// the desired structure
|
||||
pub(super) fn read_file<T: for<'de> serde::Deserialize<'de>>(path: PathBuf) -> Result<T, Box<dyn Error>> {
|
||||
// Create a new snap reader over the file
|
||||
let file_reader = BufReader::new(File::open(path)?);
|
||||
let mut d = snap::read::FrameDecoder::new(file_reader);
|
||||
|
||||
// Decode the library from the serialized data into the vec
|
||||
let library: T = bincode::serde::decode_from_std_read(
|
||||
&mut d,
|
||||
bincode::config::standard()
|
||||
.with_little_endian()
|
||||
.with_variable_int_encoding(),
|
||||
)?;
|
||||
|
||||
Ok(library)
|
||||
}
|
||||
|
||||
pub fn find_images(song_path: &Path) -> Result<Vec<AlbumArt>, Box<dyn Error>> {
|
||||
let mut images: Vec<AlbumArt> = Vec::new();
|
||||
|
||||
|
@ -85,7 +90,7 @@ pub fn find_images(song_path: &Path) -> Result<Vec<AlbumArt>, Box<dyn Error>> {
|
|||
break;
|
||||
}
|
||||
|
||||
let image_uri = URI::Local(path.to_path_buf().canonicalize().unwrap());
|
||||
let image_uri = URI::Local(path.to_path_buf().canonicalize()?);
|
||||
|
||||
images.push(AlbumArt::External(image_uri));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue