2019-04-05 17:51:32 +02:00
|
|
|
use std::ffi::OsString;
|
|
|
|
use std::fs::ReadDir;
|
|
|
|
use std::path::PathBuf;
|
2019-02-11 22:41:08 +01:00
|
|
|
|
|
|
|
use regex::Regex;
|
2019-04-05 17:51:32 +02:00
|
|
|
use structopt::StructOpt;
|
|
|
|
|
|
|
|
#[derive(Debug, StructOpt)]
|
|
|
|
#[structopt(rename_all = "kebab-case")]
|
|
|
|
pub struct Opt {
|
|
|
|
/// Path of the comic folder to bind
|
|
|
|
///
|
|
|
|
/// If the recursive option is set, consider the folder given as a library containing multiples
|
|
|
|
/// folders. It will not treat the given folder as a comic in itself.
|
|
|
|
// TODO: check if I really do this or not when implementing the recursive option
|
|
|
|
pub comic_folder: PathBuf,
|
|
|
|
|
|
|
|
// TODO: implement the recursivity
|
|
|
|
/// Recursively treat each child folder as a it's own comic to bind
|
|
|
|
#[structopt(short, long)]
|
|
|
|
pub recursive: bool,
|
|
|
|
// TODO: implement the prefix
|
|
|
|
// /// Prefix to use for the files
|
|
|
|
// ///
|
|
|
|
// /// This is usefull when the images contains a number before their page number
|
|
|
|
// /// For example: when the title contains the name of the comic with its season: fooS02-42.png
|
|
|
|
// #[structopt(short, long)]
|
|
|
|
// pub prefix: &str,
|
|
|
|
}
|
2019-02-11 22:41:08 +01:00
|
|
|
|
2019-04-05 17:51:32 +02:00
|
|
|
impl Opt {
|
|
|
|
pub fn new<I, T>(args: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = T>,
|
|
|
|
T: Into<OsString> + Clone,
|
|
|
|
{
|
|
|
|
Opt::from_iter(args)
|
|
|
|
}
|
|
|
|
}
|
2019-02-11 22:41:08 +01:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2019-04-05 17:51:32 +02:00
|
|
|
struct Page {
|
2019-02-11 22:41:08 +01:00
|
|
|
prefix: String,
|
|
|
|
number: String,
|
|
|
|
suffix: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Page {
|
|
|
|
fn new(prefix: String, number: String, suffix: String) -> Page {
|
|
|
|
println!("N p:{} n: {} s: {}", prefix, number, suffix);
|
|
|
|
Page {
|
2019-05-23 14:20:58 +02:00
|
|
|
prefix,
|
|
|
|
number,
|
|
|
|
suffix,
|
2019-02-11 22:41:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn original_filename(&self) -> String {
|
|
|
|
println!("OF p:{} n: {} s: {}", self.prefix, self.number, self.suffix);
|
|
|
|
format!("{}{}{}", self.prefix, self.number, self.suffix)
|
|
|
|
}
|
|
|
|
|
2019-05-23 14:20:58 +02:00
|
|
|
fn new_filename(&self, pad: usize) -> String {
|
2019-04-05 17:51:32 +02:00
|
|
|
println!(
|
2019-05-23 14:20:58 +02:00
|
|
|
"NF p: '{}' n: '{}' s: '{}'",
|
|
|
|
self.prefix, self.number, self.suffix
|
2019-04-05 17:51:32 +02:00
|
|
|
);
|
|
|
|
// format!("{:0pad$}-{}{}{}", number, self.prefix, self.number, self.suffix, pad = pad)
|
|
|
|
// TODO I think I will need this on in the end
|
|
|
|
format!(
|
|
|
|
"{}{:0pad$}{}",
|
|
|
|
self.prefix,
|
|
|
|
self.number.parse::<u32>().unwrap(),
|
|
|
|
self.suffix,
|
|
|
|
pad = pad
|
|
|
|
)
|
2019-02-11 22:41:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ComicBook {
|
2019-05-23 14:20:58 +02:00
|
|
|
pad: Option<u64>,
|
2019-02-11 22:41:08 +01:00
|
|
|
pages: Vec<Page>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ComicBook {
|
|
|
|
pub fn new(files: ReadDir) -> ComicBook {
|
|
|
|
let regex = Regex::new(r"\./(?P<prefix>\D*)(?P<number>\d*)(?P<suffix>.*)").unwrap();
|
|
|
|
ComicBook {
|
2019-05-23 14:20:58 +02:00
|
|
|
pad: None,
|
2019-02-11 22:41:08 +01:00
|
|
|
pages: files
|
|
|
|
.map(|entry| entry.unwrap().path())
|
|
|
|
.filter(|entry| entry.is_file())
|
|
|
|
.map(|entry| {
|
|
|
|
let caps = regex.captures(entry.to_str().unwrap()).unwrap();
|
|
|
|
Page::new(
|
|
|
|
String::from(caps.name("prefix").map_or("", |c| c.as_str())),
|
2019-04-05 17:51:32 +02:00
|
|
|
String::from(&caps["number"]), // FIXME => ignore the file?
|
2019-02-11 22:41:08 +01:00
|
|
|
String::from(caps.name("suffix").map_or("", |c| c.as_str())),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
//~ book: path.iter().map(|name| Page::new(name)).collect(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bind(&mut self) {
|
2019-04-05 17:51:32 +02:00
|
|
|
let pad = self.get_pad_size().unwrap();
|
2019-02-11 22:41:08 +01:00
|
|
|
|
|
|
|
for page in self.pages.iter() {
|
2019-05-23 14:20:58 +02:00
|
|
|
//if let Some(pos) = page.position {
|
|
|
|
let original_file = page.original_filename();
|
|
|
|
let new_file = page.new_filename(dbg!(pad));
|
2019-02-11 22:41:08 +01:00
|
|
|
|
2019-05-23 14:20:58 +02:00
|
|
|
println!("{} -> {}", original_file, dbg!(new_file));
|
2019-02-11 22:41:08 +01:00
|
|
|
|
2019-05-23 14:20:58 +02:00
|
|
|
// fs::rename(original_file, new_file).expect("RENAME FAILED");
|
|
|
|
//}
|
2019-02-11 22:41:08 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-05 17:51:32 +02:00
|
|
|
|
|
|
|
fn get_pad_size(&self) -> Option<usize> {
|
2019-05-23 14:20:58 +02:00
|
|
|
Some(
|
|
|
|
self.pages
|
|
|
|
.iter()
|
|
|
|
.max_by_key(|x| x.number.len())?
|
|
|
|
.number
|
|
|
|
.len(),
|
|
|
|
)
|
2019-04-05 17:51:32 +02:00
|
|
|
}
|
2019-02-11 22:41:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use std::path::Path;
|
|
|
|
//~ use std::sys_common::io::test::{TempDir, tmpdir};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn comic_book_creation() {
|
|
|
|
//~ let tmpdir = tmpdir();
|
|
|
|
//~ println!("{}", tmpdir);
|
|
|
|
//~ let comic = ComicBook::new(&[
|
|
|
|
//~ Path::new("01.png").to_path_buf(),
|
|
|
|
//~ Path::new("02.png").to_path_buf(),
|
|
|
|
//~ ]);
|
|
|
|
|
|
|
|
//~ println!("{:?}", comic.book);
|
|
|
|
|
|
|
|
assert!(false);
|
|
|
|
//~ assert_eq!(comic.book, [Page {filename: "01.png", position: None}, Page {filename: "02.png", position: None}]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//~ #[test]
|
|
|
|
//~ fn detection_alpha() {
|
|
|
|
//~ let l = Unsorted(vec!["1", "2", "10"]);
|
|
|
|
//~ assert_eq!(l.detect_sort_type(), false);
|
|
|
|
//~ }
|
|
|
|
|
|
|
|
//~ #[test]
|
|
|
|
//~ fn detection_numerical() {
|
|
|
|
//~ let l = Unsorted(vec!["01", "02", "10"]);
|
|
|
|
//~ assert_eq!(l.detect_sort_type(), true);
|
|
|
|
//~ }
|
|
|
|
}
|