1use std::{
2 path::PathBuf,
3 sync::{LazyLock, RwLock, RwLockReadGuard, RwLockWriteGuard},
4};
5
6use lunar_lib::{config::Config, error, formatter::TemplateOwned};
7use serde::{Deserialize, Serialize};
8
9use crate::lyrics::LyricFormat;
10
11static COMMON_CONFIG: LazyLock<RwLock<CommonConfig>> = LazyLock::new(|| {
12 let config = match CommonConfig::load() {
13 Ok(config) => config,
14 Err(err) => {
15 error!(
16 "Could not load common config from file, assuming defaults. Reason: {:?}",
17 err
18 );
19 CommonConfig::default()
20 }
21 };
22 RwLock::new(config)
23});
24
25pub fn common_config() -> RwLockReadGuard<'static, CommonConfig> {
31 COMMON_CONFIG.read().unwrap()
32}
33
34pub fn common_config_mut() -> RwLockWriteGuard<'static, CommonConfig> {
40 COMMON_CONFIG.write().unwrap()
41}
42
43mod core_impls;
44
45#[derive(Debug, Serialize, Deserialize, Default)]
46#[serde(default)]
47pub struct CommonConfig {
48 pub main: MainSettings,
49 pub loudnorm: LoudnormSettings,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53#[serde(default)]
54pub struct MainSettings {
55 pub source_directories: Vec<PathBuf>,
56 pub multithreading: bool,
57}
58
59impl Default for MainSettings {
60 fn default() -> Self {
61 Self {
62 multithreading: true,
63 source_directories: Vec::new(),
64 }
65 }
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
69pub struct TrackNameSettings {
70 pub format_string: TemplateOwned,
71 pub artist_separator: String,
72 pub alt_artist_separator: String,
73}
74
75#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
76#[serde(default)]
77pub struct LoudnormSettings {
78 pub accurate_true_peak: bool,
79
80 pub target_offset: f64,
81 pub target_i: f64,
82 pub target_tp: f64,
83}
84
85impl Default for LoudnormSettings {
86 fn default() -> Self {
87 Self {
88 accurate_true_peak: true,
89
90 target_offset: 0.0,
91 target_i: -14.0,
92 target_tp: -2.0,
93 }
94 }
95}
96
97pub struct ExportConfig {
98 pub file_name_format: TemplateOwned,
100 pub artist_separator: String,
101 pub alt_artist_separator: String,
102
103 pub album_data_path: Option<TemplateOwned>,
104
105 pub export_synced_lyrics_as: Option<LyricFormat>,
106 pub plain_lyrics_as_txt: bool,
107
108 pub singles_as_albums: bool,
110 pub multi_value_strategy: MultiValueStrategy,
111}
112
113impl ExportConfig {
114 pub fn selene_export() -> Self {
115 Self {
116 file_name_format: TemplateOwned::new("{$album>/}{$main_track_artist?UNKNOWN ARTIST} - {$title?UNKNOWN TITLE}{$feat_track_artists< (feat. >)}").unwrap(),
117 artist_separator: ", ".to_owned(),
118 alt_artist_separator: " & ".to_owned(),
119 album_data_path: Some(TemplateOwned::new("{$album}/").unwrap()),
120 export_synced_lyrics_as: Some(LyricFormat::SeleneLrc),
121 plain_lyrics_as_txt: true,
122 singles_as_albums: false,
123 multi_value_strategy: MultiValueStrategy::MultipleTags,
124 }
125 }
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
129pub enum MultiValueStrategy {
130 MultipleTags,
131 JoinBy(String),
132 First,
133}