This commit enhances the Radio France source by: 1. Updating the main.rs file to clarify the purpose of registering the Radio France source, including API route initialization 2. Modifying sources.rs to: - Add RadioFranceExt to the imports - Initialize API routes for Radio France after registering the source 3. Updating source.rs to: - Use a default logo for Radio France containers when server_base_url is configured - Apply the default logo to both group and 'Radios ICI' containers These changes improve the integration and visual presentation of Radio France content within the media server.
295 lines
9.2 KiB
Rust
295 lines
9.2 KiB
Rust
//! # Source Helpers - Helpers pour l'initialisation simplifiée de sources
|
|
//!
|
|
//! Ce module fournit des helpers pour créer et enregistrer facilement des sources
|
|
//! musicales préconfigurées à partir de la configuration système.
|
|
|
|
use pmoserver::Server;
|
|
use pmosource::MusicSourceExt;
|
|
use std::sync::Arc;
|
|
|
|
/// Erreur lors de l'initialisation d'une source
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum SourceInitError {
|
|
#[cfg(feature = "qobuz")]
|
|
#[error("Failed to initialize Qobuz: {0}")]
|
|
QobuzError(String),
|
|
|
|
#[cfg(feature = "paradise")]
|
|
#[error("Failed to initialize Radio Paradise: {0}")]
|
|
ParadiseError(String),
|
|
|
|
#[cfg(feature = "radiofrance")]
|
|
#[error("Failed to initialize Radio France: {0}")]
|
|
RadioFranceError(String),
|
|
|
|
#[error("Configuration error: {0}")]
|
|
ConfigError(String),
|
|
|
|
#[error("Source not available: {0}")]
|
|
NotAvailable(String),
|
|
}
|
|
|
|
/// Result type pour les opérations d'initialisation de sources
|
|
pub type Result<T> = std::result::Result<T, SourceInitError>;
|
|
|
|
/// Extension trait pour faciliter l'enregistrement de sources préconfigurées
|
|
///
|
|
/// Ce trait ajoute des méthodes pratiques à `Server` pour enregistrer des sources
|
|
/// musicales préconfigurées à partir de la configuration système.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```ignore
|
|
/// use pmomediaserver::sources::SourcesExt;
|
|
/// use pmoserver::ServerBuilder;
|
|
///
|
|
/// let mut server = ServerBuilder::new_configured().build();
|
|
///
|
|
/// // Enregistrer Qobuz depuis la config
|
|
/// server.register_qobuz_from_config().await?;
|
|
///
|
|
/// // Lister toutes les sources
|
|
/// let sources = server.list_music_sources().await;
|
|
/// println!("{} sources registered", sources.len());
|
|
/// ```
|
|
#[async_trait::async_trait]
|
|
pub trait SourcesExt {
|
|
/// Enregistre la source Qobuz
|
|
///
|
|
/// Cette méthode lit les credentials Qobuz depuis `pmoconfig` et crée
|
|
/// automatiquement un `QobuzSource` avec cache activé.
|
|
///
|
|
/// # Configuration requise
|
|
///
|
|
/// Le fichier de configuration doit contenir :
|
|
/// ```yaml
|
|
/// accounts:
|
|
/// qobuz:
|
|
/// username: "votre@email.com"
|
|
/// password: "votrepassword"
|
|
/// ```
|
|
///
|
|
/// # Erreurs
|
|
///
|
|
/// Retourne une erreur si :
|
|
/// - La configuration Qobuz n'est pas trouvée
|
|
/// - L'authentification échoue
|
|
/// - La feature "qobuz" n'est pas activée
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```ignore
|
|
/// server.register_qobuz().await?;
|
|
/// ```
|
|
#[cfg(feature = "qobuz")]
|
|
async fn register_qobuz(&mut self) -> Result<()>;
|
|
|
|
/// Enregistre la source Qobuz avec des credentials explicites
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `username` - Nom d'utilisateur Qobuz
|
|
/// * `password` - Mot de passe Qobuz
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```ignore
|
|
/// server.register_qobuz_with_credentials("user@example.com", "password").await?;
|
|
/// ```
|
|
#[cfg(feature = "qobuz")]
|
|
async fn register_qobuz_with_credentials(
|
|
&mut self,
|
|
username: &str,
|
|
password: &str,
|
|
) -> Result<()>;
|
|
|
|
/// Enregistre la source Radio Paradise
|
|
///
|
|
/// Cette méthode crée automatiquement un `RadioParadiseSource` avec cache activé.
|
|
/// Radio Paradise ne nécessite pas d'authentification.
|
|
///
|
|
/// # Erreurs
|
|
///
|
|
/// Retourne une erreur si :
|
|
/// - La connexion au client Radio Paradise échoue
|
|
/// - La feature "paradise" n'est pas activée
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```ignore
|
|
/// server.register_paradise().await?;
|
|
/// ```
|
|
#[cfg(feature = "paradise")]
|
|
async fn register_paradise(&mut self) -> Result<()>;
|
|
|
|
/// Enregistre la source Radio France
|
|
///
|
|
/// Cette méthode crée automatiquement un `RadioFranceSource` avec cache activé.
|
|
/// Radio France ne nécessite pas d'authentification.
|
|
///
|
|
/// # Erreurs
|
|
///
|
|
/// Retourne une erreur si :
|
|
/// - La connexion au client Radio France échoue
|
|
/// - La feature "radiofrance" n'est pas activée
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```ignore
|
|
/// server.register_radiofrance().await?;
|
|
/// ```
|
|
#[cfg(feature = "radiofrance")]
|
|
async fn register_radiofrance(&mut self) -> Result<()>;
|
|
}
|
|
|
|
#[async_trait::async_trait]
|
|
impl SourcesExt for Server {
|
|
#[cfg(feature = "qobuz")]
|
|
async fn register_qobuz(&mut self) -> Result<()> {
|
|
use pmoqobuz::{QobuzClient, QobuzSource};
|
|
|
|
tracing::info!("Initializing Qobuz source...");
|
|
|
|
// Obtenir l'URL de base du serveur
|
|
let base_url = self.base_url();
|
|
|
|
// Créer le client depuis la config
|
|
let client = QobuzClient::from_config()
|
|
.await
|
|
.map_err(|e| SourceInitError::QobuzError(format!("Failed to create client: {}", e)))?;
|
|
|
|
// Créer la source depuis le registry
|
|
let source = QobuzSource::from_registry(client, base_url)
|
|
.map_err(|e| SourceInitError::QobuzError(format!("Failed to create source: {}", e)))?;
|
|
|
|
// Enregistrer la source
|
|
self.register_music_source(Arc::new(source)).await;
|
|
|
|
tracing::info!("✅ Qobuz source registered successfully");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "qobuz")]
|
|
async fn register_qobuz_with_credentials(
|
|
&mut self,
|
|
username: &str,
|
|
password: &str,
|
|
) -> Result<()> {
|
|
use pmoqobuz::{QobuzClient, QobuzSource};
|
|
|
|
tracing::info!("Initializing Qobuz source with explicit credentials...");
|
|
|
|
// Obtenir l'URL de base du serveur
|
|
let base_url = self.base_url();
|
|
|
|
// Créer le client avec credentials
|
|
let client = QobuzClient::new(username, password)
|
|
.await
|
|
.map_err(|e| SourceInitError::QobuzError(format!("Failed to authenticate: {}", e)))?;
|
|
|
|
// Créer la source depuis le registry
|
|
let source = QobuzSource::from_registry(client, base_url)
|
|
.map_err(|e| SourceInitError::QobuzError(format!("Failed to create source: {}", e)))?;
|
|
|
|
// Enregistrer la source
|
|
self.register_music_source(Arc::new(source)).await;
|
|
|
|
tracing::info!("✅ Qobuz source registered successfully");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "paradise")]
|
|
async fn register_paradise(&mut self) -> Result<()> {
|
|
use crate::contentdirectory::state;
|
|
use pmoparadise::{RadioParadiseExt, RadioParadiseSource};
|
|
|
|
tracing::info!("Initializing Radio Paradise source...");
|
|
|
|
// Obtenir l'URL de base du serveur
|
|
let base_url = self.base_url();
|
|
|
|
// Créer la source Radio Paradise (utilise le singleton PlaylistManager)
|
|
let notifier = Arc::new(|containers: &[String]| {
|
|
let refs: Vec<&str> = containers.iter().map(|s| s.as_str()).collect();
|
|
state::notify_containers_updated(&refs);
|
|
});
|
|
let source = Arc::new(
|
|
RadioParadiseSource::new(base_url.to_string()).with_container_notifier(notifier),
|
|
);
|
|
|
|
// Brancher les callbacks de playlists (live/history) pour signaler les updates
|
|
source.attach_playlist_callbacks();
|
|
|
|
// Enregistrer la source
|
|
self.register_music_source(source.clone()).await;
|
|
|
|
tracing::info!("✅ Radio Paradise source registered successfully");
|
|
|
|
// Initialiser l'API REST Radio Paradise
|
|
#[cfg(feature = "paradise-api")]
|
|
{
|
|
tracing::info!("📻 Initializing Radio Paradise API...");
|
|
if let Err(e) = self.init_radioparadise().await {
|
|
tracing::warn!("⚠️ Failed to initialize Radio Paradise API: {}", e);
|
|
} else {
|
|
tracing::info!("✅ Radio Paradise API initialized");
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(feature = "radiofrance")]
|
|
async fn register_radiofrance(&mut self) -> Result<()> {
|
|
use pmoradiofrance::{RadioFranceExt, RadioFranceSource, RadioFranceStatefulClient};
|
|
|
|
tracing::info!("Initializing Radio France source...");
|
|
|
|
// Obtenir l'URL de base du serveur
|
|
let base_url = self.base_url();
|
|
|
|
// Créer le client stateful depuis la config
|
|
let client = RadioFranceStatefulClient::from_config()
|
|
.await
|
|
.map_err(|e| {
|
|
SourceInitError::RadioFranceError(format!("Failed to create client: {}", e))
|
|
})?;
|
|
|
|
// Créer la source depuis le registry (avec cache)
|
|
let source = RadioFranceSource::from_registry(client, base_url).map_err(|e| {
|
|
SourceInitError::RadioFranceError(format!("Failed to create source: {}", e))
|
|
})?;
|
|
|
|
// Enregistrer la source
|
|
self.register_music_source(Arc::new(source)).await;
|
|
|
|
// Initialiser les routes API Radio France
|
|
self.init_radiofrance().await.map_err(|e| {
|
|
SourceInitError::RadioFranceError(format!("Failed to init API routes: {}", e))
|
|
})?;
|
|
|
|
tracing::info!("✅ Radio France source registered successfully");
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_source_init_error() {
|
|
#[cfg(feature = "qobuz")]
|
|
{
|
|
let err = SourceInitError::QobuzError("test error".to_string());
|
|
assert!(err.to_string().contains("Qobuz"));
|
|
}
|
|
|
|
let err = SourceInitError::ConfigError("test".to_string());
|
|
assert!(err.to_string().contains("Configuration"));
|
|
}
|
|
}
|