diff --git a/src/unpacker.rs b/src/unpacker.rs index 55349c9..3e8e364 100644 --- a/src/unpacker.rs +++ b/src/unpacker.rs @@ -1,6 +1,9 @@ -use std::{fs, path::Path}; +use std::{ + fs, + path::{Path, PathBuf}, +}; -use anyhow::anyhow; +use anyhow::{Ok, anyhow}; use log::error; use zip::ZipArchive; @@ -29,6 +32,8 @@ pub fn unpack(archive_path: impl AsRef, extract_to: impl AsRef) -> a } }?; + unnest_dir(extract_to)?; + Ok(()) } @@ -53,3 +58,47 @@ fn unpack_rar(path: impl AsRef, to: impl AsRef) -> anyhow::Result<() Ok(()) } + +/// Moves a directorys content into the parent if it is the only dir +fn unnest_dir(path: impl AsRef) -> anyhow::Result<()> { + let path = path.as_ref(); + + let Some(nested_dir) = check_nested_dir(path) else { + return Ok(()); + }; + + for entry in fs::read_dir(&nested_dir)? { + let entry = entry?; + let src = entry.path(); + let dest = path.join(entry.file_name()); + fs::rename(&src, &dest)?; + } + + fs::remove_dir(&nested_dir)?; + Ok(()) +} + +/// Check if the extracted archive has a single directory in it which contains the mod files +fn check_nested_dir(path: impl AsRef) -> Option { + let path = path.as_ref(); + + let entries: Vec<_> = fs::read_dir(path).ok()?.filter_map(|e| e.ok()).collect(); + + if entries.len() == 1 { + let entry = &entries[0]; + let entry_path = entry.path(); + + if entry_path + .file_name() + .is_some_and(|e| e == "Data" || e == "data") + { + return None; + } + + if entry_path.is_dir() { + return Some(entry_path); + } + } + + None +}