lsdj_tools/
export.rs

1//! The `export` subcommand
2
3use crate::utils::check_for_overwrite;
4use anyhow::{Context, Result};
5use clap::Args;
6use lsdj::{
7    fs::{File, Filesystem},
8    sram::SRam,
9};
10use std::{env::current_dir, fs::create_dir_all};
11
12use std::path::PathBuf;
13
14/// Arguments for the `export` subcommand
15#[derive(Args)]
16#[clap(author, version, about = "Export .lsdsng's from .sav files", long_about = None)]
17pub struct ExportArgs {
18    /// The path to the save file to export from
19    path: PathBuf,
20
21    /// Indices of the songs that should be exported. No indices means all songs.
22    index: Vec<usize>,
23
24    /// The destination folder to place the songs
25    #[clap(short, long)]
26    output: Option<PathBuf>,
27
28    /// Prepend the song position to the start of the filename
29    #[clap(short = 'p', long)]
30    output_pos: bool,
31
32    /// Append the song version to the end of the filename
33    #[clap(short = 'v', long)]
34    output_version: bool,
35
36    /// Use decimal version numbers, instead of hexadecimal
37    #[clap(short, long)]
38    decimal: bool,
39}
40
41/// Export .lsdsng's from .sav files
42pub fn export(mut args: ExportArgs) -> Result<()> {
43    let sram = SRam::from_path(&args.path).context("Reading the SRAM from file failed")?;
44
45    if args.index.is_empty() {
46        args.index = (0..Filesystem::FILES_CAPACITY).collect();
47    }
48
49    let folder = match args.output {
50        Some(folder) => folder,
51        None => current_dir().context("Could not fetch current working directory")?,
52    };
53    create_dir_all(&folder).context("Could not create output directory")?;
54
55    for (index, file) in sram.filesystem.files().enumerate() {
56        if !args.index.contains(&index) {
57            continue;
58        }
59
60        if let Some(file) = file {
61            let lsdsng = file
62                .lsdsng()
63                .context("Could not create an LsdSng from an SRAM file slot")?;
64
65            let mut filename = String::new();
66            if args.output_pos {
67                filename.push_str(&format!("{:02}_", index));
68            }
69
70            let name = lsdsng.name()?;
71            filename.push_str(name.as_str());
72            if args.output_version {
73                if args.decimal {
74                    filename.push_str(&format!("_v{:03}", lsdsng.version()));
75                } else {
76                    filename.push_str(&format!("_v{:02X}", lsdsng.version()));
77                }
78            }
79
80            let path = folder.join(filename).with_extension("lsdsng");
81
82            if check_for_overwrite(&path)? {
83                lsdsng
84                    .to_path(&path)
85                    .context("Could not write lsdsng to file")?;
86
87                println!(
88                    "{:02}. {:8} => {}",
89                    index,
90                    name.as_str(),
91                    path.file_name().unwrap().to_string_lossy()
92                );
93            }
94        }
95    }
96
97    Ok(())
98}