Modified library.rs to properly save with bincode, added new functions to it as well

This commit is contained in:
G2-Games 2024-01-20 20:38:50 -06:00
parent 097cc1147e
commit e931c2b528
4 changed files with 80 additions and 74 deletions

View file

@ -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"

View file

@ -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()
},

View file

@ -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)

View file

@ -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));
}