various: simplify code; work on security and performance

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9a5114addcab5fbff430ab2b919b83466a6a6964
This commit is contained in:
raf 2026-02-02 17:32:11 +03:00
commit c4adc4e3e0
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
75 changed files with 12921 additions and 358 deletions

View file

@ -20,6 +20,16 @@ pub struct Config {
pub webhooks: Vec<WebhookConfig>,
#[serde(default)]
pub scheduled_tasks: Vec<ScheduledTaskConfig>,
#[serde(default)]
pub plugins: PluginsConfig,
#[serde(default)]
pub transcoding: TranscodingConfig,
#[serde(default)]
pub enrichment: EnrichmentConfig,
#[serde(default)]
pub cloud: CloudConfig,
#[serde(default)]
pub analytics: AnalyticsConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -192,6 +202,233 @@ impl std::fmt::Display for UserRole {
}
}
// ===== Plugin Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginsConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_plugin_data_dir")]
pub data_dir: PathBuf,
#[serde(default = "default_plugin_cache_dir")]
pub cache_dir: PathBuf,
#[serde(default)]
pub plugin_dirs: Vec<PathBuf>,
#[serde(default)]
pub enable_hot_reload: bool,
#[serde(default)]
pub allow_unsigned: bool,
#[serde(default = "default_max_concurrent_ops")]
pub max_concurrent_ops: usize,
#[serde(default = "default_plugin_timeout")]
pub plugin_timeout_secs: u64,
}
fn default_plugin_data_dir() -> PathBuf {
Config::default_data_dir().join("plugins").join("data")
}
fn default_plugin_cache_dir() -> PathBuf {
Config::default_data_dir().join("plugins").join("cache")
}
fn default_max_concurrent_ops() -> usize {
4
}
fn default_plugin_timeout() -> u64 {
30
}
impl Default for PluginsConfig {
fn default() -> Self {
Self {
enabled: false,
data_dir: default_plugin_data_dir(),
cache_dir: default_plugin_cache_dir(),
plugin_dirs: vec![],
enable_hot_reload: false,
allow_unsigned: false,
max_concurrent_ops: default_max_concurrent_ops(),
plugin_timeout_secs: default_plugin_timeout(),
}
}
}
// ===== Transcoding Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TranscodingConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub cache_dir: Option<PathBuf>,
#[serde(default = "default_cache_ttl_hours")]
pub cache_ttl_hours: u64,
#[serde(default = "default_max_concurrent_transcodes")]
pub max_concurrent: usize,
#[serde(default)]
pub hardware_acceleration: Option<String>,
#[serde(default)]
pub profiles: Vec<TranscodeProfile>,
}
fn default_cache_ttl_hours() -> u64 {
48
}
fn default_max_concurrent_transcodes() -> usize {
2
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TranscodeProfile {
pub name: String,
pub video_codec: String,
pub audio_codec: String,
pub max_bitrate_kbps: u32,
pub max_resolution: String,
}
impl Default for TranscodingConfig {
fn default() -> Self {
Self {
enabled: false,
cache_dir: None,
cache_ttl_hours: default_cache_ttl_hours(),
max_concurrent: default_max_concurrent_transcodes(),
hardware_acceleration: None,
profiles: vec![
TranscodeProfile {
name: "high".to_string(),
video_codec: "h264".to_string(),
audio_codec: "aac".to_string(),
max_bitrate_kbps: 8000,
max_resolution: "1080p".to_string(),
},
TranscodeProfile {
name: "medium".to_string(),
video_codec: "h264".to_string(),
audio_codec: "aac".to_string(),
max_bitrate_kbps: 4000,
max_resolution: "720p".to_string(),
},
],
}
}
}
// ===== Enrichment Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EnrichmentConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub auto_enrich_on_import: bool,
#[serde(default)]
pub sources: EnrichmentSources,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EnrichmentSources {
#[serde(default)]
pub musicbrainz: EnrichmentSource,
#[serde(default)]
pub tmdb: EnrichmentSource,
#[serde(default)]
pub lastfm: EnrichmentSource,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EnrichmentSource {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub api_key: Option<String>,
#[serde(default)]
pub api_endpoint: Option<String>,
}
// ===== Cloud Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_auto_sync_interval")]
pub auto_sync_interval_mins: u64,
#[serde(default)]
pub accounts: Vec<CloudAccount>,
}
fn default_auto_sync_interval() -> u64 {
60
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudAccount {
pub id: String,
pub provider: String,
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub sync_rules: Vec<CloudSyncRule>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudSyncRule {
pub local_path: PathBuf,
pub remote_path: String,
pub direction: CloudSyncDirection,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CloudSyncDirection {
Upload,
Download,
Bidirectional,
}
impl Default for CloudConfig {
fn default() -> Self {
Self {
enabled: false,
auto_sync_interval_mins: default_auto_sync_interval(),
accounts: vec![],
}
}
}
// ===== Analytics Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalyticsConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_true")]
pub track_usage: bool,
#[serde(default = "default_retention_days")]
pub retention_days: u64,
}
fn default_retention_days() -> u64 {
90
}
impl Default for AnalyticsConfig {
fn default() -> Self {
Self {
enabled: false,
track_usage: true,
retention_days: default_retention_days(),
}
}
}
// ===== Storage Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageConfig {
pub backend: StorageBackendType,
@ -379,6 +616,11 @@ impl Default for Config {
thumbnails: ThumbnailConfig::default(),
webhooks: vec![],
scheduled_tasks: vec![],
plugins: PluginsConfig::default(),
transcoding: TranscodingConfig::default(),
enrichment: EnrichmentConfig::default(),
cloud: CloudConfig::default(),
analytics: AnalyticsConfig::default(),
}
}
}