convert-invert 0.1.0

Orchestrate spotify playlist downloads using soulseek-rs
Documentation
use std::env;

use anyhow::Context;
use tracing_subscriber::EnvFilter;

#[derive(Debug, Default, Clone)]
pub struct Config {
    pub run_id: String,
    pub log_level: EnvFilter,
    pub user_name: String,
    pub user_password: String,
    pub judge_score_levenshtein: Option<f32>,
    pub judge_score_llm: Option<f32>,
    pub listen_port: u32,
    pub search_timeout_secs: u8,
    pub search_empty_result_cutoff: usize,
    pub playlist_id: String,
    pub client_id: Option<String>,
    pub client_secret: Option<String>,
}

impl Config {
    pub fn try_from_env() -> anyhow::Result<Self> {
        dotenvy::dotenv().ok();
        let run_id = env::var("RUN_ID").unwrap_or_else(|_| "default_run".to_string());
        let log_level: EnvFilter = env::var("LOG_LEVEL").unwrap_or("debug".to_string()).into();
        let user_name = env::var("USER_NAME").unwrap_or("default".to_string());
        let user_password = env::var("USER_PASSWORD").unwrap_or_default();
        let client_id = env::var("CLIENT_ID").ok();
        let client_secret = env::var("CLIENT_SECRET").ok();
        let playlist_id = env::var("PLAYLIST_ID")
            .unwrap_or_else(|_| "4RNxYgx8c1WuDV7MItXel2?si=e5b2ceac9697423f".to_string());
        let judge_score_levenshtein: Option<f32> = {
            let val = env::var("JUDGE_SCORE_LEVENSHTEIN").ok();
            val.map(|v| v.parse().context("Cannot parse JUDGE_SCORE_LEVENSHTEIN"))
                .transpose()?
        };
        let judge_score_llm: Option<f32> = {
            let val = env::var("JUDGE_SCORE_LLM").ok();
            val.map(|v| v.parse().context("Cannot parse JUDGE_SCORE_LLM"))
                .transpose()?
        };
        let listen_port: u32 = {
            let val = env::var("LISTEN_PORT").unwrap_or_else(|_| "41000".to_string());
            val.parse().context("Cannot parse LISTEN_PORT")?
        };

        let search_timeout_secs: u8 = {
            let val = env::var("SEARCH_TIMEOUT_SECS").unwrap_or("12".to_string());
            val.parse().context("Cannot parse SEARCH_TIMEOUT_SECS")?
        };
        let search_empty_result_cutoff: usize = {
            let val = env::var("SEARCH_EMPTY_RESULT_CUTOFF").unwrap_or("5".to_string());
            val.parse()
                .context("Cannot parse SEARCH_EMPTY_RESULT_CUTOFF")?
        };
        Ok(Config {
            run_id,
            log_level,
            user_name,
            user_password,
            judge_score_levenshtein,
            judge_score_llm,
            listen_port,
            search_timeout_secs,
            search_empty_result_cutoff,
            playlist_id,
            client_id,
            client_secret,
        })
    }

    #[allow(clippy::too_many_arguments)]
    pub fn new(
        log_level: EnvFilter,
        user_name: String,
        user_password: String,
        judge_score_levenshtein: Option<f32>,
        judge_score_llm: Option<f32>,
        listen_port: u32,
        search_timeout_secs: u8,
        search_empty_result_cutoff: usize,
        run_id: String,
        playlist_id: String,
        client_id: Option<String>,
        client_secret: Option<String>,
    ) -> Self {
        Config {
            run_id,
            log_level,
            user_name,
            user_password,
            judge_score_levenshtein,
            judge_score_llm,
            listen_port,
            search_timeout_secs,
            search_empty_result_cutoff,
            playlist_id,
            client_id,
            client_secret,
        }
    }
}