diff options
| -rw-r--r-- | src/epub.rs | 35 | ||||
| -rw-r--r-- | src/main.rs | 15 |
2 files changed, 48 insertions, 2 deletions
diff --git a/src/epub.rs b/src/epub.rs index c984dde..90aeafb 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -1,3 +1,5 @@ +use anyhow::{Context, Result}; +use std::fs; use std::path::{Path, PathBuf}; use unicode_normalization::UnicodeNormalization; @@ -9,6 +11,7 @@ pub struct EpubSkeleton { } impl EpubSkeleton { + /// Plan the output directory structure using the sanitized title + bookid. pub fn plan(base_books_dir: &Path, title: &str, bookid: &str) -> Self { // Maximum number of bytes in a filename. const MAX_BYTES: usize = 255; @@ -28,6 +31,38 @@ impl EpubSkeleton { root: root_dir, } } + + /// Create the directories defined in the struct. + pub fn create_dirs(&self) -> Result<()> { + fs::create_dir_all(&self.oebps) + .with_context(|| format!("Creating directory {}", self.oebps.display()))?; + fs::create_dir_all(&self.meta_inf) + .with_context(|| format!("Creating directory {}", self.meta_inf.display()))?; + Ok(()) + } + + /// Write META-INF/container.xml pointing to OEBPS/content.opf. + pub fn write_container_xml(&self) -> Result<()> { + let path = self.meta_inf.join("container.xml"); + let xml = r#"<?xml version="1.0" encoding="UTF-8"?> + <container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0"> + <rootfiles> + <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/> + </rootfiles> + </container> + "#; + fs::write(&path, xml).with_context(|| format!("Writing file {}", path.display()))?; + Ok(()) + } + + /// Write the plaintext "mimetype" file at the root (no newline). + pub fn write_mimetype(&self) -> Result<()> { + let path = self.root.join("mimetype"); + // EXACT bytes required by OCF; do not add '\n'. + fs::write(&path, b"application/epub+zip") + .with_context(|| format!("Writing file {}", path.display()))?; + Ok(()) + } } /// Sanitize a filename component for cross‑platform compatibility. diff --git a/src/main.rs b/src/main.rs index b963850..83743a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use clap::Parser; use cli::Args; use cookies::CookieStore; use display::Display; +use epub::EpubSkeleton; use http_client::HttpClient; use orly::{check_login, fetch_book_info}; @@ -68,9 +69,19 @@ async fn main() { }; ui.info(&format!("{:#?}", bookinfo)); - let output_dir = config::books_root().join(format!("(pending) ({})", args.bookid)); + let skeleton = EpubSkeleton::plan(&config::books_root(), &bookinfo.title, &args.bookid); + ui.set_output_dir(skeleton.root.clone()); - ui.set_output_dir(output_dir); + // Create directories and required files + if let Err(e) = (|| -> anyhow::Result<()> { + skeleton.create_dirs()?; + skeleton.write_mimetype()?; + skeleton.write_container_xml()?; + Ok(()) + })() { + ui.error_and_exit(&format!("EPUB skeleton creation failed: {e}")); + } + ui.info("EPUB skeleton ready (mimetype + META-INF/container.xml + OEBPS/)."); ui.info("Initialization complete."); ui.info("No network operations performed in this version."); |
