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

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

106
pmocovers/src/config_ext.rs Normal file
View File

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

View File

@@ -42,11 +42,17 @@ pub mod webp;
#[cfg(feature = "pmoserver")]
pub mod openapi;
#[cfg(feature = "pmoconfig")]
pub mod config_ext;
pub use cache::{new_cache, Cache, CoversConfig};
#[cfg(feature = "pmoserver")]
pub use openapi::ApiDoc;
#[cfg(feature = "pmoconfig")]
pub use config_ext::CoverCacheConfigExt;
#[cfg(feature = "pmoserver")]
use std::sync::Arc;
#[cfg(feature = "pmoserver")]
@@ -146,9 +152,10 @@ impl CoverCacheExt for pmoserver::Server {
}
async fn init_cover_cache_configured(&mut self) -> anyhow::Result<Arc<Cache>> {
use crate::CoverCacheConfigExt;
let config = pmoconfig::get_config();
let cache_dir = config.get_cover_cache_dir()?;
let limit = config.get_cover_cache_size()?;
let cache_dir = config.get_covers_dir()?;
let limit = config.get_covers_size()?;
self.init_cover_cache(&cache_dir, limit).await
}
}

View File

@@ -2,6 +2,25 @@ use anyhow::Result;
use image::{imageops::FilterType, DynamicImage};
use webp::{Encoder, WebPMemory};
/// Encode une image en format WebP avec un niveau de qualité de 85%
///
/// # Arguments
///
/// * `img` - Image à encoder
///
/// # Returns
///
/// Les données WebP encodées sous forme de vecteur d'octets
///
/// # Exemple
///
/// ```rust,ignore
/// use pmocovers::webp::encode_webp;
/// use image::DynamicImage;
///
/// let img = DynamicImage::new_rgba8(100, 100);
/// let webp_data = encode_webp(&img)?;
/// ```
pub fn encode_webp(img: &DynamicImage) -> Result<Vec<u8>> {
let rgb_img = img.to_rgba8();
let encoder = Encoder::from_rgba(&rgb_img, rgb_img.width(), rgb_img.height());
@@ -9,6 +28,31 @@ pub fn encode_webp(img: &DynamicImage) -> Result<Vec<u8>> {
Ok(webp_data.to_vec())
}
/// Redimensionne une image pour l'inscrire dans un carré de taille donnée
///
/// Cette fonction préserve le ratio d'aspect de l'image originale en la redimensionnant
/// pour qu'elle tienne dans un carré, puis la centre sur un fond transparent.
///
/// # Arguments
///
/// * `img` - Image à redimensionner
/// * `size` - Taille du carré de sortie (en pixels)
///
/// # Returns
///
/// Une nouvelle image carrée de taille `size × size` avec l'image originale centrée
///
/// # Exemple
///
/// ```rust,ignore
/// use pmocovers::webp::ensure_square;
/// use image::DynamicImage;
///
/// let img = DynamicImage::new_rgba8(800, 600);
/// let square = ensure_square(&img, 256);
/// assert_eq!(square.width(), 256);
/// assert_eq!(square.height(), 256);
/// ```
pub fn ensure_square(img: &DynamicImage, size: u32) -> DynamicImage {
let (width, height) = (img.width(), img.height());
@@ -38,6 +82,36 @@ pub fn ensure_square(img: &DynamicImage, size: u32) -> DynamicImage {
square
}
/// Génère une variante redimensionnée d'une image en cache
///
/// Cette fonction crée (ou récupère si déjà existante) une variante redimensionnée
/// d'une image. La variante est mise en cache sur disque pour éviter les
/// recalculs futurs.
///
/// # Arguments
///
/// * `cache` - Instance du cache de couvertures
/// * `pk` - Clé primaire de l'image
/// * `size` - Taille de la variante (carré de `size × size`)
///
/// # Returns
///
/// Les données WebP de la variante redimensionnée
///
/// # Comportement
///
/// 1. Si la variante existe déjà sur disque, elle est retournée directement
/// 2. Sinon, l'image originale est chargée, redimensionnée et encodée en WebP
/// 3. La variante est sauvegardée sur disque pour utilisation future
///
/// # Exemple
///
/// ```rust,ignore
/// use pmocovers::webp::generate_variant;
///
/// let cache = pmocovers::cache::new_cache("./cache", 1000)?;
/// let variant_256 = generate_variant(&cache, "abc123", 256).await?;
/// ```
pub async fn generate_variant(
cache: &super::cache::Cache,
pk: &str,