//! Exemple d'intégration avec un serveur HTTP //! //! Cet exemple montre comment exposer une playlist FIFO via des endpoints HTTP simples. //! Dans un vrai MediaServer UPnP, ces endpoints seraient appelés par le protocole ContentDirectory. //! //! Pour exécuter : //! ```bash //! cargo run -p pmoplaylist --example http_server_integration //! ``` use pmoplaylist::{FifoPlaylist, Track, DEFAULT_IMAGE}; use std::sync::Arc; #[tokio::main] async fn main() { println!("=== Intégration HTTP Server ===\n"); // Créer une playlist partagée let playlist = Arc::new(FifoPlaylist::new( "my-radio".to_string(), "My Internet Radio".to_string(), 20, DEFAULT_IMAGE, )); println!("📻 Playlist créée: {}", playlist.title().await); println!("🆔 ID: {}\n", playlist.id().await); // Ajouter quelques tracks initiaux println!("📝 Ajout de tracks initiaux..."); let initial_tracks = vec![ ("The Beatles", "Come Together", "Abbey Road", 259), ("Nirvana", "Smells Like Teen Spirit", "Nevermind", 301), ("Queen", "Bohemian Rhapsody", "A Night at the Opera", 354), ]; for (idx, (artist, title, album, duration)) in initial_tracks.iter().enumerate() { playlist .append_track( Track::new( format!("track-{}", idx), *title, format!("http://media.server/music/{}.flac", idx), ) .with_artist(*artist) .with_album(*album) .with_duration(*duration) .with_image(format!("http://media.server/covers/{}.jpg", idx)), ) .await; println!(" ✓ {} - {}", artist, title); } println!(); // Simuler différents endpoints HTTP // 1. GET /playlist/container - Retourne le container DIDL-Lite println!("🌐 Endpoint: GET /playlist/container"); simulate_get_container(playlist.clone()).await; println!(); // 2. GET /playlist/items?offset=0&count=10 - Retourne les items println!("🌐 Endpoint: GET /playlist/items?offset=0&count=10"); simulate_get_items(playlist.clone(), 0, 10).await; println!(); // 3. GET /playlist/metadata - Retourne les métadonnées println!("🌐 Endpoint: GET /playlist/metadata"); simulate_get_metadata(playlist.clone()).await; println!(); // 4. POST /playlist/track - Ajoute un nouveau track println!("🌐 Endpoint: POST /playlist/track"); let new_track = Track::new( "track-new-1", "Stairway to Heaven", "http://media.server/music/stairway.flac", ) .with_artist("Led Zeppelin") .with_album("Led Zeppelin IV") .with_duration(482); simulate_add_track(playlist.clone(), new_track).await; println!(); // 5. DELETE /playlist/oldest - Supprime le plus ancien println!("🌐 Endpoint: DELETE /playlist/oldest"); simulate_delete_oldest(playlist.clone()).await; println!(); // 6. GET /playlist/default-image - Retourne l'image par défaut println!("🌐 Endpoint: GET /playlist/default-image"); simulate_get_default_image(playlist.clone()).await; println!(); // 7. Vérifier l'état final println!("📊 État final:"); let final_items = playlist.get_items(0, 10).await; println!(" Total tracks: {}", playlist.len().await); println!(" Update ID: {}", playlist.update_id().await); println!("\n Tracks actuels:"); for (idx, track) in final_items.iter().enumerate() { let artist = track.artist.as_deref().unwrap_or("Unknown"); println!(" {}. {} - {}", idx + 1, artist, track.title); } println!("\n=== Exemple terminé ==="); } /// Simule GET /playlist/container async fn simulate_get_container(playlist: Arc) { let container = playlist.as_container().await; println!(" Response (JSON representation):"); println!(" {{"); println!(" \"id\": \"{}\",", container.id); println!(" \"parentId\": \"{}\",", container.parent_id); println!(" \"title\": \"{}\",", container.title); println!(" \"class\": \"{}\",", container.class); println!( " \"childCount\": {}", container.child_count.unwrap_or_default() ); println!(" }}"); } /// Simule GET /playlist/items?offset=X&count=Y async fn simulate_get_items(playlist: Arc, offset: usize, count: usize) { let items = playlist .as_objects(offset, count, Some("http://media.server/api/default-image")) .await; println!(" Response: {} items", items.len()); println!(" ["); for (idx, item) in items.iter().enumerate() { println!(" {{"); println!(" \"id\": \"{}\",", item.id); println!(" \"title\": \"{}\",", item.title); println!( " \"artist\": \"{}\",", item.artist.as_deref().unwrap_or("") ); println!( " \"album\": \"{}\",", item.album.as_deref().unwrap_or("") ); println!(" \"class\": \"{}\",", item.class); if !item.resources.is_empty() { println!(" \"uri\": \"{}\",", item.resources[0].url); } print!(" }}"); if idx < items.len() - 1 { println!(","); } else { println!(); } } println!(" ]"); } /// Simule GET /playlist/metadata async fn simulate_get_metadata(playlist: Arc) { let update_id = playlist.update_id().await; let last_change = playlist.last_change().await; let count = playlist.len().await; let id = playlist.id().await; let title = playlist.title().await; println!(" Response:"); println!(" {{"); println!(" \"id\": \"{}\",", id); println!(" \"title\": \"{}\",", title); println!(" \"trackCount\": {},", count); println!(" \"updateId\": {},", update_id); println!(" \"lastChange\": \"{:?}\"", last_change); println!(" }}"); } /// Simule POST /playlist/track async fn simulate_add_track(playlist: Arc, track: Track) { let old_update_id = playlist.update_id().await; playlist.append_track(track.clone()).await; let new_update_id = playlist.update_id().await; println!( " Track added: {} - {}", track.artist.as_deref().unwrap_or("Unknown"), track.title ); println!(" Update ID: {} → {}", old_update_id, new_update_id); println!(" Response: 201 Created"); } /// Simule DELETE /playlist/oldest async fn simulate_delete_oldest(playlist: Arc) { if let Some(removed) = playlist.remove_oldest().await { println!(" Track removed: {} ({})", removed.title, removed.id); println!(" New update ID: {}", playlist.update_id().await); println!(" Response: 200 OK"); } else { println!(" No tracks to remove"); println!(" Response: 404 Not Found"); } } /// Simule GET /playlist/default-image async fn simulate_get_default_image(playlist: Arc) { let image_bytes = playlist.default_image().await; println!(" Response:"); println!(" Content-Type: image/webp"); println!(" Content-Length: {} bytes", image_bytes.len()); println!(" Status: 200 OK"); println!(" (Image WebP {} bytes ready to serve)", image_bytes.len()); }