- 当未指定输入文件时使用-a参数仍然可以打开输出目录
- 更换终端彩色库以支持Windows默认不启用ANSI转义序列的终端
This commit is contained in:
@ -14,6 +14,7 @@ pub enum AppError {
|
||||
FileDataError,
|
||||
SaveError,
|
||||
SystemTimeError,
|
||||
CannotCreateDir,
|
||||
}
|
||||
|
||||
impl std::error::Error for AppError {}
|
||||
@ -34,8 +35,8 @@ impl std::fmt::Display for AppError {
|
||||
Self::FileDataError => "处理文件数据时出错",
|
||||
Self::SaveError => "保存文件出错",
|
||||
Self::SystemTimeError => "获取时间戳失败",
|
||||
// _ => "未知错误",
|
||||
Self::CannotCreateDir => "无法创建父级目录", // _ => "未知错误",
|
||||
};
|
||||
write!(f, "{}", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use colored::Color::{Cyan, Green, Red, Yellow,Magenta};
|
||||
use colored::Colorize;
|
||||
use crossterm::style::{Color, Stylize}; //防止windows终端乱码
|
||||
use indicatif::MultiProgress;
|
||||
use log::{Log, Metadata, Record, SetLoggerError};
|
||||
use std::sync::Arc;
|
||||
@ -16,6 +15,15 @@ impl Log for MultiProgressLogger {
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
#[cfg(target_os = "windows")]
|
||||
let level = match record.level() {
|
||||
log::Level::Error => ("Error").with(Color::Red),
|
||||
log::Level::Warn => ("Warn").with(Color::Yellow),
|
||||
log::Level::Info => ("Info").with(Color::Green),
|
||||
log::Level::Debug => ("Debug").with(Color::Magenta),
|
||||
log::Level::Trace => ("Trace").with(Color::Cyan),
|
||||
};
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let level = match record.level() {
|
||||
log::Level::Error => ("Error").color(Red),
|
||||
log::Level::Warn => ("Warn").color(Yellow),
|
||||
@ -23,6 +31,7 @@ impl Log for MultiProgressLogger {
|
||||
log::Level::Debug => ("Debug").color(Magenta),
|
||||
log::Level::Trace => ("Trace").color(Cyan),
|
||||
};
|
||||
|
||||
let message = format!(
|
||||
"[{}][{}] {}",
|
||||
chrono::Local::now().format("%H:%M:%S"),
|
||||
@ -42,6 +51,6 @@ pub fn init_logger() -> Result<(), SetLoggerError> {
|
||||
mp: crate::MP.clone(),
|
||||
};
|
||||
log::set_boxed_logger(Box::new(logger))?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
63
src/main.rs
63
src/main.rs
@ -1,6 +1,6 @@
|
||||
use ::clap::Parser;
|
||||
use colored::{Color, Colorize};
|
||||
use crossbeam_channel::{bounded, Sender};
|
||||
use crossterm::style::{Color, Stylize}; //防止windows终端乱码
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info, warn, LevelFilter};
|
||||
@ -23,16 +23,7 @@ use apperror::AppError;
|
||||
use ncmdump::Ncmfile;
|
||||
use time::TimeCompare;
|
||||
|
||||
|
||||
fn main() -> Result<(), AppError> {
|
||||
let timer = match TimeCompare::new() {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
error!("无法初始化时间戳系统。{}", e);
|
||||
exit(1)
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化日志系统
|
||||
match logger::init_logger() {
|
||||
Ok(_) => (),
|
||||
@ -41,11 +32,22 @@ fn main() -> Result<(), AppError> {
|
||||
}
|
||||
};
|
||||
|
||||
let timer = match TimeCompare::new() {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
error!("无法初始化时间戳系统。{}", e);
|
||||
exit(1)
|
||||
}
|
||||
};
|
||||
|
||||
let cli = clap::Cli::parse();
|
||||
|
||||
//设置彩色输出
|
||||
let if_colorful = !cli.nocolor;
|
||||
colored::control::set_override(if_colorful);
|
||||
// let if_colorful = !cli.nocolor;
|
||||
// colored::control::set_override(if_colorful);
|
||||
// crossterm::terminal::enable_raw_mode()
|
||||
//FIXME 更改颜色库
|
||||
//TODO控制颜色输出,更改为使用环境变量
|
||||
|
||||
//获取cpu核心数
|
||||
let cpus = num_cpus::get();
|
||||
@ -58,7 +60,7 @@ fn main() -> Result<(), AppError> {
|
||||
1
|
||||
}
|
||||
}
|
||||
None => cpus,//默认使用cpu核心数作为线程数
|
||||
None => cpus, //默认使用cpu核心数作为线程数
|
||||
};
|
||||
//输入目录
|
||||
let input = cli.input;
|
||||
@ -67,7 +69,7 @@ fn main() -> Result<(), AppError> {
|
||||
// 强制覆盖
|
||||
let forcesave = cli.forcesave;
|
||||
if forcesave {
|
||||
warn!("文件{}已开启!", "强制覆盖".bright_red())
|
||||
warn!("文件{}已开启!", "强制覆盖".with(Color::Red))
|
||||
}
|
||||
let level = match cli.debug {
|
||||
0 | 3 => LevelFilter::Info,
|
||||
@ -77,7 +79,7 @@ fn main() -> Result<(), AppError> {
|
||||
5 => LevelFilter::Trace,
|
||||
_ => LevelFilter::Off,
|
||||
};
|
||||
info!("日志等级:{}", level.to_string());
|
||||
info!("日志等级:{}", level);
|
||||
log::set_max_level(level);
|
||||
|
||||
let undumpfile = pathparse::pathparse(input); // 该列表将存入文件的路径
|
||||
@ -88,16 +90,22 @@ fn main() -> Result<(), AppError> {
|
||||
let mut failure_count = 0; //发生错误的
|
||||
|
||||
if taskcount == 0 {
|
||||
error!("没有找到有效文件。使用-i参数输入需要解密的文件或文件夹。");
|
||||
if cli.autoopen {
|
||||
opendir::autoopen(cli.autoopen, outputdir);
|
||||
} else {
|
||||
error!("没有找到有效文件。使用-i参数输入需要解密的文件或文件夹。使用-a参数自动打开输出文件夹。");
|
||||
}
|
||||
|
||||
exit(2);
|
||||
};
|
||||
// 创建完整的父目录
|
||||
if std::fs::create_dir_all(&outputdir).is_err() {
|
||||
return Err(AppError::CannotCreateDir);
|
||||
}
|
||||
// 初始化线程池
|
||||
let pool = threadpool::Pool::new(max_workers);
|
||||
|
||||
info!(
|
||||
"将启用{}线程",
|
||||
max_workers.to_string().color(Color::BrightGreen)
|
||||
);
|
||||
info!("将启用{}线程", max_workers.to_string().with(Color::Green));
|
||||
// 初始化通讯
|
||||
// let (tx, rx) = mpsc::channel();
|
||||
let (tx, rx) = bounded(taskcount * 6);
|
||||
@ -145,7 +153,7 @@ fn main() -> Result<(), AppError> {
|
||||
Signals::Err(_) => failure_count += 1,
|
||||
_ => (),
|
||||
}
|
||||
if (success_count+ignore_count+failure_count) < taskcount {
|
||||
if (success_count + ignore_count + failure_count) < taskcount {
|
||||
progressbar.inc(1);
|
||||
// messages.log(); //发送log
|
||||
} else {
|
||||
@ -164,19 +172,14 @@ fn main() -> Result<(), AppError> {
|
||||
};
|
||||
info!(
|
||||
"成功解密{}个文件,跳过{}个文件,{}个文件解密失败,{}",
|
||||
success_count.to_string().bright_green(),
|
||||
ignore_count.to_string().purple(),
|
||||
failure_count.to_string().bright_red(),
|
||||
success_count.to_string().with(Color::Green),
|
||||
ignore_count.to_string().with(Color::Magenta),
|
||||
failure_count.to_string().with(Color::Red),
|
||||
showtime()
|
||||
);
|
||||
|
||||
// 自动打开输出文件夹
|
||||
if cli.autoopen {
|
||||
info!("自动打开文件夹:[{}]", outputdir.cyan());
|
||||
opendir::opendir(outputdir.into());
|
||||
} else {
|
||||
info!("输出文件夹:[{}]", outputdir.cyan());
|
||||
};
|
||||
opendir::autoopen(cli.autoopen, outputdir);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
use crate::{messager, AppError};
|
||||
use std::fmt::Debug;
|
||||
// use
|
||||
|
||||
@ -5,13 +5,13 @@ use aes::cipher::{generic_array::GenericArray, BlockDecrypt, KeyInit};
|
||||
use aes::Aes128;
|
||||
use audiotags::{MimeType, Picture, Tag};
|
||||
use base64::{self, Engine};
|
||||
use colored::*;
|
||||
use crossterm::style::{Color, Stylize}; //防止windows终端乱码
|
||||
use log::{debug, info, trace};
|
||||
use messager::Signals;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_json::{self, Value};
|
||||
use std::fmt::Debug;
|
||||
use std::fs::{self, File};
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::from_utf8;
|
||||
@ -132,7 +132,7 @@ impl Ncmfile {
|
||||
let mut buf: Vec<u8> = vec![0; (self.size - self.position) as usize];
|
||||
let _ = reader.read_exact(&mut buf);
|
||||
self.position += length;
|
||||
buf[..].to_vec()
|
||||
buf[..].to_vec()
|
||||
}
|
||||
} else {
|
||||
let mut reader = BufReader::new(&self.file);
|
||||
@ -154,7 +154,7 @@ impl Ncmfile {
|
||||
}
|
||||
///按字节进行0x64异或。
|
||||
fn parse_key(key: &mut [u8]) -> &[u8] {
|
||||
for item in &mut *key {
|
||||
for item in &mut *key {
|
||||
*item ^= 0x64;
|
||||
}
|
||||
key
|
||||
@ -186,6 +186,15 @@ impl Ncmfile {
|
||||
fn unpad(data: &[u8]) -> Vec<u8> {
|
||||
data[..data.len() - data[data.len() - 1] as usize].to_vec()
|
||||
}
|
||||
|
||||
fn get_filename(&self) -> &str {
|
||||
&self.filename
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_fullfilename(&self) -> &str {
|
||||
&self.fullfilename
|
||||
}
|
||||
}
|
||||
|
||||
impl Ncmfile {
|
||||
@ -273,23 +282,25 @@ impl Ncmfile {
|
||||
//处理文件路径
|
||||
trace!("拼接文件路径");
|
||||
let path = {
|
||||
let filename = format!(
|
||||
let output_filename = &format!(
|
||||
"{}.{}",
|
||||
self.filename,
|
||||
self.get_filename(),
|
||||
meta_data
|
||||
.get("format")
|
||||
.ok_or(AppError::CannotReadMetaInfo)?
|
||||
.as_str()
|
||||
.ok_or(AppError::CannotReadMetaInfo)?
|
||||
);
|
||||
)[..];
|
||||
|
||||
// let filename = standardize_filename(filename);
|
||||
debug!("文件名:{}", filename.yellow());
|
||||
// let output_filename = standardize_filename(output_filename);
|
||||
debug!("文件名:{}", output_filename.with(Color::Yellow));
|
||||
|
||||
//已在程序开头创建,无需浪费性能
|
||||
//链级创建输出目录
|
||||
if fs::create_dir_all(outputdir).is_err() {
|
||||
return Err(AppError::FileWriteError);
|
||||
}
|
||||
outputdir.join(filename)
|
||||
// if fs::create_dir_all(outputdir).is_err() {
|
||||
// return Err(AppError::FileWriteError);
|
||||
// }
|
||||
outputdir.join(output_filename)
|
||||
};
|
||||
|
||||
debug!("文件路径: {:?}", path);
|
||||
@ -392,13 +403,13 @@ impl Ncmfile {
|
||||
|
||||
info!(
|
||||
"[{}] 文件已保存到: {}",
|
||||
self.filename.yellow(),
|
||||
path.to_str().ok_or(AppError::SaveError)?.bright_cyan()
|
||||
self.get_filename().with(Color::Yellow),
|
||||
path.to_str().ok_or(AppError::SaveError)?.with(Color::Cyan)
|
||||
);
|
||||
info!(
|
||||
"[{}]{}",
|
||||
self.fullfilename.yellow(),
|
||||
"解密成功".bright_green()
|
||||
self.get_filename().with(Color::Yellow),
|
||||
"解密成功".with(Color::Green)
|
||||
);
|
||||
let _ = messager.send(Signals::End);
|
||||
Ok(())
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
use log::error;
|
||||
use std::{path::PathBuf, process::Command};
|
||||
use crossterm::style::{Color, Stylize};
|
||||
use log::{error, info};
|
||||
use std::{path::PathBuf, process::Command}; //防止windows终端乱码
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn opendir(dir: PathBuf) {
|
||||
if Command::new("explorer")
|
||||
.arg(&dir) // <- Specify the directory you'd like to open.
|
||||
.spawn().is_err()
|
||||
.spawn()
|
||||
.is_err()
|
||||
{
|
||||
error!("无法打开输出文件夹:[{}]", dir.display())
|
||||
}
|
||||
@ -15,7 +17,8 @@ pub fn opendir(dir: PathBuf) {
|
||||
pub fn opendir(dir: PathBuf) {
|
||||
if Command::new("open")
|
||||
.arg(&dir) // <- Specify the directory you'd like to open.
|
||||
.spawn().is_err()
|
||||
.spawn()
|
||||
.is_err()
|
||||
{
|
||||
error!("无法打开输出文件夹:[{}]", dir.display())
|
||||
}
|
||||
@ -24,8 +27,20 @@ pub fn opendir(dir: PathBuf) {
|
||||
pub fn opendir(dir: PathBuf) {
|
||||
if Command::new("open")
|
||||
.arg(&dir) // <- Specify the directory you'd like to open.
|
||||
.spawn().is_err()
|
||||
.spawn()
|
||||
.is_err()
|
||||
{
|
||||
error!("无法打开输出文件夹:[{}]", dir.display())
|
||||
}
|
||||
}
|
||||
|
||||
// 自动打开输出文件夹的跨平台函数
|
||||
pub fn autoopen(if_auto_open: bool, path: String) {
|
||||
let styled_path = (&path[..]).with(Color::Cyan);
|
||||
if if_auto_open {
|
||||
info!("自动打开文件夹:[{}]", styled_path);
|
||||
opendir(path.into());
|
||||
} else {
|
||||
info!("输出文件夹:[{}]", styled_path);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user