aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/epub.rs35
-rw-r--r--src/main.rs15
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.");