Files
pmomusic/pmocovers/src/lib.rs

177 lines
5.6 KiB
Rust
Raw Normal View History

2025-10-07 08:33:06 +02:00
//! # pmocovers - Service de cache d'images de couvertures pour PMOMusic
//!
//! Cette crate fournit un système de cache d'images optimisé pour les couvertures d'albums,
//! avec conversion automatique en WebP et génération de variantes de tailles.
//!
2025-10-17 22:15:00 +02:00
//! ## Fonctionnalités
2025-10-07 08:33:06 +02:00
//!
//! - Conversion automatique en WebP pour réduire la taille
//! - Génération de variantes de tailles à la demande
//! - Cache persistant avec base de données SQLite
2025-10-17 22:15:00 +02:00
//! - API HTTP complète (fournie par `pmocache`)
2025-10-07 08:33:06 +02:00
//!
//! ## Architecture
//!
2025-10-17 22:15:00 +02:00
//! `pmocovers` est une spécialisation minimale de `pmocache` qui ajoute :
//! 1. La conversion WebP automatique lors du téléchargement (via transformer)
//! 2. La génération de variantes redimensionnées à la demande (via param generator)
2025-10-07 08:33:06 +02:00
//!
2025-10-17 22:15:00 +02:00
//! Tout le reste (API REST, serveur de fichiers, DB) est fourni par `pmocache`.
2025-10-07 08:33:06 +02:00
//!
//! ## Utilisation
//!
2025-10-26 13:44:41 +01:00
//! ### Exemple minimal
//!
//! ```rust,no_run
//! use pmocovers::cache;
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! let cache = cache::new_cache("./covers_cache", 200)?;
//! let pk = cache.add_from_url("https://example.com/cover.jpg", None).await?;
//! let path = cache.get(&pk).await?;
//! println!("Image convertie en WebP: {path:?}");
//! Ok(())
//! }
//! ```
//!
2025-10-17 22:15:00 +02:00
//! ### Exemple avec configuration automatique
2025-10-07 08:33:06 +02:00
//!
//! ```rust,no_run
//! use pmocovers::CoverCacheExt;
//! use pmoserver::ServerBuilder;
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! let mut server = ServerBuilder::new_configured().build();
//! server.init_cover_cache_configured().await?;
//! server.start().await;
//! server.wait().await;
//! Ok(())
//! }
//! ```
pub mod cache;
pub mod webp;
#[cfg(feature = "pmoserver")]
pub mod openapi;
2025-10-25 17:14:24 +02:00
#[cfg(feature = "pmoconfig")]
pub mod config_ext;
2025-10-19 13:42:29 +02:00
pub use cache::{new_cache, Cache, CoversConfig};
2025-10-07 08:33:06 +02:00
#[cfg(feature = "pmoserver")]
pub use openapi::ApiDoc;
2025-10-25 17:14:24 +02:00
#[cfg(feature = "pmoconfig")]
pub use config_ext::CoverCacheConfigExt;
2025-10-17 22:15:00 +02:00
#[cfg(feature = "pmoserver")]
2025-10-07 08:33:06 +02:00
use std::sync::Arc;
2025-10-19 13:42:29 +02:00
#[cfg(feature = "pmoserver")]
use utoipa::OpenApi;
2025-10-07 08:33:06 +02:00
2025-10-17 22:15:00 +02:00
/// Générateur de variantes d'images
2025-10-07 08:33:06 +02:00
///
2025-10-17 22:15:00 +02:00
/// Si param est numérique, génère une variante redimensionnée
#[cfg(feature = "pmoserver")]
fn create_variant_generator() -> pmocache::pmoserver_ext::ParamGenerator<CoversConfig> {
Arc::new(|cache, pk, param| {
Box::pin(async move {
// Si le param est numérique, c'est une taille de variante
if let Ok(size) = param.parse::<usize>() {
match webp::generate_variant(&cache, &pk, size).await {
Ok(data) => return Some(data),
Err(e) => {
2025-10-19 13:42:29 +02:00
tracing::warn!(
"Cannot generate variant {}x{} for {}: {}",
size,
size,
pk,
e
);
2025-10-17 22:15:00 +02:00
return None;
}
}
}
// Param non reconnu
None
})
})
}
/// Trait d'extension pour ajouter le cache de couvertures à pmoserver
#[cfg(feature = "pmoserver")]
2025-10-07 08:33:06 +02:00
pub trait CoverCacheExt {
2025-10-17 22:15:00 +02:00
/// Initialise le cache d'images et enregistre les routes HTTP
2025-10-07 08:33:06 +02:00
///
/// # Arguments
///
/// * `cache_dir` - Répertoire de stockage du cache
/// * `limit` - Limite de taille du cache (en nombre d'images)
///
/// # Returns
///
2025-10-17 22:15:00 +02:00
/// Instance partagée du cache
2025-10-07 08:33:06 +02:00
///
/// # Routes enregistrées
///
2025-10-17 22:15:00 +02:00
/// - `GET /covers/image/{pk}` - Image originale
/// - `GET /covers/image/{pk}/{size}` - Variante de taille (ex: 256, 512)
2025-10-07 08:33:06 +02:00
/// - `GET /api/covers` - Liste des images (API REST)
/// - `POST /api/covers` - Ajouter une image (API REST)
/// - `DELETE /api/covers/{pk}` - Supprimer une image (API REST)
2025-10-17 22:15:00 +02:00
/// - `GET /api/covers/{pk}/status` - Statut du téléchargement
/// - `GET /swagger-ui/covers` - Documentation interactive
2025-10-19 13:42:29 +02:00
async fn init_cover_cache(
&mut self,
cache_dir: &str,
limit: usize,
) -> anyhow::Result<Arc<Cache>>;
2025-10-07 08:33:06 +02:00
2025-10-17 22:15:00 +02:00
/// Initialise le cache d'images avec la configuration par défaut
2025-10-07 08:33:06 +02:00
///
2025-10-17 22:15:00 +02:00
/// Utilise automatiquement les paramètres de `pmoconfig::Config`
2025-10-19 13:42:29 +02:00
async fn init_cover_cache_configured(&mut self) -> anyhow::Result<Arc<Cache>>;
2025-10-07 08:33:06 +02:00
}
#[cfg(feature = "pmoserver")]
2025-10-17 22:15:00 +02:00
impl CoverCacheExt for pmoserver::Server {
2025-10-19 13:42:29 +02:00
async fn init_cover_cache(
&mut self,
cache_dir: &str,
limit: usize,
) -> anyhow::Result<Arc<Cache>> {
use pmocache::pmoserver_ext::{create_api_router, create_file_router_with_generator};
2025-10-17 22:15:00 +02:00
2025-10-18 09:58:39 +02:00
let cache = Arc::new(cache::new_cache(cache_dir, limit)?);
2025-10-17 22:15:00 +02:00
// Router de fichiers avec génération de variantes
// Routes: GET /covers/image/{pk} et GET /covers/image/{pk}/{size}
let file_router = create_file_router_with_generator(
cache.clone(),
"image/webp",
2025-10-19 13:42:29 +02:00
Some(create_variant_generator()),
2025-10-17 22:15:00 +02:00
);
self.add_router("/", file_router).await;
// API REST générique (pmocache)
// Routes: GET/POST/DELETE /api/covers, etc.
let api_router = create_api_router(cache.clone());
let openapi = crate::ApiDoc::openapi();
self.add_openapi(api_router, openapi, "covers").await;
Ok(cache)
}
2025-10-19 13:42:29 +02:00
async fn init_cover_cache_configured(&mut self) -> anyhow::Result<Arc<Cache>> {
2025-10-25 17:14:24 +02:00
use crate::CoverCacheConfigExt;
2025-10-17 22:15:00 +02:00
let config = pmoconfig::get_config();
2025-10-25 17:14:24 +02:00
let cache_dir = config.get_covers_dir()?;
let limit = config.get_covers_size()?;
2025-10-17 22:15:00 +02:00
self.init_cover_cache(&cache_dir, limit).await
}
}