Added exact artist matching
This commit is contained in:
93
src/main.rs
93
src/main.rs
@@ -16,7 +16,7 @@ use rand::prelude::*;
|
||||
use playlist::Candidate;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "playlists")]
|
||||
#[command(name = "drift")]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
@@ -58,8 +58,8 @@ enum Command {
|
||||
/// Popularity bias (0=no preference, 10=heavy popular bias)
|
||||
#[arg(short, default_value_t = 5, value_parser = clap::value_parser!(u8).range(0..=10))]
|
||||
popularity: u8,
|
||||
/// Seed file (or pick interactively)
|
||||
file: Option<String>,
|
||||
/// Artist name to seed (or pick interactively)
|
||||
artist: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -88,9 +88,9 @@ fn db_path() -> PathBuf {
|
||||
let home = env::var("HOME").expect("HOME not set");
|
||||
PathBuf::from(home).join(".local/share")
|
||||
});
|
||||
let dir = data_dir.join("playlists");
|
||||
let dir = data_dir.join("drift");
|
||||
std::fs::create_dir_all(&dir).expect("failed to create data directory");
|
||||
dir.join("playlists.db")
|
||||
dir.join("drift.db")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -100,11 +100,11 @@ fn main() {
|
||||
Command::Index { verbose, force, directory } => {
|
||||
cmd_index(verbose, force, &directory);
|
||||
}
|
||||
Command::Build { verbose, mpd, airsonic, shuffle, random, count, popularity, file } => {
|
||||
Command::Build { verbose, mpd, airsonic, shuffle, random, count, popularity, artist } => {
|
||||
let opts = BuildOptions {
|
||||
verbose, mpd, airsonic, shuffle, random, count, popularity_bias: popularity,
|
||||
};
|
||||
cmd_build(opts, file.as_deref());
|
||||
cmd_build(opts, artist.as_deref());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,40 +195,61 @@ fn cmd_index(verbose: bool, force: bool, directory: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_build(opts: BuildOptions, file: Option<&str>) {
|
||||
fn resolve_artist(artists: &[(String, String)], query: &str) -> Option<(String, String)> {
|
||||
let q = query.to_lowercase();
|
||||
|
||||
// Tier 1: exact case-insensitive match
|
||||
for (mbid, name) in artists {
|
||||
if name.to_lowercase() == q {
|
||||
return Some((mbid.clone(), name.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
// Tier 2: contains case-insensitive
|
||||
for (mbid, name) in artists {
|
||||
if name.to_lowercase().contains(&q) {
|
||||
return Some((mbid.clone(), name.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
// Tier 3: subsequence fuzzy match
|
||||
for (mbid, name) in artists {
|
||||
if tui::fuzzy_match(&q, name) {
|
||||
return Some((mbid.clone(), name.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn cmd_build(opts: BuildOptions, artist: Option<&str>) {
|
||||
dotenvy::dotenv().ok();
|
||||
let conn = db::open(&db_path()).expect("failed to open database");
|
||||
|
||||
let (artist_mbid, seed_name) = if let Some(file_arg) = file {
|
||||
let path = Path::new(file_arg);
|
||||
let mbid = match metadata::read_artist_mbid(path) {
|
||||
Ok(Some(mbid)) => mbid,
|
||||
Ok(None) => {
|
||||
eprintln!("{}: no artist MBID found", path.display());
|
||||
std::process::exit(1);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}: could not read artist MBID: {e}", path.display());
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
let name = metadata::read_artist_name(path)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(|| mbid.clone());
|
||||
(mbid, name)
|
||||
} else {
|
||||
let artists = match db::get_all_artists(&conn) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
eprintln!("DB error: {e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
if artists.is_empty() {
|
||||
eprintln!("No artists in database. Run 'index' first.");
|
||||
let artists = match db::get_all_artists(&conn) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
eprintln!("DB error: {e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
if artists.is_empty() {
|
||||
eprintln!("No artists in database. Run 'index' first.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let (artist_mbid, seed_name) = if let Some(query) = artist {
|
||||
match resolve_artist(&artists, query) {
|
||||
Some((mbid, name)) => {
|
||||
eprintln!("Matched: {name}");
|
||||
(mbid, name)
|
||||
}
|
||||
None => {
|
||||
eprintln!("No artist matching \"{query}\"");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match tui::run_artist_picker(&artists) {
|
||||
Some(selection) => selection,
|
||||
None => std::process::exit(0),
|
||||
|
||||
Reference in New Issue
Block a user