use super::{
ExternalUrls, Image, ItemType, Market, ReleaseDatePrecision, Restrictions, ResumePoint,
SimplifiedAudiobook,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Chapter {
#[cfg(feature = "markets")]
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub available_markets: Vec<Market>,
pub chapter_number: u32,
pub description: String,
pub html_description: String,
pub duration_ms: u32,
pub explicit: bool,
pub external_urls: ExternalUrls,
pub href: String,
pub id: String,
pub images: Vec<Image>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_playable: Option<bool>,
pub languages: Vec<String>,
pub name: String,
pub release_date: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub release_date_precision: Option<ReleaseDatePrecision>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resume_point: Option<ResumePoint>,
#[serde(rename = "type")]
pub type_: ItemType,
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub restrictions: Option<Restrictions>,
pub audiobook: SimplifiedAudiobook,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SimplifiedChapter {
#[cfg(feature = "markets")]
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub available_markets: Vec<Market>,
pub chapter_number: u32,
pub description: String,
pub html_description: String,
pub duration_ms: u32,
pub explicit: bool,
pub external_urls: ExternalUrls,
pub href: String,
pub id: String,
pub images: Vec<Image>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_playable: Option<bool>,
pub languages: Vec<String>,
pub name: String,
pub release_date: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub release_date_precision: Option<ReleaseDatePrecision>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resume_point: Option<ResumePoint>,
#[serde(rename = "type")]
pub type_: ItemType,
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub restrictions: Option<Restrictions>,
}
impl From<Chapter> for SimplifiedChapter {
fn from(chapter: Chapter) -> Self {
Self {
#[cfg(feature = "markets")]
available_markets: chapter.available_markets,
chapter_number: chapter.chapter_number,
description: chapter.description,
html_description: chapter.html_description,
duration_ms: chapter.duration_ms,
explicit: chapter.explicit,
external_urls: chapter.external_urls,
href: chapter.href,
id: chapter.id,
images: chapter.images,
is_playable: chapter.is_playable,
languages: chapter.languages,
name: chapter.name,
release_date: chapter.release_date,
release_date_precision: chapter.release_date_precision,
resume_point: chapter.resume_point,
type_: chapter.type_,
uri: chapter.uri,
restrictions: chapter.restrictions,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Chapters {
pub chapters: Vec<Option<Chapter>>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn chapter() {
let json = r#"
{
"audio_preview_url": "https://p.scdn.co/mp3-preview/2f37da1d4221f40b9d1a98cd191f4d6f1646ad17",
"available_markets": ["US"],
"chapter_number": 1,
"description": "We kept on ascending, with occasional periods of quick descent, but in the main always ascending. Suddenly, I became conscious of the fact that the driver was in the act of pulling up the horses in the courtyard of a vast ruined castle, from whose tall black windows came no ray of light, and whose broken battlements showed a jagged line against the moonlit sky.",
"html_description": "<p>We kept on ascending, with occasional periods of quick descent, but in the main always ascending. Suddenly, I became conscious of the fact that the driver was in the act of pulling up the horses in the courtyard of a vast ruined castle, from whose tall black windows came no ray of light, and whose broken battlements showed a jagged line against the moonlit sky.</p>",
"duration_ms": 1686230,
"explicit": false,
"external_urls": {
"spotify": "string"
},
"href": "https://api.spotify.com/v1/episodes/5Xt5DXGzch68nYYamXrNxZ",
"id": "5Xt5DXGzch68nYYamXrNxZ",
"images": [
{
"url": "https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228",
"height": 300,
"width": 300
}
],
"is_playable": false,
"languages": ["fr", "en"],
"name": "Starting Your Own Podcast: Tips, Tricks, and Advice From Anchor Creators",
"release_date": "1981-12-15",
"release_date_precision": "day",
"resume_point": {
"fully_played": false,
"resume_position_ms": 0
},
"type": "episode",
"uri": "spotify:episode:0zLhl3WsOCQHbe1BPTiHgr",
"restrictions": {
"reason": "string"
},
"audiobook": {
"authors": [
{
"name": "string"
}
],
"available_markets": ["US"],
"copyrights": [
{
"text": "string",
"type": "C"
}
],
"description": "string",
"html_description": "string",
"edition": "Unabridged",
"explicit": false,
"external_urls": {
"spotify": "string"
},
"href": "string",
"id": "string",
"images": [
{
"url": "https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228",
"height": 300,
"width": 300
}
],
"languages": ["string"],
"media_type": "string",
"name": "string",
"narrators": [
{
"name": "string"
}
],
"publisher": "string",
"type": "audiobook",
"uri": "string",
"total_chapters": 0
}
}
"#;
crate::test::assert_deserialized!(Chapter, json);
}
#[test]
fn simplified_chapter() {
let json = r#"
{
"audio_preview_url": "https://p.scdn.co/mp3-preview/2f37da1d4221f40b9d1a98cd191f4d6f1646ad17",
"available_markets": ["US"],
"chapter_number": 1,
"description": "We kept on ascending, with occasional periods of quick descent, but in the main always ascending. Suddenly, I became conscious of the fact that the driver was in the act of pulling up the horses in the courtyard of a vast ruined castle, from whose tall black windows came no ray of light, and whose broken battlements showed a jagged line against the moonlit sky.",
"html_description": "<p>We kept on ascending, with occasional periods of quick descent, but in the main always ascending. Suddenly, I became conscious of the fact that the driver was in the act of pulling up the horses in the courtyard of a vast ruined castle, from whose tall black windows came no ray of light, and whose broken battlements showed a jagged line against the moonlit sky.</p>",
"duration_ms": 1686230,
"explicit": false,
"external_urls": {
"spotify": "string"
},
"href": "https://api.spotify.com/v1/episodes/5Xt5DXGzch68nYYamXrNxZ",
"id": "5Xt5DXGzch68nYYamXrNxZ",
"images": [
{
"url": "https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228",
"height": 300,
"width": 300
}
],
"is_playable": false,
"languages": ["fr", "en"],
"name": "Starting Your Own Podcast: Tips, Tricks, and Advice From Anchor Creators",
"release_date": "1981-12-15",
"release_date_precision": "day",
"resume_point": {
"fully_played": false,
"resume_position_ms": 0
},
"type": "episode",
"uri": "spotify:episode:0zLhl3WsOCQHbe1BPTiHgr",
"restrictions": {
"reason": "string"
}
}
"#;
crate::test::assert_deserialized!(SimplifiedChapter, json);
}
}