//! Live validation against the real SoundCloud API. `#[ignore]`d so it never //! runs in CI or hits the network by default; run it deliberately with //! //! ```sh //! cargo test -p soundclouddy --test live -- --ignored --nocapture //! # optional: SOUNDCLOUD_CLIENT_ID= to skip the scrape, //! # SOUNDCLOUD_OAUTH= to also exercise the personal calls. //! ``` //! //! It exercises the real endpoints end-to-end (scrape client_id → search → //! resolve stream URL) so the `ScApi` DTOs and the `client_id` scrape are //! confirmed against the live shapes — the drift risk called out in //! architecture/soundcloud-provider.md. use std::time::Duration; use soundclouddy::api::{Sc, ScApi}; fn api() -> ScApi { ScApi::new( std::env::var("SOUNDCLOUD_CLIENT_ID").ok(), None, std::env::var("SOUNDCLOUD_OAUTH").ok(), Duration::from_secs(30), ) .expect("client builds") } #[tokio::test] #[ignore = "hits the real SoundCloud API (scrapes a client_id)"] async fn live_scrape_search_and_stream() { let api = api(); // Scrapes a client_id if none was provided; a failure here means the // scrape parsers need updating against the current soundcloud.com. api.ensure_ready().await.expect("obtain a client_id"); println!( "client_id acquired: {}", api.cached_client_id().await.is_some() ); let tracks = api .search_tracks("boards of canada", 5) .await .expect("search decodes"); assert!(!tracks.is_empty(), "search returns tracks"); let first = &tracks[0]; println!( "first track: {} — {} ({})", first.artist, first.title, first.id ); // Resolve a playable HLS media URL for it. let url = api .resolve_stream_url(&first.id) .await .expect("stream url resolves"); assert!( url.contains(".m3u8"), "stream URL is an HLS playlist: {url}" ); println!("stream url resolves to an m3u8 (len {})", url.len()); } #[tokio::test] #[ignore = "hits the real SoundCloud API; requires SOUNDCLOUD_OAUTH"] async fn live_personal_likes() { if std::env::var("SOUNDCLOUD_OAUTH").is_err() { eprintln!("SOUNDCLOUD_OAUTH unset — skipping personal test"); return; } let api = api(); api.ensure_ready().await.expect("client_id"); let likes = api.my_likes(5).await.expect("likes decode"); println!("liked tracks: {}", likes.len()); }