Compare commits

..

2 commits

Author SHA1 Message Date
b3bf3f62a7 feat: improve error handling
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-11-18 11:54:18 +01:00
0c4ab0a01d add album_track test 2023-06-16 01:43:18 +02:00
6 changed files with 110 additions and 5 deletions

View file

@ -2,6 +2,7 @@
name = "codegen"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
reqwest = "0.11.11"

View file

@ -12,6 +12,12 @@ pub enum Error {
/// Website parsing error
#[error("website parsing error: {0}")]
WebsiteParsing(Cow<'static, str>),
/// Item not found on Bandcamp
#[error("{0}")]
NotFound(Cow<'static, str>),
/// Other error from Bandcamp
#[error("{0}")]
Bandcamp(Cow<'static, str>),
#[error("invalid bandcamp url")]
InvalidUrl,
#[error("invalid album uid")]

View file

@ -64,6 +64,13 @@ pub struct Track {
pub band_name: Option<String>,
/// Duration in seconds
pub duration: f32,
/// Map of audio formats and URLs.
///
/// 128kbit/s MP3 is currently the only publicly available format.
///
/// **Example:**
///
/// `mp3-128` => `https://bandcamp.com/stream_redirect?enc=mp3-128&track_id=4173325157&ts=1686871135&t=a1f7904205e6caca970009ca6744ef0b512f353a`
pub streaming_url: BTreeMap<String, String>,
pub track_num: u16,
}

View file

@ -38,6 +38,28 @@ struct SearchResultWrapper {
auto: SearchResult,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum ResponseWrapper<T> {
Ok(T),
Error { error_message: String },
}
impl<T> ResponseWrapper<T> {
fn convert(self) -> Result<T> {
match self {
ResponseWrapper::Ok(data) => Ok(data),
ResponseWrapper::Error { error_message } => {
if error_message.starts_with("No such ") || error_message.ends_with(" not found") {
Err(Error::NotFound(error_message.into()))
} else {
Err(Error::Bandcamp(error_message.into()))
}
}
}
}
}
impl Bandcamp {
pub async fn band(&self, band_id: u64) -> Result<Band> {
let req = BandRequest { band_id };
@ -50,9 +72,15 @@ impl Bandcamp {
.await?
.error_for_status()?;
Ok(resp.json().await?)
resp.json::<ResponseWrapper<Band>>().await?.convert()
}
/// Get a album (or a track) from the Bandcamp API
///
/// # Parameters
/// - `band_id` The Band ID of the album/track
/// - `tralbum_id` Album/Track ID
/// - `tralbum_type` Track/Album
pub async fn album(
&self,
band_id: u64,
@ -73,7 +101,7 @@ impl Bandcamp {
.await?
.error_for_status()?;
Ok(resp.json().await?)
resp.json::<ResponseWrapper<Album>>().await?.convert()
}
pub async fn album_uid<S: AsRef<str>>(&self, uid: S) -> Result<Album> {
@ -103,7 +131,11 @@ impl Bandcamp {
.await?
.error_for_status()?;
Ok(resp.json::<SearchResultWrapper>().await?.auto)
Ok(resp
.json::<ResponseWrapper<SearchResultWrapper>>()
.await?
.convert()?
.auto)
}
pub async fn feed(&self) -> Result<Feed> {
@ -117,7 +149,7 @@ impl Bandcamp {
.await?
.error_for_status()?;
Ok(resp.json().await?)
resp.json::<ResponseWrapper<Feed>>().await?.convert()
}
pub async fn feed_cont<S: AsRef<str>>(&self, token: S) -> Result<Feed> {
@ -134,7 +166,7 @@ impl Bandcamp {
.await?
.error_for_status()?;
Ok(resp.json().await?)
resp.json::<ResponseWrapper<Feed>>().await?.convert()
}
pub async fn band_id_from_url<U: IntoUrl>(&self, url: U) -> Result<u64> {

View file

@ -0,0 +1,44 @@
---
source: tests/tests.rs
assertion_line: 69
expression: "&album"
---
Album(
id: 716010980,
title: "All Was Well",
art_id: Some(2367528067),
type: t,
tralbum_artist: "Wintergatan",
band: BandInfo(
band_id: 2464198920,
name: "Wintergatan",
bio: "",
image_id: Some(1354613),
location: "Gothenburg, Sweden",
),
bandcamp_url: "https://wintergatan.bandcamp.com/track/all-was-well",
credits: None,
about: None,
featured_track_id: 716010980,
release_date: 1366761600,
tags: [
Tag(
name: "Pop",
norm_name: "pop",
isloc: false,
),
],
tracks: [
Track(
track_id: 716010980,
title: "All Was Well",
album_id: 2572654767,
album_title: None,
band_id: 2464198920,
band_name: Some("Wintergatan"),
duration: 183.224,
streaming_url: "[streaming_url]",
track_num: 8,
),
],
)

View file

@ -58,6 +58,21 @@ async fn album2() {
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 search() {
let bc = Bandcamp::new();