feat: Replace hardcoded container stubs with dynamic source resolution

Uses `get_source_from_registry` to browse target sources and extract real metadata (title, artist, cover, track count). Updates fallback logic to set `parent_id` to `source_id` instead of `"url"`, ensuring consistent frontend routing and accurate UI rendering.
This commit is contained in:
2026-06-14 14:31:51 +02:00
parent d49bb604ca
commit 87bce3edfa

View File

@@ -1,6 +1,7 @@
use crate::handler::{ResolvedContent, ResolvedTrack, UrlResolver, UrlResolverError}; use crate::handler::{ResolvedContent, ResolvedTrack, UrlResolver, UrlResolverError};
use async_trait::async_trait; use async_trait::async_trait;
use pmodidl::{Container, Item, Resource}; use pmodidl::{Container, Item, Resource};
use pmosource::api::get_source as get_source_from_registry;
use pmosource::{BrowseResult, MusicSource, MusicSourceError, SearchQuery, SourceCapabilities}; use pmosource::{BrowseResult, MusicSource, MusicSourceError, SearchQuery, SourceCapabilities};
use std::time::SystemTime; use std::time::SystemTime;
@@ -77,14 +78,57 @@ impl MusicSource for UrlSource {
match self.resolver.resolve(url).await { match self.resolver.resolve(url).await {
Ok(ResolvedContent::SourceContainer { Ok(ResolvedContent::SourceContainer {
source_id: _, source_id,
container_id, container_id,
}) => { }) => {
// Stub container : le content directory le route vers la source cible. // Browsons la source cible pour récupérer les métadonnées réelles
// (titre album, artiste, pochette, nombre de pistes).
// On retourne un Container enrichi avec :
// - parent_id = source_id → le frontend route le browse vers la bonne source
// - child_count réel → le frontend sait que le container a du contenu
// - titre/artiste/cover → affichage correct dans l'UI
// Le container reste jouable comme unité (attach_queue) et navigable.
if let Some(source) = get_source_from_registry(&source_id).await {
match source.browse(&container_id).await {
Ok(BrowseResult::Items(tracks)) if !tracks.is_empty() => {
let first = tracks.first();
let title = first
.and_then(|t| t.album.as_deref())
.map(|s| s.to_string())
.unwrap_or_else(|| display_title_for_url(url));
let artist = first.and_then(|t| t.artist.clone());
let album_art = first.and_then(|t| t.album_art.clone());
let container = Container {
id: container_id,
parent_id: source_id,
restricted: Some("1".to_string()),
child_count: Some(tracks.len().to_string()),
searchable: Some("0".to_string()),
title,
class: "object.container".to_string(),
artist,
album_art,
containers: vec![],
items: vec![],
};
return Ok(BrowseResult::Containers(vec![container]));
}
Ok(result) => return Ok(result),
Err(e) => {
tracing::warn!(
source_id = %source_id,
container_id = %container_id,
error = %e,
"UrlSource: browse de la source cible échoué, fallback stub"
);
}
}
}
// Fallback : stub minimaliste si la source n'est pas disponible
let title = display_title_for_url(url); let title = display_title_for_url(url);
let container = Container { let container = Container {
id: container_id, id: container_id,
parent_id: "url".to_string(), parent_id: source_id,
restricted: Some("1".to_string()), restricted: Some("1".to_string()),
child_count: None, child_count: None,
searchable: Some("0".to_string()), searchable: Some("0".to_string()),