1use serde::{Deserialize, Serialize};
4
5use super::artist::ArtistSimplified;
6use super::common::{Copyright, ExternalIds, ExternalUrls, Image, Paginated, Restrictions};
7use super::track::TrackSimplified;
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
11#[serde(rename_all = "snake_case")]
12pub enum AlbumType {
13 Album,
14 Single,
15 Compilation,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct AlbumSimplified {
21 pub album_type: Option<String>,
23 pub total_tracks: Option<u32>,
25 pub available_markets: Option<Vec<String>>,
27 pub external_urls: Option<ExternalUrls>,
29 pub href: Option<String>,
31 pub id: String,
33 pub images: Option<Vec<Image>>,
35 pub name: String,
37 pub release_date: Option<String>,
39 pub release_date_precision: Option<String>,
41 pub restrictions: Option<Restrictions>,
43 #[serde(rename = "type")]
45 pub item_type: String,
46 pub uri: String,
48 pub artists: Option<Vec<ArtistSimplified>>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct Album {
55 pub album_type: Option<String>,
57 pub total_tracks: Option<u32>,
59 pub available_markets: Option<Vec<String>>,
61 pub external_urls: Option<ExternalUrls>,
63 pub href: Option<String>,
65 pub id: String,
67 pub images: Option<Vec<Image>>,
69 pub name: String,
71 pub release_date: Option<String>,
73 pub release_date_precision: Option<String>,
75 pub restrictions: Option<Restrictions>,
77 #[serde(rename = "type")]
79 pub item_type: String,
80 pub uri: String,
82 pub artists: Option<Vec<ArtistSimplified>>,
84 pub tracks: Option<Paginated<TrackSimplified>>,
86 pub copyrights: Option<Vec<Copyright>>,
88 pub external_ids: Option<ExternalIds>,
90 pub genres: Option<Vec<String>>,
92 pub label: Option<String>,
94 pub popularity: Option<u32>,
96}
97
98impl Album {
99 pub fn image_url(&self) -> Option<&str> {
101 self.images
102 .as_ref()
103 .and_then(|imgs| imgs.first())
104 .map(|img| img.url.as_str())
105 }
106
107 pub fn artist_name(&self) -> Option<&str> {
109 self.artists
110 .as_ref()
111 .and_then(|artists| artists.first())
112 .map(|a| a.name.as_str())
113 }
114
115 pub fn release_year(&self) -> Option<&str> {
117 self.release_date.as_ref().map(|d| &d[..4])
118 }
119}
120
121impl AlbumSimplified {
122 pub fn image_url(&self) -> Option<&str> {
124 self.images
125 .as_ref()
126 .and_then(|imgs| imgs.first())
127 .map(|img| img.url.as_str())
128 }
129
130 pub fn artist_name(&self) -> Option<&str> {
132 self.artists
133 .as_ref()
134 .and_then(|artists| artists.first())
135 .map(|a| a.name.as_str())
136 }
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct SavedAlbum {
142 pub added_at: String,
144 pub album: Album,
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use serde_json::json;
152
153 #[test]
154 fn album_type_deserializes() {
155 let json = json!("album");
156 let album_type: AlbumType = serde_json::from_value(json).unwrap();
157 assert_eq!(album_type, AlbumType::Album);
158
159 let json = json!("single");
160 let album_type: AlbumType = serde_json::from_value(json).unwrap();
161 assert_eq!(album_type, AlbumType::Single);
162
163 let json = json!("compilation");
164 let album_type: AlbumType = serde_json::from_value(json).unwrap();
165 assert_eq!(album_type, AlbumType::Compilation);
166 }
167
168 #[test]
169 fn album_simplified_deserializes() {
170 let json = json!({
171 "id": "album123",
172 "name": "Test Album",
173 "type": "album",
174 "uri": "spotify:album:album123",
175 "album_type": "album",
176 "total_tracks": 12,
177 "release_date": "2024-01-15"
178 });
179 let album: AlbumSimplified = serde_json::from_value(json).unwrap();
180 assert_eq!(album.id, "album123");
181 assert_eq!(album.name, "Test Album");
182 assert_eq!(album.total_tracks, Some(12));
183 }
184
185 #[test]
186 fn album_simplified_image_url() {
187 let json = json!({
188 "id": "album123",
189 "name": "Test Album",
190 "type": "album",
191 "uri": "spotify:album:album123",
192 "images": [{"url": "https://cover.jpg", "height": 640, "width": 640}]
193 });
194 let album: AlbumSimplified = serde_json::from_value(json).unwrap();
195 assert_eq!(album.image_url(), Some("https://cover.jpg"));
196 }
197
198 #[test]
199 fn album_simplified_image_url_none() {
200 let json = json!({
201 "id": "album123",
202 "name": "Test Album",
203 "type": "album",
204 "uri": "spotify:album:album123"
205 });
206 let album: AlbumSimplified = serde_json::from_value(json).unwrap();
207 assert!(album.image_url().is_none());
208 }
209
210 #[test]
211 fn album_simplified_artist_name() {
212 let json = json!({
213 "id": "album123",
214 "name": "Test Album",
215 "type": "album",
216 "uri": "spotify:album:album123",
217 "artists": [{"id": "artist1", "name": "Test Artist", "type": "artist", "uri": "spotify:artist:artist1"}]
218 });
219 let album: AlbumSimplified = serde_json::from_value(json).unwrap();
220 assert_eq!(album.artist_name(), Some("Test Artist"));
221 }
222
223 #[test]
224 fn album_simplified_artist_name_none() {
225 let json = json!({
226 "id": "album123",
227 "name": "Test Album",
228 "type": "album",
229 "uri": "spotify:album:album123"
230 });
231 let album: AlbumSimplified = serde_json::from_value(json).unwrap();
232 assert!(album.artist_name().is_none());
233 }
234
235 #[test]
236 fn album_full_deserializes() {
237 let json = json!({
238 "id": "album123",
239 "name": "Test Album",
240 "type": "album",
241 "uri": "spotify:album:album123",
242 "album_type": "album",
243 "total_tracks": 12,
244 "release_date": "2024-01-15",
245 "popularity": 75,
246 "label": "Test Label",
247 "genres": ["rock", "alternative"]
248 });
249 let album: Album = serde_json::from_value(json).unwrap();
250 assert_eq!(album.id, "album123");
251 assert_eq!(album.popularity, Some(75));
252 assert_eq!(album.label, Some("Test Label".to_string()));
253 }
254
255 #[test]
256 fn album_image_url() {
257 let json = json!({
258 "id": "album123",
259 "name": "Test Album",
260 "type": "album",
261 "uri": "spotify:album:album123",
262 "images": [{"url": "https://large.jpg", "height": 640, "width": 640}]
263 });
264 let album: Album = serde_json::from_value(json).unwrap();
265 assert_eq!(album.image_url(), Some("https://large.jpg"));
266 }
267
268 #[test]
269 fn album_artist_name() {
270 let json = json!({
271 "id": "album123",
272 "name": "Test Album",
273 "type": "album",
274 "uri": "spotify:album:album123",
275 "artists": [{"id": "artist1", "name": "Primary Artist", "type": "artist", "uri": "spotify:artist:artist1"}]
276 });
277 let album: Album = serde_json::from_value(json).unwrap();
278 assert_eq!(album.artist_name(), Some("Primary Artist"));
279 }
280
281 #[test]
282 fn album_release_year() {
283 let json = json!({
284 "id": "album123",
285 "name": "Test Album",
286 "type": "album",
287 "uri": "spotify:album:album123",
288 "release_date": "2024-01-15"
289 });
290 let album: Album = serde_json::from_value(json).unwrap();
291 assert_eq!(album.release_year(), Some("2024"));
292 }
293
294 #[test]
295 fn album_release_year_none() {
296 let json = json!({
297 "id": "album123",
298 "name": "Test Album",
299 "type": "album",
300 "uri": "spotify:album:album123"
301 });
302 let album: Album = serde_json::from_value(json).unwrap();
303 assert!(album.release_year().is_none());
304 }
305
306 #[test]
307 fn saved_album_deserializes() {
308 let json = json!({
309 "added_at": "2024-01-15T10:30:00Z",
310 "album": {
311 "id": "album123",
312 "name": "Test Album",
313 "type": "album",
314 "uri": "spotify:album:album123"
315 }
316 });
317 let saved: SavedAlbum = serde_json::from_value(json).unwrap();
318 assert_eq!(saved.added_at, "2024-01-15T10:30:00Z");
319 assert_eq!(saved.album.id, "album123");
320 }
321}