|
@@ -46,6 +46,7 @@ namespace MediaBrowser.Providers.Music
|
|
|
|
|
|
private readonly string _musicBrainzBaseUrl;
|
|
|
|
|
|
+ private SemaphoreSlim _apiRequestLock = new SemaphoreSlim(1, 1);
|
|
|
private Stopwatch _stopWatchMusicBrainz = new Stopwatch();
|
|
|
|
|
|
public MusicBrainzAlbumProvider(
|
|
@@ -742,48 +743,58 @@ namespace MediaBrowser.Providers.Music
|
|
|
/// </summary>
|
|
|
internal async Task<HttpResponseMessage> GetMusicBrainzResponse(string url, CancellationToken cancellationToken)
|
|
|
{
|
|
|
- using var options = new HttpRequestMessage(HttpMethod.Get, _musicBrainzBaseUrl.TrimEnd('/') + url);
|
|
|
+ await _apiRequestLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
- // MusicBrainz request a contact email address is supplied, as comment, in user agent field:
|
|
|
- // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent
|
|
|
- options.Headers.UserAgent.ParseAdd(string.Format(
|
|
|
- CultureInfo.InvariantCulture,
|
|
|
- "{0} ( {1} )",
|
|
|
- _appHost.ApplicationUserAgent,
|
|
|
- _appHost.ApplicationUserAgentAddress));
|
|
|
-
|
|
|
- HttpResponseMessage response;
|
|
|
- var attempts = 0u;
|
|
|
-
|
|
|
- do
|
|
|
+ try
|
|
|
{
|
|
|
- attempts++;
|
|
|
+ HttpResponseMessage response;
|
|
|
+ var attempts = 0u;
|
|
|
+ var requestUrl = _musicBrainzBaseUrl.TrimEnd('/') + url;
|
|
|
|
|
|
- if (_stopWatchMusicBrainz.ElapsedMilliseconds < _musicBrainzQueryIntervalMs)
|
|
|
+ do
|
|
|
{
|
|
|
- // MusicBrainz is extremely adamant about limiting to one request per second
|
|
|
- var delayMs = _musicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds;
|
|
|
- await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false);
|
|
|
- }
|
|
|
+ attempts++;
|
|
|
|
|
|
- // Write time since last request to debug log as evidence we're meeting rate limit
|
|
|
- // requirement, before resetting stopwatch back to zero.
|
|
|
- _logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds);
|
|
|
- _stopWatchMusicBrainz.Restart();
|
|
|
+ if (_stopWatchMusicBrainz.ElapsedMilliseconds < _musicBrainzQueryIntervalMs)
|
|
|
+ {
|
|
|
+ // MusicBrainz is extremely adamant about limiting to one request per second.
|
|
|
+ var delayMs = _musicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds;
|
|
|
+ await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false);
|
|
|
+ }
|
|
|
|
|
|
- response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options).ConfigureAwait(false);
|
|
|
+ // Write time since last request to debug log as evidence we're meeting rate limit
|
|
|
+ // requirement, before resetting stopwatch back to zero.
|
|
|
+ _logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds);
|
|
|
+ _stopWatchMusicBrainz.Restart();
|
|
|
|
|
|
- // We retry a finite number of times, and only whilst MB is indicating 503 (throttling)
|
|
|
- }
|
|
|
- while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable);
|
|
|
+ using var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
|
|
+
|
|
|
+ // MusicBrainz request a contact email address is supplied, as comment, in user agent field:
|
|
|
+ // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent .
|
|
|
+ request.Headers.UserAgent.ParseAdd(string.Format(
|
|
|
+ CultureInfo.InvariantCulture,
|
|
|
+ "{0} ( {1} )",
|
|
|
+ _appHost.ApplicationUserAgent,
|
|
|
+ _appHost.ApplicationUserAgentAddress));
|
|
|
|
|
|
- // Log error if unable to query MB database due to throttling
|
|
|
- if (attempts == MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable)
|
|
|
+ response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(request).ConfigureAwait(false);
|
|
|
+
|
|
|
+ // We retry a finite number of times, and only whilst MB is indicating 503 (throttling).
|
|
|
+ }
|
|
|
+ while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable);
|
|
|
+
|
|
|
+ // Log error if unable to query MB database due to throttling.
|
|
|
+ if (attempts == MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable)
|
|
|
+ {
|
|
|
+ _logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, requestUrl);
|
|
|
+ }
|
|
|
+
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+ finally
|
|
|
{
|
|
|
- _logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, options.RequestUri);
|
|
|
+ _apiRequestLock.Release();
|
|
|
}
|
|
|
-
|
|
|
- return response;
|
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|