speakers-core 0.2.0

Core library for the speakers local TTS CLI and daemon
Documentation
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};

const APP_NAME: &str = "speakers";
const LEGACY_APP_NAME: &str = "speake-rs";

fn home_dir() -> PathBuf {
    std::env::var("HOME")
        .map(PathBuf::from)
        .unwrap_or_else(|_| PathBuf::from("."))
}

pub fn config_home() -> PathBuf {
    std::env::var("XDG_CONFIG_HOME")
        .map(PathBuf::from)
        .unwrap_or_else(|_| home_dir().join(".config"))
}

pub fn data_home() -> PathBuf {
    std::env::var("XDG_DATA_HOME")
        .map(PathBuf::from)
        .unwrap_or_else(|_| home_dir().join(".local/share"))
}

pub fn runtime_home() -> PathBuf {
    std::env::var("XDG_RUNTIME_DIR")
        .map(PathBuf::from)
        .unwrap_or_else(|_| PathBuf::from("/tmp"))
}

pub fn app_config_dir() -> PathBuf {
    config_home().join(APP_NAME)
}

pub fn app_data_dir() -> PathBuf {
    data_home().join(APP_NAME)
}

pub fn app_runtime_dir() -> PathBuf {
    runtime_home().join(APP_NAME)
}

pub fn legacy_app_config_dir() -> PathBuf {
    config_home().join(LEGACY_APP_NAME)
}

pub fn legacy_app_data_dir() -> PathBuf {
    data_home().join(LEGACY_APP_NAME)
}

pub fn config_path() -> PathBuf {
    app_config_dir().join("config.toml")
}

pub fn legacy_config_path() -> PathBuf {
    legacy_app_config_dir().join("config.toml")
}

pub fn existing_config_path() -> Option<PathBuf> {
    let current = config_path();
    if current.exists() {
        return Some(current);
    }

    let legacy = legacy_config_path();
    legacy.exists().then_some(legacy)
}

pub fn socket_path() -> PathBuf {
    app_runtime_dir().join("daemon.sock")
}

pub fn pid_path() -> PathBuf {
    app_runtime_dir().join("daemon.pid")
}

pub fn profiles_dir() -> PathBuf {
    app_data_dir().join("voices")
}

pub fn legacy_profiles_dir() -> PathBuf {
    legacy_app_data_dir().join("voices")
}

pub fn ensure_parent(path: &Path) -> Result<()> {
    let parent = path
        .parent()
        .with_context(|| format!("path has no parent: {}", path.display()))?;
    std::fs::create_dir_all(parent)
        .with_context(|| format!("failed to create directory: {}", parent.display()))
}

pub fn ensure_runtime_dir() -> Result<PathBuf> {
    let dir = app_runtime_dir();
    std::fs::create_dir_all(&dir)
        .with_context(|| format!("failed to create runtime dir: {}", dir.display()))?;
    Ok(dir)
}

pub fn ensure_profiles_dir() -> Result<PathBuf> {
    let dir = profiles_dir();
    std::fs::create_dir_all(&dir)
        .with_context(|| format!("failed to create profiles dir: {}", dir.display()))?;
    Ok(dir)
}