change: Improved filename sanitization and some logic

This commit is contained in:
Sayantan Santra 2023-05-28 20:22:23 -05:00
parent 5e5ba7ea0a
commit 6178c022d1
Signed by: SinTan1729
GPG Key ID: EB3E68BFBA25C85F
3 changed files with 69 additions and 52 deletions

View File

@ -21,9 +21,11 @@ pub async fn process_file(
tmdb: &Client,
pattern: &str,
dry_run: bool,
movie_list: Option<&HashMap<String, String>>,
) -> (String, String, bool) {
movie_list: Option<&HashMap<String, Option<String>>>,
// The last bool tells whether the entry should be added to the movie_list or not
// The first String is filename without extension, and the second String is
// new basename, if any.
) -> (String, Option<String>, bool) {
// Set RenderConfig for the menu items
inquire::set_global_render_config(get_render_config());
@ -53,7 +55,7 @@ pub async fn process_file(
Some(list) => {
if list.contains_key(&filename_without_ext) {
preprocessed = true;
list[&filename_without_ext].clone()
list[&filename_without_ext].clone().unwrap_or_default()
} else {
String::new()
}
@ -63,7 +65,7 @@ pub async fn process_file(
// Check if it should be ignored
if preprocessed && new_name_base.is_empty() {
eprintln!(" Ignoring {file_base} as per previous choice for related files...");
return (filename_without_ext, String::new(), false);
return (filename_without_ext, None, false);
}
// Parse the filename for metadata
@ -75,7 +77,7 @@ pub async fn process_file(
println!(" Processing {file_base}...");
} else {
println!(" Ignoring {file_base}...");
return (filename_without_ext, String::new(), false);
return (filename_without_ext, None, false);
}
// Only do the TMDb API stuff if it's not preprocessed
@ -113,7 +115,7 @@ pub async fn process_file(
if let Some(pos) = directors_text.rfind(',') {
directors_text.replace_range(pos..pos + 2, " and ");
}
movie_details.director = directors_text;
movie_details.director = Some(directors_text);
}
}
}
@ -124,7 +126,7 @@ pub async fn process_file(
// If nothing is found, skip
if movie_list.is_empty() {
eprintln!(" Could not find any entries matching {file_base}!");
return (filename_without_ext, String::new(), true);
return (filename_without_ext, None, true);
}
// Choose from the possible entries
@ -141,7 +143,7 @@ pub async fn process_file(
error,
InquireError::OperationCanceled | InquireError::OperationInterrupted
);
return (filename_without_ext, String::new(), flag);
return (filename_without_ext, None, flag);
}
};
@ -196,7 +198,7 @@ pub async fn process_file(
}
}
}
(filename_without_ext, new_name_base, true)
(filename_without_ext, Some(new_name_base), true)
}
// Function to process the passed arguments

View File

@ -74,10 +74,6 @@ async fn main() {
)
.await;
// if movie_name_temp.is_empty() {
// continue;
// }
if add_to_list {
movie_list.insert(filename_without_ext, movie_name_temp);
}
@ -90,22 +86,30 @@ async fn main() {
if movie_list.len() == 1 {
let entry_clean = entry.trim_end_matches('/');
let movie_name = movie_list.into_values().next().unwrap();
// If the file was ignored, exit
if movie_name.is_empty() {
eprintln!("Not renaming directory as only movie was skipped.");
continue;
}
if entry_clean == movie_name {
println!("[directory] '{entry_clean}' already has correct name.");
} else {
println!("[directory] '{entry_clean}' -> '{movie_name}'");
if !settings["dry_run"] {
if !Path::new(movie_name.as_str()).is_dir() {
fs::rename(entry, movie_name)
.expect("Unable to rename directory!");
// If the file was ignored, exit
match movie_name {
None => {
eprintln!("Not renaming directory as only movie was skipped.");
}
Some(name) => {
if entry_clean == name {
println!(
"[directory] '{entry_clean}' already has correct name."
);
} else {
eprintln!("Destination directory already exists, skipping...");
println!("[directory] '{entry_clean}' -> '{name}'",);
if !settings["dry_run"] {
if !Path::new(name.as_str()).is_dir() {
fs::rename(entry, name)
.expect("Unable to rename directory!");
} else {
eprintln!(
"Destination directory already exists, skipping..."
);
}
}
}
}
}

View File

@ -5,8 +5,8 @@ use tmdb_api::movie::MovieShort;
pub struct MovieEntry {
pub title: String,
pub id: u64,
pub director: String,
pub year: String,
pub director: Option<String>,
pub year: Option<String>,
pub language: String,
}
@ -16,39 +16,38 @@ impl MovieEntry {
MovieEntry {
title: movie.inner.title,
id: movie.inner.id,
director: String::from("N/A"),
year: match movie.inner.release_date {
Some(date) => date.format("%Y").to_string(),
_ => String::from("N/A"),
},
director: None,
year: movie
.inner
.release_date
.map(|date| date.format("%Y").to_string()),
language: get_long_lang(movie.inner.original_language.as_str()),
}
}
// Generate desired filename from movie entry
pub fn rename_format(&self, mut format: String) -> String {
const PATTERN: &str = "^~#%$*+={}?@'`/\\\"><|:&!";
// Try to sanitize the title to avoid some characters
let mut title = self.title.clone();
title.retain(|c| !PATTERN.contains(c));
title = sanitize(title);
title.truncate(159);
format = format.replace("{title}", title.as_str());
if self.year != "N/A" {
format = format.replace("{year}", self.year.as_str());
} else {
format = format.replace("{year}", "");
}
format = match &self.year {
Some(year) => format.replace("{year}", year.as_str()),
None => format.replace("{year}", ""),
};
if self.director.as_str() != "N/A" {
// Try to sanitize the director's name to avoid some characters
let mut director = self.director.clone();
director.retain(|c| !PATTERN.contains(c));
director.truncate(63);
format = format.replace("{director}", director.as_str());
} else {
format = format.replace("{director}", "");
}
format = match &self.director {
Some(name) => {
// Try to sanitize the director's name to avoid some characters
let mut director = name.clone();
director = sanitize(director);
director.truncate(63);
format.replace("{director}", director.as_str())
}
None => format.replace("{director}", ""),
};
// Try to clean extra spaces and such
format = format.trim_matches(|c| "- ".contains(c)).to_string();
@ -65,12 +64,12 @@ impl fmt::Display for MovieEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut buffer = String::new();
buffer.push_str(&format!("{} ", self.title));
buffer.push_str(&format!("({}), ", self.year));
buffer.push_str(&format!("({:?}), ", self.year));
buffer.push_str(&format!(
"Language: {}, ",
get_long_lang(self.language.as_str())
));
buffer.push_str(&format!("Directed by: {}, ", self.director));
buffer.push_str(&format!("Directed by: {:?}, ", self.director));
buffer.push_str(&format!("TMDB ID: {}", self.id));
// buffer.push_str(&format!("Synopsis: {}", self.overview));
write!(f, "{buffer}")
@ -118,3 +117,15 @@ pub fn get_long_lang(short: &str) -> String {
};
String::from(long)
}
// Sanitize filename so that there are no errors while
// creating a file/directory
fn sanitize(input: String) -> String {
const AVOID: &str = "^~*+=`/\\\"><|";
let mut out = input;
out.retain(|c| !AVOID.contains(c));
out = out.replace(':', "");
out = out.replace('?', "");
out
}