diff --git a/Cargo.toml b/Cargo.toml index 67e2950..eddbaf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [ "derive", "lib"] +members = [ "derive", "lib", "cli"] resolver = "2" [workspace.package] @@ -11,6 +11,6 @@ description = "epub、mobi电子书读写" repository = "https://github.com/inkroom/iepub" readme = "./README.md" keywords = ["epub","mobi","azw","ebook"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + [patch.crates-io] iepub = { path = "lib" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 0000000..893015c --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "iepub-cli" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +description = { workspace = true } + +[dependencies] +md-5 = {version = "0.10.6", optional = true } +iepub = { path = "../lib", version = "1.3.1" } diff --git a/cli/build.rs b/cli/build.rs new file mode 100644 index 0000000..694cccb --- /dev/null +++ b/cli/build.rs @@ -0,0 +1,18 @@ +use std::path::Path; + +fn main() { + let out_path = std::env::var("OUT_DIR").expect("OUT_DIR not found"); + let m = format!( + r##" + pub const PROJECT_NAME :&str = r#"{}"#; + pub const PKG_VERSION :&str = r#"{}"#; + "##, + std::env::var("CARGO_PKG_NAME").expect("CARGO_PKG_NAME not found"), + std::env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION not found") + ); + + let path = Path::new(out_path.as_str()).join("version.rs"); + std::fs::write(path, m).expect("write version fail"); + println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME"); + println!("cargo:rerun-if-env-changed=CARGO_PKG_VERSION"); +} diff --git a/lib/src/cli/arg.rs b/cli/src/arg.rs similarity index 99% rename from lib/src/cli/arg.rs rename to cli/src/arg.rs index 25dec5d..a626422 100644 --- a/lib/src/cli/arg.rs +++ b/cli/src/arg.rs @@ -466,7 +466,7 @@ impl OptUtil for &[ArgOption] { #[cfg(test)] mod tests { - use crate::cli::arg::{OptUtil, OptionType}; + use crate::arg::{OptUtil, OptionType}; use super::{parse_command_arg, parse_global_arg, Arg, CommandOptionDef, OptionDef}; fn create_option_def() -> Vec { diff --git a/lib/src/cli/command.rs b/cli/src/command.rs similarity index 99% rename from lib/src/cli/command.rs rename to cli/src/command.rs index 488309d..41deb23 100644 --- a/lib/src/cli/command.rs +++ b/cli/src/command.rs @@ -1,7 +1,7 @@ use std::io::Write; use crate::{ - cli::arg::{self, OptUtil}, + arg::{self, OptUtil}, exec_err, msg, }; use iepub::prelude::*; @@ -121,14 +121,14 @@ fn read_book(file: &str) -> IResult { } pub(crate) mod epub { - + use std::vec; - use crate::cli::arg::OptUtil; - use crate::cli::command::get_single_input; - use crate::cli::command::is_overiade; - use crate::cli::command::out_file; - use crate::cli::command::write_file; + use crate::arg::OptUtil; + use crate::command::get_single_input; + use crate::command::is_overiade; + use crate::command::out_file; + use crate::command::write_file; use crate::exec_err; use crate::Book; use iepub::prelude::adapter::add_into_epub; @@ -143,7 +143,7 @@ pub(crate) mod epub { use iepub::prelude::MobiWriter; use crate::{ - cli::arg::{self, ArgOption, CommandOptionDef, OptionDef, OptionType}, + arg::{self, ArgOption, CommandOptionDef, OptionDef, OptionType}, msg, Command, }; @@ -1117,10 +1117,8 @@ pub(crate) mod mobi { use iepub::prelude::{adapter::mobi_to_epub, EpubWriter, MobiNav, MobiWriter}; use crate::{ - cli::{ - arg::{self, ArgOption, OptUtil, OptionDef, OptionType}, - command::out_file, - }, + arg::{self, ArgOption, OptUtil, OptionDef, OptionType}, + command::out_file, exec_err, msg, Book, Command, }; diff --git a/lib/src/cli/log.rs b/cli/src/log.rs similarity index 92% rename from lib/src/cli/log.rs rename to cli/src/log.rs index d950bbc..a54b35a 100644 --- a/lib/src/cli/log.rs +++ b/cli/src/log.rs @@ -7,7 +7,7 @@ pub(crate) fn set_enable_log(value: bool) { macro_rules! msg { ( $($arg:tt)+) => { unsafe{ - if $crate::cli::log::IS_LOG { + if $crate::log::IS_LOG { println!($($arg)+) } } diff --git a/lib/src/main.rs b/cli/src/main.rs similarity index 95% rename from lib/src/main.rs rename to cli/src/main.rs index 84132f6..ca222b1 100644 --- a/lib/src/main.rs +++ b/cli/src/main.rs @@ -2,12 +2,12 @@ //! //! tool -i file.epub get-cover 1.jpg //! - -mod cli; +mod arg; +mod command; +mod log; use std::{env, fs::File}; - -use cli::arg::{Arg, ArgOption, OptionDef, OptionType}; +use crate::arg::{Arg, ArgOption, OptionDef, OptionType}; use commands::{epub, mobi}; use iepub::prelude::*; @@ -24,7 +24,7 @@ fn create_option_def() -> Vec { mod commands { macro_rules! register_command { ($($cmd_type:ident),*) => { - pub(crate) fn create_command_option_def() -> Vec<$crate::cli::arg::CommandOptionDef> { + pub(crate) fn create_command_option_def() -> Vec<$crate::arg::CommandOptionDef> { vec![ $( $cmd_type::def(), @@ -43,7 +43,7 @@ mod commands { }; } pub(crate) mod epub { - use crate::cli::command::epub::*; + use crate::command::epub::*; // 注册子命令 #[cfg(feature = "md-5")] @@ -73,7 +73,7 @@ mod commands { ); } pub(crate) mod mobi { - use crate::cli::command::mobi::*; + use crate::command::mobi::*; register_command!( BookInfoGetter, GetImage, @@ -170,10 +170,10 @@ fn main() { let mut s: Vec = env::args().collect(); let exe_file_name = s.remove(0); //把第一个参数去掉 - let (mut arg, index) = cli::arg::parse_global_arg(s, create_option_def()).unwrap(); + let (mut arg, index) = arg::parse_global_arg(s, create_option_def()).unwrap(); // 设置日志 - cli::log::set_enable_log(arg.find_opt("l").is_some()); + log::set_enable_log(arg.find_opt("l").is_some()); if print_useage(&arg, &exe_file_name) { return; @@ -187,7 +187,7 @@ fn main() { if let Some((input_type, _)) = input_type { // 解析参数 // 解析后续参数 - cli::arg::parse_command_arg( + arg::parse_command_arg( &mut arg, env::args().skip(index + 1).map(|f| f.to_string()).collect(), if input_type == 0 { diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 808271c..694b9d2 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "iepub-derive" -version = { workspace=true } +version = { workspace = true } edition = { workspace = true } license = { workspace = true } description = { workspace = true } + [lib] proc-macro = true -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 707bcf2..bbd6d6c 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -10,19 +10,18 @@ keywords = { workspace = true } rust-version = { workspace = true } [dependencies] -zip = "7.2.0" -anyhow = "1.0.100" -quick-xml = { version = "0.39.0" } +zip = "8.1.0" +anyhow = "1.0.102" +quick-xml = { version = "0.39.2" } ab_glyph = { version = "0.2.32", optional = true } imageproc = { version = "0.26.0", optional = true} serde_json = { version = "1.0.149", optional = true } iepub-derive = { path = "../derive", version = "1.3.1" } serde = { version = "1.0.228", features = ["derive"], 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.13.1", features = ["blocking"] } +reqwest = { version = "0.13.2", features = ["blocking"] } [features] no_nav=[] diff --git a/lib/src/adapter/core.rs b/lib/src/adapter/core.rs index 28c6430..2ca9e2b 100644 --- a/lib/src/adapter/core.rs +++ b/lib/src/adapter/core.rs @@ -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("作者") @@ -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") @@ -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, _, _) = add_into_epub(builder, &mut book2, len, a_len, 0, None, &[]).unwrap(); let b = builder.book().unwrap(); @@ -859,13 +859,13 @@ mod tests { let assets = vec![ MobiAssets { _file_name: "1.jpg".to_string(), - media_type: String::new(), + _media_type: String::new(), _data: None, recindex: 55, }, MobiAssets { _file_name: "2.jpg".to_string(), - media_type: String::new(), + _media_type: String::new(), _data: None, recindex: 56, }, diff --git a/lib/src/cli/mod.rs b/lib/src/cli/mod.rs deleted file mode 100644 index f389aad..0000000 --- a/lib/src/cli/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub(crate) mod arg; -pub(crate) mod command; -pub(crate) mod log; diff --git a/lib/src/epub/core.rs b/lib/src/epub/core.rs index 48afeb1..89128b5 100644 --- a/lib/src/epub/core.rs +++ b/lib/src/epub/core.rs @@ -325,7 +325,7 @@ impl EpubHtml { } pub fn raw_data(&mut self) -> Option<&str> { - let (id, origin) = if let Some(index) = self._file_name.find('#') { + let (_, origin) = if let Some(index) = self._file_name.find('#') { ( Some(&self._file_name[(index + 1)..]), self._file_name[0..index].to_string(), @@ -410,7 +410,7 @@ impl EpubHtml { self } - fn get_links(&mut self) -> Option<&mut Vec> { + pub fn get_links(&mut self) -> Option<&mut Vec> { self.links.as_mut() } diff --git a/lib/src/epub/html.rs b/lib/src/epub/html.rs index 96debb3..eb1bb7f 100644 --- a/lib/src/epub/html.rs +++ b/lib/src/epub/html.rs @@ -61,10 +61,10 @@ pub(crate) fn to_html(chap: &mut EpubHtml, append_title: bool, dir: &Option "#, - chap - .body_attribute + chap.body_attribute .as_ref() - .and_then(|f| String::from_utf8(f.clone()).ok()).unwrap_or_default(), + .and_then(|f| String::from_utf8(f.clone()).ok()) + .unwrap_or_default(), if append_title { format!(r#"

{}

"#, title) } else { @@ -367,7 +367,7 @@ pub(crate) fn do_to_opf(book: &mut EpubBook, generator: &str) -> IResult } xml.write_event(Event::Start(spine.borrow()))?; // 把封面放第一个 nav,导航第二个 - if let Some(co) = book.cover_chapter() { + if let Some(_) = book.cover_chapter() { xml.create_element("itemref") .with_attribute(("idref", "cover")) .write_empty()?; diff --git a/lib/src/epub/reader.rs b/lib/src/epub/reader.rs index 4fe5332..c00c9e4 100644 --- a/lib/src/epub/reader.rs +++ b/lib/src/epub/reader.rs @@ -226,37 +226,39 @@ fn read_guide_xml( let mut buf = Vec::new(); loop { match reader.read_event_into(&mut buf) { - Ok(Event::Start(e)) => if e.name().as_ref() == b"reference" { - // - // 读取封面页的时候,不一定已经获取到了章节 - if let Some(_t) = e - .try_get_attribute("type") - .ok() - .and_then(|f| f) - .map(|f| { - f.unescape_value() - .map_or_else(|_| String::new(), |v| v.to_string()) - }) - .filter(|f| f == "cover") - { - if let Some(href) = - e.try_get_attribute("href").ok().and_then(|f| f).map(|f| { + Ok(Event::Start(e)) => { + if e.name().as_ref() == b"reference" { + // + // 读取封面页的时候,不一定已经获取到了章节 + if let Some(_t) = e + .try_get_attribute("type") + .ok() + .and_then(|f| f) + .map(|f| { f.unescape_value() .map_or_else(|_| String::new(), |v| v.to_string()) }) + .filter(|f| f == "cover") { - book.cover_chapter = Some(EpubHtml::default().with_file_name(href)); + if let Some(href) = + e.try_get_attribute("href").ok().and_then(|f| f).map(|f| { + f.unescape_value() + .map_or_else(|_| String::new(), |v| v.to_string()) + }) + { + book.cover_chapter = Some(EpubHtml::default().with_file_name(href)); + } + break; } - break; } - }, + } Ok(Event::Empty(e)) => { match e.name().as_ref() { b"reference" => { // // 读取封面页的时候,不一定已经获取到了章节 - if let Some(t) = e + if let Some(_) = e .try_get_attribute("type") .ok() .and_then(|f| f) @@ -282,9 +284,11 @@ fn read_guide_xml( } } } - Ok(Event::End(e)) => if e.name().as_ref() == b"guide" { - break; - }, + Ok(Event::End(e)) => { + if e.name().as_ref() == b"guide" { + break; + } + } Ok(Event::Eof) => { break; @@ -753,7 +757,11 @@ fn read_nav_xhtml(xhtml: &str, root_path: String, book: &mut EpubBook) -> IResul .attributes() .find(|a| a.as_ref().map(|a| a.key.0 == b"class").unwrap_or(false)) { - if class.as_ref().map(|a| &*a.value == b"toc-label").unwrap_or(false) { + if class + .as_ref() + .map(|a| &*a.value == b"toc-label") + .unwrap_or(false) + { in_label = true } } @@ -1026,7 +1034,6 @@ pub fn is_epub(value: &mut T) -> IResult { #[cfg(test)] mod tests { - use std::fs; use crate::{ common::tests::download_epub_file, epub::reader::{get_img_src, read_meta_xml}, @@ -1172,9 +1179,9 @@ html name, "https://github.com/user-attachments/files/19544787/epub-book.epub.zip", ) - .as_str(), + .as_str(), ) - .unwrap(); + .unwrap(); let nav = book.nav().as_slice(); @@ -1245,8 +1252,8 @@ html .unwrap() .to_vec() ) - .unwrap() - .len() + .unwrap() + .len() ); } /// 测试epub3的读取资源文件 @@ -1379,4 +1386,4 @@ html let book = read_from_file(name).unwrap(); assert!(book.cover().is_some()); } -} \ No newline at end of file +} diff --git a/lib/src/mobi/core.rs b/lib/src/mobi/core.rs index 1975fe9..a3e8b12 100644 --- a/lib/src/mobi/core.rs +++ b/lib/src/mobi/core.rs @@ -145,7 +145,7 @@ cache_struct! { #[derive(Debug)] pub struct MobiAssets { pub(crate) _file_name: String, - pub(crate) media_type: String, + pub(crate) _media_type: String, pub(crate) _data: Option>, pub(crate) recindex: usize, } @@ -154,7 +154,7 @@ impl MobiAssets { pub fn new(data: Vec) -> Self { MobiAssets { _file_name: String::new(), - media_type: String::new(), + _media_type: String::new(), _data: Some(data), recindex: 0, } @@ -384,7 +384,7 @@ impl MobiReader { chapters, cover: cover.map(|f| MobiAssets { _file_name: f.get_file_name(), - media_type: String::new(), + _media_type: String::new(), _data: Some(f.0), recindex: 0, }), diff --git a/lib/src/mobi/nav.rs b/lib/src/mobi/nav.rs index 6b1af0e..177f79b 100644 --- a/lib/src/mobi/nav.rs +++ b/lib/src/mobi/nav.rs @@ -157,7 +157,7 @@ pub(crate) struct NavFilePos { /// 占位符长度 pub(crate) length: usize, /// 对应的nav id - id: usize, + _id: usize, /// 对应的章节id pub(crate) chap_id: usize, pub(crate) child: Vec, @@ -189,7 +189,7 @@ fn generate_human_nav_item_xml(start: usize, nav: &[MobiNav]) -> (Vec, Vec FilePosAttr for BytesStart<'a> { mod tests { use std::{ collections::HashMap, - sync::atomic::{AtomicBool, AtomicUsize}, + sync::atomic:: AtomicUsize, }; use quick_xml::events::BytesStart; diff --git a/lib/src/mobi/reader.rs b/lib/src/mobi/reader.rs index 30bc5ff..0f6e2c5 100644 --- a/lib/src/mobi/reader.rs +++ b/lib/src/mobi/reader.rs @@ -538,7 +538,7 @@ impl MobiReader { MobiAssets { _file_name: format!("{}.{}", f, get_suffix(image.as_slice())), - media_type: String::new(), + _media_type: String::new(), _data: Some(image), recindex: *f, } diff --git a/lib/src/mobi/writer.rs b/lib/src/mobi/writer.rs index dce1ead..e3bd575 100644 --- a/lib/src/mobi/writer.rs +++ b/lib/src/mobi/writer.rs @@ -319,8 +319,8 @@ impl EXTHHeader { } struct PDBRecord { - index: usize, - magic: Option, + _index: usize, + _magic: Option, data: Vec, } /// 从字节开头查找是否有合法的utf8字符,有一个即可返回true,即便后面的字节可能不合法 @@ -510,8 +510,8 @@ impl MobiWriter { .flat_map(|f| f.data()) .enumerate() .map(|(index, f)| PDBRecord { - index, - magic: None, + _index:index, + _magic: None, data: f.to_vec(), }) .collect() @@ -642,8 +642,8 @@ impl MobiWriter { all_text_len += data.len(); res.push(PDBRecord { - index: res.len(), - magic: None, + _index: res.len(), + _magic: None, data, }); } @@ -653,8 +653,8 @@ impl MobiWriter { let mut first_non_text_record_idx = res.len() + 1; if all_text_len % 4 != 0 { res.push(PDBRecord { - index: last_text_record_idx, - magic: None, + _index: last_text_record_idx, + _magic: None, data: (0..(all_text_len % 4)).map(|_| 0).collect(), }); first_non_text_record_idx += 1; @@ -759,8 +759,8 @@ impl MobiWriter { if let Some(cover) = book.cover() { // 封面始终保持在第一个 assets.push(PDBRecord { - index: assets.len() + text.len(), - magic: None, + _index: assets.len() + text.len(), + _magic: None, data: cover.data().as_ref().unwrap().to_vec(), }); } diff --git a/lib/src/path.rs b/lib/src/path.rs index 2718b2e..6ac1605 100644 --- a/lib/src/path.rs +++ b/lib/src/path.rs @@ -6,7 +6,7 @@ pub struct Path { /// 逐级路径 paths: Vec, /// home目录 - home: String, + _home: String, /// 分隔符 sep: String, } @@ -26,7 +26,7 @@ impl Path { Self { paths: Vec::new(), sep: sep.to_string(), - home: String::new(), + _home: String::new(), } .join(path) }