Walk through filesystem and print metadata

This commit is contained in:
Connor Johnstone
2026-03-02 21:09:47 -05:00
commit 8a07a3edc2
6 changed files with 281 additions and 0 deletions

22
src/filesystem.rs Normal file
View File

@@ -0,0 +1,22 @@
use std::path::Path;
use walkdir::WalkDir;
const MUSIC_EXTENSIONS: &[&str] = &[
"mp3", "flac", "ogg", "opus", "m4a", "mp4", "wav", "aif", "aiff", "wv", "ape", "mpc",
];
fn is_music_file(path: &Path) -> bool {
path.extension()
.and_then(|ext| ext.to_str())
.is_some_and(|ext| MUSIC_EXTENSIONS.contains(&ext.to_ascii_lowercase().as_str()))
}
/// Returns an iterator over music file paths found recursively under `dir`.
pub fn walk_music_files(dir: &Path) -> impl Iterator<Item = std::path::PathBuf> + '_ {
WalkDir::new(dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| is_music_file(e.path()))
.map(|e| e.into_path())
}

30
src/main.rs Normal file
View File

@@ -0,0 +1,30 @@
mod filesystem;
mod metadata;
use std::env;
use std::path::Path;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
eprintln!("Usage: {} <directory>", args[0]);
std::process::exit(1);
}
let dir = Path::new(&args[1]);
for path in filesystem::walk_music_files(dir) {
println!("{}", path.display());
match metadata::read_track_metadata(&path) {
Ok(Some(meta)) => {
let unknown = "(unknown)";
println!(" Title: {}", meta.title.as_deref().unwrap_or(unknown));
println!(" Artist: {}", meta.artist.as_deref().unwrap_or(unknown));
println!(" Album: {}", meta.album.as_deref().unwrap_or(unknown));
}
Ok(None) => println!(" (no metadata tags found)"),
Err(e) => eprintln!(" warning: could not read metadata: {e}"),
}
}
}

25
src/metadata.rs Normal file
View File

@@ -0,0 +1,25 @@
use std::path::Path;
use lofty::file::TaggedFileExt;
use lofty::tag::Accessor;
pub struct TrackMetadata {
pub title: Option<String>,
pub artist: Option<String>,
pub album: Option<String>,
}
/// Read metadata from a music file, returning `None` if no tags are present.
pub fn read_track_metadata(path: &Path) -> Result<Option<TrackMetadata>, lofty::error::LoftyError> {
let tagged_file = lofty::read_from_path(path)?;
let Some(tag) = tagged_file.primary_tag().or_else(|| tagged_file.first_tag()) else {
return Ok(None);
};
Ok(Some(TrackMetadata {
title: tag.title().map(|s| s.into_owned()),
artist: tag.artist().map(|s| s.into_owned()),
album: tag.album().map(|s| s.into_owned()),
}))
}