aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.rs152
1 files changed, 79 insertions, 73 deletions
diff --git a/src/main.rs b/src/main.rs
index 47a1c66..0be3327 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::fs::File;
-use std::io::{stdout, Read, Write};
+use std::io::{stdout, Error, Read, Write};
use crossterm::{
cursor,
@@ -10,66 +10,81 @@ use crossterm::{
terminal,
};
+use roxmltree::Document;
+
+struct Epub {
+ container: zip::ZipArchive<File>,
+}
+
struct Bk {
+ epub: Epub,
cols: u16,
chapter: Vec<String>,
chapter_idx: usize,
- container: zip::ZipArchive<File>,
pos: usize,
rows: usize,
toc: Vec<String>,
pad: u16,
}
-fn get_toc(container: &mut zip::ZipArchive<File>) -> Vec<String> {
- // container.xml -> <rootfile> -> opf -> <manifest> + <spine>
- let mut xml = String::new();
- container
- .by_name("META-INF/container.xml")
- .unwrap()
- .read_to_string(&mut xml)
- .unwrap();
- let doc = roxmltree::Document::parse(&xml).unwrap();
- let path = doc
- .descendants()
- .find(|n| n.has_tag_name("rootfile"))
- .unwrap()
- .attribute("full-path")
- .unwrap();
-
- let mut xml = String::new();
- container
- .by_name(path)
- .unwrap()
- .read_to_string(&mut xml)
- .unwrap();
- let doc = roxmltree::Document::parse(&xml).unwrap();
- let mut manifest = HashMap::new();
- doc.root_element()
- .children()
- .find(|n| n.has_tag_name("manifest"))
- .unwrap()
- .children()
- .filter(|n| n.is_element())
- .for_each(|n| {
- manifest.insert(
- n.attribute("id").unwrap(),
- n.attribute("href").unwrap(),
- );
- });
+impl Epub {
+ fn new(path: &str) -> Result<Self, Error> {
+ let file = File::open(path)?;
- let path = std::path::Path::new(&path).parent().unwrap();
- doc.root_element()
- .children()
- .find(|n| n.has_tag_name("spine"))
- .unwrap()
- .children()
- .filter(|n| n.is_element())
- .map(|n| {
- let name = manifest.get(n.attribute("idref").unwrap()).unwrap();
- path.join(name).to_str().unwrap().to_string()
+ Ok(Epub {
+ container: zip::ZipArchive::new(file)?,
})
- .collect()
+ }
+ 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_toc(&mut self) -> Vec<String> {
+ // container.xml -> <rootfile> -> opf -> <spine> -> <manifest>
+ let xml = self.get_text("META-INF/container.xml");
+ let doc = Document::parse(&xml).unwrap();
+ let path = doc
+ .descendants()
+ .find(|n| n.has_tag_name("rootfile"))
+ .unwrap()
+ .attribute("full-path")
+ .unwrap();
+
+ let mut manifest = HashMap::new();
+ let xml = self.get_text(path);
+ let doc = Document::parse(&xml).unwrap();
+ doc.root_element()
+ .children()
+ .find(|n| n.has_tag_name("manifest"))
+ .unwrap()
+ .children()
+ .filter(|n| n.is_element())
+ .for_each(|n| {
+ manifest.insert(
+ n.attribute("id").unwrap(),
+ n.attribute("href").unwrap(),
+ );
+ });
+
+ let path = std::path::Path::new(&path).parent().unwrap();
+ doc.root_element()
+ .children()
+ .find(|n| n.has_tag_name("spine"))
+ .unwrap()
+ .children()
+ .filter(|n| n.is_element())
+ .map(|n| {
+ let name =
+ manifest.get(n.attribute("idref").unwrap()).unwrap();
+ path.join(name).to_str().unwrap().to_string()
+ })
+ .collect()
+ }
}
fn wrap(text: Vec<String>, width: u16) -> Vec<String> {
@@ -103,38 +118,31 @@ fn wrap(text: Vec<String>, width: u16) -> Vec<String> {
impl Bk {
fn new(
path: &str,
- cols: u16,
- rows: usize,
chapter_idx: usize,
pos: usize,
pad: u16,
- ) -> Result<Self, std::io::Error> {
- let file = File::open(path)?;
- let mut container = zip::ZipArchive::new(file)?;
- let toc = get_toc(&mut container);
+ ) -> Result<Self, Error> {
+ let (cols, rows) = terminal::size().unwrap();
+ let mut epub = Epub::new(path)?;
+ let toc = epub.get_toc();
let mut bk = Bk {
chapter: Vec::new(),
- container,
- toc,
- cols,
- rows,
+ epub,
chapter_idx,
pos,
pad,
+ cols,
+ toc,
+ rows: rows as usize,
};
bk.load_chapter();
Ok(bk)
}
fn load_chapter(&mut self) {
- let mut text = String::new();
- self.container
- .by_name(&self.toc[self.chapter_idx])
- .unwrap()
- .read_to_string(&mut text)
- .unwrap();
- let doc = roxmltree::Document::parse(&text).unwrap();
-
let mut chapter = Vec::new();
+ let xml = self.epub.get_text(&self.toc[self.chapter_idx]);
+ let doc = Document::parse(&xml).unwrap();
+
for n in doc.descendants() {
match n.tag_name().name() {
"h1" | "h2" | "h3" | "h4" | "h5" | "h6" => {
@@ -238,13 +246,11 @@ fn main() -> crossterm::Result<()> {
let save_path =
format!("{}/.local/share/bk", std::env::var("HOME").unwrap());
let (path, chapter, pos) = restore(&save_path);
- let (cols, rows) = terminal::size().unwrap();
- let mut bk = Bk::new(&path, cols, rows as usize, chapter, pos, 2)
- .unwrap_or_else(|e| {
- println!("error reading epub: {}", e);
- std::process::exit(1);
- });
+ let mut bk = Bk::new(&path, chapter, pos, 2).unwrap_or_else(|e| {
+ println!("error reading epub: {}", e);
+ std::process::exit(1);
+ });
let mut stdout = stdout();
queue!(stdout, terminal::EnterAlternateScreen, cursor::Hide)?;