Start refactoring for version 6

This commit is contained in:
Jonas Dellinger 2020-05-01 20:05:28 +02:00
parent 22d800d487
commit 2c4463529b
106 changed files with 1359 additions and 5930 deletions

18
.vscode/csharp.code-snippets vendored Normal file
View File

@ -0,0 +1,18 @@
{
"model": {
"scope": "csharp",
"prefix": "model",
"body": [
"namespace SpotifyAPI.Web",
"{",
" public class $1",
" {",
" public ${2:string} ${3:Name} { get; set; }",
"",
" $4",
" }",
"}"
],
"description": "Creates a new model"
}
}

View File

@ -2,6 +2,4 @@
"editor.detectIndentation": false,
"editor.insertSpaces": true,
"editor.tabSize": 2,
"csharpfixformat.style.braces.onSameLine": false,
"csharpfixformat.style.spaces.beforeParenthesis": false,
}

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFrameworks>netstandard2.1</TargetFrameworks>
<PackageId>SpotifyAPI.Web.Auth</PackageId>
<Title>SpotifyAPI.Web.Auth</Title>

View File

@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using SpotifyAPI.Web.Models;
namespace SpotifyAPI.Web.Tests
{
[TestFixture]
public class SpotifyWebAPITest
{
private static readonly string FixtureDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../fixtures/");
private Mock<IClient> _mock;
private SpotifyWebAPI _spotify;
[SetUp]
public void SetUp()
{
_mock = new Mock<IClient>();
_spotify = new SpotifyWebAPI
{
WebClient = _mock.Object,
UseAuth = false
};
}
private static T GetFixture<T>(string file)
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(Path.Combine(FixtureDir, file)));
}
private static bool ContainsValues(string str, params string[] values)
{
return values.All(str.Contains);
}
[Test]
public void ShouldGetPrivateProfile_WithoutAuth()
{
_spotify.UseAuth = false;
Assert.Throws<InvalidOperationException>(() => _spotify.GetPrivateProfile());
}
[Test]
public void ShouldGetPrivateProfile_WithAuth()
{
PrivateProfile profile = GetFixture<PrivateProfile>("private-user.json");
_mock.Setup(client => client.DownloadJson<PrivateProfile>(It.IsAny<string>(), It.IsAny<Dictionary<string, string>>()))
.Returns(new Tuple<ResponseInfo, PrivateProfile>(ResponseInfo.Empty, profile));
_spotify.UseAuth = true;
Assert.AreEqual(profile, _spotify.GetPrivateProfile());
_mock.Verify(client => client.DownloadJson<PrivateProfile>(
It.Is<string>(str => ContainsValues(str, "/me")),
It.IsNotNull<Dictionary<string, string>>()), Times.Exactly(1));
}
[Test]
public void ShouldGetPublicProfile()
{
PublicProfile profile = GetFixture<PublicProfile>("public-user.json");
_mock.Setup(client => client.DownloadJson<PublicProfile>(It.IsAny<string>(), It.IsAny<Dictionary<string, string>>()))
.Returns(new Tuple<ResponseInfo, PublicProfile>(ResponseInfo.Empty, profile));
_spotify.UseAuth = false;
Assert.AreEqual(profile, _spotify.GetPublicProfile("wizzler"));
_mock.Verify(client => client.DownloadJson<PublicProfile>(
It.Is<string>(str => ContainsValues(str, "/users/wizzler")),
It.Is<Dictionary<string, string>>(headers => headers.Count == 0)), Times.Exactly(1));
}
//Will add more tests once I decided if this is worth the effort (propably not?)
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Threading.Tasks;
using NUnit.Framework;
namespace SpotifyAPI.Web.Tests
{
[TestFixture]
public class Test
{
[Test]
public async Task Testing()
{
var token = "";
var spotify = new SpotifyClient(token);
var categories = await spotify.Browse.GetCategories();
var playlists = await spotify.Browse.GetCategoryPlaylists(categories.Categories.Items[0].Id);
}
}
}

View File

@ -0,0 +1,51 @@
using System.Collections.Generic;
using System;
using NUnit.Framework;
namespace SpotifyAPI.Web.Tests
{
[TestFixture]
public class URIExtensionTest
{
[Test]
public void ApplyParameters_WithoutExistingParameters()
{
var expected = "http://google.com/?hello=world&nice=day";
Uri uri = new Uri("http://google.com/");
var parameters = new Dictionary<string, string>
{
{ "hello", "world" },
{ "nice", "day" }
};
Assert.AreEqual(expected, uri.ApplyParameters(parameters).ToString());
}
[Test]
public void ApplyParameters_WithExistingParameters()
{
var expected = "http://google.com/?existing=paramter&hello=world&nice=day";
Uri uri = new Uri("http://google.com/?existing=paramter");
var parameters = new Dictionary<string, string>
{
{ "hello", "world" },
{ "nice", "day" }
};
Assert.AreEqual(expected, uri.ApplyParameters(parameters).ToString());
}
[Test]
public void ApplyParameters_HandlesEscape()
{
var expected = "http://google.com/?existing=paramter&hello=%26world++";
Uri uri = new Uri("http://google.com/?existing=paramter");
var parameters = new Dictionary<string, string>
{
{ "hello", "&world " },
};
Assert.AreEqual(expected, uri.ApplyParameters(parameters).ToString());
}
}
}

View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
using System;
using NUnit.Framework;
namespace SpotifyAPI.Web.Tests
{
[TestFixture]
public class URIParameterFormatProviderTest
{
[Test]
public void Format_NormalParameters()
{
var expected = "/users/wizzler";
var user = "wizzler";
var formatter = new URIParameterFormatProvider();
Func<FormattableString, string> func = (FormattableString str) => str.ToString(formatter);
Assert.AreEqual(expected, func($"/users/{user}"));
}
[Test]
public void Format_EscapedParameters()
{
var expected = "/users/++wizzler";
var user = " wizzler";
var formatter = new URIParameterFormatProvider();
Func<FormattableString, string> func = (FormattableString str) => str.ToString(formatter);
Assert.AreEqual(expected, func($"/users/{user}"));
}
}
}

View File

@ -1,25 +0,0 @@
{
"birthdate": "1937-06-01",
"country": "SE",
"display_name": "JM Wizzler",
"email": "email@example.com",
"external_urls": {
"spotify": "https://open.spotify.com/user/wizzler"
},
"followers" : {
"href" : null,
"total" : 3829
},
"href": "https://api.spotify.com/v1/users/wizzler",
"id": "wizzler",
"images": [
{
"height": 200,
"url": "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-frc3/t1.0-1/1970403_10152215092574354_1798272330_n.jpg",
"width": 200
}
],
"product": "premium",
"type": "user",
"uri": "spotify:user:wizzler"
}

View File

@ -1,9 +0,0 @@
{
"external_urls": {
"spotify": "https://open.spotify.com/user/wizzler"
},
"href": "https://api.spotify.com/v1/users/wizzler",
"id": "wizzler",
"type": "user",
"uri": "spotify:user:wizzler"
}

View File

@ -0,0 +1,16 @@
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web
{
public abstract class APIClient
{
public APIClient(IAPIConnector apiConnector)
{
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
API = apiConnector;
}
public IAPIConnector API { get; set; }
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
using SpotifyAPI.Web.Models;
using URLs = SpotifyAPI.Web.SpotifyUrls;
namespace SpotifyAPI.Web
{
public class BrowseClient : APIClient, IBrowseClient
{
public BrowseClient(IAPIConnector apiConnector) : base(apiConnector) { }
public Task<CategoriesResponse> GetCategories()
{
return API.Get<CategoriesResponse>(URLs.Categories());
}
public Task<CategoriesResponse> GetCategories(CategoriesRequest request)
{
Ensure.ArgumentNotNull(request, nameof(request));
return API.Get<CategoriesResponse>(URLs.Categories(), request.BuildQueryParams());
}
public Task<Category> GetCategory(string categoryId)
{
Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId));
return API.Get<Category>(URLs.Category(categoryId));
}
public Task<Category> GetCategory(string categoryId, CategoryRequest request)
{
Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId));
Ensure.ArgumentNotNull(request, nameof(request));
return API.Get<Category>(URLs.Category(categoryId), request.BuildQueryParams());
}
public Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId)
{
Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId));
return API.Get<CategoryPlaylistsResponse>(URLs.CategoryPlaylists(categoryId));
}
public Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId, CategoriesPlaylistsRequest request)
{
Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId));
Ensure.ArgumentNotNull(request, nameof(request));
return API.Get<CategoryPlaylistsResponse>(URLs.CategoryPlaylists(categoryId), request.BuildQueryParams());
}
}
}

View File

@ -0,0 +1,16 @@
using System.Threading.Tasks;
namespace SpotifyAPI.Web
{
public interface IBrowseClient
{
Task<CategoriesResponse> GetCategories();
Task<CategoriesResponse> GetCategories(CategoriesRequest request);
Task<Category> GetCategory(string categoryId);
Task<Category> GetCategory(string categoryId, CategoryRequest request);
Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId);
Task<CategoryPlaylistsResponse> GetCategoryPlaylists(string categoryId, CategoriesPlaylistsRequest request);
}
}

View File

@ -0,0 +1,9 @@
namespace SpotifyAPI.Web
{
interface ISpotifyClient
{
IUserProfileClient UserProfile { get; }
IBrowseClient Browse { get; }
}
}

View File

@ -0,0 +1,24 @@
using System.Threading.Tasks;
using SpotifyAPI.Web.Models;
namespace SpotifyAPI.Web
{
public interface IUserProfileClient
{
/// <summary>
/// Test
/// </summary>
/// <exception cref="APIUnauthorizedException">Thrown if the client is not authenticated.</exception>
/// <returns>A <see cref="PrivateUser"/></returns>
Task<PrivateUser> Current();
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <exception cref="APIUnauthorizedException">Thrown if the client is not authenticated.</exception>
/// <returns></returns>
Task<PublicUser> Get(string userId);
}
}

View File

@ -0,0 +1,30 @@
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web
{
public class SpotifyClient : ISpotifyClient
{
private IAPIConnector _apiConnector;
public SpotifyClient(string token, string tokenType = "Bearer") :
this(new TokenHeaderAuthenticator(token, tokenType))
{ }
public SpotifyClient(IAuthenticator authenticator) :
this(new APIConnector(SpotifyUrls.API_V1, authenticator))
{ }
public SpotifyClient(IAPIConnector apiConnector)
{
Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector));
_apiConnector = apiConnector;
UserProfile = new UserProfileClient(_apiConnector);
Browse = new BrowseClient(_apiConnector);
}
public IUserProfileClient UserProfile { get; }
public IBrowseClient Browse { get; }
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
using SpotifyAPI.Web.Models;
namespace SpotifyAPI.Web
{
public class UserProfileClient : APIClient, IUserProfileClient
{
public UserProfileClient(IAPIConnector apiConnector) : base(apiConnector) { }
public Task<PrivateUser> Current()
{
return API.Get<PrivateUser>(SpotifyUrls.Me());
}
public Task<PublicUser> Get(string userId)
{
Ensure.ArgumentNotNullOrEmptyString(userId, nameof(userId));
return API.Get<PublicUser>(SpotifyUrls.User(userId));
}
}
}

View File

@ -0,0 +1,43 @@
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web
{
[System.Serializable]
public class APIException : System.Exception
{
public APIException(IResponse response) : base(ParseAPIErrorMessage(response))
{
Ensure.ArgumentNotNull(response, nameof(response));
Response = response;
}
private static string ParseAPIErrorMessage(IResponse response)
{
var body = response.Body as string;
if (string.IsNullOrEmpty(body))
{
return null;
}
try
{
JObject bodyObject = JObject.Parse(body);
JObject error = bodyObject.Value<JObject>("error");
if (error != null)
{
return error.Value<string>("message");
}
}
catch (JsonReaderException)
{
return null;
}
return null;
}
public IResponse Response { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web
{
[System.Serializable]
public class APIUnauthorizedException : APIException
{
public APIUnauthorizedException(IResponse response) : base(response) { }
}
}

View File

@ -0,0 +1,155 @@
using System.Net.Http;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net;
namespace SpotifyAPI.Web.Http
{
public class APIConnector : IAPIConnector
{
private Uri _baseAddress;
private IAuthenticator _authenticator;
private IJSONSerializer _jsonSerializer;
private IHTTPClient _httpClient;
public APIConnector(Uri baseAddress, IAuthenticator authenticator) :
this(baseAddress, authenticator, new NewtonsoftJSONSerializer(), new NetHttpClient())
{ }
public APIConnector(Uri baseAddress, IAuthenticator authenticator, IJSONSerializer jsonSerializer, IHTTPClient httpClient)
{
_baseAddress = baseAddress;
_authenticator = authenticator;
_jsonSerializer = jsonSerializer;
_httpClient = httpClient;
}
public Task<T> Delete<T>(Uri uri)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Delete);
}
public Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Delete, parameters);
}
public Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters, object body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Delete, parameters, body);
}
public Task<T> Get<T>(Uri uri)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Get);
}
public Task<T> Get<T>(Uri uri, IDictionary<string, string> parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Get, parameters);
}
public Task<T> Post<T>(Uri uri)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Post);
}
public Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Post, parameters);
}
public Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Get, parameters, body);
}
public Task<T> Put<T>(Uri uri)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Put);
}
public Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Put, parameters);
}
public Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters, object body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
return SendAPIRequest<T>(uri, HttpMethod.Put, parameters, body);
}
public void SetRequestTimeout(TimeSpan timeout)
{
_httpClient.SetRequestTimeout(timeout);
}
private async Task<T> SendAPIRequest<T>(
Uri uri,
HttpMethod method,
IDictionary<string, string> parameters = null,
object body = null
)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(method, nameof(method));
var request = new Request
{
BaseAddress = _baseAddress,
ContentType = "application/json",
Parameters = parameters,
Endpoint = uri,
Method = method
};
_jsonSerializer.SerializeRequest(request);
await _authenticator.Apply(request).ConfigureAwait(false);
IResponse response = await _httpClient.DoRequest(request).ConfigureAwait(false);
ProcessErrors(response);
IAPIResponse<T> apiResponse = _jsonSerializer.DeserializeResponse<T>(response);
return apiResponse.Body;
}
private void ProcessErrors(IResponse response)
{
Ensure.ArgumentNotNull(response, nameof(response));
if ((int)response.StatusCode >= 200 && (int)response.StatusCode < 400)
{
return;
}
switch (response.StatusCode)
{
case HttpStatusCode.Unauthorized:
throw new APIUnauthorizedException(response);
default:
throw new APIException(response);
}
}
}
}

View File

@ -0,0 +1,17 @@
namespace SpotifyAPI.Web.Http
{
public class APIResponse<T> : IAPIResponse<T>
{
public APIResponse(IResponse response, T body = default(T))
{
Ensure.ArgumentNotNull(response, nameof(response));
Body = body;
Response = response;
}
public T Body { get; set; }
public IResponse Response { get; set; }
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SpotifyAPI.Web.Http
{
public interface IAPIConnector
{
// IAuthenticator Authenticator { get; }
// IJSONSerializer JSONSerializer { get; }
// IHTTPClient HTTPClient { get; }
Task<T> Get<T>(Uri uri);
Task<T> Get<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Post<T>(Uri uri);
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Post<T>(Uri uri, IDictionary<string, string> parameters, object body);
Task<T> Put<T>(Uri uri);
Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Put<T>(Uri uri, IDictionary<string, string> parameters, object body);
Task<T> Delete<T>(Uri uri);
Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters);
Task<T> Delete<T>(Uri uri, IDictionary<string, string> parameters, object body);
void SetRequestTimeout(TimeSpan timeout);
}
}

View File

@ -0,0 +1,9 @@
namespace SpotifyAPI.Web.Http
{
public interface IAPIResponse<out T>
{
T Body { get; }
IResponse Response { get; }
}
}

View File

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace SpotifyAPI.Web.Http
{
public interface IAuthenticator
{
Task Apply(IRequest request);
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Threading.Tasks;
namespace SpotifyAPI.Web.Http
{
public interface IHTTPClient : IDisposable
{
Task<IResponse> DoRequest(IRequest request);
void SetRequestTimeout(TimeSpan timeout);
}
}

View File

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace SpotifyAPI.Web.Http
{
public interface IJSONSerializer
{
void SerializeRequest(IRequest request);
IAPIResponse<T> DeserializeResponse<T>(IResponse response);
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
namespace SpotifyAPI.Web.Http
{
public interface IRequest
{
Uri BaseAddress { get; }
Uri Endpoint { get; }
IDictionary<string, string> Headers { get; }
IDictionary<string, string> Parameters { get; }
HttpMethod Method { get; }
string ContentType { get; }
object Body { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Net;
namespace SpotifyAPI.Web.Http
{
public interface IResponse
{
object Body { get; }
IReadOnlyDictionary<string, string> Headers { get; }
HttpStatusCode StatusCode { get; }
string ContentType { get; }
}
}

View File

@ -0,0 +1,98 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace SpotifyAPI.Web.Http
{
public class NetHttpClient : IHTTPClient
{
private HttpClient _httpClient;
public NetHttpClient()
{
_httpClient = new HttpClient();
}
public async Task<IResponse> DoRequest(IRequest request)
{
Ensure.ArgumentNotNull(request, nameof(request));
using (HttpRequestMessage requestMsg = BuildRequestMessage(request))
{
var responseMsg = await _httpClient
.SendAsync(requestMsg, HttpCompletionOption.ResponseContentRead)
.ConfigureAwait(false);
return await BuildResponse(responseMsg).ConfigureAwait(false);
}
}
private async Task<IResponse> BuildResponse(HttpResponseMessage responseMsg)
{
Ensure.ArgumentNotNull(responseMsg, nameof(responseMsg));
// We only support text stuff for now
using (var content = responseMsg.Content)
{
var headers = responseMsg.Headers.ToDictionary(header => header.Key, header => header.Value.First());
var body = await responseMsg.Content.ReadAsStringAsync().ConfigureAwait(false);
var contentType = content.Headers?.ContentType?.MediaType;
return new Response(headers)
{
ContentType = contentType,
StatusCode = responseMsg.StatusCode,
Body = body
};
}
}
private HttpRequestMessage BuildRequestMessage(IRequest request)
{
Ensure.ArgumentNotNull(request, nameof(request));
var fullUri = new Uri(request.BaseAddress, request.Endpoint).ApplyParameters(request.Parameters);
var requestMsg = new HttpRequestMessage(request.Method, fullUri);
foreach (var header in request.Headers)
{
requestMsg.Headers.Add(header.Key, header.Value);
}
switch (request.Body)
{
case HttpContent body:
requestMsg.Content = body;
break;
case string body:
requestMsg.Content = new StringContent(body);
break;
case Stream body:
requestMsg.Content = new StreamContent(body);
break;
}
return requestMsg;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
_httpClient?.Dispose();
}
}
public void SetRequestTimeout(TimeSpan timeout)
{
_httpClient.Timeout = timeout;
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace SpotifyAPI.Web.Http
{
public class NewtonsoftJSONSerializer : IJSONSerializer
{
JsonSerializerSettings _serializerSettings;
public NewtonsoftJSONSerializer()
{
_serializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
};
}
public IAPIResponse<T> DeserializeResponse<T>(IResponse response)
{
Ensure.ArgumentNotNull(response, nameof(response));
if (response.ContentType?.Equals("application/json", StringComparison.Ordinal) is true)
{
var body = JsonConvert.DeserializeObject<T>(response.Body as string, _serializerSettings);
return new APIResponse<T>(response, body);
}
return new APIResponse<T>(response);
}
public void SerializeRequest(IRequest request)
{
Ensure.ArgumentNotNull(request, nameof(request));
if (request.Body is string || request.Body is Stream || request.Body is HttpContent || request.Body is null)
{
return;
}
request.Body = JsonConvert.SerializeObject(request.Body, _serializerSettings);
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
namespace SpotifyAPI.Web.Http
{
class Request : IRequest
{
public Request()
{
Headers = new Dictionary<string, string>();
Parameters = new Dictionary<string, string>();
}
public Uri BaseAddress { get; set; }
public Uri Endpoint { get; set; }
public IDictionary<string, string> Headers { get; set; }
public IDictionary<string, string> Parameters { get; set; }
public HttpMethod Method { get; set; }
public string ContentType { get; set; }
public object Body { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
namespace SpotifyAPI.Web.Http
{
public class Response : IResponse
{
public Response(IDictionary<string, string> headers)
{
Ensure.ArgumentNotNull(headers, nameof(headers));
Headers = new ReadOnlyDictionary<string, string>(headers);
}
public object Body { get; set; }
public IReadOnlyDictionary<string, string> Headers { get; set; }
public HttpStatusCode StatusCode { get; set; }
public string ContentType { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System.Threading.Tasks;
namespace SpotifyAPI.Web.Http
{
class TokenHeaderAuthenticator : IAuthenticator
{
public TokenHeaderAuthenticator(string token, string tokenType)
{
Token = token;
TokenType = tokenType;
}
public string Token { get; set; }
public string TokenType { get; set; }
public Task Apply(IRequest request)
{
request.Headers["Authorization"] = $"{TokenType} {Token}";
return Task.CompletedTask;
}
}
}

View File

@ -1,125 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using SpotifyAPI.Web.Models;
namespace SpotifyAPI.Web
{
public interface IClient : IDisposable
{
JsonSerializerSettings JsonSettings { get; set; }
/// <summary>
/// Downloads data from an URL and returns it
/// </summary>
/// <param name="url">An URL</param>
/// <param name="headers"></param>
/// <returns></returns>
Tuple<ResponseInfo, string> Download(string url, Dictionary<string, string> headers = null);
/// <summary>
/// Downloads data async from an URL and returns it
/// </summary>
/// <param name="url"></param>
/// <param name="headers"></param>
/// <returns></returns>
Task<Tuple<ResponseInfo, string>> DownloadAsync(string url, Dictionary<string, string> headers = null);
/// <summary>
/// Downloads data from an URL and returns it
/// </summary>
/// <param name="url">An URL</param>
/// <param name="headers"></param>
/// <returns></returns>
Tuple<ResponseInfo, byte[]> DownloadRaw(string url, Dictionary<string, string> headers = null);
/// <summary>
/// Downloads data async from an URL and returns it
/// </summary>
/// <param name="url"></param>
/// <param name="headers"></param>
/// <returns></returns>
Task<Tuple<ResponseInfo, byte[]>> DownloadRawAsync(string url, Dictionary<string, string> headers = null);
/// <summary>
/// Downloads data from an URL and converts it to an object
/// </summary>
/// <typeparam name="T">The Type which the object gets converted to</typeparam>
/// <param name="url">An URL</param>
/// <param name="headers"></param>
/// <returns></returns>
Tuple<ResponseInfo, T> DownloadJson<T>(string url, Dictionary<string, string> headers = null);
/// <summary>
/// Downloads data async from an URL and converts it to an object
/// </summary>
/// <typeparam name="T">The Type which the object gets converted to</typeparam>
/// <param name="url">An URL</param>
/// <param name="headers"></param>
/// <returns></returns>
Task<Tuple<ResponseInfo, T>> DownloadJsonAsync<T>(string url, Dictionary<string, string> headers = null);
/// <summary>
/// Uploads data from an URL and returns the response
/// </summary>
/// <param name="url">An URL</param>
/// <param name="body">The Body-Data (most likely a JSON String)</param>
/// <param name="method">The Upload-method (POST,DELETE,PUT)</param>
/// <param name="headers"></param>
/// <returns></returns>
Tuple<ResponseInfo, string> Upload(string url, string body, string method, Dictionary<string, string> headers = null);
/// <summary>
/// Uploads data async from an URL and returns the response
/// </summary>
/// <param name="url">An URL</param>
/// <param name="body">The Body-Data (most likely a JSON String)</param>
/// <param name="method">The Upload-method (POST,DELETE,PUT)</param>
/// <param name="headers"></param>
/// <returns></returns>
Task<Tuple<ResponseInfo, string>> UploadAsync(string url, string body, string method, Dictionary<string, string> headers = null);
/// <summary>
/// Uploads data from an URL and returns the response
/// </summary>
/// <param name="url">An URL</param>
/// <param name="body">The Body-Data (most likely a JSON String)</param>
/// <param name="method">The Upload-method (POST,DELETE,PUT)</param>
/// <param name="headers"></param>
/// <returns></returns>
Tuple<ResponseInfo, byte[]> UploadRaw(string url, string body, string method, Dictionary<string, string> headers = null);
/// <summary>
/// Uploads data async from an URL and returns the response
/// </summary>
/// <param name="url">An URL</param>
/// <param name="body">The Body-Data (most likely a JSON String)</param>
/// <param name="method">The Upload-method (POST,DELETE,PUT)</param>
/// <param name="headers"></param>
/// <returns></returns>
Task<Tuple<ResponseInfo, byte[]>> UploadRawAsync(string url, string body, string method, Dictionary<string, string> headers = null);
/// <summary>
/// Uploads data from an URL and converts the response to an object
/// </summary>
/// <typeparam name="T">The Type which the object gets converted to</typeparam>
/// <param name="url">An URL</param>
/// <param name="body">The Body-Data (most likely a JSON String)</param>
/// <param name="method">The Upload-method (POST,DELETE,PUT)</param>
/// <param name="headers"></param>
/// <returns></returns>
Tuple<ResponseInfo, T> UploadJson<T>(string url, string body, string method, Dictionary<string, string> headers = null);
/// <summary>
/// Uploads data async from an URL and converts the response to an object
/// </summary>
/// <typeparam name="T">The Type which the object gets converted to</typeparam>
/// <param name="url">An URL</param>
/// <param name="body">The Body-Data (most likely a JSON String)</param>
/// <param name="method">The Upload-method (POST,DELETE,PUT)</param>
/// <param name="headers"></param>
/// <returns></returns>
Task<Tuple<ResponseInfo, T>> UploadJsonAsync<T>(string url, string body, string method, Dictionary<string, string> headers = null);
}
}

View File

@ -1,28 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AnalysisMeta
{
[JsonProperty("analyzer_platform")]
public string AnalyzerVersion { get; set; }
[JsonProperty("platform")]
public string Platform { get; set; }
[JsonProperty("status_code")]
public int StatusCode { get; set; }
[JsonProperty("detailed_status")]
public string DetailedStatus { get; set; }
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
[JsonProperty("analysis_time")]
public double AnalysisTime { get; set; }
[JsonProperty("input_process")]
public string InputProcess { get; set; }
}
}

View File

@ -1,43 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AnalysisSection
{
[JsonProperty("start")]
public double Start { get; set; }
[JsonProperty("duration")]
public double Duration { get; set; }
[JsonProperty("confidence")]
public double Confidence { get; set; }
[JsonProperty("loudness")]
public double Loudness { get; set; }
[JsonProperty("tempo")]
public double Tempo { get; set; }
[JsonProperty("tempo_confidence")]
public double TempoConfidence { get; set; }
[JsonProperty("key")]
public int Key { get; set; }
[JsonProperty("key_confidence")]
public double KeyConfidence { get; set; }
[JsonProperty("mode")]
public int Mode { get; set; }
[JsonProperty("mode_confidence")]
public double ModeConfidence { get; set; }
[JsonProperty("time_signature")]
public int TimeSignature { get; set; }
[JsonProperty("time_signature_confidence")]
public double TimeSignatureConfidence { get; set; }
}
}

View File

@ -1,35 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AnalysisSegment
{
[JsonProperty("start")]
public double Start { get; set; }
[JsonProperty("duration")]
public double Duration { get; set; }
[JsonProperty("confidence")]
public double Confidence { get; set; }
[JsonProperty("loudness_start")]
public double LoudnessStart { get; set; }
[JsonProperty("loudness_max_time")]
public double LoudnessMaxTime { get; set; }
[JsonProperty("loudness_max")]
public double LoudnessMax { get; set; }
[JsonProperty("loudness_end")]
public double LoudnessEnd { get; set; }
[JsonProperty("pitches")]
public List<double> Pitches { get; set; }
[JsonProperty("timbre")]
public List<double> Timbre { get; set; }
}
}

View File

@ -1,16 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AnalysisTimeSlice
{
[JsonProperty("start")]
public double Start { get; set; }
[JsonProperty("duration")]
public double Duration { get; set; }
[JsonProperty("confidence")]
public double Confidence { get; set; }
}
}

View File

@ -1,86 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AnalysisTrack
{
[JsonProperty("num_samples")]
public int NumSamples { get; set; }
[JsonProperty("duration")]
public double Duration { get; set; }
[JsonProperty("sample_md5")]
public string SampleMD5 { get; set; }
[JsonProperty("offset_seconds")]
public double OffsetSeconds { get; set; }
[JsonProperty("window_seconds")]
public double WindowSeconds { get; set; }
[JsonProperty("analysis_sample_rate")]
public int AnalysisSampleRate { get; set; }
[JsonProperty("analysis_channels")]
public int AnalysisChannels { get; set; }
[JsonProperty("end_of_fade_in")]
public double EndOfFadeIn { get; set; }
[JsonProperty("start_of_fade_out")]
public double StartOfFadeOut { get; set; }
[JsonProperty("loudness")]
public double Loudness { get; set; }
[JsonProperty("tempo")]
public double Tempo { get; set; }
[JsonProperty("tempo_confidence")]
public double TempoConfidence { get; set; }
[JsonProperty("time_signature")]
public double TimeSignature { get; set; }
[JsonProperty("time_signature_confidence")]
public double TimeSignatureConfidence { get; set; }
[JsonProperty("key")]
public int Key { get; set; }
[JsonProperty("key_confidence")]
public double KeyConfidence { get; set; }
[JsonProperty("mode")]
public int Mode { get; set; }
[JsonProperty("mode_confidence")]
public double ModeConfidence { get; set; }
[JsonProperty("codestring")]
public string Codestring { get; set; }
[JsonProperty("code_version")]
public double CodeVersion { get; set; }
[JsonProperty("echoprintstring")]
public string Echoprintstring { get; set; }
[JsonProperty("echoprint_version")]
public double EchoprintVersion { get; set; }
[JsonProperty("synchstring")]
public string Synchstring { get; set; }
[JsonProperty("synch_version")]
public double SynchVersion { get; set; }
[JsonProperty("rhythmstring")]
public string Rhythmstring { get; set; }
[JsonProperty("rhythm_version")]
public double RhythmVersion { get; set; }
}
}

View File

@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web.Models
{
public class ListResponse<T> : BasicModel
{
public List<T> List { get; set; }
}
}

View File

@ -1,29 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AudioAnalysis : BasicModel
{
[JsonProperty("bars")]
public List<AnalysisTimeSlice> Bars { get; set; }
[JsonProperty("beats")]
public List<AnalysisTimeSlice> Beats { get; set; }
[JsonProperty("meta")]
public AnalysisMeta Meta { get; set; }
[JsonProperty("sections")]
public List<AnalysisSection> Sections { get; set; }
[JsonProperty("segments")]
public List<AnalysisSegment> Segments { get; set; }
[JsonProperty("tatums")]
public List<AnalysisTimeSlice> Tatums { get; set; }
[JsonProperty("track")]
public AnalysisTrack Track { get; set; }
}
}

View File

@ -1,61 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AudioFeatures : BasicModel
{
[JsonProperty("acousticness")]
public float Acousticness { get; set; }
[JsonProperty("analysis_url")]
public string AnalysisUrl { get; set; }
[JsonProperty("danceability")]
public float Danceability { get; set; }
[JsonProperty("duration_ms")]
public int DurationMs { get; set; }
[JsonProperty("energy")]
public float Energy { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("instrumentalness")]
public float Instrumentalness { get; set; }
[JsonProperty("key")]
public int Key { get; set; }
[JsonProperty("liveness")]
public float Liveness { get; set; }
[JsonProperty("loudness")]
public float Loudness { get; set; }
[JsonProperty("mode")]
public int Mode { get; set; }
[JsonProperty("speechiness")]
public float Speechiness { get; set; }
[JsonProperty("tempo")]
public float Tempo { get; set; }
[JsonProperty("time_signature")]
public int TimeSignature { get; set; }
[JsonProperty("track_href")]
public string TrackHref { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
[JsonProperty("valence")]
public float Valence { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AvailabeDevices : BasicModel
{
[JsonProperty("devices")]
public List<Device> Devices { get; set; }
}
}

View File

@ -1,23 +0,0 @@
using System.Net;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public abstract class BasicModel
{
[JsonProperty("error")]
public Error Error { get; set; }
private ResponseInfo _info;
public bool HasError() => Error != null;
internal void AddResponseInfo(ResponseInfo info) => _info = info;
public string Header(string key) => _info.Headers?.Get(key);
public WebHeaderCollection Headers() => _info.Headers;
public HttpStatusCode StatusCode() => _info.StatusCode;
}
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Category : BasicModel
{
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("icons")]
public List<Image> Icons { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class CategoryList : BasicModel
{
[JsonProperty("categories")]
public Paging<Category> Categories { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class CategoryPlaylist : BasicModel
{
[JsonProperty("playlists")]
public Paging<SimplePlaylist> Playlists { get; set; }
}
}

View File

@ -0,0 +1,45 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace SpotifyAPI.Web
{
public class PlaylistElementConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var token = JToken.ReadFrom(reader);
if (token.Type == JTokenType.Null)
{
return null;
}
var type = token["type"].Value<string>();
if (type == "track")
{
var obj = new FullTrack();
serializer.Populate(token.CreateReader(), obj);
return obj;
}
else if (type == "episode")
{
var obj = new FullEpisode();
serializer.Populate(token.CreateReader(), obj);
return obj;
}
else
{
throw new Exception($"Received unkown playlist element type: {type}");
}
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotSupportedException();
}
}
}

View File

@ -1,31 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class CursorPaging<T> : BasicModel
{
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("items")]
public List<T> Items { get; set; }
[JsonProperty("limit")]
public int Limit { get; set; }
[JsonProperty("next")]
public string Next { get; set; }
[JsonProperty("cursors")]
public Cursor Cursors { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
public bool HasNext()
{
return !string.IsNullOrEmpty(Next);
}
}
}

View File

@ -1,25 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Device
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("is_active")]
public bool IsActive { get; set; }
[JsonProperty("is_restricted")]
public bool IsRestricted { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("volume_percent")]
public int VolumePercent { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class FeaturedPlaylists : BasicModel
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("playlists")]
public Paging<SimplePlaylist> Playlists { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class FollowedArtists : BasicModel
{
[JsonProperty("artists")]
public CursorPaging<FullArtist> Artists { get; set; }
}
}

View File

@ -1,68 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class FullAlbum : BasicModel
{
[JsonProperty("album_type")]
public string AlbumType { get; set; }
[JsonProperty("artists")]
public List<SimpleArtist> Artists { get; set; }
[JsonProperty("available_markets")]
public List<string> AvailableMarkets { get; set; }
[JsonProperty("copyrights")]
public List<Copyright> Copyrights { get; set; }
[JsonProperty("external_ids")]
public Dictionary<string, string> ExternalIds { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("genres")]
public List<string> Genres { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("popularity")]
public int Popularity { get; set; }
[JsonProperty("release_date")]
public string ReleaseDate { get; set; }
[JsonProperty("release_date_precision")]
public string ReleaseDatePrecision { get; set; }
[JsonProperty("tracks")]
public Paging<SimpleTrack> Tracks { get; set; }
[JsonProperty("restrictions")]
public Dictionary<string, string> Restrictions { get; set; }
[JsonProperty("total_tracks")]
public int TotalTracks { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,38 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class FullArtist : BasicModel
{
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("followers")]
public Followers Followers { get; set; }
[JsonProperty("genres")]
public List<string> Genres { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("popularity")]
public int Popularity { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,50 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class FullPlaylist : BasicModel
{
[JsonProperty("collaborative")]
public bool Collaborative { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("followers")]
public Followers Followers { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("owner")]
public PublicProfile Owner { get; set; }
[JsonProperty("public")]
public bool Public { get; set; }
[JsonProperty("snapshot_id")]
public string SnapshotId { get; set; }
[JsonProperty("tracks")]
public Paging<PlaylistTrack> Tracks { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,71 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class FullTrack : BasicModel
{
[JsonProperty("album")]
public SimpleAlbum Album { get; set; }
[JsonProperty("artists")]
public List<SimpleArtist> Artists { get; set; }
[JsonProperty("available_markets")]
public List<string> AvailableMarkets { get; set; }
[JsonProperty("disc_number")]
public int DiscNumber { get; set; }
[JsonProperty("duration_ms")]
public int DurationMs { get; set; }
[JsonProperty("explicit")]
public bool Explicit { get; set; }
[JsonProperty("external_ids")]
public Dictionary<string, string> ExternalIds { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternUrls { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("popularity")]
public int Popularity { get; set; }
[JsonProperty("preview_url")]
public string PreviewUrl { get; set; }
[JsonProperty("track_number")]
public int TrackNumber { get; set; }
[JsonProperty("restrictions")]
public Dictionary<string, string> Restrictions { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
/// <summary>
/// Only filled when the "market"-parameter was supplied!
/// </summary>
[JsonProperty("is_playable")]
public bool? IsPlayable { get; set; }
/// <summary>
/// Only filled when the "market"-parameter was supplied!
/// </summary>
[JsonProperty("linked_from")]
public LinkedFrom LinkedFrom { get; set; }
}
}

View File

@ -1,158 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Image
{
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("width")]
public int Width { get; set; }
[JsonProperty("height")]
public int Height { get; set; }
}
public class ErrorResponse : BasicModel
{ }
public class Error
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
public class PlaylistTrackCollection
{
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
public class Followers
{
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
public class PlaylistTrack
{
[JsonProperty("added_at")]
public DateTime AddedAt { get; set; }
[JsonProperty("added_by")]
public PublicProfile AddedBy { get; set; }
[JsonProperty("track")]
public FullTrack Track { get; set; }
[JsonProperty("is_local")]
public bool IsLocal { get; set; }
}
public class DeleteTrackUri
{
/// <summary>
/// Delete-Track Wrapper
/// </summary>
/// <param name="uri">An Spotify-URI</param>
/// <param name="positions">Optional positions</param>
public DeleteTrackUri(string uri, params int[] positions)
{
Positions = positions.ToList();
Uri = uri;
}
[JsonProperty("uri")]
public string Uri { get; set; }
[JsonProperty("positions")]
public List<int> Positions { get; set; }
public bool ShouldSerializePositions()
{
return Positions.Count > 0;
}
}
public class Copyright
{
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
public class LinkedFrom
{
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
public class SavedTrack
{
[JsonProperty("added_at")]
public DateTime AddedAt { get; set; }
[JsonProperty("track")]
public FullTrack Track { get; set; }
}
public class SavedAlbum
{
[JsonProperty("added_at")]
public DateTime AddedAt { get; set; }
[JsonProperty("album")]
public FullAlbum Album { get; set; }
}
public class Cursor
{
[JsonProperty("after")]
public string After { get; set; }
[JsonProperty("before")]
public string Before { get; set; }
}
public class Context
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class NewAlbumReleases : BasicModel
{
[JsonProperty("albums")]
public Paging<SimpleAlbum> Albums { get; set; }
}
}

View File

@ -1,39 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Paging<T> : BasicModel
{
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("items")]
public List<T> Items { get; set; }
[JsonProperty("limit")]
public int Limit { get; set; }
[JsonProperty("next")]
public string Next { get; set; }
[JsonProperty("offset")]
public int Offset { get; set; }
[JsonProperty("previous")]
public string Previous { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
public bool HasNextPage()
{
return Next != null;
}
public bool HasPreviousPage()
{
return Previous != null;
}
}
}

View File

@ -1,17 +0,0 @@
using System;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class PlayHistory : BasicModel
{
[JsonProperty("track")]
public SimpleTrack Track { get; set; }
[JsonProperty("played_at")]
public DateTime PlayedAt { get; set; }
[JsonProperty("context")]
public Context Context { get; set; }
}
}

View File

@ -1,38 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SpotifyAPI.Web.Enums;
namespace SpotifyAPI.Web.Models
{
public class PlaybackContext : BasicModel
{
[JsonProperty("device")]
public Device Device { get; set; }
[JsonProperty("repeat_state")]
[JsonConverter(typeof(StringEnumConverter))]
public RepeatState RepeatState { get; set; }
[JsonProperty("shuffle_state")]
public bool ShuffleState { get; set; }
[JsonProperty("context")]
public Context Context { get; set; }
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
[JsonProperty("progress_ms")]
public int ProgressMs { get; set; }
[JsonProperty("is_playing")]
public bool IsPlaying { get; set; }
[JsonProperty("item")]
public FullTrack Item { get; set; }
[JsonProperty("currently_playing_type")]
[JsonConverter(typeof(StringEnumConverter))]
public TrackType CurrentlyPlayingType { get; set; }
}
}

View File

@ -1,44 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class PrivateProfile : BasicModel
{
[JsonProperty("birthdate")]
public string Birthdate { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("display_name")]
public string DisplayName { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("followers")]
public Followers Followers { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("product")]
public string Product { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,25 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class RecommendationSeed
{
[JsonProperty("afterFilteringSize")]
public int AfterFilteringSize { get; set; }
[JsonProperty("afterRelinkingSize")]
public int AfterRelinkingSize { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("initialPoolSize")]
public int InitialPoolSize { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class RecommendationSeedGenres : BasicModel
{
[JsonProperty("genres")]
public List<string> Genres { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Recommendations : BasicModel
{
[JsonProperty("seeds")]
public List<RecommendationSeed> Seeds { get; set; }
[JsonProperty("tracks")]
public List<SimpleTrack> Tracks { get; set; }
}
}

View File

@ -0,0 +1,17 @@
namespace SpotifyAPI.Web
{
public class CategoriesRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
[QueryParam("locale")]
public string Locale { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
[QueryParam("offset")]
public int? Offset { get; set; }
}
}

View File

@ -0,0 +1,14 @@
namespace SpotifyAPI.Web
{
public class CategoriesPlaylistsRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
[QueryParam("limit")]
public int? Limit { get; set; }
[QueryParam("offset")]
public int? Offset { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace SpotifyAPI.Web
{
public class CategoryRequest : RequestParams
{
[QueryParam("country")]
public string Country { get; set; }
[QueryParam("locale")]
public string Locale { get; set; }
}
}

View File

@ -0,0 +1,44 @@
using System.Reflection;
using System;
using System.Linq;
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public abstract class RequestParams
{
public Dictionary<string, string> BuildQueryParams()
{
var queryProps = this.GetType().GetProperties()
.Where(prop => prop.GetCustomAttributes(typeof(QueryParamAttribute), true).Length > 0);
var queryParams = new Dictionary<string, string>();
foreach (var prop in queryProps)
{
var attribute = prop.GetCustomAttribute(typeof(QueryParamAttribute)) as QueryParamAttribute;
var value = prop.GetValue(this);
if (value != null)
{
queryParams.Add(attribute.Key ?? prop.Name, value.ToString());
}
}
return queryParams;
}
}
public class QueryParamAttribute : Attribute
{
public string Key { get; set; }
public QueryParamAttribute() { }
public QueryParamAttribute(string key)
{
Key = key;
}
}
public class BodyParamAttribute : Attribute
{
public BodyParamAttribute() { }
}
}

View File

@ -0,0 +1,7 @@
namespace SpotifyAPI.Web
{
public class CategoriesResponse
{
public Paging<Category> Categories { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class Category
{
public string Href { get; set; }
public List<Image> Icons { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace SpotifyAPI.Web
{
public class CategoryPlaylistsResponse
{
public Paging<SimplePlaylist> Playlists { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace SpotifyAPI.Web
{
public class Copyright
{
public string Text { get; set; }
public string Type { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace SpotifyAPI.Web
{
public class Followers
{
public string Href { get; set; }
public int Total { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class FullEpisode : IPlaylistElement
{
public string AudioPreviewUrl { get; set; }
public string Description { get; set; }
public int DurationMs { get; set; }
public bool Explicit { get; set; }
public Dictionary<string, string> ExternalUrls { get; set; }
public string Href { get; set; }
public string Id { get; set; }
public List<Image> Images { get; set; }
public bool IsExternallyHosted { get; set; }
public bool IsPlayable { get; set; }
public List<string> Languages { get; set; }
public string Name { get; set; }
public string ReleaseDate { get; set; }
public string ReleaseDatePrecision { get; set; }
public ResumePoint ResumePoint { get; set; }
public SimpleShow Show { get; set; }
public PlaylistElementType Type { get; set; }
public string Uri { get; set; }
}
}

View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class FullTrack : IPlaylistElement
{
public SimpleAlbum Album { get; set; }
public List<SimpleArtist> Artists { get; set; }
public List<string> AvailableMarkets { get; set; }
public int DiscNumber { get; set; }
public int DurationMs { get; set; }
public bool Explicit { get; set; }
public Dictionary<string, string> ExternalIds { get; set; }
public Dictionary<string, string> ExternalUrls { get; set; }
public string Href { get; set; }
public string Id { get; set; }
public bool IsPlayable { get; set; }
public LinkedTrack LinkedFrom { get; set; }
public Dictionary<string, string> Restrictions { get; set; }
public string Name { get; set; }
public int Popularity { get; set; }
public string PreviewUrl { get; set; }
public int TrackNumber { get; set; }
public PlaylistElementType Type { get; set; }
public string Uri { get; set; }
public bool IsLocal { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace SpotifyAPI.Web
{
public class Image
{
public int Height { get; set; }
public int Width { get; set; }
public string Url { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace SpotifyAPI.Web
{
public enum PlaylistElementType
{
Track,
Episode
}
public interface IPlaylistElement
{
[JsonConverter(typeof(StringEnumConverter))]
public PlaylistElementType Type { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class LinkedTrack
{
public Dictionary<string, string> ExternalUrls { get; set; }
public string Href { get; set; }
public string Id { get; set; }
public string Type { get; set; }
public string uri { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class Paging<T>
{
public string Href { get; set; }
public List<T> Items { get; set; }
public int Limit { get; set; }
public string Next { get; set; }
public int Offset { get; set; }
public string Previous { get; set; }
public int Total { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace SpotifyAPI.Web
{
public class PlaylistTrack
{
public DateTime? AddedAt { get; set; }
public PublicUser AddedBy { get; set; }
public bool IsLocal { get; set; }
public IPlaylistElement Track { get; set; }
}
}

View File

@ -3,30 +3,18 @@ using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class PublicProfile : BasicModel
public class PrivateUser
{
[JsonProperty("display_name")]
public string Country { get; set; }
public string DisplayName { get; set; }
[JsonProperty("external_urls")]
public string Email { get; set; }
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("followers")]
public Followers Followers { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("type")]
public string Product { get; set; }
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web
{
public class PublicUser
{
public string DisplayName { get; set; }
public Dictionary<string, string> ExternalUrls { get; set; }
public Followers Followers { get; set; }
public string Href { get; set; }
public string Id { get; set; }
public List<Image> Images { get; set; }
public string Type { get; set; }
public string Uri { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace SpotifyAPI.Web
{
public class ResumePoint
{
public bool FullyPlayed { get; set; }
public int ResumePositionMs { get; set; }
}
}

View File

@ -1,53 +1,22 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
namespace SpotifyAPI.Web
{
public class SimpleAlbum : BasicModel
public class SimpleAlbum
{
[JsonProperty("album_group")]
public string AlbumGroup { get; set; }
[JsonProperty("album_type")]
public string AlbumType { get; set; }
[JsonProperty("artists")]
public List<SimpleArtist> Artists { get; set; }
[JsonProperty("available_markets")]
public List<string> AvailableMarkets { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("release_date")]
public string ReleaseDate { get; set; }
[JsonProperty("release_date_precision")]
public string ReleaseDatePrecision { get; set; }
[JsonProperty("restrictions")]
public Dictionary<string, string> Restrictions { get; set; }
[JsonProperty("total_tracks")]
public int TotalTracks { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,26 +1,13 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
namespace SpotifyAPI.Web
{
public class SimpleArtist : BasicModel
public class SimpleArtist
{
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
/// <summary>
/// <a href="https://developer.spotify.com/documentation/web-api/reference/object-model/#playlist-object-simplified">Docs</a>
/// </summary>
public class SimplePlaylist
{
public bool Collaborative { get; set; }
public string Description { get; set; }
public Dictionary<string, string> ExternalUrls { get; set; }
public string Href { get; set; }
public string Id { get; set; }
public List<Image> Images { get; set; }
public string Name { get; set; }
public PublicUser Owner { get; set; }
public bool? Public { get; set; }
public string SnapshotId { get; set; }
public Paging<PlaylistTrack> Tracks { get; set; }
public string Type { get; set; }
public string Uri { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace SpotifyAPI.Web
{
public class SimpleShow
{
public List<string> AvailableMarkets { get; set; }
public Copyright Copyright { get; set; }
public string Description { get; set; }
public bool Explicit { get; set; }
public Dictionary<string, string> ExternalUrls { get; set; }
public string Href { get; set; }
public string Id { get; set; }
public List<Image> Images { get; set; }
public bool IsExternallyHosted { get; set; }
public List<string> Languages { get; set; }
public string MediaType { get; set; }
public string Name { get; set; }
public string Publisher { get; set; }
public string Type { get; set; }
public string Uri { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System.Net;
namespace SpotifyAPI.Web.Models
{
public class ResponseInfo
{
public WebHeaderCollection Headers { get; set; }
public HttpStatusCode StatusCode { get; set; }
public static readonly ResponseInfo Empty = new ResponseInfo();
}
}

View File

@ -1,19 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SearchItem : BasicModel
{
[JsonProperty("artists")]
public Paging<FullArtist> Artists { get; set; }
[JsonProperty("albums")]
public Paging<SimpleAlbum> Albums { get; set; }
[JsonProperty("tracks")]
public Paging<FullTrack> Tracks { get; set; }
[JsonProperty("playlists")]
public Paging<SimplePlaylist> Playlists { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SeveralAlbums : BasicModel
{
[JsonProperty("albums")]
public List<FullAlbum> Albums { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SeveralArtists : BasicModel
{
[JsonProperty("artists")]
public List<FullArtist> Artists { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SeveralAudioFeatures : BasicModel
{
[JsonProperty("audio_features")]
public List<AudioFeatures> AudioFeatures { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SeveralTracks : BasicModel
{
[JsonProperty("tracks")]
public List<FullTrack> Tracks { get; set; }
}
}

View File

@ -1,44 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SimplePlaylist : BasicModel
{
[JsonProperty("collaborative")]
public bool Collaborative { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("owner")]
public PublicProfile Owner { get; set; }
[JsonProperty("public")]
public bool Public { get; set; }
[JsonProperty("snapshot_id")]
public string SnapshotId { get; set; }
[JsonProperty("tracks")]
public PlaylistTrackCollection Tracks { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,50 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class SimpleTrack : BasicModel
{
[JsonProperty("artists")]
public List<SimpleArtist> Artists { get; set; }
[JsonProperty("available_markets")]
public List<string> AvailableMarkets { get; set; }
[JsonProperty("disc_number")]
public int DiscNumber { get; set; }
[JsonProperty("duration_ms")]
public int DurationMs { get; set; }
[JsonProperty("explicit")]
public bool Explicit { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternUrls { get; set; }
[JsonProperty("href")]
public string Href { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("preview_url")]
public string PreviewUrl { get; set; }
[JsonProperty("track_number")]
public int TrackNumber { get; set; }
[JsonProperty("restrictions")]
public Dictionary<string, string> Restrictions { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("uri")]
public string Uri { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Snapshot : BasicModel
{
[JsonProperty("snapshot_id")]
public string SnapshotId { get; set; }
}
}

View File

@ -1,47 +0,0 @@
using System;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Token
{
public Token()
{
CreateDate = DateTime.Now;
}
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public double ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
[JsonProperty("error")]
public string Error { get; set; }
[JsonProperty("error_description")]
public string ErrorDescription { get; set; }
public DateTime CreateDate { get; set; }
/// <summary>
/// Checks if the token has expired
/// </summary>
/// <returns></returns>
public bool IsExpired()
{
return CreateDate.Add(TimeSpan.FromSeconds(ExpiresIn)) <= DateTime.Now;
}
public bool HasError()
{
return Error != null;
}
}
}

View File

@ -1,69 +0,0 @@
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
namespace SpotifyAPI.Web.Models
{
public class TuneableTrack
{
[String("acousticness")]
public float? Acousticness { get; set; }
[String("danceability")]
public float? Danceability { get; set; }
[String("duration_ms")]
public int? DurationMs { get; set; }
[String("energy")]
public float? Energy { get; set; }
[String("instrumentalness")]
public float? Instrumentalness { get; set; }
[String("key")]
public int? Key { get; set; }
[String("liveness")]
public float? Liveness { get; set; }
[String("loudness")]
public float? Loudness { get; set; }
[String("mode")]
public int? Mode { get; set; }
[String("popularity")]
public int? Popularity { get; set; }
[String("speechiness")]
public float? Speechiness { get; set; }
[String("tempo")]
public float? Tempo { get; set; }
[String("time_signature")]
public int? TimeSignature { get; set; }
[String("valence")]
public float? Valence { get; set; }
public string BuildUrlParams(string prefix)
{
List<string> urlParams = new List<string>();
foreach (PropertyInfo info in GetType().GetProperties())
{
object value = info.GetValue(this);
string name = info.GetCustomAttribute<StringAttribute>()?.Text;
if (name == null || value == null)
continue;
urlParams.Add(value is float valueAsFloat ?
$"{prefix}_{name}={valueAsFloat.ToString(CultureInfo.InvariantCulture)}" :
$"{prefix}_{name}={value}");
}
if (urlParams.Count > 0)
return "&" + string.Join("&", urlParams);
return "";
}
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFrameworks>netstandard2.1</TargetFrameworks>
<PackageId>SpotifyAPI.Web</PackageId>
<Title>SpotifyAPI.Web</Title>
<Authors>Jonas Dellinger</Authors>

View File

@ -0,0 +1,23 @@
using System;
namespace SpotifyAPI.Web
{
public static class SpotifyUrls
{
static URIParameterFormatProvider _provider = new URIParameterFormatProvider();
public static Uri API_V1 = new Uri("https://api.spotify.com/v1/");
public static Uri Me() => _Uri("me");
public static Uri User(string userId) => _Uri($"users/{userId}");
public static Uri Categories() => _Uri("browse/categories");
public static Uri Category(string categoryId) => _Uri($"browse/categories/{categoryId}");
public static Uri CategoryPlaylists(string categoryId) => _Uri($"browse/categories/{categoryId}/playlists");
private static Uri _Uri(FormattableString path) => new Uri(path.ToString(_provider), UriKind.Relative);
private static Uri _Uri(string path) => new Uri(path, UriKind.Relative);
}
}

Some files were not shown because too many files have changed in this diff Show More