selene-core 0.4.2

selene-core is the backend for Selene, a local-first music player
Documentation
use std::{
    path::{Path, PathBuf},
    sync::LazyLock,
};

use directories::{BaseDirs, UserDirs};
pub use lofty::picture::PictureType;
#[cfg(feature = "net-features")]
use reqwest::blocking::Client;

use crate::media_container::{Codec, ContainerFormat};

pub const PROGRAM_FS_NAME: &str = "selene";
pub const PROGRAM_DISPLAY_NAME: &str = "Selene";

pub mod config;
pub mod database;
pub mod errors;
mod ffmpeg;
pub mod library;
pub mod media_container;
pub mod utils;

pub mod decoding;

pub mod synced_lyrics;

#[cfg(feature = "net-features")]
static REQWEST_CLIENT: LazyLock<Client> = LazyLock::new(|| {
    Client::builder()
        .user_agent(format!(
            "{PROGRAM_DISPLAY_NAME} v{ver} (https://codeberg.org/CrypticCreator/Selene)",
            ver = env!("CARGO_PKG_VERSION")
        ))
        .build()
        .unwrap()
});

#[cfg(feature = "net-features")]
pub mod lrclib;

static BASE_DIRS: LazyLock<Option<BaseDirs>> = LazyLock::new(BaseDirs::new);

/// Returns the users `base_dirs`
///
/// # Panics
///
/// Panics if the internal `BASE_DIRS` static is [`None`]. This can only happen if the home directory is not found
#[must_use]
pub fn base_dirs() -> &'static BaseDirs {
    BASE_DIRS.as_ref().unwrap()
}

#[must_use]
pub fn config_dir() -> &'static Path {
    &CONFIG_DIR
}
static CONFIG_DIR: LazyLock<PathBuf> =
    LazyLock::new(|| base_dirs().config_dir().join(PROGRAM_FS_NAME));

#[must_use]
pub fn data_dir() -> &'static Path {
    &DATA_DIR
}
static DATA_DIR: LazyLock<PathBuf> = LazyLock::new(|| base_dirs().data_dir().join(PROGRAM_FS_NAME));

#[must_use]
pub fn cache_dir() -> PathBuf {
    base_dirs().cache_dir().join(PROGRAM_FS_NAME)
}

#[must_use]
pub fn runtime_dir() -> PathBuf {
    base_dirs().runtime_dir().unwrap().join(PROGRAM_FS_NAME)
}

pub fn music_dir() -> Option<&'static Path> {
    MUSIC_DIR.as_deref()
}
static MUSIC_DIR: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
    UserDirs::new().and_then(|user_dirs| user_dirs.audio_dir().map(|p| p.join("Selene Library")))
});

// These two are the only two valid transcode pairs I plan on supporting for selene
pub const VALID_TRANSCODE_PAIRS: [(ContainerFormat, Codec); 2] = [
    (ContainerFormat::Flac, Codec::Flac),
    (ContainerFormat::Ogg, Codec::Vorbis),
];

pub const VALID_LIBRARY_FORMATS: [ContainerFormat; 3] = [
    ContainerFormat::Flac,
    ContainerFormat::Mpa,
    ContainerFormat::Ogg,
];
pub const VALID_LIBRARY_CODECS: [Codec; 3] = [Codec::Flac, Codec::Vorbis, Codec::Mp3];