From 709dd46f1c9c5057ac14e8f7ec77f4c0de5be8fd Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 20 Jun 2026 15:09:13 -0400 Subject: [PATCH] feat(library): app-managed book storage commands --- src-tauri/src/lib.rs | 7 +++- src-tauri/src/library.rs | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src-tauri/src/library.rs diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b653be2..c8b1315 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,5 @@ mod epub; +mod library; mod pdf; mod project; @@ -12,7 +13,11 @@ pub fn run() { pdf::compile_pdf, project::read_file, project::write_file, - project::write_bytes + project::write_bytes, + library::list_books, + library::load_book, + library::save_book, + library::delete_book ]) .run(tauri::generate_context!()) .expect("error while running margin"); diff --git a/src-tauri/src/library.rs b/src-tauri/src/library.rs new file mode 100644 index 0000000..89ce039 --- /dev/null +++ b/src-tauri/src/library.rs @@ -0,0 +1,85 @@ +use std::fs; +use std::path::PathBuf; +use tauri::Manager; + +#[derive(serde::Serialize)] +pub struct BookSummary { + id: String, + title: String, + author: String, +} + +fn library_dir(app: &tauri::AppHandle) -> Result { + let dir = app + .path() + .app_data_dir() + .map_err(|e| e.to_string())? + .join("library"); + fs::create_dir_all(&dir).map_err(|e| e.to_string())?; + Ok(dir) +} + +#[tauri::command] +pub fn list_books(app: tauri::AppHandle) -> Result, String> { + let dir = library_dir(&app)?; + let mut books = Vec::new(); + for entry in fs::read_dir(&dir).map_err(|e| e.to_string())? { + let path = match entry { + Ok(entry) => entry.path(), + Err(_) => continue, + }; + if path.extension().and_then(|e| e.to_str()) != Some("margin") { + continue; + } + let contents = match fs::read_to_string(&path) { + Ok(contents) => contents, + Err(_) => continue, + }; + let value: serde_json::Value = match serde_json::from_str(&contents) { + Ok(value) => value, + Err(_) => continue, + }; + let id = value.get("id").and_then(|v| v.as_str()).unwrap_or(""); + if id.is_empty() { + continue; + } + let metadata = value.get("metadata"); + let title = metadata + .and_then(|m| m.get("title")) + .and_then(|v| v.as_str()) + .unwrap_or("Untitled") + .to_string(); + let author = metadata + .and_then(|m| m.get("author")) + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string(); + books.push(BookSummary { + id: id.to_string(), + title, + author, + }); + } + Ok(books) +} + +#[tauri::command] +pub fn load_book(app: tauri::AppHandle, id: String) -> Result { + let path = library_dir(&app)?.join(format!("{id}.margin")); + fs::read_to_string(&path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn save_book(app: tauri::AppHandle, id: String, contents: String) -> Result<(), String> { + let path = library_dir(&app)?.join(format!("{id}.margin")); + fs::write(&path, contents).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn delete_book(app: tauri::AppHandle, id: String) -> Result<(), String> { + let path = library_dir(&app)?.join(format!("{id}.margin")); + if path.exists() { + fs::remove_file(&path).map_err(|e| e.to_string())?; + } + Ok(()) +}