use std::collections::HashSet; use bandcamp::{ models::{SearchFilter, SearchItem, TrAlbumType, Track}, Bandcamp, ImageUrl, }; use reqwest::{header, Client}; const BAND_WINTERGATAN: u64 = 2464198920; const BAND_ONESHOTPOD: u64 = 3760769193; const ALBUM_WINTERGATAN: u64 = 2572654767; const ALBUM_SKYJACKS: u64 = 1493086082; #[tokio::test] async fn band1() { let bc = Bandcamp::new(); let band = bc.band(BAND_WINTERGATAN).await.unwrap(); insta::assert_ron_snapshot!(&band); check_image(&band.img_url().unwrap()).await; } #[tokio::test] async fn band2() { let bc = Bandcamp::new(); let band = bc.band(BAND_ONESHOTPOD).await.unwrap(); insta::assert_ron_snapshot!(&band); check_image(&band.img_url().unwrap()).await; } #[tokio::test] async fn band3() { let bc = Bandcamp::new(); let band = bc.band(3453236550).await.unwrap(); insta::assert_ron_snapshot!(&band); check_image(&band.img_url().unwrap()).await; } #[tokio::test] async fn album1() { let bc = Bandcamp::new(); let album = bc .album(BAND_WINTERGATAN, ALBUM_WINTERGATAN, TrAlbumType::Album) .await .unwrap(); insta::assert_ron_snapshot!(&album, { ".tracks[].streaming_url" => "[streaming_url]" }); check_stream_urls(&album.tracks); check_image(&album.img_url().unwrap()).await; } #[tokio::test] async fn album2() { let bc = Bandcamp::new(); let album = bc .album_uid(format!("{}a{}", BAND_ONESHOTPOD, ALBUM_SKYJACKS)) .await .unwrap(); insta::assert_ron_snapshot!(&album, { ".tracks[].streaming_url" => "[streaming_url]" }); check_stream_urls(&album.tracks); check_image(&album.img_url().unwrap()).await; } #[tokio::test] async fn album_track() { let bc = Bandcamp::new(); let album = bc .album_uid(format!("{}t{}", BAND_WINTERGATAN, 716010980)) .await .unwrap(); insta::assert_ron_snapshot!(&album, { ".tracks[].streaming_url" => "[streaming_url]" }); check_stream_urls(&album.tracks); check_image(&album.img_url().unwrap()).await; } #[tokio::test] async fn album_track2() { let bc = Bandcamp::new(); let album = bc.album_uid("3453236550t3835153004").await.unwrap(); insta::assert_ron_snapshot!(&album, { ".tracks[].streaming_url" => "[streaming_url]" }); check_stream_urls(&album.tracks); check_image(&album.img_url().unwrap()).await; } #[tokio::test] async fn search() { let bc = Bandcamp::new(); let res = bc.search("skyjacks", SearchFilter::All).await.unwrap(); assert!(res.results.len() > 40, "got {} results", res.results.len()); let album = res .results .iter() .find_map(|it| match it { SearchItem::Album(album) => { if album.id == 2856844961 { Some(album) } else { None } } _ => None, }) .unwrap(); let track = res .results .iter() .find_map(|it| match it { SearchItem::Track(track) => { if track.id == 2988986230 { Some(track) } else { None } } _ => None, }) .unwrap(); assert_eq!(album.name, "Skyjacks: Call of the Sky"); assert_eq!(album.art_id, Some(3000513536)); assert_eq!(album.band_id, BAND_ONESHOTPOD); assert_eq!(album.band_name, "Arne Parrott"); check_image(&album.img_url().unwrap()).await; assert_eq!(track.name, "Skyjacks"); assert_eq!(track.art_id, Some(3000513536)); assert_eq!(track.band_id, BAND_ONESHOTPOD); assert_eq!(track.band_name, "Arne Parrott"); assert_eq!(track.album_id, Some(2856844961)); assert_eq!( track.album_name.as_deref().unwrap(), "Skyjacks: Call of the Sky" ); check_image(&track.img_url().unwrap()).await; } #[tokio::test] async fn search2() { let bc = Bandcamp::new(); let res = bc .search("wintergatan proof of concept", SearchFilter::All) .await .unwrap(); let track = res .results .iter() .find_map(|it| match it { SearchItem::Track(track) => { if track.id == 1672155926 { Some(track) } else { None } } _ => None, }) .unwrap(); assert_eq!(track.name, "Proof of Concept"); assert_eq!(track.art_id, Some(4030354464)); assert_eq!(track.band_id, BAND_WINTERGATAN); assert_eq!(track.band_name, "Wintergatan"); assert_eq!(track.album_id, None); assert_eq!(track.album_name, None); check_image(&track.img_url().unwrap()).await; } #[tokio::test] async fn feed() { let bc = Bandcamp::new(); let feed = bc.feed().await.unwrap(); let stories = feed.stories.featured; assert!(stories.len() > 8, "got {} results", stories.len()); let story_ids = stories.iter().map(|s| s.ntid).collect::>(); let ctoken = &stories.last().unwrap().story_token; let feed_cont = bc.feed_cont(ctoken).await.unwrap(); let stories_cont = feed_cont.stories.featured; assert!(stories_cont.len() > 8, "got {} results", stories_cont.len()); // Check for duplicates in the continuation stories_cont.iter().for_each(|s| { assert!( !story_ids.contains(&s.ntid), "found duplicate story {} in cont", s.ntid ) }); } #[tokio::test] async fn band_from_url() { let bc = Bandcamp::new(); let band_id = bc .band_id_from_url("https://oneshotpodcast.bandcamp.com") .await .unwrap(); assert_eq!(band_id, BAND_ONESHOTPOD); } // TEST UTILS fn check_stream_urls(tracks: &[Track]) { for t in tracks { let url = t.streaming_url.get("mp3-128").expect("no mp3-128 track"); assert!( url.starts_with("https://bandcamp.com/stream_redirect"), "invalid url: {url}" ) } } async fn check_image(url: &str) { let client = Client::new(); let resp = client .get(url) .send() .await .unwrap() .error_for_status() .unwrap(); let img_type = resp .headers() .get(header::CONTENT_TYPE) .unwrap() .to_str() .unwrap(); assert!( img_type == "image/jpeg" || img_type == "image/png", "image type: {img_type}" ); }