Walk through filesystem and print metadata
This commit is contained in:
22
src/filesystem.rs
Normal file
22
src/filesystem.rs
Normal 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
30
src/main.rs
Normal 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
25
src/metadata.rs
Normal 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()),
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user