aboutsummaryrefslogtreecommitdiff
path: root/src/epub.rs
diff options
context:
space:
mode:
authorA Farzat <a@farzat.xyz>2026-03-03 14:16:45 +0300
committerA Farzat <a@farzat.xyz>2026-03-03 14:16:45 +0300
commit6782269bb52a349e9568a28ed6c1f43438b7bb24 (patch)
tree4f2cc973c6d160c475790dccf38aebeb4c5d4a69 /src/epub.rs
parent9a95cf1684fcd8bfc81efcac7676532413d35328 (diff)
downloadoreilly-epub-6782269bb52a349e9568a28ed6c1f43438b7bb24.tar.gz
oreilly-epub-6782269bb52a349e9568a28ed6c1f43438b7bb24.zip
Add container.xml to zip
Instead of writing it to file and then reading it again, we write container.xml straight to zip, just like we did with mimetype.
Diffstat (limited to 'src/epub.rs')
-rw-r--r--src/epub.rs35
1 files changed, 21 insertions, 14 deletions
diff --git a/src/epub.rs b/src/epub.rs
index e71e3ca..e993c31 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -1,5 +1,5 @@
use crate::models::FileEntry;
-use anyhow::Result;
+use anyhow::{Context, Result};
use reqwest::Client;
use std::{io::Write, path::Path};
use tokio::{
@@ -9,15 +9,7 @@ use tokio::{
use zip::{CompressionMethod, ZipWriter, write::FileOptions};
/// Creates and writes container.xml.
-pub async fn write_container_xml(dest_root: &Path, opf_full_path: &str) -> Result<()> {
- // Create destination directory.
- let dest_dir = dest_root.join("META-INF");
- fs::create_dir_all(&dest_dir).await?;
-
- // Create distination file.
- let dest_path = dest_dir.join("container.xml");
- let mut file = File::create(dest_path).await?;
-
+fn write_container_xml_to_zip(zip: &mut ZipWriter<std::fs::File>, opf_full_path: &str) -> Result<()> {
// Prepare file contents.
let contents = format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
@@ -30,7 +22,10 @@ pub async fn write_container_xml(dest_root: &Path, opf_full_path: &str) -> Resul
);
// Write down the file.
- file.write_all(contents.as_bytes()).await?;
+ let options: FileOptions<()> =
+ FileOptions::default().compression_method(CompressionMethod::Deflated);
+ zip.start_file("META-INF/container.xml", options)?;
+ zip.write_all(contents.as_bytes())?;
Ok(())
}
@@ -61,14 +56,26 @@ pub async fn download_all_files(
}
/// Creates the EPUB archive (creates zip and includes all files in it).
-pub fn create_epub_archive(epub_root: &Path, output_epub: &Path) -> Result<()> {
+pub fn create_epub_archive(
+ epub_root: &Path,
+ output_epub: &Path,
+ file_entries: &[FileEntry],
+) -> Result<()> {
let out_file = std::fs::File::create(output_epub)?;
let mut zip = ZipWriter::new(out_file);
- let mimetype_options: FileOptions<()> =
+ // Write mimetype to zip first. It must be uncompressed.
+ let options: FileOptions<()> =
FileOptions::default().compression_method(CompressionMethod::Stored);
- zip.start_file("mimetype", mimetype_options)?;
+ zip.start_file("mimetype", options)?;
zip.write_all(b"application/epub+zip")?;
+ // Find the OPF file entry to reference it in container.xml
+ let opf_entry = file_entries
+ .iter()
+ .find(|f| f.filename_ext == ".opf" && f.media_type == "application/oebps-package+xml")
+ .context("No OPF file with the correct MIME type was found.")?;
+ write_container_xml_to_zip(&mut zip, &opf_entry.full_path)?;
+
Ok(())
}