From 2c4463529b40363276a17e458902521b0d64a07f Mon Sep 17 00:00:00 2001 From: Jonas Dellinger Date: Fri, 1 May 2020 20:05:28 +0200 Subject: [PATCH] Start refactoring for version 6 --- .vscode/csharp.code-snippets | 18 + .vscode/settings.json | 2 - .../SpotifyAPI.Web.Auth.csproj | 6 +- SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs | 79 - SpotifyAPI.Web.Tests/UtilTests/Test.cs | 21 + .../UtilTests/URIExtensionTest.cs | 51 + .../URIParameterFormatProviderTest.cs | 34 + .../fixtures/private-user.json | 25 - .../fixtures/public-user.json | 9 - SpotifyAPI.Web/Clients/APIClient.cs | 16 + SpotifyAPI.Web/Clients/BrowseClient.cs | 55 + .../Clients/Interfaces/IBrowseClient.cs | 16 + .../Clients/Interfaces/ISpotifyClient.cs | 9 + .../Clients/Interfaces/IUserProfileClient.cs | 24 + SpotifyAPI.Web/Clients/SpotifyClient.cs | 30 + SpotifyAPI.Web/Clients/UserProfileClient.cs | 24 + SpotifyAPI.Web/Exceptions/APIException.cs | 43 + .../Exceptions/APIUnauthorizedException.cs | 10 + SpotifyAPI.Web/Http/APIConnector.cs | 155 + SpotifyAPI.Web/Http/APIResponse.cs | 17 + .../Http/Interfaces/IAPIConnector.cs | 32 + .../Http/Interfaces/IAPIResponse.cs | 9 + .../Http/Interfaces/IAuthenticator.cs | 9 + SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs | 12 + .../Http/Interfaces/IJSONSerializer.cs | 10 + SpotifyAPI.Web/Http/Interfaces/IRequest.cs | 23 + SpotifyAPI.Web/Http/Interfaces/IResponse.cs | 16 + SpotifyAPI.Web/Http/NetHttpClient.cs | 98 + .../Http/NewtonsoftJSONSerializer.cs | 50 + SpotifyAPI.Web/Http/Request.cs | 29 + SpotifyAPI.Web/Http/Response.cs | 25 + .../Http/TokenHeaderAuthenticator.cs | 23 + SpotifyAPI.Web/IClient.cs | 125 - SpotifyAPI.Web/Models/AnalysisMeta.cs | 28 - SpotifyAPI.Web/Models/AnalysisSection.cs | 43 - SpotifyAPI.Web/Models/AnalysisSegment.cs | 35 - SpotifyAPI.Web/Models/AnalysisTimeSlice.cs | 16 - SpotifyAPI.Web/Models/AnalysisTrack.cs | 86 - SpotifyAPI.Web/Models/ArrayResponse.cs | 9 - SpotifyAPI.Web/Models/AudioAnalysis.cs | 29 - SpotifyAPI.Web/Models/AudioFeatures.cs | 61 - SpotifyAPI.Web/Models/AvailabeDevices.cs | 11 - SpotifyAPI.Web/Models/BasicModel.cs | 23 - SpotifyAPI.Web/Models/Category.cs | 20 - SpotifyAPI.Web/Models/CategoryList.cs | 10 - SpotifyAPI.Web/Models/CategoryPlaylist.cs | 10 - .../Converters/PlaylistElementConverter.cs | 45 + SpotifyAPI.Web/Models/CursorPaging.cs | 31 - SpotifyAPI.Web/Models/Device.cs | 25 - SpotifyAPI.Web/Models/FeaturedPlaylists.cs | 13 - SpotifyAPI.Web/Models/FollowedArtists.cs | 10 - SpotifyAPI.Web/Models/FullAlbum.cs | 68 - SpotifyAPI.Web/Models/FullArtist.cs | 38 - SpotifyAPI.Web/Models/FullPlaylist.cs | 50 - SpotifyAPI.Web/Models/FullTrack.cs | 71 - SpotifyAPI.Web/Models/GeneralModels.cs | 158 - SpotifyAPI.Web/Models/NewAlbumReleases.cs | 10 - SpotifyAPI.Web/Models/Paging.cs | 39 - SpotifyAPI.Web/Models/PlayHistory.cs | 17 - SpotifyAPI.Web/Models/PlaybackContext.cs | 38 - SpotifyAPI.Web/Models/PrivateProfile.cs | 44 - SpotifyAPI.Web/Models/RecommendationSeed .cs | 25 - .../Models/RecommendationSeedGenres.cs | 11 - SpotifyAPI.Web/Models/Recommendations.cs | 14 - .../Models/Request/CategoriesRequest.cs | 17 + .../Request/CategoryPlaylistsRequest.cs | 14 + .../Models/Request/CategoryRequest.cs | 11 + .../Models/Request/RequestParams.cs | 44 + .../Models/Response/CategoriesResponse.cs | 7 + SpotifyAPI.Web/Models/Response/Category.cs | 12 + .../Response/CategoryPlaylistsResponse.cs | 7 + SpotifyAPI.Web/Models/Response/Copyright.cs | 8 + SpotifyAPI.Web/Models/Response/Followers.cs | 9 + SpotifyAPI.Web/Models/Response/FullEpisode.cs | 25 + SpotifyAPI.Web/Models/Response/FullTrack.cs | 28 + SpotifyAPI.Web/Models/Response/Image.cs | 9 + .../Response/Interfaces/IPlaylistElement.cs | 16 + SpotifyAPI.Web/Models/Response/LinkedTrack.cs | 12 + SpotifyAPI.Web/Models/Response/Paging.cs | 15 + .../Models/Response/PlaylistTrack.cs | 11 + .../PrivateUser.cs} | 22 +- SpotifyAPI.Web/Models/Response/PublicUser.cs | 17 + .../Models/Response/ResumePointObject.cs | 8 + .../Models/{ => Response}/SimpleAlbum.cs | 37 +- .../Models/{ => Response}/SimpleArtist.cs | 17 +- .../Models/Response/SimplePlaylist.cs | 23 + SpotifyAPI.Web/Models/Response/SimpleShow.cs | 22 + SpotifyAPI.Web/Models/ResponseInfo.cs | 13 - SpotifyAPI.Web/Models/SearchItem.cs | 19 - SpotifyAPI.Web/Models/SeveralAlbums.cs | 11 - SpotifyAPI.Web/Models/SeveralArtists.cs | 11 - SpotifyAPI.Web/Models/SeveralAudioFeatures.cs | 11 - SpotifyAPI.Web/Models/SeveralTracks.cs | 11 - SpotifyAPI.Web/Models/SimplePlaylist.cs | 44 - SpotifyAPI.Web/Models/SimpleTrack.cs | 50 - SpotifyAPI.Web/Models/Snapshot.cs | 10 - SpotifyAPI.Web/Models/Token.cs | 47 - SpotifyAPI.Web/Models/TuneableTrack.cs | 69 - SpotifyAPI.Web/SpotifyAPI.Web.csproj | 2 +- SpotifyAPI.Web/SpotifyUrls.cs | 23 + SpotifyAPI.Web/SpotifyWebAPI.cs | 2941 ----------------- SpotifyAPI.Web/SpotifyWebBuilder.cs | 1135 ------- SpotifyAPI.Web/SpotifyWebClient.cs | 205 -- SpotifyAPI.Web/Util/Ensure.cs | 34 + SpotifyAPI.Web/Util/URIExtension.cs | 40 + .../Util/URIParameterFormatProvider.cs | 29 + 106 files changed, 1359 insertions(+), 5930 deletions(-) create mode 100644 .vscode/csharp.code-snippets delete mode 100644 SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs create mode 100644 SpotifyAPI.Web.Tests/UtilTests/Test.cs create mode 100644 SpotifyAPI.Web.Tests/UtilTests/URIExtensionTest.cs create mode 100644 SpotifyAPI.Web.Tests/UtilTests/URIParameterFormatProviderTest.cs delete mode 100644 SpotifyAPI.Web.Tests/fixtures/private-user.json delete mode 100644 SpotifyAPI.Web.Tests/fixtures/public-user.json create mode 100644 SpotifyAPI.Web/Clients/APIClient.cs create mode 100644 SpotifyAPI.Web/Clients/BrowseClient.cs create mode 100644 SpotifyAPI.Web/Clients/Interfaces/IBrowseClient.cs create mode 100644 SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs create mode 100644 SpotifyAPI.Web/Clients/Interfaces/IUserProfileClient.cs create mode 100644 SpotifyAPI.Web/Clients/SpotifyClient.cs create mode 100644 SpotifyAPI.Web/Clients/UserProfileClient.cs create mode 100644 SpotifyAPI.Web/Exceptions/APIException.cs create mode 100644 SpotifyAPI.Web/Exceptions/APIUnauthorizedException.cs create mode 100644 SpotifyAPI.Web/Http/APIConnector.cs create mode 100644 SpotifyAPI.Web/Http/APIResponse.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IAPIResponse.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IAuthenticator.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IJSONSerializer.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IRequest.cs create mode 100644 SpotifyAPI.Web/Http/Interfaces/IResponse.cs create mode 100644 SpotifyAPI.Web/Http/NetHttpClient.cs create mode 100644 SpotifyAPI.Web/Http/NewtonsoftJSONSerializer.cs create mode 100644 SpotifyAPI.Web/Http/Request.cs create mode 100644 SpotifyAPI.Web/Http/Response.cs create mode 100644 SpotifyAPI.Web/Http/TokenHeaderAuthenticator.cs delete mode 100644 SpotifyAPI.Web/IClient.cs delete mode 100644 SpotifyAPI.Web/Models/AnalysisMeta.cs delete mode 100644 SpotifyAPI.Web/Models/AnalysisSection.cs delete mode 100644 SpotifyAPI.Web/Models/AnalysisSegment.cs delete mode 100644 SpotifyAPI.Web/Models/AnalysisTimeSlice.cs delete mode 100644 SpotifyAPI.Web/Models/AnalysisTrack.cs delete mode 100644 SpotifyAPI.Web/Models/ArrayResponse.cs delete mode 100644 SpotifyAPI.Web/Models/AudioAnalysis.cs delete mode 100644 SpotifyAPI.Web/Models/AudioFeatures.cs delete mode 100644 SpotifyAPI.Web/Models/AvailabeDevices.cs delete mode 100644 SpotifyAPI.Web/Models/BasicModel.cs delete mode 100644 SpotifyAPI.Web/Models/Category.cs delete mode 100644 SpotifyAPI.Web/Models/CategoryList.cs delete mode 100644 SpotifyAPI.Web/Models/CategoryPlaylist.cs create mode 100644 SpotifyAPI.Web/Models/Converters/PlaylistElementConverter.cs delete mode 100644 SpotifyAPI.Web/Models/CursorPaging.cs delete mode 100644 SpotifyAPI.Web/Models/Device.cs delete mode 100644 SpotifyAPI.Web/Models/FeaturedPlaylists.cs delete mode 100644 SpotifyAPI.Web/Models/FollowedArtists.cs delete mode 100644 SpotifyAPI.Web/Models/FullAlbum.cs delete mode 100644 SpotifyAPI.Web/Models/FullArtist.cs delete mode 100644 SpotifyAPI.Web/Models/FullPlaylist.cs delete mode 100644 SpotifyAPI.Web/Models/FullTrack.cs delete mode 100644 SpotifyAPI.Web/Models/GeneralModels.cs delete mode 100644 SpotifyAPI.Web/Models/NewAlbumReleases.cs delete mode 100644 SpotifyAPI.Web/Models/Paging.cs delete mode 100644 SpotifyAPI.Web/Models/PlayHistory.cs delete mode 100644 SpotifyAPI.Web/Models/PlaybackContext.cs delete mode 100644 SpotifyAPI.Web/Models/PrivateProfile.cs delete mode 100644 SpotifyAPI.Web/Models/RecommendationSeed .cs delete mode 100644 SpotifyAPI.Web/Models/RecommendationSeedGenres.cs delete mode 100644 SpotifyAPI.Web/Models/Recommendations.cs create mode 100644 SpotifyAPI.Web/Models/Request/CategoriesRequest.cs create mode 100644 SpotifyAPI.Web/Models/Request/CategoryPlaylistsRequest.cs create mode 100644 SpotifyAPI.Web/Models/Request/CategoryRequest.cs create mode 100644 SpotifyAPI.Web/Models/Request/RequestParams.cs create mode 100644 SpotifyAPI.Web/Models/Response/CategoriesResponse.cs create mode 100644 SpotifyAPI.Web/Models/Response/Category.cs create mode 100644 SpotifyAPI.Web/Models/Response/CategoryPlaylistsResponse.cs create mode 100644 SpotifyAPI.Web/Models/Response/Copyright.cs create mode 100644 SpotifyAPI.Web/Models/Response/Followers.cs create mode 100644 SpotifyAPI.Web/Models/Response/FullEpisode.cs create mode 100644 SpotifyAPI.Web/Models/Response/FullTrack.cs create mode 100644 SpotifyAPI.Web/Models/Response/Image.cs create mode 100644 SpotifyAPI.Web/Models/Response/Interfaces/IPlaylistElement.cs create mode 100644 SpotifyAPI.Web/Models/Response/LinkedTrack.cs create mode 100644 SpotifyAPI.Web/Models/Response/Paging.cs create mode 100644 SpotifyAPI.Web/Models/Response/PlaylistTrack.cs rename SpotifyAPI.Web/Models/{PublicProfile.cs => Response/PrivateUser.cs} (60%) create mode 100644 SpotifyAPI.Web/Models/Response/PublicUser.cs create mode 100644 SpotifyAPI.Web/Models/Response/ResumePointObject.cs rename SpotifyAPI.Web/Models/{ => Response}/SimpleAlbum.cs (52%) rename SpotifyAPI.Web/Models/{ => Response}/SimpleArtist.cs (52%) create mode 100644 SpotifyAPI.Web/Models/Response/SimplePlaylist.cs create mode 100644 SpotifyAPI.Web/Models/Response/SimpleShow.cs delete mode 100644 SpotifyAPI.Web/Models/ResponseInfo.cs delete mode 100644 SpotifyAPI.Web/Models/SearchItem.cs delete mode 100644 SpotifyAPI.Web/Models/SeveralAlbums.cs delete mode 100644 SpotifyAPI.Web/Models/SeveralArtists.cs delete mode 100644 SpotifyAPI.Web/Models/SeveralAudioFeatures.cs delete mode 100644 SpotifyAPI.Web/Models/SeveralTracks.cs delete mode 100644 SpotifyAPI.Web/Models/SimplePlaylist.cs delete mode 100644 SpotifyAPI.Web/Models/SimpleTrack.cs delete mode 100644 SpotifyAPI.Web/Models/Snapshot.cs delete mode 100644 SpotifyAPI.Web/Models/Token.cs delete mode 100644 SpotifyAPI.Web/Models/TuneableTrack.cs create mode 100644 SpotifyAPI.Web/SpotifyUrls.cs delete mode 100644 SpotifyAPI.Web/SpotifyWebAPI.cs delete mode 100644 SpotifyAPI.Web/SpotifyWebBuilder.cs delete mode 100644 SpotifyAPI.Web/SpotifyWebClient.cs create mode 100644 SpotifyAPI.Web/Util/Ensure.cs create mode 100644 SpotifyAPI.Web/Util/URIExtension.cs create mode 100644 SpotifyAPI.Web/Util/URIParameterFormatProvider.cs diff --git a/.vscode/csharp.code-snippets b/.vscode/csharp.code-snippets new file mode 100644 index 00000000..8eae99f8 --- /dev/null +++ b/.vscode/csharp.code-snippets @@ -0,0 +1,18 @@ +{ + "model": { + "scope": "csharp", + "prefix": "model", + "body": [ + "namespace SpotifyAPI.Web", + "{", + " public class $1", + " {", + " public ${2:string} ${3:Name} { get; set; }", + "", + " $4", + " }", + "}" + ], + "description": "Creates a new model" + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index f8f049f6..56af8e14 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,4 @@ "editor.detectIndentation": false, "editor.insertSpaces": true, "editor.tabSize": 2, - "csharpfixformat.style.braces.onSameLine": false, - "csharpfixformat.style.spaces.beforeParenthesis": false, } diff --git a/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj b/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj index 09b14f63..4e991185 100644 --- a/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj +++ b/SpotifyAPI.Web.Auth/SpotifyAPI.Web.Auth.csproj @@ -1,7 +1,7 @@  - netstandard2.0 - + netstandard2.1 + SpotifyAPI.Web.Auth SpotifyAPI.Web.Auth Jonas Dellinger @@ -27,7 +27,7 @@ bin\Release\netstandard2.0\SpotifyAPI.Web.Auth.xml 1701;1702;1705;1591 - + None diff --git a/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs b/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs deleted file mode 100644 index 48c598c0..00000000 --- a/SpotifyAPI.Web.Tests/SpotifyWebAPITest.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Moq; -using Newtonsoft.Json; -using NUnit.Framework; -using SpotifyAPI.Web.Models; - -namespace SpotifyAPI.Web.Tests -{ - [TestFixture] - public class SpotifyWebAPITest - { - private static readonly string FixtureDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../fixtures/"); - - private Mock _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?) - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web.Tests/UtilTests/Test.cs b/SpotifyAPI.Web.Tests/UtilTests/Test.cs new file mode 100644 index 00000000..657ade42 --- /dev/null +++ b/SpotifyAPI.Web.Tests/UtilTests/Test.cs @@ -0,0 +1,21 @@ +using System; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace SpotifyAPI.Web.Tests +{ + [TestFixture] + public class Test + { + [Test] + public async Task Testing() + { + var token = ""; + + var spotify = new SpotifyClient(token); + + var categories = await spotify.Browse.GetCategories(); + var playlists = await spotify.Browse.GetCategoryPlaylists(categories.Categories.Items[0].Id); + } + } +} diff --git a/SpotifyAPI.Web.Tests/UtilTests/URIExtensionTest.cs b/SpotifyAPI.Web.Tests/UtilTests/URIExtensionTest.cs new file mode 100644 index 00000000..96daa508 --- /dev/null +++ b/SpotifyAPI.Web.Tests/UtilTests/URIExtensionTest.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System; +using NUnit.Framework; + +namespace SpotifyAPI.Web.Tests +{ + [TestFixture] + public class URIExtensionTest + { + [Test] + public void ApplyParameters_WithoutExistingParameters() + { + var expected = "http://google.com/?hello=world&nice=day"; + Uri uri = new Uri("http://google.com/"); + + var parameters = new Dictionary + { + { "hello", "world" }, + { "nice", "day" } + }; + Assert.AreEqual(expected, uri.ApplyParameters(parameters).ToString()); + } + + [Test] + public void ApplyParameters_WithExistingParameters() + { + var expected = "http://google.com/?existing=paramter&hello=world&nice=day"; + Uri uri = new Uri("http://google.com/?existing=paramter"); + + var parameters = new Dictionary + { + { "hello", "world" }, + { "nice", "day" } + }; + Assert.AreEqual(expected, uri.ApplyParameters(parameters).ToString()); + } + + [Test] + public void ApplyParameters_HandlesEscape() + { + var expected = "http://google.com/?existing=paramter&hello=%26world++"; + Uri uri = new Uri("http://google.com/?existing=paramter"); + + var parameters = new Dictionary + { + { "hello", "&world " }, + }; + Assert.AreEqual(expected, uri.ApplyParameters(parameters).ToString()); + } + } +} diff --git a/SpotifyAPI.Web.Tests/UtilTests/URIParameterFormatProviderTest.cs b/SpotifyAPI.Web.Tests/UtilTests/URIParameterFormatProviderTest.cs new file mode 100644 index 00000000..2e47a65c --- /dev/null +++ b/SpotifyAPI.Web.Tests/UtilTests/URIParameterFormatProviderTest.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System; +using NUnit.Framework; + +namespace SpotifyAPI.Web.Tests +{ + [TestFixture] + public class URIParameterFormatProviderTest + { + [Test] + public void Format_NormalParameters() + { + var expected = "/users/wizzler"; + + var user = "wizzler"; + var formatter = new URIParameterFormatProvider(); + Func func = (FormattableString str) => str.ToString(formatter); + + Assert.AreEqual(expected, func($"/users/{user}")); + } + + [Test] + public void Format_EscapedParameters() + { + var expected = "/users/++wizzler"; + + var user = " wizzler"; + var formatter = new URIParameterFormatProvider(); + Func func = (FormattableString str) => str.ToString(formatter); + + Assert.AreEqual(expected, func($"/users/{user}")); + } + } +} diff --git a/SpotifyAPI.Web.Tests/fixtures/private-user.json b/SpotifyAPI.Web.Tests/fixtures/private-user.json deleted file mode 100644 index 6b491929..00000000 --- a/SpotifyAPI.Web.Tests/fixtures/private-user.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "birthdate": "1937-06-01", - "country": "SE", - "display_name": "JM Wizzler", - "email": "email@example.com", - "external_urls": { - "spotify": "https://open.spotify.com/user/wizzler" - }, - "followers" : { - "href" : null, - "total" : 3829 - }, - "href": "https://api.spotify.com/v1/users/wizzler", - "id": "wizzler", - "images": [ - { - "height": 200, - "url": "https://fbcdn-profile-a.akamaihd.net/hprofile-ak-frc3/t1.0-1/1970403_10152215092574354_1798272330_n.jpg", - "width": 200 - } - ], - "product": "premium", - "type": "user", - "uri": "spotify:user:wizzler" -} \ No newline at end of file diff --git a/SpotifyAPI.Web.Tests/fixtures/public-user.json b/SpotifyAPI.Web.Tests/fixtures/public-user.json deleted file mode 100644 index e56f06c5..00000000 --- a/SpotifyAPI.Web.Tests/fixtures/public-user.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "external_urls": { - "spotify": "https://open.spotify.com/user/wizzler" - }, - "href": "https://api.spotify.com/v1/users/wizzler", - "id": "wizzler", - "type": "user", - "uri": "spotify:user:wizzler" -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Clients/APIClient.cs b/SpotifyAPI.Web/Clients/APIClient.cs new file mode 100644 index 00000000..7008b13f --- /dev/null +++ b/SpotifyAPI.Web/Clients/APIClient.cs @@ -0,0 +1,16 @@ +using SpotifyAPI.Web.Http; + +namespace SpotifyAPI.Web +{ + public abstract class APIClient + { + public APIClient(IAPIConnector apiConnector) + { + Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); + + API = apiConnector; + } + + public IAPIConnector API { get; set; } + } +} diff --git a/SpotifyAPI.Web/Clients/BrowseClient.cs b/SpotifyAPI.Web/Clients/BrowseClient.cs new file mode 100644 index 00000000..f07217e9 --- /dev/null +++ b/SpotifyAPI.Web/Clients/BrowseClient.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using SpotifyAPI.Web.Http; +using SpotifyAPI.Web.Models; +using URLs = SpotifyAPI.Web.SpotifyUrls; + +namespace SpotifyAPI.Web +{ + public class BrowseClient : APIClient, IBrowseClient + { + public BrowseClient(IAPIConnector apiConnector) : base(apiConnector) { } + + public Task GetCategories() + { + return API.Get(URLs.Categories()); + } + + public Task GetCategories(CategoriesRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.Categories(), request.BuildQueryParams()); + } + + public Task GetCategory(string categoryId) + { + Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId)); + + return API.Get(URLs.Category(categoryId)); + } + + public Task GetCategory(string categoryId, CategoryRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId)); + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.Category(categoryId), request.BuildQueryParams()); + } + + public Task GetCategoryPlaylists(string categoryId) + { + Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId)); + + return API.Get(URLs.CategoryPlaylists(categoryId)); + } + + public Task GetCategoryPlaylists(string categoryId, CategoriesPlaylistsRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(categoryId, nameof(categoryId)); + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.CategoryPlaylists(categoryId), request.BuildQueryParams()); + } + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/IBrowseClient.cs b/SpotifyAPI.Web/Clients/Interfaces/IBrowseClient.cs new file mode 100644 index 00000000..974c1774 --- /dev/null +++ b/SpotifyAPI.Web/Clients/Interfaces/IBrowseClient.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; + +namespace SpotifyAPI.Web +{ + public interface IBrowseClient + { + Task GetCategories(); + Task GetCategories(CategoriesRequest request); + + Task GetCategory(string categoryId); + Task GetCategory(string categoryId, CategoryRequest request); + + Task GetCategoryPlaylists(string categoryId); + Task GetCategoryPlaylists(string categoryId, CategoriesPlaylistsRequest request); + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs new file mode 100644 index 00000000..4f33b281 --- /dev/null +++ b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs @@ -0,0 +1,9 @@ +namespace SpotifyAPI.Web +{ + interface ISpotifyClient + { + IUserProfileClient UserProfile { get; } + + IBrowseClient Browse { get; } + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/IUserProfileClient.cs b/SpotifyAPI.Web/Clients/Interfaces/IUserProfileClient.cs new file mode 100644 index 00000000..419e5e2a --- /dev/null +++ b/SpotifyAPI.Web/Clients/Interfaces/IUserProfileClient.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using SpotifyAPI.Web.Models; + +namespace SpotifyAPI.Web +{ + public interface IUserProfileClient + { + /// + /// Test + /// + /// Thrown if the client is not authenticated. + /// A + Task Current(); + + + /// + /// + /// + /// + /// Thrown if the client is not authenticated. + /// + Task Get(string userId); + } +} diff --git a/SpotifyAPI.Web/Clients/SpotifyClient.cs b/SpotifyAPI.Web/Clients/SpotifyClient.cs new file mode 100644 index 00000000..61aab136 --- /dev/null +++ b/SpotifyAPI.Web/Clients/SpotifyClient.cs @@ -0,0 +1,30 @@ +using SpotifyAPI.Web.Http; + +namespace SpotifyAPI.Web +{ + public class SpotifyClient : ISpotifyClient + { + private IAPIConnector _apiConnector; + + public SpotifyClient(string token, string tokenType = "Bearer") : + this(new TokenHeaderAuthenticator(token, tokenType)) + { } + + public SpotifyClient(IAuthenticator authenticator) : + this(new APIConnector(SpotifyUrls.API_V1, authenticator)) + { } + + public SpotifyClient(IAPIConnector apiConnector) + { + Ensure.ArgumentNotNull(apiConnector, nameof(apiConnector)); + + _apiConnector = apiConnector; + UserProfile = new UserProfileClient(_apiConnector); + Browse = new BrowseClient(_apiConnector); + } + + public IUserProfileClient UserProfile { get; } + + public IBrowseClient Browse { get; } + } +} diff --git a/SpotifyAPI.Web/Clients/UserProfileClient.cs b/SpotifyAPI.Web/Clients/UserProfileClient.cs new file mode 100644 index 00000000..0e23051f --- /dev/null +++ b/SpotifyAPI.Web/Clients/UserProfileClient.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; +using SpotifyAPI.Web.Http; +using SpotifyAPI.Web.Models; + +namespace SpotifyAPI.Web +{ + public class UserProfileClient : APIClient, IUserProfileClient + { + public UserProfileClient(IAPIConnector apiConnector) : base(apiConnector) { } + + public Task Current() + { + return API.Get(SpotifyUrls.Me()); + } + + public Task Get(string userId) + { + Ensure.ArgumentNotNullOrEmptyString(userId, nameof(userId)); + + return API.Get(SpotifyUrls.User(userId)); + } + } +} diff --git a/SpotifyAPI.Web/Exceptions/APIException.cs b/SpotifyAPI.Web/Exceptions/APIException.cs new file mode 100644 index 00000000..440461e0 --- /dev/null +++ b/SpotifyAPI.Web/Exceptions/APIException.cs @@ -0,0 +1,43 @@ +using System.Net; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SpotifyAPI.Web.Http; + +namespace SpotifyAPI.Web +{ + [System.Serializable] + public class APIException : System.Exception + { + public APIException(IResponse response) : base(ParseAPIErrorMessage(response)) + { + Ensure.ArgumentNotNull(response, nameof(response)); + + Response = response; + } + + private static string ParseAPIErrorMessage(IResponse response) + { + var body = response.Body as string; + if (string.IsNullOrEmpty(body)) + { + return null; + } + try + { + JObject bodyObject = JObject.Parse(body); + JObject error = bodyObject.Value("error"); + if (error != null) + { + return error.Value("message"); + } + } + catch (JsonReaderException) + { + return null; + } + return null; + } + + public IResponse Response { get; set; } + } +} diff --git a/SpotifyAPI.Web/Exceptions/APIUnauthorizedException.cs b/SpotifyAPI.Web/Exceptions/APIUnauthorizedException.cs new file mode 100644 index 00000000..cf0cca60 --- /dev/null +++ b/SpotifyAPI.Web/Exceptions/APIUnauthorizedException.cs @@ -0,0 +1,10 @@ +using SpotifyAPI.Web.Http; + +namespace SpotifyAPI.Web +{ + [System.Serializable] + public class APIUnauthorizedException : APIException + { + public APIUnauthorizedException(IResponse response) : base(response) { } + } +} diff --git a/SpotifyAPI.Web/Http/APIConnector.cs b/SpotifyAPI.Web/Http/APIConnector.cs new file mode 100644 index 00000000..3812dff3 --- /dev/null +++ b/SpotifyAPI.Web/Http/APIConnector.cs @@ -0,0 +1,155 @@ +using System.Net.Http; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Net; + +namespace SpotifyAPI.Web.Http +{ + public class APIConnector : IAPIConnector + { + private Uri _baseAddress; + private IAuthenticator _authenticator; + private IJSONSerializer _jsonSerializer; + private IHTTPClient _httpClient; + + public APIConnector(Uri baseAddress, IAuthenticator authenticator) : + this(baseAddress, authenticator, new NewtonsoftJSONSerializer(), new NetHttpClient()) + { } + public APIConnector(Uri baseAddress, IAuthenticator authenticator, IJSONSerializer jsonSerializer, IHTTPClient httpClient) + { + _baseAddress = baseAddress; + _authenticator = authenticator; + _jsonSerializer = jsonSerializer; + _httpClient = httpClient; + } + + public Task Delete(Uri uri) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Delete); + } + + public Task Delete(Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Delete, parameters); + } + + public Task Delete(Uri uri, IDictionary parameters, object body) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Delete, parameters, body); + } + + public Task Get(Uri uri) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Get); + } + + public Task Get(Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Get, parameters); + } + + public Task Post(Uri uri) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Post); + } + + public Task Post(Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Post, parameters); + } + + public Task Post(Uri uri, IDictionary parameters, object body) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Get, parameters, body); + } + + public Task Put(Uri uri) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Put); + } + + public Task Put(Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Put, parameters); + } + + public Task Put(Uri uri, IDictionary parameters, object body) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + return SendAPIRequest(uri, HttpMethod.Put, parameters, body); + } + + public void SetRequestTimeout(TimeSpan timeout) + { + _httpClient.SetRequestTimeout(timeout); + } + + private async Task SendAPIRequest( + Uri uri, + HttpMethod method, + IDictionary parameters = null, + object body = null + ) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + Ensure.ArgumentNotNull(method, nameof(method)); + + var request = new Request + { + BaseAddress = _baseAddress, + ContentType = "application/json", + Parameters = parameters, + Endpoint = uri, + Method = method + }; + + _jsonSerializer.SerializeRequest(request); + await _authenticator.Apply(request).ConfigureAwait(false); + IResponse response = await _httpClient.DoRequest(request).ConfigureAwait(false); + ProcessErrors(response); + + IAPIResponse apiResponse = _jsonSerializer.DeserializeResponse(response); + return apiResponse.Body; + } + + private void ProcessErrors(IResponse response) + { + Ensure.ArgumentNotNull(response, nameof(response)); + + if ((int)response.StatusCode >= 200 && (int)response.StatusCode < 400) + { + return; + } + + switch (response.StatusCode) + { + case HttpStatusCode.Unauthorized: + throw new APIUnauthorizedException(response); + default: + throw new APIException(response); + } + } + } +} diff --git a/SpotifyAPI.Web/Http/APIResponse.cs b/SpotifyAPI.Web/Http/APIResponse.cs new file mode 100644 index 00000000..efda8bb9 --- /dev/null +++ b/SpotifyAPI.Web/Http/APIResponse.cs @@ -0,0 +1,17 @@ +namespace SpotifyAPI.Web.Http +{ + public class APIResponse : IAPIResponse + { + public APIResponse(IResponse response, T body = default(T)) + { + Ensure.ArgumentNotNull(response, nameof(response)); + + Body = body; + Response = response; + } + + public T Body { get; set; } + + public IResponse Response { get; set; } + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs b/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs new file mode 100644 index 00000000..c46fb4be --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace SpotifyAPI.Web.Http +{ + public interface IAPIConnector + { + // IAuthenticator Authenticator { get; } + + // IJSONSerializer JSONSerializer { get; } + + // IHTTPClient HTTPClient { get; } + + Task Get(Uri uri); + Task Get(Uri uri, IDictionary parameters); + + Task Post(Uri uri); + Task Post(Uri uri, IDictionary parameters); + Task Post(Uri uri, IDictionary parameters, object body); + + Task Put(Uri uri); + Task Put(Uri uri, IDictionary parameters); + Task Put(Uri uri, IDictionary parameters, object body); + + Task Delete(Uri uri); + Task Delete(Uri uri, IDictionary parameters); + Task Delete(Uri uri, IDictionary parameters, object body); + + void SetRequestTimeout(TimeSpan timeout); + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IAPIResponse.cs b/SpotifyAPI.Web/Http/Interfaces/IAPIResponse.cs new file mode 100644 index 00000000..2de5db76 --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IAPIResponse.cs @@ -0,0 +1,9 @@ +namespace SpotifyAPI.Web.Http +{ + public interface IAPIResponse + { + T Body { get; } + + IResponse Response { get; } + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IAuthenticator.cs b/SpotifyAPI.Web/Http/Interfaces/IAuthenticator.cs new file mode 100644 index 00000000..b6ac2d8c --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IAuthenticator.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace SpotifyAPI.Web.Http +{ + public interface IAuthenticator + { + Task Apply(IRequest request); + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs b/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs new file mode 100644 index 00000000..5d830c0d --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IHttpClient.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; + +namespace SpotifyAPI.Web.Http +{ + public interface IHTTPClient : IDisposable + { + Task DoRequest(IRequest request); + + void SetRequestTimeout(TimeSpan timeout); + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IJSONSerializer.cs b/SpotifyAPI.Web/Http/Interfaces/IJSONSerializer.cs new file mode 100644 index 00000000..6561b26c --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IJSONSerializer.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace SpotifyAPI.Web.Http +{ + public interface IJSONSerializer + { + void SerializeRequest(IRequest request); + IAPIResponse DeserializeResponse(IResponse response); + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IRequest.cs b/SpotifyAPI.Web/Http/Interfaces/IRequest.cs new file mode 100644 index 00000000..72860ece --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IRequest.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; + +namespace SpotifyAPI.Web.Http +{ + public interface IRequest + { + Uri BaseAddress { get; } + + Uri Endpoint { get; } + + IDictionary Headers { get; } + + IDictionary Parameters { get; } + + HttpMethod Method { get; } + + string ContentType { get; } + + object Body { get; set; } + } +} diff --git a/SpotifyAPI.Web/Http/Interfaces/IResponse.cs b/SpotifyAPI.Web/Http/Interfaces/IResponse.cs new file mode 100644 index 00000000..09b54fab --- /dev/null +++ b/SpotifyAPI.Web/Http/Interfaces/IResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Net; + +namespace SpotifyAPI.Web.Http +{ + public interface IResponse + { + object Body { get; } + + IReadOnlyDictionary Headers { get; } + + HttpStatusCode StatusCode { get; } + + string ContentType { get; } + } +} diff --git a/SpotifyAPI.Web/Http/NetHttpClient.cs b/SpotifyAPI.Web/Http/NetHttpClient.cs new file mode 100644 index 00000000..8c31f822 --- /dev/null +++ b/SpotifyAPI.Web/Http/NetHttpClient.cs @@ -0,0 +1,98 @@ +using System; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace SpotifyAPI.Web.Http +{ + public class NetHttpClient : IHTTPClient + { + private HttpClient _httpClient; + + public NetHttpClient() + { + _httpClient = new HttpClient(); + } + + public async Task DoRequest(IRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + using (HttpRequestMessage requestMsg = BuildRequestMessage(request)) + { + var responseMsg = await _httpClient + .SendAsync(requestMsg, HttpCompletionOption.ResponseContentRead) + .ConfigureAwait(false); + + return await BuildResponse(responseMsg).ConfigureAwait(false); + } + } + + private async Task BuildResponse(HttpResponseMessage responseMsg) + { + Ensure.ArgumentNotNull(responseMsg, nameof(responseMsg)); + + // We only support text stuff for now + using (var content = responseMsg.Content) + { + var headers = responseMsg.Headers.ToDictionary(header => header.Key, header => header.Value.First()); + var body = await responseMsg.Content.ReadAsStringAsync().ConfigureAwait(false); + var contentType = content.Headers?.ContentType?.MediaType; + + return new Response(headers) + { + ContentType = contentType, + StatusCode = responseMsg.StatusCode, + Body = body + }; + } + } + + private HttpRequestMessage BuildRequestMessage(IRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + var fullUri = new Uri(request.BaseAddress, request.Endpoint).ApplyParameters(request.Parameters); + var requestMsg = new HttpRequestMessage(request.Method, fullUri); + foreach (var header in request.Headers) + { + requestMsg.Headers.Add(header.Key, header.Value); + } + + switch (request.Body) + { + case HttpContent body: + requestMsg.Content = body; + break; + case string body: + requestMsg.Content = new StringContent(body); + break; + case Stream body: + requestMsg.Content = new StreamContent(body); + break; + } + + return requestMsg; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposing) + { + _httpClient?.Dispose(); + } + } + + public void SetRequestTimeout(TimeSpan timeout) + { + _httpClient.Timeout = timeout; + } + } +} diff --git a/SpotifyAPI.Web/Http/NewtonsoftJSONSerializer.cs b/SpotifyAPI.Web/Http/NewtonsoftJSONSerializer.cs new file mode 100644 index 00000000..d182acfb --- /dev/null +++ b/SpotifyAPI.Web/Http/NewtonsoftJSONSerializer.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace SpotifyAPI.Web.Http +{ + public class NewtonsoftJSONSerializer : IJSONSerializer + { + JsonSerializerSettings _serializerSettings; + + public NewtonsoftJSONSerializer() + { + _serializerSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new DefaultContractResolver + { + NamingStrategy = new SnakeCaseNamingStrategy() + } + }; + } + + public IAPIResponse DeserializeResponse(IResponse response) + { + Ensure.ArgumentNotNull(response, nameof(response)); + + if (response.ContentType?.Equals("application/json", StringComparison.Ordinal) is true) + { + var body = JsonConvert.DeserializeObject(response.Body as string, _serializerSettings); + return new APIResponse(response, body); + } + return new APIResponse(response); + } + + public void SerializeRequest(IRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + if (request.Body is string || request.Body is Stream || request.Body is HttpContent || request.Body is null) + { + return; + } + + request.Body = JsonConvert.SerializeObject(request.Body, _serializerSettings); + } + } +} diff --git a/SpotifyAPI.Web/Http/Request.cs b/SpotifyAPI.Web/Http/Request.cs new file mode 100644 index 00000000..7d88789c --- /dev/null +++ b/SpotifyAPI.Web/Http/Request.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; + +namespace SpotifyAPI.Web.Http +{ + class Request : IRequest + { + public Request() + { + Headers = new Dictionary(); + Parameters = new Dictionary(); + } + + public Uri BaseAddress { get; set; } + + public Uri Endpoint { get; set; } + + public IDictionary Headers { get; set; } + + public IDictionary Parameters { get; set; } + + public HttpMethod Method { get; set; } + + public string ContentType { get; set; } + + public object Body { get; set; } + } +} diff --git a/SpotifyAPI.Web/Http/Response.cs b/SpotifyAPI.Web/Http/Response.cs new file mode 100644 index 00000000..93d3ed74 --- /dev/null +++ b/SpotifyAPI.Web/Http/Response.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Net; + +namespace SpotifyAPI.Web.Http +{ + public class Response : IResponse + { + public Response(IDictionary headers) + { + Ensure.ArgumentNotNull(headers, nameof(headers)); + + Headers = new ReadOnlyDictionary(headers); + } + + public object Body { get; set; } + + public IReadOnlyDictionary Headers { get; set; } + + public HttpStatusCode StatusCode { get; set; } + + public string ContentType { get; set; } + } +} diff --git a/SpotifyAPI.Web/Http/TokenHeaderAuthenticator.cs b/SpotifyAPI.Web/Http/TokenHeaderAuthenticator.cs new file mode 100644 index 00000000..a4ec0cbe --- /dev/null +++ b/SpotifyAPI.Web/Http/TokenHeaderAuthenticator.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; + +namespace SpotifyAPI.Web.Http +{ + class TokenHeaderAuthenticator : IAuthenticator + { + public TokenHeaderAuthenticator(string token, string tokenType) + { + Token = token; + TokenType = tokenType; + } + + public string Token { get; set; } + + public string TokenType { get; set; } + + public Task Apply(IRequest request) + { + request.Headers["Authorization"] = $"{TokenType} {Token}"; + return Task.CompletedTask; + } + } +} diff --git a/SpotifyAPI.Web/IClient.cs b/SpotifyAPI.Web/IClient.cs deleted file mode 100644 index 7000be23..00000000 --- a/SpotifyAPI.Web/IClient.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Newtonsoft.Json; -using SpotifyAPI.Web.Models; - -namespace SpotifyAPI.Web -{ - public interface IClient : IDisposable - { - JsonSerializerSettings JsonSettings { get; set; } - - /// - /// 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 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 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); - - /// - /// 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 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 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); - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisMeta.cs b/SpotifyAPI.Web/Models/AnalysisMeta.cs deleted file mode 100644 index 71fcc461..00000000 --- a/SpotifyAPI.Web/Models/AnalysisMeta.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AnalysisMeta - { - [JsonProperty("analyzer_platform")] - public string AnalyzerVersion { get; set; } - - [JsonProperty("platform")] - public string Platform { get; set; } - - [JsonProperty("status_code")] - public int StatusCode { get; set; } - - [JsonProperty("detailed_status")] - public string DetailedStatus { get; set; } - - [JsonProperty("timestamp")] - public long Timestamp { get; set; } - - [JsonProperty("analysis_time")] - public double AnalysisTime { get; set; } - - [JsonProperty("input_process")] - public string InputProcess { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisSection.cs b/SpotifyAPI.Web/Models/AnalysisSection.cs deleted file mode 100644 index 1240c786..00000000 --- a/SpotifyAPI.Web/Models/AnalysisSection.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AnalysisSection - { - [JsonProperty("start")] - public double Start { get; set; } - - [JsonProperty("duration")] - public double Duration { get; set; } - - [JsonProperty("confidence")] - public double Confidence { get; set; } - - [JsonProperty("loudness")] - public double Loudness { get; set; } - - [JsonProperty("tempo")] - public double Tempo { get; set; } - - [JsonProperty("tempo_confidence")] - public double TempoConfidence { get; set; } - - [JsonProperty("key")] - public int Key { get; set; } - - [JsonProperty("key_confidence")] - public double KeyConfidence { get; set; } - - [JsonProperty("mode")] - public int Mode { get; set; } - - [JsonProperty("mode_confidence")] - public double ModeConfidence { get; set; } - - [JsonProperty("time_signature")] - public int TimeSignature { get; set; } - - [JsonProperty("time_signature_confidence")] - public double TimeSignatureConfidence { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisSegment.cs b/SpotifyAPI.Web/Models/AnalysisSegment.cs deleted file mode 100644 index 80de52c6..00000000 --- a/SpotifyAPI.Web/Models/AnalysisSegment.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AnalysisSegment - { - [JsonProperty("start")] - public double Start { get; set; } - - [JsonProperty("duration")] - public double Duration { get; set; } - - [JsonProperty("confidence")] - public double Confidence { get; set; } - - [JsonProperty("loudness_start")] - public double LoudnessStart { get; set; } - - [JsonProperty("loudness_max_time")] - public double LoudnessMaxTime { get; set; } - - [JsonProperty("loudness_max")] - public double LoudnessMax { get; set; } - - [JsonProperty("loudness_end")] - public double LoudnessEnd { get; set; } - - [JsonProperty("pitches")] - public List Pitches { 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 deleted file mode 100644 index cb7843f7..00000000 --- a/SpotifyAPI.Web/Models/AnalysisTimeSlice.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AnalysisTimeSlice - { - [JsonProperty("start")] - public double Start { get; set; } - - [JsonProperty("duration")] - public double Duration { get; set; } - - [JsonProperty("confidence")] - public double Confidence { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AnalysisTrack.cs b/SpotifyAPI.Web/Models/AnalysisTrack.cs deleted file mode 100644 index 5ffd78ee..00000000 --- a/SpotifyAPI.Web/Models/AnalysisTrack.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AnalysisTrack - { - [JsonProperty("num_samples")] - public int NumSamples { get; set; } - - [JsonProperty("duration")] - public double Duration { get; set; } - - [JsonProperty("sample_md5")] - public string SampleMD5 { get; set; } - - [JsonProperty("offset_seconds")] - public double OffsetSeconds { get; set; } - - [JsonProperty("window_seconds")] - public double WindowSeconds { get; set; } - - [JsonProperty("analysis_sample_rate")] - public int AnalysisSampleRate { get; set; } - - [JsonProperty("analysis_channels")] - public int AnalysisChannels { get; set; } - - [JsonProperty("end_of_fade_in")] - public double EndOfFadeIn { get; set; } - - [JsonProperty("start_of_fade_out")] - public double StartOfFadeOut { get; set; } - - [JsonProperty("loudness")] - public double Loudness { get; set; } - - [JsonProperty("tempo")] - public double Tempo { get; set; } - - [JsonProperty("tempo_confidence")] - public double TempoConfidence { get; set; } - - [JsonProperty("time_signature")] - public double TimeSignature { get; set; } - - [JsonProperty("time_signature_confidence")] - public double TimeSignatureConfidence { get; set; } - - [JsonProperty("key")] - public int Key { get; set; } - - [JsonProperty("key_confidence")] - public double KeyConfidence { get; set; } - - [JsonProperty("mode")] - public int Mode { get; set; } - - [JsonProperty("mode_confidence")] - public double ModeConfidence { get; set; } - - [JsonProperty("codestring")] - public string Codestring { get; set; } - - [JsonProperty("code_version")] - public double CodeVersion { get; set; } - - [JsonProperty("echoprintstring")] - public string Echoprintstring { get; set; } - - [JsonProperty("echoprint_version")] - public double EchoprintVersion { get; set; } - - [JsonProperty("synchstring")] - public string Synchstring { get; set; } - - [JsonProperty("synch_version")] - public double SynchVersion { get; set; } - - [JsonProperty("rhythmstring")] - public string Rhythmstring { get; set; } - - [JsonProperty("rhythm_version")] - public double RhythmVersion { get; set; } - - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/ArrayResponse.cs b/SpotifyAPI.Web/Models/ArrayResponse.cs deleted file mode 100644 index c87e8967..00000000 --- a/SpotifyAPI.Web/Models/ArrayResponse.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index 1dd4ab5d..00000000 --- a/SpotifyAPI.Web/Models/AudioAnalysis.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AudioAnalysis : BasicModel - { - [JsonProperty("bars")] - public List Bars { get; set; } - - [JsonProperty("beats")] - public List Beats { get; set; } - - [JsonProperty("meta")] - public AnalysisMeta Meta { get; set; } - - [JsonProperty("sections")] - public List Sections { get; set; } - - [JsonProperty("segments")] - public List Segments { get; set; } - - [JsonProperty("tatums")] - public List Tatums { 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 deleted file mode 100644 index fbc40fd6..00000000 --- a/SpotifyAPI.Web/Models/AudioFeatures.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class AudioFeatures : BasicModel - { - [JsonProperty("acousticness")] - public float Acousticness { get; set; } - - [JsonProperty("analysis_url")] - public string AnalysisUrl { get; set; } - - [JsonProperty("danceability")] - public float Danceability { get; set; } - - [JsonProperty("duration_ms")] - public int DurationMs { get; set; } - - [JsonProperty("energy")] - public float Energy { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("instrumentalness")] - public float Instrumentalness { get; set; } - - [JsonProperty("key")] - public int Key { get; set; } - - [JsonProperty("liveness")] - public float Liveness { get; set; } - - [JsonProperty("loudness")] - public float Loudness { get; set; } - - [JsonProperty("mode")] - public int Mode { get; set; } - - [JsonProperty("speechiness")] - public float Speechiness { get; set; } - - [JsonProperty("tempo")] - public float Tempo { get; set; } - - [JsonProperty("time_signature")] - public int TimeSignature { get; set; } - - [JsonProperty("track_href")] - public string TrackHref { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("uri")] - public string Uri { get; set; } - - [JsonProperty("valence")] - public float Valence { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/AvailabeDevices.cs b/SpotifyAPI.Web/Models/AvailabeDevices.cs deleted file mode 100644 index 718cc98d..00000000 --- a/SpotifyAPI.Web/Models/AvailabeDevices.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index 27153eef..00000000 --- a/SpotifyAPI.Web/Models/BasicModel.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Net; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public abstract class BasicModel - { - [JsonProperty("error")] - public Error Error { get; set; } - - private ResponseInfo _info; - - public bool HasError() => Error != null; - - internal void AddResponseInfo(ResponseInfo info) => _info = info; - - public string Header(string key) => _info.Headers?.Get(key); - - public WebHeaderCollection Headers() => _info.Headers; - - public HttpStatusCode StatusCode() => _info.StatusCode; - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Category.cs b/SpotifyAPI.Web/Models/Category.cs deleted file mode 100644 index fcba4088..00000000 --- a/SpotifyAPI.Web/Models/Category.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class Category : BasicModel - { - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("icons")] - public List Icons { get; set; } - - [JsonProperty("id")] - public string Id { 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 deleted file mode 100644 index 0970cd22..00000000 --- a/SpotifyAPI.Web/Models/CategoryList.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index 9597df36..00000000 --- a/SpotifyAPI.Web/Models/CategoryPlaylist.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class CategoryPlaylist : BasicModel - { - [JsonProperty("playlists")] - public Paging Playlists { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Converters/PlaylistElementConverter.cs b/SpotifyAPI.Web/Models/Converters/PlaylistElementConverter.cs new file mode 100644 index 00000000..9fad42f8 --- /dev/null +++ b/SpotifyAPI.Web/Models/Converters/PlaylistElementConverter.cs @@ -0,0 +1,45 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace SpotifyAPI.Web +{ + public class PlaylistElementConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => true; + + public override object ReadJson(JsonReader reader, Type objectType, + object existingValue, JsonSerializer serializer) + { + var token = JToken.ReadFrom(reader); + if (token.Type == JTokenType.Null) + { + return null; + } + + var type = token["type"].Value(); + if (type == "track") + { + var obj = new FullTrack(); + serializer.Populate(token.CreateReader(), obj); + return obj; + } + else if (type == "episode") + { + var obj = new FullEpisode(); + serializer.Populate(token.CreateReader(), obj); + return obj; + } + else + { + throw new Exception($"Received unkown playlist element type: {type}"); + } + } + + public override void WriteJson(JsonWriter writer, object value, + JsonSerializer serializer) + { + throw new NotSupportedException(); + } + } +} diff --git a/SpotifyAPI.Web/Models/CursorPaging.cs b/SpotifyAPI.Web/Models/CursorPaging.cs deleted file mode 100644 index ca717642..00000000 --- a/SpotifyAPI.Web/Models/CursorPaging.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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() - { - return !string.IsNullOrEmpty(Next); - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Device.cs b/SpotifyAPI.Web/Models/Device.cs deleted file mode 100644 index 12b3eca0..00000000 --- a/SpotifyAPI.Web/Models/Device.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class Device - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("is_active")] - public bool IsActive { get; set; } - - [JsonProperty("is_restricted")] - public bool IsRestricted { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("volume_percent")] - public int VolumePercent { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FeaturedPlaylists.cs b/SpotifyAPI.Web/Models/FeaturedPlaylists.cs deleted file mode 100644 index f5a48deb..00000000 --- a/SpotifyAPI.Web/Models/FeaturedPlaylists.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class FeaturedPlaylists : BasicModel - { - [JsonProperty("message")] - public string Message { get; set; } - - [JsonProperty("playlists")] - public Paging Playlists { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FollowedArtists.cs b/SpotifyAPI.Web/Models/FollowedArtists.cs deleted file mode 100644 index 39072106..00000000 --- a/SpotifyAPI.Web/Models/FollowedArtists.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index cd9c89ad..00000000 --- a/SpotifyAPI.Web/Models/FullAlbum.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class FullAlbum : BasicModel - { - [JsonProperty("album_type")] - public string AlbumType { get; set; } - - [JsonProperty("artists")] - public List Artists { get; set; } - - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } - - [JsonProperty("copyrights")] - public List Copyrights { get; set; } - - [JsonProperty("external_ids")] - public Dictionary ExternalIds { get; set; } - - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } - - [JsonProperty("genres")] - public List Genres { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("images")] - public List Images { get; set; } - - [JsonProperty("label")] - public string Label { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("popularity")] - public int Popularity { get; set; } - - [JsonProperty("release_date")] - public string ReleaseDate { get; set; } - - [JsonProperty("release_date_precision")] - public string ReleaseDatePrecision { get; set; } - - [JsonProperty("tracks")] - public Paging Tracks { get; set; } - - [JsonProperty("restrictions")] - public Dictionary Restrictions { get; set; } - - [JsonProperty("total_tracks")] - public int TotalTracks { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("uri")] - public string Uri { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FullArtist.cs b/SpotifyAPI.Web/Models/FullArtist.cs deleted file mode 100644 index 78e2cf2e..00000000 --- a/SpotifyAPI.Web/Models/FullArtist.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class FullArtist : BasicModel - { - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } - - [JsonProperty("followers")] - public Followers Followers { get; set; } - - [JsonProperty("genres")] - public List Genres { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("images")] - public List Images { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("popularity")] - public int Popularity { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("uri")] - public string Uri { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/FullPlaylist.cs b/SpotifyAPI.Web/Models/FullPlaylist.cs deleted file mode 100644 index 0a8f6b3e..00000000 --- a/SpotifyAPI.Web/Models/FullPlaylist.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class FullPlaylist : BasicModel - { - [JsonProperty("collaborative")] - public bool Collaborative { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } - - [JsonProperty("followers")] - public Followers Followers { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("images")] - public List Images { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("owner")] - public PublicProfile Owner { get; set; } - - [JsonProperty("public")] - public bool Public { get; set; } - - [JsonProperty("snapshot_id")] - public string SnapshotId { get; set; } - - [JsonProperty("tracks")] - public Paging Tracks { 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/FullTrack.cs b/SpotifyAPI.Web/Models/FullTrack.cs deleted file mode 100644 index d75c8d00..00000000 --- a/SpotifyAPI.Web/Models/FullTrack.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class FullTrack : BasicModel - { - [JsonProperty("album")] - public SimpleAlbum Album { get; set; } - - [JsonProperty("artists")] - public List Artists { get; set; } - - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } - - [JsonProperty("disc_number")] - public int DiscNumber { get; set; } - - [JsonProperty("duration_ms")] - public int DurationMs { get; set; } - - [JsonProperty("explicit")] - public bool Explicit { get; set; } - - [JsonProperty("external_ids")] - public Dictionary ExternalIds { get; set; } - - [JsonProperty("external_urls")] - public Dictionary ExternUrls { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("popularity")] - public int Popularity { get; set; } - - [JsonProperty("preview_url")] - public string PreviewUrl { get; set; } - - [JsonProperty("track_number")] - public int TrackNumber { get; set; } - - [JsonProperty("restrictions")] - public Dictionary Restrictions { get; set; } - - [JsonProperty("type")] - public string Type { 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("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 deleted file mode 100644 index b263aacb..00000000 --- a/SpotifyAPI.Web/Models/GeneralModels.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class Image - { - [JsonProperty("url")] - public string Url { get; set; } - - [JsonProperty("width")] - public int Width { get; set; } - - [JsonProperty("height")] - public int Height { get; set; } - } - - public class ErrorResponse : BasicModel - { } - - public class Error - { - [JsonProperty("status")] - public int Status { get; set; } - - [JsonProperty("message")] - public string Message { get; set; } - } - - public class PlaylistTrackCollection - { - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("total")] - public int Total { get; set; } - } - - public class Followers - { - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("total")] - public int Total { get; set; } - } - - public class PlaylistTrack - { - [JsonProperty("added_at")] - public DateTime AddedAt { get; set; } - - [JsonProperty("added_by")] - public PublicProfile AddedBy { get; set; } - - [JsonProperty("track")] - public FullTrack Track { get; set; } - - [JsonProperty("is_local")] - public bool IsLocal { get; set; } - } - - public class DeleteTrackUri - { - /// - /// Delete-Track Wrapper - /// - /// An Spotify-URI - /// Optional positions - public DeleteTrackUri(string uri, params int[] positions) - { - Positions = positions.ToList(); - Uri = uri; - } - - [JsonProperty("uri")] - public string Uri { get; set; } - - [JsonProperty("positions")] - public List Positions { get; set; } - - public bool ShouldSerializePositions() - { - return Positions.Count > 0; - } - } - - public class Copyright - { - [JsonProperty("text")] - public string Text { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - } - - public class LinkedFrom - { - [JsonProperty("external_urls")] - public Dictionary 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; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/NewAlbumReleases.cs b/SpotifyAPI.Web/Models/NewAlbumReleases.cs deleted file mode 100644 index 935c0dd1..00000000 --- a/SpotifyAPI.Web/Models/NewAlbumReleases.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index fe5838d0..00000000 --- a/SpotifyAPI.Web/Models/Paging.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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() - { - 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 deleted file mode 100644 index a02d6d20..00000000 --- a/SpotifyAPI.Web/Models/PlayHistory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class PlayHistory : BasicModel - { - [JsonProperty("track")] - public SimpleTrack Track { get; set; } - - [JsonProperty("played_at")] - public DateTime PlayedAt { get; set; } - - [JsonProperty("context")] - public Context Context { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/PlaybackContext.cs b/SpotifyAPI.Web/Models/PlaybackContext.cs deleted file mode 100644 index 6636ba29..00000000 --- a/SpotifyAPI.Web/Models/PlaybackContext.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using SpotifyAPI.Web.Enums; - -namespace SpotifyAPI.Web.Models -{ - public class PlaybackContext : BasicModel - { - [JsonProperty("device")] - public Device Device { get; set; } - - [JsonProperty("repeat_state")] - [JsonConverter(typeof(StringEnumConverter))] - public RepeatState RepeatState { get; set; } - - [JsonProperty("shuffle_state")] - public bool ShuffleState { get; set; } - - [JsonProperty("context")] - public Context Context { get; set; } - - [JsonProperty("timestamp")] - public long Timestamp { get; set; } - - [JsonProperty("progress_ms")] - public int ProgressMs { get; set; } - - [JsonProperty("is_playing")] - public bool IsPlaying { get; set; } - - [JsonProperty("item")] - public FullTrack Item { get; set; } - - [JsonProperty("currently_playing_type")] - [JsonConverter(typeof(StringEnumConverter))] - public TrackType CurrentlyPlayingType { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/PrivateProfile.cs b/SpotifyAPI.Web/Models/PrivateProfile.cs deleted file mode 100644 index 26cf5db8..00000000 --- a/SpotifyAPI.Web/Models/PrivateProfile.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class PrivateProfile : BasicModel - { - [JsonProperty("birthdate")] - public string Birthdate { get; set; } - - [JsonProperty("country")] - public string Country { get; set; } - - [JsonProperty("display_name")] - public string DisplayName { get; set; } - - [JsonProperty("email")] - public string Email { get; set; } - - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } - - [JsonProperty("followers")] - public Followers Followers { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("images")] - public List Images { get; set; } - - [JsonProperty("product")] - public string Product { 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/RecommendationSeed .cs b/SpotifyAPI.Web/Models/RecommendationSeed .cs deleted file mode 100644 index 28e2fcdd..00000000 --- a/SpotifyAPI.Web/Models/RecommendationSeed .cs +++ /dev/null @@ -1,25 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class RecommendationSeed - { - [JsonProperty("afterFilteringSize")] - public int AfterFilteringSize { get; set; } - - [JsonProperty("afterRelinkingSize")] - public int AfterRelinkingSize { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("initialPoolSize")] - public int InitialPoolSize { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs b/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs deleted file mode 100644 index e92ad5a7..00000000 --- a/SpotifyAPI.Web/Models/RecommendationSeedGenres.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index 7b00f611..00000000 --- a/SpotifyAPI.Web/Models/Recommendations.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class Recommendations : BasicModel - { - [JsonProperty("seeds")] - public List Seeds { get; set; } - - [JsonProperty("tracks")] - public List Tracks { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/Request/CategoriesRequest.cs b/SpotifyAPI.Web/Models/Request/CategoriesRequest.cs new file mode 100644 index 00000000..0e0072c6 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/CategoriesRequest.cs @@ -0,0 +1,17 @@ +namespace SpotifyAPI.Web +{ + public class CategoriesRequest : RequestParams + { + [QueryParam("country")] + public string Country { get; set; } + + [QueryParam("locale")] + public string Locale { get; set; } + + [QueryParam("limit")] + public int? Limit { get; set; } + + [QueryParam("offset")] + public int? Offset { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Request/CategoryPlaylistsRequest.cs b/SpotifyAPI.Web/Models/Request/CategoryPlaylistsRequest.cs new file mode 100644 index 00000000..e7ff31f9 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/CategoryPlaylistsRequest.cs @@ -0,0 +1,14 @@ +namespace SpotifyAPI.Web +{ + public class CategoriesPlaylistsRequest : RequestParams + { + [QueryParam("country")] + public string Country { get; set; } + + [QueryParam("limit")] + public int? Limit { get; set; } + + [QueryParam("offset")] + public int? Offset { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Request/CategoryRequest.cs b/SpotifyAPI.Web/Models/Request/CategoryRequest.cs new file mode 100644 index 00000000..6fd31513 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/CategoryRequest.cs @@ -0,0 +1,11 @@ +namespace SpotifyAPI.Web +{ + public class CategoryRequest : RequestParams + { + [QueryParam("country")] + public string Country { get; set; } + + [QueryParam("locale")] + public string Locale { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Request/RequestParams.cs b/SpotifyAPI.Web/Models/Request/RequestParams.cs new file mode 100644 index 00000000..e47798e5 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/RequestParams.cs @@ -0,0 +1,44 @@ +using System.Reflection; +using System; +using System.Linq; +using System.Collections.Generic; +namespace SpotifyAPI.Web +{ + public abstract class RequestParams + { + public Dictionary BuildQueryParams() + { + var queryProps = this.GetType().GetProperties() + .Where(prop => prop.GetCustomAttributes(typeof(QueryParamAttribute), true).Length > 0); + + var queryParams = new Dictionary(); + foreach (var prop in queryProps) + { + var attribute = prop.GetCustomAttribute(typeof(QueryParamAttribute)) as QueryParamAttribute; + var value = prop.GetValue(this); + if (value != null) + { + queryParams.Add(attribute.Key ?? prop.Name, value.ToString()); + } + } + + return queryParams; + } + } + + public class QueryParamAttribute : Attribute + { + public string Key { get; set; } + + public QueryParamAttribute() { } + public QueryParamAttribute(string key) + { + Key = key; + } + } + + public class BodyParamAttribute : Attribute + { + public BodyParamAttribute() { } + } +} diff --git a/SpotifyAPI.Web/Models/Response/CategoriesResponse.cs b/SpotifyAPI.Web/Models/Response/CategoriesResponse.cs new file mode 100644 index 00000000..a609a431 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/CategoriesResponse.cs @@ -0,0 +1,7 @@ +namespace SpotifyAPI.Web +{ + public class CategoriesResponse + { + public Paging Categories { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Category.cs b/SpotifyAPI.Web/Models/Response/Category.cs new file mode 100644 index 00000000..826a150d --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Category.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class Category + { + public string Href { get; set; } + public List Icons { get; set; } + public string Id { get; set; } + public string Name { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/CategoryPlaylistsResponse.cs b/SpotifyAPI.Web/Models/Response/CategoryPlaylistsResponse.cs new file mode 100644 index 00000000..f798afa2 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/CategoryPlaylistsResponse.cs @@ -0,0 +1,7 @@ +namespace SpotifyAPI.Web +{ + public class CategoryPlaylistsResponse + { + public Paging Playlists { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Copyright.cs b/SpotifyAPI.Web/Models/Response/Copyright.cs new file mode 100644 index 00000000..d7ee53ef --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Copyright.cs @@ -0,0 +1,8 @@ +namespace SpotifyAPI.Web +{ + public class Copyright + { + public string Text { get; set; } + public string Type { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Followers.cs b/SpotifyAPI.Web/Models/Response/Followers.cs new file mode 100644 index 00000000..282dd0bb --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Followers.cs @@ -0,0 +1,9 @@ +namespace SpotifyAPI.Web +{ + public class Followers + { + public string Href { get; set; } + + public int Total { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/FullEpisode.cs b/SpotifyAPI.Web/Models/Response/FullEpisode.cs new file mode 100644 index 00000000..68abd37f --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/FullEpisode.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +namespace SpotifyAPI.Web +{ + public class FullEpisode : IPlaylistElement + { + public string AudioPreviewUrl { get; set; } + public string Description { get; set; } + public int DurationMs { get; set; } + public bool Explicit { get; set; } + public Dictionary ExternalUrls { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public List Images { get; set; } + public bool IsExternallyHosted { get; set; } + public bool IsPlayable { get; set; } + public List Languages { get; set; } + public string Name { get; set; } + public string ReleaseDate { get; set; } + public string ReleaseDatePrecision { get; set; } + public ResumePoint ResumePoint { get; set; } + public SimpleShow Show { get; set; } + public PlaylistElementType Type { get; set; } + public string Uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/FullTrack.cs b/SpotifyAPI.Web/Models/Response/FullTrack.cs new file mode 100644 index 00000000..4fe09996 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/FullTrack.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class FullTrack : IPlaylistElement + { + public SimpleAlbum Album { get; set; } + public List Artists { get; set; } + public List AvailableMarkets { get; set; } + public int DiscNumber { get; set; } + public int DurationMs { get; set; } + public bool Explicit { get; set; } + public Dictionary ExternalIds { get; set; } + public Dictionary ExternalUrls { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public bool IsPlayable { get; set; } + public LinkedTrack LinkedFrom { get; set; } + public Dictionary Restrictions { get; set; } + public string Name { get; set; } + public int Popularity { get; set; } + public string PreviewUrl { get; set; } + public int TrackNumber { get; set; } + public PlaylistElementType Type { get; set; } + public string Uri { get; set; } + public bool IsLocal { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Image.cs b/SpotifyAPI.Web/Models/Response/Image.cs new file mode 100644 index 00000000..f904d16f --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Image.cs @@ -0,0 +1,9 @@ +namespace SpotifyAPI.Web +{ + public class Image + { + public int Height { get; set; } + public int Width { get; set; } + public string Url { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Interfaces/IPlaylistElement.cs b/SpotifyAPI.Web/Models/Response/Interfaces/IPlaylistElement.cs new file mode 100644 index 00000000..7d5a627b --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Interfaces/IPlaylistElement.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace SpotifyAPI.Web +{ + public enum PlaylistElementType + { + Track, + Episode + } + public interface IPlaylistElement + { + [JsonConverter(typeof(StringEnumConverter))] + public PlaylistElementType Type { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/LinkedTrack.cs b/SpotifyAPI.Web/Models/Response/LinkedTrack.cs new file mode 100644 index 00000000..1915b943 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/LinkedTrack.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +namespace SpotifyAPI.Web +{ + public class LinkedTrack + { + public Dictionary ExternalUrls { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public string Type { get; set; } + public string uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Paging.cs b/SpotifyAPI.Web/Models/Response/Paging.cs new file mode 100644 index 00000000..a072cae4 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Paging.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class Paging + { + public string Href { get; set; } + public List Items { get; set; } + public int Limit { get; set; } + public string Next { get; set; } + public int Offset { get; set; } + public string Previous { get; set; } + public int Total { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/PlaylistTrack.cs b/SpotifyAPI.Web/Models/Response/PlaylistTrack.cs new file mode 100644 index 00000000..48314615 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/PlaylistTrack.cs @@ -0,0 +1,11 @@ +using System; +namespace SpotifyAPI.Web +{ + public class PlaylistTrack + { + public DateTime? AddedAt { get; set; } + public PublicUser AddedBy { get; set; } + public bool IsLocal { get; set; } + public IPlaylistElement Track { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/PublicProfile.cs b/SpotifyAPI.Web/Models/Response/PrivateUser.cs similarity index 60% rename from SpotifyAPI.Web/Models/PublicProfile.cs rename to SpotifyAPI.Web/Models/Response/PrivateUser.cs index db18a5f9..597ba34c 100644 --- a/SpotifyAPI.Web/Models/PublicProfile.cs +++ b/SpotifyAPI.Web/Models/Response/PrivateUser.cs @@ -3,30 +3,18 @@ using Newtonsoft.Json; namespace SpotifyAPI.Web.Models { - public class PublicProfile : BasicModel + public class PrivateUser { - [JsonProperty("display_name")] + public string Country { get; set; } public string DisplayName { get; set; } - - [JsonProperty("external_urls")] + public string Email { get; set; } public Dictionary ExternalUrls { get; set; } - - [JsonProperty("followers")] public Followers Followers { get; set; } - - [JsonProperty("href")] public string Href { get; set; } - - [JsonProperty("id")] public string Id { get; set; } - - [JsonProperty("images")] public List Images { get; set; } - - [JsonProperty("type")] + public string Product { get; set; } public string Type { get; set; } - - [JsonProperty("uri")] public string Uri { get; set; } } -} \ No newline at end of file +} diff --git a/SpotifyAPI.Web/Models/Response/PublicUser.cs b/SpotifyAPI.Web/Models/Response/PublicUser.cs new file mode 100644 index 00000000..a739c4bc --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/PublicUser.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace SpotifyAPI.Web +{ + public class PublicUser + { + public string DisplayName { get; set; } + public Dictionary ExternalUrls { get; set; } + public Followers Followers { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public List Images { get; set; } + public string Type { get; set; } + public string Uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/ResumePointObject.cs b/SpotifyAPI.Web/Models/Response/ResumePointObject.cs new file mode 100644 index 00000000..52afa146 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/ResumePointObject.cs @@ -0,0 +1,8 @@ +namespace SpotifyAPI.Web +{ + public class ResumePoint + { + public bool FullyPlayed { get; set; } + public int ResumePositionMs { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/SimpleAlbum.cs b/SpotifyAPI.Web/Models/Response/SimpleAlbum.cs similarity index 52% rename from SpotifyAPI.Web/Models/SimpleAlbum.cs rename to SpotifyAPI.Web/Models/Response/SimpleAlbum.cs index 860b2840..78eb47ee 100644 --- a/SpotifyAPI.Web/Models/SimpleAlbum.cs +++ b/SpotifyAPI.Web/Models/Response/SimpleAlbum.cs @@ -1,53 +1,22 @@ using System.Collections.Generic; -using Newtonsoft.Json; -namespace SpotifyAPI.Web.Models +namespace SpotifyAPI.Web { - public class SimpleAlbum : BasicModel + public class SimpleAlbum { - [JsonProperty("album_group")] public string AlbumGroup { get; set; } - - [JsonProperty("album_type")] public string AlbumType { get; set; } - - [JsonProperty("artists")] public List Artists { get; set; } - - [JsonProperty("available_markets")] public List AvailableMarkets { get; set; } - - [JsonProperty("external_urls")] public Dictionary ExternalUrls { get; set; } - - [JsonProperty("href")] public string Href { get; set; } - - [JsonProperty("id")] public string Id { get; set; } - - [JsonProperty("images")] public List Images { get; set; } - - [JsonProperty("name")] public string Name { get; set; } - - [JsonProperty("release_date")] public string ReleaseDate { get; set; } - - [JsonProperty("release_date_precision")] public string ReleaseDatePrecision { get; set; } - - [JsonProperty("restrictions")] public Dictionary Restrictions { get; set; } - - [JsonProperty("total_tracks")] - public int TotalTracks { get; set; } - - [JsonProperty("type")] public string Type { get; set; } - - [JsonProperty("uri")] public string Uri { get; set; } } -} \ No newline at end of file +} diff --git a/SpotifyAPI.Web/Models/SimpleArtist.cs b/SpotifyAPI.Web/Models/Response/SimpleArtist.cs similarity index 52% rename from SpotifyAPI.Web/Models/SimpleArtist.cs rename to SpotifyAPI.Web/Models/Response/SimpleArtist.cs index a599436e..b272e812 100644 --- a/SpotifyAPI.Web/Models/SimpleArtist.cs +++ b/SpotifyAPI.Web/Models/Response/SimpleArtist.cs @@ -1,26 +1,13 @@ using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models +namespace SpotifyAPI.Web { - public class SimpleArtist : BasicModel + public class SimpleArtist { - [JsonProperty("external_urls")] public Dictionary ExternalUrls { get; set; } - - [JsonProperty("href")] public string Href { get; set; } - - [JsonProperty("id")] public string Id { get; set; } - - [JsonProperty("name")] public string Name { get; set; } - - [JsonProperty("type")] public string Type { get; set; } - - [JsonProperty("uri")] public string Uri { get; set; } } } diff --git a/SpotifyAPI.Web/Models/Response/SimplePlaylist.cs b/SpotifyAPI.Web/Models/Response/SimplePlaylist.cs new file mode 100644 index 00000000..06abf5d6 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/SimplePlaylist.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +namespace SpotifyAPI.Web +{ + /// + /// Docs + /// + public class SimplePlaylist + { + public bool Collaborative { get; set; } + public string Description { get; set; } + public Dictionary ExternalUrls { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public List Images { get; set; } + public string Name { get; set; } + public PublicUser Owner { get; set; } + public bool? Public { get; set; } + public string SnapshotId { get; set; } + public Paging Tracks { get; set; } + public string Type { get; set; } + public string Uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/SimpleShow.cs b/SpotifyAPI.Web/Models/Response/SimpleShow.cs new file mode 100644 index 00000000..6635bc29 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/SimpleShow.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +namespace SpotifyAPI.Web +{ + public class SimpleShow + { + public List AvailableMarkets { get; set; } + public Copyright Copyright { get; set; } + public string Description { get; set; } + public bool Explicit { get; set; } + public Dictionary ExternalUrls { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public List Images { get; set; } + public bool IsExternallyHosted { get; set; } + public List Languages { get; set; } + public string MediaType { get; set; } + public string Name { get; set; } + public string Publisher { get; set; } + public string Type { get; set; } + public string Uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/ResponseInfo.cs b/SpotifyAPI.Web/Models/ResponseInfo.cs deleted file mode 100644 index de1665cb..00000000 --- a/SpotifyAPI.Web/Models/ResponseInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Net; - -namespace SpotifyAPI.Web.Models -{ - public class ResponseInfo - { - public WebHeaderCollection Headers { get; set; } - - public HttpStatusCode StatusCode { get; set; } - - public static readonly ResponseInfo Empty = new ResponseInfo(); - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SearchItem.cs b/SpotifyAPI.Web/Models/SearchItem.cs deleted file mode 100644 index 447187b7..00000000 --- a/SpotifyAPI.Web/Models/SearchItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class SearchItem : BasicModel - { - [JsonProperty("artists")] - public Paging Artists { get; set; } - - [JsonProperty("albums")] - public Paging Albums { get; set; } - - [JsonProperty("tracks")] - public Paging Tracks { 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 deleted file mode 100644 index a69f82d0..00000000 --- a/SpotifyAPI.Web/Models/SeveralAlbums.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index eae18f9c..00000000 --- a/SpotifyAPI.Web/Models/SeveralArtists.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index 3f6bb9ca..00000000 --- a/SpotifyAPI.Web/Models/SeveralAudioFeatures.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class SeveralAudioFeatures : BasicModel - { - [JsonProperty("audio_features")] - public List AudioFeatures { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SeveralTracks.cs b/SpotifyAPI.Web/Models/SeveralTracks.cs deleted file mode 100644 index f156508c..00000000 --- a/SpotifyAPI.Web/Models/SeveralTracks.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class SeveralTracks : BasicModel - { - [JsonProperty("tracks")] - public List Tracks { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SimplePlaylist.cs b/SpotifyAPI.Web/Models/SimplePlaylist.cs deleted file mode 100644 index 73f61bea..00000000 --- a/SpotifyAPI.Web/Models/SimplePlaylist.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class SimplePlaylist : BasicModel - { - [JsonProperty("collaborative")] - public bool Collaborative { get; set; } - - [JsonProperty("external_urls")] - public Dictionary ExternalUrls { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("images")] - public List Images { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("owner")] - public PublicProfile Owner { get; set; } - - [JsonProperty("public")] - public bool Public { get; set; } - - [JsonProperty("snapshot_id")] - public string SnapshotId { get; set; } - - [JsonProperty("tracks")] - public PlaylistTrackCollection Tracks { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("uri")] - public string Uri { get; set; } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Models/SimpleTrack.cs b/SpotifyAPI.Web/Models/SimpleTrack.cs deleted file mode 100644 index aa4a8fe9..00000000 --- a/SpotifyAPI.Web/Models/SimpleTrack.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class SimpleTrack : BasicModel - { - [JsonProperty("artists")] - public List Artists { get; set; } - - [JsonProperty("available_markets")] - public List AvailableMarkets { get; set; } - - [JsonProperty("disc_number")] - public int DiscNumber { get; set; } - - [JsonProperty("duration_ms")] - public int DurationMs { get; set; } - - [JsonProperty("explicit")] - public bool Explicit { get; set; } - - [JsonProperty("external_urls")] - public Dictionary ExternUrls { get; set; } - - [JsonProperty("href")] - public string Href { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("preview_url")] - public string PreviewUrl { get; set; } - - [JsonProperty("track_number")] - public int TrackNumber { get; set; } - - [JsonProperty("restrictions")] - public Dictionary Restrictions { 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/Snapshot.cs b/SpotifyAPI.Web/Models/Snapshot.cs deleted file mode 100644 index 47c53096..00000000 --- a/SpotifyAPI.Web/Models/Snapshot.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - 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 deleted file mode 100644 index b5dc31d4..00000000 --- a/SpotifyAPI.Web/Models/Token.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace SpotifyAPI.Web.Models -{ - public class Token - { - public Token() - { - CreateDate = DateTime.Now; - } - - [JsonProperty("access_token")] - public string AccessToken { get; set; } - - [JsonProperty("token_type")] - public string TokenType { get; set; } - - [JsonProperty("expires_in")] - public double ExpiresIn { get; set; } - - [JsonProperty("refresh_token")] - public string RefreshToken { get; set; } - - [JsonProperty("error")] - public string Error { get; set; } - - [JsonProperty("error_description")] - public string ErrorDescription { get; set; } - - public DateTime CreateDate { get; set; } - - /// - /// 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 deleted file mode 100644 index 994caff9..00000000 --- a/SpotifyAPI.Web/Models/TuneableTrack.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Reflection; - -namespace SpotifyAPI.Web.Models -{ - public class TuneableTrack - { - [String("acousticness")] - public float? Acousticness { get; set; } - - [String("danceability")] - public float? Danceability { get; set; } - - [String("duration_ms")] - public int? DurationMs { get; set; } - - [String("energy")] - public float? Energy { get; set; } - - [String("instrumentalness")] - public float? Instrumentalness { get; set; } - - [String("key")] - public int? Key { get; set; } - - [String("liveness")] - public float? Liveness { get; set; } - - [String("loudness")] - public float? Loudness { get; set; } - - [String("mode")] - public int? Mode { get; set; } - - [String("popularity")] - public int? Popularity { get; set; } - - [String("speechiness")] - public float? Speechiness { get; set; } - - [String("tempo")] - public float? Tempo { get; set; } - - [String("time_signature")] - public int? TimeSignature { get; set; } - - [String("valence")] - public float? Valence { get; set; } - - public string BuildUrlParams(string prefix) - { - List 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/SpotifyAPI.Web.csproj b/SpotifyAPI.Web/SpotifyAPI.Web.csproj index c9a9d5cf..9fea25d3 100644 --- a/SpotifyAPI.Web/SpotifyAPI.Web.csproj +++ b/SpotifyAPI.Web/SpotifyAPI.Web.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.1 SpotifyAPI.Web SpotifyAPI.Web Jonas Dellinger diff --git a/SpotifyAPI.Web/SpotifyUrls.cs b/SpotifyAPI.Web/SpotifyUrls.cs new file mode 100644 index 00000000..2e5e2244 --- /dev/null +++ b/SpotifyAPI.Web/SpotifyUrls.cs @@ -0,0 +1,23 @@ +using System; +namespace SpotifyAPI.Web +{ + public static class SpotifyUrls + { + static URIParameterFormatProvider _provider = new URIParameterFormatProvider(); + + public static Uri API_V1 = new Uri("https://api.spotify.com/v1/"); + + public static Uri Me() => _Uri("me"); + + public static Uri User(string userId) => _Uri($"users/{userId}"); + + public static Uri Categories() => _Uri("browse/categories"); + + public static Uri Category(string categoryId) => _Uri($"browse/categories/{categoryId}"); + + public static Uri CategoryPlaylists(string categoryId) => _Uri($"browse/categories/{categoryId}/playlists"); + + private static Uri _Uri(FormattableString path) => new Uri(path.ToString(_provider), UriKind.Relative); + private static Uri _Uri(string path) => new Uri(path, UriKind.Relative); + } +} diff --git a/SpotifyAPI.Web/SpotifyWebAPI.cs b/SpotifyAPI.Web/SpotifyWebAPI.cs deleted file mode 100644 index b6574b34..00000000 --- a/SpotifyAPI.Web/SpotifyWebAPI.cs +++ /dev/null @@ -1,2941 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; - -namespace SpotifyAPI.Web -{ - // ReSharper disable once InconsistentNaming - public sealed class SpotifyWebAPI : IDisposable - { - private readonly SpotifyWebBuilder _builder; - - public SpotifyWebAPI() : this(null) { } - - public SpotifyWebAPI(ProxyConfig proxyConfig) - { - _builder = new SpotifyWebBuilder(); - UseAuth = true; - WebClient = new SpotifyWebClient(proxyConfig) - { - JsonSettings = - new JsonSerializerSettings - { - NullValueHandling = NullValueHandling.Ignore - } - }; - } - - public void Dispose() - { - WebClient.Dispose(); - GC.SuppressFinalize(this); - } - - #region Configuration - - /// - /// The type of the - /// - public string TokenType { get; set; } - - /// - /// A valid token issued by spotify. Used only when is true - /// - public string AccessToken { get; set; } - - /// - /// If true, an authorization header based on and will be used - /// - public bool UseAuth { get; set; } - - /// - /// A custom WebClient, used for Unit-Testing - /// - public IClient WebClient { get; set; } - - /// - /// Specifies after how many miliseconds should a failed request be retried. - /// - public int RetryAfter { get; set; } = 50; - - /// - /// Should a failed request (specified by be automatically retried or not. - /// - public bool UseAutoRetry { get; set; } = false; - - /// - /// Maximum number of tries for one failed request. - /// - public int RetryTimes { get; set; } = 10; - - /// - /// Whether a failure of type "Too Many Requests" should use up one of the allocated retry attempts. - /// - public bool TooManyRequestsConsumesARetry { get; set; } = false; - - /// - /// Error codes that will trigger auto-retry if is enabled. - /// - public IEnumerable RetryErrorCodes { get; set; } = new[] { 500, 502, 503 }; - - #endregion Configuration - - #region Search - - /// - /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string. - /// - /// The search query's keywords (and optional field filters and operators), for example q=roadhouse+blues. - /// A list of item types to search across. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first result to return. Default: 0 - /// An ISO 3166-1 alpha-2 country code or the string from_token. - /// - public SearchItem SearchItems(string q, SearchType type, int limit = 20, int offset = 0, string market = "") - { - return DownloadData(_builder.SearchItems(q, type, limit, offset, market)); - } - - /// - /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string asynchronously. - /// - /// The search query's keywords (and optional field filters and operators), for example q=roadhouse+blues. - /// A list of item types to search across. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first result to return. Default: 0 - /// An ISO 3166-1 alpha-2 country code or the string from_token. - /// - public Task SearchItemsAsync(string q, SearchType type, int limit = 20, int offset = 0, string market = "") - { - return DownloadDataAsync(_builder.SearchItems(q, type, limit, offset, market)); - } - - /// - /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string. - /// - /// The search query's keywords (and optional field filters and operators), for example q=roadhouse+blues. (properly escaped) - /// A list of item types to search across. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first result to return. Default: 0 - /// An ISO 3166-1 alpha-2 country code or the string from_token. - /// - public SearchItem SearchItemsEscaped(string q, SearchType type, int limit = 20, int offset = 0, string market = "") - { - string escapedQuery = WebUtility.UrlEncode(q); - return DownloadData(_builder.SearchItems(escapedQuery, type, limit, offset, market)); - } - - /// - /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string asynchronously. - /// - /// The search query's keywords (and optional field filters and operators), for example q=roadhouse+blues. (properly escaped) - /// A list of item types to search across. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first result to return. Default: 0 - /// An ISO 3166-1 alpha-2 country code or the string from_token. - /// - public Task SearchItemsEscapedAsync(string q, SearchType type, int limit = 20, int offset = 0, string market = "") - { - string escapedQuery = WebUtility.UrlEncode(q); - return DownloadDataAsync(_builder.SearchItems(escapedQuery, type, limit, offset, market)); - } - - #endregion Search - - #region Albums - - /// - /// Get Spotify catalog information about an album’s tracks. Optional parameters can be used to limit the number of - /// tracks returned. - /// - /// The Spotify ID for the album. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first track to return. Default: 0 (the first object). - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Paging GetAlbumTracks(string id, int limit = 20, int offset = 0, string market = "") - { - return DownloadData>(_builder.GetAlbumTracks(id, limit, offset, market)); - } - - /// - /// Get Spotify catalog information about an album’s tracks asynchronously. Optional parameters can be used to limit the number of - /// tracks returned. - /// - /// The Spotify ID for the album. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first track to return. Default: 0 (the first object). - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task> GetAlbumTracksAsync(string id, int limit = 20, int offset = 0, string market = "") - { - return DownloadDataAsync>(_builder.GetAlbumTracks(id, limit, offset, market)); - } - - /// - /// Get Spotify catalog information for a single album. - /// - /// The Spotify ID for the album. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public FullAlbum GetAlbum(string id, string market = "") - { - return DownloadData(_builder.GetAlbum(id, market)); - } - - /// - /// Get Spotify catalog information for a single album asynchronously. - /// - /// The Spotify ID for the album. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task GetAlbumAsync(string id, string market = "") - { - return DownloadDataAsync(_builder.GetAlbum(id, market)); - } - - /// - /// Get Spotify catalog information for multiple albums identified by their Spotify IDs. - /// - /// A list of the Spotify IDs for the albums. Maximum: 20 IDs. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public SeveralAlbums GetSeveralAlbums(List ids, string market = "") - { - return DownloadData(_builder.GetSeveralAlbums(ids, market)); - } - - /// - /// Get Spotify catalog information for multiple albums identified by their Spotify IDs asynchrously. - /// - /// A list of the Spotify IDs for the albums. Maximum: 20 IDs. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task GetSeveralAlbumsAsync(List ids, string market = "") - { - return DownloadDataAsync(_builder.GetSeveralAlbums(ids, market)); - } - - #endregion Albums - - #region Artists - - /// - /// Get Spotify catalog information for a single artist identified by their unique Spotify ID. - /// - /// The Spotify ID for the artist. - /// - public FullArtist GetArtist(string id) - { - return DownloadData(_builder.GetArtist(id)); - } - - /// - /// Get Spotify catalog information for a single artist identified by their unique Spotify ID asynchronously. - /// - /// The Spotify ID for the artist. - /// - public Task GetArtistAsync(string id) - { - return DownloadDataAsync(_builder.GetArtist(id)); - } - - /// - /// Get Spotify catalog information about artists similar to a given artist. Similarity is based on analysis of the - /// Spotify community’s listening history. - /// - /// The Spotify ID for the artist. - /// - public SeveralArtists GetRelatedArtists(string id) - { - return DownloadData(_builder.GetRelatedArtists(id)); - } - - /// - /// Get Spotify catalog information about artists similar to a given artist asynchronously. Similarity is based on analysis of the - /// Spotify community’s listening history. - /// - /// The Spotify ID for the artist. - /// - public Task GetRelatedArtistsAsync(string id) - { - return DownloadDataAsync(_builder.GetRelatedArtists(id)); - } - - /// - /// Get Spotify catalog information about an artist’s top tracks by country. - /// - /// The Spotify ID for the artist. - /// The country: an ISO 3166-1 alpha-2 country code. - /// - public SeveralTracks GetArtistsTopTracks(string id, string country) - { - return DownloadData(_builder.GetArtistsTopTracks(id, country)); - } - - /// - /// Get Spotify catalog information about an artist’s top tracks by country asynchronously. - /// - /// The Spotify ID for the artist. - /// The country: an ISO 3166-1 alpha-2 country code. - /// - public Task GetArtistsTopTracksAsync(string id, string country) - { - return DownloadDataAsync(_builder.GetArtistsTopTracks(id, country)); - } - - /// - /// Get Spotify catalog information about an artist’s albums. Optional parameters can be specified in the query string - /// to filter and sort the response. - /// - /// The Spotify ID for the artist. - /// - /// A list of keywords that will be used to filter the response. If not supplied, all album types will - /// be returned - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first album to return. Default: 0 - /// - /// An ISO 3166-1 alpha-2 country code. Supply this parameter to limit the response to one particular - /// geographical market - /// - /// - public Paging GetArtistsAlbums(string id, AlbumType type = AlbumType.All, int limit = 20, int offset = 0, string market = "") - { - return DownloadData>(_builder.GetArtistsAlbums(id, type, limit, offset, market)); - } - - /// - /// Get Spotify catalog information about an artist’s albums asynchronously. Optional parameters can be specified in the query string - /// to filter and sort the response. - /// - /// The Spotify ID for the artist. - /// - /// A list of keywords that will be used to filter the response. If not supplied, all album types will - /// be returned - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first album to return. Default: 0 - /// - /// An ISO 3166-1 alpha-2 country code. Supply this parameter to limit the response to one particular - /// geographical market - /// - /// - public Task> GetArtistsAlbumsAsync(string id, AlbumType type = AlbumType.All, int limit = 20, int offset = 0, string market = "") - { - return DownloadDataAsync>(_builder.GetArtistsAlbums(id, type, limit, offset, market)); - } - - /// - /// Get Spotify catalog information for several artists based on their Spotify IDs. - /// - /// A list of the Spotify IDs for the artists. Maximum: 50 IDs. - /// - public SeveralArtists GetSeveralArtists(List ids) - { - return DownloadData(_builder.GetSeveralArtists(ids)); - } - - /// - /// Get Spotify catalog information for several artists based on their Spotify IDs asynchronously. - /// - /// A list of the Spotify IDs for the artists. Maximum: 50 IDs. - /// - public Task GetSeveralArtistsAsync(List ids) - { - return DownloadDataAsync(_builder.GetSeveralArtists(ids)); - } - - #endregion Artists - - #region Browse - - /// - /// Get a list of Spotify featured playlists (shown, for example, on a Spotify player’s “Browse” tab). - /// - /// - /// The desired language, consisting of a lowercase ISO 639 language code and an uppercase ISO 3166-1 - /// alpha-2 country code, joined by an underscore. - /// - /// A country: an ISO 3166-1 alpha-2 country code. - /// A timestamp in ISO 8601 format - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// AUTH NEEDED - public FeaturedPlaylists GetFeaturedPlaylists(string locale = "", string country = "", DateTime timestamp = default(DateTime), int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetFeaturedPlaylists"); - return DownloadData(_builder.GetFeaturedPlaylists(locale, country, timestamp, limit, offset)); - } - - /// - /// Get a list of Spotify featured playlists asynchronously (shown, for example, on a Spotify player’s “Browse” tab). - /// - /// - /// The desired language, consisting of a lowercase ISO 639 language code and an uppercase ISO 3166-1 - /// alpha-2 country code, joined by an underscore. - /// - /// A country: an ISO 3166-1 alpha-2 country code. - /// A timestamp in ISO 8601 format - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// AUTH NEEDED - public Task GetFeaturedPlaylistsAsync(string locale = "", string country = "", DateTime timestamp = default(DateTime), int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetFeaturedPlaylists"); - return DownloadDataAsync(_builder.GetFeaturedPlaylists(locale, country, timestamp, limit, offset)); - } - - /// - /// Get a list of new album releases featured in Spotify (shown, for example, on a Spotify player’s “Browse” tab). - /// - /// A country: an ISO 3166-1 alpha-2 country code. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// - /// AUTH NEEDED - public NewAlbumReleases GetNewAlbumReleases(string country = "", int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetNewAlbumReleases"); - return DownloadData(_builder.GetNewAlbumReleases(country, limit, offset)); - } - - /// - /// Get a list of new album releases featured in Spotify asynchronously (shown, for example, on a Spotify player’s “Browse” tab). - /// - /// A country: an ISO 3166-1 alpha-2 country code. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// - /// AUTH NEEDED - public Task GetNewAlbumReleasesAsync(string country = "", int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetNewAlbumReleases"); - return DownloadDataAsync(_builder.GetNewAlbumReleases(country, limit, offset)); - } - - /// - /// Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab). - /// - /// - /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want to narrow the - /// list of returned categories to those relevant to a particular country - /// - /// - /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country - /// code, joined by an underscore - /// - /// The maximum number of categories to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 (the first object). - /// - /// AUTH NEEDED - public CategoryList GetCategories(string country = "", string locale = "", int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetCategories"); - return DownloadData(_builder.GetCategories(country, locale, limit, offset)); - } - - /// - /// Get a list of categories used to tag items in Spotify asynchronously (on, for example, the Spotify player’s “Browse” tab). - /// - /// - /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want to narrow the - /// list of returned categories to those relevant to a particular country - /// - /// - /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country - /// code, joined by an underscore - /// - /// The maximum number of categories to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 (the first object). - /// - /// AUTH NEEDED - public Task GetCategoriesAsync(string country = "", string locale = "", int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetCategories"); - return DownloadDataAsync(_builder.GetCategories(country, locale, limit, offset)); - } - - /// - /// Get a single category used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab). - /// - /// The Spotify category ID for the category. - /// - /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter to ensure that the category - /// exists for a particular country. - /// - /// - /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country - /// code, joined by an underscore - /// - /// - /// AUTH NEEDED - public Category GetCategory(string categoryId, string country = "", string locale = "") - { - return DownloadData(_builder.GetCategory(categoryId, country, locale)); - } - - /// - /// Get a single category used to tag items in Spotify asynchronously (on, for example, the Spotify player’s “Browse” tab). - /// - /// The Spotify category ID for the category. - /// - /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter to ensure that the category - /// exists for a particular country. - /// - /// - /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country - /// code, joined by an underscore - /// - /// - /// AUTH NEEDED - public Task GetCategoryAsync(string categoryId, string country = "", string locale = "") - { - return DownloadDataAsync(_builder.GetCategory(categoryId, country, locale)); - } - - /// - /// Get a list of Spotify playlists tagged with a particular category. - /// - /// The Spotify category ID for the category. - /// A country: an ISO 3166-1 alpha-2 country code. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// - /// AUTH NEEDED - public CategoryPlaylist GetCategoryPlaylists(string categoryId, string country = "", int limit = 20, int offset = 0) - { - return DownloadData(_builder.GetCategoryPlaylists(categoryId, country, limit, offset)); - } - - /// - /// Get a list of Spotify playlists tagged with a particular category asynchronously. - /// - /// The Spotify category ID for the category. - /// A country: an ISO 3166-1 alpha-2 country code. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// - /// AUTH NEEDED - public Task GetCategoryPlaylistsAsync(string categoryId, string country = "", int limit = 20, int offset = 0) - { - return DownloadDataAsync(_builder.GetCategoryPlaylists(categoryId, country, limit, offset)); - } - - /// - /// Create a playlist-style listening experience based on seed artists, tracks and genres. - /// - /// A comma separated list of Spotify IDs for seed artists. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// A comma separated list of any genres in the set of available genre seeds. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// A comma separated list of Spotify IDs for a seed track. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// Tracks with the attribute values nearest to the target values will be preferred. - /// For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided - /// For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided - /// The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100. - /// For seeds with unusually small pools or when highly restrictive filtering is applied, it may be impossible to generate the requested number of recommended tracks. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// Because min_*, max_* and target_* are applied to pools before relinking, the generated results may not precisely match the filters applied. - /// - /// AUTH NEEDED - public Recommendations GetRecommendations(List artistSeed = null, List genreSeed = null, List trackSeed = null, - TuneableTrack target = null, TuneableTrack min = null, TuneableTrack max = null, int limit = 20, string market = "") - { - return DownloadData(_builder.GetRecommendations(artistSeed, genreSeed, trackSeed, target, min, max, limit, market)); - } - - /// - /// Create a playlist-style listening experience based on seed artists, tracks and genres asynchronously. - /// - /// A comma separated list of Spotify IDs for seed artists. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// A comma separated list of any genres in the set of available genre seeds. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// A comma separated list of Spotify IDs for a seed track. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// Tracks with the attribute values nearest to the target values will be preferred. - /// For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided - /// For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided - /// The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100. - /// For seeds with unusually small pools or when highly restrictive filtering is applied, it may be impossible to generate the requested number of recommended tracks. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// Because min_*, max_* and target_* are applied to pools before relinking, the generated results may not precisely match the filters applied. - /// - /// AUTH NEEDED - public Task GetRecommendationsAsync(List artistSeed = null, List genreSeed = null, List trackSeed = null, - TuneableTrack target = null, TuneableTrack min = null, TuneableTrack max = null, int limit = 20, string market = "") - { - return DownloadDataAsync(_builder.GetRecommendations(artistSeed, genreSeed, trackSeed, target, min, max, limit, market)); - } - - /// - /// Retrieve a list of available genres seed parameter values for recommendations. - /// - /// - /// AUTH NEEDED - public RecommendationSeedGenres GetRecommendationSeedsGenres() - { - return DownloadData(_builder.GetRecommendationSeedsGenres()); - } - - /// - /// Retrieve a list of available genres seed parameter values for recommendations asynchronously. - /// - /// - /// AUTH NEEDED - public Task GetRecommendationSeedsGenresAsync() - { - return DownloadDataAsync(_builder.GetRecommendationSeedsGenres()); - } - - #endregion Browse - - #region Follow - - /// - /// Get the current user’s followed artists. - /// - /// The ID type: currently only artist is supported. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The last artist ID retrieved from the previous request. - /// - /// AUTH NEEDED - public FollowedArtists GetFollowedArtists(FollowType followType, int limit = 20, string after = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetFollowedArtists"); - return DownloadData(_builder.GetFollowedArtists(limit, after)); - } - - /// - /// Get the current user’s followed artists asynchronously. - /// - /// The ID type: currently only artist is supported. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The last artist ID retrieved from the previous request. - /// - /// AUTH NEEDED - public Task GetFollowedArtistsAsync(FollowType followType, int limit = 20, string after = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetFollowedArtists"); - return DownloadDataAsync(_builder.GetFollowedArtists(limit, after)); - } - - /// - /// Add the current user as a follower of one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs - /// - /// AUTH NEEDED - public ErrorResponse Follow(FollowType followType, List ids) - { - JObject ob = new JObject - { { "ids", new JArray(ids) } - }; - return UploadData(_builder.Follow(followType), ob.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Add the current user as a follower of one or more artists or other Spotify users asynchronously. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs - /// - /// AUTH NEEDED - public async Task FollowAsync(FollowType followType, List ids) - { - JObject ob = new JObject - { { "ids", new JArray(ids) } - }; - return await UploadDataAsync(_builder.Follow(followType), - ob.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Add the current user as a follower of one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// Artists or the Users Spotify ID - /// - /// AUTH NEEDED - public ErrorResponse Follow(FollowType followType, string id) - { - return Follow(followType, new List { id }); - } - - /// - /// Add the current user as a follower of one or more artists or other Spotify users asynchronously. - /// - /// The ID type: either artist or user. - /// Artists or the Users Spotify ID - /// - /// AUTH NEEDED - public Task FollowAsync(FollowType followType, string id) - { - return FollowAsync(followType, new List { id }); - } - - /// - /// Remove the current user as a follower of one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs - /// - /// AUTH NEEDED - public ErrorResponse Unfollow(FollowType followType, List ids) - { - JObject ob = new JObject - { { "ids", new JArray(ids) } - }; - return UploadData(_builder.Unfollow(followType), ob.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); - } - - /// - /// Remove the current user as a follower of one or more artists or other Spotify users asynchronously. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs - /// - /// AUTH NEEDED - public async Task UnfollowAsync(FollowType followType, List ids) - { - JObject ob = new JObject - { { "ids", new JArray(ids) } - }; - return await UploadDataAsync(_builder.Unfollow(followType), ob.ToString(Formatting.None), "DELETE").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Remove the current user as a follower of one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// Artists or the Users Spotify ID - /// - /// AUTH NEEDED - public ErrorResponse Unfollow(FollowType followType, string id) - { - return Unfollow(followType, new List { id }); - } - - /// - /// Remove the current user as a follower of one or more artists or other Spotify users asynchronously. - /// - /// The ID type: either artist or user. - /// Artists or the Users Spotify ID - /// - /// AUTH NEEDED - public Task UnfollowAsync(FollowType followType, string id) - { - return UnfollowAsync(followType, new List { id }); - } - - /// - /// Check to see if the current user is following one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs to check - /// - /// AUTH NEEDED - public ListResponse IsFollowing(FollowType followType, List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for IsFollowing"); - - string url = _builder.IsFollowing(followType, ids); - return DownloadList(url); - } - - /// - /// Check to see if the current user is following one or more artists or other Spotify users asynchronously. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs to check - /// - /// AUTH NEEDED - public Task> IsFollowingAsync(FollowType followType, List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for IsFollowing"); - - string url = _builder.IsFollowing(followType, ids); - return DownloadListAsync(url); - } - - /// - /// Check to see if the current user is following one artist or another Spotify user. - /// - /// The ID type: either artist or user. - /// Artists or the Users Spotify ID - /// - /// AUTH NEEDED - public ListResponse IsFollowing(FollowType followType, string id) - { - return IsFollowing(followType, new List { id }); - } - - /// - /// Check to see if the current user is following one artist or another Spotify user asynchronously. - /// - /// The ID type: either artist or user. - /// Artists or the Users Spotify ID - /// - /// AUTH NEEDED - public Task> IsFollowingAsync(FollowType followType, string id) - { - return IsFollowingAsync(followType, new List { id }); - } - - /// - /// Add the current user as a follower of a playlist. - /// - /// - /// The Spotify ID of the playlist. Any playlist can be followed, regardless of its public/private - /// status, as long as you know its playlist ID. - /// - /// - /// If true the playlist will be included in user's public playlists, if false it will remain - /// private. - /// - /// - /// AUTH NEEDED - public ErrorResponse FollowPlaylist(string ownerId, string playlistId, bool showPublic = true) - { - JObject body = new JObject - { { "public", showPublic } - }; - return UploadData(_builder.FollowPlaylist(playlistId), body.ToString(Formatting.None), "PUT"); - } - - /// - /// Add the current user as a follower of a playlist asynchronously. - /// - /// - /// The Spotify ID of the playlist. Any playlist can be followed, regardless of its public/private - /// status, as long as you know its playlist ID. - /// - /// - /// If true the playlist will be included in user's public playlists, if false it will remain - /// private. - /// - /// - /// AUTH NEEDED - public Task FollowPlaylistAsync(string playlistId, bool showPublic = true) - { - JObject body = new JObject - { { "public", showPublic } - }; - return UploadDataAsync(_builder.FollowPlaylist(playlistId), body.ToString(Formatting.None), "PUT"); - } - - /// - /// Remove the current user as a follower of a playlist. - /// - /// The Spotify ID of the playlist that is to be no longer followed. - /// - /// AUTH NEEDED - public ErrorResponse UnfollowPlaylist(string playlistId) - { - return UploadData(_builder.UnfollowPlaylist(playlistId), "", "DELETE"); - } - - /// - /// Remove the current user as a follower of a playlist asynchronously. - /// - /// The Spotify user ID of the person who owns the playlist. - /// The Spotify ID of the playlist that is to be no longer followed. - /// - /// AUTH NEEDED - public Task UnfollowPlaylistAsync(string playlistId) - { - return UploadDataAsync(_builder.UnfollowPlaylist(playlistId), "", "DELETE"); - } - - /// - /// Check to see if one or more Spotify users are following a specified playlist. - /// - /// The Spotify ID of the playlist. - /// A list of Spotify User IDs - /// - /// AUTH NEEDED - public ListResponse IsFollowingPlaylist(string playlistId, List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for IsFollowingPlaylist"); - - string url = _builder.IsFollowingPlaylist(playlistId, ids); - return DownloadList(url); - } - - /// - /// Check to see if one or more Spotify users are following a specified playlist asynchronously. - /// - /// The Spotify ID of the playlist. - /// A list of Spotify User IDs - /// - /// AUTH NEEDED - public Task> IsFollowingPlaylistAsync(string playlistId, List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for IsFollowingPlaylist"); - - string url = _builder.IsFollowingPlaylist(playlistId, ids); - return DownloadListAsync(url); - } - - /// - /// Check to see if one or more Spotify users are following a specified playlist. - /// - /// The Spotify ID of the playlist. - /// A Spotify User ID - /// - /// AUTH NEEDED - public ListResponse IsFollowingPlaylist(string playlistId, string id) - { - return IsFollowingPlaylist(playlistId, new List { id }); - } - - /// - /// Check to see if one or more Spotify users are following a specified playlist asynchronously. - /// - /// The Spotify ID of the playlist. - /// A Spotify User ID - /// - /// AUTH NEEDED - public Task> IsFollowingPlaylistAsync(string playlistId, string id) - { - return IsFollowingPlaylistAsync(playlistId, new List { id }); - } - - #endregion Follow - - #region Library - - /// - /// Save one or more tracks to the current user’s “Your Music” library. - /// - /// A list of the Spotify IDs - /// - /// AUTH NEEDED - public ErrorResponse SaveTracks(List ids) - { - JArray array = new JArray(ids); - return UploadData(_builder.SaveTracks(), array.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Save one or more tracks to the current user’s “Your Music” library asynchronously. - /// - /// A list of the Spotify IDs - /// - /// AUTH NEEDED - public async Task SaveTracksAsync(List ids) - { - JArray array = new JArray(ids); - return await UploadDataAsync(_builder.SaveTracks(), array.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Save one track to the current user’s “Your Music” library. - /// - /// A Spotify ID - /// - /// AUTH NEEDED - public ErrorResponse SaveTrack(string id) - { - return SaveTracks(new List { id }); - } - - /// - /// Save one track to the current user’s “Your Music” library asynchronously. - /// - /// A Spotify ID - /// - /// AUTH NEEDED - public Task SaveTrackAsync(string id) - { - return SaveTracksAsync(new List { id }); - } - - /// - /// Get a list of the songs saved in the current Spotify user’s “Your Music” library. - /// - /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Paging GetSavedTracks(int limit = 20, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetSavedTracks"); - return DownloadData>(_builder.GetSavedTracks(limit, offset, market)); - } - - /// - /// Get a list of the songs saved in the current Spotify user’s “Your Music” library asynchronously. - /// - /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Task> GetSavedTracksAsync(int limit = 20, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetSavedTracks"); - return DownloadDataAsync>(_builder.GetSavedTracks(limit, offset, market)); - } - - /// - /// Remove one or more tracks from the current user’s “Your Music” library. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public ErrorResponse RemoveSavedTracks(List ids) - { - JArray array = new JArray(ids); - return UploadData(_builder.RemoveSavedTracks(), array.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); - } - - /// - /// Remove one or more tracks from the current user’s “Your Music” library asynchronously. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public async Task RemoveSavedTracksAsync(List ids) - { - JArray array = new JArray(ids); - return await UploadDataAsync(_builder.RemoveSavedTracks(), array.ToString(Formatting.None), "DELETE").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public ListResponse CheckSavedTracks(List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for CheckSavedTracks"); - - string url = _builder.CheckSavedTracks(ids); - return DownloadList(url); - } - - /// - /// Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library asynchronously. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public Task> CheckSavedTracksAsync(List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for CheckSavedTracks"); - string url = _builder.CheckSavedTracks(ids); - return DownloadListAsync(url); - } - - /// - /// Save one or more albums to the current user’s “Your Music” library. - /// - /// A list of the Spotify IDs - /// - /// AUTH NEEDED - public ErrorResponse SaveAlbums(List ids) - { - JArray array = new JArray(ids); - return UploadData(_builder.SaveAlbums(), array.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Save one or more albums to the current user’s “Your Music” library asynchronously. - /// - /// A list of the Spotify IDs - /// - /// AUTH NEEDED - public async Task SaveAlbumsAsync(List ids) - { - JArray array = new JArray(ids); - return await UploadDataAsync(_builder.SaveAlbums(), array.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Save one album to the current user’s “Your Music” library. - /// - /// A Spotify ID - /// - /// AUTH NEEDED - public ErrorResponse SaveAlbum(string id) - { - return SaveAlbums(new List { id }); - } - - /// - /// Save one album to the current user’s “Your Music” library asynchronously. - /// - /// A Spotify ID - /// - /// AUTH NEEDED - public Task SaveAlbumAsync(string id) - { - return SaveAlbumsAsync(new List { id }); - } - - /// - /// Get a list of the albums saved in the current Spotify user’s “Your Music” library. - /// - /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Paging GetSavedAlbums(int limit = 20, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetSavedAlbums"); - return DownloadData>(_builder.GetSavedAlbums(limit, offset, market)); - } - - /// - /// Get a list of the albums saved in the current Spotify user’s “Your Music” library asynchronously. - /// - /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Task> GetSavedAlbumsAsync(int limit = 20, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetSavedAlbumsAsync"); - return DownloadDataAsync>(_builder.GetSavedAlbums(limit, offset, market)); - } - - /// - /// Remove one or more albums from the current user’s “Your Music” library. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public ErrorResponse RemoveSavedAlbums(List ids) - { - JArray array = new JArray(ids); - return UploadData(_builder.RemoveSavedAlbums(), array.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); - } - - /// - /// Remove one or more albums from the current user’s “Your Music” library asynchronously. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public async Task RemoveSavedAlbumsAsync(List ids) - { - JArray array = new JArray(ids); - return await UploadDataAsync(_builder.RemoveSavedAlbums(), array.ToString(Formatting.None), "DELETE").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Check if one or more albums is already saved in the current Spotify user’s “Your Music” library. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public ListResponse CheckSavedAlbums(List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for CheckSavedTracks"); - - string url = _builder.CheckSavedAlbums(ids); - return DownloadList(url); - } - - /// - /// Check if one or more albums is already saved in the current Spotify user’s “Your Music” library asynchronously. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public Task> CheckSavedAlbumsAsync(List ids) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for CheckSavedAlbumsAsync"); - string url = _builder.CheckSavedAlbums(ids); - return DownloadListAsync(url); - } - - #endregion Library - - #region Personalization - - /// - /// Get the current user’s top tracks based on calculated affinity. - /// - /// Over what time frame the affinities are computed. - /// Valid values: long_term (calculated from several years of data and including all new data as it becomes available), - /// medium_term (approximately last 6 months), short_term (approximately last 4 weeks). - /// The number of entities to return. Default: 20. Minimum: 1. Maximum: 50 - /// The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities. - /// - /// AUTH NEEDED - public Paging GetUsersTopTracks(TimeRangeType timeRange = TimeRangeType.MediumTerm, int limit = 20, int offest = 0) - { - return DownloadData>(_builder.GetUsersTopTracks(timeRange, limit, offest)); - } - - /// - /// Get the current user’s top tracks based on calculated affinity asynchronously. - /// - /// Over what time frame the affinities are computed. - /// Valid values: long_term (calculated from several years of data and including all new data as it becomes available), - /// medium_term (approximately last 6 months), short_term (approximately last 4 weeks). - /// The number of entities to return. Default: 20. Minimum: 1. Maximum: 50 - /// The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities. - /// - /// AUTH NEEDED - public Task> GetUsersTopTracksAsync(TimeRangeType timeRange = TimeRangeType.MediumTerm, int limit = 20, int offest = 0) - { - return DownloadDataAsync>(_builder.GetUsersTopTracks(timeRange, limit, offest)); - } - - /// - /// Get the current user’s top artists based on calculated affinity. - /// - /// Over what time frame the affinities are computed. - /// Valid values: long_term (calculated from several years of data and including all new data as it becomes available), - /// medium_term (approximately last 6 months), short_term (approximately last 4 weeks). - /// The number of entities to return. Default: 20. Minimum: 1. Maximum: 50 - /// The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities. - /// - /// AUTH NEEDED - public Paging GetUsersTopArtists(TimeRangeType timeRange = TimeRangeType.MediumTerm, int limit = 20, int offest = 0) - { - return DownloadData>(_builder.GetUsersTopArtists(timeRange, limit, offest)); - } - - /// - /// Get the current user’s top artists based on calculated affinity asynchronously. - /// - /// Over what time frame the affinities are computed. - /// Valid values: long_term (calculated from several years of data and including all new data as it becomes available), - /// medium_term (approximately last 6 months), short_term (approximately last 4 weeks). - /// The number of entities to return. Default: 20. Minimum: 1. Maximum: 50 - /// The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities. - /// - /// AUTH NEEDED - public Task> GetUsersTopArtistsAsync(TimeRangeType timeRange = TimeRangeType.MediumTerm, int limit = 20, int offest = 0) - { - return DownloadDataAsync>(_builder.GetUsersTopArtists(timeRange, limit, offest)); - } - - /// - /// Get tracks from the current user’s recent play history. - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// A Unix timestamp in milliseconds. Returns all items after (but not including) this cursor position. If after is specified, before must not be specified. - /// A Unix timestamp in milliseconds. Returns all items before (but not including) this cursor position. If before is specified, after must not be specified. - /// - /// AUTH NEEDED - public CursorPaging GetUsersRecentlyPlayedTracks(int limit = 20, DateTime? after = null, - DateTime? before = null) - { - return DownloadData>(_builder.GetUsersRecentlyPlayedTracks(limit, after, before)); - } - - /// - /// Get tracks from the current user’s recent play history asynchronously - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// A Unix timestamp in milliseconds. Returns all items after (but not including) this cursor position. If after is specified, before must not be specified. - /// A Unix timestamp in milliseconds. Returns all items before (but not including) this cursor position. If before is specified, after must not be specified. - /// - /// AUTH NEEDED - public Task> GetUsersRecentlyPlayedTracksAsync(int limit = 20, DateTime? after = null, - DateTime? before = null) - { - return DownloadDataAsync>(_builder.GetUsersRecentlyPlayedTracks(limit, after, before)); - } - - #endregion - - #region Playlists - - /// - /// Get a list of the playlists owned or followed by a Spotify user. - /// - /// The user's Spotify user ID. - /// The maximum number of playlists to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first playlist to return. Default: 0 (the first object) - /// - /// AUTH NEEDED - public Paging GetUserPlaylists(string userId, int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetUserPlaylists"); - return DownloadData>(_builder.GetUserPlaylists(userId, limit, offset)); - } - - /// - /// Get a list of the playlists owned or followed by a Spotify user asynchronously. - /// - /// The user's Spotify user ID. - /// The maximum number of playlists to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first playlist to return. Default: 0 (the first object) - /// - /// AUTH NEEDED - public Task> GetUserPlaylistsAsync(string userId, int limit = 20, int offset = 0) - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetUserPlaylists"); - return DownloadDataAsync>(_builder.GetUserPlaylists(userId, limit, offset)); - } - - /// - /// Get a playlist owned by a Spotify user. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - [Obsolete("Calling GetPlaylist with a userId is deprecated, remove the parameter")] - public FullPlaylist GetPlaylist(string userId, string playlistId, string fields = "", string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylist"); - return DownloadData(_builder.GetPlaylist(userId, playlistId, fields, market)); - } - - /// - /// Get a playlist owned by a Spotify user. - /// - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public FullPlaylist GetPlaylist(string playlistId, string fields = "", string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylist"); - return DownloadData(_builder.GetPlaylist(playlistId, fields, market)); - } - - /// - /// Get a playlist owned by a Spotify user asynchronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - [Obsolete("Calling GetPlaylist with a userId is deprecated, remove the parameter")] - public Task GetPlaylistAsync(string userId, string playlistId, string fields = "", string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylist"); - return DownloadDataAsync(_builder.GetPlaylist(userId, playlistId, fields, market)); - } - - /// - /// Get a playlist owned by a Spotify user asynchronously. - /// - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Task GetPlaylistAsync(string playlistId, string fields = "", string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylist"); - return DownloadDataAsync(_builder.GetPlaylist(playlistId, fields, market)); - } - - /// - /// Get full details of the tracks of a playlist owned by a Spotify user. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - [Obsolete("Calling GetPlaylistTracks with a userId is deprecated, remove the parameter")] - public Paging GetPlaylistTracks(string userId, string playlistId, string fields = "", int limit = 100, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylistTracks"); - return DownloadData>(_builder.GetPlaylistTracks(userId, playlistId, fields, limit, offset, market)); - } - - /// - /// Get full details of the tracks of a playlist owned by a Spotify user. - /// - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Paging GetPlaylistTracks(string playlistId, string fields = "", int limit = 100, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylistTracks"); - return DownloadData>(_builder.GetPlaylistTracks(playlistId, fields, limit, offset, market)); - } - - /// - /// Get full details of the tracks of a playlist owned by a Spotify user asyncronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - [Obsolete("Calling GetPlaylistTracks with a userId is deprecated, remove the parameter")] - public Task> GetPlaylistTracksAsync(string userId, string playlistId, string fields = "", int limit = 100, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylistTracks"); - return DownloadDataAsync>(_builder.GetPlaylistTracks(userId, playlistId, fields, limit, offset, market)); - } - - /// - /// Get full details of the tracks of a playlist owned by a Spotify user asyncronously. - /// - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public Task> GetPlaylistTracksAsync(string playlistId, string fields = "", int limit = 100, int offset = 0, string market = "") - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPlaylistTracks"); - return DownloadDataAsync>(_builder.GetPlaylistTracks(playlistId, fields, limit, offset, market)); - } - - /// - /// Create a playlist for a Spotify user. (The playlist will be empty until you add tracks.) - /// - /// The user's Spotify user ID. - /// - /// The name for the new playlist, for example "Your Coolest Playlist". This name does not need - /// to be unique. - /// - /// - /// default true. If true the playlist will be public, if false it will be private. To be able to - /// create private playlists, the user must have granted the playlist-modify-private scope. - /// - /// If true the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. - /// Note: You can only set collaborative to true on non-public playlists. - /// Value for playlist description as displayed in Spotify Clients and in the Web API. - /// - /// AUTH NEEDED - public FullPlaylist CreatePlaylist(string userId, string playlistName, bool isPublic = true, bool isCollaborative = false, string playlistDescription = "") - { - JObject body = new JObject - { { "name", playlistName }, { "public", isPublic }, { "collaborative", isCollaborative }, { "description", playlistDescription } - }; - return UploadData(_builder.CreatePlaylist(userId, playlistName, isPublic), body.ToString(Formatting.None)); - } - - /// - /// Create a playlist for a Spotify user asynchronously. (The playlist will be empty until you add tracks.) - /// - /// The user's Spotify user ID. - /// - /// The name for the new playlist, for example "Your Coolest Playlist". This name does not need - /// to be unique. - /// - /// - /// default true. If true the playlist will be public, if false it will be private. To be able to - /// create private playlists, the user must have granted the playlist-modify-private scope. - /// - /// If true the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. - /// Note: You can only set collaborative to true on non-public playlists. - /// Value for playlist description as displayed in Spotify Clients and in the Web API. - /// - /// AUTH NEEDED - public Task CreatePlaylistAsync(string userId, string playlistName, bool isPublic = true, bool isCollaborative = false, string playlistDescription = "") - { - JObject body = new JObject - { { "name", playlistName }, { "public", isPublic }, { "collaborative", isCollaborative }, { "description", playlistDescription } - }; - return UploadDataAsync(_builder.CreatePlaylist(userId, playlistName, isPublic), body.ToString(Formatting.None)); - } - - /// - /// Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// The new name for the playlist, for example "My New Playlist Title". - /// If true the playlist will be public, if false it will be private. - /// If true the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. - /// Note: You can only set collaborative to true on non-public playlists. - /// Value for playlist description as displayed in Spotify Clients and in the Web API. - /// - /// AUTH NEEDED - [Obsolete("Calling UpdatePlaylist with a userId is deprecated, remove the parameter")] - public ErrorResponse UpdatePlaylist(string userId, string playlistId, string newName = null, bool? newPublic = null, bool? newCollaborative = null, string newDescription = null) - { - JObject body = new JObject(); - if (newName != null) - body.Add("name", newName); - if (newPublic != null) - body.Add("public", newPublic); - if (newCollaborative != null) - body.Add("collaborative", newCollaborative); - if (newDescription != null) - body.Add("description", newDescription); - return UploadData(_builder.UpdatePlaylist(userId, playlistId), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) - /// - /// The Spotify ID for the playlist. - /// The new name for the playlist, for example "My New Playlist Title". - /// If true the playlist will be public, if false it will be private. - /// If true the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. - /// Note: You can only set collaborative to true on non-public playlists. - /// Value for playlist description as displayed in Spotify Clients and in the Web API. - /// - /// AUTH NEEDED - public ErrorResponse UpdatePlaylist(string playlistId, string newName = null, bool? newPublic = null, bool? newCollaborative = null, string newDescription = null) - { - JObject body = new JObject(); - if (newName != null) - body.Add("name", newName); - if (newPublic != null) - body.Add("public", newPublic); - if (newCollaborative != null) - body.Add("collaborative", newCollaborative); - if (newDescription != null) - body.Add("description", newDescription); - return UploadData(_builder.UpdatePlaylist(playlistId), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state asynchronously. (The user must, of course, own the playlist.) - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// The new name for the playlist, for example "My New Playlist Title". - /// If true the playlist will be public, if false it will be private. - /// If true the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. Note: You can only set collaborative to true on non-public playlists. - /// Value for playlist description as displayed in Spotify Clients and in the Web API. - /// - /// AUTH NEEDED - [Obsolete("Calling UpdatePlaylist with a userId is deprecated, remove the parameter")] - public async Task UpdatePlaylistAsync(string userId, string playlistId, string newName = null, bool? newPublic = null, bool? newCollaborative = null, string newDescription = null) - { - JObject body = new JObject(); - if (newName != null) - body.Add("name", newName); - if (newPublic != null) - body.Add("public", newPublic); - if (newCollaborative != null) - body.Add("collaborative", newCollaborative); - if (newDescription != null) - body.Add("description", newDescription); - return await UploadDataAsync(_builder.UpdatePlaylist(userId, playlistId), body.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state asynchronously. (The user must, of course, own the playlist.) - /// - /// The Spotify ID for the playlist. - /// The new name for the playlist, for example "My New Playlist Title". - /// If true the playlist will be public, if false it will be private. - /// If true the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. Note: You can only set collaborative to true on non-public playlists. - /// Value for playlist description as displayed in Spotify Clients and in the Web API. - /// - /// AUTH NEEDED - public async Task UpdatePlaylistAsync(string playlistId, string newName = null, bool? newPublic = null, bool? newCollaborative = null, string newDescription = null) - { - JObject body = new JObject(); - if (newName != null) - body.Add("name", newName); - if (newPublic != null) - body.Add("public", newPublic); - if (newCollaborative != null) - body.Add("collaborative", newCollaborative); - if (newDescription != null) - body.Add("description", newDescription); - return await UploadDataAsync(_builder.UpdatePlaylist(playlistId), body.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// The image as a base64 encoded string - /// - /// AUTH NEEDED - public ErrorResponse UploadPlaylistImage(string userId, string playlistId, string base64EncodedJpgImage) - { - return UploadData(_builder.UploadPlaylistImage(userId, playlistId), base64EncodedJpgImage, "PUT") ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state asynchronously. (The user must, of course, own the playlist.) - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// The image as a base64 encoded string - /// - /// AUTH NEEDED - public async Task UploadPlaylistImageAsync(string userId, string playlistId, string base64EncodedJpgImage) - { - return await UploadDataAsync(_builder.UploadPlaylistImage(userId, playlistId), base64EncodedJpgImage, "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) - /// - /// The Spotify ID for the playlist. - /// The image as a base64 encoded string - /// - /// AUTH NEEDED - public ErrorResponse UploadPlaylistImage(string playlistId, string base64EncodedJpgImage) - { - return UploadData(_builder.UploadPlaylistImage(playlistId), base64EncodedJpgImage, "PUT") ?? new ErrorResponse(); - } - - /// - /// Change a playlist’s name and public/private state asynchronously. (The user must, of course, own the playlist.) - /// - /// The Spotify ID for the playlist. - /// The image as a base64 encoded string - /// - /// AUTH NEEDED - public async Task UploadPlaylistImageAsync(string playlistId, string base64EncodedJpgImage) - { - return await UploadDataAsync(_builder.UploadPlaylistImage(playlistId), - base64EncodedJpgImage, "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Replace all the tracks in a playlist, overwriting its existing tracks. This powerful request can be useful for - /// replacing tracks, re-ordering existing tracks, or clearing the playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to set. A maximum of 100 tracks can be set in one request. - /// - /// AUTH NEEDED - [Obsolete("Calling ReplacePlaylistTracks with a userId is deprecated, remove the parameter")] - public ErrorResponse ReplacePlaylistTracks(string userId, string playlistId, List uris) - { - JObject body = new JObject - { { "uris", new JArray(uris.Take(100)) } - }; - return UploadData(_builder.ReplacePlaylistTracks(userId, playlistId), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Replace all the tracks in a playlist, overwriting its existing tracks. This powerful request can be useful for - /// replacing tracks, re-ordering existing tracks, or clearing the playlist. - /// - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to set. A maximum of 100 tracks can be set in one request. - /// - /// AUTH NEEDED - public ErrorResponse ReplacePlaylistTracks(string playlistId, List uris) - { - JObject body = new JObject - { { "uris", new JArray(uris.Take(100)) } - }; - return UploadData(_builder.ReplacePlaylistTracks(playlistId), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); - } - - /// - /// Replace all the tracks in a playlist asynchronously, overwriting its existing tracks. This powerful request can be useful for - /// replacing tracks, re-ordering existing tracks, or clearing the playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to set. A maximum of 100 tracks can be set in one request. - /// - /// AUTH NEEDED - [Obsolete("Calling ReplacePlaylistTracks with a userId is deprecated, remove the parameter")] - public async Task ReplacePlaylistTracksAsync(string userId, string playlistId, List uris) - { - JObject body = new JObject - { { "uris", new JArray(uris.Take(100)) } - }; - return await UploadDataAsync(_builder.ReplacePlaylistTracks(userId, playlistId), body.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Replace all the tracks in a playlist asynchronously, overwriting its existing tracks. This powerful request can be useful for - /// replacing tracks, re-ordering existing tracks, or clearing the playlist. - /// - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to set. A maximum of 100 tracks can be set in one request. - /// - /// AUTH NEEDED - public async Task ReplacePlaylistTracksAsync(string playlistId, List uris) - { - JObject body = new JObject - { { "uris", new JArray(uris.Take(100)) } - }; - return await UploadDataAsync(_builder.ReplacePlaylistTracks(playlistId), body.ToString(Formatting.None), "PUT").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Remove one or more tracks from a user’s playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of - /// 100 objects can be sent at once. - /// - /// - /// AUTH NEEDED - [Obsolete("Calling RemovePlaylistTracks with a userId is deprecated, remove the parameter")] - public ErrorResponse RemovePlaylistTracks(string userId, string playlistId, List uris) - { - JObject body = new JObject - { { "tracks", JArray.FromObject(uris.Take(100)) } - }; - return UploadData(_builder.RemovePlaylistTracks(userId, playlistId, uris), body.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); - } - - /// - /// Remove one or more tracks from a user’s playlist. - /// - /// The Spotify ID for the playlist. - /// - /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of - /// 100 objects can be sent at once. - /// - /// - /// AUTH NEEDED - public ErrorResponse RemovePlaylistTracks(string playlistId, List uris) - { - JObject body = new JObject - { { "tracks", JArray.FromObject(uris.Take(100)) } - }; - return UploadData(_builder.RemovePlaylistTracks(playlistId, uris), body.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); - } - - /// - /// Remove one or more tracks from a user’s playlist asynchronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of - /// 100 objects can be sent at once. - /// - /// - /// AUTH NEEDED - [Obsolete("Calling RemovePlaylistTracks with a userId is deprecated, remove the parameter")] - public async Task RemovePlaylistTracksAsync(string userId, string playlistId, List uris) - { - JObject body = new JObject - { { "tracks", JArray.FromObject(uris.Take(100)) } - }; - return await UploadDataAsync(_builder.RemovePlaylistTracks(userId, playlistId, uris), body.ToString(Formatting.None), "DELETE").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Remove one or more tracks from a user’s playlist asynchronously. - /// - /// The Spotify ID for the playlist. - /// - /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of - /// 100 objects can be sent at once. - /// - /// - /// AUTH NEEDED - public async Task RemovePlaylistTracksAsync(string playlistId, List uris) - { - JObject body = new JObject - { { "tracks", JArray.FromObject(uris.Take(100)) } - }; - return await UploadDataAsync(_builder.RemovePlaylistTracks(playlistId, uris), body.ToString(Formatting.None), "DELETE").ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Remove a track from a user’s playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// Spotify URI - /// - /// AUTH NEEDED - [Obsolete("Calling RemovePlaylistTrack with a userId is deprecated, remove the parameter")] - public ErrorResponse RemovePlaylistTrack(string userId, string playlistId, DeleteTrackUri uri) - { - return RemovePlaylistTracks(playlistId, new List { uri }); - } - - /// - /// Remove a track from a user’s playlist. - /// - /// The Spotify ID for the playlist. - /// Spotify URI - /// - /// AUTH NEEDED - public ErrorResponse RemovePlaylistTrack(string playlistId, DeleteTrackUri uri) - { - return RemovePlaylistTracks(playlistId, new List { uri }); - } - - /// - /// Remove a track from a user’s playlist asynchronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// Spotify URI - /// - /// AUTH NEEDED - [Obsolete("Calling RemovePlaylistTrack with a userId is deprecated, remove the parameter")] - public Task RemovePlaylistTrackAsync(string userId, string playlistId, DeleteTrackUri uri) - { - return RemovePlaylistTracksAsync(playlistId, new List { uri }); - } - - /// - /// Remove a track from a user’s playlist asynchronously. - /// - /// The Spotify ID for the playlist. - /// Spotify URI - /// - /// AUTH NEEDED - public Task RemovePlaylistTrackAsync(string playlistId, DeleteTrackUri uri) - { - return RemovePlaylistTracksAsync(playlistId, new List { uri }); - } - - /// - /// Add one or more tracks to a user’s playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to add - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - [Obsolete("Calling AddPlaylistTracks with a userId is deprecated, remove the parameter")] - public ErrorResponse AddPlaylistTracks(string userId, string playlistId, List uris, int? position = null) - { - JObject body = new JObject - { { "uris", JArray.FromObject(uris.Take(100)) } - }; - return UploadData(_builder.AddPlaylistTracks(userId, playlistId, uris, position), body.ToString(Formatting.None)) ?? new ErrorResponse(); - } - - /// - /// Add one or more tracks to a user’s playlist. - /// - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to add - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - public ErrorResponse AddPlaylistTracks(string playlistId, List uris, int? position = null) - { - JObject body = new JObject - { { "uris", JArray.FromObject(uris.Take(100)) } - }; - return UploadData(_builder.AddPlaylistTracks(playlistId, uris, position), body.ToString(Formatting.None)) ?? new ErrorResponse(); - } - - /// - /// Add one or more tracks to a user’s playlist asynchronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to add - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - [Obsolete("Calling AddPlaylistTracks with a userId is deprecated, remove the parameter")] - public async Task AddPlaylistTracksAsync(string userId, string playlistId, List uris, int? position = null) - { - JObject body = new JObject - { { "uris", JArray.FromObject(uris.Take(100)) } - }; - return await UploadDataAsync(_builder.AddPlaylistTracks(userId, playlistId, uris, position), body.ToString(Formatting.None)).ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Add one or more tracks to a user’s playlist asynchronously. - /// - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to add - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - public async Task AddPlaylistTracksAsync(string playlistId, List uris, int? position = null) - { - JObject body = new JObject - { { "uris", JArray.FromObject(uris.Take(100)) } - }; - return await UploadDataAsync(_builder.AddPlaylistTracks(playlistId, uris, position), body.ToString(Formatting.None)).ConfigureAwait(false) ?? new ErrorResponse(); - } - - /// - /// Add a track to a user’s playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A Spotify Track URI - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - [Obsolete("Calling AddPlaylistTrack with a userId is deprecated, remove the parameter")] - public ErrorResponse AddPlaylistTrack(string userId, string playlistId, string uri, int? position = null) - { - return AddPlaylistTracks(playlistId, new List { uri }, position); - } - - /// - /// Add a track to a user’s playlist. - /// - /// The Spotify ID for the playlist. - /// A Spotify Track URI - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - public ErrorResponse AddPlaylistTrack(string playlistId, string uri, int? position = null) - { - return AddPlaylistTracks(playlistId, new List { uri }, position); - } - - /// - /// Add a track to a user’s playlist asynchronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A Spotify Track URI - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - [Obsolete("Calling AddPlaylistTrack with a userId is deprecated, remove the parameter")] - public Task AddPlaylistTrackAsync(string userId, string playlistId, string uri, int? position = null) - { - return AddPlaylistTracksAsync(userId, playlistId, new List { uri }, position); - } - - /// - /// Add a track to a user’s playlist asynchronously. - /// - /// The Spotify ID for the playlist. - /// A Spotify Track URI - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - public Task AddPlaylistTrackAsync(string playlistId, string uri, int? position = null) - { - return AddPlaylistTracksAsync(playlistId, new List { uri }, position); - } - - /// - /// Reorder a track or a group of tracks in a playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// The position of the first track to be reordered. - /// The position where the tracks should be inserted. - /// The amount of tracks to be reordered. Defaults to 1 if not set. - /// The playlist's snapshot ID against which you want to make the changes. - /// - /// AUTH NEEDED - [Obsolete("Calling ReorderPlaylist with a userId is deprecated, remove the parameter")] - public Snapshot ReorderPlaylist(string userId, string playlistId, int rangeStart, int insertBefore, int rangeLength = 1, string snapshotId = "") - { - JObject body = new JObject - { { "range_start", rangeStart }, { "range_length", rangeLength }, { "insert_before", insertBefore } - }; - if (!string.IsNullOrEmpty(snapshotId)) - body.Add("snapshot_id", snapshotId); - return UploadData(_builder.ReorderPlaylist(userId, playlistId), body.ToString(Formatting.None), "PUT"); - } - - /// - /// Reorder a track or a group of tracks in a playlist. - /// - /// The Spotify ID for the playlist. - /// The position of the first track to be reordered. - /// The position where the tracks should be inserted. - /// The amount of tracks to be reordered. Defaults to 1 if not set. - /// The playlist's snapshot ID against which you want to make the changes. - /// - /// AUTH NEEDED - public Snapshot ReorderPlaylist(string playlistId, int rangeStart, int insertBefore, int rangeLength = 1, string snapshotId = "") - { - JObject body = new JObject - { { "range_start", rangeStart }, { "range_length", rangeLength }, { "insert_before", insertBefore } - }; - if (!string.IsNullOrEmpty(snapshotId)) - body.Add("snapshot_id", snapshotId); - return UploadData(_builder.ReorderPlaylist(playlistId), body.ToString(Formatting.None), "PUT"); - } - - /// - /// Reorder a track or a group of tracks in a playlist asynchronously. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// The position of the first track to be reordered. - /// The position where the tracks should be inserted. - /// The amount of tracks to be reordered. Defaults to 1 if not set. - /// The playlist's snapshot ID against which you want to make the changes. - /// - /// AUTH NEEDED - [Obsolete("Calling ReorderPlaylist with a userId is deprecated, remove the parameter")] - public Task ReorderPlaylistAsync(string userId, string playlistId, int rangeStart, int insertBefore, int rangeLength = 1, string snapshotId = "") - { - JObject body = new JObject - { { "range_start", rangeStart }, { "range_length", rangeLength }, { "insert_before", insertBefore }, { "snapshot_id", snapshotId } - }; - if (!string.IsNullOrEmpty(snapshotId)) - body.Add("snapshot_id", snapshotId); - return UploadDataAsync(_builder.ReorderPlaylist(userId, playlistId), body.ToString(Formatting.None), "PUT"); - } - - /// - /// Reorder a track or a group of tracks in a playlist asynchronously. - /// - /// The Spotify ID for the playlist. - /// The position of the first track to be reordered. - /// The position where the tracks should be inserted. - /// The amount of tracks to be reordered. Defaults to 1 if not set. - /// The playlist's snapshot ID against which you want to make the changes. - /// - /// AUTH NEEDED - public Task ReorderPlaylistAsync(string playlistId, int rangeStart, int insertBefore, int rangeLength = 1, string snapshotId = "") - { - JObject body = new JObject - { { "range_start", rangeStart }, { "range_length", rangeLength }, { "insert_before", insertBefore }, { "snapshot_id", snapshotId } - }; - if (!string.IsNullOrEmpty(snapshotId)) - body.Add("snapshot_id", snapshotId); - return UploadDataAsync(_builder.ReorderPlaylist(playlistId), body.ToString(Formatting.None), "PUT"); - } - - #endregion Playlists - - #region Profiles - - /// - /// Get detailed profile information about the current user (including the current user’s username). - /// - /// - /// AUTH NEEDED - public PrivateProfile GetPrivateProfile() - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPrivateProfile"); - return DownloadData(_builder.GetPrivateProfile()); - } - - /// - /// Get detailed profile information about the current user asynchronously (including the current user’s username). - /// - /// - /// AUTH NEEDED - public Task GetPrivateProfileAsync() - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for GetPrivateProfile"); - return DownloadDataAsync(_builder.GetPrivateProfile()); - } - - /// - /// Get public profile information about a Spotify user. - /// - /// The user's Spotify user ID. - /// - public PublicProfile GetPublicProfile(string userId) - { - return DownloadData(_builder.GetPublicProfile(userId)); - } - - /// - /// Get public profile information about a Spotify user asynchronously. - /// - /// The user's Spotify user ID. - /// - public Task GetPublicProfileAsync(string userId) - { - return DownloadDataAsync(_builder.GetPublicProfile(userId)); - } - - #endregion Profiles - - #region Tracks - - /// - /// Get Spotify catalog information for multiple tracks based on their Spotify IDs. - /// - /// A list of the Spotify IDs for the tracks. Maximum: 50 IDs. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public SeveralTracks GetSeveralTracks(List ids, string market = "") - { - return DownloadData(_builder.GetSeveralTracks(ids, market)); - } - - /// - /// Get Spotify catalog information for multiple tracks based on their Spotify IDs asynchronously. - /// - /// A list of the Spotify IDs for the tracks. Maximum: 50 IDs. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task GetSeveralTracksAsync(List ids, string market = "") - { - return DownloadDataAsync(_builder.GetSeveralTracks(ids, market)); - } - - /// - /// Get Spotify catalog information for a single track identified by its unique Spotify ID. - /// - /// The Spotify ID for the track. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public FullTrack GetTrack(string id, string market = "") - { - return DownloadData(_builder.GetTrack(id, market)); - } - - /// - /// Get Spotify catalog information for a single track identified by its unique Spotify ID asynchronously. - /// - /// The Spotify ID for the track. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task GetTrackAsync(string id, string market = "") - { - return DownloadDataAsync(_builder.GetTrack(id, market)); - } - - /// - /// Get a detailed audio analysis for a single track identified by its unique Spotify ID. - /// - /// The Spotify ID for the track. - /// - /// AUTH NEEDED - public AudioAnalysis GetAudioAnalysis(string id) - { - return DownloadData(_builder.GetAudioAnalysis(id)); - } - - /// - /// Get a detailed audio analysis for a single track identified by its unique Spotify ID asynchronously. - /// - /// The Spotify ID for the track. - /// - /// AUTH NEEDED - public Task GetAudioAnalysisAsync(string id) - { - return DownloadDataAsync(_builder.GetAudioAnalysis(id)); - } - - /// - /// Get audio feature information for a single track identified by its unique Spotify ID. - /// - /// The Spotify ID for the track. - /// - /// AUTH NEEDED - public AudioFeatures GetAudioFeatures(string id) - { - return DownloadData(_builder.GetAudioFeatures(id)); - } - - /// - /// Get audio feature information for a single track identified by its unique Spotify ID asynchronously. - /// - /// The Spotify ID for the track. - /// - /// AUTH NEEDED - public Task GetAudioFeaturesAsync(string id) - { - return DownloadDataAsync(_builder.GetAudioFeatures(id)); - } - - /// - /// Get audio features for multiple tracks based on their Spotify IDs. - /// - /// A list of Spotify Track-IDs. Maximum: 100 IDs. - /// - /// AUTH NEEDED - public SeveralAudioFeatures GetSeveralAudioFeatures(List ids) - { - return DownloadData(_builder.GetSeveralAudioFeatures(ids)); - } - - /// - /// Get audio features for multiple tracks based on their Spotify IDs asynchronously. - /// - /// A list of Spotify Track-IDs. Maximum: 100 IDs. - /// - /// AUTH NEEDED - public Task GetSeveralAudioFeaturesAsync(List ids) - { - return DownloadDataAsync(_builder.GetSeveralAudioFeatures(ids)); - } - - #endregion Tracks - - #region Player - - /// - /// Get information about a user’s available devices. - /// - /// - public AvailabeDevices GetDevices() - { - return DownloadData(_builder.GetDevices()); - } - - /// - /// Get information about a user’s available devices. - /// - /// - public Task GetDevicesAsync() - { - return DownloadDataAsync(_builder.GetDevices()); - } - - /// - /// Get information about the user’s current playback state, including track, track progress, and active device. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public PlaybackContext GetPlayback(string market = "") - { - return DownloadData(_builder.GetPlayback(market)); - } - - /// - /// Get information about the user’s current playback state, including track, track progress, and active device. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task GetPlaybackAsync(string market = "") - { - return DownloadDataAsync(_builder.GetPlayback(market)); - } - - /// - /// Get the object currently being played on the user’s Spotify account. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public PlaybackContext GetPlayingTrack(string market = "") - { - return DownloadData(_builder.GetPlayingTrack(market)); - } - - /// - /// Get the object currently being played on the user’s Spotify account. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public Task GetPlayingTrackAsync(string market = "") - { - return DownloadDataAsync(_builder.GetPlayingTrack(market)); - } - - /// - /// Transfer playback to a new device and determine if it should start playing. - /// - /// ID of the device on which playback should be started/transferred to - /// - /// true: ensure playback happens on new device. - /// false or not provided: keep the current playback state. - /// - /// - public ErrorResponse TransferPlayback(string deviceId, bool play = false) => TransferPlayback( - new List { deviceId }, play); - - /// - /// Transfer playback to a new device and determine if it should start playing. - /// - /// ID of the device on which playback should be started/transferred to - /// - /// true: ensure playback happens on new device. - /// false or not provided: keep the current playback state. - /// - /// - public Task TransferPlaybackAsync(string deviceId, bool play = false) => TransferPlaybackAsync( - new List { deviceId }, play); - - /// - /// Transfer playback to a new device and determine if it should start playing. - /// NOTE: Although an array is accepted, only a single device_id is currently supported. Supplying more than one will return 400 Bad Request - /// - /// A array containing the ID of the device on which playback should be started/transferred. - /// - /// true: ensure playback happens on new device. - /// false or not provided: keep the current playback state. - /// - /// - public ErrorResponse TransferPlayback(List deviceIds, bool play = false) - { - JObject ob = new JObject - { { "play", play }, { "device_ids", new JArray(deviceIds) } - }; - return UploadData(_builder.TransferPlayback(), ob.ToString(Formatting.None), "PUT"); - } - - /// - /// Transfer playback to a new device and determine if it should start playing. - /// NOTE: Although an array is accepted, only a single device_id is currently supported. Supplying more than one will return 400 Bad Request - /// - /// A array containing the ID of the device on which playback should be started/transferred. - /// - /// true: ensure playback happens on new device. - /// false or not provided: keep the current playback state. - /// - /// - public Task TransferPlaybackAsync(List deviceIds, bool play = false) - { - JObject ob = new JObject - { { "play", play }, { "device_ids", new JArray(deviceIds) } - }; - return UploadDataAsync(_builder.TransferPlayback(), ob.ToString(Formatting.None), "PUT"); - } - - /// - /// Start a new context or resume current playback on the user’s active device. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// Spotify URI of the context to play. - /// A JSON array of the Spotify track URIs to play. - /// Indicates from where in the context playback should start. - /// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used. - /// The starting time to seek the track to - /// - public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = "", List uris = null, - int? offset = null, int positionMs = 0) - { - JObject ob = new JObject(); - if (!string.IsNullOrEmpty(contextUri)) - ob.Add("context_uri", contextUri); - if (uris != null) - ob.Add("uris", new JArray(uris)); - if (offset != null) - ob.Add("offset", new JObject { { "position", offset } }); - if (positionMs > 0) - ob.Add("position_ms", positionMs); - return UploadData(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT"); - } - - /// - /// Start a new context or resume current playback on the user’s active device. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// Spotify URI of the context to play. - /// A JSON array of the Spotify track URIs to play. - /// Indicates from where in the context playback should start. - /// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used. - /// The starting time to seek the track to - /// - public Task ResumePlaybackAsync(string deviceId = "", string contextUri = "", List uris = null, - int? offset = null, int positionMs = 0) - { - JObject ob = new JObject(); - if (!string.IsNullOrEmpty(contextUri)) - ob.Add("context_uri", contextUri); - if (uris != null) - ob.Add("uris", new JArray(uris)); - if (offset != null) - ob.Add("offset", new JObject { { "position", offset } }); - if (positionMs > 0) - ob.Add("position_ms", positionMs); - return UploadDataAsync(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT"); - } - - /// - /// Start a new context or resume current playback on the user’s active device. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// Spotify URI of the context to play. - /// A JSON array of the Spotify track URIs to play. - /// Indicates from where in the context playback should start. - /// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used. - /// The starting time to seek the track to - /// - public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = "", List uris = null, - string offset = "", int positionMs = 0) - { - JObject ob = new JObject(); - if (!string.IsNullOrEmpty(contextUri)) - ob.Add("context_uri", contextUri); - if (uris != null) - ob.Add("uris", new JArray(uris)); - if (!string.IsNullOrEmpty(offset)) - ob.Add("offset", new JObject { { "uri", offset } }); - if (positionMs > 0) - ob.Add("position_ms", positionMs); - return UploadData(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT"); - } - - /// - /// Start a new context or resume current playback on the user’s active device. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// Spotify URI of the context to play. - /// A JSON array of the Spotify track URIs to play. - /// Indicates from where in the context playback should start. - /// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used. - /// The starting time to seek the track to - /// - public Task ResumePlaybackAsync(string deviceId = "", string contextUri = "", List uris = null, - string offset = "", int positionMs = 0) - { - JObject ob = new JObject(); - if (!string.IsNullOrEmpty(contextUri)) - ob.Add("context_uri", contextUri); - if (uris != null) - ob.Add("uris", new JArray(uris)); - if (!string.IsNullOrEmpty(offset)) - ob.Add("offset", new JObject { { "uri", offset } }); - if (positionMs > 0) - ob.Add("position_ms", positionMs); - return UploadDataAsync(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT"); - } - - /// - /// Pause playback on the user’s account. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse PausePlayback(string deviceId = "") - { - return UploadData(_builder.PausePlayback(deviceId), string.Empty, "PUT"); - } - - /// - /// Pause playback on the user’s account. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task PausePlaybackAsync(string deviceId = "") - { - return UploadDataAsync(_builder.PausePlayback(deviceId), string.Empty, "PUT"); - } - - /// - /// Skips to next track in the user’s queue. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse SkipPlaybackToNext(string deviceId = "") - { - return UploadData(_builder.SkipPlaybackToNext(deviceId), string.Empty); - } - - /// - /// Skips to next track in the user’s queue. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task SkipPlaybackToNextAsync(string deviceId = "") - { - return UploadDataAsync(_builder.SkipPlaybackToNext(deviceId), string.Empty); - } - - /// - /// Skips to previous track in the user’s queue. - /// Note that this will ALWAYS skip to the previous track, regardless of the current track’s progress. - /// Returning to the start of the current track should be performed using the https://api.spotify.com/v1/me/player/seek endpoint. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse SkipPlaybackToPrevious(string deviceId = "") - { - return UploadData(_builder.SkipPlaybackToPrevious(deviceId), string.Empty); - } - - /// - /// Skips to previous track in the user’s queue. - /// Note that this will ALWAYS skip to the previous track, regardless of the current track’s progress. - /// Returning to the start of the current track should be performed using the https://api.spotify.com/v1/me/player/seek endpoint. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task SkipPlaybackToPreviousAsync(string deviceId = "") - { - return UploadDataAsync(_builder.SkipPlaybackToPrevious(deviceId), string.Empty); - } - - /// - /// Seeks to the given position in the user’s currently playing track. - /// - /// The position in milliseconds to seek to. Must be a positive number. - /// Passing in a position that is greater than the length of the track will cause the player to start playing the next song. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse SeekPlayback(int positionMs, string deviceId = "") - { - return UploadData(_builder.SeekPlayback(positionMs, deviceId), string.Empty, "PUT"); - } - - /// - /// Seeks to the given position in the user’s currently playing track. - /// - /// The position in milliseconds to seek to. Must be a positive number. - /// Passing in a position that is greater than the length of the track will cause the player to start playing the next song. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task SeekPlaybackAsync(int positionMs, string deviceId = "") - { - return UploadDataAsync(_builder.SeekPlayback(positionMs, deviceId), string.Empty, "PUT"); - } - - /// - /// Set the repeat mode for the user’s playback. Options are repeat-track, repeat-context, and off. - /// - /// track, context or off. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse SetRepeatMode(RepeatState state, string deviceId = "") - { - return UploadData(_builder.SetRepeatMode(state, deviceId), string.Empty, "PUT"); - } - - /// - /// Set the repeat mode for the user’s playback. Options are repeat-track, repeat-context, and off. - /// - /// track, context or off. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task SetRepeatModeAsync(RepeatState state, string deviceId = "") - { - return UploadDataAsync(_builder.SetRepeatMode(state, deviceId), string.Empty, "PUT"); - } - - /// - /// Set the volume for the user’s current playback device. - /// - /// Integer. The volume to set. Must be a value from 0 to 100 inclusive. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse SetVolume(int volumePercent, string deviceId = "") - { - return UploadData(_builder.SetVolume(volumePercent, deviceId), string.Empty, "PUT"); - } - - /// - /// Set the volume for the user’s current playback device. - /// - /// Integer. The volume to set. Must be a value from 0 to 100 inclusive. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task SetVolumeAsync(int volumePercent, string deviceId = "") - { - return UploadDataAsync(_builder.SetVolume(volumePercent, deviceId), string.Empty, "PUT"); - } - - /// - /// Toggle shuffle on or off for user’s playback. - /// - /// True or False - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public ErrorResponse SetShuffle(bool shuffle, string deviceId = "") - { - return UploadData(_builder.SetShuffle(shuffle, deviceId), string.Empty, "PUT"); - } - - /// - /// Toggle shuffle on or off for user’s playback. - /// - /// True or False - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public Task SetShuffleAsync(bool shuffle, string deviceId = "") - { - return UploadDataAsync(_builder.SetShuffle(shuffle, deviceId), string.Empty, "PUT"); - } - - /// - /// Add an Item to the User's Playback Queue. BETA - /// - /// The uri of the item to add to the queue. Must be a track or an episode uri. - /// The id of the device this command is targeting. If not supplied, the user’s currently active device is the target. - /// - public ErrorResponse AddToQueue(string uri, string deviceId = "") - { - return UploadData(_builder.AddToQueue(uri, deviceId), string.Empty); - } - - /// - /// Add an Item to the User's Playback Queue. BETA - /// - /// The uri of the item to add to the queue. Must be a track or an episode uri. - /// The id of the device this command is targeting. If not supplied, the user’s currently active device is the target. - /// - public Task AddToQueueAsync(string uri, string deviceId = "") - { - return UploadDataAsync(_builder.AddToQueue(uri, deviceId), string.Empty); - } - - #endregion - - #region Util - - public TOut GetNextPage(Paging paging) where TOut : BasicModel - { - if (!paging.HasNextPage()) - throw new InvalidOperationException("This Paging-Object has no Next-Page"); - return DownloadData(paging.Next); - } - - public TOut GetNextPage(CursorPaging paging) where TOut : BasicModel - { - if (!paging.HasNext()) - throw new InvalidOperationException("This CursorPaging-Object has no Next-Page"); - return DownloadData(paging.Next); - } - - public Paging GetNextPage(Paging paging) - { - return GetNextPage, T>(paging); - } - - public CursorPaging GetNextPage(CursorPaging paging) - { - return GetNextPage, T>(paging); - } - - public Task GetNextPageAsync(Paging paging) where TOut : BasicModel - { - if (!paging.HasNextPage()) - throw new InvalidOperationException("This Paging-Object has no Next-Page"); - return DownloadDataAsync(paging.Next); - } - - public Task GetNextPageAsync(CursorPaging paging) where TOut : BasicModel - { - if (!paging.HasNext()) - throw new InvalidOperationException("This Paging-Object has no Next-Page"); - return DownloadDataAsync(paging.Next); - } - - public Task> GetNextPageAsync(Paging paging) - { - return GetNextPageAsync, T>(paging); - } - - public Task> GetNextPageAsync(CursorPaging paging) - { - return GetNextPageAsync, T>(paging); - } - - public TOut GetPreviousPage(Paging paging) where TOut : BasicModel - { - if (!paging.HasPreviousPage()) - throw new InvalidOperationException("This Paging-Object has no Previous-Page"); - return DownloadData(paging.Previous); - } - - public Paging GetPreviousPage(Paging paging) - { - return GetPreviousPage, T>(paging); - } - - public Task GetPreviousPageAsync(Paging paging) where TOut : BasicModel - { - if (!paging.HasPreviousPage()) - throw new InvalidOperationException("This Paging-Object has no Previous-Page"); - return DownloadDataAsync(paging.Previous); - } - - public Task> GetPreviousPageAsync(Paging paging) - { - return GetPreviousPageAsync, T>(paging); - } - - private ListResponse DownloadList(string url) - { - int triesLeft = RetryTimes + 1; - Error lastError; - - ListResponse data = null; - do - { - if (data != null) { Thread.Sleep(RetryAfter); } - Tuple res = DownloadDataAlt(url); - data = ExtractDataToListResponse(res); - - lastError = data.Error; - - triesLeft -= 1; - - } while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status)); - - return data; - } - - private async Task> DownloadListAsync(string url) - { - int triesLeft = RetryTimes + 1; - Error lastError; - - ListResponse data = null; - do - { - if (data != null) { await Task.Delay(RetryAfter).ConfigureAwait(false); } - Tuple res = await DownloadDataAltAsync(url).ConfigureAwait(false); - data = ExtractDataToListResponse(res); - - lastError = data.Error; - - triesLeft -= 1; - - } while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status)); - - return data; - } - - private static ListResponse ExtractDataToListResponse(Tuple res) - { - ListResponse ret; - if (res.Item2 is JArray) - { - ret = new ListResponse - { - List = res.Item2.ToObject>(), - Error = null - }; - } - else - { - ret = new ListResponse - { - List = null, - Error = res.Item2["error"].ToObject() - }; - } - ret.AddResponseInfo(res.Item1); - return ret; - } - - public T UploadData(string url, string uploadData, string method = "POST") where T : BasicModel - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for all Upload-Actions"); - int triesLeft = RetryTimes + 1; - Error lastError; - - Tuple response = null; - do - { - Dictionary headers = new Dictionary - { { "Authorization", TokenType + " " + AccessToken }, - { "Content-Type", "application/json" } - }; - - if (response != null) { Thread.Sleep(RetryAfter); } - response = WebClient.UploadJson(url, uploadData, method, headers); - - response.Item2.AddResponseInfo(response.Item1); - lastError = response.Item2.Error; - triesLeft -= 1; - - } while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status)); - - return response.Item2; - } - - public async Task UploadDataAsync(string url, string uploadData, string method = "POST") where T : BasicModel - { - if (!UseAuth) - throw new InvalidOperationException("Auth is required for all Upload-Actions"); - - int triesLeft = RetryTimes + 1; - Error lastError; - - Tuple response = null; - do - { - Dictionary headers = new Dictionary - { { "Authorization", TokenType + " " + AccessToken }, - { "Content-Type", "application/json" } - }; - - if (response != null) { await Task.Delay(RetryAfter).ConfigureAwait(false); } - response = await WebClient.UploadJsonAsync(url, uploadData, method, headers).ConfigureAwait(false); - - response.Item2.AddResponseInfo(response.Item1); - lastError = response.Item2.Error; - - triesLeft -= 1; - - } while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status)); - - return response.Item2; - } - - public T DownloadData(string url) where T : BasicModel - { - int triesLeft = RetryTimes + 1; - Error lastError; - - Tuple response = null; - do - { - if (response != null) { Thread.Sleep(RetryAfter); } - response = DownloadDataAlt(url); - - response.Item2.AddResponseInfo(response.Item1); - lastError = response.Item2.Error; - - triesLeft -= 1; - - } while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status)); - - return response.Item2; - } - - /// - /// Retrieves whether request had a "TooManyRequests" error, and get the amount Spotify recommends waiting before another request. - /// - /// Info object to analyze. - /// Seconds to wait before making another request. -1 if no error. - /// AUTH NEEDED - private int GetTooManyRequests(ResponseInfo info) - { - // 429 is "TooManyRequests" value specified in Spotify API - if (429 != (int)info.StatusCode) - { - return -1; - } - if (!int.TryParse(info.Headers.Get("Retry-After"), out int secondsToWait)) - { - return -1; - } - return secondsToWait; - } - - public async Task DownloadDataAsync(string url) where T : BasicModel - { - int triesLeft = RetryTimes + 1; - Error lastError; - - Tuple response = null; - do - { - if (response != null) - { - int msToWait = RetryAfter; - int secondsToWait = GetTooManyRequests(response.Item1); - if (secondsToWait > 0) - { - msToWait = secondsToWait * 1000; - } - await Task.Delay(msToWait).ConfigureAwait(false); - } - response = await DownloadDataAltAsync(url).ConfigureAwait(false); - - response.Item2.AddResponseInfo(response.Item1); - lastError = response.Item2.Error; - - if (TooManyRequestsConsumesARetry || GetTooManyRequests(response.Item1) == -1) - { - triesLeft -= 1; - } - - } while (UseAutoRetry && - triesLeft > 0 && - (GetTooManyRequests(response.Item1) != -1 || - lastError != null && RetryErrorCodes.Contains(lastError.Status))); - - return response.Item2; - } - - private Tuple DownloadDataAlt(string url) - { - Dictionary headers = new Dictionary(); - if (UseAuth) - headers.Add("Authorization", TokenType + " " + AccessToken); - return WebClient.DownloadJson(url, headers); - } - - private Task> DownloadDataAltAsync(string url) - { - Dictionary headers = new Dictionary(); - if (UseAuth) - headers.Add("Authorization", TokenType + " " + AccessToken); - return WebClient.DownloadJsonAsync(url, headers); - } - - #endregion Util - } -} diff --git a/SpotifyAPI.Web/SpotifyWebBuilder.cs b/SpotifyAPI.Web/SpotifyWebBuilder.cs deleted file mode 100644 index 120abef1..00000000 --- a/SpotifyAPI.Web/SpotifyWebBuilder.cs +++ /dev/null @@ -1,1135 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using SpotifyAPI.Web.Enums; -using SpotifyAPI.Web.Models; - -namespace SpotifyAPI.Web -{ - /// - /// SpotifyAPI URL-Generator - /// - public class SpotifyWebBuilder - { - public const string APIBase = "https://api.spotify.com/v1"; - - #region Search - - /// - /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string. - /// - /// The search query's keywords (and optional field filters and operators), for example q=roadhouse+blues. - /// A list of item types to search across. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first result to return. Default: 0 - /// An ISO 3166-1 alpha-2 country code or the string from_token. - /// - public string SearchItems(string q, SearchType type, int limit = 20, int offset = 0, string market = "") - { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder(APIBase + "/search"); - builder.Append("?q=" + q); - builder.Append("&type=" + type.GetStringAttribute(",")); - builder.Append("&limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - #endregion Search - - #region Albums - - /// - /// Get Spotify catalog information about an album’s tracks. Optional parameters can be used to limit the number of - /// tracks returned. - /// - /// The Spotify ID for the album. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first track to return. Default: 0 (the first object). - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetAlbumTracks(string id, int limit = 20, int offset = 0, string market = "") - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/albums/" + id + "/tracks"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Get Spotify catalog information for a single album. - /// - /// The Spotify ID for the album. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetAlbum(string id, string market = "") - { - return string.IsNullOrEmpty(market) ? $"{APIBase}/albums/{id}" : $"{APIBase}/albums/{id}?market={market}"; - } - - /// - /// Get Spotify catalog information for multiple albums identified by their Spotify IDs. - /// - /// A list of the Spotify IDs for the albums. Maximum: 20 IDs. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetSeveralAlbums(List ids, string market = "") - { - return string.IsNullOrEmpty(market) ? - $"{APIBase}/albums?ids={string.Join(",", ids.Take(20))}" : - $"{APIBase}/albums?market={market}&ids={string.Join(",", ids.Take(20))}"; - } - - #endregion Albums - - #region Artists - - /// - /// Get Spotify catalog information for a single artist identified by their unique Spotify ID. - /// - /// The Spotify ID for the artist. - /// - public string GetArtist(string id) - { - return $"{APIBase}/artists/{id}"; - } - - /// - /// Get Spotify catalog information about artists similar to a given artist. Similarity is based on analysis of the - /// Spotify community’s listening history. - /// - /// The Spotify ID for the artist. - /// - public string GetRelatedArtists(string id) - { - return $"{APIBase}/artists/{id}/related-artists"; - } - - /// - /// Get Spotify catalog information about an artist’s top tracks by country. - /// - /// The Spotify ID for the artist. - /// The country: an ISO 3166-1 alpha-2 country code. - /// - public string GetArtistsTopTracks(string id, string country) - { - return $"{APIBase}/artists/{id}/top-tracks?country={country}"; - } - - /// - /// Get Spotify catalog information about an artist’s albums. Optional parameters can be specified in the query string - /// to filter and sort the response. - /// - /// The Spotify ID for the artist. - /// - /// A list of keywords that will be used to filter the response. If not supplied, all album types will - /// be returned - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first album to return. Default: 0 - /// - /// An ISO 3166-1 alpha-2 country code. Supply this parameter to limit the response to one particular - /// geographical market - /// - /// - public string GetArtistsAlbums(string id, AlbumType type = AlbumType.All, int limit = 20, int offset = 0, string market = "") - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/artists/" + id + "/albums"); - builder.Append("?album_type=" + type.GetStringAttribute(",")); - builder.Append("&limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Get Spotify catalog information for several artists based on their Spotify IDs. - /// - /// A list of the Spotify IDs for the artists. Maximum: 50 IDs. - /// - public string GetSeveralArtists(List ids) - { - return $"{APIBase}/artists?ids={string.Join(",", ids.Take(50))}"; - } - - #endregion Artists - - #region Browse - - /// - /// Get a list of Spotify featured playlists (shown, for example, on a Spotify player’s “Browse” tab). - /// - /// - /// The desired language, consisting of a lowercase ISO 639 language code and an uppercase ISO 3166-1 - /// alpha-2 country code, joined by an underscore. - /// - /// A country: an ISO 3166-1 alpha-2 country code. - /// A timestamp in ISO 8601 format - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// AUTH NEEDED - public string GetFeaturedPlaylists(string locale = "", string country = "", DateTime timestamp = default(DateTime), int limit = 20, int offset = 0) - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/browse/featured-playlists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(locale)) - builder.Append("&locale=" + locale); - if (!string.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - if (timestamp != default(DateTime)) - builder.Append("×tamp=" + timestamp.ToString("yyyy-MM-ddTHH:mm:ss")); - return builder.ToString(); - } - - /// - /// Get a list of new album releases featured in Spotify (shown, for example, on a Spotify player’s “Browse” tab). - /// - /// A country: an ISO 3166-1 alpha-2 country code. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// - /// AUTH NEEDED - public string GetNewAlbumReleases(string country = "", int limit = 20, int offset = 0) - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/browse/new-releases"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - return builder.ToString(); - } - - /// - /// Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab). - /// - /// - /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want to narrow the - /// list of returned categories to those relevant to a particular country - /// - /// - /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country - /// code, joined by an underscore - /// - /// The maximum number of categories to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 (the first object). - /// - /// AUTH NEEDED - public string GetCategories(string country = "", string locale = "", int limit = 20, int offset = 0) - { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder(APIBase + "/browse/categories"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - if (!string.IsNullOrEmpty(locale)) - builder.Append("&locale=" + locale); - return builder.ToString(); - } - - /// - /// Get a single category used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab). - /// - /// The Spotify category ID for the category. - /// - /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter to ensure that the category - /// exists for a particular country. - /// - /// - /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country - /// code, joined by an underscore - /// - /// - /// AUTH NEEDED - public string GetCategory(string categoryId, string country = "", string locale = "") - { - StringBuilder builder = new StringBuilder(APIBase + "/browse/categories/" + categoryId); - if (!string.IsNullOrEmpty(country)) - builder.Append("?country=" + country); - if (!string.IsNullOrEmpty(locale)) - builder.Append((country == "" ? "?locale=" : "&locale=") + locale); - return builder.ToString(); - } - - /// - /// Get a list of Spotify playlists tagged with a particular category. - /// - /// The Spotify category ID for the category. - /// A country: an ISO 3166-1 alpha-2 country code. - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first item to return. Default: 0 - /// - /// AUTH NEEDED - public string GetCategoryPlaylists(string categoryId, string country = "", int limit = 20, int offset = 0) - { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder(APIBase + "/browse/categories/" + categoryId + "/playlists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - return builder.ToString(); - } - - /// - /// Create a playlist-style listening experience based on seed artists, tracks and genres. - /// - /// A comma separated list of Spotify IDs for seed artists. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// A comma separated list of any genres in the set of available genre seeds. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// A comma separated list of Spotify IDs for a seed track. - /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. - /// - /// Tracks with the attribute values nearest to the target values will be preferred. - /// For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided - /// For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided - /// The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100. - /// For seeds with unusually small pools or when highly restrictive filtering is applied, it may be impossible to generate the requested number of recommended tracks. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// Because min_*, max_* and target_* are applied to pools before relinking, the generated results may not precisely match the filters applied. - /// - /// AUTH NEEDED - public string GetRecommendations(List artistSeed = null, List genreSeed = null, List trackSeed = null, - TuneableTrack target = null, TuneableTrack min = null, TuneableTrack max = null, int limit = 20, string market = "") - { - limit = Math.Min(100, limit); - StringBuilder builder = new StringBuilder($"{APIBase}/recommendations"); - builder.Append("?limit=" + limit); - if (artistSeed?.Count > 0) - builder.Append("&seed_artists=" + string.Join(",", artistSeed)); - if (genreSeed?.Count > 0) - builder.Append("&seed_genres=" + string.Join(",", genreSeed)); - if (trackSeed?.Count > 0) - builder.Append("&seed_tracks=" + string.Join(",", trackSeed)); - if (target != null) - builder.Append(target.BuildUrlParams("target")); - if (min != null) - builder.Append(min.BuildUrlParams("min")); - if (max != null) - builder.Append(max.BuildUrlParams("max")); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Retrieve a list of available genres seed parameter values for recommendations. - /// - /// - /// AUTH NEEDED - public string GetRecommendationSeedsGenres() - { - return $"{APIBase}/recommendations/available-genre-seeds"; - } - - #endregion Browse - - #region Follow - - /// - /// Get the current user’s followed artists. - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// The last artist ID retrieved from the previous request. - /// - /// AUTH NEEDED - public string GetFollowedArtists(int limit = 20, string after = "") - { - limit = Math.Min(limit, 50); - const FollowType followType = FollowType.Artist; //currently only artist is supported. - StringBuilder builder = new StringBuilder(APIBase + "/me/following?type=" + followType.GetStringAttribute()); - builder.Append("&limit=" + limit); - if (!string.IsNullOrEmpty(after)) - builder.Append("&after=" + after); - return builder.ToString(); - } - - /// - /// Add the current user as a follower of one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// - /// AUTH NEEDED - public string Follow(FollowType followType) - { - return $"{APIBase}/me/following?type={followType.GetStringAttribute()}"; - } - - /// - /// Remove the current user as a follower of one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// - /// AUTH NEEDED - public string Unfollow(FollowType followType) - { - return $"{APIBase}/me/following?type={followType.GetStringAttribute()}"; - } - - /// - /// Check to see if the current user is following one or more artists or other Spotify users. - /// - /// The ID type: either artist or user. - /// A list of the artist or the user Spotify IDs to check - /// - /// AUTH NEEDED - public string IsFollowing(FollowType followType, List ids) - { - return $"{APIBase}/me/following/contains?type={followType.GetStringAttribute()}&ids={string.Join(",", ids)}"; - } - - /// - /// Add the current user as a follower of a playlist. - /// - /// - /// The Spotify ID of the playlist. Any playlist can be followed, regardless of its public/private - /// status, as long as you know its playlist ID. - /// - /// - /// AUTH NEEDED - public string FollowPlaylist(string playlistId) - { - return $"{APIBase}/playlists/{playlistId}/followers"; - } - - /// - /// Remove the current user as a follower of a playlist. - /// - /// The Spotify ID of the playlist that is to be no longer followed. - /// - /// AUTH NEEDED - public string UnfollowPlaylist(string playlistId) - { - return $"{APIBase}/playlists/{playlistId}/followers"; - } - - /// - /// Check to see if one or more Spotify users are following a specified playlist. - /// - /// The Spotify ID of the playlist. - /// A list of Spotify User IDs - /// - /// AUTH NEEDED - public string IsFollowingPlaylist(string playlistId, List ids) - { - return $"{APIBase}/playlists/{playlistId}/followers/contains?ids={string.Join(",", ids)}"; - } - - #endregion Follow - - #region Library - - /// - /// Save one or more tracks to the current user’s “Your Music” library. - /// - /// - /// AUTH NEEDED - public string SaveTracks() - { - return APIBase + "/me/tracks/"; - } - - /// - /// Get a list of the songs saved in the current Spotify user’s “Your Music” library. - /// - /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public string GetSavedTracks(int limit = 20, int offset = 0, string market = "") - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/me/tracks"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Remove one or more tracks from the current user’s “Your Music” library. - /// - /// - /// AUTH NEEDED - public string RemoveSavedTracks() - { - return APIBase + "/me/tracks/"; - } - - /// - /// Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public string CheckSavedTracks(List ids) - { - return APIBase + "/me/tracks/contains?ids=" + string.Join(",", ids); - } - - /// - /// Save one or more albums to the current user’s "Your Music" library. - /// - /// - /// AUTH NEEDED - public string SaveAlbums() - { - return $"{APIBase}/me/albums"; - } - - /// - /// Get a list of the albums saved in the current Spotify user’s "Your Music" library. - /// - /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public string GetSavedAlbums(int limit = 20, int offset = 0, string market = "") - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/me/albums"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Remove one or more albums from the current user’s "Your Music" library. - /// - /// - /// AUTH NEEDED - public string RemoveSavedAlbums() - { - return APIBase + "/me/albums/"; - } - - /// - /// Check if one or more albums is already saved in the current Spotify user’s "Your Music" library. - /// - /// A list of the Spotify IDs. - /// - /// AUTH NEEDED - public string CheckSavedAlbums(List ids) - { - return APIBase + "/me/albums/contains?ids=" + string.Join(",", ids); - } - - #endregion Library - - #region Personalization - - /// - /// Get the current user’s top tracks based on calculated affinity. - /// - /// Over what time frame the affinities are computed. - /// Valid values: long_term (calculated from several years of data and including all new data as it becomes available), - /// medium_term (approximately last 6 months), short_term (approximately last 4 weeks). - /// The number of entities to return. Default: 20. Minimum: 1. Maximum: 50 - /// The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities. - /// - /// AUTH NEEDED - public string GetUsersTopTracks(TimeRangeType timeRange = TimeRangeType.MediumTerm, int limit = 20, int offest = 0) - { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder($"{APIBase}/me/top/tracks"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offest); - builder.Append("&time_range=" + timeRange.GetStringAttribute()); - return builder.ToString(); - } - - /// - /// Get the current user’s top artists based on calculated affinity. - /// - /// Over what time frame the affinities are computed. - /// Valid values: long_term (calculated from several years of data and including all new data as it becomes available), - /// medium_term (approximately last 6 months), short_term (approximately last 4 weeks). - /// The number of entities to return. Default: 20. Minimum: 1. Maximum: 50 - /// The index of the first entity to return. Default: 0 (i.e., the first track). Use with limit to get the next set of entities. - /// - /// AUTH NEEDED - public string GetUsersTopArtists(TimeRangeType timeRange = TimeRangeType.MediumTerm, int limit = 20, int offest = 0) - { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder($"{APIBase}/me/top/artists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offest); - builder.Append("&time_range=" + timeRange.GetStringAttribute()); - return builder.ToString(); - } - - /// - /// Get tracks from the current user’s recent play history. - /// - /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. - /// A Unix timestamp in milliseconds. Returns all items after (but not including) this cursor position. If after is specified, before must not be specified. - /// A Unix timestamp in milliseconds. Returns all items before (but not including) this cursor position. If before is specified, after must not be specified. - /// - /// AUTH NEEDED - public string GetUsersRecentlyPlayedTracks(int limit = 20, DateTime? after = null, DateTime? before = null) - { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder($"{APIBase}/me/player/recently-played"); - builder.Append("?limit=" + limit); - if (after.HasValue) - builder.Append("&after=" + after.Value.ToUnixTimeMillisecondsPoly()); - if (before.HasValue) - builder.Append("&before=" + before.Value.ToUnixTimeMillisecondsPoly()); - return builder.ToString(); - } - - #endregion - - #region Playlists - - /// - /// Get a list of the playlists owned or followed by a Spotify user. - /// - /// The user's Spotify user ID. - /// The maximum number of playlists to return. Default: 20. Minimum: 1. Maximum: 50. - /// The index of the first playlist to return. Default: 0 (the first object) - /// - /// AUTH NEEDED - public string GetUserPlaylists(string userId, int limit = 20, int offset = 0) - { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/users/" + userId + "/playlists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - return builder.ToString(); - } - - /// - /// Get a playlist owned by a Spotify user. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public string GetPlaylist(string userId, string playlistId, string fields = "", string market = "") - { - StringBuilder builder = new StringBuilder(APIBase + "/users/" + userId + "/playlists/" + playlistId); - builder.Append("?fields=" + fields); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Get a playlist owned by a Spotify user. - /// - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public string GetPlaylist(string playlistId, string fields = "", string market = "") - { - StringBuilder builder = new StringBuilder(APIBase + "/playlists/" + playlistId); - builder.Append("?fields=" + fields); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Get full details of the tracks of a playlist owned by a Spotify user. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public string GetPlaylistTracks(string userId, string playlistId, string fields = "", int limit = 100, int offset = 0, string market = "") - { - limit = Math.Min(limit, 100); - StringBuilder builder = new StringBuilder(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks"); - builder.Append("?fields=" + fields); - builder.Append("&limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Get full details of the tracks of a playlist owned by a Spotify user. - /// - /// The Spotify ID for the playlist. - /// - /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are - /// returned. - /// - /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. - /// The index of the first object to return. Default: 0 (i.e., the first object) - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - /// AUTH NEEDED - public string GetPlaylistTracks(string playlistId, string fields = "", int limit = 100, int offset = 0, string market = "") - { - limit = Math.Min(limit, 100); - StringBuilder builder = new StringBuilder(APIBase + "/playlists/" + playlistId + "/tracks"); - builder.Append("?fields=" + fields); - builder.Append("&limit=" + limit); - builder.Append("&offset=" + offset); - if (!string.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return builder.ToString(); - } - - /// - /// Create a playlist for a Spotify user. (The playlist will be empty until you add tracks.) - /// - /// The user's Spotify user ID. - /// - /// The name for the new playlist, for example "Your Coolest Playlist". This name does not need - /// to be unique. - /// - /// - /// default true. If true the playlist will be public, if false it will be private. To be able to - /// create private playlists, the user must have granted the playlist-modify-private scope. - /// - /// - /// AUTH NEEDED - public string CreatePlaylist(string userId, string playlistName, bool isPublic = true) - { - return $"{APIBase}/users/{userId}/playlists"; - } - - /// - /// Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string UpdatePlaylist(string userId, string playlistId) - { - return $"{APIBase}/users/{userId}/playlists/{playlistId}"; - } - - /// - /// Change a playlist’s name and public/private state. (The user must, of course, own the playlist.) - /// - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string UpdatePlaylist(string playlistId) - { - return $"{APIBase}/playlists/{playlistId}"; - } - - /// - /// Replace all the tracks in a playlist, overwriting its existing tracks. This powerful request can be useful for - /// replacing tracks, re-ordering existing tracks, or clearing the playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string ReplacePlaylistTracks(string userId, string playlistId) - { - return $"{APIBase}/users/{userId}/playlists/{playlistId}/tracks"; - } - - /// - /// Replace all the tracks in a playlist, overwriting its existing tracks. This powerful request can be useful for - /// replacing tracks, re-ordering existing tracks, or clearing the playlist. - /// - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string ReplacePlaylistTracks(string playlistId) - { - return $"{APIBase}/playlists/{playlistId}/tracks"; - } - - /// - /// Remove one or more tracks from a user’s playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of - /// 100 objects can be sent at once. - /// - /// - /// AUTH NEEDED - public string RemovePlaylistTracks(string userId, string playlistId, List uris) - { - return $"{APIBase}/users/{userId}/playlists/{playlistId}/tracks"; - } - - /// - /// Remove one or more tracks from a user’s playlist. - /// - /// The Spotify ID for the playlist. - /// - /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of - /// 100 objects can be sent at once. - /// - /// - /// AUTH NEEDED - public string RemovePlaylistTracks(string playlistId, List uris) - { - return $"{APIBase}/playlists/{playlistId}/tracks"; - } - - /// - /// Add one or more tracks to a user’s playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to add - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - public string AddPlaylistTracks(string userId, string playlistId, List uris, int? position = null) - { - return position == null ? - $"{APIBase}/users/{userId}/playlists/{playlistId}/tracks" : - $"{APIBase}/users/{userId}/playlists/{playlistId}/tracks?position={position}"; - } - - /// - /// Add one or more tracks to a user’s playlist. - /// - /// The Spotify ID for the playlist. - /// A list of Spotify track URIs to add - /// The position to insert the tracks, a zero-based index - /// - /// AUTH NEEDED - public string AddPlaylistTracks(string playlistId, List uris, int? position = null) - { - return position == null ? - $"{APIBase}/playlists/{playlistId}/tracks" : - $"{APIBase}/playlists/{playlistId}/tracks?position={position}"; - } - - /// - /// Reorder a track or a group of tracks in a playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string ReorderPlaylist(string userId, string playlistId) - { - return $"{APIBase}/users/{userId}/playlists/{playlistId}/tracks"; - } - - /// - /// Reorder a track or a group of tracks in a playlist. - /// - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string ReorderPlaylist(string playlistId) - { - return $"{APIBase}/playlists/{playlistId}/tracks"; - } - - /// - /// Upload an image for a playlist. - /// - /// The user's Spotify user ID. - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string UploadPlaylistImage(string userId, string playlistId) - { - return $"{APIBase}/users/{userId}/playlists/{playlistId}/images"; - } - - /// - /// Upload an image for a playlist. - /// - /// The Spotify ID for the playlist. - /// - /// AUTH NEEDED - public string UploadPlaylistImage(string playlistId) - { - return $"{APIBase}/playlists/{playlistId}/images"; - } - - #endregion Playlists - - #region Profiles - - /// - /// Get detailed profile information about the current user (including the current user’s username). - /// - /// - /// AUTH NEEDED - public string GetPrivateProfile() - { - return $"{APIBase}/me"; - } - - /// - /// Get public profile information about a Spotify user. - /// - /// The user's Spotify user ID. - /// - public string GetPublicProfile(string userId) - { - return $"{APIBase}/users/{userId}"; - } - - #endregion Profiles - - #region Tracks - - /// - /// Get Spotify catalog information for multiple tracks based on their Spotify IDs. - /// - /// A list of the Spotify IDs for the tracks. Maximum: 50 IDs. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetSeveralTracks(List ids, string market = "") - { - return string.IsNullOrEmpty(market) ? - $"{APIBase}/tracks?ids={string.Join(",", ids.Take(50))}" : - $"{APIBase}/tracks?market={market}&ids={string.Join(",", ids.Take(50))}"; - } - - /// - /// Get Spotify catalog information for a single track identified by its unique Spotify ID. - /// - /// The Spotify ID for the track. - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetTrack(string id, string market = "") - { - return string.IsNullOrEmpty(market) ? $"{APIBase}/tracks/{id}" : $"{APIBase}/tracks/{id}?market={market}"; - } - - /// - /// Get a detailed audio analysis for a single track identified by its unique Spotify ID. - /// - /// The Spotify ID for the track. - /// - /// AUTH NEEDED - public string GetAudioAnalysis(string id) - { - return $"{APIBase}/audio-analysis/{id}"; - } - - /// - /// Get audio feature information for a single track identified by its unique Spotify ID. - /// - /// The Spotify ID for the track. - /// - /// AUTH NEEDED - public string GetAudioFeatures(string id) - { - return $"{APIBase}/audio-features/{id}"; - } - - /// - /// Get audio features for multiple tracks based on their Spotify IDs. - /// - /// A list of Spotify Track-IDs. Maximum: 100 IDs. - /// - /// AUTH NEEDED - public string GetSeveralAudioFeatures(List ids) - { - return $"{APIBase}/audio-features?ids={string.Join(",", ids.Take(100))}"; - } - - #endregion Tracks - - #region Player - - /// - /// Get information about a user’s available devices. - /// - /// - public string GetDevices() - { - return $"{APIBase}/me/player/devices"; - } - - /// - /// Get information about the user’s current playback state, including track, track progress, and active device. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetPlayback(string market = "") - { - return string.IsNullOrEmpty(market) ? $"{APIBase}/me/player" : $"{APIBase}/me/player?market={market}"; - } - - /// - /// Get the object currently being played on the user’s Spotify account. - /// - /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. - /// - public string GetPlayingTrack(string market = "") - { - return string.IsNullOrEmpty(market) ? - $"{APIBase}/me/player/currently-playing" : - $"{APIBase}/me/player/currently-playing?market={market}"; - } - - /// - /// Transfer playback to a new device and determine if it should start playing. - /// - /// - public string TransferPlayback() - { - return $"{APIBase}/me/player"; - } - - /// - /// Start a new context or resume current playback on the user’s active device. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string ResumePlayback(string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/play" : - $"{APIBase}/me/player/play?device_id={deviceId}"; - } - - /// - /// Pause playback on the user’s account. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string PausePlayback(string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/pause" : - $"{APIBase}/me/player/pause?device_id={deviceId}"; - } - - /// - /// Skips to next track in the user’s queue. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string SkipPlaybackToNext(string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/next" : - $"{APIBase}/me/player/next?device_id={deviceId}"; - } - - /// - /// Skips to previous track in the user’s queue. - /// Note that this will ALWAYS skip to the previous track, regardless of the current track’s progress. - /// Returning to the start of the current track should be performed using the https://api.spotify.com/v1/me/player/seek endpoint. - /// - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string SkipPlaybackToPrevious(string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/previous" : - $"{APIBase}/me/player/previous?device_id={deviceId}"; - } - - /// - /// Seeks to the given position in the user’s currently playing track. - /// - /// The position in milliseconds to seek to. Must be a positive number. - /// Passing in a position that is greater than the length of the track will cause the player to start playing the next song. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string SeekPlayback(int positionMs, string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/seek?position_ms={positionMs}" : - $"{APIBase}/me/player/seek?position_ms={positionMs}&device_id={deviceId}"; - } - - /// - /// Set the repeat mode for the user’s playback. Options are repeat-track, repeat-context, and off. - /// - /// track, context or off. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string SetRepeatMode(RepeatState repeatState, string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/repeat?state={repeatState.GetStringAttribute()}" : - $"{APIBase}/me/player/repeat?state={repeatState.GetStringAttribute()}&device_id={deviceId}"; - } - - /// - /// Set the volume for the user’s current playback device. - /// - /// Integer. The volume to set. Must be a value from 0 to 100 inclusive. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string SetVolume(int volumePercent, string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/volume?volume_percent={volumePercent}" : - $"{APIBase}/me/player/volume?volume_percent={volumePercent}&device_id={deviceId}"; - } - - /// - /// Toggle shuffle on or off for user’s playback. - /// - /// True of False. - /// The id of the device this command is targeting. If not supplied, the user's currently active device is the target. - /// - public string SetShuffle(bool shuffle, string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/shuffle?state={shuffle}" : - $"{APIBase}/me/player/shuffle?state={shuffle}&device_id={deviceId}"; - } - - /// - /// Add an Item to the User's Playback Queue. - /// - /// The uri of the item to add to the queue. Must be a track or an episode uri. - /// The id of the device this command is targeting. If not supplied, the user’s currently active device is the target. - /// - public string AddToQueue(string uri, string deviceId = "") - { - return string.IsNullOrEmpty(deviceId) ? - $"{APIBase}/me/player/queue?uri={uri}" : - $"{APIBase}/me/player/queue?uri={uri}&device_id={deviceId}"; - } - #endregion - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/SpotifyWebClient.cs b/SpotifyAPI.Web/SpotifyWebClient.cs deleted file mode 100644 index 488cecd5..00000000 --- a/SpotifyAPI.Web/SpotifyWebClient.cs +++ /dev/null @@ -1,205 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -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 - { - 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); - } - } - } -} \ No newline at end of file diff --git a/SpotifyAPI.Web/Util/Ensure.cs b/SpotifyAPI.Web/Util/Ensure.cs new file mode 100644 index 00000000..e162b9cb --- /dev/null +++ b/SpotifyAPI.Web/Util/Ensure.cs @@ -0,0 +1,34 @@ +using System; + +namespace SpotifyAPI.Web +{ + /// + /// Ensure input parameters + /// + internal static class Ensure + { + /// + /// Checks an argument to ensure it isn't null. + /// + /// The argument value to check + /// The name of the argument + public static void ArgumentNotNull(object value, string name) + { + if (value != null) return; + + throw new ArgumentNullException(name); + } + + /// + /// Checks an argument to ensure it isn't null or an empty string + /// + /// The argument value to check + /// The name of the argument + public static void ArgumentNotNullOrEmptyString(string value, string name) + { + if (!string.IsNullOrEmpty(value)) return; + + throw new ArgumentException("String is empty or null", name); + } + } +} diff --git a/SpotifyAPI.Web/Util/URIExtension.cs b/SpotifyAPI.Web/Util/URIExtension.cs new file mode 100644 index 00000000..1a443a90 --- /dev/null +++ b/SpotifyAPI.Web/Util/URIExtension.cs @@ -0,0 +1,40 @@ +using System.Web; +using System.Linq; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace SpotifyAPI.Web +{ + public static class URIExtensions + { + public static Uri ApplyParameters(this Uri uri, IDictionary parameters) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + if (parameters == null || !parameters.Any()) + { + return uri; + } + + var newParameters = new Dictionary(); + NameValueCollection existingParameters = HttpUtility.ParseQueryString(uri.Query); + foreach (string key in existingParameters.AllKeys) + { + newParameters.Add(key, existingParameters[key]); + } + foreach (KeyValuePair parameter in parameters) + { + newParameters.Add(parameter.Key, HttpUtility.UrlEncode(parameter.Value)); + } + + var queryString = String.Join("&", newParameters.Select((parameter) => $"{parameter.Key}={parameter.Value}")); + var query = string.IsNullOrEmpty(queryString) ? null : $"?{queryString}"; + + var uriBuilder = new UriBuilder(uri); + uriBuilder.Query = query; + + return uriBuilder.Uri; + } + } +} diff --git a/SpotifyAPI.Web/Util/URIParameterFormatProvider.cs b/SpotifyAPI.Web/Util/URIParameterFormatProvider.cs new file mode 100644 index 00000000..1686f3c5 --- /dev/null +++ b/SpotifyAPI.Web/Util/URIParameterFormatProvider.cs @@ -0,0 +1,29 @@ +using System.Web; +using System; +namespace SpotifyAPI.Web +{ + public class URIParameterFormatProvider : IFormatProvider + { + private readonly URIParameterFormatter _formatter; + + public URIParameterFormatProvider() + { + _formatter = new URIParameterFormatter(); + } + + public object GetFormat(Type formatType) + { + if (formatType == typeof(ICustomFormatter)) + return _formatter; + return null; + } + + class URIParameterFormatter : ICustomFormatter + { + public string Format(string format, object arg, IFormatProvider formatProvider) + { + return HttpUtility.UrlEncode(arg.ToString()); + } + } + } +}