Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ repository = { workspace = true }
readme = { workspace = true }
keywords = { workspace = true }
rust-version = { workspace = true }

[dependencies]
zip = "6.0.0"
zip = "7.0.0"
anyhow = "1.0.100"
quick-xml = { version = "0.38.3" }
quick-xml = { version = "0.38.4" }
ab_glyph = { version = "0.2.32", optional = true }
imageproc = { version = "0.25.0", optional = true}
serde_json = { version = "1.0.145", optional = true }
imageproc = { version = "0.26.0", optional = true}
serde_json = { version = "1.0.149", optional = true }
iepub-derive = { path = "../derive", version = "1.2.6" }
serde = { version = "1.0.228", features = ["derive"], optional = true }
image = { version = "0.25.8", default-features = false, features = ["jpeg"], optional = true }
image = { version = "0.25.9", default-features = false, features = ["jpeg"], optional = true }
md-5 = {version = "0.10.6", optional = true }

[dev-dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
reqwest = { version = "0.13.1", features = ["blocking"] }

[features]
no_nav=[]
Expand Down
10 changes: 5 additions & 5 deletions lib/src/adapter/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ pub mod concat {
.with_title("1.1")
.with_file_name("1/1.xhtml"),
);
let mut builder = EpubBuilder::new()
let builder = EpubBuilder::new()
.custome_nav(true)
.with_title("测试合并")
.with_creator("作者")
Expand Down Expand Up @@ -706,7 +706,7 @@ pub mod concat {
.with_title("3.1")
.with_file_name("2/1.xhtml"),
);
let mut builder = EpubBuilder::new()
let builder = EpubBuilder::new()
.custome_nav(true)
.with_title("测试合并2")
.with_creator("作者2")
Expand All @@ -730,11 +730,11 @@ pub mod concat {
);
let mut book2 = builder.book().unwrap();

let mut builder = EpubBuilder::default();
let (mut builder, len, a_len) =
let builder = EpubBuilder::default();
let (builder, len, a_len) =
add_into_epub(builder, &mut book1, 0, 0, 0, None, &[]).unwrap();

let (mut builder, len, a_len) =
let (builder, len, a_len) =
add_into_epub(builder, &mut book2, len, a_len, 0, None, &[]).unwrap();

let b = builder.book().unwrap();
Expand Down
93 changes: 93 additions & 0 deletions lib/src/epub/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use std::fmt::{Debug, Display};
use std::io::Write;
use std::sync::{Arc, Mutex};

use quick_xml::events::Event;
use quick_xml::Reader;

use super::common::{self};
use super::html::{get_html_info, to_html};
use crate::cache_struct;
Expand Down Expand Up @@ -137,6 +140,17 @@ crate::cache_struct! {
}
}

crate::cache_struct! {
/**
* 标注
*/
#[derive(Debug, Clone)]
pub struct Annotation{
id:String,
text:String,
}
}

epub_base_field! {
#[derive(Default, Clone)]
pub struct EpubHtml {
Expand All @@ -152,6 +166,7 @@ epub_base_field! {
pub(crate) direction: Option<Direction>,
/// body 标签上的attribute
pub(crate) body_attribute: Option<Vec<u8>>,
pub(crate) annotations: Option<Vec<Annotation>>,
}
}

Expand Down Expand Up @@ -183,6 +198,78 @@ impl EpubHtml {
self._data.as_deref()
}

fn get_annotation(&mut self, data: &Vec<u8>) -> Vec<Annotation> {
let mut annotations = Vec::new();
if let Ok(content) = String::from_utf8(data.to_vec()) {
let mut reader = quick_xml::reader::NsReader::from_str(&content);
reader.config_mut().trim_text(true);
let mut buf = Vec::new();
let mut in_annotation = false;
let mut current_text = String::new();
let mut data_id: Option<String> = None;
loop {
if let Ok(event) = reader.read_event_into(&mut buf) {
match event {
Event::Start(e) => {
// 检测标注标签(如 <span class="annotation">)
if e.name().as_ref() == b"span" {
if let Some(attr) = e.attributes().find(|a| {
a.as_ref()
.map(|a| a.key == quick_xml::name::QName(b"class"))
.unwrap_or(false)
}) {
if let Ok(attr) = attr {
let class_val = attr.unescape_value().unwrap_or_default();
if class_val.contains("annotation") {
in_annotation = true;
// 提取元数据标识(如 data-id)
data_id = e
.attributes()
.find(|a| {
a.as_ref()
.map(|a| {
a.key
== quick_xml::name::QName(
b"data-id",
)
})
.unwrap_or(false)
})
.and_then(|a| {
a.ok().map(|a| {
a.unescape_value()
.unwrap_or_default()
.to_string()
})
});
}
}
}
}
}
Event::Text(e) if in_annotation => {
current_text.push_str(&e.decode().unwrap_or_default());
// 累积标注文本
}
Event::End(e) if e.name().as_ref() == b"span" && in_annotation => {
if let Some(id) = data_id.take() {
annotations.push(Annotation {
id,
text: current_text.clone(),
});
}
in_annotation = false;
}
Event::Eof => break,
_ => {}
}
}
buf.clear();
}
}
annotations
}

pub(crate) fn read_data(&mut self, reader: &mut impl EpubReaderTrait) {
let (id, origin) = if let Some(index) = self._file_name.find('#') {
(
Expand Down Expand Up @@ -214,6 +301,7 @@ impl EpubHtml {
if !title.is_empty() {
self.set_title(&title);
}
self.get_annotation(&content);
self.set_data(content);
if let Some(lang) = language {
self.set_language(lang);
Expand Down Expand Up @@ -273,6 +361,7 @@ impl EpubHtml {
if !title.is_empty() {
self.set_title(&title);
}
self.get_annotation(&content);
self.set_data(content);
if let Some(lang) = language {
self.set_language(lang);
Expand Down Expand Up @@ -303,6 +392,10 @@ impl EpubHtml {
self._data = None;
}

pub fn annotation(&self) -> Option<Vec<Annotation>> {
self.annotations.clone()
}

pub fn format(&mut self) -> Option<String> {
self.data_mut();
Some(to_html(self, false, &None))
Expand Down
2 changes: 1 addition & 1 deletion lib/src/epub/html.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ops::Deref;

use super::common;
use crate::{common::get_media_type, prelude::*};
use crate::{common::get_media_type, epub::core::Annotation, prelude::*};
use quick_xml::events::Event;

/// 生成html
Expand Down
Loading