use lofty::read_from_path; use lofty::prelude::*; use std::path::Path; use walkdir::WalkDir; fn main() { let music_path = "data/maple"; if !Path::new(music_path).exists() { println!("Music directory {} not found", music_path); return; } println!("Scanning music files in {}...\n", music_path); for entry in WalkDir::new(music_path) .follow_links(true) .into_iter() .filter_map(|e| e.ok()) { let path = entry.path(); // Skip _missing_tags directory if path.to_string_lossy().contains("_missing_tags") { continue; } if let Some(extension) = path.extension() { let ext = extension.to_string_lossy().to_lowercase(); if ext == "mp3" || ext == "flac" { if let Err(e) = print_file_metadata(path) { println!("Error reading {}: {}", path.display(), e); } println!(); } } } } fn print_file_metadata(path: &Path) -> Result<(), Box> { let tagged_file = read_from_path(path)?; println!("File: {}", path.display()); if let Some(tag) = tagged_file.primary_tag() { if let Some(title) = tag.title() { println!(" Title: {}", title); } if let Some(artist) = tag.artist() { println!(" Artist: {}", artist); } if let Some(album) = tag.album() { println!(" Album: {}", album); } if let Some(year) = tag.year() { println!(" Year: {}", year); } if let Some(track) = tag.track() { println!(" Track: {}", track); } if let Some(genre) = tag.genre() { println!(" Genre: {}", genre); } } else { println!(" No metadata found"); } let properties = tagged_file.properties(); println!(" Duration: {}:{:02}", properties.duration().as_secs() / 60, properties.duration().as_secs() % 60); println!(" Bitrate: {} kbps", properties.overall_bitrate().unwrap_or(0)); Ok(()) }