lavende-core 0.1.13

Core in-process Discord voice connection and playback engine
Documentation
pub mod audio;
pub mod common;
pub mod config;
pub mod events;
pub mod gateway;
pub mod pipeline;
pub mod player;
pub mod protocol;
pub mod routeplanner;
pub mod sources;
pub mod transport;
pub mod utils;

pub use player::Player;

use config::AppConfig;
use sources::manager::SourceManager;
use std::fs;
use std::path::Path;
use std::sync::{Arc, Mutex, OnceLock};

static SOURCE_MANAGER: OnceLock<Mutex<Option<Arc<SourceManager>>>> = OnceLock::new();
static CONFIG_PATH: Mutex<Option<String>> = Mutex::new(None);

pub fn set_config_path(path: Option<String>) {
    if let Ok(mut config_path) = CONFIG_PATH.lock() {
        *config_path = path;
    }
}

pub fn get_source_manager() -> &'static Mutex<Option<Arc<SourceManager>>> {
    SOURCE_MANAGER.get_or_init(|| {
        let config_file = CONFIG_PATH
            .lock()
            .ok()
            .and_then(|p| p.clone())
            .unwrap_or_else(|| "source.json".to_string());

        let mut config = AppConfig::default();
        let path = Path::new(&config_file);

        if path.exists() {
            if let Ok(raw) = fs::read_to_string(path) {
                if let Ok(json_val) = serde_json::from_str::<serde_json::Value>(&raw) {
                    if let Some(sources_val) = json_val.get("sources") {
                        if let Ok(sources_cfg) = serde_json::from_value(sources_val.clone()) {
                            config.sources = sources_cfg;
                        }
                    }
                    if let Some(rp_val) = json_val.get("route_planner") {
                        if let Ok(rp_cfg) = serde_json::from_value(rp_val.clone()) {
                            config.route_planner = rp_cfg;
                        }
                    }
                    if let Some(player_val) = json_val.get("player") {
                        if let Ok(player_cfg) = serde_json::from_value(player_val.clone()) {
                            config.player = player_cfg;
                        }
                    }
                }
            }
        } else {
            println!(
                "Warning: {} not found in current directory. Using default source configuration.",
                config_file
            );
        }

        let logging_cfg = config.logging.clone().unwrap_or_default();
        common::logger::init(&logging_cfg);
        Mutex::new(Some(Arc::new(SourceManager::new(&config))))
    })
}

pub async fn resolve_jiosaavn(url_or_token: String) -> Result<String, String> {
    Ok(url_or_token)
}

pub async fn resolve_youtube(url_or_id: String) -> Result<String, String> {
    Ok(url_or_id)
}

pub async fn load(identifier: String) -> Result<String, String> {
    let sm_arc = {
        let sm_guard = get_source_manager().lock().map_err(|e| e.to_string())?;
        sm_guard
            .as_ref()
            .ok_or("SourceManager not initialized")?
            .clone()
    };
    let res = sm_arc.load(&identifier, None).await;
    serde_json::to_string(&res).map_err(|e| e.to_string())
}