Google Play Music からエクスポートしたところ、トラックフォルダ中にすべてのファイルが展開されている形だったので、アルバム名を基にフォルダを作ってそこにファイル移動するツールを作りました。

あと、ついでにトラック番号をファイル名の先頭に付加。

使い方は

cargo run C:\PATH_TO\Google Play Music\トラック

以下は、cargo new後に作ったプログラム。

[dependencies]
id3 = "0.5"
use std::env;
use std::fs;
use id3::{Tag};
use std::path::{Path, MAIN_SEPARATOR};

fn main() -> Result<(), String> {
    let args:Vec<String> = env::args().collect();
    if args.len() < 2 {
        return Err("empty args".to_string());
    }

    let base_path = &args[1];

    // MP3ファイルを集める。
    let mut paths = vec![];
    match fs::read_dir(base_path) {
        Err(why) => return Err(format!("read dir failure: {:?} - {}", why, base_path)),
        Ok(pathsi) => for path in pathsi {
            let path = path.unwrap().path();
            if let Some(ext) = path.extension() {
                if ext.to_str().unwrap().to_lowercase() == "mp3" {
                    paths.push(path);
                }
            }
        },
    };

    for path in paths {
        let path_str = path.to_str().unwrap();
        let tag = Tag::read_from_path(&path).unwrap();

        let new_path = new_path(&tag, &path_str);
        
        // MP3ファイルを各ディレクトリに移動する。
        match move_file(&path_str, &new_path) {
            Err(why) => return Err(format!("read dir failure: {:?} - {}", why, new_path)),
            Ok(_) => println!("{} move to {}", path_str, new_path),
        }
    }

    Ok(())
}

fn safe_dir_str(source: &str) -> String {
    source
    .replace(":", ":")
    .replace("\\", "¥")
    .replace("/", "/")
    .replace("*", "*")
    .replace("?", "?")
    .replace("\"", "'")
    .replace("<", "<")
    .replace(">", ">")
    .replace("|", "|").to_string()
}

fn new_path(tag: &Tag, source_path: &str) -> String {
    let track = tag.track().unwrap_or(10);

    let total_tracks = tag.total_tracks().unwrap_or(10);

    let album = safe_dir_str(tag.album().unwrap_or("UNKNOWN"));

    let disc = tag.disc().unwrap_or(1);

    let path = Path::new(source_path);

    let parent = path.parent().unwrap();

    let ext = path.extension().unwrap();

    let file_stem = path.file_stem().unwrap();

    let mut temp = total_tracks as i32;
    let mut keta = 0;
    while 1 <= temp {
        temp /= 10;
        keta += 1;
    }

    format!(
        "{}{}{}({:02}){}{:0keta$} {}.{}",
        parent.to_str().unwrap(),
        MAIN_SEPARATOR,
        album,
        disc,
        MAIN_SEPARATOR,
        track,
        file_stem.to_str().unwrap(),
        ext.to_str().unwrap(),
        keta=keta
    )
}

fn move_file(source:&str, dist:&str) -> std::io::Result<()> {
    let path = Path::new(&dist);
    
    if !path.parent().unwrap().exists() {
        fs::create_dir(path.parent().unwrap().to_str().unwrap())?
    }
    fs::rename(source, dist)?;

    Ok(())
}