From cf4f35117ce14bc8dd5a1b5633c686b5587feb0d Mon Sep 17 00:00:00 2001 From: Toasterkitten Date: Sun, 23 Aug 2026 09:44:42 -0400 Subject: [PATCH] repair --- Cargo.lock | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 146 +++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 270 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 139d04b..32a8b6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,56 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + [[package]] name = "block-buffer" version = "0.12.1" @@ -29,6 +79,52 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "clap" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "const-oid" version = "0.10.2" @@ -89,6 +185,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -104,6 +206,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "libc" version = "0.2.189" @@ -161,6 +269,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "paste" version = "1.0.15" @@ -202,6 +316,12 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "3.0.3" @@ -217,6 +337,7 @@ dependencies = [ name = "timbre" version = "0.1.0" dependencies = [ + "clap", "hex", "lofty", "sha2", @@ -233,3 +354,24 @@ name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml index 45558ba..7de0552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +clap = { version = "4.6.6", features = ["derive"] } hex = "0.4.3" lofty = "0.25.1" sha2 = "0.11.0" diff --git a/src/main.rs b/src/main.rs index e9a0bf3..96d1773 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +use clap::{ + Parser, Subcommand, + builder::styling::{AnsiColor, Effects, Styles}, +}; use sha2::{Digest, Sha256}; use std::{ fs::{self, File, create_dir_all}, @@ -5,18 +9,24 @@ use std::{ path::{Path, PathBuf}, }; +const CLAP_STYLING: Styles = Styles::styled() + .header(AnsiColor::Green.on_default().effects(Effects::BOLD)) + .usage(AnsiColor::Green.on_default().effects(Effects::BOLD)) + .literal(AnsiColor::Cyan.on_default().effects(Effects::BOLD)) + .placeholder(AnsiColor::Cyan.on_default()); + #[cfg(not(target_os = "linux"))] compile_error!("kitty like linux more"); -fn hashcat(cat_path: &Path) { - let file = File::open(cat_path).expect("how dare u! i want my cat back :("); +fn check_cat_hash(cat_path: &Path) -> bool { + let file = File::open(cat_path).expect("how dare u! i want my cat back :(\n"); let mut cat = BufReader::new(file); let mut hasher = Sha256::new(); let mut buffer = [0u8; 4096]; loop { - let bytes_read = cat.read(&mut buffer).expect("what happened to my cat!?"); + let bytes_read = cat.read(&mut buffer).expect("what happened to my cat!?\n"); if bytes_read == 0 { break; } @@ -25,13 +35,33 @@ fn hashcat(cat_path: &Path) { let file_hash = hex::encode(hasher.finalize()); - if !file_hash + file_hash .eq_ignore_ascii_case("45d4cf2fb11999c39ec5cd0cbedb436767421c8b8dab575c76f0b6ad9265d640") - { +} +fn hashcat(cat_path: &Path) { + if !check_cat_hash(cat_path) { panic!("this is not my cat. where is my cat. what did you do!? KITTYYYYYYYYYY") } } +#[derive(Parser)] +#[command(name = "timbre")] +#[command(about = "a music manager to finally solve this huge mess of music management")] +#[command(styles=CLAP_STYLING)] +struct Cli { + #[command(subcommand)] + command: Commands, +} +#[derive(Subcommand, PartialEq)] +enum Commands { + /// give timbre a home so it can help you + Init, + /// look through your library and see what's there + Scan, + /// attempt to repair timbre's home, this won't restore lost tracks + Repair, +} + fn is_audio(path: &Path) -> bool { match path.extension().and_then(|e| e.to_str()) { Some(ext) => { @@ -42,7 +72,7 @@ fn is_audio(path: &Path) -> bool { true } else { println!( - "while looking through each of your songs, i found one that i don't understand.\nits named {}, and i don't understand it's file extension.\nyou can try to help teach me by opening a git issue if it's a music file! :)\ni will continue, but ignore this file :(", + "while looking through each of your songs, i found one that i don't understand.\nits named {}, and i don't understand its file extension.\nyou can try to help teach me by opening a git issue if it's a music file! :)\ni will continue, but ignore this file :(", path.display() ); false @@ -53,10 +83,10 @@ fn is_audio(path: &Path) -> bool { } fn scan(dir: &Path, out: &mut Vec) { for entry in fs::read_dir(dir) - .expect("i want to help you, but i don't know how to read your music folder :( sorry.") + .expect("i want to help you, but i had trouble reading my music folder :( sorry.\n") { let path=entry.expect( - "i wanna help you, but, i can't do everything. i couldn't read a file, to the point where i can't tell you which :(").path(); + "i wanna help you, but, i can't do everything. i couldn't read a file, to the point where i can't tell you which :(\n").path(); if path.is_dir() { scan(&path, out); } else if is_audio(&path) { @@ -68,20 +98,98 @@ fn scan(dir: &Path, out: &mut Vec) { fn main() { let cat = include_bytes!("../cat_01.jpg"); // my kitty! + let cli = Cli::parse(); + let timbre_dir = Path::new(&std::env::var("HOME").expect("NERD!!!")) .join("Music") .join("Timbre"); - if !timbre_dir.exists() { - println!("First run detected... Initializing..."); - create_dir_all(&timbre_dir).expect("wat"); - fs::write(timbre_dir.join("cat_01.jpg"), cat) - .expect("my cat! he can't come! what did you do!?!"); - println!("Done!"); - } else { - hashcat(&timbre_dir.join("cat_01.jpg")); // meow + if cli.command != Commands::Init && cli.command != Commands::Repair { + if timbre_dir.exists() { + hashcat(&timbre_dir.join("cat_01.jpg")); // meow + } else { + println!( + "i can't help you since i don't have a home :(\nyou can create one with the command timbre init." + ); + return; + } + } + + match cli.command { + Commands::Init => { + if !timbre_dir.exists() { + println!("making a home..."); + create_dir_all(&timbre_dir).expect("wat"); + fs::write(timbre_dir.join("cat_01.jpg"), cat) + .expect("my cat! he can't come! what did you do!?!\n"); + for dir in ["Albums", "Singles", "Unidentified"] { + create_dir_all(timbre_dir.join(dir)) + .expect("sorry, but i couldn't create a folder that i need.\n"); + } + println!("i now have a home!"); + } else { + println!("i already has a home!"); + } + } + Commands::Scan => { + let mut tracks = Vec::new(); + scan(&timbre_dir.join("Singles"), &mut tracks); + scan(&timbre_dir.join("Albums"), &mut tracks); + if tracks.is_empty() { + println!("i couldn't find any audio files :("); + } else { + println!("i found {} audio files :)", tracks.len()); + } + } + Commands::Repair => { + println!("repairing my home..."); + let mut fixed_something = false; + + if !timbre_dir.exists() { + println!( + "it appears that my home is gone. your songs may have been deleted :(\nrebuilding my home..." + ); + create_dir_all(&timbre_dir).expect("wat"); + fs::write(timbre_dir.join("cat_01.jpg"), cat) + .expect("my cat! he can't come! what did you do!?!\n"); + for dir in ["Albums", "Singles", "Unidentified"] { + create_dir_all(timbre_dir.join(dir)) + .expect("sorry, but i couldn't create a folder that i need.\n"); + } + println!("i rebuilt my home! your audio won't be there though :("); + fixed_something = true; + } + if !timbre_dir.join("Albums").exists() + || !timbre_dir.join("Singles").exists() + || !timbre_dir.join("Unidentified").exists() + { + println!("i found folders that don't exist! recreating them..."); + for dir in ["Albums", "Singles", "Unidentified"] { + create_dir_all(timbre_dir.join(dir)) + .expect("sorry, but i couldn't create a folder that i need.\n"); + } + println!("done!"); + fixed_something = true; + } + if !timbre_dir.join("cat_01.jpg").exists() { + println!("where did my cat go!?!"); + fs::write(timbre_dir.join("cat_01.jpg"), cat) + .expect("my cat! he can't come! what did you do!?!\n"); + println!("he's back :)"); + fixed_something = true; + } + if !check_cat_hash(&timbre_dir.join("cat_01.jpg")) { + println!("what happened to my cat :( let me bring my kitty back."); + fs::write(timbre_dir.join("cat_01.jpg"), cat) + .expect("what did you do! i can't bring my cat back :(\n"); + println!("yay he's back!"); + fixed_something = true; + } + if !fixed_something { + println!( + "i wasn't able to fix anything :(\neither there is no problem, or i couldn't fix it :(" + ); + } + } } - let mut tracks = Vec::new(); - scan(&timbre_dir.join("Tracks"), &mut tracks); - println!("Found {} audio files", tracks.len()); }