refactoring des caches

This commit is contained in:
2025-10-25 17:14:24 +02:00
parent 180241a315
commit ecb362ae48
21 changed files with 964 additions and 245 deletions

View File

@@ -48,4 +48,5 @@ tracing-subscriber = "0.3"
[features]
default = ["pmoserver"]
pmoserver = ["dep:pmoserver", "dep:pmoconfig", "dep:axum", "dep:utoipa", "pmocache/pmoserver", "pmocache/openapi"]
pmoconfig = ["dep:pmoconfig", "pmocache/pmoconfig"]
pmoserver = ["pmoconfig", "dep:pmoserver", "dep:axum", "dep:utoipa", "pmocache/pmoserver", "pmocache/openapi"]

View File

@@ -0,0 +1,106 @@
//! Extension pour intégrer le cache audio dans pmoconfig
//!
//! Ce module fournit le trait `AudioCacheConfigExt` qui permet d'ajouter facilement
//! des méthodes de gestion du cache audio à pmoconfig::Config.
use anyhow::Result;
use pmoconfig::Config;
use pmocache::CacheConfigExt;
use std::sync::Arc;
const DEFAULT_AUDIO_CACHE_DIR: &str = "cache_audio";
const DEFAULT_AUDIO_CACHE_SIZE: usize = 500;
/// Trait d'extension pour gérer le cache audio dans pmoconfig
///
/// Ce trait étend `pmoconfig::Config` avec des méthodes spécifiques
/// au cache audio avec conversion FLAC.
///
/// # Exemple
///
/// ```rust,ignore
/// use pmoconfig::get_config;
/// use pmoaudiocache::AudioCacheConfigExt;
///
/// let config = get_config();
/// let cache = config.create_audio_cache()?;
///
/// // Utiliser le cache
/// let pk = cache.add_from_url("http://example.com/track.mp3", Some("album:123")).await?;
/// ```
pub trait AudioCacheConfigExt {
/// Récupère le répertoire du cache audio
///
/// # Returns
///
/// Le chemin absolu du répertoire du cache audio (default: "cache_audio")
fn get_audiocache_dir(&self) -> Result<String>;
/// Définit le répertoire du cache audio
///
/// # Arguments
///
/// * `directory` - Chemin du répertoire (absolu ou relatif au config_dir)
fn set_audiocache_dir(&self, directory: String) -> Result<()>;
/// Récupère la taille maximale du cache audio
///
/// # Returns
///
/// Le nombre maximal de pistes audio dans le cache (default: 500)
fn get_audiocache_size(&self) -> Result<usize>;
/// Définit la taille maximale du cache audio
///
/// # Arguments
///
/// * `size` - Nombre maximal de pistes audio
fn set_audiocache_size(&self, size: usize) -> Result<()>;
/// Crée une instance du cache audio configurée avec conversion FLAC
///
/// Cette méthode factory crée un cache audio en utilisant les paramètres
/// de configuration (répertoire et taille) et active la conversion FLAC
/// automatique pour tous les fichiers audio téléchargés.
///
/// # Returns
///
/// Une instance Arc du cache audio configuré
///
/// # Exemple
///
/// ```rust,ignore
/// use pmoconfig::get_config;
/// use pmoaudiocache::AudioCacheConfigExt;
///
/// let config = get_config();
/// let cache = config.create_audio_cache()?;
///
/// // Le cache est prêt à être utilisé avec conversion FLAC automatique
/// ```
fn create_audio_cache(&self) -> Result<Arc<crate::Cache>>;
}
impl AudioCacheConfigExt for Config {
fn get_audiocache_dir(&self) -> Result<String> {
self.get_cache_dir("audio_cache", DEFAULT_AUDIO_CACHE_DIR)
}
fn set_audiocache_dir(&self, directory: String) -> Result<()> {
self.set_cache_dir("audio_cache", directory)
}
fn get_audiocache_size(&self) -> Result<usize> {
self.get_cache_size("audio_cache", DEFAULT_AUDIO_CACHE_SIZE)
}
fn set_audiocache_size(&self, size: usize) -> Result<()> {
self.set_cache_size("audio_cache", size)
}
fn create_audio_cache(&self) -> Result<Arc<crate::Cache>> {
let dir = self.get_audiocache_dir()?;
let size = self.get_audiocache_size()?;
Ok(Arc::new(crate::cache::new_cache(&dir, size)?))
}
}

View File

@@ -137,10 +137,16 @@ pub mod metadata;
#[cfg(feature = "pmoserver")]
pub mod openapi;
#[cfg(feature = "pmoconfig")]
pub mod config_ext;
// Re-exports principaux
pub use cache::{add_with_metadata_extraction, get_metadata, new_cache, AudioConfig, Cache};
pub use metadata::AudioMetadata;
#[cfg(feature = "pmoconfig")]
pub use config_ext::AudioCacheConfigExt;
#[cfg(feature = "pmoserver")]
pub use openapi::ApiDoc;
@@ -207,9 +213,10 @@ impl AudioCacheExt for pmoserver::Server {
}
async fn init_audio_cache_configured(&mut self) -> anyhow::Result<Arc<Cache>> {
use crate::AudioCacheConfigExt;
let config = pmoconfig::get_config();
let cache_dir = config.get_audio_cache_dir()?;
let limit = config.get_audio_cache_size()?;
let cache_dir = config.get_audiocache_dir()?;
let limit = config.get_audiocache_size()?;
self.init_audio_cache(&cache_dir, limit).await
}
}

View File

@@ -71,6 +71,46 @@ pub struct AudioMetadata {
}
impl AudioMetadata {
/// Extrait les métadonnées depuis un fichier audio taggé
///
/// Fonction interne commune pour extraire les métadonnées depuis un TaggedFile
fn from_tagged_file(tagged_file: lofty::file::TaggedFile) -> Self {
let properties = tagged_file.properties();
let tag = tagged_file
.primary_tag()
.or_else(|| tagged_file.first_tag());
let mut metadata = Self {
title: None,
artist: None,
album: None,
year: None,
track_number: None,
track_total: None,
disc_number: None,
disc_total: None,
genre: None,
duration_secs: Some(properties.duration().as_secs()),
sample_rate: properties.sample_rate(),
channels: properties.channels(),
bitrate: properties.audio_bitrate(),
};
if let Some(tag) = tag {
metadata.title = tag.title().map(|s| s.to_string());
metadata.artist = tag.artist().map(|s| s.to_string());
metadata.album = tag.album().map(|s| s.to_string());
metadata.year = tag.year();
metadata.track_number = tag.track();
metadata.track_total = tag.track_total();
metadata.disc_number = tag.disk();
metadata.disc_total = tag.disk_total();
metadata.genre = tag.genre().map(|s| s.to_string());
}
metadata
}
/// Extrait les métadonnées d'un fichier audio
///
/// # Arguments
@@ -88,41 +128,7 @@ impl AudioMetadata {
/// ```
pub fn from_file(path: &Path) -> Result<Self> {
let tagged_file = Probe::open(path)?.options(ParseOptions::new()).read()?;
let properties = tagged_file.properties();
let tag = tagged_file
.primary_tag()
.or_else(|| tagged_file.first_tag());
let mut metadata = Self {
title: None,
artist: None,
album: None,
year: None,
track_number: None,
track_total: None,
disc_number: None,
disc_total: None,
genre: None,
duration_secs: Some(properties.duration().as_secs()),
sample_rate: properties.sample_rate(),
channels: properties.channels(),
bitrate: properties.audio_bitrate(),
};
if let Some(tag) = tag {
metadata.title = tag.title().map(|s| s.to_string());
metadata.artist = tag.artist().map(|s| s.to_string());
metadata.album = tag.album().map(|s| s.to_string());
metadata.year = tag.year();
metadata.track_number = tag.track();
metadata.track_total = tag.track_total();
metadata.disc_number = tag.disk();
metadata.disc_total = tag.disk_total();
metadata.genre = tag.genre().map(|s| s.to_string());
}
Ok(metadata)
Ok(Self::from_tagged_file(tagged_file))
}
/// Crée des métadonnées depuis des données brutes audio
@@ -136,41 +142,7 @@ impl AudioMetadata {
.guess_file_type()?
.options(ParseOptions::new())
.read()?;
let properties = tagged_file.properties();
let tag = tagged_file
.primary_tag()
.or_else(|| tagged_file.first_tag());
let mut metadata = Self {
title: None,
artist: None,
album: None,
year: None,
track_number: None,
track_total: None,
disc_number: None,
disc_total: None,
genre: None,
duration_secs: Some(properties.duration().as_secs()),
sample_rate: properties.sample_rate(),
channels: properties.channels(),
bitrate: properties.audio_bitrate(),
};
if let Some(tag) = tag {
metadata.title = tag.title().map(|s| s.to_string());
metadata.artist = tag.artist().map(|s| s.to_string());
metadata.album = tag.album().map(|s| s.to_string());
metadata.year = tag.year();
metadata.track_number = tag.track();
metadata.track_total = tag.track_total();
metadata.disc_number = tag.disk();
metadata.disc_total = tag.disk_total();
metadata.genre = tag.genre().map(|s| s.to_string());
}
Ok(metadata)
Ok(Self::from_tagged_file(tagged_file))
}
/// Génère une clé de collection basée sur l'artiste et l'album