From aa3e655520a729e1108d21313d1a5e5014842ea8 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 27 Aug 2023 14:15:29 +0100 Subject: [PATCH] determine new file name from tags --- .gitignore | 1 + Cargo.lock | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 +++ README.md | 7 ++ src/main.rs | 68 +++++++++++++++++ 5 files changed, 295 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..07a107a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,209 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "auto-file-mp4" +version = "0.1.0" +dependencies = [ + "mp4", + "taglib", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "mp4" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9ef834d5ed55e494a2ae350220314dc4aacd1c43a9498b00e320e0ea352a5c3" +dependencies = [ + "byteorder", + "bytes", + "num-rational", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "taglib" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89f5ef37e426deffeed459ea78a564bbe85baf6a9b023a69437655b46ad2013" +dependencies = [ + "libc", + "taglib-sys", +] + +[[package]] +name = "taglib-sys" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e20ea22a603f1e8ccea16694cf8e8e3a192e5d6d6bb41d6e86dcbf3680d2a4e" +dependencies = [ + "libc", +] + +[[package]] +name = "thiserror" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..46a2065 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "auto-file-mp4" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +mp4 = "0.14.0" +taglib = "1.0.0" diff --git a/README.md b/README.md new file mode 100644 index 0000000..2305022 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +## dependencies + +### debian + +```bash +sudo apt install libtag1-dev libtagc0-dev +``` diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d74c53a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,68 @@ +use std::fs::{self}; + +fn main() { + let directory = std::env::args().nth(1).unwrap(); + println!("Renaming files in {}", directory); + match rename_files(&directory) { + Ok(count) => println!("Renamed {} files", count), + Err(e) => eprintln!("Error: {}", e), + } +} + +fn rename_files(directory: &str) -> Result> { + // Read the directory entries + let entries = fs::read_dir(directory)?; + + let mut count = 0; + + // Iterate over each entry + for entry in entries { + let entry = entry?; + + // Get the file path + let path = entry.path(); + + if path.is_dir() { + if let Some(sub_dir) = path.to_str() { + count += rename_files(sub_dir)?; + } + } + // Check if the entry is a file + if path.is_file() { + if let Ok(file) = taglib::File::new(&path) { + if let Ok(tag) = file.tag() { + if let Some(title) = tag.title() { + if let Some(artist) = tag.artist() { + let album = parse_album(&title); + count += 1; + // println!("{album}: {title} by {artist}"); + let new_name = match album.len() { + 0 => format!("{artist}/{title}.mp4a"), + _ => format!("{artist}/{album}/{title}.mp4a"), + }; + println!("Renaming {} to {}", path.display(), new_name); + } + } + } + } + } + } + + Ok(count) +} + +fn parse_album(title: &str) -> String { + let parts: Vec<&str> = title.split(':').collect(); + match &parts[..] { + [_, b] => { + let parts: Vec<&str> = b.split(',').collect(); + match &parts[..] { + [c, _] => c.to_string(), + _ => "".to_string(), + } + } + _ => "".to_string(), + } + .trim() + .to_string() +}