From 466e61523d6af7abff1e783401630fe3955859b6 Mon Sep 17 00:00:00 2001 From: Jonas Dellinger Date: Mon, 9 Mar 2020 20:47:39 +0100 Subject: [PATCH] VSCode Formatter - Also bumped tests to net core 3.1 --- SpotifyAPI.Web.Auth/AuthUtil.cs | 40 +- SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs | 224 ++++---- SpotifyAPI.Web.Auth/CredentialsAuth.cs | 65 ++- SpotifyAPI.Web.Auth/ImplicitGrantAuth.cs | 100 ++-- SpotifyAPI.Web.Auth/SpotifyAuthServer.cs | 158 +++--- SpotifyAPI.Web.Auth/TokenSwapAuth.cs | 385 +++++++------ SpotifyAPI.Web.Auth/TokenSwapWebAPIFactory.cs | 536 +++++++++--------- .../Controllers/HomeController.cs | 42 +- .../Models/ErrorViewModel.cs | 12 +- .../Models/IndexModel.cs | 10 +- SpotifyAPI.Web.Examples.ASP/Program.cs | 26 +- SpotifyAPI.Web.Examples.ASP/Startup.cs | 112 ++-- SpotifyAPI.Web.Examples.CLI/Program.cs | 122 ++-- SpotifyAPI.Web.Tests/ProxyConfigTest.cs | 220 +++---- .../SpotifyAPI.Web.Tests.csproj | 3 +- SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs | 133 +++-- SpotifyAPI.Web.Tests/UtilTest.cs | 20 +- SpotifyAPI.Web/Enums/AlbumType.cs | 30 +- SpotifyAPI.Web/Enums/FollowType.cs | 18 +- SpotifyAPI.Web/Enums/RepeatState.cs | 22 +- SpotifyAPI.Web/Enums/Scope.cs | 92 +-- SpotifyAPI.Web/Enums/SearchType.cs | 30 +- SpotifyAPI.Web/Enums/TimeRangeType.cs | 28 +- SpotifyAPI.Web/Enums/TrackType.cs | 26 +- SpotifyAPI.Web/IClient.cs | 210 +++---- SpotifyAPI.Web/Models/AnalysisMeta.cs | 38 +- SpotifyAPI.Web/Models/AnalysisSection.cs | 58 +- SpotifyAPI.Web/Models/AnalysisSegment.cs | 46 +- SpotifyAPI.Web/Models/AnalysisTimeSlice.cs | 22 +- SpotifyAPI.Web/Models/AnalysisTrack.cs | 114 ++-- SpotifyAPI.Web/Models/ArrayResponse.cs | 10 +- SpotifyAPI.Web/Models/AudioAnalysis.cs | 38 +- SpotifyAPI.Web/Models/AudioFeatures.cs | 80 +-- SpotifyAPI.Web/Models/AvailabeDevices.cs | 12 +- SpotifyAPI.Web/Models/BasicModel.cs | 24 +- SpotifyAPI.Web/Models/Category.cs | 24 +- SpotifyAPI.Web/Models/CategoryList.cs | 12 +- SpotifyAPI.Web/Models/CategoryPlaylist.cs | 12 +- SpotifyAPI.Web/Models/CursorPaging.cs | 50 +- SpotifyAPI.Web/Models/Device.cs | 32 +- SpotifyAPI.Web/Models/FeaturedPlaylists.cs | 16 +- SpotifyAPI.Web/Models/FollowedArtists.cs | 12 +- SpotifyAPI.Web/Models/FullAlbum.cs | 92 +-- SpotifyAPI.Web/Models/FullArtist.cs | 48 +- SpotifyAPI.Web/Models/FullPlaylist.cs | 64 +-- SpotifyAPI.Web/Models/FullTrack.cs | 96 ++-- SpotifyAPI.Web/Models/GeneralModels.cs | 259 +++++---- SpotifyAPI.Web/Models/NewAlbumReleases.cs | 12 +- SpotifyAPI.Web/Models/Paging.cs | 66 +-- SpotifyAPI.Web/Models/PlayHistory.cs | 20 +- SpotifyAPI.Web/Models/PlaybackContext.cs | 48 +- SpotifyAPI.Web/Models/PrivateProfile.cs | 56 +- SpotifyAPI.Web/Models/PublicProfile.cs | 40 +- SpotifyAPI.Web/Models/RecommendationSeed .cs | 32 +- .../Models/RecommendationSeedGenres.cs | 12 +- SpotifyAPI.Web/Models/Recommendations.cs | 16 +- SpotifyAPI.Web/Models/ResponseInfo.cs | 14 +- SpotifyAPI.Web/Models/SearchItem.cs | 24 +- SpotifyAPI.Web/Models/SeveralAlbums.cs | 12 +- SpotifyAPI.Web/Models/SeveralArtists.cs | 10 +- SpotifyAPI.Web/Models/SeveralAudioFeatures.cs | 12 +- SpotifyAPI.Web/Models/SeveralTracks.cs | 12 +- SpotifyAPI.Web/Models/SimpleAlbum.cs | 68 +-- SpotifyAPI.Web/Models/SimpleArtist.cs | 34 +- SpotifyAPI.Web/Models/SimplePlaylist.cs | 56 +- SpotifyAPI.Web/Models/SimpleTrack.cs | 64 +-- SpotifyAPI.Web/Models/Snapshot.cs | 12 +- SpotifyAPI.Web/Models/Token.cs | 80 +-- SpotifyAPI.Web/Models/TuneableTrack.cs | 122 ++-- SpotifyAPI.Web/ProxyConfig.cs | 178 +++--- SpotifyAPI.Web/SpotifyWebAPI.cs | 2 +- SpotifyAPI.Web/SpotifyWebBuilder.cs | 4 +- SpotifyAPI.Web/SpotifyWebClient.cs | 381 ++++++------- SpotifyAPI.Web/Util.cs | 58 +- 74 files changed, 2626 insertions(+), 2642 deletions(-) diff --git a/SpotifyAPI.Web.Auth/AuthUtil.cs b/SpotifyAPI.Web.Auth/AuthUtil.cs index 2e6025a2..b72d3ead 100644 --- a/SpotifyAPI.Web.Auth/AuthUtil.cs +++ b/SpotifyAPI.Web.Auth/AuthUtil.cs @@ -1,30 +1,30 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Runtime.InteropServices; namespace SpotifyAPI.Web.Auth { - internal static class AuthUtil + internal static class AuthUtil + { + public static void OpenBrowser(string url) { - public static void OpenBrowser(string url) - { #if NETSTANDARD2_0 - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - url = url.Replace("&", "^&"); - Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - Process.Start("xdg-open", url); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - Process.Start("open", url); - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + url = url.Replace("&", "^&"); + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", url); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Process.Start("open", url); + } #else - url = url.Replace("&", "^&"); - Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); + url = url.Replace("&", "^&"); + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); #endif - } } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs b/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs index e7e24df9..e5145676 100644 --- a/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs +++ b/SpotifyAPI.Web.Auth/AuthorizationCodeAuth.cs @@ -12,125 +12,121 @@ using Unosquare.Labs.EmbedIO.Modules; namespace SpotifyAPI.Web.Auth { - public class AuthorizationCodeAuth : SpotifyAuthServer + public class AuthorizationCodeAuth : SpotifyAuthServer + { + public string SecretId { get; set; } + + public ProxyConfig ProxyConfig { get; set; } + + public AuthorizationCodeAuth(string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") : base("code", "AuthorizationCodeAuth", redirectUri, serverUri, scope, state) + { } + + public AuthorizationCodeAuth(string clientId, string secretId, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") : this(redirectUri, serverUri, scope, state) { - public string SecretId { get; set; } - - public ProxyConfig ProxyConfig { get; set; } - - public AuthorizationCodeAuth(string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") - : base("code", "AuthorizationCodeAuth", redirectUri, serverUri, scope, state) - { - } - - public AuthorizationCodeAuth(string clientId, string secretId, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") - : this(redirectUri, serverUri, scope, state) - { - ClientId = clientId; - SecretId = secretId; - } - - private bool ShouldRegisterNewApp() - { - return string.IsNullOrEmpty(SecretId) || string.IsNullOrEmpty(ClientId); - } - - public override string GetUri() - { - return ShouldRegisterNewApp() ? $"{RedirectUri}/start.html#{State}" : base.GetUri(); - } - - protected override void AdaptWebServer(WebServer webServer) - { - webServer.Module().RegisterController(); - } - - private string GetAuthHeader() => $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + SecretId))}"; - - public async Task RefreshToken(string refreshToken) - { - List> args = new List> - { - new KeyValuePair("grant_type", "refresh_token"), - new KeyValuePair("refresh_token", refreshToken) - }; - - return await GetToken(args); - } - - public async Task ExchangeCode(string code) - { - List> args = new List> - { - new KeyValuePair("grant_type", "authorization_code"), - new KeyValuePair("code", code), - new KeyValuePair("redirect_uri", RedirectUri) - }; - - return await GetToken(args); - } - - private async Task GetToken(IEnumerable> args) - { - HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig); - HttpClient client = new HttpClient(handler); - client.DefaultRequestHeaders.Add("Authorization", GetAuthHeader()); - HttpContent content = new FormUrlEncodedContent(args); - - HttpResponseMessage resp = await client.PostAsync("https://accounts.spotify.com/api/token", content); - string msg = await resp.Content.ReadAsStringAsync(); - - return JsonConvert.DeserializeObject(msg); - } + ClientId = clientId; + SecretId = secretId; } - public class AuthorizationCode + private bool ShouldRegisterNewApp() { - public string Code { get; set; } - - public string Error { get; set; } + return string.IsNullOrEmpty(SecretId) || string.IsNullOrEmpty(ClientId); } - internal class AuthorizationCodeAuthController : WebApiController + public override string GetUri() { - [WebApiHandler(HttpVerbs.Get, "/")] - public Task GetEmpty() - { - string state = Request.QueryString["state"]; - AuthorizationCodeAuth.Instances.TryGetValue(state, out SpotifyAuthServer auth); - - string code = null; - string error = Request.QueryString["error"]; - if (error == null) - code = Request.QueryString["code"]; - - Task.Factory.StartNew(() => auth?.TriggerAuth(new AuthorizationCode - { - Code = code, - Error = error - })); - - return HttpContext.HtmlResponseAsync("OK - This window can be closed now"); - } - - [WebApiHandler(HttpVerbs.Post, "/")] - public async Task PostValues() - { - Dictionary formParams = await HttpContext.RequestFormDataDictionaryAsync(); - - string state = (string) formParams["state"]; - AuthorizationCodeAuth.Instances.TryGetValue(state, out SpotifyAuthServer authServer); - - AuthorizationCodeAuth auth = (AuthorizationCodeAuth) authServer; - auth.ClientId = (string) formParams["clientId"]; - auth.SecretId = (string) formParams["secretId"]; - - string uri = auth.GetUri(); - return HttpContext.Redirect(uri, false); - } - - public AuthorizationCodeAuthController(IHttpContext context) : base(context) - { - } + return ShouldRegisterNewApp() ? $"{RedirectUri}/start.html#{State}" : base.GetUri(); } -} + + protected override void AdaptWebServer(WebServer webServer) + { + webServer.Module().RegisterController(); + } + + private string GetAuthHeader() => $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + SecretId))}"; + + public async Task RefreshToken(string refreshToken) + { + List> args = new List> + { + new KeyValuePair("grant_type", "refresh_token"), + new KeyValuePair("refresh_token", refreshToken) + }; + + return await GetToken(args); + } + + public async Task ExchangeCode(string code) + { + List> args = new List> + { + new KeyValuePair("grant_type", "authorization_code"), + new KeyValuePair("code", code), + new KeyValuePair("redirect_uri", RedirectUri) + }; + + return await GetToken(args); + } + + private async Task GetToken(IEnumerable> args) + { + HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig); + HttpClient client = new HttpClient(handler); + client.DefaultRequestHeaders.Add("Authorization", GetAuthHeader()); + HttpContent content = new FormUrlEncodedContent(args); + + HttpResponseMessage resp = await client.PostAsync("https://accounts.spotify.com/api/token", content); + string msg = await resp.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(msg); + } + } + + public class AuthorizationCode + { + public string Code { get; set; } + + public string Error { get; set; } + } + + internal class AuthorizationCodeAuthController : WebApiController + { + [WebApiHandler(HttpVerbs.Get, "/")] + public Task GetEmpty() + { + string state = Request.QueryString["state"]; + AuthorizationCodeAuth.Instances.TryGetValue(state, out SpotifyAuthServer auth); + + string code = null; + string error = Request.QueryString["error"]; + if (error == null) + code = Request.QueryString["code"]; + + Task.Factory.StartNew(() => auth?.TriggerAuth(new AuthorizationCode + { + Code = code, + Error = error + })); + + return HttpContext.HtmlResponseAsync("OK - This window can be closed now"); + } + + [WebApiHandler(HttpVerbs.Post, "/")] + public async Task PostValues() + { + Dictionary formParams = await HttpContext.RequestFormDataDictionaryAsync(); + + string state = (string) formParams["state"]; + AuthorizationCodeAuth.Instances.TryGetValue(state, out SpotifyAuthServer authServer); + + AuthorizationCodeAuth auth = (AuthorizationCodeAuth) authServer; + auth.ClientId = (string) formParams["clientId"]; + auth.SecretId = (string) formParams["secretId"]; + + string uri = auth.GetUri(); + return HttpContext.Redirect(uri, false); + } + + public AuthorizationCodeAuthController(IHttpContext context) : base(context) + { } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/CredentialsAuth.cs b/SpotifyAPI.Web.Auth/CredentialsAuth.cs index 0d270be4..661d987d 100644 --- a/SpotifyAPI.Web.Auth/CredentialsAuth.cs +++ b/SpotifyAPI.Web.Auth/CredentialsAuth.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Net.Http; using System.Text; @@ -8,38 +8,37 @@ using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web.Auth { - public class CredentialsAuth + public class CredentialsAuth + { + public string ClientSecret { get; set; } + + public string ClientId { get; set; } + + public ProxyConfig ProxyConfig { get; set; } + + public CredentialsAuth(string clientId, string clientSecret) { - public string ClientSecret { get; set; } - - public string ClientId { get; set; } - - public ProxyConfig ProxyConfig { get; set; } - - public CredentialsAuth(string clientId, string clientSecret) - { - ClientId = clientId; - ClientSecret = clientSecret; - } - - public async Task GetToken() - { - string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret)); - - List> args = new List> - { - new KeyValuePair("grant_type", "client_credentials") - }; - - HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig); - HttpClient client = new HttpClient(handler); - client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}"); - HttpContent content = new FormUrlEncodedContent(args); - - HttpResponseMessage resp = await client.PostAsync("https://accounts.spotify.com/api/token", content); - string msg = await resp.Content.ReadAsStringAsync(); - - return JsonConvert.DeserializeObject(msg); - } + ClientId = clientId; + ClientSecret = clientSecret; } + + public async Task GetToken() + { + string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret)); + + List> args = new List> + {new KeyValuePair("grant_type", "client_credentials") + }; + + HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig); + HttpClient client = new HttpClient(handler); + client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}"); + HttpContent content = new FormUrlEncodedContent(args); + + HttpResponseMessage resp = await client.PostAsync("https://accounts.spotify.com/api/token", content); + string msg = await resp.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(msg); + } + } } diff --git a/SpotifyAPI.Web.Auth/ImplicitGrantAuth.cs b/SpotifyAPI.Web.Auth/ImplicitGrantAuth.cs index 17c3d189..2489fdfa 100644 --- a/SpotifyAPI.Web.Auth/ImplicitGrantAuth.cs +++ b/SpotifyAPI.Web.Auth/ImplicitGrantAuth.cs @@ -7,59 +7,57 @@ using Unosquare.Labs.EmbedIO.Modules; namespace SpotifyAPI.Web.Auth { - public class ImplicitGrantAuth : SpotifyAuthServer + public class ImplicitGrantAuth : SpotifyAuthServer + { + public ImplicitGrantAuth(string clientId, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") : base("token", "ImplicitGrantAuth", redirectUri, serverUri, scope, state) { - public ImplicitGrantAuth(string clientId, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") : - base("token", "ImplicitGrantAuth", redirectUri, serverUri, scope, state) - { - ClientId = clientId; - } - - protected override void AdaptWebServer(WebServer webServer) - { - webServer.Module().RegisterController(); - } + ClientId = clientId; } - public class ImplicitGrantAuthController : WebApiController + protected override void AdaptWebServer(WebServer webServer) { - [WebApiHandler(HttpVerbs.Get, "/auth")] - public Task GetAuth() - { - string state = Request.QueryString["state"]; - SpotifyAuthServer auth = ImplicitGrantAuth.GetByState(state); - if (auth == null) - return HttpContext.StringResponseAsync( - $"Failed - Unable to find auth request with state \"{state}\" - Please retry"); - - Token token; - string error = Request.QueryString["error"]; - if (error == null) - { - string accessToken = Request.QueryString["access_token"]; - string tokenType = Request.QueryString["token_type"]; - string expiresIn = Request.QueryString["expires_in"]; - token = new Token - { - AccessToken = accessToken, - ExpiresIn = double.Parse(expiresIn), - TokenType = tokenType - }; - } - else - { - token = new Token - { - Error = error - }; - } - - Task.Factory.StartNew(() => auth.TriggerAuth(token)); - return HttpContext.HtmlResponseAsync("OK - This window can be closed now"); - } - - public ImplicitGrantAuthController(IHttpContext context) : base(context) - { - } + webServer.Module().RegisterController(); } -} + } + + public class ImplicitGrantAuthController : WebApiController + { + [WebApiHandler(HttpVerbs.Get, "/auth")] + public Task GetAuth() + { + string state = Request.QueryString["state"]; + SpotifyAuthServer auth = ImplicitGrantAuth.GetByState(state); + if (auth == null) + return HttpContext.StringResponseAsync( + $"Failed - Unable to find auth request with state \"{state}\" - Please retry"); + + Token token; + string error = Request.QueryString["error"]; + if (error == null) + { + string accessToken = Request.QueryString["access_token"]; + string tokenType = Request.QueryString["token_type"]; + string expiresIn = Request.QueryString["expires_in"]; + token = new Token + { + AccessToken = accessToken, + ExpiresIn = double.Parse(expiresIn), + TokenType = tokenType + }; + } + else + { + token = new Token + { + Error = error + }; + } + + Task.Factory.StartNew(() => auth.TriggerAuth(token)); + return HttpContext.HtmlResponseAsync("OK - This window can be closed now"); + } + + public ImplicitGrantAuthController(IHttpContext context) : base(context) + { } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs b/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs index cc1d827a..33c6f035 100644 --- a/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs +++ b/SpotifyAPI.Web.Auth/SpotifyAuthServer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -10,84 +10,84 @@ using Unosquare.Labs.EmbedIO.Modules; namespace SpotifyAPI.Web.Auth { - public abstract class SpotifyAuthServer + public abstract class SpotifyAuthServer + { + public string ClientId { get; set; } + public string ServerUri { get; set; } + public string RedirectUri { get; set; } + public string State { get; set; } + public Scope Scope { get; set; } + public bool ShowDialog { get; set; } + + private readonly string _folder; + private readonly string _type; + private WebServer _server; + protected CancellationTokenSource _serverSource; + + public delegate void OnAuthReceived(object sender, T payload); + public event OnAuthReceived AuthReceived; + + internal static readonly Dictionary> Instances = new Dictionary>(); + + internal SpotifyAuthServer(string type, string folder, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") { - public string ClientId { get; set; } - public string ServerUri { get; set; } - public string RedirectUri { get; set; } - public string State { get; set; } - public Scope Scope { get; set; } - public bool ShowDialog { get; set; } - - private readonly string _folder; - private readonly string _type; - private WebServer _server; - protected CancellationTokenSource _serverSource; - - public delegate void OnAuthReceived(object sender, T payload); - public event OnAuthReceived AuthReceived; - - internal static readonly Dictionary> Instances = new Dictionary>(); - - internal SpotifyAuthServer(string type, string folder, string redirectUri, string serverUri, Scope scope = Scope.None, string state = "") - { - _type = type; - _folder = folder; - ServerUri = serverUri; - RedirectUri = redirectUri; - Scope = scope; - State = string.IsNullOrEmpty(state) ? string.Join("", Guid.NewGuid().ToString("n").Take(8)) : state; - } - - public void Start() - { - Instances.Add(State, this); - _serverSource = new CancellationTokenSource(); - - _server = WebServer.Create(ServerUri); - _server.RegisterModule(new WebApiModule()); - AdaptWebServer(_server); - _server.RegisterModule(new ResourceFilesModule(Assembly.GetExecutingAssembly(), $"SpotifyAPI.Web.Auth.Resources.{_folder}")); -#pragma warning disable 4014 - _server.RunAsync(_serverSource.Token); -#pragma warning restore 4014 - } - - public virtual string GetUri() - { - StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?"); - builder.Append("client_id=" + ClientId); - builder.Append($"&response_type={_type}"); - builder.Append("&redirect_uri=" + RedirectUri); - builder.Append("&state=" + State); - builder.Append("&scope=" + Scope.GetStringAttribute(" ")); - builder.Append("&show_dialog=" + ShowDialog); - return Uri.EscapeUriString(builder.ToString()); - } - - public void Stop(int delay = 2000) - { - if (_serverSource == null) return; - _serverSource.CancelAfter(delay); - Instances.Remove(State); - } - - public void OpenBrowser() - { - string uri = GetUri(); - AuthUtil.OpenBrowser(uri); - } - - internal void TriggerAuth(T payload) - { - AuthReceived?.Invoke(this, payload); - } - - internal static SpotifyAuthServer GetByState(string state) - { - return Instances.TryGetValue(state, out SpotifyAuthServer auth) ? auth : null; - } - - protected abstract void AdaptWebServer(WebServer webServer); + _type = type; + _folder = folder; + ServerUri = serverUri; + RedirectUri = redirectUri; + Scope = scope; + State = string.IsNullOrEmpty(state) ? string.Join("", Guid.NewGuid().ToString("n").Take(8)) : state; } + + public void Start() + { + Instances.Add(State, this); + _serverSource = new CancellationTokenSource(); + + _server = WebServer.Create(ServerUri); + _server.RegisterModule(new WebApiModule()); + AdaptWebServer(_server); + _server.RegisterModule(new ResourceFilesModule(Assembly.GetExecutingAssembly(), $"SpotifyAPI.Web.Auth.Resources.{_folder}")); +#pragma warning disable 4014 + _server.RunAsync(_serverSource.Token); +#pragma warning restore 4014 + } + + public virtual string GetUri() + { + StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?"); + builder.Append("client_id=" + ClientId); + builder.Append($"&response_type={_type}"); + builder.Append("&redirect_uri=" + RedirectUri); + builder.Append("&state=" + State); + builder.Append("&scope=" + Scope.GetStringAttribute(" ")); + builder.Append("&show_dialog=" + ShowDialog); + return Uri.EscapeUriString(builder.ToString()); + } + + public void Stop(int delay = 2000) + { + if (_serverSource == null) return; + _serverSource.CancelAfter(delay); + Instances.Remove(State); + } + + public void OpenBrowser() + { + string uri = GetUri(); + AuthUtil.OpenBrowser(uri); + } + + internal void TriggerAuth(T payload) + { + AuthReceived?.Invoke(this, payload); + } + + internal static SpotifyAuthServer GetByState(string state) + { + return Instances.TryGetValue(state, out SpotifyAuthServer auth) ? auth : null; + } + + protected abstract void AdaptWebServer(WebServer webServer); + } } \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/TokenSwapAuth.cs b/SpotifyAPI.Web.Auth/TokenSwapAuth.cs index 092945ff..1514b38d 100644 --- a/SpotifyAPI.Web.Auth/TokenSwapAuth.cs +++ b/SpotifyAPI.Web.Auth/TokenSwapAuth.cs @@ -1,221 +1,218 @@ -using System; +using System; using System.Collections.Generic; +using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; using SpotifyAPI.Web.Enums; +using SpotifyAPI.Web.Models; using Unosquare.Labs.EmbedIO; using Unosquare.Labs.EmbedIO.Constants; using Unosquare.Labs.EmbedIO.Modules; -using SpotifyAPI.Web.Models; -using Newtonsoft.Json; -using System.Net.Http; namespace SpotifyAPI.Web.Auth { + /// + /// + /// A version of that does not store your client secret, client ID or redirect URI, enforcing a secure authorization flow. Requires an exchange server that will return the authorization code to its callback server via GET request. + /// + /// + /// It's recommended that you use if you would like to use the TokenSwap method. + /// + /// + public class TokenSwapAuth : SpotifyAuthServer + { + readonly string _exchangeServerUri; + /// + /// The HTML to respond with when the callback server (serverUri) is reached. The default value will close the window on arrival. + /// + public string HtmlResponse { get; set; } = ""; + + /// + /// If true, will time how long it takes for access to expire. On expiry, the event fires. + /// + public bool TimeAccessExpiry { get; set; } + + public ProxyConfig ProxyConfig { get; set; } + + /// The URI to an exchange server that will perform the key exchange. + /// The URI to host the server at that your exchange server should return the authorization code to by GET request. (e.g. http://localhost:4002) + /// + /// Stating none will randomly generate a state parameter. + /// The HTML to respond with when the callback server (serverUri) is reached. The default value will close the window on arrival. + public TokenSwapAuth(string exchangeServerUri, string serverUri, Scope scope = Scope.None, string state = "", + string htmlResponse = "") : base("code", "", "", serverUri, scope, state) + { + if (!string.IsNullOrEmpty(htmlResponse)) + { + HtmlResponse = htmlResponse; + } + + _exchangeServerUri = exchangeServerUri; + } + + protected override void AdaptWebServer(WebServer webServer) + { + webServer.Module().RegisterController(); + } + + public override string GetUri() + { + StringBuilder builder = new StringBuilder(_exchangeServerUri); + builder.Append("?"); + builder.Append("response_type=code"); + builder.Append("&state=" + State); + builder.Append("&scope=" + Scope.GetStringAttribute(" ")); + builder.Append("&show_dialog=" + ShowDialog); + return Uri.EscapeUriString(builder.ToString()); + } + + /// + /// The maximum amount of times to retry getting a token. + /// + /// A token get is attempted every time you and . + /// + public int MaxGetTokenRetries { get; set; } = 10; + + /// + /// Creates a HTTP request to obtain a token object. + /// Parameter grantType can only be "refresh_token" or "authorization_code". authorizationCode and refreshToken are not mandatory, but at least one must be provided for your desired grant_type request otherwise an invalid response will be given and an exception is likely to be thrown. /// - /// A version of that does not store your client secret, client ID or redirect URI, enforcing a secure authorization flow. Requires an exchange server that will return the authorization code to its callback server via GET request. - /// - /// - /// It's recommended that you use if you would like to use the TokenSwap method. + /// Will re-attempt on error, on null or on no access token times before finally returning null. /// /// - public class TokenSwapAuth : SpotifyAuthServer + /// Can only be "refresh_token" or "authorization_code". + /// This needs to be defined if "grantType" is "authorization_code". + /// This needs to be defined if "grantType" is "refresh_token". + /// Does not need to be defined. Used internally for retry attempt recursion. + /// Attempts to return a full , but after retry attempts, may return a with no , or null. + async Task GetToken(string grantType, string authorizationCode = "", string refreshToken = "", + int currentRetries = 0) { - readonly string _exchangeServerUri; + FormUrlEncodedContent content = new FormUrlEncodedContent(new Dictionary + { { "grant_type", grantType }, + { "code", authorizationCode }, + { "refresh_token", refreshToken } + }); - /// - /// The HTML to respond with when the callback server (serverUri) is reached. The default value will close the window on arrival. - /// - public string HtmlResponse { get; set; } = ""; + try + { + HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig); + HttpClient client = new HttpClient(handler); + HttpResponseMessage siteResponse = await client.PostAsync(_exchangeServerUri, content); - /// - /// If true, will time how long it takes for access to expire. On expiry, the event fires. - /// - public bool TimeAccessExpiry { get; set; } - - public ProxyConfig ProxyConfig { get; set; } - - /// The URI to an exchange server that will perform the key exchange. - /// The URI to host the server at that your exchange server should return the authorization code to by GET request. (e.g. http://localhost:4002) - /// - /// Stating none will randomly generate a state parameter. - /// The HTML to respond with when the callback server (serverUri) is reached. The default value will close the window on arrival. - public TokenSwapAuth(string exchangeServerUri, string serverUri, Scope scope = Scope.None, string state = "", - string htmlResponse = "") : base("code", "", "", serverUri, scope, state) + Token token = JsonConvert.DeserializeObject(await siteResponse.Content.ReadAsStringAsync()); + // Don't need to check if it was null - if it is, it will resort to the catch block. + if (!token.HasError() && !string.IsNullOrEmpty(token.AccessToken)) { - if (!string.IsNullOrEmpty(htmlResponse)) - { - HtmlResponse = htmlResponse; - } - - _exchangeServerUri = exchangeServerUri; + return token; } + } + catch + { } - protected override void AdaptWebServer(WebServer webServer) - { - webServer.Module().RegisterController(); - } - - public override string GetUri() - { - StringBuilder builder = new StringBuilder(_exchangeServerUri); - builder.Append("?"); - builder.Append("response_type=code"); - builder.Append("&state=" + State); - builder.Append("&scope=" + Scope.GetStringAttribute(" ")); - builder.Append("&show_dialog=" + ShowDialog); - return Uri.EscapeUriString(builder.ToString()); - } - - /// - /// The maximum amount of times to retry getting a token. - /// - /// A token get is attempted every time you and . - /// - public int MaxGetTokenRetries { get; set; } = 10; - - /// - /// Creates a HTTP request to obtain a token object. - /// Parameter grantType can only be "refresh_token" or "authorization_code". authorizationCode and refreshToken are not mandatory, but at least one must be provided for your desired grant_type request otherwise an invalid response will be given and an exception is likely to be thrown. - /// - /// Will re-attempt on error, on null or on no access token times before finally returning null. - /// - /// - /// Can only be "refresh_token" or "authorization_code". - /// This needs to be defined if "grantType" is "authorization_code". - /// This needs to be defined if "grantType" is "refresh_token". - /// Does not need to be defined. Used internally for retry attempt recursion. - /// Attempts to return a full , but after retry attempts, may return a with no , or null. - async Task GetToken(string grantType, string authorizationCode = "", string refreshToken = "", - int currentRetries = 0) - { - FormUrlEncodedContent content = new FormUrlEncodedContent(new Dictionary - { - {"grant_type", grantType}, - {"code", authorizationCode}, - {"refresh_token", refreshToken} - }); - - try - { - HttpClientHandler handler = ProxyConfig.CreateClientHandler(ProxyConfig); - HttpClient client = new HttpClient(handler); - HttpResponseMessage siteResponse = await client.PostAsync(_exchangeServerUri, content); - - Token token = JsonConvert.DeserializeObject(await siteResponse.Content.ReadAsStringAsync()); - // Don't need to check if it was null - if it is, it will resort to the catch block. - if (!token.HasError() && !string.IsNullOrEmpty(token.AccessToken)) - { - return token; - } - } - catch - { - } - - if (currentRetries >= MaxGetTokenRetries) - { - return null; - } - else - { - currentRetries++; - // The reason I chose to implement the retries system this way is because a static or instance - // variable keeping track would inhibit parallelism i.e. using this function on multiple threads/tasks. - // It's not clear why someone would like to do that, but it's better to cater for all kinds of uses. - return await GetToken(grantType, authorizationCode, refreshToken, currentRetries); - } - } - - System.Timers.Timer _accessTokenExpireTimer; - - /// - /// When Spotify authorization has expired. Will only trigger if is true. - /// - public event EventHandler OnAccessTokenExpired; - - /// - /// If is true, sets a timer for how long access will take to expire. - /// - /// - void SetAccessExpireTimer(Token token) - { - if (!TimeAccessExpiry) return; - - if (_accessTokenExpireTimer != null) - { - _accessTokenExpireTimer.Stop(); - _accessTokenExpireTimer.Dispose(); - } - - _accessTokenExpireTimer = new System.Timers.Timer - { - Enabled = true, - Interval = token.ExpiresIn * 1000, - AutoReset = false - }; - _accessTokenExpireTimer.Elapsed += (sender, e) => OnAccessTokenExpired?.Invoke(this, EventArgs.Empty); - } - - /// - /// Uses the authorization code to silently (doesn't open a browser) obtain both an access token and refresh token, where the refresh token would be required for you to use . - /// - /// - /// - public async Task ExchangeCodeAsync(string authorizationCode) - { - Token token = await GetToken("authorization_code", authorizationCode: authorizationCode); - if (token != null && !token.HasError() && !string.IsNullOrEmpty(token.AccessToken)) - { - SetAccessExpireTimer(token); - } - - return token; - } - - /// - /// Uses the refresh token to silently (doesn't open a browser) obtain a fresh access token, no refresh token is given however (as it does not change). - /// - /// - /// - public async Task RefreshAuthAsync(string refreshToken) - { - Token token = await GetToken("refresh_token", refreshToken: refreshToken); - if (token != null && !token.HasError() && !string.IsNullOrEmpty(token.AccessToken)) - { - SetAccessExpireTimer(token); - } - - return token; - } + if (currentRetries >= MaxGetTokenRetries) + { + return null; + } + else + { + currentRetries++; + // The reason I chose to implement the retries system this way is because a static or instance + // variable keeping track would inhibit parallelism i.e. using this function on multiple threads/tasks. + // It's not clear why someone would like to do that, but it's better to cater for all kinds of uses. + return await GetToken(grantType, authorizationCode, refreshToken, currentRetries); + } } - internal class TokenSwapAuthController : WebApiController + System.Timers.Timer _accessTokenExpireTimer; + + /// + /// When Spotify authorization has expired. Will only trigger if is true. + /// + public event EventHandler OnAccessTokenExpired; + + /// + /// If is true, sets a timer for how long access will take to expire. + /// + /// + void SetAccessExpireTimer(Token token) { - public TokenSwapAuthController(IHttpContext context) : base(context) - { - } + if (!TimeAccessExpiry) return; - [WebApiHandler(HttpVerbs.Get, "/auth")] - public Task GetAuth() - { - string state = Request.QueryString["state"]; - SpotifyAuthServer auth = TokenSwapAuth.GetByState(state); + if (_accessTokenExpireTimer != null) + { + _accessTokenExpireTimer.Stop(); + _accessTokenExpireTimer.Dispose(); + } - string code = null; - string error = Request.QueryString["error"]; - if (error == null) - { - code = Request.QueryString["code"]; - } - - Task.Factory.StartNew(() => auth?.TriggerAuth(new AuthorizationCode - { - Code = code, - Error = error - })); - return HttpContext.HtmlResponseAsync(((TokenSwapAuth) auth).HtmlResponse); - } + _accessTokenExpireTimer = new System.Timers.Timer + { + Enabled = true, + Interval = token.ExpiresIn * 1000, + AutoReset = false + }; + _accessTokenExpireTimer.Elapsed += (sender, e) => OnAccessTokenExpired?.Invoke(this, EventArgs.Empty); } + + /// + /// Uses the authorization code to silently (doesn't open a browser) obtain both an access token and refresh token, where the refresh token would be required for you to use . + /// + /// + /// + public async Task ExchangeCodeAsync(string authorizationCode) + { + Token token = await GetToken("authorization_code", authorizationCode : authorizationCode); + if (token != null && !token.HasError() && !string.IsNullOrEmpty(token.AccessToken)) + { + SetAccessExpireTimer(token); + } + + return token; + } + + /// + /// Uses the refresh token to silently (doesn't open a browser) obtain a fresh access token, no refresh token is given however (as it does not change). + /// + /// + /// + public async Task RefreshAuthAsync(string refreshToken) + { + Token token = await GetToken("refresh_token", refreshToken : refreshToken); + if (token != null && !token.HasError() && !string.IsNullOrEmpty(token.AccessToken)) + { + SetAccessExpireTimer(token); + } + + return token; + } + } + + internal class TokenSwapAuthController : WebApiController + { + public TokenSwapAuthController(IHttpContext context) : base(context) + { } + + [WebApiHandler(HttpVerbs.Get, "/auth")] + public Task GetAuth() + { + string state = Request.QueryString["state"]; + SpotifyAuthServer auth = TokenSwapAuth.GetByState(state); + + string code = null; + string error = Request.QueryString["error"]; + if (error == null) + { + code = Request.QueryString["code"]; + } + + Task.Factory.StartNew(() => auth?.TriggerAuth(new AuthorizationCode + { + Code = code, + Error = error + })); + return HttpContext.HtmlResponseAsync(((TokenSwapAuth) auth).HtmlResponse); + } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web.Auth/TokenSwapWebAPIFactory.cs b/SpotifyAPI.Web.Auth/TokenSwapWebAPIFactory.cs index 11f47485..604be245 100644 --- a/SpotifyAPI.Web.Auth/TokenSwapWebAPIFactory.cs +++ b/SpotifyAPI.Web.Auth/TokenSwapWebAPIFactory.cs @@ -1,282 +1,280 @@ -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; +using SpotifyAPI.Web.Enums; +using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web.Auth { + /// + /// Returns a using the TokenSwapAuth process. + /// + public class TokenSwapWebAPIFactory + { /// - /// Returns a using the TokenSwapAuth process. + /// Access provided by Spotify expires after 1 hour. If true, will time the access tokens, and access will attempt to be silently (without opening a browser) refreshed automatically. This will not make fire, see for that. /// - public class TokenSwapWebAPIFactory + public bool AutoRefresh { get; set; } + /// + /// If true when calling , will time how long it takes for access to Spotify to expire. The event fires when the timer elapses. + /// + public bool TimeAccessExpiry { get; set; } + /// + /// The maximum time in seconds to wait for a SpotifyWebAPI to be returned. The timeout is cancelled early regardless if an auth success or failure occured. + /// + public int Timeout { get; set; } + public Scope Scope { get; set; } + /// + /// The URI (or URL) of the exchange server which exchanges the auth code for access and refresh tokens. + /// + public string ExchangeServerUri { get; set; } + /// + /// The URI (or URL) of where a callback server to receive the auth code will be hosted. e.g. http://localhost:4002 + /// + public string HostServerUri { get; set; } + /// + /// Opens the user's browser and visits the exchange server for you, triggering the key exchange. This should be true unless you want to handle the key exchange in a nicer way. + /// + public bool OpenBrowser { get; set; } + /// + /// The HTML to respond with when the callback server has been reached. By default, it is set to close the window on arrival. + /// + public string HtmlResponse { get; set; } + /// + /// Whether or not to show a dialog saying "Is this you?" during the initial key exchange. It should be noted that this would allow a user the opportunity to change accounts. + /// + public bool ShowDialog { get; set; } + /// + /// The maximum amount of times to retry getting a token. + /// + /// A token get is attempted every time you and . Increasing this may improve how often these actions succeed - although it won't solve any underlying problems causing a get token failure. + /// + public int MaxGetTokenRetries { get; set; } = 10; + /// + /// Returns a SpotifyWebAPI using the TokenSwapAuth process. + /// + /// The URI (or URL) of the exchange server which exchanges the auth code for access and refresh tokens. + /// + /// The URI (or URL) of where a callback server to receive the auth code will be hosted. e.g. http://localhost:4002 + /// The maximum time in seconds to wait for a SpotifyWebAPI to be returned. The timeout is cancelled early regardless if an auth success or failure occured. + /// Access provided by Spotify expires after 1 hour. If true, access will attempt to be silently (without opening a browser) refreshed automatically. + /// Opens the user's browser and visits the exchange server for you, triggering the key exchange. This should be true unless you want to handle the key exchange in a nicer way. + public TokenSwapWebAPIFactory(string exchangeServerUri, Scope scope = Scope.None, string hostServerUri = "http://localhost:4002", int timeout = 10, bool autoRefresh = false, bool openBrowser = true) { - /// - /// Access provided by Spotify expires after 1 hour. If true, will time the access tokens, and access will attempt to be silently (without opening a browser) refreshed automatically. This will not make fire, see for that. - /// - public bool AutoRefresh { get; set; } - /// - /// If true when calling , will time how long it takes for access to Spotify to expire. The event fires when the timer elapses. - /// - public bool TimeAccessExpiry { get; set; } - /// - /// The maximum time in seconds to wait for a SpotifyWebAPI to be returned. The timeout is cancelled early regardless if an auth success or failure occured. - /// - public int Timeout { get; set; } - public Scope Scope { get; set; } - /// - /// The URI (or URL) of the exchange server which exchanges the auth code for access and refresh tokens. - /// - public string ExchangeServerUri { get; set; } - /// - /// The URI (or URL) of where a callback server to receive the auth code will be hosted. e.g. http://localhost:4002 - /// - public string HostServerUri { get; set; } - /// - /// Opens the user's browser and visits the exchange server for you, triggering the key exchange. This should be true unless you want to handle the key exchange in a nicer way. - /// - public bool OpenBrowser { get; set; } - /// - /// The HTML to respond with when the callback server has been reached. By default, it is set to close the window on arrival. - /// - public string HtmlResponse { get; set; } - /// - /// Whether or not to show a dialog saying "Is this you?" during the initial key exchange. It should be noted that this would allow a user the opportunity to change accounts. - /// - public bool ShowDialog { get; set; } - /// - /// The maximum amount of times to retry getting a token. - /// - /// A token get is attempted every time you and . Increasing this may improve how often these actions succeed - although it won't solve any underlying problems causing a get token failure. - /// - public int MaxGetTokenRetries { get; set; } = 10; - /// - /// Returns a SpotifyWebAPI using the TokenSwapAuth process. - /// - /// The URI (or URL) of the exchange server which exchanges the auth code for access and refresh tokens. - /// - /// The URI (or URL) of where a callback server to receive the auth code will be hosted. e.g. http://localhost:4002 - /// The maximum time in seconds to wait for a SpotifyWebAPI to be returned. The timeout is cancelled early regardless if an auth success or failure occured. - /// Access provided by Spotify expires after 1 hour. If true, access will attempt to be silently (without opening a browser) refreshed automatically. - /// Opens the user's browser and visits the exchange server for you, triggering the key exchange. This should be true unless you want to handle the key exchange in a nicer way. - public TokenSwapWebAPIFactory(string exchangeServerUri, Scope scope = Scope.None, string hostServerUri = "http://localhost:4002", int timeout = 10, bool autoRefresh = false, bool openBrowser = true) + AutoRefresh = autoRefresh; + Timeout = timeout; + Scope = scope; + ExchangeServerUri = exchangeServerUri; + HostServerUri = hostServerUri; + OpenBrowser = openBrowser; + + OnAccessTokenExpired += async(sender, e) => + { + if (AutoRefresh) { - AutoRefresh = autoRefresh; - Timeout = timeout; - Scope = scope; - ExchangeServerUri = exchangeServerUri; - HostServerUri = hostServerUri; - OpenBrowser = openBrowser; - - OnAccessTokenExpired += async (sender, e) => - { - if (AutoRefresh) - { - await RefreshAuthAsync(); - } - }; - } - - Token lastToken; - SpotifyWebAPI lastWebApi; - TokenSwapAuth lastAuth; - - public class ExchangeReadyEventArgs : EventArgs - { - public string ExchangeUri { get; set; } - } - /// - /// When the URI to get an authorization code is ready to be used to be visited. Not required if is true as the exchange URI will automatically be visited for you. - /// - public event EventHandler OnExchangeReady; - - /// - /// Refreshes the access for a SpotifyWebAPI returned by this factory. - /// - /// - public async Task RefreshAuthAsync() - { - Token token = await lastAuth.RefreshAuthAsync(lastToken.RefreshToken); - - if (token == null) - { - OnAuthFailure?.Invoke(this, new AuthFailureEventArgs($"Token not returned by server.")); - } - else if (token.HasError()) - { - OnAuthFailure?.Invoke(this, new AuthFailureEventArgs($"{token.Error} {token.ErrorDescription}")); - } - else if (string.IsNullOrEmpty(token.AccessToken)) - { - OnAuthFailure?.Invoke(this, new AuthFailureEventArgs("Token had no access token attached.")); - } - else - { - lastWebApi.AccessToken = token.AccessToken; - OnAuthSuccess?.Invoke(this, new AuthSuccessEventArgs()); - } - } - - // By defining empty EventArgs objects, you can specify additional information later on as you see fit and it won't - // be considered a breaking change to consumers of this API. - // - // They don't even need to be constructed for their associated events to be invoked - just pass the static Empty property. - public class AccessTokenExpiredEventArgs : EventArgs - { - public static new AccessTokenExpiredEventArgs Empty { get; } = new AccessTokenExpiredEventArgs(); - - public AccessTokenExpiredEventArgs() - { - } - } - /// - /// When the authorization from Spotify expires. This will only occur if is true. - /// - public event EventHandler OnAccessTokenExpired; - - public class AuthSuccessEventArgs : EventArgs - { - public static new AuthSuccessEventArgs Empty { get; } = new AuthSuccessEventArgs(); - - public AuthSuccessEventArgs() - { - } - } - /// - /// When an authorization attempt succeeds and gains authorization. - /// - public event EventHandler OnAuthSuccess; - - public class AuthFailureEventArgs : EventArgs - { - public static new AuthFailureEventArgs Empty { get; } = new AuthFailureEventArgs(""); - - public string Error { get; } - - public AuthFailureEventArgs(string error) - { - Error = error; - } - } - /// - /// When an authorization attempt fails to gain authorization. - /// - public event EventHandler OnAuthFailure; - - /// - /// Manually triggers the timeout for any ongoing get web API request. - /// - public void CancelGetWebApiRequest() - { - if (webApiTimeoutTimer == null) return; - - // The while loop in GetWebApiSync() will react and trigger the timeout. - webApiTimeoutTimer.Stop(); - webApiTimeoutTimer.Dispose(); - webApiTimeoutTimer = null; - } - - System.Timers.Timer webApiTimeoutTimer; - - /// - /// Gets an authorized and ready to use SpotifyWebAPI by following the SecureAuthorizationCodeAuth process with its current settings. - /// - /// - public async Task GetWebApiAsync() - { - return await Task.Factory.StartNew(() => - { - bool currentlyAuthorizing = true; - - // Cancel any ongoing get web API requests - CancelGetWebApiRequest(); - - lastAuth = new TokenSwapAuth( - exchangeServerUri: ExchangeServerUri, - serverUri: HostServerUri, - scope: Scope, - htmlResponse: HtmlResponse) - { - ShowDialog = ShowDialog, - MaxGetTokenRetries = MaxGetTokenRetries, - TimeAccessExpiry = AutoRefresh || TimeAccessExpiry - }; - lastAuth.AuthReceived += async (sender, response) => - { - if (!string.IsNullOrEmpty(response.Error) || string.IsNullOrEmpty(response.Code)) - { - // We only want one auth failure to be fired, if the request timed out then don't bother. - if (!webApiTimeoutTimer.Enabled) return; - - OnAuthFailure?.Invoke(this, new AuthFailureEventArgs(response.Error)); - currentlyAuthorizing = false; - return; - } - - lastToken = await lastAuth.ExchangeCodeAsync(response.Code); - - if (lastToken == null || lastToken.HasError() || string.IsNullOrEmpty(lastToken.AccessToken)) - { - // We only want one auth failure to be fired, if the request timed out then don't bother. - if (!webApiTimeoutTimer.Enabled) return; - - OnAuthFailure?.Invoke(this, new AuthFailureEventArgs("Exchange token not returned by server.")); - currentlyAuthorizing = false; - return; - } - - if (lastWebApi != null) - { - lastWebApi.Dispose(); - } - lastWebApi = new SpotifyWebAPI() - { - TokenType = lastToken.TokenType, - AccessToken = lastToken.AccessToken - }; - - lastAuth.Stop(); - - OnAuthSuccess?.Invoke(this, AuthSuccessEventArgs.Empty); - currentlyAuthorizing = false; - }; - lastAuth.OnAccessTokenExpired += async (sender, e) => - { - if (TimeAccessExpiry) - { - OnAccessTokenExpired?.Invoke(sender, AccessTokenExpiredEventArgs.Empty); - } - - if (AutoRefresh) - { - await RefreshAuthAsync(); - } - }; - lastAuth.Start(); - OnExchangeReady?.Invoke(this, new ExchangeReadyEventArgs { ExchangeUri = lastAuth.GetUri() }); - if (OpenBrowser) - { - lastAuth.OpenBrowser(); - } - - webApiTimeoutTimer = new System.Timers.Timer - { - AutoReset = false, - Enabled = true, - Interval = Timeout * 1000 - }; - - while (currentlyAuthorizing && webApiTimeoutTimer.Enabled) ; - - // If a timeout occurred - if (lastWebApi == null && currentlyAuthorizing) - { - OnAuthFailure?.Invoke(this, new AuthFailureEventArgs("Authorization request has timed out.")); - } - - return lastWebApi; - }); + await RefreshAuthAsync(); } + }; } -} + + Token lastToken; + SpotifyWebAPI lastWebApi; + TokenSwapAuth lastAuth; + + public class ExchangeReadyEventArgs : EventArgs + { + public string ExchangeUri { get; set; } + } + /// + /// When the URI to get an authorization code is ready to be used to be visited. Not required if is true as the exchange URI will automatically be visited for you. + /// + public event EventHandler OnExchangeReady; + + /// + /// Refreshes the access for a SpotifyWebAPI returned by this factory. + /// + /// + public async Task RefreshAuthAsync() + { + Token token = await lastAuth.RefreshAuthAsync(lastToken.RefreshToken); + + if (token == null) + { + OnAuthFailure?.Invoke(this, new AuthFailureEventArgs($"Token not returned by server.")); + } + else if (token.HasError()) + { + OnAuthFailure?.Invoke(this, new AuthFailureEventArgs($"{token.Error} {token.ErrorDescription}")); + } + else if (string.IsNullOrEmpty(token.AccessToken)) + { + OnAuthFailure?.Invoke(this, new AuthFailureEventArgs("Token had no access token attached.")); + } + else + { + lastWebApi.AccessToken = token.AccessToken; + OnAuthSuccess?.Invoke(this, new AuthSuccessEventArgs()); + } + } + + // By defining empty EventArgs objects, you can specify additional information later on as you see fit and it won't + // be considered a breaking change to consumers of this API. + // + // They don't even need to be constructed for their associated events to be invoked - just pass the static Empty property. + public class AccessTokenExpiredEventArgs : EventArgs + { + public static new AccessTokenExpiredEventArgs Empty { get; } = new AccessTokenExpiredEventArgs(); + + public AccessTokenExpiredEventArgs() + { } + } + /// + /// When the authorization from Spotify expires. This will only occur if is true. + /// + public event EventHandler OnAccessTokenExpired; + + public class AuthSuccessEventArgs : EventArgs + { + public static new AuthSuccessEventArgs Empty { get; } = new AuthSuccessEventArgs(); + + public AuthSuccessEventArgs() + { } + } + /// + /// When an authorization attempt succeeds and gains authorization. + /// + public event EventHandler OnAuthSuccess; + + public class AuthFailureEventArgs : EventArgs + { + public static new AuthFailureEventArgs Empty { get; } = new AuthFailureEventArgs(""); + + public string Error { get; } + + public AuthFailureEventArgs(string error) + { + Error = error; + } + } + /// + /// When an authorization attempt fails to gain authorization. + /// + public event EventHandler OnAuthFailure; + + /// + /// Manually triggers the timeout for any ongoing get web API request. + /// + public void CancelGetWebApiRequest() + { + if (webApiTimeoutTimer == null) return; + + // The while loop in GetWebApiSync() will react and trigger the timeout. + webApiTimeoutTimer.Stop(); + webApiTimeoutTimer.Dispose(); + webApiTimeoutTimer = null; + } + + System.Timers.Timer webApiTimeoutTimer; + + /// + /// Gets an authorized and ready to use SpotifyWebAPI by following the SecureAuthorizationCodeAuth process with its current settings. + /// + /// + public async Task GetWebApiAsync() + { + return await Task.Factory.StartNew(() => + { + bool currentlyAuthorizing = true; + + // Cancel any ongoing get web API requests + CancelGetWebApiRequest(); + + lastAuth = new TokenSwapAuth( + exchangeServerUri: ExchangeServerUri, + serverUri: HostServerUri, + scope: Scope, + htmlResponse: HtmlResponse) + { + ShowDialog = ShowDialog, + MaxGetTokenRetries = MaxGetTokenRetries, + TimeAccessExpiry = AutoRefresh || TimeAccessExpiry + }; + lastAuth.AuthReceived += async(sender, response) => + { + if (!string.IsNullOrEmpty(response.Error) || string.IsNullOrEmpty(response.Code)) + { + // We only want one auth failure to be fired, if the request timed out then don't bother. + if (!webApiTimeoutTimer.Enabled) return; + + OnAuthFailure?.Invoke(this, new AuthFailureEventArgs(response.Error)); + currentlyAuthorizing = false; + return; + } + + lastToken = await lastAuth.ExchangeCodeAsync(response.Code); + + if (lastToken == null || lastToken.HasError() || string.IsNullOrEmpty(lastToken.AccessToken)) + { + // We only want one auth failure to be fired, if the request timed out then don't bother. + if (!webApiTimeoutTimer.Enabled) return; + + OnAuthFailure?.Invoke(this, new AuthFailureEventArgs("Exchange token not returned by server.")); + currentlyAuthorizing = false; + return; + } + + if (lastWebApi != null) + { + lastWebApi.Dispose(); + } + lastWebApi = new SpotifyWebAPI() + { + TokenType = lastToken.TokenType, + AccessToken = lastToken.AccessToken + }; + + lastAuth.Stop(); + + OnAuthSuccess?.Invoke(this, AuthSuccessEventArgs.Empty); + currentlyAuthorizing = false; + }; + lastAuth.OnAccessTokenExpired += async(sender, e) => + { + if (TimeAccessExpiry) + { + OnAccessTokenExpired?.Invoke(sender, AccessTokenExpiredEventArgs.Empty); + } + + if (AutoRefresh) + { + await RefreshAuthAsync(); + } + }; + lastAuth.Start(); + OnExchangeReady?.Invoke(this, new ExchangeReadyEventArgs { ExchangeUri = lastAuth.GetUri() }); + if (OpenBrowser) + { + lastAuth.OpenBrowser(); + } + + webApiTimeoutTimer = new System.Timers.Timer + { + AutoReset = false, + Enabled = true, + Interval = Timeout * 1000 + }; + + while (currentlyAuthorizing && webApiTimeoutTimer.Enabled); + + // If a timeout occurred + if (lastWebApi == null && currentlyAuthorizing) + { + OnAuthFailure?.Invoke(this, new AuthFailureEventArgs("Authorization request has timed out.")); + } + + return lastWebApi; + }); + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Examples.ASP/Controllers/HomeController.cs b/SpotifyAPI.Web.Examples.ASP/Controllers/HomeController.cs index 8eb7c806..cce16ad4 100644 --- a/SpotifyAPI.Web.Examples.ASP/Controllers/HomeController.cs +++ b/SpotifyAPI.Web.Examples.ASP/Controllers/HomeController.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; @@ -7,27 +7,27 @@ using SpotifyAPI.Web.Examples.ASP.Models; namespace SpotifyAPI.Web.Examples.ASP.Controllers { - [Authorize(AuthenticationSchemes = "Spotify")] - public class HomeController : Controller + [Authorize(AuthenticationSchemes = "Spotify")] + public class HomeController : Controller + { + public async Task Index() { - public async Task Index() - { - var accessToken = await HttpContext.GetTokenAsync("Spotify", "access_token"); - SpotifyWebAPI api = new SpotifyWebAPI - { - AccessToken = accessToken, - TokenType = "Bearer" - }; + var accessToken = await HttpContext.GetTokenAsync("Spotify", "access_token"); + SpotifyWebAPI api = new SpotifyWebAPI + { + AccessToken = accessToken, + TokenType = "Bearer" + }; - var savedTracks = await api.GetSavedTracksAsync(50); + var savedTracks = await api.GetSavedTracksAsync(50); - return View(new IndexModel { SavedTracks = savedTracks }); - } - - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public IActionResult Error() - { - return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); - } + return View(new IndexModel { SavedTracks = savedTracks }); } -} + + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Examples.ASP/Models/ErrorViewModel.cs b/SpotifyAPI.Web.Examples.ASP/Models/ErrorViewModel.cs index e7e3c079..1fcd1aea 100644 --- a/SpotifyAPI.Web.Examples.ASP/Models/ErrorViewModel.cs +++ b/SpotifyAPI.Web.Examples.ASP/Models/ErrorViewModel.cs @@ -2,10 +2,10 @@ using System; namespace SpotifyAPI.Web.Examples.ASP.Models { - public class ErrorViewModel - { - public string RequestId { get; set; } + public class ErrorViewModel + { + public string RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - } -} + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Examples.ASP/Models/IndexModel.cs b/SpotifyAPI.Web.Examples.ASP/Models/IndexModel.cs index 149e1497..15f04055 100644 --- a/SpotifyAPI.Web.Examples.ASP/Models/IndexModel.cs +++ b/SpotifyAPI.Web.Examples.ASP/Models/IndexModel.cs @@ -3,8 +3,8 @@ using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web.Examples.ASP.Models { - public class IndexModel - { - public Paging SavedTracks; - } -} + public class IndexModel + { + public Paging SavedTracks; + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Examples.ASP/Program.cs b/SpotifyAPI.Web.Examples.ASP/Program.cs index a8acd307..05dbcc74 100644 --- a/SpotifyAPI.Web.Examples.ASP/Program.cs +++ b/SpotifyAPI.Web.Examples.ASP/Program.cs @@ -9,18 +9,18 @@ using Microsoft.Extensions.Logging; namespace SpotifyAPI.Web.Examples.ASP { - public class Program + public class Program + { + public static void Main(string[] args) { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); + CreateHostBuilder(args).Build().Run(); } -} + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Examples.ASP/Startup.cs b/SpotifyAPI.Web.Examples.ASP/Startup.cs index 78d46c8e..43167411 100644 --- a/SpotifyAPI.Web.Examples.ASP/Startup.cs +++ b/SpotifyAPI.Web.Examples.ASP/Startup.cs @@ -8,61 +8,61 @@ using SpotifyAPI.Web.Enums; namespace SpotifyAPI.Web.Examples.ASP { - public class Startup + public class Startup + { + public Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllersWithViews(); - - services.AddAuthentication(o => o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme) - .AddCookie() - .AddSpotify(options => - { - var scopes = Scope.UserLibraryRead; - options.Scope.Add(scopes.GetStringAttribute(",")); - - options.SaveTokens = true; - options.ClientId = Configuration["client_id"]; - options.ClientSecret = Configuration["client_secret"]; - options.CallbackPath = "/callback"; - }); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - // app.UseHttpsRedirection(); - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } + Configuration = configuration; } -} + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllersWithViews(); + + services.AddAuthentication(o => o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie() + .AddSpotify(options => + { + var scopes = Scope.UserLibraryRead | Scope.UserModifyPlaybackState; + options.Scope.Add(scopes.GetStringAttribute(",")); + + options.SaveTokens = true; + options.ClientId = Configuration["client_id"]; + options.ClientSecret = Configuration["client_secret"]; + options.CallbackPath = "/callback"; + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + // app.UseHttpsRedirection(); + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web.Examples.CLI/Program.cs b/SpotifyAPI.Web.Examples.CLI/Program.cs index 43668888..eeb2b607 100644 --- a/SpotifyAPI.Web.Examples.CLI/Program.cs +++ b/SpotifyAPI.Web.Examples.CLI/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; using SpotifyAPI.Web.Auth; using SpotifyAPI.Web.Enums; @@ -6,72 +6,70 @@ using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web.Examples.CLI { - internal static class Program + internal static class Program + { + private static string _clientId = ""; //""; + private static string _secretId = ""; //""; + + // ReSharper disable once UnusedParameter.Local + public static void Main(string[] args) { - private static string _clientId = ""; //""; - private static string _secretId = ""; //""; + _clientId = string.IsNullOrEmpty(_clientId) ? + Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_ID") : + _clientId; - // ReSharper disable once UnusedParameter.Local - public static void Main(string[] args) - { - _clientId = string.IsNullOrEmpty(_clientId) - ? Environment.GetEnvironmentVariable("SPOTIFY_CLIENT_ID") - : _clientId; + _secretId = string.IsNullOrEmpty(_secretId) ? + Environment.GetEnvironmentVariable("SPOTIFY_SECRET_ID") : + _secretId; - _secretId = string.IsNullOrEmpty(_secretId) - ? Environment.GetEnvironmentVariable("SPOTIFY_SECRET_ID") - : _secretId; + Console.WriteLine("####### Spotify API Example #######"); + Console.WriteLine("This example uses AuthorizationCodeAuth."); + Console.WriteLine( + "Tip: If you want to supply your ClientID and SecretId beforehand, use env variables (SPOTIFY_CLIENT_ID and SPOTIFY_SECRET_ID)"); - Console.WriteLine("####### Spotify API Example #######"); - Console.WriteLine("This example uses AuthorizationCodeAuth."); - Console.WriteLine( - "Tip: If you want to supply your ClientID and SecretId beforehand, use env variables (SPOTIFY_CLIENT_ID and SPOTIFY_SECRET_ID)"); + var auth = + new AuthorizationCodeAuth(_clientId, _secretId, "http://localhost:4002", "http://localhost:4002", + Scope.PlaylistReadPrivate | Scope.PlaylistReadCollaborative); + auth.AuthReceived += AuthOnAuthReceived; + auth.Start(); + auth.OpenBrowser(); - var auth = - new AuthorizationCodeAuth(_clientId, _secretId, "http://localhost:4002", "http://localhost:4002", - Scope.PlaylistReadPrivate | Scope.PlaylistReadCollaborative); - auth.AuthReceived += AuthOnAuthReceived; - auth.Start(); - auth.OpenBrowser(); + Console.ReadLine(); + auth.Stop(0); - Console.ReadLine(); - auth.Stop(0); - - - - } - - private static async void AuthOnAuthReceived(object sender, AuthorizationCode payload) - { - var auth = (AuthorizationCodeAuth) sender; - auth.Stop(); - - Token token = await auth.ExchangeCode(payload.Code); - var api = new SpotifyWebAPI - { - AccessToken = token.AccessToken, - TokenType = token.TokenType - }; - await PrintUsefulData(api); - } - - private static async Task PrintAllPlaylistTracks(SpotifyWebAPI api, Paging playlists) - { - if (playlists.Items == null) return; - - playlists.Items.ForEach(playlist => Console.WriteLine($"- {playlist.Name}")); - if(playlists.HasNextPage()) - await PrintAllPlaylistTracks(api, await api.GetNextPageAsync(playlists)); - } - - private static async Task PrintUsefulData(SpotifyWebAPI api) - { - PrivateProfile profile = await api.GetPrivateProfileAsync(); - string name = string.IsNullOrEmpty(profile.DisplayName) ? profile.Id : profile.DisplayName; - Console.WriteLine($"Hello there, {name}!"); - - Console.WriteLine("Your playlists:"); - await PrintAllPlaylistTracks(api, api.GetUserPlaylists(profile.Id)); - } } + + private static async void AuthOnAuthReceived(object sender, AuthorizationCode payload) + { + var auth = (AuthorizationCodeAuth) sender; + auth.Stop(); + + Token token = await auth.ExchangeCode(payload.Code); + var api = new SpotifyWebAPI + { + AccessToken = token.AccessToken, + TokenType = token.TokenType + }; + await PrintUsefulData(api); + } + + private static async Task PrintAllPlaylistTracks(SpotifyWebAPI api, Paging playlists) + { + if (playlists.Items == null) return; + + playlists.Items.ForEach(playlist => Console.WriteLine($"- {playlist.Name}")); + if (playlists.HasNextPage()) + await PrintAllPlaylistTracks(api, await api.GetNextPageAsync(playlists)); + } + + private static async Task PrintUsefulData(SpotifyWebAPI api) + { + PrivateProfile profile = await api.GetPrivateProfileAsync(); + string name = string.IsNullOrEmpty(profile.DisplayName) ? profile.Id : profile.DisplayName; + Console.WriteLine($"Hello there, {name}!"); + + Console.WriteLine("Your playlists:"); + await PrintAllPlaylistTracks(api, api.GetUserPlaylists(profile.Id)); + } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web.Tests/ProxyConfigTest.cs b/SpotifyAPI.Web.Tests/ProxyConfigTest.cs index bc32e046..3ab9897c 100644 --- a/SpotifyAPI.Web.Tests/ProxyConfigTest.cs +++ b/SpotifyAPI.Web.Tests/ProxyConfigTest.cs @@ -1,116 +1,116 @@ -using System; +using System; using NUnit.Framework; namespace SpotifyAPI.Web.Tests { - [TestFixture] - public class ProxyConfigTest + [TestFixture] + public class ProxyConfigTest + { + #region GetUri + + [Test] + public void GetUri_HostNameWithScheme() { - #region GetUri - - [Test] - public void GetUri_HostNameWithScheme() - { - ProxyConfig config = new ProxyConfig { Host = "https://test-host.com" }; - CheckUri(config.GetUri(), "https", "test-host.com", 80); - } - - [Test] - public void GetUri_HostNameWithoutScheme() - { - ProxyConfig config = new ProxyConfig { Host = "test-host.com" }; - CheckUri(config.GetUri(), "http", "test-host.com", 80); - } - - [Test] - public void GetUri_HostNameWithSchemeAndPort() - { - ProxyConfig config = new ProxyConfig - { - Host = "https://test-host.com", - Port = 8080 - }; - CheckUri(config.GetUri(), "https", "test-host.com", 8080); - } - - [Test] - public void GetUri_HostAddressWithScheme() - { - ProxyConfig config = new ProxyConfig { Host = "https://192.168.0.1" }; - CheckUri(config.GetUri(), "https", "192.168.0.1", 80); - } - - [Test] - public void GetUri_HostAddressWithoutScheme() - { - ProxyConfig config = new ProxyConfig { Host = "192.168.0.1" }; - CheckUri(config.GetUri(), "http", "192.168.0.1", 80); - } - - [Test] - public void GetUri_HostAddressWithSchemeAndPort() - { - ProxyConfig config = new ProxyConfig - { - Host = "https://192.168.0.1", - Port = 8080 - }; - CheckUri(config.GetUri(), "https", "192.168.0.1", 8080); - } - - [Test] - public void GetUri_NullHost() - { - ProxyConfig config = new ProxyConfig { Host = null }; - Assert.Throws(() => config.GetUri()); - } - - [Test] - public void GetUri_EmptyHost() - { - ProxyConfig config = new ProxyConfig { Host = string.Empty }; - Assert.Throws(() => config.GetUri()); - } - - [Test] - public void GetUri_NegativePort() - { - ProxyConfig config = new ProxyConfig - { - Host = "test-host.com", - Port = -10 - }; - Assert.Throws(() => config.GetUri()); - } - - #endregion GetUri - - [Test] - public void Set_Null() - { - ProxyConfig config = new ProxyConfig - { - Host = "https://test-host.com", - Port = 1234, - Username = "admin", - Password = "password", - BypassProxyOnLocal = true - }; - config.Set(null); - - Assert.NotNull(config); - Assert.Null(config.Host); - Assert.AreEqual(80, config.Port); - Assert.Null(config.Username); - Assert.Null(config.Password); - Assert.False(config.BypassProxyOnLocal); - } - - private static void CheckUri(Uri uri, string expectedScheme, string expectedHost, int expectedPort) - { - Assert.AreEqual(expectedScheme, uri.Scheme); - Assert.AreEqual(expectedHost, uri.Host); - Assert.AreEqual(expectedPort, uri.Port); - } + ProxyConfig config = new ProxyConfig { Host = "https://test-host.com" }; + CheckUri(config.GetUri(), "https", "test-host.com", 80); } -} \ No newline at end of file + + [Test] + public void GetUri_HostNameWithoutScheme() + { + ProxyConfig config = new ProxyConfig { Host = "test-host.com" }; + CheckUri(config.GetUri(), "http", "test-host.com", 80); + } + + [Test] + public void GetUri_HostNameWithSchemeAndPort() + { + ProxyConfig config = new ProxyConfig + { + Host = "https://test-host.com", + Port = 8080 + }; + CheckUri(config.GetUri(), "https", "test-host.com", 8080); + } + + [Test] + public void GetUri_HostAddressWithScheme() + { + ProxyConfig config = new ProxyConfig { Host = "https://192.168.0.1" }; + CheckUri(config.GetUri(), "https", "192.168.0.1", 80); + } + + [Test] + public void GetUri_HostAddressWithoutScheme() + { + ProxyConfig config = new ProxyConfig { Host = "192.168.0.1" }; + CheckUri(config.GetUri(), "http", "192.168.0.1", 80); + } + + [Test] + public void GetUri_HostAddressWithSchemeAndPort() + { + ProxyConfig config = new ProxyConfig + { + Host = "https://192.168.0.1", + Port = 8080 + }; + CheckUri(config.GetUri(), "https", "192.168.0.1", 8080); + } + + [Test] + public void GetUri_NullHost() + { + ProxyConfig config = new ProxyConfig { Host = null }; + Assert.Throws(() => config.GetUri()); + } + + [Test] + public void GetUri_EmptyHost() + { + ProxyConfig config = new ProxyConfig { Host = string.Empty }; + Assert.Throws(() => config.GetUri()); + } + + [Test] + public void GetUri_NegativePort() + { + ProxyConfig config = new ProxyConfig + { + Host = "test-host.com", + Port = -10 + }; + Assert.Throws(() => config.GetUri()); + } + + #endregion GetUri + + [Test] + public void Set_Null() + { + ProxyConfig config = new ProxyConfig + { + Host = "https://test-host.com", + Port = 1234, + Username = "admin", + Password = "password", + BypassProxyOnLocal = true + }; + config.Set(null); + + Assert.NotNull(config); + Assert.Null(config.Host); + Assert.AreEqual(80, config.Port); + Assert.Null(config.Username); + Assert.Null(config.Password); + Assert.False(config.BypassProxyOnLocal); + } + + private static void CheckUri(Uri uri, string expectedScheme, string expectedHost, int expectedPort) + { + Assert.AreEqual(expectedScheme, uri.Scheme); + Assert.AreEqual(expectedHost, uri.Host); + Assert.AreEqual(expectedPort, uri.Port); + } + } +} diff --git a/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj b/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj index 804d24d7..b42819bb 100644 --- a/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj +++ b/SpotifyAPI.Web.Tests/SpotifyAPI.Web.Tests.csproj @@ -1,8 +1,7 @@  - netcoreapp2.0 - + netcoreapp3.1 false diff --git a/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs b/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs index d00e5e3a..48c598c0 100644 --- a/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs +++ b/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -9,72 +9,71 @@ using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web.Tests { - [TestFixture] - public class SpotifyWebAPITest + [TestFixture] + public class SpotifyWebAPITest + { + private static readonly string FixtureDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../fixtures/"); + + private Mock _mock; + private SpotifyWebAPI _spotify; + + [SetUp] + public void SetUp() { - private static readonly string FixtureDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../fixtures/"); - - private Mock _mock; - private SpotifyWebAPI _spotify; - - [SetUp] - public void SetUp() - { - _mock = new Mock(); - _spotify = new SpotifyWebAPI - { - WebClient = _mock.Object, - UseAuth = false - }; - } - - private static T GetFixture(string file) - { - return JsonConvert.DeserializeObject(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(() => _spotify.GetPrivateProfile()); - } - - [Test] - public void ShouldGetPrivateProfile_WithAuth() - { - PrivateProfile profile = GetFixture("private-user.json"); - _mock.Setup(client => client.DownloadJson(It.IsAny(), It.IsAny>())) - .Returns(new Tuple(ResponseInfo.Empty, profile)); - - _spotify.UseAuth = true; - Assert.AreEqual(profile, _spotify.GetPrivateProfile()); - _mock.Verify(client => client.DownloadJson( - It.Is(str => ContainsValues(str, "/me")), - It.IsNotNull>()), Times.Exactly(1)); - } - - [Test] - public void ShouldGetPublicProfile() - { - PublicProfile profile = GetFixture("public-user.json"); - _mock.Setup(client => client.DownloadJson(It.IsAny(), It.IsAny>())) - .Returns(new Tuple(ResponseInfo.Empty, profile)); - - - _spotify.UseAuth = false; - Assert.AreEqual(profile, _spotify.GetPublicProfile("wizzler")); - _mock.Verify(client => client.DownloadJson( - It.Is(str => ContainsValues(str, "/users/wizzler")), - It.Is>(headers => headers.Count == 0)), Times.Exactly(1)); - } - - //Will add more tests once I decided if this is worth the effort (propably not?) + _mock = new Mock(); + _spotify = new SpotifyWebAPI + { + WebClient = _mock.Object, + UseAuth = false + }; } + + private static T GetFixture(string file) + { + return JsonConvert.DeserializeObject(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(() => _spotify.GetPrivateProfile()); + } + + [Test] + public void ShouldGetPrivateProfile_WithAuth() + { + PrivateProfile profile = GetFixture("private-user.json"); + _mock.Setup(client => client.DownloadJson(It.IsAny(), It.IsAny>())) + .Returns(new Tuple(ResponseInfo.Empty, profile)); + + _spotify.UseAuth = true; + Assert.AreEqual(profile, _spotify.GetPrivateProfile()); + _mock.Verify(client => client.DownloadJson( + It.Is(str => ContainsValues(str, "/me")), + It.IsNotNull>()), Times.Exactly(1)); + } + + [Test] + public void ShouldGetPublicProfile() + { + PublicProfile profile = GetFixture("public-user.json"); + _mock.Setup(client => client.DownloadJson(It.IsAny(), It.IsAny>())) + .Returns(new Tuple(ResponseInfo.Empty, profile)); + + _spotify.UseAuth = false; + Assert.AreEqual(profile, _spotify.GetPublicProfile("wizzler")); + _mock.Verify(client => client.DownloadJson( + It.Is(str => ContainsValues(str, "/users/wizzler")), + It.Is>(headers => headers.Count == 0)), Times.Exactly(1)); + } + + //Will add more tests once I decided if this is worth the effort (propably not?) + } } \ No newline at end of file diff --git a/SpotifyAPI.Web.Tests/UtilTest.cs b/SpotifyAPI.Web.Tests/UtilTest.cs index 67c243d1..81c20f1d 100644 --- a/SpotifyAPI.Web.Tests/UtilTest.cs +++ b/SpotifyAPI.Web.Tests/UtilTest.cs @@ -1,18 +1,18 @@ -using System; +using System; using NUnit.Framework; namespace SpotifyAPI.Web.Tests { - [TestFixture] - public class UtilTest + [TestFixture] + public class UtilTest + { + [Test] + public void TimestampShouldBeNoFloatingPoint() { - [Test] - public void TimestampShouldBeNoFloatingPoint() - { - string timestamp = DateTime.Now.ToUnixTimeMillisecondsPoly().ToString(); + string timestamp = DateTime.Now.ToUnixTimeMillisecondsPoly().ToString(); - StringAssert.DoesNotContain(".", timestamp); - StringAssert.DoesNotContain(",", timestamp); - } + StringAssert.DoesNotContain(".", timestamp); + StringAssert.DoesNotContain(",", timestamp); } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/AlbumType.cs b/SpotifyAPI.Web/Enums/AlbumType.cs index c05df333..c8750121 100644 --- a/SpotifyAPI.Web/Enums/AlbumType.cs +++ b/SpotifyAPI.Web/Enums/AlbumType.cs @@ -1,23 +1,23 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - [Flags] - public enum AlbumType - { - [String("album")] - Album = 1, + [Flags] + public enum AlbumType + { + [String("album")] + Album = 1, - [String("single")] - Single = 2, + [String("single")] + Single = 2, - [String("compilation")] - Compilation = 4, + [String("compilation")] + Compilation = 4, - [String("appears_on")] - AppearsOn = 8, + [String("appears_on")] + AppearsOn = 8, - [String("album,single,compilation,appears_on")] - All = 16 - } + [String("album,single,compilation,appears_on")] + All = 16 + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/FollowType.cs b/SpotifyAPI.Web/Enums/FollowType.cs index 6cd802bc..4a1e76be 100644 --- a/SpotifyAPI.Web/Enums/FollowType.cs +++ b/SpotifyAPI.Web/Enums/FollowType.cs @@ -1,14 +1,14 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - [Flags] - public enum FollowType - { - [String("artist")] - Artist = 1, + [Flags] + public enum FollowType + { + [String("artist")] + Artist = 1, - [String("user")] - User = 2 - } + [String("user")] + User = 2 + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/RepeatState.cs b/SpotifyAPI.Web/Enums/RepeatState.cs index d4abcf61..c97be5eb 100644 --- a/SpotifyAPI.Web/Enums/RepeatState.cs +++ b/SpotifyAPI.Web/Enums/RepeatState.cs @@ -1,17 +1,17 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - [Flags] - public enum RepeatState - { - [String("track")] - Track = 1, + [Flags] + public enum RepeatState + { + [String("track")] + Track = 1, - [String("context")] - Context = 2, + [String("context")] + Context = 2, - [String("off")] - Off = 4 - } + [String("off")] + Off = 4 + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/Scope.cs b/SpotifyAPI.Web/Enums/Scope.cs index 5b500b98..bc66bc2c 100644 --- a/SpotifyAPI.Web/Enums/Scope.cs +++ b/SpotifyAPI.Web/Enums/Scope.cs @@ -1,68 +1,68 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - [Flags] - public enum Scope - { - [String("")] - None = 1, + [Flags] + public enum Scope + { + [String("")] + None = 1, - [String("playlist-modify-public")] - PlaylistModifyPublic = 2, + [String("playlist-modify-public")] + PlaylistModifyPublic = 2, - [String("playlist-modify-private")] - PlaylistModifyPrivate = 4, + [String("playlist-modify-private")] + PlaylistModifyPrivate = 4, - [String("playlist-read-private")] - PlaylistReadPrivate = 8, + [String("playlist-read-private")] + PlaylistReadPrivate = 8, - [String("streaming")] - Streaming = 16, + [String("streaming")] + Streaming = 16, - [String("user-read-private")] - UserReadPrivate = 32, + [String("user-read-private")] + UserReadPrivate = 32, - [String("user-read-email")] - UserReadEmail = 64, + [String("user-read-email")] + UserReadEmail = 64, - [String("user-library-read")] - UserLibraryRead = 128, + [String("user-library-read")] + UserLibraryRead = 128, - [String("user-library-modify")] - UserLibraryModify = 256, + [String("user-library-modify")] + UserLibraryModify = 256, - [String("user-follow-modify")] - UserFollowModify = 512, + [String("user-follow-modify")] + UserFollowModify = 512, - [String("user-follow-read")] - UserFollowRead = 1024, + [String("user-follow-read")] + UserFollowRead = 1024, - [String("user-read-birthdate")] - UserReadBirthdate = 2048, + [String("user-read-birthdate")] + UserReadBirthdate = 2048, - [String("user-top-read")] - UserTopRead = 4096, + [String("user-top-read")] + UserTopRead = 4096, - [String("playlist-read-collaborative")] - PlaylistReadCollaborative = 8192, + [String("playlist-read-collaborative")] + PlaylistReadCollaborative = 8192, - [String("user-read-recently-played")] - UserReadRecentlyPlayed = 16384, + [String("user-read-recently-played")] + UserReadRecentlyPlayed = 16384, - [String("user-read-playback-state")] - UserReadPlaybackState = 32768, + [String("user-read-playback-state")] + UserReadPlaybackState = 32768, - [String("user-modify-playback-state")] - UserModifyPlaybackState = 65536, + [String("user-modify-playback-state")] + UserModifyPlaybackState = 65536, - [String("user-read-currently-playing")] - UserReadCurrentlyPlaying = 131072, + [String("user-read-currently-playing")] + UserReadCurrentlyPlaying = 131072, - [String("app-remote-control")] - AppRemoteControl = 262144, + [String("app-remote-control")] + AppRemoteControl = 262144, - [String("ugc-image-upload")] - UgcImageUpload = 524288 - } -} + [String("ugc-image-upload")] + UgcImageUpload = 524288 + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/SearchType.cs b/SpotifyAPI.Web/Enums/SearchType.cs index 652161c1..abf24c0a 100644 --- a/SpotifyAPI.Web/Enums/SearchType.cs +++ b/SpotifyAPI.Web/Enums/SearchType.cs @@ -1,23 +1,23 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - [Flags] - public enum SearchType - { - [String("artist")] - Artist = 1, + [Flags] + public enum SearchType + { + [String("artist")] + Artist = 1, - [String("album")] - Album = 2, + [String("album")] + Album = 2, - [String("track")] - Track = 4, + [String("track")] + Track = 4, - [String("playlist")] - Playlist = 8, + [String("playlist")] + Playlist = 8, - [String("track,album,artist,playlist")] - All = 16 - } + [String("track,album,artist,playlist")] + All = 16 + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/TimeRangeType.cs b/SpotifyAPI.Web/Enums/TimeRangeType.cs index 468a8081..8c5fb4c4 100644 --- a/SpotifyAPI.Web/Enums/TimeRangeType.cs +++ b/SpotifyAPI.Web/Enums/TimeRangeType.cs @@ -1,20 +1,20 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - /// - /// Only one value allowed - /// - [Flags] - public enum TimeRangeType - { - [String("long_term")] - LongTerm = 1, + /// + /// Only one value allowed + /// + [Flags] + public enum TimeRangeType + { + [String("long_term")] + LongTerm = 1, - [String("medium_term")] - MediumTerm = 2, + [String("medium_term")] + MediumTerm = 2, - [String("short_term")] - ShortTerm = 4 - } + [String("short_term")] + ShortTerm = 4 + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Enums/TrackType.cs b/SpotifyAPI.Web/Enums/TrackType.cs index 63c43419..74baea9a 100644 --- a/SpotifyAPI.Web/Enums/TrackType.cs +++ b/SpotifyAPI.Web/Enums/TrackType.cs @@ -1,20 +1,20 @@ -using System; +using System; namespace SpotifyAPI.Web.Enums { - [Flags] - public enum TrackType - { - [String("track")] - Track = 1, + [Flags] + public enum TrackType + { + [String("track")] + Track = 1, - [String("episode")] - Episode = 2, + [String("episode")] + Episode = 2, - [String("ad")] - Ad = 4, + [String("ad")] + Ad = 4, - [String("unknown")] - Unknown = 8 - } + [String("unknown")] + Unknown = 8 + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/IClient.cs b/SpotifyAPI.Web/IClient.cs index c0960a63..7000be23 100644 --- a/SpotifyAPI.Web/IClient.cs +++ b/SpotifyAPI.Web/IClient.cs @@ -1,125 +1,125 @@ -using Newtonsoft.Json; 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; } + public interface IClient : IDisposable + { + JsonSerializerSettings JsonSettings { get; set; } - /// - /// Downloads data from an URL and returns it - /// - /// An URL - /// - /// - Tuple Download(string url, Dictionary headers = null); + /// + /// Downloads data from an URL and returns it + /// + /// An URL + /// + /// + Tuple Download(string url, Dictionary headers = null); - /// - /// Downloads data async from an URL and returns it - /// - /// - /// - /// - Task> DownloadAsync(string url, Dictionary headers = null); + /// + /// Downloads data async from an URL and returns it + /// + /// + /// + /// + Task> DownloadAsync(string url, Dictionary headers = null); - /// - /// Downloads data from an URL and returns it - /// - /// An URL - /// - /// - Tuple DownloadRaw(string url, Dictionary headers = null); + /// + /// Downloads data from an URL and returns it + /// + /// An URL + /// + /// + Tuple DownloadRaw(string url, Dictionary headers = null); - /// - /// Downloads data async from an URL and returns it - /// - /// - /// - /// - Task> DownloadRawAsync(string url, Dictionary headers = null); + /// + /// Downloads data async from an URL and returns it + /// + /// + /// + /// + Task> DownloadRawAsync(string url, Dictionary headers = null); - /// - /// Downloads data from an URL and converts it to an object - /// - /// The Type which the object gets converted to - /// An URL - /// - /// - Tuple DownloadJson(string url, Dictionary headers = null); + /// + /// Downloads data from an URL and converts it to an object + /// + /// The Type which the object gets converted to + /// An URL + /// + /// + Tuple DownloadJson(string url, Dictionary headers = null); - /// - /// Downloads data async from an URL and converts it to an object - /// - /// The Type which the object gets converted to - /// An URL - /// - /// - Task> DownloadJsonAsync(string url, Dictionary headers = null); + /// + /// Downloads data async from an URL and converts it to an object + /// + /// The Type which the object gets converted to + /// An URL + /// + /// + Task> DownloadJsonAsync(string url, Dictionary headers = null); - /// - /// Uploads data from an URL and returns the response - /// - /// An URL - /// The Body-Data (most likely a JSON String) - /// The Upload-method (POST,DELETE,PUT) - /// - /// - Tuple Upload(string url, string body, string method, Dictionary headers = null); + /// + /// Uploads data from an URL and returns the response + /// + /// An URL + /// The Body-Data (most likely a JSON String) + /// The Upload-method (POST,DELETE,PUT) + /// + /// + Tuple Upload(string url, string body, string method, Dictionary headers = null); - /// - /// Uploads data async from an URL and returns the response - /// - /// An URL - /// The Body-Data (most likely a JSON String) - /// The Upload-method (POST,DELETE,PUT) - /// - /// - Task> UploadAsync(string url, string body, string method, Dictionary headers = null); + /// + /// Uploads data async from an URL and returns the response + /// + /// An URL + /// The Body-Data (most likely a JSON String) + /// The Upload-method (POST,DELETE,PUT) + /// + /// + Task> UploadAsync(string url, string body, string method, Dictionary headers = null); - /// - /// Uploads data from an URL and returns the response - /// - /// An URL - /// The Body-Data (most likely a JSON String) - /// The Upload-method (POST,DELETE,PUT) - /// - /// - Tuple UploadRaw(string url, string body, string method, Dictionary headers = null); + /// + /// Uploads data from an URL and returns the response + /// + /// An URL + /// The Body-Data (most likely a JSON String) + /// The Upload-method (POST,DELETE,PUT) + /// + /// + Tuple UploadRaw(string url, string body, string method, Dictionary headers = null); - /// - /// Uploads data async from an URL and returns the response - /// - /// An URL - /// The Body-Data (most likely a JSON String) - /// The Upload-method (POST,DELETE,PUT) - /// - /// - Task> UploadRawAsync(string url, string body, string method, Dictionary headers = null); + /// + /// Uploads data async from an URL and returns the response + /// + /// An URL + /// The Body-Data (most likely a JSON String) + /// The Upload-method (POST,DELETE,PUT) + /// + /// + Task> UploadRawAsync(string url, string body, string method, Dictionary headers = null); - /// - /// Uploads data from an URL and converts the response to an object - /// - /// The Type which the object gets converted to - /// An URL - /// The Body-Data (most likely a JSON String) - /// The Upload-method (POST,DELETE,PUT) - /// - /// - Tuple UploadJson(string url, string body, string method, Dictionary headers = null); + /// + /// Uploads data from an URL and converts the response to an object + /// + /// The Type which the object gets converted to + /// An URL + /// The Body-Data (most likely a JSON String) + /// The Upload-method (POST,DELETE,PUT) + /// + /// + Tuple UploadJson(string url, string body, string method, Dictionary headers = null); - /// - /// Uploads data async from an URL and converts the response to an object - /// - /// The Type which the object gets converted to - /// An URL - /// The Body-Data (most likely a JSON String) - /// The Upload-method (POST,DELETE,PUT) - /// - /// - Task> UploadJsonAsync(string url, string body, string method, Dictionary headers = null); - } + /// + /// Uploads data async from an URL and converts the response to an object + /// + /// The Type which the object gets converted to + /// An URL + /// The Body-Data (most likely a JSON String) + /// The Upload-method (POST,DELETE,PUT) + /// + /// + Task> UploadJsonAsync(string url, string body, string method, Dictionary headers = null); + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisMeta.cs b/SpotifyAPI.Web/Models/AnalysisMeta.cs index bb9b7774..71fcc461 100644 --- a/SpotifyAPI.Web/Models/AnalysisMeta.cs +++ b/SpotifyAPI.Web/Models/AnalysisMeta.cs @@ -1,28 +1,28 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AnalysisMeta - { - [JsonProperty("analyzer_platform")] - public string AnalyzerVersion { get; set; } + public class AnalysisMeta + { + [JsonProperty("analyzer_platform")] + public string AnalyzerVersion { get; set; } - [JsonProperty("platform")] - public string Platform { get; set; } + [JsonProperty("platform")] + public string Platform { get; set; } - [JsonProperty("status_code")] - public int StatusCode { get; set; } + [JsonProperty("status_code")] + public int StatusCode { get; set; } - [JsonProperty("detailed_status")] - public string DetailedStatus { get; set; } + [JsonProperty("detailed_status")] + public string DetailedStatus { get; set; } - [JsonProperty("timestamp")] - public long Timestamp { get; set; } + [JsonProperty("timestamp")] + public long Timestamp { get; set; } - [JsonProperty("analysis_time")] - public double AnalysisTime { get; set; } + [JsonProperty("analysis_time")] + public double AnalysisTime { get; set; } - [JsonProperty("input_process")] - public string InputProcess { get; set; } - } -} + [JsonProperty("input_process")] + public string InputProcess { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisSection.cs b/SpotifyAPI.Web/Models/AnalysisSection.cs index bcb92bc2..1240c786 100644 --- a/SpotifyAPI.Web/Models/AnalysisSection.cs +++ b/SpotifyAPI.Web/Models/AnalysisSection.cs @@ -1,43 +1,43 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AnalysisSection - { - [JsonProperty("start")] - public double Start { get; set; } + public class AnalysisSection + { + [JsonProperty("start")] + public double Start { get; set; } - [JsonProperty("duration")] - public double Duration { get; set; } + [JsonProperty("duration")] + public double Duration { get; set; } - [JsonProperty("confidence")] - public double Confidence { get; set; } + [JsonProperty("confidence")] + public double Confidence { get; set; } - [JsonProperty("loudness")] - public double Loudness { get; set; } + [JsonProperty("loudness")] + public double Loudness { get; set; } - [JsonProperty("tempo")] - public double Tempo { get; set; } + [JsonProperty("tempo")] + public double Tempo { get; set; } - [JsonProperty("tempo_confidence")] - public double TempoConfidence { get; set; } + [JsonProperty("tempo_confidence")] + public double TempoConfidence { get; set; } - [JsonProperty("key")] - public int Key { get; set; } + [JsonProperty("key")] + public int Key { get; set; } - [JsonProperty("key_confidence")] - public double KeyConfidence { get; set; } + [JsonProperty("key_confidence")] + public double KeyConfidence { get; set; } - [JsonProperty("mode")] - public int Mode { get; set; } + [JsonProperty("mode")] + public int Mode { get; set; } - [JsonProperty("mode_confidence")] - public double ModeConfidence { get; set; } + [JsonProperty("mode_confidence")] + public double ModeConfidence { get; set; } - [JsonProperty("time_signature")] - public int TimeSignature { get; set; } + [JsonProperty("time_signature")] + public int TimeSignature { get; set; } - [JsonProperty("time_signature_confidence")] - public double TimeSignatureConfidence { get; set; } - } -} + [JsonProperty("time_signature_confidence")] + public double TimeSignatureConfidence { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisSegment.cs b/SpotifyAPI.Web/Models/AnalysisSegment.cs index bdf5270b..80de52c6 100644 --- a/SpotifyAPI.Web/Models/AnalysisSegment.cs +++ b/SpotifyAPI.Web/Models/AnalysisSegment.cs @@ -1,35 +1,35 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AnalysisSegment - { - [JsonProperty("start")] - public double Start { get; set; } + public class AnalysisSegment + { + [JsonProperty("start")] + public double Start { get; set; } - [JsonProperty("duration")] - public double Duration { get; set; } + [JsonProperty("duration")] + public double Duration { get; set; } - [JsonProperty("confidence")] - public double Confidence { get; set; } + [JsonProperty("confidence")] + public double Confidence { get; set; } - [JsonProperty("loudness_start")] - public double LoudnessStart { get; set; } + [JsonProperty("loudness_start")] + public double LoudnessStart { get; set; } - [JsonProperty("loudness_max_time")] - public double LoudnessMaxTime { get; set; } + [JsonProperty("loudness_max_time")] + public double LoudnessMaxTime { get; set; } - [JsonProperty("loudness_max")] - public double LoudnessMax { get; set; } + [JsonProperty("loudness_max")] + public double LoudnessMax { get; set; } - [JsonProperty("loudness_end")] - public double LoudnessEnd { get; set; } + [JsonProperty("loudness_end")] + public double LoudnessEnd { get; set; } - [JsonProperty("pitches")] - public List Pitches { get; set; } + [JsonProperty("pitches")] + public List Pitches { get; set; } - [JsonProperty("timbre")] - public List Timbre { get; set; } - } -} + [JsonProperty("timbre")] + public List Timbre { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisTimeSlice.cs b/SpotifyAPI.Web/Models/AnalysisTimeSlice.cs index 41ab5f15..cb7843f7 100644 --- a/SpotifyAPI.Web/Models/AnalysisTimeSlice.cs +++ b/SpotifyAPI.Web/Models/AnalysisTimeSlice.cs @@ -1,16 +1,16 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AnalysisTimeSlice - { - [JsonProperty("start")] - public double Start { get; set; } + public class AnalysisTimeSlice + { + [JsonProperty("start")] + public double Start { get; set; } - [JsonProperty("duration")] - public double Duration { get; set; } + [JsonProperty("duration")] + public double Duration { get; set; } - [JsonProperty("confidence")] - public double Confidence { get; set; } - } -} + [JsonProperty("confidence")] + public double Confidence { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisTrack.cs b/SpotifyAPI.Web/Models/AnalysisTrack.cs index e84bc629..5ffd78ee 100644 --- a/SpotifyAPI.Web/Models/AnalysisTrack.cs +++ b/SpotifyAPI.Web/Models/AnalysisTrack.cs @@ -1,86 +1,86 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AnalysisTrack - { - [JsonProperty("num_samples")] - public int NumSamples { get; set; } + public class AnalysisTrack + { + [JsonProperty("num_samples")] + public int NumSamples { get; set; } - [JsonProperty("duration")] - public double Duration { get; set; } + [JsonProperty("duration")] + public double Duration { get; set; } - [JsonProperty("sample_md5")] - public string SampleMD5 { get; set; } + [JsonProperty("sample_md5")] + public string SampleMD5 { get; set; } - [JsonProperty("offset_seconds")] - public double OffsetSeconds { get; set; } + [JsonProperty("offset_seconds")] + public double OffsetSeconds { get; set; } - [JsonProperty("window_seconds")] - public double WindowSeconds { get; set; } + [JsonProperty("window_seconds")] + public double WindowSeconds { get; set; } - [JsonProperty("analysis_sample_rate")] - public int AnalysisSampleRate { get; set; } + [JsonProperty("analysis_sample_rate")] + public int AnalysisSampleRate { get; set; } - [JsonProperty("analysis_channels")] - public int AnalysisChannels { get; set; } + [JsonProperty("analysis_channels")] + public int AnalysisChannels { get; set; } - [JsonProperty("end_of_fade_in")] - public double EndOfFadeIn { get; set; } + [JsonProperty("end_of_fade_in")] + public double EndOfFadeIn { get; set; } - [JsonProperty("start_of_fade_out")] - public double StartOfFadeOut { get; set; } + [JsonProperty("start_of_fade_out")] + public double StartOfFadeOut { get; set; } - [JsonProperty("loudness")] - public double Loudness { get; set; } + [JsonProperty("loudness")] + public double Loudness { get; set; } - [JsonProperty("tempo")] - public double Tempo { get; set; } + [JsonProperty("tempo")] + public double Tempo { get; set; } - [JsonProperty("tempo_confidence")] - public double TempoConfidence { get; set; } + [JsonProperty("tempo_confidence")] + public double TempoConfidence { get; set; } - [JsonProperty("time_signature")] - public double TimeSignature { get; set; } + [JsonProperty("time_signature")] + public double TimeSignature { get; set; } - [JsonProperty("time_signature_confidence")] - public double TimeSignatureConfidence { get; set; } + [JsonProperty("time_signature_confidence")] + public double TimeSignatureConfidence { get; set; } - [JsonProperty("key")] - public int Key { get; set; } + [JsonProperty("key")] + public int Key { get; set; } - [JsonProperty("key_confidence")] - public double KeyConfidence { get; set; } + [JsonProperty("key_confidence")] + public double KeyConfidence { get; set; } - [JsonProperty("mode")] - public int Mode { get; set; } + [JsonProperty("mode")] + public int Mode { get; set; } - [JsonProperty("mode_confidence")] - public double ModeConfidence { get; set; } + [JsonProperty("mode_confidence")] + public double ModeConfidence { get; set; } - [JsonProperty("codestring")] - public string Codestring { get; set; } + [JsonProperty("codestring")] + public string Codestring { get; set; } - [JsonProperty("code_version")] - public double CodeVersion { get; set; } + [JsonProperty("code_version")] + public double CodeVersion { get; set; } - [JsonProperty("echoprintstring")] - public string Echoprintstring { get; set; } + [JsonProperty("echoprintstring")] + public string Echoprintstring { get; set; } - [JsonProperty("echoprint_version")] - public double EchoprintVersion { get; set; } + [JsonProperty("echoprint_version")] + public double EchoprintVersion { get; set; } - [JsonProperty("synchstring")] - public string Synchstring { get; set; } + [JsonProperty("synchstring")] + public string Synchstring { get; set; } - [JsonProperty("synch_version")] - public double SynchVersion { get; set; } + [JsonProperty("synch_version")] + public double SynchVersion { get; set; } - [JsonProperty("rhythmstring")] - public string Rhythmstring { get; set; } + [JsonProperty("rhythmstring")] + public string Rhythmstring { get; set; } - [JsonProperty("rhythm_version")] - public double RhythmVersion { get; set; } + [JsonProperty("rhythm_version")] + public double RhythmVersion { get; set; } - } -} + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/ArrayResponse.cs b/SpotifyAPI.Web/Models/ArrayResponse.cs index eea3be62..c87e8967 100644 --- a/SpotifyAPI.Web/Models/ArrayResponse.cs +++ b/SpotifyAPI.Web/Models/ArrayResponse.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SpotifyAPI.Web.Models { - public class ListResponse : BasicModel - { - public List List { get; set; } - } + public class ListResponse : BasicModel + { + public List List { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AudioAnalysis.cs b/SpotifyAPI.Web/Models/AudioAnalysis.cs index bc8f622b..1dd4ab5d 100644 --- a/SpotifyAPI.Web/Models/AudioAnalysis.cs +++ b/SpotifyAPI.Web/Models/AudioAnalysis.cs @@ -1,29 +1,29 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AudioAnalysis : BasicModel - { - [JsonProperty("bars")] - public List Bars { get; set; } + public class AudioAnalysis : BasicModel + { + [JsonProperty("bars")] + public List Bars { get; set; } - [JsonProperty("beats")] - public List Beats { get; set; } + [JsonProperty("beats")] + public List Beats { get; set; } - [JsonProperty("meta")] - public AnalysisMeta Meta { get; set; } + [JsonProperty("meta")] + public AnalysisMeta Meta { get; set; } - [JsonProperty("sections")] - public List Sections { get; set; } + [JsonProperty("sections")] + public List Sections { get; set; } - [JsonProperty("segments")] - public List Segments { get; set; } + [JsonProperty("segments")] + public List Segments { get; set; } - [JsonProperty("tatums")] - public List Tatums { get; set; } + [JsonProperty("tatums")] + public List Tatums { get; set; } - [JsonProperty("track")] - public AnalysisTrack Track { get; set; } - } -} + [JsonProperty("track")] + public AnalysisTrack Track { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AudioFeatures.cs b/SpotifyAPI.Web/Models/AudioFeatures.cs index a3b029f9..fbc40fd6 100644 --- a/SpotifyAPI.Web/Models/AudioFeatures.cs +++ b/SpotifyAPI.Web/Models/AudioFeatures.cs @@ -1,61 +1,61 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AudioFeatures : BasicModel - { - [JsonProperty("acousticness")] - public float Acousticness { get; set; } + public class AudioFeatures : BasicModel + { + [JsonProperty("acousticness")] + public float Acousticness { get; set; } - [JsonProperty("analysis_url")] - public string AnalysisUrl { get; set; } + [JsonProperty("analysis_url")] + public string AnalysisUrl { get; set; } - [JsonProperty("danceability")] - public float Danceability { get; set; } + [JsonProperty("danceability")] + public float Danceability { get; set; } - [JsonProperty("duration_ms")] - public int DurationMs { get; set; } + [JsonProperty("duration_ms")] + public int DurationMs { get; set; } - [JsonProperty("energy")] - public float Energy { get; set; } + [JsonProperty("energy")] + public float Energy { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("instrumentalness")] - public float Instrumentalness { get; set; } + [JsonProperty("instrumentalness")] + public float Instrumentalness { get; set; } - [JsonProperty("key")] - public int Key { get; set; } + [JsonProperty("key")] + public int Key { get; set; } - [JsonProperty("liveness")] - public float Liveness { get; set; } + [JsonProperty("liveness")] + public float Liveness { get; set; } - [JsonProperty("loudness")] - public float Loudness { get; set; } + [JsonProperty("loudness")] + public float Loudness { get; set; } - [JsonProperty("mode")] - public int Mode { get; set; } + [JsonProperty("mode")] + public int Mode { get; set; } - [JsonProperty("speechiness")] - public float Speechiness { get; set; } + [JsonProperty("speechiness")] + public float Speechiness { get; set; } - [JsonProperty("tempo")] - public float Tempo { get; set; } + [JsonProperty("tempo")] + public float Tempo { get; set; } - [JsonProperty("time_signature")] - public int TimeSignature { get; set; } + [JsonProperty("time_signature")] + public int TimeSignature { get; set; } - [JsonProperty("track_href")] - public string TrackHref { get; set; } + [JsonProperty("track_href")] + public string TrackHref { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } + [JsonProperty("uri")] + public string Uri { get; set; } - [JsonProperty("valence")] - public float Valence { get; set; } - } + [JsonProperty("valence")] + public float Valence { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AvailabeDevices.cs b/SpotifyAPI.Web/Models/AvailabeDevices.cs index 6275ec01..718cc98d 100644 --- a/SpotifyAPI.Web/Models/AvailabeDevices.cs +++ b/SpotifyAPI.Web/Models/AvailabeDevices.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class AvailabeDevices : BasicModel - { - [JsonProperty("devices")] - public List Devices { get; set; } - } + public class AvailabeDevices : BasicModel + { + [JsonProperty("devices")] + public List Devices { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/BasicModel.cs b/SpotifyAPI.Web/Models/BasicModel.cs index d888dc21..27153eef 100644 --- a/SpotifyAPI.Web/Models/BasicModel.cs +++ b/SpotifyAPI.Web/Models/BasicModel.cs @@ -1,23 +1,23 @@ -using Newtonsoft.Json; using System.Net; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public abstract class BasicModel - { - [JsonProperty("error")] - public Error Error { get; set; } + public abstract class BasicModel + { + [JsonProperty("error")] + public Error Error { get; set; } - private ResponseInfo _info; + private ResponseInfo _info; - public bool HasError() => Error != null; + public bool HasError() => Error != null; - internal void AddResponseInfo(ResponseInfo info) => _info = info; + internal void AddResponseInfo(ResponseInfo info) => _info = info; - public string Header(string key) => _info.Headers?.Get(key); + public string Header(string key) => _info.Headers?.Get(key); - public WebHeaderCollection Headers() => _info.Headers; + public WebHeaderCollection Headers() => _info.Headers; - public HttpStatusCode StatusCode() => _info.StatusCode; - } + public HttpStatusCode StatusCode() => _info.StatusCode; + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Category.cs b/SpotifyAPI.Web/Models/Category.cs index 03be7a0b..fcba4088 100644 --- a/SpotifyAPI.Web/Models/Category.cs +++ b/SpotifyAPI.Web/Models/Category.cs @@ -1,20 +1,20 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Category : BasicModel - { - [JsonProperty("href")] - public string Href { get; set; } + public class Category : BasicModel + { + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("icons")] - public List Icons { get; set; } + [JsonProperty("icons")] + public List Icons { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } - } + [JsonProperty("name")] + public string Name { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/CategoryList.cs b/SpotifyAPI.Web/Models/CategoryList.cs index c46d5cbe..0970cd22 100644 --- a/SpotifyAPI.Web/Models/CategoryList.cs +++ b/SpotifyAPI.Web/Models/CategoryList.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class CategoryList : BasicModel - { - [JsonProperty("categories")] - public Paging Categories { get; set; } - } + public class CategoryList : BasicModel + { + [JsonProperty("categories")] + public Paging Categories { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/CategoryPlaylist.cs b/SpotifyAPI.Web/Models/CategoryPlaylist.cs index 02875d5a..9597df36 100644 --- a/SpotifyAPI.Web/Models/CategoryPlaylist.cs +++ b/SpotifyAPI.Web/Models/CategoryPlaylist.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class CategoryPlaylist : BasicModel - { - [JsonProperty("playlists")] - public Paging Playlists { get; set; } - } + public class CategoryPlaylist : BasicModel + { + [JsonProperty("playlists")] + public Paging Playlists { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/CursorPaging.cs b/SpotifyAPI.Web/Models/CursorPaging.cs index 3499ede2..ca717642 100644 --- a/SpotifyAPI.Web/Models/CursorPaging.cs +++ b/SpotifyAPI.Web/Models/CursorPaging.cs @@ -1,31 +1,31 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class CursorPaging : BasicModel + public class CursorPaging : BasicModel + { + [JsonProperty("href")] + public string Href { get; set; } + + [JsonProperty("items")] + public List 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() { - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("items")] - public List 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); - } + return !string.IsNullOrEmpty(Next); } -} + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Device.cs b/SpotifyAPI.Web/Models/Device.cs index 3a0d79cc..12b3eca0 100644 --- a/SpotifyAPI.Web/Models/Device.cs +++ b/SpotifyAPI.Web/Models/Device.cs @@ -1,25 +1,25 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Device - { - [JsonProperty("id")] - public string Id { get; set; } + public class Device + { + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("is_active")] - public bool IsActive { get; set; } + [JsonProperty("is_active")] + public bool IsActive { get; set; } - [JsonProperty("is_restricted")] - public bool IsRestricted { get; set; } + [JsonProperty("is_restricted")] + public bool IsRestricted { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("volume_percent")] - public int VolumePercent { get; set; } - } + [JsonProperty("volume_percent")] + public int VolumePercent { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FeaturedPlaylists.cs b/SpotifyAPI.Web/Models/FeaturedPlaylists.cs index ab1dc09d..f5a48deb 100644 --- a/SpotifyAPI.Web/Models/FeaturedPlaylists.cs +++ b/SpotifyAPI.Web/Models/FeaturedPlaylists.cs @@ -1,13 +1,13 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class FeaturedPlaylists : BasicModel - { - [JsonProperty("message")] - public string Message { get; set; } + public class FeaturedPlaylists : BasicModel + { + [JsonProperty("message")] + public string Message { get; set; } - [JsonProperty("playlists")] - public Paging Playlists { get; set; } - } + [JsonProperty("playlists")] + public Paging Playlists { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FollowedArtists.cs b/SpotifyAPI.Web/Models/FollowedArtists.cs index 163ce877..39072106 100644 --- a/SpotifyAPI.Web/Models/FollowedArtists.cs +++ b/SpotifyAPI.Web/Models/FollowedArtists.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class FollowedArtists : BasicModel - { - [JsonProperty("artists")] - public CursorPaging Artists { get; set; } - } + public class FollowedArtists : BasicModel + { + [JsonProperty("artists")] + public CursorPaging Artists { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FullAlbum.cs b/SpotifyAPI.Web/Models/FullAlbum.cs index 9447a11c..cd9c89ad 100644 --- a/SpotifyAPI.Web/Models/FullAlbum.cs +++ b/SpotifyAPI.Web/Models/FullAlbum.cs @@ -1,68 +1,68 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class FullAlbum : BasicModel - { - [JsonProperty("album_type")] - public string AlbumType { get; set; } + public class FullAlbum : BasicModel + { + [JsonProperty("album_type")] + public string AlbumType { get; set; } - [JsonProperty("artists")] - public List Artists { get; set; } + [JsonProperty("artists")] + public List Artists { get; set; } - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } + [JsonProperty("available_markets")] + public List AvailableMarkets { get; set; } - [JsonProperty("copyrights")] - public List Copyrights { get; set; } + [JsonProperty("copyrights")] + public List Copyrights { get; set; } - [JsonProperty("external_ids")] - public Dictionary ExternalIds { get; set; } + [JsonProperty("external_ids")] + public Dictionary ExternalIds { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("genres")] - public List Genres { get; set; } + [JsonProperty("genres")] + public List Genres { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } - - [JsonProperty("label")] - public string Label { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("label")] + public string Label { get; set; } - [JsonProperty("popularity")] - public int Popularity { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("release_date")] - public string ReleaseDate { get; set; } + [JsonProperty("popularity")] + public int Popularity { get; set; } - [JsonProperty("release_date_precision")] - public string ReleaseDatePrecision { get; set; } + [JsonProperty("release_date")] + public string ReleaseDate { get; set; } - [JsonProperty("tracks")] - public Paging Tracks { get; set; } + [JsonProperty("release_date_precision")] + public string ReleaseDatePrecision { get; set; } - [JsonProperty("restrictions")] - public Dictionary Restrictions { get; set; } + [JsonProperty("tracks")] + public Paging Tracks { get; set; } - [JsonProperty("total_tracks")] - public int TotalTracks { get; set; } + [JsonProperty("restrictions")] + public Dictionary Restrictions { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("total_tracks")] + public int TotalTracks { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } -} + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("uri")] + public string Uri { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FullArtist.cs b/SpotifyAPI.Web/Models/FullArtist.cs index 1b38a747..78e2cf2e 100644 --- a/SpotifyAPI.Web/Models/FullArtist.cs +++ b/SpotifyAPI.Web/Models/FullArtist.cs @@ -1,38 +1,38 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class FullArtist : BasicModel - { - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + public class FullArtist : BasicModel + { + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("followers")] - public Followers Followers { get; set; } + [JsonProperty("followers")] + public Followers Followers { get; set; } - [JsonProperty("genres")] - public List Genres { get; set; } + [JsonProperty("genres")] + public List Genres { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("popularity")] - public int Popularity { get; set; } + [JsonProperty("popularity")] + public int Popularity { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FullPlaylist.cs b/SpotifyAPI.Web/Models/FullPlaylist.cs index aec32d0b..0a8f6b3e 100644 --- a/SpotifyAPI.Web/Models/FullPlaylist.cs +++ b/SpotifyAPI.Web/Models/FullPlaylist.cs @@ -1,50 +1,50 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class FullPlaylist : BasicModel - { - [JsonProperty("collaborative")] - public bool Collaborative { get; set; } + public class FullPlaylist : BasicModel + { + [JsonProperty("collaborative")] + public bool Collaborative { get; set; } - [JsonProperty("description")] - public string Description { get; set; } + [JsonProperty("description")] + public string Description { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("followers")] - public Followers Followers { get; set; } + [JsonProperty("followers")] + public Followers Followers { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("owner")] - public PublicProfile Owner { get; set; } + [JsonProperty("owner")] + public PublicProfile Owner { get; set; } - [JsonProperty("public")] - public bool Public { get; set; } + [JsonProperty("public")] + public bool Public { get; set; } - [JsonProperty("snapshot_id")] - public string SnapshotId { get; set; } + [JsonProperty("snapshot_id")] + public string SnapshotId { get; set; } - [JsonProperty("tracks")] - public Paging Tracks { get; set; } + [JsonProperty("tracks")] + public Paging Tracks { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FullTrack.cs b/SpotifyAPI.Web/Models/FullTrack.cs index bab52feb..d75c8d00 100644 --- a/SpotifyAPI.Web/Models/FullTrack.cs +++ b/SpotifyAPI.Web/Models/FullTrack.cs @@ -1,71 +1,71 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class FullTrack : BasicModel - { - [JsonProperty("album")] - public SimpleAlbum Album { get; set; } + public class FullTrack : BasicModel + { + [JsonProperty("album")] + public SimpleAlbum Album { get; set; } - [JsonProperty("artists")] - public List Artists { get; set; } + [JsonProperty("artists")] + public List Artists { get; set; } - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } + [JsonProperty("available_markets")] + public List AvailableMarkets { get; set; } - [JsonProperty("disc_number")] - public int DiscNumber { get; set; } + [JsonProperty("disc_number")] + public int DiscNumber { get; set; } - [JsonProperty("duration_ms")] - public int DurationMs { get; set; } + [JsonProperty("duration_ms")] + public int DurationMs { get; set; } - [JsonProperty("explicit")] - public bool Explicit { get; set; } + [JsonProperty("explicit")] + public bool Explicit { get; set; } - [JsonProperty("external_ids")] - public Dictionary ExternalIds { get; set; } + [JsonProperty("external_ids")] + public Dictionary ExternalIds { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternUrls { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("popularity")] - public int Popularity { get; set; } + [JsonProperty("popularity")] + public int Popularity { get; set; } - [JsonProperty("preview_url")] - public string PreviewUrl { get; set; } + [JsonProperty("preview_url")] + public string PreviewUrl { get; set; } - [JsonProperty("track_number")] - public int TrackNumber { get; set; } + [JsonProperty("track_number")] + public int TrackNumber { get; set; } - [JsonProperty("restrictions")] - public Dictionary Restrictions { get; set; } + [JsonProperty("restrictions")] + public Dictionary Restrictions { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } + [JsonProperty("uri")] + public string Uri { get; set; } - /// - /// Only filled when the "market"-parameter was supplied! - /// - [JsonProperty("is_playable")] - public bool? IsPlayable { get; set; } + /// + /// Only filled when the "market"-parameter was supplied! + /// + [JsonProperty("is_playable")] + public bool? IsPlayable { get; set; } - /// - /// Only filled when the "market"-parameter was supplied! - /// - [JsonProperty("linked_from")] - public LinkedFrom LinkedFrom { get; set; } - } + /// + /// Only filled when the "market"-parameter was supplied! + /// + [JsonProperty("linked_from")] + public LinkedFrom LinkedFrom { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/GeneralModels.cs b/SpotifyAPI.Web/Models/GeneralModels.cs index 8dffd92b..b263aacb 100644 --- a/SpotifyAPI.Web/Models/GeneralModels.cs +++ b/SpotifyAPI.Web/Models/GeneralModels.cs @@ -1,159 +1,158 @@ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Image + 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 + { + /// + /// Delete-Track Wrapper + /// + /// An Spotify-URI + /// Optional positions + public DeleteTrackUri(string uri, params int[] positions) { - [JsonProperty("url")] - public string Url { get; set; } - - [JsonProperty("width")] - public int Width { get; set; } - - [JsonProperty("height")] - public int Height { get; set; } + Positions = positions.ToList(); + Uri = uri; } - public class ErrorResponse : BasicModel + [JsonProperty("uri")] + public string Uri { get; set; } + + [JsonProperty("positions")] + public List Positions { get; set; } + + public bool ShouldSerializePositions() { + return Positions.Count > 0; } + } - public class Error - { - [JsonProperty("status")] - public int Status { get; set; } + public class Copyright + { + [JsonProperty("text")] + public string Text { get; set; } - [JsonProperty("message")] - public string Message { get; set; } - } + [JsonProperty("type")] + public string Type { get; set; } + } - public class PlaylistTrackCollection - { - [JsonProperty("href")] - public string Href { get; set; } + public class LinkedFrom + { + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("total")] - public int Total { get; set; } - } + [JsonProperty("href")] + public string Href { get; set; } - public class Followers - { - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("total")] - public int Total { get; set; } - } + [JsonProperty("type")] + public string Type { get; set; } - public class PlaylistTrack - { - [JsonProperty("added_at")] - public DateTime AddedAt { get; set; } + [JsonProperty("uri")] + public string Uri { get; set; } + } - [JsonProperty("added_by")] - public PublicProfile AddedBy { get; set; } + public class SavedTrack + { + [JsonProperty("added_at")] + public DateTime AddedAt { get; set; } - [JsonProperty("track")] - public FullTrack Track { get; set; } + [JsonProperty("track")] + public FullTrack Track { get; set; } + } - [JsonProperty("is_local")] - public bool IsLocal { get; set; } - } + public class SavedAlbum + { + [JsonProperty("added_at")] + public DateTime AddedAt { get; set; } - public class DeleteTrackUri - { - /// - /// Delete-Track Wrapper - /// - /// An Spotify-URI - /// Optional positions - public DeleteTrackUri(string uri, params int[] positions) - { - Positions = positions.ToList(); - Uri = uri; - } + [JsonProperty("album")] + public FullAlbum Album { get; set; } + } - [JsonProperty("uri")] - public string Uri { get; set; } + public class Cursor + { + [JsonProperty("after")] + public string After { get; set; } - [JsonProperty("positions")] - public List Positions { get; set; } + [JsonProperty("before")] + public string Before { get; set; } + } - public bool ShouldSerializePositions() - { - return Positions.Count > 0; - } - } + public class Context + { + [JsonProperty("type")] + public string Type { get; set; } - public class Copyright - { - [JsonProperty("text")] - public string Text { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("type")] - public string Type { get; set; } - } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - public class LinkedFrom - { - [JsonProperty("external_urls")] - public Dictionary 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 ExternalUrls { get; set; } - - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/NewAlbumReleases.cs b/SpotifyAPI.Web/Models/NewAlbumReleases.cs index c85139ef..935c0dd1 100644 --- a/SpotifyAPI.Web/Models/NewAlbumReleases.cs +++ b/SpotifyAPI.Web/Models/NewAlbumReleases.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class NewAlbumReleases : BasicModel - { - [JsonProperty("albums")] - public Paging Albums { get; set; } - } + public class NewAlbumReleases : BasicModel + { + [JsonProperty("albums")] + public Paging Albums { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Paging.cs b/SpotifyAPI.Web/Models/Paging.cs index bbd2e86c..fe5838d0 100644 --- a/SpotifyAPI.Web/Models/Paging.cs +++ b/SpotifyAPI.Web/Models/Paging.cs @@ -1,39 +1,39 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Paging : BasicModel + public class Paging : BasicModel + { + [JsonProperty("href")] + public string Href { get; set; } + + [JsonProperty("items")] + public List 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() { - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("items")] - public List 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; - } + return Next != null; } -} + + public bool HasPreviousPage() + { + return Previous != null; + } + } +} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/PlayHistory.cs b/SpotifyAPI.Web/Models/PlayHistory.cs index ae1c28ec..a02d6d20 100644 --- a/SpotifyAPI.Web/Models/PlayHistory.cs +++ b/SpotifyAPI.Web/Models/PlayHistory.cs @@ -1,17 +1,17 @@ -using System; +using System; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class PlayHistory : BasicModel - { - [JsonProperty("track")] - public SimpleTrack Track { get; set; } + public class PlayHistory : BasicModel + { + [JsonProperty("track")] + public SimpleTrack Track { get; set; } - [JsonProperty("played_at")] - public DateTime PlayedAt { get; set; } + [JsonProperty("played_at")] + public DateTime PlayedAt { get; set; } - [JsonProperty("context")] - public Context Context { get; set; } - } + [JsonProperty("context")] + public Context Context { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/PlaybackContext.cs b/SpotifyAPI.Web/Models/PlaybackContext.cs index 37d6d4a7..6636ba29 100644 --- a/SpotifyAPI.Web/Models/PlaybackContext.cs +++ b/SpotifyAPI.Web/Models/PlaybackContext.cs @@ -1,38 +1,38 @@ -using Newtonsoft.Json; +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; } + public class PlaybackContext : BasicModel + { + [JsonProperty("device")] + public Device Device { get; set; } - [JsonProperty("repeat_state")] - [JsonConverter(typeof(StringEnumConverter))] - public RepeatState RepeatState { get; set; } + [JsonProperty("repeat_state")] + [JsonConverter(typeof(StringEnumConverter))] + public RepeatState RepeatState { get; set; } - [JsonProperty("shuffle_state")] - public bool ShuffleState { get; set; } + [JsonProperty("shuffle_state")] + public bool ShuffleState { get; set; } - [JsonProperty("context")] - public Context Context { get; set; } + [JsonProperty("context")] + public Context Context { get; set; } - [JsonProperty("timestamp")] - public long Timestamp { get; set; } + [JsonProperty("timestamp")] + public long Timestamp { get; set; } - [JsonProperty("progress_ms")] - public int ProgressMs { get; set; } + [JsonProperty("progress_ms")] + public int ProgressMs { get; set; } - [JsonProperty("is_playing")] - public bool IsPlaying { get; set; } + [JsonProperty("is_playing")] + public bool IsPlaying { get; set; } - [JsonProperty("item")] - public FullTrack Item { get; set; } + [JsonProperty("item")] + public FullTrack Item { get; set; } - [JsonProperty("currently_playing_type")] - [JsonConverter(typeof(StringEnumConverter))] - public TrackType CurrentlyPlayingType { get; set; } - } + [JsonProperty("currently_playing_type")] + [JsonConverter(typeof(StringEnumConverter))] + public TrackType CurrentlyPlayingType { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/PrivateProfile.cs b/SpotifyAPI.Web/Models/PrivateProfile.cs index 243d6b94..26cf5db8 100644 --- a/SpotifyAPI.Web/Models/PrivateProfile.cs +++ b/SpotifyAPI.Web/Models/PrivateProfile.cs @@ -1,44 +1,44 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class PrivateProfile : BasicModel - { - [JsonProperty("birthdate")] - public string Birthdate { get; set; } + public class PrivateProfile : BasicModel + { + [JsonProperty("birthdate")] + public string Birthdate { get; set; } - [JsonProperty("country")] - public string Country { get; set; } + [JsonProperty("country")] + public string Country { get; set; } - [JsonProperty("display_name")] - public string DisplayName { get; set; } + [JsonProperty("display_name")] + public string DisplayName { get; set; } - [JsonProperty("email")] - public string Email { get; set; } + [JsonProperty("email")] + public string Email { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("followers")] - public Followers Followers { get; set; } + [JsonProperty("followers")] + public Followers Followers { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("product")] - public string Product { get; set; } + [JsonProperty("product")] + public string Product { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/PublicProfile.cs b/SpotifyAPI.Web/Models/PublicProfile.cs index a28b8ea4..db18a5f9 100644 --- a/SpotifyAPI.Web/Models/PublicProfile.cs +++ b/SpotifyAPI.Web/Models/PublicProfile.cs @@ -1,32 +1,32 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class PublicProfile : BasicModel - { - [JsonProperty("display_name")] - public string DisplayName { get; set; } + public class PublicProfile : BasicModel + { + [JsonProperty("display_name")] + public string DisplayName { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("followers")] - public Followers Followers { get; set; } + [JsonProperty("followers")] + public Followers Followers { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/RecommendationSeed .cs b/SpotifyAPI.Web/Models/RecommendationSeed .cs index b0cd94a1..28e2fcdd 100644 --- a/SpotifyAPI.Web/Models/RecommendationSeed .cs +++ b/SpotifyAPI.Web/Models/RecommendationSeed .cs @@ -1,25 +1,25 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class RecommendationSeed - { - [JsonProperty("afterFilteringSize")] - public int AfterFilteringSize { get; set; } + public class RecommendationSeed + { + [JsonProperty("afterFilteringSize")] + public int AfterFilteringSize { get; set; } - [JsonProperty("afterRelinkingSize")] - public int AfterRelinkingSize { get; set; } + [JsonProperty("afterRelinkingSize")] + public int AfterRelinkingSize { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("initialPoolSize")] - public int InitialPoolSize { get; set; } + [JsonProperty("initialPoolSize")] + public int InitialPoolSize { get; set; } - [JsonProperty("type")] - public string Type { get; set; } - } + [JsonProperty("type")] + public string Type { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs b/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs index 663c8bf7..e92ad5a7 100644 --- a/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs +++ b/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class RecommendationSeedGenres : BasicModel - { - [JsonProperty("genres")] - public List Genres { get; set; } - } + public class RecommendationSeedGenres : BasicModel + { + [JsonProperty("genres")] + public List Genres { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Recommendations.cs b/SpotifyAPI.Web/Models/Recommendations.cs index 921522ec..7b00f611 100644 --- a/SpotifyAPI.Web/Models/Recommendations.cs +++ b/SpotifyAPI.Web/Models/Recommendations.cs @@ -1,14 +1,14 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Recommendations : BasicModel - { - [JsonProperty("seeds")] - public List Seeds { get; set; } + public class Recommendations : BasicModel + { + [JsonProperty("seeds")] + public List Seeds { get; set; } - [JsonProperty("tracks")] - public List Tracks { get; set; } - } + [JsonProperty("tracks")] + public List Tracks { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/ResponseInfo.cs b/SpotifyAPI.Web/Models/ResponseInfo.cs index 1a8a12c2..de1665cb 100644 --- a/SpotifyAPI.Web/Models/ResponseInfo.cs +++ b/SpotifyAPI.Web/Models/ResponseInfo.cs @@ -1,13 +1,13 @@ -using System.Net; +using System.Net; namespace SpotifyAPI.Web.Models { - public class ResponseInfo - { - public WebHeaderCollection Headers { get; set; } + public class ResponseInfo + { + public WebHeaderCollection Headers { get; set; } - public HttpStatusCode StatusCode { get; set; } + public HttpStatusCode StatusCode { get; set; } - public static readonly ResponseInfo Empty = new ResponseInfo(); - } + public static readonly ResponseInfo Empty = new ResponseInfo(); + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SearchItem.cs b/SpotifyAPI.Web/Models/SearchItem.cs index 65b76c52..447187b7 100644 --- a/SpotifyAPI.Web/Models/SearchItem.cs +++ b/SpotifyAPI.Web/Models/SearchItem.cs @@ -1,19 +1,19 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SearchItem : BasicModel - { - [JsonProperty("artists")] - public Paging Artists { get; set; } + public class SearchItem : BasicModel + { + [JsonProperty("artists")] + public Paging Artists { get; set; } - [JsonProperty("albums")] - public Paging Albums { get; set; } + [JsonProperty("albums")] + public Paging Albums { get; set; } - [JsonProperty("tracks")] - public Paging Tracks { get; set; } + [JsonProperty("tracks")] + public Paging Tracks { get; set; } - [JsonProperty("playlists")] - public Paging Playlists { get; set; } - } + [JsonProperty("playlists")] + public Paging Playlists { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SeveralAlbums.cs b/SpotifyAPI.Web/Models/SeveralAlbums.cs index 74025da0..a69f82d0 100644 --- a/SpotifyAPI.Web/Models/SeveralAlbums.cs +++ b/SpotifyAPI.Web/Models/SeveralAlbums.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SeveralAlbums : BasicModel - { - [JsonProperty("albums")] - public List Albums { get; set; } - } + public class SeveralAlbums : BasicModel + { + [JsonProperty("albums")] + public List Albums { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SeveralArtists.cs b/SpotifyAPI.Web/Models/SeveralArtists.cs index 28df5db5..eae18f9c 100644 --- a/SpotifyAPI.Web/Models/SeveralArtists.cs +++ b/SpotifyAPI.Web/Models/SeveralArtists.cs @@ -3,9 +3,9 @@ using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SeveralArtists : BasicModel - { - [JsonProperty("artists")] - public List Artists { get; set; } - } + public class SeveralArtists : BasicModel + { + [JsonProperty("artists")] + public List Artists { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SeveralAudioFeatures.cs b/SpotifyAPI.Web/Models/SeveralAudioFeatures.cs index 34ea6515..3f6bb9ca 100644 --- a/SpotifyAPI.Web/Models/SeveralAudioFeatures.cs +++ b/SpotifyAPI.Web/Models/SeveralAudioFeatures.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SeveralAudioFeatures : BasicModel - { - [JsonProperty("audio_features")] - public List AudioFeatures { get; set; } - } + public class SeveralAudioFeatures : BasicModel + { + [JsonProperty("audio_features")] + public List AudioFeatures { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SeveralTracks.cs b/SpotifyAPI.Web/Models/SeveralTracks.cs index a72c216e..f156508c 100644 --- a/SpotifyAPI.Web/Models/SeveralTracks.cs +++ b/SpotifyAPI.Web/Models/SeveralTracks.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SeveralTracks : BasicModel - { - [JsonProperty("tracks")] - public List Tracks { get; set; } - } + public class SeveralTracks : BasicModel + { + [JsonProperty("tracks")] + public List Tracks { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SimpleAlbum.cs b/SpotifyAPI.Web/Models/SimpleAlbum.cs index c90bbf88..860b2840 100644 --- a/SpotifyAPI.Web/Models/SimpleAlbum.cs +++ b/SpotifyAPI.Web/Models/SimpleAlbum.cs @@ -1,53 +1,53 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SimpleAlbum : BasicModel - { - [JsonProperty("album_group")] - public string AlbumGroup { get; set; } + public class SimpleAlbum : BasicModel + { + [JsonProperty("album_group")] + public string AlbumGroup { get; set; } - [JsonProperty("album_type")] - public string AlbumType { get; set; } + [JsonProperty("album_type")] + public string AlbumType { get; set; } - [JsonProperty("artists")] - public List Artists { get; set; } + [JsonProperty("artists")] + public List Artists { get; set; } - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } + [JsonProperty("available_markets")] + public List AvailableMarkets { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("release_date")] - public string ReleaseDate { get; set; } + [JsonProperty("release_date")] + public string ReleaseDate { get; set; } - [JsonProperty("release_date_precision")] - public string ReleaseDatePrecision { get; set; } + [JsonProperty("release_date_precision")] + public string ReleaseDatePrecision { get; set; } - [JsonProperty("restrictions")] - public Dictionary Restrictions { get; set; } + [JsonProperty("restrictions")] + public Dictionary Restrictions { get; set; } - [JsonProperty("total_tracks")] - public int TotalTracks { get; set; } + [JsonProperty("total_tracks")] + public int TotalTracks { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SimpleArtist.cs b/SpotifyAPI.Web/Models/SimpleArtist.cs index c1294eea..a599436e 100644 --- a/SpotifyAPI.Web/Models/SimpleArtist.cs +++ b/SpotifyAPI.Web/Models/SimpleArtist.cs @@ -1,26 +1,26 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SimpleArtist : BasicModel - { - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + public class SimpleArtist : BasicModel + { + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } -} \ No newline at end of file + [JsonProperty("uri")] + public string Uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/SimplePlaylist.cs b/SpotifyAPI.Web/Models/SimplePlaylist.cs index 37b37608..73f61bea 100644 --- a/SpotifyAPI.Web/Models/SimplePlaylist.cs +++ b/SpotifyAPI.Web/Models/SimplePlaylist.cs @@ -1,44 +1,44 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SimplePlaylist : BasicModel - { - [JsonProperty("collaborative")] - public bool Collaborative { get; set; } + public class SimplePlaylist : BasicModel + { + [JsonProperty("collaborative")] + public bool Collaborative { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternalUrls { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("images")] - public List Images { get; set; } + [JsonProperty("images")] + public List Images { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("owner")] - public PublicProfile Owner { get; set; } + [JsonProperty("owner")] + public PublicProfile Owner { get; set; } - [JsonProperty("public")] - public bool Public { get; set; } + [JsonProperty("public")] + public bool Public { get; set; } - [JsonProperty("snapshot_id")] - public string SnapshotId { get; set; } + [JsonProperty("snapshot_id")] + public string SnapshotId { get; set; } - [JsonProperty("tracks")] - public PlaylistTrackCollection Tracks { get; set; } + [JsonProperty("tracks")] + public PlaylistTrackCollection Tracks { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SimpleTrack.cs b/SpotifyAPI.Web/Models/SimpleTrack.cs index 85702a3e..aa4a8fe9 100644 --- a/SpotifyAPI.Web/Models/SimpleTrack.cs +++ b/SpotifyAPI.Web/Models/SimpleTrack.cs @@ -1,50 +1,50 @@ -using Newtonsoft.Json; using System.Collections.Generic; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class SimpleTrack : BasicModel - { - [JsonProperty("artists")] - public List Artists { get; set; } + public class SimpleTrack : BasicModel + { + [JsonProperty("artists")] + public List Artists { get; set; } - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } + [JsonProperty("available_markets")] + public List AvailableMarkets { get; set; } - [JsonProperty("disc_number")] - public int DiscNumber { get; set; } + [JsonProperty("disc_number")] + public int DiscNumber { get; set; } - [JsonProperty("duration_ms")] - public int DurationMs { get; set; } + [JsonProperty("duration_ms")] + public int DurationMs { get; set; } - [JsonProperty("explicit")] - public bool Explicit { get; set; } + [JsonProperty("explicit")] + public bool Explicit { get; set; } - [JsonProperty("external_urls")] - public Dictionary ExternUrls { get; set; } + [JsonProperty("external_urls")] + public Dictionary ExternUrls { get; set; } - [JsonProperty("href")] - public string Href { get; set; } + [JsonProperty("href")] + public string Href { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] + public string Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("preview_url")] - public string PreviewUrl { get; set; } + [JsonProperty("preview_url")] + public string PreviewUrl { get; set; } - [JsonProperty("track_number")] - public int TrackNumber { get; set; } + [JsonProperty("track_number")] + public int TrackNumber { get; set; } - [JsonProperty("restrictions")] - public Dictionary Restrictions { get; set; } + [JsonProperty("restrictions")] + public Dictionary Restrictions { get; set; } - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] + public string Type { get; set; } - [JsonProperty("uri")] - public string Uri { get; set; } - } + [JsonProperty("uri")] + public string Uri { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Snapshot.cs b/SpotifyAPI.Web/Models/Snapshot.cs index 4a7e3e7c..47c53096 100644 --- a/SpotifyAPI.Web/Models/Snapshot.cs +++ b/SpotifyAPI.Web/Models/Snapshot.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Snapshot : BasicModel - { - [JsonProperty("snapshot_id")] - public string SnapshotId { get; set; } - } + public class Snapshot : BasicModel + { + [JsonProperty("snapshot_id")] + public string SnapshotId { get; set; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Token.cs b/SpotifyAPI.Web/Models/Token.cs index 941d6f95..b5dc31d4 100644 --- a/SpotifyAPI.Web/Models/Token.cs +++ b/SpotifyAPI.Web/Models/Token.cs @@ -1,47 +1,47 @@ -using Newtonsoft.Json; using System; +using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class Token + public class Token + { + public 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; } - - /// - /// Checks if the token has expired - /// - /// - public bool IsExpired() - { - return CreateDate.Add(TimeSpan.FromSeconds(ExpiresIn)) <= DateTime.Now; - } - - public bool HasError() - { - return Error != null; - } + 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; } + + /// + /// Checks if the token has expired + /// + /// + public bool IsExpired() + { + return CreateDate.Add(TimeSpan.FromSeconds(ExpiresIn)) <= DateTime.Now; + } + + public bool HasError() + { + return Error != null; + } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/TuneableTrack.cs b/SpotifyAPI.Web/Models/TuneableTrack.cs index 9f3943b3..994caff9 100644 --- a/SpotifyAPI.Web/Models/TuneableTrack.cs +++ b/SpotifyAPI.Web/Models/TuneableTrack.cs @@ -1,69 +1,69 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Reflection; namespace SpotifyAPI.Web.Models { - public class TuneableTrack + 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) { - [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 urlParams = new List(); - foreach (PropertyInfo info in GetType().GetProperties()) - { - object value = info.GetValue(this); - string name = info.GetCustomAttribute()?.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 ""; - } + List urlParams = new List(); + foreach (PropertyInfo info in GetType().GetProperties()) + { + object value = info.GetValue(this); + string name = info.GetCustomAttribute()?.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 ""; } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/ProxyConfig.cs b/SpotifyAPI.Web/ProxyConfig.cs index 8b7a631e..4baec0a8 100644 --- a/SpotifyAPI.Web/ProxyConfig.cs +++ b/SpotifyAPI.Web/ProxyConfig.cs @@ -1,97 +1,97 @@ -using System; +using System; using System.Net; using System.Net.Http; namespace SpotifyAPI.Web { - public class ProxyConfig + public class ProxyConfig + { + public string Host { get; set; } + + public int Port { get; set; } = 80; + + public string Username { get; set; } + + public string Password { get; set; } + + /// + /// Whether to bypass the proxy server for local addresses. + /// + public bool BypassProxyOnLocal { get; set; } + + public void Set(ProxyConfig proxyConfig) { - public string Host { get; set; } - - public int Port { get; set; } = 80; - - public string Username { get; set; } - - public string Password { get; set; } - - /// - /// Whether to bypass the proxy server for local addresses. - /// - public bool BypassProxyOnLocal { get; set; } - - public void Set(ProxyConfig proxyConfig) - { - Host = proxyConfig?.Host; - Port = proxyConfig?.Port ?? 80; - Username = proxyConfig?.Username; - Password = proxyConfig?.Password; - BypassProxyOnLocal = proxyConfig?.BypassProxyOnLocal ?? false; - } - - /// - /// Whether both and have valid values. - /// - /// - public bool IsValid() - { - return !string.IsNullOrWhiteSpace(Host) && Port > 0; - } - - /// - /// Create a from the host and port number - /// - /// A URI - public Uri GetUri() - { - UriBuilder uriBuilder = new UriBuilder(Host) - { - Port = Port - }; - return uriBuilder.Uri; - } - - /// - /// Creates a from the proxy details of this object. - /// - /// A or null if the proxy details are invalid. - public WebProxy CreateWebProxy() - { - if (!IsValid()) - return null; - - WebProxy proxy = new WebProxy - { - Address = GetUri(), - UseDefaultCredentials = true, - BypassProxyOnLocal = BypassProxyOnLocal - }; - - if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password)) - return proxy; - - proxy.UseDefaultCredentials = false; - proxy.Credentials = new NetworkCredential(Username, Password); - - return proxy; - } - - public static HttpClientHandler CreateClientHandler(ProxyConfig proxyConfig = null) - { - HttpClientHandler clientHandler = new HttpClientHandler - { - PreAuthenticate = false, - UseDefaultCredentials = true, - UseProxy = false - }; - - if (string.IsNullOrWhiteSpace(proxyConfig?.Host)) return clientHandler; - WebProxy proxy = proxyConfig.CreateWebProxy(); - clientHandler.UseProxy = true; - clientHandler.Proxy = proxy; - clientHandler.UseDefaultCredentials = proxy.UseDefaultCredentials; - clientHandler.PreAuthenticate = proxy.UseDefaultCredentials; - - return clientHandler; - } + Host = proxyConfig?.Host; + Port = proxyConfig?.Port ?? 80; + Username = proxyConfig?.Username; + Password = proxyConfig?.Password; + BypassProxyOnLocal = proxyConfig?.BypassProxyOnLocal ?? false; } + + /// + /// Whether both and have valid values. + /// + /// + public bool IsValid() + { + return !string.IsNullOrWhiteSpace(Host) && Port > 0; + } + + /// + /// Create a from the host and port number + /// + /// A URI + public Uri GetUri() + { + UriBuilder uriBuilder = new UriBuilder(Host) + { + Port = Port + }; + return uriBuilder.Uri; + } + + /// + /// Creates a from the proxy details of this object. + /// + /// A or null if the proxy details are invalid. + public WebProxy CreateWebProxy() + { + if (!IsValid()) + return null; + + WebProxy proxy = new WebProxy + { + Address = GetUri(), + UseDefaultCredentials = true, + BypassProxyOnLocal = BypassProxyOnLocal + }; + + if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password)) + return proxy; + + proxy.UseDefaultCredentials = false; + proxy.Credentials = new NetworkCredential(Username, Password); + + return proxy; + } + + public static HttpClientHandler CreateClientHandler(ProxyConfig proxyConfig = null) + { + HttpClientHandler clientHandler = new HttpClientHandler + { + PreAuthenticate = false, + UseDefaultCredentials = true, + UseProxy = false + }; + + if (string.IsNullOrWhiteSpace(proxyConfig?.Host)) return clientHandler; + WebProxy proxy = proxyConfig.CreateWebProxy(); + clientHandler.UseProxy = true; + clientHandler.Proxy = proxy; + clientHandler.UseDefaultCredentials = proxy.UseDefaultCredentials; + clientHandler.PreAuthenticate = proxy.UseDefaultCredentials; + + return clientHandler; + } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/SpotifyWebAPI.cs b/SpotifyAPI.Web/SpotifyWebAPI.cs index 2c26e3b4..6cf94ae9 100644 --- a/SpotifyAPI.Web/SpotifyWebAPI.cs +++ b/SpotifyAPI.Web/SpotifyWebAPI.cs @@ -2938,4 +2938,4 @@ namespace SpotifyAPI.Web #endregion Util } -} +} \ No newline at end of file diff --git a/SpotifyAPI.Web/SpotifyWebBuilder.cs b/SpotifyAPI.Web/SpotifyWebBuilder.cs index 8cbe3383..120abef1 100644 --- a/SpotifyAPI.Web/SpotifyWebBuilder.cs +++ b/SpotifyAPI.Web/SpotifyWebBuilder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -1132,4 +1132,4 @@ namespace SpotifyAPI.Web } #endregion } -} +} \ No newline at end of file diff --git a/SpotifyAPI.Web/SpotifyWebClient.cs b/SpotifyAPI.Web/SpotifyWebClient.cs index 9beaffde..488cecd5 100644 --- a/SpotifyAPI.Web/SpotifyWebClient.cs +++ b/SpotifyAPI.Web/SpotifyWebClient.cs @@ -1,4 +1,3 @@ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; @@ -6,199 +5,201 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web { - internal class SpotifyWebClient : IClient + internal class SpotifyWebClient : IClient + { + public JsonSerializerSettings JsonSettings { get; set; } + private readonly Encoding _encoding = Encoding.UTF8; + private readonly HttpClient _client; + + private const string UnknownErrorJson = "{\"error\": { \"status\": 0, \"message\": \"SpotifyAPI.Web - Unkown Spotify Error\" }}"; + + public SpotifyWebClient(ProxyConfig proxyConfig = null) { - public JsonSerializerSettings JsonSettings { get; set; } - private readonly Encoding _encoding = Encoding.UTF8; - private readonly HttpClient _client; - - private const string UnknownErrorJson = "{\"error\": { \"status\": 0, \"message\": \"SpotifyAPI.Web - Unkown Spotify Error\" }}"; - - public SpotifyWebClient(ProxyConfig proxyConfig = null) - { - HttpClientHandler clientHandler = ProxyConfig.CreateClientHandler(proxyConfig); - _client = new HttpClient(clientHandler); - } - - public Tuple Download(string url, Dictionary headers = null) - { - Tuple raw = DownloadRaw(url, headers); - return new Tuple(raw.Item1, raw.Item2.Length > 0 ? _encoding.GetString(raw.Item2) : "{}"); - } - - public async Task> DownloadAsync(string url, Dictionary headers = null) - { - Tuple raw = await DownloadRawAsync(url, headers).ConfigureAwait(false); - return new Tuple(raw.Item1, raw.Item2.Length > 0 ? _encoding.GetString(raw.Item2) : "{}"); - } - - public Tuple DownloadRaw(string url, Dictionary headers = null) - { - if (headers != null) - { - AddHeaders(headers); - } - using (HttpResponseMessage response = Task.Run(() => _client.GetAsync(url)).Result) - { - return new Tuple(new ResponseInfo - { - StatusCode = response.StatusCode, - Headers = ConvertHeaders(response.Headers) - }, Task.Run(() => response.Content.ReadAsByteArrayAsync()).Result); - } - } - - public async Task> DownloadRawAsync(string url, Dictionary headers = null) - { - if (headers != null) - { - AddHeaders(headers); - } - using (HttpResponseMessage response = await _client.GetAsync(url).ConfigureAwait(false)) - { - return new Tuple(new ResponseInfo - { - StatusCode = response.StatusCode, - Headers = ConvertHeaders(response.Headers) - }, await response.Content.ReadAsByteArrayAsync()); - } - } - - public Tuple DownloadJson(string url, Dictionary headers = null) - { - Tuple response = Download(url, headers); - try - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); - } - catch (JsonException) - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); - } - } - - public async Task> DownloadJsonAsync(string url, Dictionary headers = null) - { - Tuple response = await DownloadAsync(url, headers).ConfigureAwait(false);try - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); - } - catch (JsonException) - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); - } - } - - public Tuple Upload(string url, string body, string method, Dictionary headers = null) - { - Tuple data = UploadRaw(url, body, method, headers); - return new Tuple(data.Item1, data.Item2.Length > 0 ? _encoding.GetString(data.Item2) : "{}"); - } - - public async Task> UploadAsync(string url, string body, string method, Dictionary headers = null) - { - Tuple data = await UploadRawAsync(url, body, method, headers).ConfigureAwait(false); - return new Tuple(data.Item1, data.Item2.Length > 0 ? _encoding.GetString(data.Item2) : "{}"); - } - - public Tuple UploadRaw(string url, string body, string method, Dictionary headers = null) - { - if (headers != null) - { - AddHeaders(headers); - } - - HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(method), url) - { - Content = new StringContent(body, _encoding) - }; - using (HttpResponseMessage response = Task.Run(() => _client.SendAsync(message)).Result) - { - return new Tuple(new ResponseInfo - { - StatusCode = response.StatusCode, - Headers = ConvertHeaders(response.Headers) - }, Task.Run(() => response.Content.ReadAsByteArrayAsync()).Result); - } - } - - public async Task> UploadRawAsync(string url, string body, string method, Dictionary headers = null) - { - if (headers != null) - { - AddHeaders(headers); - } - - HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(method), url) - { - Content = new StringContent(body, _encoding) - }; - using (HttpResponseMessage response = await _client.SendAsync(message)) - { - return new Tuple(new ResponseInfo - { - StatusCode = response.StatusCode, - Headers = ConvertHeaders(response.Headers) - }, await response.Content.ReadAsByteArrayAsync()); - } - } - - public Tuple UploadJson(string url, string body, string method, Dictionary headers = null) - { - Tuple response = Upload(url, body, method, headers); - try - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); - } - catch (JsonException) - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); - } - } - - public async Task> UploadJsonAsync(string url, string body, string method, Dictionary headers = null) - { - Tuple response = await UploadAsync(url, body, method, headers).ConfigureAwait(false); - try - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); - } - catch (JsonException) - { - return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); - } - } - - public void Dispose() - { - _client.Dispose(); - GC.SuppressFinalize(this); - } - - private static WebHeaderCollection ConvertHeaders(HttpResponseHeaders headers) - { - WebHeaderCollection newHeaders = new WebHeaderCollection(); - foreach (KeyValuePair> headerPair in headers) - { - foreach (string headerValue in headerPair.Value) - { - newHeaders.Add(headerPair.Key, headerValue); - } - } - return newHeaders; - } - - private void AddHeaders(Dictionary headers) - { - _client.DefaultRequestHeaders.Clear(); - foreach (KeyValuePair headerPair in headers) - { - _client.DefaultRequestHeaders.TryAddWithoutValidation(headerPair.Key, headerPair.Value); - } - } + HttpClientHandler clientHandler = ProxyConfig.CreateClientHandler(proxyConfig); + _client = new HttpClient(clientHandler); } + + public Tuple Download(string url, Dictionary headers = null) + { + Tuple raw = DownloadRaw(url, headers); + return new Tuple(raw.Item1, raw.Item2.Length > 0 ? _encoding.GetString(raw.Item2) : "{}"); + } + + public async Task> DownloadAsync(string url, Dictionary headers = null) + { + Tuple raw = await DownloadRawAsync(url, headers).ConfigureAwait(false); + return new Tuple(raw.Item1, raw.Item2.Length > 0 ? _encoding.GetString(raw.Item2) : "{}"); + } + + public Tuple DownloadRaw(string url, Dictionary headers = null) + { + if (headers != null) + { + AddHeaders(headers); + } + using(HttpResponseMessage response = Task.Run(() => _client.GetAsync(url)).Result) + { + return new Tuple(new ResponseInfo + { + StatusCode = response.StatusCode, + Headers = ConvertHeaders(response.Headers) + }, Task.Run(() => response.Content.ReadAsByteArrayAsync()).Result); + } + } + + public async Task> DownloadRawAsync(string url, Dictionary headers = null) + { + if (headers != null) + { + AddHeaders(headers); + } + using(HttpResponseMessage response = await _client.GetAsync(url).ConfigureAwait(false)) + { + return new Tuple(new ResponseInfo + { + StatusCode = response.StatusCode, + Headers = ConvertHeaders(response.Headers) + }, await response.Content.ReadAsByteArrayAsync()); + } + } + + public Tuple DownloadJson(string url, Dictionary headers = null) + { + Tuple response = Download(url, headers); + try + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); + } + catch (JsonException) + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); + } + } + + public async Task> DownloadJsonAsync(string url, Dictionary headers = null) + { + Tuple response = await DownloadAsync(url, headers).ConfigureAwait(false); + try + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); + } + catch (JsonException) + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); + } + } + + public Tuple Upload(string url, string body, string method, Dictionary headers = null) + { + Tuple data = UploadRaw(url, body, method, headers); + return new Tuple(data.Item1, data.Item2.Length > 0 ? _encoding.GetString(data.Item2) : "{}"); + } + + public async Task> UploadAsync(string url, string body, string method, Dictionary headers = null) + { + Tuple data = await UploadRawAsync(url, body, method, headers).ConfigureAwait(false); + return new Tuple(data.Item1, data.Item2.Length > 0 ? _encoding.GetString(data.Item2) : "{}"); + } + + public Tuple UploadRaw(string url, string body, string method, Dictionary headers = null) + { + if (headers != null) + { + AddHeaders(headers); + } + + HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(method), url) + { + Content = new StringContent(body, _encoding) + }; + using(HttpResponseMessage response = Task.Run(() => _client.SendAsync(message)).Result) + { + return new Tuple(new ResponseInfo + { + StatusCode = response.StatusCode, + Headers = ConvertHeaders(response.Headers) + }, Task.Run(() => response.Content.ReadAsByteArrayAsync()).Result); + } + } + + public async Task> UploadRawAsync(string url, string body, string method, Dictionary headers = null) + { + if (headers != null) + { + AddHeaders(headers); + } + + HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(method), url) + { + Content = new StringContent(body, _encoding) + }; + using(HttpResponseMessage response = await _client.SendAsync(message)) + { + return new Tuple(new ResponseInfo + { + StatusCode = response.StatusCode, + Headers = ConvertHeaders(response.Headers) + }, await response.Content.ReadAsByteArrayAsync()); + } + } + + public Tuple UploadJson(string url, string body, string method, Dictionary headers = null) + { + Tuple response = Upload(url, body, method, headers); + try + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); + } + catch (JsonException) + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); + } + } + + public async Task> UploadJsonAsync(string url, string body, string method, Dictionary headers = null) + { + Tuple response = await UploadAsync(url, body, method, headers).ConfigureAwait(false); + try + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(response.Item2, JsonSettings)); + } + catch (JsonException) + { + return new Tuple(response.Item1, JsonConvert.DeserializeObject(UnknownErrorJson, JsonSettings)); + } + } + + public void Dispose() + { + _client.Dispose(); + GC.SuppressFinalize(this); + } + + private static WebHeaderCollection ConvertHeaders(HttpResponseHeaders headers) + { + WebHeaderCollection newHeaders = new WebHeaderCollection(); + foreach (KeyValuePair> headerPair in headers) + { + foreach (string headerValue in headerPair.Value) + { + newHeaders.Add(headerPair.Key, headerValue); + } + } + return newHeaders; + } + + private void AddHeaders(Dictionary headers) + { + _client.DefaultRequestHeaders.Clear(); + foreach (KeyValuePair headerPair in headers) + { + _client.DefaultRequestHeaders.TryAddWithoutValidation(headerPair.Key, headerPair.Value); + } + } + } } \ No newline at end of file diff --git a/SpotifyAPI.Web/Util.cs b/SpotifyAPI.Web/Util.cs index 5d6df3c0..2cb2ca5b 100644 --- a/SpotifyAPI.Web/Util.cs +++ b/SpotifyAPI.Web/Util.cs @@ -1,41 +1,41 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; namespace SpotifyAPI.Web { - public static class Util + public static class Util + { + public static string GetStringAttribute(this T en, string separator = "") where T : struct, IConvertible { - public static string GetStringAttribute(this T en, string separator = "") where T : struct, IConvertible - { - Enum e = (Enum)(object)en; - IEnumerable attributes = - Enum.GetValues(typeof(T)) - .Cast() - .Where(v => e.HasFlag((Enum)(object)v)) - .Select(v => typeof(T).GetField(v.ToString(CultureInfo.InvariantCulture))) - .Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0]) - .Cast(); + Enum e = (Enum) (object) en; + IEnumerable attributes = + Enum.GetValues(typeof(T)) + .Cast() + .Where(v => e.HasFlag((Enum) (object) v)) + .Select(v => typeof(T).GetField(v.ToString(CultureInfo.InvariantCulture))) + .Select(f => f.GetCustomAttributes(typeof(StringAttribute), false) [0]) + .Cast(); - List list = new List(); - attributes.ToList().ForEach(element => list.Add(element.Text)); - return string.Join(separator, list); - } - - public static long ToUnixTimeMillisecondsPoly(this DateTime time) - { - return (long)time.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; - } + List list = new List(); + attributes.ToList().ForEach(element => list.Add(element.Text)); + return string.Join(separator, list); } - public sealed class StringAttribute : Attribute + public static long ToUnixTimeMillisecondsPoly(this DateTime time) { - public string Text { get; set; } - - public StringAttribute(string text) - { - Text = text; - } + return (long) time.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; } -} + } + + public sealed class StringAttribute : Attribute + { + public string Text { get; set; } + + public StringAttribute(string text) + { + Text = text; + } + } +} \ No newline at end of file