mod cli;
use std::{env, fs::File};
use cli::arg::{Arg, ArgOption, OptionDef, OptionType};
use commands::{epub, mobi};
use iepub::prelude::*;
fn create_option_def() -> Vec<OptionDef> {
vec![
OptionDef::create("i", "输入文件路径", OptionType::String, true),
OptionDef::over(),
OptionDef::create("l", "打开终端日志输出", OptionType::NoParamter, false),
]
}
mod commands {
macro_rules! register_command {
($($cmd_type:ident),*) => {
pub(crate) fn create_command_option_def() -> Vec<$crate::cli::arg::CommandOptionDef> {
vec![
$(
$cmd_type::def(),
)*
]
}
pub(crate) fn support_command() -> Vec<Box<dyn $crate::Command>> {
vec![
$(
Box::<$cmd_type>::default(),
)*
]
}
};
}
pub(crate) mod epub {
use crate::cli::command::epub::*;
#[cfg(feature = "md-5")]
register_command!(
GetCover,
BookInfoGetter,
BookInfoSetter,
NavScanner,
GetImage,
GetChapter,
FormatConvert,
Concat,
Replace,
Optimize
);
#[cfg(not(feature = "md-5"))]
register_command!(
GetCover,
BookInfoGetter,
BookInfoSetter,
NavScanner,
GetImage,
GetChapter,
FormatConvert,
Concat,
Replace
);
}
pub(crate) mod mobi {
use crate::cli::command::mobi::*;
register_command!(
BookInfoGetter,
GetImage,
GetCover,
Unpack,
FormatConvert,
NavScanner,
GetChapter,
Replace
);
}
}
pub(crate) trait Command {
fn name(&self) -> String;
fn exec(&self, book: &mut Book, global_opts: &[ArgOption], opts: &[ArgOption], args: &[String]);
}
pub(crate) enum Book<'a> {
EPUB(&'a mut EpubBook),
MOBI(&'a mut MobiBook),
}
fn check_input_type(arg: &Arg) -> Option<(usize, String)> {
let check_method: Vec<fn(&mut File) -> IResult<bool>> = vec![
iepub::prelude::check::is_epub,
iepub::prelude::check::is_mobi,
];
if let Some(opt) = arg.find_opt("i") {
let path = opt.value.as_ref().unwrap().as_str();
msg!("opening file {}", path);
let v = std::fs::File::open(path);
if let Err(e) = v {
exec_err!("open file err: {}", e);
}
let mut fs = v.unwrap();
for (index, ele) in check_method.iter().enumerate() {
if ele(&mut fs).unwrap_or(false) {
return Some((index, path.to_string()));
}
}
exec_err!("unsupport file format");
}
None
}
mod info {
include!(concat!(env!("OUT_DIR"), "/version.rs"));
}
fn print_useage(arg: &Arg, exe_file_name: &str) -> bool {
if arg.find_opt("h").is_some() {
println!(
"Usage: {} [options...] [command] [command options...] ",
exe_file_name
);
println!(
"Example: {} -i input.epub get-cover out.jpg\n",
exe_file_name
);
for ele in create_option_def() {
println!("{}", ele);
}
println!("\nsupported sub command for epub:\n");
for ele in commands::epub::create_command_option_def() {
println!("{}", ele);
}
println!("\nsupported sub command for mobi:\n");
for ele in commands::mobi::create_command_option_def() {
println!("{}", ele);
}
println!("version: {}", info::PKG_VERSION);
return true;
}
false
}
fn main() {
let mut s: Vec<String> = env::args().collect();
let exe_file_name = s.remove(0);
let (mut arg, index) = cli::arg::parse_global_arg(s, create_option_def()).unwrap();
cli::log::set_enable_log(arg.find_opt("l").is_some());
if print_useage(&arg, &exe_file_name) {
return;
}
let input_type = check_input_type(&arg);
if input_type.is_none() {
exec_err!("has no file, please use -i <file>");
}
if let Some((input_type, _)) = input_type {
cli::arg::parse_command_arg(
&mut arg,
env::args().skip(index + 1).map(|f| f.to_string()).collect(),
if input_type == 0 {
epub::create_command_option_def()
} else {
mobi::create_command_option_def()
},
);
}
let (res, path) = input_type.unwrap();
if res == 0 {
match read_from_file(path.as_str()) {
Ok(mut book) => {
exec_epub(&arg, &mut book, exe_file_name.as_str());
}
Err(e) => {
exec_err!("err: {}", e);
}
}
} else if res == 1 {
match iepub::prelude::MobiReader::new(std::fs::File::open(path).unwrap_or_else(|s| {
exec_err!("err: {}", s);
}))
.and_then(|mut f| f.load())
{
Ok(mut book) => {
exec_mobi(&arg, &mut book, exe_file_name.as_str());
}
Err(e) => {
exec_err!("err: {}", e);
}
}
}
}
fn exec_epub(arg: &Arg, book: &mut EpubBook, exe_file_name: &str) {
let global_opts = arg.opts.as_slice();
let commands = commands::epub::support_command();
for ele in &arg.group {
let m = commands.iter().find(|s| s.name() == ele.command);
if let Some(com) = m {
if ele.opts.iter().any(|s| s.key == "h") {
if let Some(def) = commands::epub::create_command_option_def()
.iter()
.find(|s| s.command == com.name())
{
println!(
"Usage: {} {} {}",
exe_file_name,
com.name(),
if def.support_args != 0 {
"[file_path]"
} else {
""
}
);
for ele in &def.opts {
println!("-{:10} {}", ele.key, ele.desc);
}
}
continue;
}
com.exec(&mut Book::EPUB(book), global_opts, &ele.opts, &ele.args);
}
}
}
fn exec_mobi(arg: &Arg, book: &mut MobiBook, exe_file_name: &str) {
let global_opts = arg.opts.as_slice();
let commands = commands::mobi::support_command();
for ele in &arg.group {
let m = commands.iter().find(|s| s.name() == ele.command);
if let Some(com) = m {
if ele.opts.iter().any(|s| s.key == "h") {
if let Some(def) = commands::mobi::create_command_option_def()
.iter()
.find(|s| s.command == com.name())
{
println!(
"Usage: {} {} {}",
exe_file_name,
com.name(),
if def.support_args != 0 {
"[file_path]"
} else {
""
}
);
for ele in &def.opts {
println!("-{:10} {}", ele.key, ele.desc);
}
}
continue;
}
com.exec(&mut Book::MOBI(book), global_opts, &ele.opts, &ele.args);
}
}
}