1pub mod album;
5pub mod artist;
6pub mod audio;
7pub mod auth;
8pub mod category;
9pub mod context;
10pub(crate) mod custom_serde;
11pub mod device;
12pub mod enums;
13pub mod error;
14pub mod idtypes;
15pub mod image;
16pub mod offset;
17pub mod page;
18pub mod playing;
19pub mod playlist;
20pub mod recommend;
21pub mod search;
22pub mod show;
23pub mod track;
24pub mod user;
25
26pub use {
27 album::*, artist::*, audio::*, auth::*, category::*, context::*, device::*, enums::*, error::*,
28 idtypes::*, image::*, offset::*, page::*, playing::*, playlist::*, recommend::*, search::*,
29 show::*, track::*, user::*,
30};
31
32use serde::{Deserialize, Serialize};
33
34#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
36pub struct Followers {
37 pub total: u32,
40}
41
42#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
44#[serde(untagged)]
45pub enum PlayableItem {
46 Track(track::FullTrack),
47 Episode(show::FullEpisode),
48 Unknown(serde_json::Value),
52}
53
54impl PlayableItem {
55 pub fn is_unknown(&self) -> bool {
59 matches!(self, PlayableItem::Unknown(_))
60 }
61
62 #[must_use]
67 pub fn id(&self) -> Option<PlayableId<'_>> {
68 match self {
69 PlayableItem::Track(t) => t.id.as_ref().map(|t| PlayableId::Track(t.as_ref())),
70 PlayableItem::Episode(e) => Some(PlayableId::Episode(e.id.as_ref())),
71 PlayableItem::Unknown(value) => {
72 let id_str = value.get("id")?.as_str()?;
73 if let Some(type_str) = value.get("type").and_then(|v| v.as_str()) {
74 match type_str {
75 "episode" => Some(PlayableId::Episode(EpisodeId::from_id(id_str).ok()?)),
76 _ => Some(PlayableId::Track(TrackId::from_id(id_str).ok()?)),
77 }
78 } else {
79 Some(PlayableId::Track(TrackId::from_id(id_str).ok()?))
81 }
82 }
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_get_id() {
93 let artist_id = "spotify:artist:2WX2uTcsvV5OnS0inACecP";
95 let id = ArtistId::from_id_or_uri(artist_id).unwrap();
96 assert_eq!("2WX2uTcsvV5OnS0inACecP", id.id());
97
98 let album_id_a = "spotify/album/2WX2uTcsvV5OnS0inACecP";
100 assert_eq!(
101 "2WX2uTcsvV5OnS0inACecP",
102 AlbumId::from_id_or_uri(album_id_a).unwrap().id()
103 );
104
105 assert_eq!(
107 Err(IdError::InvalidType),
108 ArtistId::from_id_or_uri(album_id_a)
109 );
110
111 let artist_id_c = "spotify-album-2WX2uTcsvV5OnS0inACecP";
113 assert_eq!(
114 Err(IdError::InvalidId),
115 ArtistId::from_id_or_uri(artist_id_c)
116 );
117
118 let playlist_id = "spotify:playlist:59ZbFPES4DQwEjBpWHzrtC";
119 assert_eq!(
120 "59ZbFPES4DQwEjBpWHzrtC",
121 PlaylistId::from_id_or_uri(playlist_id).unwrap().id()
122 );
123 }
124
125 #[test]
126 fn test_get_uri() {
127 let track_id1 = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh";
128 let track_id2 = "1301WleyT98MSxVHPZCA6M";
129 let id1 = TrackId::from_id_or_uri(track_id1).unwrap();
130 let id2 = TrackId::from_id_or_uri(track_id2).unwrap();
131 assert_eq!(track_id1, &id1.uri());
132 assert_eq!("spotify:track:1301WleyT98MSxVHPZCA6M", &id2.uri());
133 }
134}