From 7d55b5c3f0f350223751d19e0a6e874e6cb8e1ec Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sat, 24 Jan 2026 20:19:40 +0100 Subject: [PATCH] Corrige l'affichage des groupes de radios et supprime la station virtuelle 'ici' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correction des bugs d'affichage des groupes de radios : - La radio principale n'était plus présente dans les groupes multi-stations - Le groupe ICI était inaccessible en raison d'une station virtuelle mal gérée Implémentation d'un refactoring complet : - Suppression de la notion de 'station virtuelle' - Ajout de champs optionnels `group_name` et `group_slug` dans `StationGroup` - Simplification de la logique de tri et de génération des IDs - Les stations sont maintenant triées alphabétiquement dans chaque groupe - Le groupe ICI est désormais accessible et affiche toutes les radios locales triées --- Blackboard/Report/Oubli_Main_Radio.md | 51 ++++++++++++++++++ Blackboard/Todo/Oubli_Main_Radio.md | 15 ++++++ pmoradiofrance/src/playlist.rs | 77 ++++++++++++++++----------- 3 files changed, 112 insertions(+), 31 deletions(-) create mode 100644 Blackboard/Report/Oubli_Main_Radio.md create mode 100644 Blackboard/Todo/Oubli_Main_Radio.md diff --git a/Blackboard/Report/Oubli_Main_Radio.md b/Blackboard/Report/Oubli_Main_Radio.md new file mode 100644 index 00000000..4e6d773f --- /dev/null +++ b/Blackboard/Report/Oubli_Main_Radio.md @@ -0,0 +1,51 @@ +# Rapport : Correction de l'affichage des groupes de radios + +## Résumé + +Correction des deux bugs identifiés dans l'organisation des groupes de stations Radio France : +1. La radio principale était absente des groupes multi-stations (écrasée par les webradios) +2. Le groupe ICI (radios locales) était inaccessible à cause d'une station virtuelle "ici" mal gérée + +## Solution implémentée + +Refactoring complet pour supprimer la notion de "station virtuelle" et utiliser des champs optionnels `group_name` et `group_slug` dans `StationGroup`. + +### Modifications + +**Fichier modifié :** +- `pmoradiofrance/src/playlist.rs` + +### Changements structurels + +1. **Ajout de champs optionnels à `StationGroup`** : + - `group_name: Option` : nom personnalisé du groupe (pour ICI : "Radios ICI") + - `group_slug: Option` : slug personnalisé du groupe (pour ICI : "ici") + +2. **Suppression de la station virtuelle "ici"** : + - Plus de création d'une `Station { slug: "ici", name: "Radios ICI" }` + - Le groupe ICI contient maintenant uniquement les vraies stations `francebleu_*` + +3. **Méthodes helper dans `StationGroup`** : + - `name()` : retourne `group_name` ou le nom de `stations[0]` + - `slug()` : retourne `group_slug` ou le slug de `stations[0]` + +4. **Simplification de la logique** : + - `to_stub()` et `to_didl()` de `StationGroup` utilisent `self.name()` et `self.slug()` + - Plus de traitement spécial pour détecter ou sauter la station virtuelle "ici" + - `compute_parent_id()` de `Station` utilise le slug fixe "ici" pour les stations `francebleu_*` + +5. **Tri alphabétique des stations** : + - Dans chaque groupe : station principale en position 0, puis webradios triées par nom + - Groupe ICI : toutes les stations triées par nom (pas de station principale) + - Les stations se retrouvent toujours à la même position dans la liste + +### Résultat + +- **Groupes avec radio principale** (FIP, France Inter, etc.) : la radio principale apparaît à l'index 0, suivie des webradios triées alphabétiquement +- **Groupe ICI** : accessible et affiche toutes les radios locales triées alphabétiquement +- Code plus simple et sans logique spéciale dispersée +- Interface prévisible : les stations sont toujours au même endroit + +## Statut + +Modifications terminées. Compilation à vérifier par l'utilisateur. diff --git a/Blackboard/Todo/Oubli_Main_Radio.md b/Blackboard/Todo/Oubli_Main_Radio.md new file mode 100644 index 00000000..03174cf3 --- /dev/null +++ b/Blackboard/Todo/Oubli_Main_Radio.md @@ -0,0 +1,15 @@ +**Tu réaliseras ce travail en appliquant scrupuleusement les règles définies dans [@Rules.md](file:///Users/coissac/Sync/maison/Petite_maisons/src/pmomusic/Blackboard/Rules.md)** + +Ce travail se réalisera dans la crate [@pmoradiofrance](file:///Users/coissac/Sync/maison/Petite_maisons/src/pmomusic/pmoradiofrance). + + +- L'ensemble des éditions devraient se réaliser dans le fichier [@playlist.rs](file:///Users/coissac/Sync/maison/Petite_maisons/src/pmomusic/pmoradiofrance/src/playlist.rs). +- Il est fort probable que tu n'aies besoin de lire aucun autre fichier. + +Le problème, les groupes de radio sont composés d'une radio principale, parfois, et de web radio parfois. + +Quand on a une radio principale unique, comme France Culture, tout se passe bien. + +Quand on a un groupe de radio avec une radio principale et des web radios, la radio principale devrait se trouver à l'index 0 du container et les radios secondaires aux index suivants. Mais la radio principale est absente. ÷Sans doute qu'elle a été écrasée par des webradio. + +Et quant au seul cas de groupe de radio qui n'ont pas de radio principale, ICI, Les radios locales de Radio France, Rien ne marche du tout, on n'arrive même pas à accéder au container. C'est peut-être un reliquat du temps où tu traitais ICI à part. diff --git a/pmoradiofrance/src/playlist.rs b/pmoradiofrance/src/playlist.rs index 5c78fda6..ee26c7e8 100644 --- a/pmoradiofrance/src/playlist.rs +++ b/pmoradiofrance/src/playlist.rs @@ -60,31 +60,33 @@ impl StationGroups { let mut groups: Vec = groups_map .into_iter() .map(|(group_key, mut stations)| { - // Trier : station principale (sans _) en premier - stations.sort_by_key(|s| { - if s.slug == group_key { - 0 // Station principale en premier - } else { - 1 + // Trier : station principale en premier, puis webradios par ordre alphabétique + stations.sort_by(|a, b| { + let a_is_main = a.slug == group_key; + let b_is_main = b.slug == group_key; + + match (a_is_main, b_is_main) { + (true, false) => std::cmp::Ordering::Less, // Main avant webradios + (false, true) => std::cmp::Ordering::Greater, // Webradios après main + _ => a.name.cmp(&b.name), // Sinon tri alphabétique } }); - StationGroup { stations } + StationGroup { + stations, + group_name: None, + group_slug: None, + } }) .collect(); // Ajouter le groupe ICI si on a des radios locales if !ici_stations.is_empty() { ici_stations.sort_by(|a, b| a.name.cmp(&b.name)); - // Créer une station virtuelle "ici" comme station principale - let ici_main = Station { - slug: "ici".to_string(), - name: "Radios ICI".to_string(), - }; - let mut ici_group_stations = vec![ici_main]; - ici_group_stations.extend(ici_stations); groups.push(StationGroup { - stations: ici_group_stations, + stations: ici_stations, + group_name: Some("Radios ICI".to_string()), + group_slug: Some("ici".to_string()), }); } @@ -131,13 +133,27 @@ impl StationGroups { /// Groupe de stations - Niveau 1 /// -/// Index 0 = station principale du groupe (ex: FIP pour le groupe FIP) +/// Index 0 = première station du groupe (donne le nom/slug par défaut) #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct StationGroup { pub stations: Vec, + /// Nom personnalisé du groupe (optionnel, sinon utilise le nom de stations[0]) + pub group_name: Option, + /// Slug personnalisé du groupe (optionnel, sinon utilise le slug de stations[0]) + pub group_slug: Option, } impl StationGroup { + /// Retourne le nom du groupe (personnalisé ou nom de la première station) + fn name(&self) -> &str { + self.group_name.as_deref().unwrap_or(&self.stations[0].name) + } + + /// Retourne le slug du groupe (personnalisé ou slug de la première station) + fn slug(&self) -> &str { + self.group_slug.as_deref().unwrap_or(&self.stations[0].slug) + } + /// Niveau 1: to_stub() retourne comment ce groupe apparaît dans la liste de StationGroups /// /// - Si 1 station: retourne une playlist avec métadonnées (pour avoir titre/artiste à jour) @@ -154,19 +170,18 @@ impl StationGroup { .await } else { // Groupe multi-stations : juste le nom, pas de métadonnées - let main_station = &self.stations[0]; let album_art = Some(format!( "{}/api/radiofrance/default-logo", server_base_url.trim_end_matches('/') )); Ok(Container { - id: format!("radiofrance:group:{}", main_station.slug), + id: format!("radiofrance:group:{}", self.slug()), parent_id: "radiofrance".to_string(), restricted: Some("1".to_string()), - child_count: Some(self.stations.len().saturating_sub(1).to_string()), + child_count: Some(self.stations.len().to_string()), searchable: Some("0".to_string()), - title: main_station.name.clone(), + title: self.name().to_string(), class: "object.container".to_string(), artist: None, album_art, @@ -179,7 +194,7 @@ impl StationGroup { /// Niveau 1: to_didl() retourne le container du groupe avec TOUT son contenu /// /// - Si 1 station: retourne la playlist complète avec l'item stream - /// - Si plusieurs: retourne le container avec toutes les playlists des webradios en stub + /// - Si plusieurs: retourne le container avec toutes les playlists en stub pub async fn to_didl( &self, metadata_cache: &MetadataCache, @@ -191,11 +206,10 @@ impl StationGroup { .to_didl(metadata_cache, server_base_url) .await } else { - // Groupe multi-stations : retourner un container avec les playlists en stub - let main_station = &self.stations[0]; + // Groupe multi-stations : retourner un container avec toutes les playlists en stub let mut containers = Vec::new(); - for station in &self.stations[1..] { + for station in &self.stations { // Appeler to_stub() sur chaque station let playlist_stub = station.to_stub(metadata_cache, server_base_url).await?; containers.push(playlist_stub); @@ -207,12 +221,12 @@ impl StationGroup { )); Ok(Container { - id: format!("radiofrance:group:{}", main_station.slug), + id: format!("radiofrance:group:{}", self.slug()), parent_id: "radiofrance".to_string(), restricted: Some("1".to_string()), child_count: Some(containers.len().to_string()), searchable: Some("0".to_string()), - title: main_station.name.clone(), + title: self.name().to_string(), class: "object.container".to_string(), artist: None, album_art, @@ -236,13 +250,13 @@ impl Station { metadata_cache: &MetadataCache, _server_base_url: &str, ) -> Result { + let playlist_id = format!("radiofrance:{}", self.slug); + let parent_id = self.compute_parent_id(); + // Récupérer les métadonnées du cache let cached_metadata = metadata_cache.get(&self.slug).await?; // Construire juste le container de playlist (sans l'item stream) - let playlist_id = format!("radiofrance:{}", self.slug); - let parent_id = self.compute_parent_id(); - Ok(Container { id: playlist_id, parent_id, @@ -278,8 +292,9 @@ impl Station { /// Calcule le parent_id selon la position de la station fn compute_parent_id(&self) -> String { - if self.slug == "ici" { - "radiofrance".to_string() + if self.slug.starts_with("francebleu_") { + // Radio locale ICI (ex-France Bleu) : parent = groupe ICI + "radiofrance:group:ici".to_string() } else if let Some(pos) = self.slug.find('_') { // Webradio : parent = groupe format!("radiofrance:group:{}", &self.slug[..pos])