Corrige l'affichage des groupes de radios et supprime la station virtuelle 'ici'
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
This commit is contained in:
51
Blackboard/Report/Oubli_Main_Radio.md
Normal file
51
Blackboard/Report/Oubli_Main_Radio.md
Normal file
@@ -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<String>` : nom personnalisé du groupe (pour ICI : "Radios ICI")
|
||||
- `group_slug: Option<String>` : 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.
|
||||
15
Blackboard/Todo/Oubli_Main_Radio.md
Normal file
15
Blackboard/Todo/Oubli_Main_Radio.md
Normal file
@@ -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.
|
||||
@@ -60,31 +60,33 @@ impl StationGroups {
|
||||
let mut groups: Vec<StationGroup> = 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<Station>,
|
||||
/// Nom personnalisé du groupe (optionnel, sinon utilise le nom de stations[0])
|
||||
pub group_name: Option<String>,
|
||||
/// Slug personnalisé du groupe (optionnel, sinon utilise le slug de stations[0])
|
||||
pub group_slug: Option<String>,
|
||||
}
|
||||
|
||||
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<Container> {
|
||||
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])
|
||||
|
||||
Reference in New Issue
Block a user