diff --git a/src-native/data.rs b/src-native/data.rs index b72b6c8..6e81a4e 100644 --- a/src-native/data.rs +++ b/src-native/data.rs @@ -1,4 +1,4 @@ -use crate::library::{Paths, open_library}; +use crate::library::{Paths, load_library_json, open_library}; use crate::library_types::Library; use crate::tracks::Tag; use anyhow::Context; @@ -123,9 +123,12 @@ impl Data { let library_sqlite = open_library(&paths)?; + let loaded_library_json = + load_library_json(&library_dir.join("Library.json"))?.unwrap_or(Library::new()); + let data = Data { paths, - library: Library::new(), + library: loaded_library_json, db: library_sqlite, current_tag: None, }; diff --git a/src-native/library.rs b/src-native/library.rs index b87049e..1bed9f3 100644 --- a/src-native/library.rs +++ b/src-native/library.rs @@ -1,18 +1,21 @@ #[cfg(feature = "napi-rs")] use crate::data::Data; -use crate::library_types::{ItemId, Library, SpecialTrackListName, TrackList}; +use crate::library_types::{ItemId, Library, SpecialTrackListName, TrackList, VersionedLibrary}; #[cfg(feature = "napi-rs")] use crate::migrate::migrate_to_sqlite; use anyhow::{Context, Result, bail}; use linked_hash_map::LinkedHashMap; -use sqlx::SqliteConnection; -use sqlx::{ConnectOptions, sqlite::SqliteConnectOptions}; +use serde_json::{Value, json}; #[cfg(feature = "napi-rs")] +use sqlx::{ConnectOptions, SqliteConnection, sqlite::SqliteConnectOptions}; +use std::fs::File; +use std::io::{ErrorKind, Read, Seek, SeekFrom}; use std::path::PathBuf; #[cfg(feature = "napi-rs")] use std::time::Instant; #[cfg(feature = "napi-rs")] use std::{fs::create_dir_all, path::Path}; +#[cfg(feature = "napi-rs")] use tokio::runtime::Runtime; #[cfg(feature = "napi-rs")] @@ -46,6 +49,63 @@ impl Paths { } } +// todo: delete +pub fn load_library_json(library_json: &PathBuf) -> Result> { + let mut library_file = match File::open(&library_json) { + Ok(file) => file, + Err(err) => match err.kind() { + ErrorKind::NotFound => return Ok(None), + _ => return Err(err).context("Error opening library file"), + }, + }; + + let mut json_bytes = Vec::new(); + library_file + .read_to_end(&mut json_bytes) + .context("Error reading library file")?; + + let versioned_library: VersionedLibrary = match simd_json::from_slice(&mut json_bytes) { + Ok(lib) => lib, + Err(_) => { + library_file + .seek(SeekFrom::Start(0)) + .context("Error seeking to start of library file")?; + let versioned_library = parse_old_versionless_library_json(&mut library_file)?; + versioned_library + } + }; + + let library = versioned_library.upgrade().init_libary(); + Ok(Some(library)) +} + +// todo: delete +fn parse_old_versionless_library_json(library_file: &mut File) -> Result> { + let mut json_str = String::new(); + library_file + .read_to_string(&mut json_str) + .context("Error reading library file")?; + + let mut value: Value = + serde_json::from_str(&mut json_str).context("Error parsing library file")?; + // Migrate version number to string + if let Some(obj) = value.as_object_mut() { + if let Some(version_field) = obj.get_mut("version") { + if let Some(version) = version_field.as_number() { + if version.as_u64() == Some(1) { + *version_field = json!("1"); + } else if version.as_u64() == Some(2) { + *version_field = json!("2"); + } + } + } + } + + let versioned_library: VersionedLibrary = + serde_json::from_value(value).context("Error parsing library file")?; + Ok(versioned_library) +} + #[cfg(feature = "napi-rs")] pub fn open_library(paths: &Paths) -> Result { let now = Instant::now();