handle rate limiting imposed by spotify web api

closes #29
This commit is contained in:
Henrik Friedrichsen
2019-03-20 23:12:58 +01:00
parent 8ee3ffed92
commit 2b45778196
3 changed files with 32 additions and 12 deletions

View File

@@ -97,7 +97,7 @@ impl Playlists {
let mut collected_tracks = Vec::new();
let mut tracks_result = spotify.user_playlist_tracks(&id, 100, 0).ok();
let mut tracks_result = spotify.user_playlist_tracks(&id, 100, 0);
while let Some(ref tracks) = tracks_result.clone() {
for listtrack in &tracks.items {
collected_tracks.push(Track::new(&listtrack.track));
@@ -110,7 +110,6 @@ impl Playlists {
debug!("requesting tracks again..");
spotify
.user_playlist_tracks(&id, 100, tracks.offset + tracks.items.len() as u32)
.ok()
}
None => None,
}
@@ -144,7 +143,7 @@ impl Playlists {
pub fn fetch_playlists(&self) {
debug!("loading playlists");
let mut lists_result = self.spotify.current_user_playlist(50, 0).ok();
let mut lists_result = self.spotify.current_user_playlist(50, 0);
while let Some(ref lists) = lists_result.clone() {
for remote in &lists.items {
if self.needs_download(remote) {
@@ -162,7 +161,6 @@ impl Playlists {
debug!("requesting playlists again..");
self.spotify
.current_user_playlist(50, lists.offset + lists.items.len() as u32)
.ok()
}
None => None,
}

View File

@@ -11,6 +11,7 @@ use librespot::playback::config::Bitrate;
use librespot::playback::player::Player;
use rspotify::spotify::client::Spotify as SpotifyAPI;
use rspotify::spotify::client::ApiError;
use rspotify::spotify::model::page::Page;
use rspotify::spotify::model::playlist::{PlaylistTrack, SimplifiedPlaylist};
use rspotify::spotify::model::search::SearchTracks;
@@ -281,16 +282,37 @@ impl Spotify {
(*since).clone()
}
pub fn search(&self, query: &str, limit: u32, offset: u32) -> Result<SearchTracks, Error> {
self.api.search_track(query, limit, offset, None)
/// retries once when rate limits are hit
fn api_with_retry<F, R>(&self, cb: F) -> Option<R>
where F: Fn(&SpotifyAPI) -> Result<R, Error> {
match cb(&self.api) {
Ok(v) => Some(v),
Err(e) => {
debug!("api error: {:?}", e);
if let Ok(apierror) = e.downcast::<ApiError>() {
if let ApiError::RateLimited(d) = apierror {
debug!("rate limit hit. waiting {:?} seconds", d);
thread::sleep(Duration::from_secs(d.unwrap_or(0) as u64));
cb(&self.api).ok()
}
else { None }
}
else { None }
}
}
}
pub fn search(&self, query: &str, limit: u32, offset: u32) -> Option<SearchTracks> {
//let res = self.api.search_track(query, limit, offset, None);
self.api_with_retry(|api| api.search_track(query, limit, offset, None) )
}
pub fn current_user_playlist(
&self,
limit: u32,
offset: u32,
) -> Result<Page<SimplifiedPlaylist>, Error> {
self.api.current_user_playlists(limit, offset)
) -> Option<Page<SimplifiedPlaylist>> {
self.api_with_retry(|api| api.current_user_playlists(limit, offset) )
}
pub fn user_playlist_tracks(
@@ -298,9 +320,9 @@ impl Spotify {
playlist_id: &str,
limit: u32,
offset: u32,
) -> Result<Page<PlaylistTrack>, Error> {
self.api
.user_playlist_tracks(&self.user, playlist_id, None, limit, offset, None)
) -> Option<Page<PlaylistTrack>> {
self.api_with_retry(|api| api
.user_playlist_tracks(&self.user, playlist_id, None, limit, offset, None))
}
pub fn load(&self, track: &Track) {

View File

@@ -53,7 +53,7 @@ impl SearchView {
v.set_content(q);
});
if let Ok(results) = spotify.search(&query, 50, 0) {
if let Some(results) = spotify.search(&query, 50, 0) {
let tracks = results
.tracks
.items