use clap::Parser;
use log::LevelFilter;
mod commands;
use commands::{
execute_command, utils::get_credentials, utils::load_or_create_client,
utils::prompt_for_credentials, utils::try_restore_most_recent_session, Commands,
};
#[derive(Parser)]
#[command(
name = "lastfm-edit",
about = "Last.fm scrobble metadata editor",
long_about = None
)]
struct Cli {
#[arg(short, long, action = clap::ArgAction::Count, global = true)]
quiet: u8,
#[arg(short, long, action = clap::ArgAction::Count, global = true)]
verbose: u8,
#[arg(short, long, global = true)]
username: Option<String>,
#[arg(short, long, global = true)]
password: Option<String>,
#[command(subcommand)]
command: Commands,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Cli::parse();
let mut builder = env_logger::Builder::from_default_env();
let effective_level = args.verbose as i8 - args.quiet as i8;
match effective_level {
i8::MIN..=-3 => {
builder.filter_level(LevelFilter::Off);
}
-2 => {
builder.filter_level(LevelFilter::Error);
}
-1 => {
builder.filter_level(LevelFilter::Warn);
}
0 => {
builder.filter_level(LevelFilter::Warn);
builder.filter_module("lastfm_edit", LevelFilter::Info);
}
1 => {
builder.filter_level(LevelFilter::Warn);
builder.filter_module("lastfm_edit", LevelFilter::Debug);
}
2 => {
builder.filter_level(LevelFilter::Warn);
builder.filter_module("lastfm_edit", LevelFilter::Trace);
}
3 => {
builder.filter_level(LevelFilter::Info);
builder.filter_module("lastfm_edit", LevelFilter::Trace);
}
4 => {
builder.filter_level(LevelFilter::Debug);
builder.filter_module("lastfm_edit", LevelFilter::Trace);
}
_ => {
builder.filter_level(LevelFilter::Trace);
}
}
builder.init();
let (username, password) = if let (Some(u), Some(p)) = (&args.username, &args.password) {
(Some(u.clone()), Some(p.clone()))
} else if args.username.is_some() || args.password.is_some() {
log::error!("Both username and password must be provided together");
log::error!("Either provide both --username and --password, or set environment variables");
std::process::exit(1);
} else {
match get_credentials() {
Ok((u, p)) => (Some(u), Some(p)),
Err(_) => (None, None), }
};
let client = if username.is_none() && password.is_none() {
match try_restore_most_recent_session().await {
Some(client) => {
log::info!("Restored most recent session");
client
}
None => {
log::info!("No valid saved session found. Please provide credentials:");
let (prompted_username, prompted_password) = prompt_for_credentials();
log::info!("Using username: {prompted_username}");
match load_or_create_client(&prompted_username, &prompted_password).await {
Ok(client) => client,
Err(e) => {
log::error!("Failed to create client: {e}");
std::process::exit(1);
}
}
}
}
} else {
let username = username.unwrap();
let password = password.unwrap();
log::info!("Using username: {username}");
match load_or_create_client(&username, &password).await {
Ok(client) => client,
Err(e) => {
log::error!("Failed to create client: {e}");
std::process::exit(1);
}
}
};
log::info!("Client ready");
if let Err(e) = execute_command(args.command, &client).await {
log::error!("Command failed: {e}");
std::process::exit(1);
}
Ok(())
}