From 71be6d51387912547921098309ccdbc1c6965a83 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Sun, 12 Jun 2022 19:21:38 -0400 Subject: [PATCH 01/12] Add 429 API error handling --- beetsplug/spotify.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index d7062f7d4..021fa8fc9 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -164,6 +164,11 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): ) self._authenticate() return self._handle_response(request_type, url, params=params) + elif response.status_code == 429: + seconds = response.headers['Retry-After'] + time.sleep(int(seconds)) + self._log.info('Too many API requests. Retrying after {} seconds.', seconds) + return self._handle_response(request_type, url, params=params) else: raise ui.UserError( '{} API error:\n{}\nURL:\n{}\nparams:\n{}'.format( From c4dec04dcf4d886cc10ebbbf50444285e3eeff0f Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Sun, 12 Jun 2022 19:27:15 -0400 Subject: [PATCH 02/12] Fix lint --- beetsplug/spotify.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 021fa8fc9..ea5a73fbd 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -167,7 +167,8 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): elif response.status_code == 429: seconds = response.headers['Retry-After'] time.sleep(int(seconds)) - self._log.info('Too many API requests. Retrying after {} seconds.', seconds) + self._log.info('Too many API requests. Retrying after {} seconds.', + seconds) return self._handle_response(request_type, url, params=params) else: raise ui.UserError( From 4bb8862b6f2f528cc9621f3ea22790026f7a9520 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Sun, 12 Jun 2022 19:28:47 -0400 Subject: [PATCH 03/12] lint --- beetsplug/spotify.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index ea5a73fbd..771d2e436 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -167,8 +167,8 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): elif response.status_code == 429: seconds = response.headers['Retry-After'] time.sleep(int(seconds)) - self._log.info('Too many API requests. Retrying after {} seconds.', - seconds) + self._log.info('Too many API requests. Retrying after {} \ + seconds.', seconds) return self._handle_response(request_type, url, params=params) else: raise ui.UserError( From a2e6680e2f21e84ccc81c6febb912b9838c022fe Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Mon, 13 Jun 2022 09:26:15 -0400 Subject: [PATCH 04/12] Address comments --- beetsplug/spotify.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 771d2e436..4aac5b24c 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -32,6 +32,7 @@ from beets import ui from beets.autotag.hooks import AlbumInfo, TrackInfo from beets.plugins import MetadataSourcePlugin, BeetsPlugin +DEFAULT_WAITING_TIME = 5 class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): data_source = 'Spotify' @@ -165,10 +166,11 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): self._authenticate() return self._handle_response(request_type, url, params=params) elif response.status_code == 429: - seconds = response.headers['Retry-After'] - time.sleep(int(seconds)) - self._log.info('Too many API requests. Retrying after {} \ + seconds = response.headers.get('Retry-After', + DEFAULT_WAITING_TIME) + self._log.debug('Too many API requests. Retrying after {} \ seconds.', seconds) + time.sleep(int(seconds)) return self._handle_response(request_type, url, params=params) else: raise ui.UserError( From c9f9ed3b646fcb66c0ccaafb94a338aa323c03bd Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Mon, 13 Jun 2022 09:31:19 -0400 Subject: [PATCH 05/12] lint --- beetsplug/spotify.py | 1 + 1 file changed, 1 insertion(+) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 4aac5b24c..ac680d99e 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -34,6 +34,7 @@ from beets.plugins import MetadataSourcePlugin, BeetsPlugin DEFAULT_WAITING_TIME = 5 + class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): data_source = 'Spotify' From 8ba2c015abbdd7935d8edfb97b873d44f0add256 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Mon, 13 Jun 2022 09:57:07 -0400 Subject: [PATCH 06/12] Sorted imports using iSort --- beetsplug/spotify.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index ac680d99e..21e97ef2c 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -17,20 +17,19 @@ Spotify playlist construction. """ -import re -import json import base64 +import collections +import json +import re import time import webbrowser -import collections -import unidecode -import requests import confuse - +import requests +import unidecode from beets import ui from beets.autotag.hooks import AlbumInfo, TrackInfo -from beets.plugins import MetadataSourcePlugin, BeetsPlugin +from beets.plugins import BeetsPlugin, MetadataSourcePlugin DEFAULT_WAITING_TIME = 5 From 3c68f717e9a2ec820eca9f41805a61555c7925de Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Mon, 13 Jun 2022 10:16:10 -0400 Subject: [PATCH 07/12] Added an extra second (based on other libraries) --- beetsplug/spotify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 21e97ef2c..d7290d963 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -170,7 +170,7 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): DEFAULT_WAITING_TIME) self._log.debug('Too many API requests. Retrying after {} \ seconds.', seconds) - time.sleep(int(seconds)) + time.sleep(int(seconds) + 1) return self._handle_response(request_type, url, params=params) else: raise ui.UserError( From 9f26190fa3289663ca2dc32a92f24049379464f4 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Mon, 13 Jun 2022 10:25:48 -0400 Subject: [PATCH 08/12] Added changelog --- docs/changelog.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index c95287443..dc13ee781 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,7 +32,9 @@ New features: Bug fixes: -* Fix implicit paths OR queries (e.g. ``beet list /path/ , /other-path/``) +* Added Spotify 429 (too many requests) API error handling + :bug:`4370` +* Fix implicit paths OR queries (e.g. ``beet list /path/ , /other-path/``) which have previously been returning the entire library. :bug:`1865` * The Discogs release ID is now populated correctly to the discogs_albumid From 4d826168a4eec04fb49bd410cb20ef631cbd3438 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Thu, 16 Jun 2022 09:00:17 -0400 Subject: [PATCH 09/12] Remove sleep --- beetsplug/spotify.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index d7290d963..4980d9c1b 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -585,9 +585,6 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): self._log.debug('Total {} tracks', len(items)) for index, item in enumerate(items, start=1): - # Added sleep to avoid API rate limit - # https://developer.spotify.com/documentation/web-api/guides/rate-limits/ - time.sleep(.5) self._log.info('Processing {}/{} tracks - {} ', index, len(items), item) # If we're not forcing re-downloading for all tracks, check From 1cd78ad3c551aa09e836c51a1da092770c441593 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Thu, 16 Jun 2022 09:28:07 -0400 Subject: [PATCH 10/12] Change log to info --- beetsplug/spotify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index 4980d9c1b..c4174d02b 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -168,7 +168,7 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): elif response.status_code == 429: seconds = response.headers.get('Retry-After', DEFAULT_WAITING_TIME) - self._log.debug('Too many API requests. Retrying after {} \ + self._log.info('Too many API requests. Retrying after {} \ seconds.', seconds) time.sleep(int(seconds) + 1) return self._handle_response(request_type, url, params=params) From b1b0926eed50e46d88809d07b806672ea0628514 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Sat, 18 Jun 2022 10:45:02 -0400 Subject: [PATCH 11/12] UPdate changelog --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index dc13ee781..dbee12764 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,7 +32,7 @@ New features: Bug fixes: -* Added Spotify 429 (too many requests) API error handling +* We now respect the Spotify API's rate limiting, which avoids crashing when the API reports code 429 (too many requests). :bug:`4370` * Fix implicit paths OR queries (e.g. ``beet list /path/ , /other-path/``) which have previously been returning the entire library. From abe4f203b1f989456b1bf646f83ff2be08938129 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Sat, 18 Jun 2022 11:23:22 -0400 Subject: [PATCH 12/12] Changed log to debug --- beetsplug/spotify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/spotify.py b/beetsplug/spotify.py index c4174d02b..4980d9c1b 100644 --- a/beetsplug/spotify.py +++ b/beetsplug/spotify.py @@ -168,7 +168,7 @@ class SpotifyPlugin(MetadataSourcePlugin, BeetsPlugin): elif response.status_code == 429: seconds = response.headers.get('Retry-After', DEFAULT_WAITING_TIME) - self._log.info('Too many API requests. Retrying after {} \ + self._log.debug('Too many API requests. Retrying after {} \ seconds.', seconds) time.sleep(int(seconds) + 1) return self._handle_response(request_type, url, params=params)