From 49cfa00c30b1784e76889a95d4b6022e511659b4 Mon Sep 17 00:00:00 2001 From: Akshay Srinivasan <35820570+akshays2112@users.noreply.github.com> Date: Fri, 16 Oct 2020 15:49:52 +0530 Subject: [PATCH 1/5] Completed PlaylistsApi.RemoveItems. Due to HttpClient.Delete not supporting any payload content I have added a method for Delete that uses HttpClient.SendAsync to SpotifyWebApi.cs. --- .../PlaylistsTests.cs | 39 +++++++++++++ .../TracksApiTests.cs | 6 +- .../Models/PlaylistRemoveItemsPayloadData.cs | 56 +++++++++++++++++++ src/SpotifyApi.NetCore/PlaylistsApi.cs | 29 ++++++++-- src/SpotifyApi.NetCore/SpotifyWebApi.cs | 48 ++++++++++++++++ 5 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 src/SpotifyApi.NetCore/Models/PlaylistRemoveItemsPayloadData.cs diff --git a/src/SpotifyApi.NetCore.Tests/PlaylistsTests.cs b/src/SpotifyApi.NetCore.Tests/PlaylistsTests.cs index 46eacc1..c4c7b64 100644 --- a/src/SpotifyApi.NetCore.Tests/PlaylistsTests.cs +++ b/src/SpotifyApi.NetCore.Tests/PlaylistsTests.cs @@ -252,5 +252,44 @@ public async Task GetPlaylistCoverImage_PlaylistId_AtLeastOnePlalistCoverImageRe var playlistCoverImages = await api.GetPlaylistCoverImage("3cEYpjA9oz9GiPac4AsH4n", accessToken); Assert.IsTrue(playlistCoverImages.Length > 0, "No playlist images were found."); } + + [TestMethod] + [TestCategory("Integration")] + public async Task RemoveItems_PlaylistId_SpotifyUris_SnapshotIdIsNotNull() + { + // act + Assert.IsNotNull(await api.RemoveItems("46sqDMykUCnssu2F3zWXEF", new string[] { "spotify:track:5ArQzSBevAdXTxRY6Ulhbq" }, + accessToken: await TestsHelper.GetUserAccessToken())); + } + + [TestMethod] + [TestCategory("Integration")] + public async Task RemoveItems_PlaylistId_SpotifyUris_SnapshotId_SnapshotIdIsNotNull() + { + // act + Assert.IsNotNull(await api.RemoveItems("46sqDMykUCnssu2F3zWXEF", new string[] { "spotify:track:5ArQzSBevAdXTxRY6Ulhbq" }, + "MTQsMWNlNjE5NWJkYWFjOTNmNDM1M2NjZDM4NGNjMWViMTZlNzk0ZWEyYw==", accessToken: await TestsHelper.GetUserAccessToken())); + } + + [TestMethod] + [TestCategory("Integration")] + public async Task RemoveItems_PlaylistId_SpotifyUriLocations_SnapshotIdIsNotNull() + { + // act + Assert.IsNotNull(await api.RemoveItems("46sqDMykUCnssu2F3zWXEF", + new (string uri, int[] positions)[] { ("spotify:track:1Eolhana7nKHYpcYpdVcT5", new int[] { 0 }) }, + accessToken: await TestsHelper.GetUserAccessToken())); + } + + [TestMethod] + [TestCategory("Integration")] + public async Task RemoveItems_PlaylistId_SpotifyUriLocations_SnapshotId_SnapshotIdIsNotNull() + { + // act + Assert.IsNotNull(await api.RemoveItems("46sqDMykUCnssu2F3zWXEF", + new (string uri, int[] positions)[] { ("spotify:track:7iL6o9tox1zgHpKUfh9vuC", new int[] { 0 }) }, + "MTQsMWNlNjE5NWJkYWFjOTNmNDM1M2NjZDM4NGNjMWViMTZlNzk0ZWEyYw==", accessToken: await TestsHelper.GetUserAccessToken())); + } + } } diff --git a/src/SpotifyApi.NetCore.Tests/TracksApiTests.cs b/src/SpotifyApi.NetCore.Tests/TracksApiTests.cs index 2cf24ff..5242153 100644 --- a/src/SpotifyApi.NetCore.Tests/TracksApiTests.cs +++ b/src/SpotifyApi.NetCore.Tests/TracksApiTests.cs @@ -52,8 +52,8 @@ public async Task GetTrack_TrackIdNoMarket_MarketsArrayExists() public async Task GetTrack_TrackIdMarket_AvailableMarketsIsNull() { // arrange - const string trackId = "5lA3pwMkBdd24StM90QrNR"; - const string market = SpotifyCountryCodes.New_Zealand; + const string trackId = "11dFghVXANMlKmJXsNCbd8"; + const string market = SpotifyCountryCodes.Spain; var http = new HttpClient(); var accounts = new AccountsService(http, TestsHelper.GetLocalConfig()); @@ -64,7 +64,7 @@ public async Task GetTrack_TrackIdMarket_AvailableMarketsIsNull() var response = await api.GetTrack(trackId, market); // assert - Assert.IsNull(response.AvailableMarkets); + Assert.IsNull(response?.AvailableMarkets?.Length == 0 ? null : "Array not empty."); } [TestCategory("Integration")] diff --git a/src/SpotifyApi.NetCore/Models/PlaylistRemoveItemsPayloadData.cs b/src/SpotifyApi.NetCore/Models/PlaylistRemoveItemsPayloadData.cs new file mode 100644 index 0000000..e6730d5 --- /dev/null +++ b/src/SpotifyApi.NetCore/Models/PlaylistRemoveItemsPayloadData.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace SpotifyApi.NetCore.Models +{ + public partial class PlaylistRemoveItemsPayloadDataUriItems + { + + public PlaylistRemoveItemsPayloadDataUriItems(string[] uris, string snapshotId = null) + { + Uris = new PlaylistRemoveItemsPayloadDataUriItem[uris.Length]; + for (int i = 0; i < Uris.Length; i++) + { + Uris[i] = new PlaylistRemoveItemsPayloadDataUriItem(uris[i]); + } + SnapshotId = snapshotId; + } + + public PlaylistRemoveItemsPayloadDataUriItems((string uri, int[] positions)[] uriPositions, string snapshotId = null) + { + Uris = new PlaylistRemoveItemsPayloadDataUriItem[uriPositions.Length]; + for (int i = 0; i < Uris.Length; i++) + { + Uris[i] = new PlaylistRemoveItemsPayloadDataUriItem(uriPositions[i]); + } + SnapshotId = snapshotId; + } + + [JsonProperty("tracks", NullValueHandling = NullValueHandling.Ignore)] + public PlaylistRemoveItemsPayloadDataUriItem[] Uris { get; set; } + + [JsonProperty("snapshot_id", NullValueHandling = NullValueHandling.Ignore)] + public string SnapshotId { get; set; } + + } + + public partial class PlaylistRemoveItemsPayloadDataUriItem + { + + public PlaylistRemoveItemsPayloadDataUriItem(string uri) => this.Uri = uri; + + public PlaylistRemoveItemsPayloadDataUriItem((string uri, int[] positions) uriPositions) + { + Uri = uriPositions.uri; + Positions = uriPositions.positions; + } + + [JsonProperty("uri")] + public string Uri { get; set; } + + [JsonProperty("positions", NullValueHandling = NullValueHandling.Ignore)] + public int[] Positions { get; set; } + + } + +} diff --git a/src/SpotifyApi.NetCore/PlaylistsApi.cs b/src/SpotifyApi.NetCore/PlaylistsApi.cs index 65d0e7d..86ff84a 100644 --- a/src/SpotifyApi.NetCore/PlaylistsApi.cs +++ b/src/SpotifyApi.NetCore/PlaylistsApi.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Newtonsoft.Json; using System.Text; +using SpotifyApi.NetCore.Models; namespace SpotifyApi.NetCore { @@ -464,11 +465,21 @@ public async Task GetPlaylistCoverImage( /// /// https://developer.spotify.com/documentation/web-api/reference/playlists/remove-tracks-playlist/ /// - public Task RemoveItems( + public async Task RemoveItems( string playlistId, string[] spotifyUris, string snapshotId = null, - string accessToken = null) => throw new NotImplementedException(); + string accessToken = null) + { + if (string.IsNullOrWhiteSpace(playlistId)) throw new + ArgumentException("A valid Spotify playlist id must be specified."); + + if (spotifyUris?.Length < 1 || spotifyUris?.Length > 100) throw new + ArgumentException("A minimum of 1 and a maximum of 100 Spotify uri must be specified."); + + var builder = new UriBuilder($"{BaseUrl}/playlists/{playlistId}/tracks"); + return (await Delete(builder.Uri, new PlaylistRemoveItemsPayloadDataUriItems(spotifyUris, snapshotId), accessToken)).Data; + } /// /// Remove one or more items from a user’s playlist. @@ -485,11 +496,21 @@ public Task RemoveItems( /// /// https://developer.spotify.com/documentation/web-api/reference/playlists/remove-tracks-playlist/ /// - public Task RemoveItems( + public async Task RemoveItems( string playlistId, (string uri, int[] positions)[] spotifyUriPositions, string snapshotId = null, - string accessToken = null) => throw new NotImplementedException(); + string accessToken = null) + { + if (string.IsNullOrWhiteSpace(playlistId)) throw new + ArgumentException("A valid Spotify playlist id must be specified."); + + if (spotifyUriPositions?.Length < 1 || spotifyUriPositions?.Length > 100) throw new + ArgumentException("A minimum of 1 and a maximum of 100 Spotify uri and positions must be specified."); + + var builder = new UriBuilder($"{BaseUrl}/playlists/{playlistId}/tracks"); + return (await Delete(builder.Uri, new PlaylistRemoveItemsPayloadDataUriItems(spotifyUriPositions, snapshotId), accessToken)).Data; + } #endregion diff --git a/src/SpotifyApi.NetCore/SpotifyWebApi.cs b/src/SpotifyApi.NetCore/SpotifyWebApi.cs index a0b002b..4435361 100644 --- a/src/SpotifyApi.NetCore/SpotifyWebApi.cs +++ b/src/SpotifyApi.NetCore/SpotifyWebApi.cs @@ -180,6 +180,54 @@ protected internal virtual async Task Post(Uri uri, object data protected internal virtual async Task> Post(Uri uri, object data, string accessToken = null) => await PostOrPut("POST", uri, data, accessToken); + /// + /// Helper to DELETE an object with content to put in request body. + /// + protected internal virtual async Task> Delete(Uri uri, object data, string accessToken = null) + { + Logger.Debug($"DELETE {uri}. Token = {accessToken?.ToString()?.Substring(0, 4)}...", nameof(SpotifyWebApi)); + + _http.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", accessToken ?? (await GetAccessToken())); + + StringContent content = null; + + if (data == null) + { + content = null; + } + else + { + content = new StringContent(JsonConvert.SerializeObject(data)); + content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); + } + + HttpResponseMessage response = null; + + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Delete, uri); + request.Content = content; + + response = await _http.SendAsync(request); + + Logger.Information($"DELETE {uri} {response.StatusCode}", nameof(RestHttpClient)); + + await RestHttpClient.CheckForErrors(response); + + var spotifyResponse = new SpotifyResponse + { + StatusCode = response.StatusCode, + ReasonPhrase = response.ReasonPhrase + }; + + if (response.Content != null) + { + string json = await response.Content.ReadAsStringAsync(); + if (!string.IsNullOrEmpty(json)) spotifyResponse.Data = JsonConvert.DeserializeObject(json); + } + + return spotifyResponse; + } + /// /// Helper to DELETE an object /// From 063df76b4ec134bd3691ccae9a8da57f43f26aaa Mon Sep 17 00:00:00 2001 From: Akshay Srinivasan <35820570+akshays2112@users.noreply.github.com> Date: Thu, 7 Apr 2022 06:38:58 -0700 Subject: [PATCH 2/5] Message to Daniel Larson Please forward through your chain of command of contacts raj to Daniel Larson ya jajajarblinks!!! --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index b5c37f0..c3aa130 100644 --- a/README.md +++ b/README.md @@ -168,3 +168,17 @@ Huge thanks to **@aevansme**, **@brandongregoryscott** and **@akshays2112** for Contributions welcomed. Read [CONTRIB.md](./CONTRIB.md) [SpotifyApi.NetCore.Samples]:https://github.com/Ringobot/SpotifyApi.NetCore.Samples + + + + + + + +To be all deleted by Daniel Larson only contributed by "um" scary me everyone will not follow etc.::::: +Hey Daniel Larson you are a greatest guy in your NZ place who got collaped by some assholes like this who +talk about why I am given the exception here in Mumbai/Dumbai/"um"WhatsItsName and they are all talking +about my skin color here in Moms apartment still. Lol. Take care of yourself buddy now you know the game +just stay alive long as you can as the non-whites at Otters club say while I breeze through them. Play +your role to perfection as you always do. Hey you had to explain to me how this thing github works +THX BRO!!! From 2d9bb7321c25fcc0f1dd87b2d2be39cfa56f614d Mon Sep 17 00:00:00 2001 From: Akshay Srinivasan <98100672+InspiredNPerspiring@users.noreply.github.com> Date: Thu, 7 Apr 2022 19:34:22 +0530 Subject: [PATCH 3/5] Update README.md --- README.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/README.md b/README.md index c3aa130..6d4d5f5 100644 --- a/README.md +++ b/README.md @@ -169,16 +169,3 @@ Contributions welcomed. Read [CONTRIB.md](./CONTRIB.md) [SpotifyApi.NetCore.Samples]:https://github.com/Ringobot/SpotifyApi.NetCore.Samples - - - - - - -To be all deleted by Daniel Larson only contributed by "um" scary me everyone will not follow etc.::::: -Hey Daniel Larson you are a greatest guy in your NZ place who got collaped by some assholes like this who -talk about why I am given the exception here in Mumbai/Dumbai/"um"WhatsItsName and they are all talking -about my skin color here in Moms apartment still. Lol. Take care of yourself buddy now you know the game -just stay alive long as you can as the non-whites at Otters club say while I breeze through them. Play -your role to perfection as you always do. Hey you had to explain to me how this thing github works -THX BRO!!! From 6710b53f869f1e029088b800de7425427f13c9d1 Mon Sep 17 00:00:00 2001 From: Akshay Srinivasan <98100672+InspiredNPerspiring@users.noreply.github.com> Date: Thu, 7 Apr 2022 19:41:58 +0530 Subject: [PATCH 4/5] Last message for Daniel Larson To be all deleted by Daniel Larson only contributed by "um" scary me everyone will not follow etc.::::: Hey Daniel Larson you are a greatest guy in your NZ place who got collaped by some assholes like this who talk about why I am given the exception here in Mumbai/Dumbai/"um"WhatsItsName and they are all talking about my skin color here in Moms apartment still. Lol. Take care of yourself buddy now you know the game just stay alive long as you can as the non-whites at Otters club say while I breeze through them. Play your role to perfection as you always do. Hey you had to explain to me how this thing github works THX BRO!!! --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d4d5f5..e1c2e5c 100644 --- a/README.md +++ b/README.md @@ -167,5 +167,4 @@ Huge thanks to **@aevansme**, **@brandongregoryscott** and **@akshays2112** for Contributions welcomed. Read [CONTRIB.md](./CONTRIB.md) -[SpotifyApi.NetCore.Samples]:https://github.com/Ringobot/SpotifyApi.NetCore.Samples - +[SpotifyApi.NetCore.Samples]:https://github.com/Ringobot/SpotifyApi.NetCore.Samples \ No newline at end of file From 381204dd458c8bbd26e6457c0741d30521408e59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Dec 2022 02:24:01 +0000 Subject: [PATCH 5/5] Bump Newtonsoft.Json from 11.0.2 to 13.0.2 in /src/SpotifyApi.NetCore Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 11.0.2 to 13.0.2. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/11.0.2...13.0.2) --- updated-dependencies: - dependency-name: Newtonsoft.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- src/SpotifyApi.NetCore/SpotifyApi.NetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SpotifyApi.NetCore/SpotifyApi.NetCore.csproj b/src/SpotifyApi.NetCore/SpotifyApi.NetCore.csproj index fb7e6e3..436dd32 100644 --- a/src/SpotifyApi.NetCore/SpotifyApi.NetCore.csproj +++ b/src/SpotifyApi.NetCore/SpotifyApi.NetCore.csproj @@ -26,6 +26,6 @@ - +