From a053b5ee5cbd30e0aa3ee7f0592281cdee8a8913 Mon Sep 17 00:00:00 2001 From: Mark <> Date: Sat, 23 Aug 2025 14:41:27 +0200 Subject: [PATCH] feat: use better structure for custom files --- musicdb-filldb/src/main.rs | 126 ++++++++++++++++++++++++++----- musicdb-lib/src/data/database.rs | 9 +++ 2 files changed, 118 insertions(+), 17 deletions(-) diff --git a/musicdb-filldb/src/main.rs b/musicdb-filldb/src/main.rs index 6dfbb84..7054a14 100755 --- a/musicdb-filldb/src/main.rs +++ b/musicdb-filldb/src/main.rs @@ -4,7 +4,8 @@ use std::{ fs, io::Write, path::{Path, PathBuf}, - sync::{Arc, Mutex}, time::SystemTime, + sync::{Arc, Mutex}, + time::SystemTime, }; use id3::TagLike; @@ -28,7 +29,6 @@ fn main() { let mut bad_arg = false; let mut skip_duration = false; let mut custom_files = None; - let mut artist_txt = false; let mut artist_img = false; loop { match args.next() { @@ -50,7 +50,6 @@ fn main() { eprintln!("--custom-files :: missing !"); } } - "--cf-artist-txt" => artist_txt = true, "--cf-artist-img" => artist_img = true, arg => { bad_arg = true; @@ -249,7 +248,6 @@ fn main() { song_path ); None - } }, title.clone(), @@ -335,23 +333,95 @@ fn main() { } } if let Some(custom_files) = custom_files { - if artist_txt { - eprintln!("[info] Searching for .txt files in custom-files dir..."); - let l = database.artists().len(); - let mut c = 0; - for (i, artist) in database.artists_mut().values_mut().enumerate() { - if let Ok(info) = - fs::read_to_string(custom_files.join(format!("{}.txt", artist.name))) + eprintln!("[info] Searching for .tags, .d/.tags, .d/singles.d/.tags, .d/.d/.tags in custom-files dir..."); + let l = database.artists().len() + database.albums().len() + database.songs().len(); + let mut cc = 0; + let mut c = 0; + let (artists, albums, songs) = database.artists_albums_songs_mut(); + for artist in artists.values_mut() { + // .tags + cc += 1; + if let Ok(info) = fs::read_to_string(custom_files.join(format!( + "{}.tags", + normalize_to_file_path_component_for_custom_files(&artist.name) + ))) { + c += 1; + for line in info.lines() { + artist.general.tags.push(normalized_str_to_tag(line)); + } + } + // .d/ + let dir = custom_files.join(format!( + "{}.d", + normalize_to_file_path_component_for_custom_files(&artist.name) + )); + if fs::metadata(&dir).is_ok_and(|meta| meta.is_dir()) { + // .d/singles/ { - c += 1; - for line in info.lines() { - artist.general.tags.push(line.to_owned()); + let dir = dir.join("singles"); + for song in artist.singles.iter() { + // .d/singles/.tags + cc += 1; + if let Some(song) = songs.get_mut(song) { + if let Ok(info) = fs::read_to_string(dir.join(format!( + "{}.tags", + normalize_to_file_path_component_for_custom_files(&song.title) + ))) { + c += 1; + for line in info.lines() { + song.general.tags.push(normalized_str_to_tag(line)); + } + } + } + } + } + for album in artist.albums.iter() { + eprint!(" {cc}/{l} ({c})\r"); + cc += 1; + if let Some(album) = albums.get_mut(album) { + // .d/.tags + if let Ok(info) = fs::read_to_string(dir.join(format!( + "{}.tags", + normalize_to_file_path_component_for_custom_files(&album.name) + ))) { + c += 1; + for line in info.lines() { + album.general.tags.push(normalized_str_to_tag(line)); + } + } + // .d/.d/ + let dir = dir.join(format!( + "{}.d", + normalize_to_file_path_component_for_custom_files(&album.name) + )); + for song in album.songs.iter() { + cc += 1; + if let Some(song) = songs.get_mut(song) { + // .d/.d/.tags + if let Ok(info) = fs::read_to_string(dir.join(format!( + "{}.tags", + normalize_to_file_path_component_for_custom_files(&song.title) + ))) { + c += 1; + for line in info.lines() { + song.general.tags.push(normalized_str_to_tag(line)); + } + } + } + } + } + } + } else { + cc += artist.albums.len(); + for album in artist.albums.iter() { + if let Some(album) = albums.get(album) { + cc += album.songs.len(); } } - eprint!(" {}/{l} ({c})\r", i + 1); } - eprintln!(); + eprint!(" {cc}/{l} ({c})\r"); } + eprintln!(); if artist_img { eprintln!("[info] Searching for .{{png,jpg,...}} files in custom-files dir..."); match fs::read_dir(&custom_files) { @@ -434,7 +504,7 @@ fn get_cover( if let Ok(files) = fs::read_dir(&abs_dir) { for file in files { if let Ok(file) = file { - let path = file.path(); + let path = file.path(); if let Ok(metadata) = path.metadata() { if metadata.is_file() { if path.extension().and_then(|v| v.to_str()).is_some_and(|v| { @@ -471,3 +541,25 @@ fn get_cover( None } } + +fn normalize_to_file_path_component_for_custom_files(str: &str) -> String { + str.replace('%', "%p") + .replace('\0', "%0") + .replace('/', "%s") + .replace('\\', "%S") + .replace('\t', "%t") + .replace('\r', "%r") + .replace('\n', "%n") +} + +fn normalize_tag_to_str(str: &str) -> String { + str.replace('\\', "\\S") + .replace('\n', "\\n") + .replace('\r', "\\r") +} +fn normalized_str_to_tag(str: &str) -> String { + str.replace(['\n', '\r'], "") + .replace("\\n", "\n") + .replace("\\r", "\r") + .replace("\\S", "\\") +} diff --git a/musicdb-lib/src/data/database.rs b/musicdb-lib/src/data/database.rs index 7bc0bc9..54f82ba 100755 --- a/musicdb-lib/src/data/database.rs +++ b/musicdb-lib/src/data/database.rs @@ -1145,6 +1145,15 @@ impl Database { self.modified_data(); &mut self.covers } + pub fn artists_albums_songs_mut( + &mut self, + ) -> ( + &mut HashMap, + &mut HashMap, + &mut HashMap, + ) { + (&mut self.artists, &mut self.albums, &mut self.songs) + } } #[derive(Clone, Debug)]