122 lines
No EOL
3.7 KiB
Rust
122 lines
No EOL
3.7 KiB
Rust
mod args;
|
|
mod rules;
|
|
mod utils;
|
|
|
|
use std::fmt::{Display, Formatter};
|
|
use eyre::Result;
|
|
use clap::Parser;
|
|
use walkdir::{DirEntry, WalkDir};
|
|
|
|
use args::Args;
|
|
use rules::*;
|
|
use utils::status_icon::*;
|
|
|
|
const VIDEO_EXTENSIONS: [&str; 14] = ["mkv", "mp4", "avi", "webm", "mov", "wmv", "flv", "ogg", "ogv", "yuv", "amv", "mpg", "mpeg", "m4v"];
|
|
const SERIES_REGEX: &str = r"^(?P<title>.+)\s(?P<titleSeparator>-\s)?S(?P<season>\d\d)E(?P<episode>\d{2,3})(E(?P<episode2>\d{2,3}))?((?P<nameSeparator>\s-\s)?(?P<name>.+))?\.(?P<ext>...)$";
|
|
// const FILE_EXT_REGEX: &str = r"^(?P<title>.+)\.(?P<ext>...)$";
|
|
// const MOVIE_REGEX: &str = r"^(?P<title>.+)\s(?P<year>\(\d{4}\))\s(?P<resolution>\[.+\])\.(?P<ext>...)$";
|
|
|
|
struct Stats {
|
|
success: usize,
|
|
warning: usize,
|
|
error: usize,
|
|
files: usize,
|
|
}
|
|
|
|
impl Display for Stats {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"Files: {} - Success: {} - Warnings: {} - Errors: {}",
|
|
self.files,
|
|
self.success,
|
|
self.warning,
|
|
self.error)
|
|
}
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let params = Args::parse();
|
|
|
|
println!("{}", params.path);
|
|
|
|
let mut stats = Stats {
|
|
files: 0,
|
|
success: 0,
|
|
warning: 0,
|
|
error: 0,
|
|
};
|
|
|
|
for entry in WalkDir::new(params.path) {
|
|
if let Ok(file) = entry {
|
|
check_file(file, &mut stats, params.no_emoji, params.show_success);
|
|
}
|
|
}
|
|
|
|
println!("{}", stats);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn check_file(file: DirEntry, stats: &mut Stats, no_emoji: bool, show_success: bool) -> () {
|
|
let file_type = file.file_type();
|
|
if file_type.is_file() {
|
|
let filename = file.file_name().to_str().unwrap();
|
|
match lint_file_name(&file, filename) {
|
|
ComplianceStatus::NotMatched => {
|
|
stats.files += 1;
|
|
stats.error += 1;
|
|
println!("{} {} --- (Failed to match)", get_status_icon(StatusIcon::Failure, no_emoji), filename)
|
|
}
|
|
ComplianceStatus::NonCompliant(reason) => {
|
|
stats.files += 1;
|
|
stats.warning += 1;
|
|
println!("{} {} --- ({})", get_status_icon(StatusIcon::Warning, no_emoji), filename, reason);
|
|
}
|
|
ComplianceStatus::Compliant => {
|
|
stats.files += 1;
|
|
stats.success += 1;
|
|
if show_success {
|
|
println!("{} {}", get_status_icon(StatusIcon::Success, no_emoji), filename)
|
|
}
|
|
}
|
|
ComplianceStatus::Ignored => {}
|
|
}
|
|
} else if file_type.is_dir() {
|
|
println!("\n\n=== {} {}", get_status_icon(StatusIcon::Directory, no_emoji), file.path().display())
|
|
}
|
|
}
|
|
|
|
fn lint_file_name(file: &DirEntry, filename: &str) -> ComplianceStatus {
|
|
if let Some(ext) = file.path().extension() {
|
|
if !VIDEO_EXTENSIONS.contains(&ext.to_str().unwrap()) {
|
|
return ComplianceStatus::Ignored;
|
|
}
|
|
}
|
|
|
|
let captures = regex::Regex::new(SERIES_REGEX).unwrap().captures(filename);
|
|
|
|
if captures.is_none() {
|
|
return ComplianceStatus::NotMatched;
|
|
}
|
|
|
|
let captures = captures.unwrap();
|
|
|
|
if let Some(reason) = HasEpisodeName::check(filename, &captures) {
|
|
return ComplianceStatus::NonCompliant(reason);
|
|
}
|
|
|
|
if let Some(reason) = MissingSeparator::check(filename, &captures) {
|
|
return ComplianceStatus::NonCompliant(reason);
|
|
}
|
|
|
|
if let Some(reason) = DashInTitle::check(filename, &captures) {
|
|
return ComplianceStatus::NonCompliant(reason);
|
|
}
|
|
|
|
if let Some(reason) = HasFluff::check(filename, &captures) {
|
|
return ComplianceStatus::NonCompliant(reason);
|
|
}
|
|
|
|
ComplianceStatus::Compliant
|
|
} |