commit 48dfccd5d56b01f40f86c515b5feb6c54358d7c0
parent b44df3563bdf09df96415f324d6d11bf7d9c4c8e
Author: mtmn <miro@haravara.org>
Date: Thu, 14 May 2026 01:08:56 +0200
feat!: deprecate csv report; default db path
Diffstat:
3 files changed, 35 insertions(+), 42 deletions(-)
diff --git a/README.md b/README.md
@@ -6,7 +6,6 @@ A command-line tool that analyzes audio files to detect `BPM` and `Key` tags.
* Detect BPM and Key of audio files
* Write detected BPM and Key to metadata tags
-* Generate CSV reports of analyzed tracks
* Save track metadata to a database
## Building
@@ -32,11 +31,10 @@ cargo build --release
* `-w`, `--write`: Write detected BPM and Key to audio file metadata.
* `-f`, `--force`: Re-analyze files even if they already have BPM/Key tags.
* `-j`, `--jobs <JOBS>`: Number of threads to use (0 = all cores).
-* `-r`, `--report`: Generate a CSV report with timestamped filename.
* `-S`, `--save`: Save track reports (artist, track, BPM, key) to the database.
* `-l`, `--list`: List all track reports stored in the database.
-* `--query <PATH>`: Look up a track report by file path.
-* `--db-path <PATH>`: Path to the database directory (default: `~/.local/share/virittaa.db`).
+* `--query <KEY>`: Look up a track report by artist - track key.
+* `--db-path <PATH>`: Path to the database directory (default: `~/.local/share/virittaa`).
* `-h`, `--help`: Print help information.
* `-V`, `--version`: Print version information.
@@ -55,24 +53,19 @@ cargo build --release
# Limit to 4 threads
./target/release/virittaa -j 4 /path/to/music/
-# Generate a CSV report
-./target/release/virittaa --report /path/to/music/
-
# Analyze and save reports to database
./target/release/virittaa --save /path/to/music/
# Write tags and save to database with custom path
-./target/release/virittaa -w --save --db-path ~/my_library.db /path/to/music/
-
-# Generate CSV report and save to database
-./target/release/virittaa -r --save /path/to/music/
+./target/release/virittaa -w --save --db-path ~/my_library /path/to/music/
# List all tracks in the database
./target/release/virittaa --list
-# Look up a specific track by file path
-./target/release/virittaa --query /path/to/track.flac
+# Look up a specific track
+./target/release/virittaa --query "Aphex Twin - Xtal"
# Query using a custom database path
-./target/release/virittaa --list --db-path ~/my_library.db
+./target/release/virittaa --list --db-path ~/my_library
```
+
diff --git a/src/db.rs b/src/db.rs
@@ -11,17 +11,17 @@ pub struct TrackReport {
pub key: Option<String>,
}
-pub struct ReportDb {
+pub struct LibraryDb {
db: Db,
}
-impl ReportDb {
+impl LibraryDb {
/// # Errors
///
/// Returns an error if the database cannot be opened or created.
pub fn open(path: &Path) -> Result<Self> {
let db = sled::open(path)
- .with_context(|| format!("Failed to open sled database at {}", path.display()))?;
+ .with_context(|| format!("Failed to open database at {}", path.display()))?;
Ok(Self { db })
}
diff --git a/src/main.rs b/src/main.rs
@@ -10,8 +10,8 @@ use rayon::prelude::*;
use std::path::PathBuf;
use walkdir::WalkDir;
-use crate::db::ReportDb;
-use crate::file_io::{process_file, write_report};
+use crate::db::LibraryDb;
+use crate::file_io::process_file;
use crate::types::TrackError;
use crate::constants::SUPPORTED_EXTENSIONS;
@@ -30,9 +30,11 @@ fn main() -> Result<()> {
let matches = Command::new("virittaa")
.version(clap::crate_version!())
.about("Analyze audio files to detect BPM and Key")
- .arg(Arg::new("path").num_args(1..).help(
- "One or more files or directories to analyze (not required with --list or --query)",
- ))
+ .arg(
+ Arg::new("path")
+ .num_args(1..)
+ .help("One or more files or directories to analyze (not required with --list or --query)"),
+ )
.arg(
Arg::new("write")
.short('w')
@@ -56,18 +58,11 @@ fn main() -> Result<()> {
.value_parser(clap::value_parser!(usize)),
)
.arg(
- Arg::new("report")
- .short('r')
- .long("report")
- .action(clap::ArgAction::SetTrue)
- .help("Generate a CSV report file in the current directory"),
- )
- .arg(
Arg::new("save")
.short('S')
.long("save")
.action(clap::ArgAction::SetTrue)
- .help("Save track metadata to a database"),
+ .help("Save track reports (artist, track, BPM, key) to a database"),
)
.arg(
Arg::new("list")
@@ -79,19 +74,18 @@ fn main() -> Result<()> {
.arg(
Arg::new("query")
.long("query")
- .help("Look up a track report by file path"),
+ .help("Look up a track report by artist - track key"),
)
.arg(
Arg::new("db-path")
.long("db-path")
- .help("Path to the database directory for saved reports (default: ~/.local/share/virittaa.db)"),
+ .help("Path to the database directory for saved reports (default: ~/.local/share/virittaa)"),
)
.get_matches();
let write_tags = matches.get_flag("write");
let force = matches.get_flag("force");
let jobs = *matches.get_one::<usize>("jobs").unwrap();
- let generate_report = matches.get_flag("report");
let save_to_db = matches.get_flag("save");
let list_db = matches.get_flag("list");
let query_path = matches.get_one::<String>("query").map(String::as_str);
@@ -99,17 +93,17 @@ fn main() -> Result<()> {
p.clone()
} else {
let mut dir = dirs::data_local_dir().unwrap_or_else(|| std::path::PathBuf::from("."));
- dir.push("virittaa.db");
+ dir.push("virittaa");
dir.to_string_lossy().to_string()
};
// Read-only DB operations that don't need file paths
if list_db || query_path.is_some() {
- let db = ReportDb::open(std::path::Path::new(&db_path))?;
+ let db = LibraryDb::open(std::path::Path::new(&db_path))?;
if let Some(path) = query_path {
match db.get(path)? {
- Some(report) => println!("{path}: {}", db::format_report(&report)),
+ Some(report) => println!("{}", db::format_report(&report)),
None => eprintln!("No report found for: {path}"),
}
} else {
@@ -142,7 +136,7 @@ fn main() -> Result<()> {
}
let report_db = if save_to_db {
- Some(ReportDb::open(std::path::Path::new(&db_path))?)
+ Some(LibraryDb::open(std::path::Path::new(&db_path))?)
} else {
None
};
@@ -179,9 +173,19 @@ fn main() -> Result<()> {
let results: Vec<_> = results.into_iter().map(|r| r.unwrap()).collect();
let errors: Vec<_> = errors.into_iter().map(|r| r.unwrap_err()).collect();
+ if !errors.is_empty() {
+ for err in &errors {
+ eprintln!("Error: {} - {}", err.path.display(), err.reason);
+ }
+ }
+
if let Some(db) = &report_db {
for track in &results {
- let key = track.path.to_string_lossy();
+ let key = format!(
+ "{} - {}",
+ track.artist.as_deref().unwrap_or("Unknown"),
+ track.track.as_deref().unwrap_or("Unknown")
+ );
let report = db::TrackReport {
artist: track.artist.clone(),
track: track.track.clone(),
@@ -196,9 +200,5 @@ fn main() -> Result<()> {
}
}
- if generate_report {
- write_report(&results, &errors)?;
- }
-
Ok(())
}