diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/epub.rs | 204 | ||||
-rw-r--r-- | src/main.rs | 3 |
2 files changed, 101 insertions, 106 deletions
diff --git a/src/epub.rs b/src/epub.rs index c4f79e3..882175e 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -8,18 +8,30 @@ pub struct Epub { } impl Epub { - pub fn new(path: &str) -> std::io::Result<Self> { + pub fn new(path: &str, meta: bool) -> std::io::Result<Self> { let file = File::open(path)?; let mut epub = Epub { container: zip::ZipArchive::new(file)?, chapters: Vec::new(), meta: String::new(), }; - epub.get_rootfile(); + let chapters = epub.get_rootfile(); + if !meta { + epub.get_chapters(chapters); + } Ok(epub) } - pub fn get_chapters(&mut self) { - self.chapters = std::mem::take(&mut self.chapters) + fn get_text(&mut self, name: &str) -> String { + let mut text = String::new(); + self.container + .by_name(name) + .unwrap() + .read_to_string(&mut text) + .unwrap(); + text + } + fn get_chapters(&mut self, chapters: Vec<(String, String)>) { + self.chapters = chapters .into_iter() .filter_map(|(path, title)| { let xml = self.get_text(&path); @@ -28,7 +40,7 @@ impl Epub { let doc = Document::parse(&xml).unwrap(); let body = doc.root_element().last_element_child().unwrap(); let mut chapter = String::new(); - Epub::render(&mut chapter, body); + render(body, &mut chapter); if chapter.is_empty() { None } else { @@ -37,55 +49,7 @@ impl Epub { }) .collect(); } - fn render(buf: &mut String, n: Node) { - if n.is_text() { - let text = n.text().unwrap(); - if !text.trim().is_empty() { - buf.push_str(text); - } - return; - } - - match n.tag_name().name() { - "h1" | "h2" | "h3" | "h4" | "h5" | "h6" => { - buf.push_str("\n\x1b[1m"); - for c in n.children() { - Self::render(buf, c); - } - buf.push_str("\x1b[0m\n"); - } - "blockquote" | "p" | "tr" => { - buf.push('\n'); - for c in n.children() { - Self::render(buf, c); - } - buf.push('\n'); - } - "li" => { - buf.push_str("\n- "); - for c in n.children() { - Self::render(buf, c); - } - buf.push('\n'); - } - "br" => buf.push('\n'), - _ => { - for c in n.children() { - Self::render(buf, c); - } - } - } - } - fn get_text(&mut self, name: &str) -> String { - let mut text = String::new(); - self.container - .by_name(name) - .unwrap() - .read_to_string(&mut text) - .unwrap(); - text - } - fn get_rootfile(&mut self) { + fn get_rootfile(&mut self) -> Vec<(String, String)> { let xml = self.get_text("META-INF/container.xml"); let doc = Document::parse(&xml).unwrap(); let path = doc @@ -123,7 +87,6 @@ impl Epub { .for_each(|n| { manifest.insert(n.attribute("id").unwrap(), n.attribute("href").unwrap()); }); - if doc.root_element().attribute("version") == Some("3.0") { let path = manifest_node .children() @@ -133,52 +96,15 @@ impl Epub { .unwrap(); let xml = self.get_text(&format!("{}{}", rootdir, path)); let doc = Document::parse(&xml).unwrap(); - - doc.descendants() - .find(|n| n.has_tag_name("nav")) - .unwrap() - .descendants() - .filter(|n| n.has_tag_name("a")) - .for_each(|n| { - let path = n.attribute("href").unwrap().to_string(); - let text = n - .descendants() - .filter(Node::is_text) - .map(|n| n.text().unwrap()) - .collect(); - nav.insert(path, text); - }) + epub3(doc, &mut nav); } else { let toc = spine_node.attribute("toc").unwrap_or("ncx"); let path = manifest.get(toc).unwrap(); let xml = self.get_text(&format!("{}{}", rootdir, path)); let doc = Document::parse(&xml).unwrap(); - - doc.descendants() - .find(|n| n.has_tag_name("navMap")) - .unwrap() - .descendants() - .filter(|n| n.has_tag_name("navPoint")) - .for_each(|n| { - let path = n - .descendants() - .find(|n| n.has_tag_name("content")) - .unwrap() - .attribute("src") - .unwrap() - .to_string(); - let text = n - .descendants() - .find(|n| n.has_tag_name("text")) - .unwrap() - .text() - .unwrap() - .to_string(); - nav.insert(path, text); - }) + epub2(doc, &mut nav); } - - self.chapters = spine_node + spine_node .children() .filter(Node::is_element) .enumerate() @@ -189,17 +115,87 @@ impl Epub { let path = format!("{}{}", rootdir, path); (path, label) }) - .collect(); + .collect() } } -#[test] -fn test_dir() { - let path = "/mnt/lit/read"; - for entry in std::fs::read_dir(path).unwrap() { - let path = entry.unwrap().path(); - let s = path.to_str().unwrap(); - println!("testing: {}", s); - Epub::new(s).unwrap(); +fn render(n: Node, buf: &mut String) { + if n.is_text() { + let text = n.text().unwrap(); + if !text.trim().is_empty() { + buf.push_str(text); + } + return; } + + match n.tag_name().name() { + "h1" | "h2" | "h3" | "h4" | "h5" | "h6" => { + buf.push_str("\n\x1b[1m"); + for c in n.children() { + render(c, buf); + } + buf.push_str("\x1b[0m\n"); + } + "blockquote" | "p" | "tr" => { + buf.push('\n'); + for c in n.children() { + render(c, buf); + } + buf.push('\n'); + } + "li" => { + buf.push_str("\n- "); + for c in n.children() { + render(c, buf); + } + buf.push('\n'); + } + "br" => buf.push('\n'), + _ => { + for c in n.children() { + render(c, buf); + } + } + } +} + +fn epub2(doc: Document, nav: &mut HashMap<String, String>) { + doc.descendants() + .find(|n| n.has_tag_name("navMap")) + .unwrap() + .descendants() + .filter(|n| n.has_tag_name("navPoint")) + .for_each(|n| { + let path = n + .descendants() + .find(|n| n.has_tag_name("content")) + .unwrap() + .attribute("src") + .unwrap() + .to_string(); + let text = n + .descendants() + .find(|n| n.has_tag_name("text")) + .unwrap() + .text() + .unwrap() + .to_string(); + nav.insert(path, text); + }); +} +fn epub3(doc: Document, nav: &mut HashMap<String, String>) { + doc.descendants() + .find(|n| n.has_tag_name("nav")) + .unwrap() + .descendants() + .filter(|n| n.has_tag_name("a")) + .for_each(|n| { + let path = n.attribute("href").unwrap().to_string(); + let text = n + .descendants() + .filter(Node::is_text) + .map(|n| n.text().unwrap()) + .collect(); + nav.insert(path, text); + }); } diff --git a/src/main.rs b/src/main.rs index 7e16c74..8626541 100644 --- a/src/main.rs +++ b/src/main.rs @@ -656,7 +656,7 @@ fn main() { exit(1); }); - let mut epub = epub::Epub::new(&path).unwrap_or_else(|e| { + let epub = epub::Epub::new(&path, meta).unwrap_or_else(|e| { println!("error reading epub: {}", e); exit(1); }); @@ -666,7 +666,6 @@ fn main() { exit(0); } - epub.get_chapters(); let mut bk = Bk::new(epub, args); // i have never seen crossterm error bk.run().unwrap(); |