Files
NotAlterra/examples/dump_samples.rs
T

78 lines
2.7 KiB
Rust

//! Dump GVAS metadata for all .sav/.bak files in `samples/`.
//! Run: cargo run --example dump_samples
use chrono::TimeZone;
use std::fs;
use std::path::Path;
fn main() {
let dir = Path::new("samples");
let mut entries: Vec<_> = fs::read_dir(dir)
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| {
let s = e.file_name().to_string_lossy();
s.ends_with(".sav") || s.ends_with(".bak")
})
.collect();
entries.sort_by(|a, b| {
let ma = a.metadata().ok().and_then(|m| m.modified().ok());
let mb = b.metadata().ok().and_then(|m| m.modified().ok());
mb.cmp(&ma)
.then_with(|| a.file_name().cmp(&b.file_name()))
});
println!(
"{:<8} {:<26} {:<6} {:>7} {:<19} {:<28}",
"", "Display Name", "Type", "Size", "Date", "File"
);
println!("{}", "-".repeat(115));
let mut seen = std::collections::HashSet::new();
for entry in &entries {
let path = entry.path();
let name = entry.file_name().to_string_lossy().to_string();
let size = entry.metadata().map(|m| m.len()).unwrap_or(0);
let mtime = entry
.metadata()
.ok()
.and_then(|m| m.modified().ok())
.and_then(|t| {
let secs = t.duration_since(std::time::UNIX_EPOCH).ok()?.as_secs();
chrono::Local
.timestamp_opt(secs as i64, 0)
.single()
})
.map(|dt| dt.format("%Y-%m-%d %H:%M:%S").to_string());
let meta = notalterra::gvas::extract_metadata(&path).ok();
let slot = meta.as_ref().and_then(|m| m.slot_name.clone()).unwrap_or_else(|| {
notalterra::gvas::derive_slot_from_filename(&name).unwrap_or_else(|| "?".into())
});
let display = meta
.as_ref()
.and_then(|m| m.display_name.clone())
.unwrap_or_else(|| "(unnamed)".into());
let is_online = meta.map(|m| m.is_online).unwrap_or(false);
let label_num = slot.strip_prefix("savegame_").unwrap_or(&slot);
let first = seen.insert(slot.clone());
let label = if first { format!("Slot {label_num}") } else { String::new() };
let typ = if is_online { "Multiplayer" } else { "Single Player" };
let sz = if size < 1024 {
format!("{size} B")
} else if size < 1024 * 1024 {
format!("{:.0} KB", size as f64 / 1024.0)
} else {
format!("{:.1} MB", size as f64 / (1024.0 * 1024.0))
};
println!(
"{label:<8} {display:<26} {typ:<6} {sz:>7} {:<19} {name:<28}",
mtime.as_deref().unwrap_or("?"),
);
}
}