mirror of
https://github.com/Dangoware/dmp-core.git
synced 2025-04-19 17:42:56 -05:00
Implemented new reading/writing in utils, improved library init function
This commit is contained in:
parent
0f49c50c42
commit
0f5eda5d1d
5 changed files with 108 additions and 78 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
@ -1,9 +1,15 @@
|
||||||
|
# Rust binary output dir
|
||||||
target/
|
target/
|
||||||
|
|
||||||
music_database*
|
# Rust configuration
|
||||||
*.db3*
|
|
||||||
config.toml
|
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
*.db3*
|
||||||
|
music_database*
|
||||||
|
|
||||||
|
# Storage formats
|
||||||
*.kate-swp*
|
*.kate-swp*
|
||||||
*.m3u
|
*.m3u
|
||||||
*.m3u8
|
*.m3u8
|
||||||
|
*.json
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use std::{path::{PathBuf, Path}, marker::PhantomData, fs::{File, OpenOptions, self}, io::{Error, Write, Read}, default};
|
use std::{
|
||||||
|
path::PathBuf,
|
||||||
|
fs::{File, OpenOptions, self},
|
||||||
|
io::{Error, Write, Read},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use serde_json::{to_string, to_string_pretty};
|
use serde_json::to_string_pretty;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -11,6 +15,7 @@ pub struct ConfigLibrary {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub uuid: Uuid
|
pub uuid: Uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigLibrary {
|
impl ConfigLibrary {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ConfigLibrary::default()
|
ConfigLibrary::default()
|
||||||
|
@ -22,6 +27,7 @@ impl ConfigLibrary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ConfigLibrary {
|
impl Default for ConfigLibrary {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ConfigLibrary {
|
ConfigLibrary {
|
||||||
|
@ -31,29 +37,71 @@ impl Default for ConfigLibrary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct ConfigLibraries {
|
pub struct ConfigLibraries {
|
||||||
default_library: Uuid,
|
default_library: Uuid,
|
||||||
pub library_folder: PathBuf,
|
pub library_folder: PathBuf,
|
||||||
pub libraries: Vec<ConfigLibrary>,
|
pub libraries: Vec<ConfigLibrary>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ConfigLibraries {
|
||||||
|
//TODO: Add new function for test tube
|
||||||
|
pub fn set_default(mut self, uuid: &Uuid) {
|
||||||
|
self.default_library = *uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_default(&self) -> Result<&ConfigLibrary, ConfigError> {
|
||||||
|
for library in &self.libraries {
|
||||||
|
if library.uuid == self.default_library {
|
||||||
|
return Ok(library)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ConfigError::NoDefaultLibrary)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_library(&self, uuid: &Uuid) -> Result<ConfigLibrary, ConfigError> {
|
||||||
|
for library in &self.libraries {
|
||||||
|
if &library.uuid == uuid {
|
||||||
|
return Ok(library.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ConfigError::NoConfigLibrary(*uuid))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uuid_exists(&self, uuid: &Uuid) -> bool {
|
||||||
|
for library in &self.libraries {
|
||||||
|
if &library.uuid == uuid {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub libraries: ConfigLibraries,
|
pub libraries: ConfigLibraries,
|
||||||
volume: f32,
|
volume: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn config_test_() {
|
fn config_test() {
|
||||||
Config {
|
let _ = Config {
|
||||||
path: PathBuf::from("F:\\temp\\config.json"),
|
path: PathBuf::from("config_test.json"),
|
||||||
libraries: ConfigLibraries {
|
libraries: ConfigLibraries {
|
||||||
libraries: vec![ConfigLibrary::default(),ConfigLibrary::default(),ConfigLibrary::default()],
|
libraries: vec![
|
||||||
|
ConfigLibrary::default(),
|
||||||
|
ConfigLibrary::default(),
|
||||||
|
ConfigLibrary::default()
|
||||||
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}.to_file();
|
}.write_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Config {
|
Config {
|
||||||
|
@ -64,38 +112,12 @@ impl Config {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_main() -> Self {
|
pub fn new_main() -> Self {
|
||||||
Config::default()
|
Config::default()
|
||||||
}
|
}
|
||||||
//TODO: Add new function for test tube
|
|
||||||
pub fn set_default_library(mut self, uuid: &Uuid) {
|
pub fn write_file(&self) -> Result<(), Error> {
|
||||||
self.libraries.default_library = *uuid;
|
|
||||||
}
|
|
||||||
pub fn get_default_library(&self) -> Result<&ConfigLibrary, ConfigError> {
|
|
||||||
for library in &self.libraries.libraries {
|
|
||||||
if library.uuid == self.libraries.default_library {
|
|
||||||
return Ok(library)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(ConfigError::NoDefaultLibrary)
|
|
||||||
}
|
|
||||||
pub fn get_library(&self, uuid: &Uuid) -> Result<ConfigLibrary, ConfigError> {
|
|
||||||
for library in &self.libraries.libraries {
|
|
||||||
if &library.uuid == uuid {
|
|
||||||
return Ok(library.to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(ConfigError::NoConfigLibrary(*uuid))
|
|
||||||
}
|
|
||||||
pub fn library_exists(&self, uuid: &Uuid) -> bool {
|
|
||||||
for library in &self.libraries.libraries {
|
|
||||||
if &library.uuid == uuid {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
pub fn to_file(&self) -> Result<(), Error> {
|
|
||||||
let mut writer = self.path.clone();
|
let mut writer = self.path.clone();
|
||||||
writer.set_extension("tmp");
|
writer.set_extension("tmp");
|
||||||
let mut file = OpenOptions::new().create(true).truncate(true).read(true).write(true).open(&writer)?;
|
let mut file = OpenOptions::new().create(true).truncate(true).read(true).write(true).open(&writer)?;
|
||||||
|
@ -106,7 +128,8 @@ impl Config {
|
||||||
fs::rename(writer, self.path.as_path())?;
|
fs::rename(writer, self.path.as_path())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn load_file(path: PathBuf) -> Result<Self, Error> {
|
|
||||||
|
pub fn read_file(path: PathBuf) -> Result<Self, Error> {
|
||||||
let mut file: File = File::open(path)?;
|
let mut file: File = File::open(path)?;
|
||||||
let mut bun: String = String::new();
|
let mut bun: String = String::new();
|
||||||
_ = file.read_to_string(&mut bun);
|
_ = file.read_to_string(&mut bun);
|
||||||
|
|
|
@ -3,6 +3,8 @@ pub mod music_storage {
|
||||||
pub mod music_collection;
|
pub mod music_collection;
|
||||||
pub mod playlist;
|
pub mod playlist;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub mod db_reader;
|
pub mod db_reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Crate things
|
// Crate things
|
||||||
use super::utils::{find_images, normalize, read_library, write_library};
|
use super::utils::{find_images, normalize, read_file, write_file};
|
||||||
use super::music_collection::MusicCollection;
|
|
||||||
use crate::config::config::Config;
|
use crate::config::config::Config;
|
||||||
use crate::music_storage::library;
|
|
||||||
|
|
||||||
// Various std things
|
// Various std things
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
@ -316,25 +314,30 @@ impl Album<'_> {
|
||||||
|
|
||||||
const BLOCKED_EXTENSIONS: [&str; 4] = ["vob", "log", "txt", "sf2"];
|
const BLOCKED_EXTENSIONS: [&str; 4] = ["vob", "log", "txt", "sf2"];
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct MusicLibrary {
|
pub struct MusicLibrary {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
pub library: Vec<Song>,
|
pub library: Vec<Song>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_() {
|
fn library_init() {
|
||||||
let a = MusicLibrary::init(Arc::new(RwLock::from(Config::new())), None).unwrap();
|
let uuidv4 = Uuid::new_v4();
|
||||||
|
let a = MusicLibrary::init(Arc::new(RwLock::from(Config::new())), uuidv4).unwrap();
|
||||||
dbg!(a);
|
dbg!(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MusicLibrary {
|
impl MusicLibrary {
|
||||||
pub fn new() -> Self {
|
pub fn new(name: String, uuid: Uuid) -> Self {
|
||||||
MusicLibrary {
|
MusicLibrary {
|
||||||
name: String::default(),
|
name,
|
||||||
uuid: Uuid::default(),
|
uuid,
|
||||||
library: Vec::new(),
|
library: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn with_uuid(uuid: Uuid, path: PathBuf) -> Result<Self, Box<dyn Error>> {
|
pub fn with_uuid(uuid: Uuid, path: PathBuf) -> Result<Self, Box<dyn Error>> {
|
||||||
MusicLibrary {
|
MusicLibrary {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
|
@ -344,40 +347,35 @@ impl MusicLibrary {
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Initialize the database
|
/// Initialize the database
|
||||||
///
|
///
|
||||||
/// If the database file already exists, return the [MusicLibrary], otherwise create
|
/// If the database file already exists, return the [MusicLibrary], otherwise create
|
||||||
/// the database first. This needs to be run before anything else to retrieve
|
/// the database first. This needs to be run before anything else to retrieve
|
||||||
/// the [MusicLibrary] Vec
|
/// the [MusicLibrary] Vec
|
||||||
pub fn init(config: Arc<RwLock<Config>>, uuid: Option<Uuid>) -> Result<Self, Box<dyn Error>> {
|
pub fn init(config: Arc<RwLock<Config>>, uuid: Uuid) -> Result<Self, Box<dyn Error>> {
|
||||||
let global_config = &*config.read().unwrap();
|
let global_config = &*config.read().unwrap();
|
||||||
|
|
||||||
let mut library = MusicLibrary::new();
|
let library: MusicLibrary = match global_config.libraries.uuid_exists(&uuid) {
|
||||||
|
true => read_file(global_config.libraries.get_library(&uuid)?.path)?,
|
||||||
if let Some(uuid) = uuid {
|
|
||||||
match global_config.library_exists(&uuid) {
|
|
||||||
true => {
|
|
||||||
library.library = read_library(global_config.get_library(&uuid)?.path)?;
|
|
||||||
},
|
|
||||||
false => {
|
false => {
|
||||||
// Create the database if it does not exist
|
// If the library does not exist, re-create it
|
||||||
write_library(&library.library, global_config.path.clone())?;
|
let lib = MusicLibrary::new(String::new(), uuid);
|
||||||
library = MusicLibrary::with_uuid(uuid, global_config.path.parent().unwrap().to_path_buf())?;
|
write_file(&lib, global_config.libraries.get_library(&uuid)?.path)?;
|
||||||
|
lib
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}else {
|
|
||||||
write_library(&library.library, global_config.path.clone())?;
|
|
||||||
}
|
|
||||||
Ok(library)
|
Ok(library)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes the database out to the file specified in the config
|
/// Serializes the database out to the file specified in the config
|
||||||
pub fn save(&self, config: &Config) -> Result<(), Box<dyn Error>> {
|
pub fn save(&self, config: &Config) -> Result<(), Box<dyn Error>> {
|
||||||
let path = config.get_library(&self.uuid)?.path;
|
let path = config.libraries.get_library(&self.uuid)?.path;
|
||||||
match path.try_exists() {
|
match path.try_exists() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
write_library(&self.library, path)?;
|
write_file(&self.library, path)?;
|
||||||
}
|
}
|
||||||
Err(error) => return Err(error.into()),
|
Err(error) => return Err(error.into()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use walkdir::WalkDir;
|
||||||
|
|
||||||
use snap;
|
use snap;
|
||||||
|
|
||||||
use super::library::{AlbumArt, Song, URI};
|
use super::library::{AlbumArt, URI};
|
||||||
use unidecode::unidecode;
|
use unidecode::unidecode;
|
||||||
|
|
||||||
pub(super) fn normalize(input_string: &str) -> String {
|
pub(super) fn normalize(input_string: &str) -> String {
|
||||||
|
@ -19,35 +19,36 @@ pub(super) fn normalize(input_string: &str) -> String {
|
||||||
normalized
|
normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn read_library(path: PathBuf) -> Result<Vec<Song>, Box<dyn Error>> {
|
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
|
// Create a new snap reader over the database file
|
||||||
let database = fs::File::open(path)?;
|
let database = fs::File::open(path)?;
|
||||||
let reader = BufReader::new(database);
|
let reader = BufReader::new(database);
|
||||||
let mut d = snap::read::FrameDecoder::new(reader);
|
let mut d = snap::read::FrameDecoder::new(reader);
|
||||||
|
|
||||||
// Decode the library from the serialized data into the vec
|
// Decode the library from the serialized data into the vec
|
||||||
let library: Vec<Song> = bincode::serde::decode_from_std_read(
|
let library: T = bincode::serde::decode_from_std_read(
|
||||||
&mut d,
|
&mut d,
|
||||||
bincode::config::standard()
|
bincode::config::standard()
|
||||||
.with_little_endian()
|
.with_little_endian()
|
||||||
.with_variable_int_encoding(),
|
.with_variable_int_encoding(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(library)
|
Ok(library)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn write_library(
|
pub(super) fn write_file<T: serde::Serialize>(
|
||||||
library: &Vec<Song>,
|
library: &T,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
// Create 2 new names for the file, a temporary one for writing out, and a backup
|
// Create a temporary name for writing out
|
||||||
let mut writer_name = path.clone();
|
let mut writer_name = path.clone();
|
||||||
writer_name.set_extension("tmp");
|
writer_name.set_extension("tmp");
|
||||||
|
|
||||||
// Create a new BufWriter on the file and make a snap frame encoer for it too
|
// 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(fs::File::create(&writer_name)?);
|
||||||
let mut e = snap::write::FrameEncoder::new(writer);
|
let mut e = snap::write::FrameEncoder::new(writer);
|
||||||
|
|
||||||
// Write out the data using bincode
|
// Write out the data
|
||||||
bincode::serde::encode_into_std_write(
|
bincode::serde::encode_into_std_write(
|
||||||
library,
|
library,
|
||||||
&mut e,
|
&mut e,
|
||||||
|
|
Loading…
Reference in a new issue