ferrispot/client/
unscoped.rs1use log::warn;
2use reqwest::{Method, StatusCode};
3
4use super::{request_builder::RequestBuilder, API_USER_PROFILE_ENDPOINT};
5#[cfg(feature = "async")]
6use crate::client::request_builder::AsyncResponseHandler;
7#[cfg(feature = "sync")]
8use crate::client::request_builder::SyncResponseHandler;
9use crate::{
10 client::{
11 object,
12 request_builder::{BaseRequestBuilderContainer, CatalogItemRequestBuilder, SearchBuilder},
13 API_SEARCH_ENDPOINT, API_TRACKS_ENDPOINT,
14 },
15 error::Error,
16 model::{
17 id::{Id, IdTrait, TrackId, UserId},
18 track::FullTrack,
19 user::PublicUser,
20 },
21};
22
23pub trait UnscopedClient
26where
27 Self: crate::private::Sealed + Clone + Sized,
28{
29 fn track<'a>(&'a self, track: Id<'a, TrackId>) -> CatalogItemRequestBuilder<Self, FullTrack> {
35 let mut builder = CatalogItemRequestBuilder::new(
36 Method::GET,
37 format!("{}/{}", API_TRACKS_ENDPOINT, track.as_str()),
38 self.clone(),
39 );
40
41 #[cfg(feature = "async")]
42 {
43 builder = builder.with_async_response_handler(track_response_handler_async_fn(track.as_owned()));
44 }
45
46 #[cfg(feature = "sync")]
47 {
48 builder = builder.with_sync_response_handler(track_response_handler_sync_fn(track.as_owned()));
49 }
50
51 builder
52 }
53
54 fn tracks<'a, I>(&'a self, tracks: I) -> CatalogItemRequestBuilder<Self, object::TracksResponse, Vec<FullTrack>>
62 where
63 I: IntoIterator<Item = Id<'a, TrackId>>,
64 {
65 CatalogItemRequestBuilder::new(Method::GET, API_TRACKS_ENDPOINT, self.clone()).append_query(
66 object::TRACKS_IDS_QUERY,
67 tracks
68 .into_iter()
69 .map(|id| id.as_str().to_owned())
70 .collect::<Vec<_>>()
71 .join(","),
72 )
73 }
74
75 fn search<S>(&self, query: S) -> SearchBuilder<Self>
81 where
82 S: Into<String>,
83 {
84 SearchBuilder::new(Method::GET, API_SEARCH_ENDPOINT, self.clone()).query(query.into())
85 }
86
87 fn user_profile<'a>(&'a self, user_id: Id<'a, UserId>) -> RequestBuilder<Self, PublicUser> {
89 RequestBuilder::new(
90 Method::GET,
91 format!("{API_USER_PROFILE_ENDPOINT}/{}", user_id.as_str()),
92 self.clone(),
93 )
94 }
95}
96
97#[cfg(feature = "async")]
98fn track_response_handler_async_fn(track_id: Id<'static, TrackId>) -> AsyncResponseHandler {
99 Box::new(move |response| {
100 Box::pin(async move {
101 match response.status() {
102 StatusCode::OK => Ok(response),
103
104 StatusCode::NOT_FOUND => {
105 warn!("Got 404 Not Found to track call");
106 Err(Error::NonexistentTrack(track_id))
107 }
108
109 other => Err(Error::UnhandledSpotifyResponseStatusCode(other.as_u16())),
110 }
111 })
112 })
113}
114
115#[cfg(feature = "sync")]
116fn track_response_handler_sync_fn(track_id: Id<'static, TrackId>) -> SyncResponseHandler {
117 Box::new(move |response| match response.status() {
118 StatusCode::OK => Ok(response),
119
120 StatusCode::NOT_FOUND => {
121 warn!("Got 404 Not Found to track call");
122 Err(Error::NonexistentTrack(track_id))
123 }
124
125 other => Err(Error::UnhandledSpotifyResponseStatusCode(other.as_u16())),
126 })
127}