Skip to content

Commit 70a5757

Browse files
author
Jonas Dellinger
committed
Merge branch 'master' of github.com:JohnnyCrazy/SpotifyAPI-NET
2 parents e7f4047 + 67cb3e4 commit 70a5757

5 files changed

Lines changed: 135 additions & 92 deletions

File tree

‎README.md‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,26 @@ SpotifyAPI-NET
55
[![Nuget](https://badge.fury.io/nu/SpotifyAPI-NET.svg)](https://www.nuget.org/packages/SpotifyAPI-NET/)
66
[![Gitter](https://img.shields.io/gitter/room/SpotifyAPI-NET/Lobby.svg)](https://gitter.im/SpotifyAPI-NET/Lobby)
77

8-
An API for the Spotify-Client and Spotify's Web API, written in .NET
8+
A Wrapper for Spotify's Web API, written in .NET
99

1010
**Spotify's Web API** ([link](https://developer.spotify.com/web-api/))
1111
> Based on simple REST principles, our Web API endpoints return metadata in JSON format about artists, albums, and tracks directly from the Spotify catalogue.
1212
> The API also provides access to user-related data such as playlists and music saved in a “Your Music” library, subject to user’s authorization.
1313
14-
**Spotify's *unofficial* Local API**
15-
> Do you ever wanted to control your local Spotify Client with some sort of API? Now you can! This API gives you full control over your spotify client.
16-
> You can get infos about the currently playing song, get its Album-Art, skip/pause and much more. It also features multiple Event-Interfaces.
17-
1814
### Docs and Usage
1915

2016
More Information, Installation-Instructions, Examples and API-Reference can be found at [github.io/SpotifyAPI-Net/](http://johnnycrazy.github.io/SpotifyAPI-NET/)
2117

2218
### NuGet
23-
You can add the API to your project via [nuget-package](https://www.nuget.org/packages/SpotifyAPI-NET/):
19+
You can add the API to your project via [nuget-package](https://www.nuget.org/packages/SpotifyAPI.Web/):
2420
```
25-
Install-Package SpotifyAPI-NET
21+
Install-Package SpotifyAPI.Web
22+
Install-Package SpotifyAPI.Web.Auth
23+
2624
//or
27-
Install-Package SpotifyAPI-Net -pre
25+
26+
Install-Package SpotifyAPI.Web -pre
27+
Install-Package SpotifyAPI.Web.Auth -pre
2828
```
2929

3030
### Example

‎SpotifyAPI.Web/Models/BasicModel.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Newtonsoft.Json;
2+
using SpotifyAPI.Web.Enums;
23
using System;
34
using System.Net;
45

‎SpotifyAPI.Web/Models/ResponseInfo.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Net;
1+
using SpotifyAPI.Web.Enums;
2+
using System.Net;
23

34
namespace SpotifyAPI.Web.Models
45
{

‎SpotifyAPI.Web/SpotifyWebAPI.cs‎

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Newtonsoft.Json;
1+
using Newtonsoft.Json;
22
using Newtonsoft.Json.Linq;
33
using SpotifyAPI.Web.Enums;
44
using SpotifyAPI.Web.Models;
@@ -23,15 +23,14 @@ public SpotifyWebAPI(ProxyConfig proxyConfig)
2323
{
2424
_builder = new SpotifyWebBuilder();
2525
UseAuth = true;
26-
WebClient = new SpotifyWebClient
26+
WebClient = new SpotifyWebClient(proxyConfig)
2727
{
2828
JsonSettings =
2929
new JsonSerializerSettings
3030
{
3131
NullValueHandling = NullValueHandling.Ignore,
3232
TypeNameHandling = TypeNameHandling.All
33-
},
34-
ProxyConfig = proxyConfig
33+
}
3534
};
3635
}
3736

@@ -79,6 +78,11 @@ public void Dispose()
7978
/// </summary>
8079
public int RetryTimes { get; set; } = 10;
8180

81+
/// <summary>
82+
/// Whether a failure of type "Too Many Requests" should use up one of the allocated retry attempts.
83+
/// </summary>
84+
public bool TooManyRequestsConsumesARetry { get; set; } = false;
85+
8286
/// <summary>
8387
/// Error codes that will trigger auto-retry if <see cref="UseAutoRetry"/> is enabled.
8488
/// </summary>
@@ -2001,11 +2005,12 @@ public Task<ErrorResponse> TransferPlaybackAsync(List<string> deviceIds, bool pl
20012005
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
20022006
/// <param name="contextUri">Spotify URI of the context to play.</param>
20032007
/// <param name="uris">A JSON array of the Spotify track URIs to play.</param>
2004-
/// <param name="offset">Indicates from where in the context playback should start.
2008+
/// <param name="offset">Indicates from where in the context playback should start.
2009+
/// <param name="positionMs">The starting time to seek the track to</param>
20052010
/// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used.</param>
20062011
/// <returns></returns>
20072012
public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = "", List<string> uris = null,
2008-
int? offset = null)
2013+
int? offset = null, int positionMs = 0)
20092014
{
20102015
JObject ob = new JObject();
20112016
if(!string.IsNullOrEmpty(contextUri))
@@ -2014,6 +2019,8 @@ public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = ""
20142019
ob.Add("uris", new JArray(uris));
20152020
if(offset != null)
20162021
ob.Add("offset", new JObject { { "position", offset } });
2022+
if (positionMs > 0)
2023+
ob.Add("position_ms", positionMs);
20172024
return UploadData<ErrorResponse>(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT");
20182025
}
20192026

@@ -2023,11 +2030,12 @@ public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = ""
20232030
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
20242031
/// <param name="contextUri">Spotify URI of the context to play.</param>
20252032
/// <param name="uris">A JSON array of the Spotify track URIs to play.</param>
2026-
/// <param name="offset">Indicates from where in the context playback should start.
2033+
/// <param name="offset">Indicates from where in the context playback should start.
2034+
/// <param name="positionMs">The starting time to seek the track to</param>
20272035
/// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used.</param>
20282036
/// <returns></returns>
20292037
public Task<ErrorResponse> ResumePlaybackAsync(string deviceId = "", string contextUri = "", List<string> uris = null,
2030-
int? offset = null)
2038+
int? offset = null, int positionMs = 0)
20312039
{
20322040
JObject ob = new JObject();
20332041
if (!string.IsNullOrEmpty(contextUri))
@@ -2036,6 +2044,8 @@ public Task<ErrorResponse> ResumePlaybackAsync(string deviceId = "", string cont
20362044
ob.Add("uris", new JArray(uris));
20372045
if (offset != null)
20382046
ob.Add("offset", new JObject { { "position", offset } });
2047+
if (positionMs > 0)
2048+
ob.Add("position_ms", positionMs);
20392049
return UploadDataAsync<ErrorResponse>(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT");
20402050
}
20412051

@@ -2045,11 +2055,12 @@ public Task<ErrorResponse> ResumePlaybackAsync(string deviceId = "", string cont
20452055
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
20462056
/// <param name="contextUri">Spotify URI of the context to play.</param>
20472057
/// <param name="uris">A JSON array of the Spotify track URIs to play.</param>
2048-
/// <param name="offset">Indicates from where in the context playback should start.
2058+
/// <param name="offset">Indicates from where in the context playback should start.
2059+
/// <param name="positionMs">The starting time to seek the track to</param>
20492060
/// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used.</param>
20502061
/// <returns></returns>
20512062
public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = "", List<string> uris = null,
2052-
string offset = "")
2063+
string offset = "", int positionMs = 0)
20532064
{
20542065
JObject ob = new JObject();
20552066
if (!string.IsNullOrEmpty(contextUri))
@@ -2058,6 +2069,8 @@ public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = ""
20582069
ob.Add("uris", new JArray(uris));
20592070
if (!string.IsNullOrEmpty(offset))
20602071
ob.Add("offset", new JObject {{"uri", offset}});
2072+
if (positionMs > 0)
2073+
ob.Add("position_ms", positionMs);
20612074
return UploadData<ErrorResponse>(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT");
20622075
}
20632076

@@ -2067,11 +2080,12 @@ public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = ""
20672080
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
20682081
/// <param name="contextUri">Spotify URI of the context to play.</param>
20692082
/// <param name="uris">A JSON array of the Spotify track URIs to play.</param>
2070-
/// <param name="offset">Indicates from where in the context playback should start.
2083+
/// <param name="offset">Indicates from where in the context playback should start.
2084+
/// <param name="positionMs">The starting time to seek the track to</param>
20712085
/// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used.</param>
20722086
/// <returns></returns>
20732087
public Task<ErrorResponse> ResumePlaybackAsync(string deviceId = "", string contextUri = "", List<string> uris = null,
2074-
string offset = "")
2088+
string offset = "", int positionMs = 0)
20752089
{
20762090
JObject ob = new JObject();
20772091
if (!string.IsNullOrEmpty(contextUri))
@@ -2080,6 +2094,8 @@ public Task<ErrorResponse> ResumePlaybackAsync(string deviceId = "", string cont
20802094
ob.Add("uris", new JArray(uris));
20812095
if (!string.IsNullOrEmpty(offset))
20822096
ob.Add("offset", new JObject { { "uri", offset } });
2097+
if (positionMs > 0)
2098+
ob.Add("position_ms", positionMs);
20832099
return UploadDataAsync<ErrorResponse>(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT");
20842100
}
20852101

@@ -2434,6 +2450,26 @@ public T DownloadData<T>(string url) where T : BasicModel
24342450
return response.Item2;
24352451
}
24362452

2453+
/// <summary>
2454+
/// Retrieves whether request had a "TooManyRequests" error, and get the amount Spotify recommends waiting before another request.
2455+
/// </summary>
2456+
/// <param name="info">Info object to analyze.</param>
2457+
/// <returns>Seconds to wait before making another request. -1 if no error.</returns>
2458+
/// <remarks>AUTH NEEDED</remarks>
2459+
private int GetTooManyRequests(ResponseInfo info)
2460+
{
2461+
// 429 is "TooManyRequests" value specified in Spotify API
2462+
if (429 != (int)info.StatusCode)
2463+
{
2464+
return -1;
2465+
}
2466+
if (!int.TryParse(info.Headers.Get("Retry-After"), out var secondsToWait))
2467+
{
2468+
return -1;
2469+
}
2470+
return secondsToWait;
2471+
}
2472+
24372473
public async Task<T> DownloadDataAsync<T>(string url) where T : BasicModel
24382474
{
24392475
int triesLeft = RetryTimes + 1;
@@ -2442,15 +2478,30 @@ public async Task<T> DownloadDataAsync<T>(string url) where T : BasicModel
24422478
Tuple<ResponseInfo, T> response = null;
24432479
do
24442480
{
2445-
if (response != null) { await Task.Delay(RetryAfter).ConfigureAwait(false); }
2481+
if (response != null)
2482+
{
2483+
int msToWait = RetryAfter;
2484+
var secondsToWait = GetTooManyRequests(response.Item1);
2485+
if (secondsToWait > 0)
2486+
{
2487+
msToWait = secondsToWait * 1000;
2488+
}
2489+
await Task.Delay(msToWait).ConfigureAwait(false);
2490+
}
24462491
response = await DownloadDataAltAsync<T>(url).ConfigureAwait(false);
24472492

24482493
response.Item2.AddResponseInfo(response.Item1);
24492494
lastError = response.Item2.Error;
24502495

2451-
triesLeft -= 1;
2496+
if (TooManyRequestsConsumesARetry || GetTooManyRequests(response.Item1) == -1)
2497+
{
2498+
triesLeft -= 1;
2499+
}
24522500

2453-
} while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status));
2501+
} while (UseAutoRetry
2502+
&& triesLeft > 0
2503+
&& (GetTooManyRequests(response.Item1) != -1
2504+
|| (lastError != null && RetryErrorCodes.Contains(lastError.Status))));
24542505

24552506

24562507
return response.Item2;

0 commit comments

Comments
 (0)