songrec-lib 0.5.4

A clean headless Shazam client library with comprehensive device management and API
Documentation
use clap::{Arg, ArgAction, Command};
use songrec::{Config, OutputFormat, RecognitionOutput, SongRec};
use std::process;

fn main() {
    let matches = Command::new("SongRec CLI")
        .version("0.4.3")
        .about("An open-source Shazam client library and CLI")
        .subcommand(
            Command::new("recognize")
                .about("Recognize a song from an audio file")
                .arg(
                    Arg::new("input")
                        .required(true)
                        .help("Input audio file path")
                        .index(1),
                )
                .arg(
                    Arg::new("format")
                        .short('f')
                        .long("format")
                        .value_name("FORMAT")
                        .help("Output format: simple, json, csv")
                        .default_value("simple"),
                )
                .arg(
                    Arg::new("quiet")
                        .short('q')
                        .long("quiet")
                        .action(ArgAction::SetTrue)
                        .help("Suppress verbose debug output (default)"),
                )
                .arg(
                    Arg::new("verbose")
                        .short('v')
                        .long("verbose")
                        .action(ArgAction::SetTrue)
                        .help("Enable verbose debug output"),
                ),
        )
        .subcommand(
            Command::new("listen")
                .about("Listen continuously for songs")
                .arg(
                    Arg::new("device")
                        .short('d')
                        .long("device")
                        .value_name("DEVICE")
                        .help("Audio input device name"),
                )
                .arg(
                    Arg::new("format")
                        .short('f')
                        .long("format")
                        .value_name("FORMAT")
                        .help("Output format: simple, json, csv")
                        .default_value("simple"),
                )
                .arg(
                    Arg::new("quiet")
                        .short('q')
                        .long("quiet")
                        .action(ArgAction::SetTrue)
                        .help("Suppress verbose debug output (default)"),
                )
                .arg(
                    Arg::new("verbose")
                        .short('v')
                        .long("verbose")
                        .action(ArgAction::SetTrue)
                        .help("Enable verbose debug output"),
                )
                .arg(
                    Arg::new("no-dedupe")
                        .long("no-dedupe")
                        .action(ArgAction::SetTrue)
                        .help("Disable request deduplication"),
                ),
        )
        .subcommand(Command::new("devices").about("List available audio input devices"))
        .get_matches();

    match matches.subcommand() {
        Some(("recognize", sub_matches)) => {
            let input_file = sub_matches.get_one::<String>("input").unwrap();
            let format_str = sub_matches.get_one::<String>("format").unwrap();
            let verbose = sub_matches.get_flag("verbose");

            let format = match format_str.as_str() {
                "json" => OutputFormat::Json,
                "csv" => OutputFormat::Csv,
                _ => OutputFormat::Simple,
            };

            let config = Config::default().with_quiet_mode(!verbose);
            let songrec = SongRec::new(config);

            match songrec.recognize_from_file(input_file) {
                Ok(result) => {
                    let output = RecognitionOutput::format_result(&result, format);
                    println!("{}", output);
                }
                Err(e) => {
                    eprintln!("Error: {}", e);
                    process::exit(1);
                }
            }
        }
        Some(("listen", sub_matches)) => {
            let device = sub_matches.get_one::<String>("device").cloned();
            let format_str = sub_matches.get_one::<String>("format").unwrap();
            let verbose = sub_matches.get_flag("verbose");
            let no_dedupe = sub_matches.get_flag("no-dedupe");

            let format = match format_str.as_str() {
                "json" => OutputFormat::Json,
                "csv" => OutputFormat::Csv,
                _ => OutputFormat::Simple,
            };

            let config = Config::default()
                .with_quiet_mode(!verbose)
                .with_deduplication(!no_dedupe);
            let songrec = SongRec::new(config);

            if verbose {
                println!("Starting continuous recognition...");
            }
            if format == OutputFormat::Csv {
                println!("{}", RecognitionOutput::csv_header());
            }

            match songrec.start_continuous_recognition_with_device(device) {
                Ok(stream) => {
                    for result in stream {
                        match result {
                            Ok(recognition) => {
                                let output = RecognitionOutput::format_result(&recognition, format);
                                println!("{}", output);
                            }
                            Err(e) => {
                                if verbose {
                                    eprintln!("Recognition error: {}", e);
                                }
                            }
                        }
                    }
                }
                Err(e) => {
                    if verbose {
                        eprintln!("Error starting recognition: {}", e);
                    }
                    process::exit(1);
                }
            }
        }
        Some(("devices", _)) => {
            match songrec::audio::AudioRecorder::list_input_devices() {
                Ok(devices) => {
                    println!("Available audio input devices:");
                    for (i, device) in devices.iter().enumerate() {
                        println!("  {}: {}", i, device);
                    }
                }
                Err(e) => {
                    eprintln!("Error listing devices: {}", e);
                    process::exit(1);
                }
            }
        }
        _ => {}
    }
}