aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA Farzat <a@farzat.xyz>2026-03-03 18:35:38 +0300
committerA Farzat <a@farzat.xyz>2026-03-03 18:35:38 +0300
commitffd97108068a0dde153dbb64aa4493fa5945a5d3 (patch)
tree0f286c607d819bc13278bc5e191b7ae230294c6b
parent6782269bb52a349e9568a28ed6c1f43438b7bb24 (diff)
downloadoreilly-epub-ffd97108068a0dde153dbb64aa4493fa5945a5d3.tar.gz
oreilly-epub-ffd97108068a0dde153dbb64aa4493fa5945a5d3.zip
Generate the EPUB file
-rw-r--r--src/epub.rs23
-rw-r--r--src/main.rs5
2 files changed, 25 insertions, 3 deletions
diff --git a/src/epub.rs b/src/epub.rs
index e993c31..7eb47f3 100644
--- a/src/epub.rs
+++ b/src/epub.rs
@@ -1,7 +1,10 @@
use crate::models::FileEntry;
use anyhow::{Context, Result};
use reqwest::Client;
-use std::{io::Write, path::Path};
+use std::{
+ io::{Read, Write},
+ path::Path,
+};
use tokio::{
fs::{self, File},
io::AsyncWriteExt,
@@ -9,7 +12,10 @@ use tokio::{
use zip::{CompressionMethod, ZipWriter, write::FileOptions};
/// Creates and writes container.xml.
-fn write_container_xml_to_zip(zip: &mut ZipWriter<std::fs::File>, opf_full_path: &str) -> Result<()> {
+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"?>
@@ -77,5 +83,18 @@ pub fn create_epub_archive(
.context("No OPF file with the correct MIME type was found.")?;
write_container_xml_to_zip(&mut zip, &opf_entry.full_path)?;
+ // Add the rest of the files according to file_entries.
+ let options: FileOptions<()> =
+ FileOptions::default().compression_method(CompressionMethod::Deflated);
+ for entry in file_entries {
+ zip.start_file(&entry.full_path, options)?;
+ let mut src_file = std::fs::File::open(epub_root.join(&entry.full_path))?;
+ let mut buffer = Vec::new();
+ src_file.read_to_end(&mut buffer)?;
+ zip.write_all(&buffer)?;
+ }
+
+ zip.finish()?;
+
Ok(())
}
diff --git a/src/main.rs b/src/main.rs
index 8c5c712..002f669 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,7 +5,7 @@ mod models;
use std::collections::HashMap;
use std::path::Path;
-use crate::epub::{download_all_files,};
+use crate::epub::{create_epub_archive, download_all_files};
use crate::http_client::build_authenticated_client;
use crate::models::{Chapter, EpubResponse, FileEntry, Paginated, SpineItem, TocNode};
use anyhow::{Context, Result, ensure};
@@ -115,6 +115,9 @@ async fn main() -> Result<()> {
let dest_root = format!("Books/{}/epub_root", args.bookid);
let dest_root = Path::new(&dest_root);
download_all_files(&client, &file_entries, dest_root).await?;
+ let epub_path = format!("Books/{0}/{0}.epub", args.bookid);
+ let epub_path = Path::new(&epub_path);
+ create_epub_archive(dest_root, &epub_path, &file_entries)?;
// Sanity check: Every entry in spine exists in chapters.
let chapters: HashMap<String, Chapter> =