Files
pmomusic/pmoradiofrance/src/source.rs

384 lines
13 KiB
Rust
Raw Normal View History

//! MusicSource implementation for Radio France
//!
//! This module implements the `MusicSource` trait from `pmosource` for Radio France,
//! providing UPnP/DLNA integration with dynamic container generation.
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
use crate::client::RadioFranceClient;
use crate::error::Result;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
use crate::metadata_cache::MetadataCache;
use crate::playlist::StationGroups;
use pmoconfig::Config;
use pmodidl::{Container, Item};
use pmosource::{async_trait, BrowseResult, MusicSource, MusicSourceError, SourceCapabilities};
use std::sync::Arc;
use std::time::SystemTime;
use tokio::sync::RwLock;
#[cfg(feature = "server")]
use pmoupnp;
/// Default image for Radio France source (embedded in binary)
pub const RADIOFRANCE_DEFAULT_IMAGE: &[u8] = include_bytes!("../assets/radiofrance-logo.webp");
/// Radio France music source
///
/// Provides access to ~70 Radio France stations via UPnP/DLNA with:
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// - Cache de métadonnées avec TTL et système d'événements
/// - Construction dynamique de containers DIDL
/// - Notifications GENA pour les playlists
pub struct RadioFranceSource {
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// Cache de métadonnées centralisé
metadata_cache: Arc<MetadataCache>,
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// Server base URL
server_base_url: String,
/// Update counter for change tracking
update_id: Arc<RwLock<u32>>,
/// Last change timestamp
last_change: Arc<RwLock<Option<SystemTime>>>,
/// Callback for notifying container updates (UPnP GENA)
container_notifier: Option<Arc<dyn Fn(&[String]) + Send + Sync + 'static>>,
}
impl RadioFranceSource {
/// Create a new Radio France source
///
/// # Arguments
///
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// * `config` - Configuration for cache and discovery
///
/// # Example
///
/// ```no_run
/// use pmoradiofrance::RadioFranceSource;
/// use pmoconfig::get_config;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let config = get_config();
/// let source = RadioFranceSource::new(config).await?;
/// Ok(())
/// }
/// ```
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
#[cfg(feature = "cache")]
pub async fn new(config: Arc<Config>) -> Result<Self> {
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let client = RadioFranceClient::new().await?;
let cover_cache = pmoupnp::cache_registry::get_cover_cache()
.ok_or_else(|| crate::error::Error::Other("Cover cache not initialized".to_string()))?;
let server_base_url = config.get_base_url();
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let metadata_cache = Arc::new(MetadataCache::new(
client,
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
cover_cache,
server_base_url.clone(),
config,
));
let update_id = Arc::new(RwLock::new(0));
let last_change = Arc::new(RwLock::new(None));
let source = Self {
metadata_cache,
server_base_url,
update_id,
last_change,
container_notifier: None,
};
Ok(source)
}
/// Set the container notifier for UPnP GENA events
pub fn with_container_notifier(
mut self,
notifier: Arc<dyn Fn(&[String]) + Send + Sync + 'static>,
) -> Self {
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
// S'abonner aux événements du cache de métadonnées
let container_notifier = Arc::new(notifier.clone());
let update_id = self.update_id.clone();
let last_change = self.last_change.clone();
self.metadata_cache.subscribe(Arc::new(move |slug: &str| {
let slug = slug.to_string();
let update_id = update_id.clone();
let last_change = last_change.clone();
let container_notifier = container_notifier.clone();
tokio::spawn(async move {
*update_id.write().await += 1;
*last_change.write().await = Some(SystemTime::now());
// Notifier le container de playlist (pas l'item)
container_notifier(&[format!("radiofrance:{}", slug)]);
});
}));
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
self.container_notifier = Some(notifier);
self
}
/// Create a new Radio France source from the cache registry
///
/// This is the recommended way to create a source when using the UPnP server.
///
/// # Arguments
///
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// * `config` - Configuration
/// * `base_url` - Base URL for streaming server
#[cfg(feature = "server")]
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
pub async fn from_registry(config: Arc<Config>, base_url: impl Into<String>) -> Result<Self> {
let client = RadioFranceClient::new().await?;
let cover_cache = pmoupnp::cache_registry::get_cover_cache()
.ok_or_else(|| crate::error::Error::Other("Cover cache not initialized".to_string()))?;
let server_base_url = base_url.into();
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let metadata_cache = Arc::new(MetadataCache::new(
client,
cover_cache,
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
server_base_url.clone(),
config,
));
let update_id = Arc::new(RwLock::new(0));
let last_change = Arc::new(RwLock::new(None));
Ok(Self {
metadata_cache,
server_base_url,
update_id,
last_change,
container_notifier: None,
})
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
impl RadioFranceSource {
/// Get the list of all Radio France stations
pub async fn get_stations(&self) -> Result<Vec<crate::models::Station>> {
self.metadata_cache.get_stations().await
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// Get live metadata for a station
pub async fn get_live_metadata(&self, slug: &str) -> Result<crate::models::LiveResponse> {
self.metadata_cache.get_live_metadata(slug).await
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
/// Get the HiFi stream URL for a station
pub async fn get_stream_url(&self, slug: &str) -> Result<String> {
self.metadata_cache.get_stream_url(slug).await
}
}
impl std::fmt::Debug for RadioFranceSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RadioFranceSource")
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.field("server_base_url", &self.server_base_url)
.finish()
}
}
#[async_trait]
impl MusicSource for RadioFranceSource {
fn name(&self) -> &str {
"Radio France"
}
fn id(&self) -> &str {
"radiofrance"
}
fn default_image(&self) -> &[u8] {
RADIOFRANCE_DEFAULT_IMAGE
}
fn capabilities(&self) -> SourceCapabilities {
SourceCapabilities {
supports_fifo: false,
supports_search: false,
supports_favorites: false,
supports_playlists: false,
supports_user_content: false,
supports_high_res_audio: false,
max_sample_rate: Some(48000), // AAC 48kHz
supports_multiple_formats: false,
supports_advanced_search: false,
supports_pagination: false,
}
}
async fn root_container(&self) -> pmosource::Result<Container> {
Ok(Container {
id: "radiofrance".to_string(),
parent_id: "0".to_string(),
restricted: Some("1".to_string()),
child_count: None,
searchable: Some("0".to_string()),
title: "Radio France".to_string(),
class: "object.container".to_string(),
artist: None,
album_art: None,
containers: vec![],
items: vec![],
})
}
async fn browse(&self, object_id: &str) -> pmosource::Result<BrowseResult> {
match object_id {
"radiofrance" => {
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
// Niveau 0: retourne le Container avec les groupes
let stations = self
.metadata_cache
.get_stations()
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
let groups = StationGroups::from_stations(stations);
let container = groups
.to_didl(&self.metadata_cache, &self.server_base_url)
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
Ok(BrowseResult::Containers(container.containers))
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
id if id.starts_with("radiofrance:group:") || id == "radiofrance:ici" => {
// Niveau 1: browse d'un groupe
let slug = id
.strip_prefix("radiofrance:group:")
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.or_else(|| {
if id == "radiofrance:ici" {
Some("ici")
} else {
None
}
})
.ok_or_else(|| MusicSourceError::ObjectNotFound(id.to_string()))?;
let stations = self
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.metadata_cache
.get_stations()
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let groups = StationGroups::from_stations(stations);
let group = groups
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.groups
.iter()
.find(|g| g.slug() == slug)
.ok_or_else(|| MusicSourceError::ObjectNotFound(id.to_string()))?;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let container = group
.to_didl(&self.metadata_cache, &self.server_base_url)
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
// Si c'est une playlist (1 station), retourner le container lui-même
// Sinon retourner ses sous-containers
if container.class == "object.container.playlistContainer" {
Ok(BrowseResult::Containers(vec![container]))
} else {
Ok(BrowseResult::Containers(container.containers))
}
}
id if id.starts_with("radiofrance:") && !id.contains(":stream") => {
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
// Niveau 2: browse d'une station (playlist)
let slug = id
.strip_prefix("radiofrance:")
.ok_or_else(|| MusicSourceError::ObjectNotFound(id.to_string()))?;
let stations = self
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.metadata_cache
.get_stations()
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
let station = stations
.iter()
.find(|s| s.slug == slug)
.ok_or_else(|| MusicSourceError::ObjectNotFound(id.to_string()))?;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let container = station
.to_didl(&self.metadata_cache, &self.server_base_url)
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
// Retourner les items de la playlist
Ok(BrowseResult::Items(container.items))
}
_ => Err(MusicSourceError::ObjectNotFound(object_id.to_string())),
}
}
async fn get_item(&self, object_id: &str) -> pmosource::Result<Item> {
// Format: radiofrance:{slug}:stream
let slug = object_id
.strip_prefix("radiofrance:")
.and_then(|s| s.strip_suffix(":stream"))
.ok_or_else(|| MusicSourceError::ObjectNotFound(object_id.to_string()))?;
let stations = self
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.metadata_cache
.get_stations()
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
let station = stations
.iter()
.find(|s| s.slug == slug)
.ok_or_else(|| MusicSourceError::ObjectNotFound(object_id.to_string()))?;
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let container = station
.to_didl(&self.metadata_cache, &self.server_base_url)
.await
.map_err(|e| MusicSourceError::BrowseError(e.to_string()))?;
container
.items
.into_iter()
.next()
.ok_or_else(|| MusicSourceError::ObjectNotFound(object_id.to_string()))
}
async fn resolve_uri(&self, object_id: &str) -> pmosource::Result<String> {
// Extract station slug from object_id (format: radiofrance:{slug}:stream)
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
let _slug = object_id
.strip_prefix("radiofrance:")
.and_then(|s| s.strip_suffix(":stream"))
.ok_or_else(|| MusicSourceError::ObjectNotFound(object_id.to_string()))?;
// Get the item to extract the stream URL
let item = self.get_item(object_id).await?;
item.resources
.first()
.map(|r| r.url.clone())
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
.ok_or_else(|| MusicSourceError::ObjectNotFound(object_id.to_string()))
}
fn supports_fifo(&self) -> bool {
false
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
async fn append_track(&self, _item: Item) -> pmosource::Result<()> {
Err(MusicSourceError::FifoNotSupported)
}
async fn remove_oldest(&self) -> pmosource::Result<Option<Item>> {
Err(MusicSourceError::FifoNotSupported)
}
async fn update_id(&self) -> u32 {
*self.update_id.read().await
}
async fn last_change(&self) -> Option<SystemTime> {
*self.last_change.read().await
}
Refactorisation complète de pmoradiofrance : cache centralisé avec système d'événements Refactorisation complète de la crate `pmoradiofrance` pour simplifier l'architecture autour d'un cache de métadonnées centralisé avec système d'événements. ## Objectifs 1. Simplifier les structures de stations (supprimer StationType) 2. Créer un cache de métadonnées in-memory avec TTL basé sur `end_time` 3. Maintenir le cache de stations persistant (pmoconfig, TTL 1 semaine) 4. Implémenter un système d'événements pour la synchronisation GENA 5. Unifier les méthodes `to_didl()` pour retourner des Containers DIDL 6. Gérer automatiquement le cache des covers via pmocovers ## Changements architecturaux majeurs ### 1. Nouveau fichier: metadata_cache.rs **Créé**: `pmoradiofrance/src/metadata_cache.rs` Contient deux structures principales: - **CachedMetadata**: Stocke uniquement les données nécessaires au DIDL (titre, artiste, album, cover, stream URL, etc.) - **MetadataCache**: Gère le cache in-memory avec TTL + cache persistant des stations + système d'événements **Fonctionnalités**: - TTL basé sur `end_time` de l'API Radio France - Gestion automatique du cache de covers via pmocovers - Système subscribe/notify pour les événements - Graceful degradation si API Radio France down - Méthode `to_didl()` retournant une playlist à un item avec métadonnées identiques ### 2. Suppression: stateful_client.rs **Supprimé**: `pmoradiofrance/src/stateful_client.rs` Raison: Complètement redondant avec `MetadataCache`. Toute la logique a été déplacée dans le nouveau module. ### 3. Simplification: models.rs **Modifications**: - Supprimé `StationType` enum - Simplifié `Station` struct (juste `slug` + `name`) - Supprimé méthodes `is_main()`, `is_webradio()`, `is_local_radio()`, `base_station()` - Conservé structures d'API (`LiveResponse`, `ShowMetadata`, etc.) ### 4. Simplification: playlist.rs **Modifications**: - Supprimé `StationPlaylist` complètement - Simplifié `StationGroup` et `StationGroups` - **Important**: `to_didl()` retourne `Container` (pas `Vec<Container>`) - Logique unifiée: ICI fonctionne comme FIP (plus de traitement spécial) - Préservé les règles de mapping RF → UPnP existantes ### 5. Refactoring: source.rs **Modifications**: - Utilise uniquement `MetadataCache` (plus de `stateful_client`) - Simplifié `browse()` en 3 cas simples - Abonnement aux événements du cache pour GENA - Retourne des `Container` (cohérence avec to_didl) ### 6. Adaptation: config_ext.rs **Modifications**: - Format simplifié: `Vec<Station>` au lieu de `CachedStationList` - TTL reste à 7 jours (1 semaine) ### 7. Mise à jour: lib.rs **Modifications**: - Ajouté `pub mod metadata_cache;` - Supprimé export de `stateful_client` - Ajouté exports: `MetadataCache`, `CachedMetadata` ## Hiérarchie de browse **Niveau 0**: `radiofrance` - Retourne UN Container contenant les containers de groupes - Exemple: Container "FIP", Container "France Culture", Container "ICI" **Niveau 1**: `radiofrance:group:fip` ou `radiofrance:ici` - Si 1 station: retourne directement la playlist (Container playlistContainer) - Si plusieurs stations: retourne un container contenant les playlists **Niveau 2**: `radiofrance:fip` - Retourne Container playlistContainer avec 1 item - Métadonnées identiques entre playlist et item ## Règles de mapping préservées Les règles existantes de transformation RF → UPnP ont été préservées: - Radio musicale avec song → métadonnées du morceau - Radio parlée → agrégation émission/producteur - Éviter duplications du nom de station - Calcul de duration depuis end_time ## Système d'événements **Flux**: 1. `MetadataCache` rafraîchit les métadonnées d'un slug 2. Notifie tous les abonnés via `notify(slug)` 3. `RadioFranceSource` reçoit l'événement 4. Émet un événement GENA UPnP pour la playlist `radiofrance:{slug}` 5. Le Control Point reçoit la notification et peut se mettre à jour ## Fichiers modifiés ### Créés - `pmoradiofrance/src/metadata_cache.rs` ### Supprimés - `pmoradiofrance/src/stateful_client.rs` ### Modifiés - `pmoradiofrance/src/models.rs` - `pmoradiofrance/src/playlist.rs` - `pmoradiofrance/src/source.rs` - `pmoradiofrance/src/config_ext.rs` - `pmoradiofrance/src/lib.rs` ### Inchangés - `pmoradiofrance/src/client.rs` - `pmoradiofrance/src/error.rs` ## Points de vigilance 1. **Migration**: Le cache pmoconfig existant sera invalidé (nouveau format) 2. **Covers**: Nécessite que pmocovers soit initialisé via cache_registry 3. **Thread safety**: Utilisation d'Arc<RwLock> pour la sécurité thread 4. **Graceful degradation**: Retourne cache expiré si API Radio France down ## Prochaines étapes 1. Tester le cache de métadonnées (TTL, refresh, graceful degradation) 2. Tester le système d'événements 3. Tester le browse sur les 3 niveaux 4. Vérifier les événements GENA 5. Vérifier que les covers sont correctement cachées
2026-01-24 14:15:26 +01:00
async fn get_items(&self, _offset: usize, _count: usize) -> pmosource::Result<Vec<Item>> {
Ok(vec![])
}
}