1#![forbid(unsafe_code)]
2
3use std::{
4 path::{Path, PathBuf},
5 sync::LazyLock,
6};
7
8use directories::{BaseDirs, UserDirs};
9
10pub const PROGRAM_FS_NAME: &str = "selene";
11pub const PROGRAM_DISPLAY_NAME: &str = "Selene";
12
13#[cfg(feature = "lrclib")]
14pub mod lrclib;
15
16#[cfg(feature = "lastfm")]
17pub mod scrobbling;
18
19pub mod config;
20pub mod database;
21pub mod library;
22pub mod lyrics;
23pub mod media_container;
24pub mod utils;
25
26pub mod symphonia_helpers;
27
28#[cfg(any(feature = "lrclib", feature = "lastfm"))]
29static REQWEST_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(|| {
30 reqwest::Client::builder()
31 .user_agent(format!(
32 "{PROGRAM_DISPLAY_NAME} v{ver} (https://codeberg.org/CrypticCreator/Selene)",
33 ver = env!("CARGO_PKG_VERSION")
34 ))
35 .build()
36 .unwrap()
37});
38
39static BASE_DIRS: LazyLock<Option<BaseDirs>> = LazyLock::new(BaseDirs::new);
40
41#[must_use]
47pub fn base_dirs() -> &'static BaseDirs {
48 BASE_DIRS.as_ref().unwrap()
49}
50
51#[must_use]
52pub fn config_dir() -> &'static Path {
53 &CONFIG_DIR
54}
55static CONFIG_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
56 let config_dir = base_dirs().config_dir();
57 if config_dir == base_dirs().data_dir() {
58 DATA_DIR.join("config")
59 } else {
60 config_dir.join(PROGRAM_FS_NAME)
61 }
62});
63
64#[must_use]
65pub fn data_dir() -> &'static Path {
66 &DATA_DIR
67}
68static DATA_DIR: LazyLock<PathBuf> = LazyLock::new(|| base_dirs().data_dir().join(PROGRAM_FS_NAME));
69
70#[must_use]
71pub fn state_dir() -> &'static Path {
72 &STATE_DIR
73}
74static STATE_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
75 base_dirs()
76 .state_dir()
77 .map_or(DATA_DIR.join("state"), |p| p.join(PROGRAM_FS_NAME))
78});
79
80#[must_use]
81pub fn cache_dir() -> PathBuf {
82 base_dirs().cache_dir().join(PROGRAM_FS_NAME)
83}
84
85#[must_use]
86pub fn runtime_dir() -> PathBuf {
87 base_dirs()
88 .runtime_dir()
89 .unwrap_or_else(|| base_dirs().cache_dir())
90 .join(PROGRAM_FS_NAME)
91}
92
93pub fn music_dir() -> Option<&'static Path> {
94 MUSIC_DIR.as_deref()
95}
96static MUSIC_DIR: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
97 UserDirs::new().and_then(|user_dirs| user_dirs.audio_dir().map(|p| p.join("Selene Library")))
98});