From 7c94de211020ff04857fe941c5915bb3f321d076 Mon Sep 17 00:00:00 2001 From: Jonas Dellinger Date: Sun, 3 May 2020 22:34:03 +0200 Subject: [PATCH] Allow Enum in QueryParams and added more endpoints --- .../Clients/Interfaces/IPlaylistsClient.cs | 2 + .../Clients/Interfaces/ISearchClient.cs | 9 +++ .../Clients/Interfaces/ISpotifyClient.cs | 2 + SpotifyAPI.Web/Clients/PlaylistsClient.cs | 8 +++ SpotifyAPI.Web/Clients/SearchClient.cs | 18 ++++++ SpotifyAPI.Web/Clients/SpotifyClient.cs | 3 + SpotifyAPI.Web/Clients/SpotifyClientConfig.cs | 3 +- .../Models/Request/PlaylistGetItemsRequest.cs | 15 ++++- .../Models/Request/PlaylistGetRequest.cs | 15 ++++- .../Request/PlaylistRemoveItemsRequest.cs | 10 ++-- .../Request/PlaylistReorderItemsRequest.cs | 23 ++++++++ .../Models/Request/RequestParams.cs | 23 +++++++- .../Models/Request/SearchRequest.cs | 56 +++++++++++++++++++ SpotifyAPI.Web/Models/Response/FullArtist.cs | 18 ++++++ .../Models/Response/SearchResponse.cs | 11 ++++ SpotifyAPI.Web/SpotifyUrls.cs | 2 + SpotifyAPI.Web/Util/Ensure.cs | 5 +- SpotifyAPI.Web/Util/StringAttribute.cs | 14 +++++ 18 files changed, 222 insertions(+), 15 deletions(-) create mode 100644 SpotifyAPI.Web/Clients/Interfaces/ISearchClient.cs create mode 100644 SpotifyAPI.Web/Clients/SearchClient.cs create mode 100644 SpotifyAPI.Web/Models/Request/PlaylistReorderItemsRequest.cs create mode 100644 SpotifyAPI.Web/Models/Request/SearchRequest.cs create mode 100644 SpotifyAPI.Web/Models/Response/FullArtist.cs create mode 100644 SpotifyAPI.Web/Models/Response/SearchResponse.cs create mode 100644 SpotifyAPI.Web/Util/StringAttribute.cs diff --git a/SpotifyAPI.Web/Clients/Interfaces/IPlaylistsClient.cs b/SpotifyAPI.Web/Clients/Interfaces/IPlaylistsClient.cs index 721d9c76..41f8e50d 100644 --- a/SpotifyAPI.Web/Clients/Interfaces/IPlaylistsClient.cs +++ b/SpotifyAPI.Web/Clients/Interfaces/IPlaylistsClient.cs @@ -29,5 +29,7 @@ namespace SpotifyAPI.Web Task> CurrentUsers(PlaylistCurrentUsersRequest request); Task ChangeDetails(string playlistId, PlaylistChangeDetailsRequest request); + + Task ReorderItems(string playlistId, PlaylistReorderItemsRequest request); } } diff --git a/SpotifyAPI.Web/Clients/Interfaces/ISearchClient.cs b/SpotifyAPI.Web/Clients/Interfaces/ISearchClient.cs new file mode 100644 index 00000000..d6471562 --- /dev/null +++ b/SpotifyAPI.Web/Clients/Interfaces/ISearchClient.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace SpotifyAPI.Web +{ + public interface ISearchClient + { + Task Item(SearchRequest request); + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs index 74ef0f08..97eeb7ea 100644 --- a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs +++ b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs @@ -9,5 +9,7 @@ namespace SpotifyAPI.Web IShowsClient Shows { get; } IPlaylistsClient Playlists { get; } + + ISearchClient Search { get; } } } diff --git a/SpotifyAPI.Web/Clients/PlaylistsClient.cs b/SpotifyAPI.Web/Clients/PlaylistsClient.cs index 80204d0e..b17a72b8 100644 --- a/SpotifyAPI.Web/Clients/PlaylistsClient.cs +++ b/SpotifyAPI.Web/Clients/PlaylistsClient.cs @@ -126,5 +126,13 @@ namespace SpotifyAPI.Web var statusCode = await API.Put(URLs.Playlist(playlistId), null, request.BuildBodyParams()); return statusCode == HttpStatusCode.OK; } + + public Task ReorderItems(string playlistId, PlaylistReorderItemsRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(playlistId, nameof(playlistId)); + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Put(URLs.PlaylistTracks(playlistId), null, request.BuildBodyParams()); + } } } diff --git a/SpotifyAPI.Web/Clients/SearchClient.cs b/SpotifyAPI.Web/Clients/SearchClient.cs new file mode 100644 index 00000000..b7e9b1bb --- /dev/null +++ b/SpotifyAPI.Web/Clients/SearchClient.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using SpotifyAPI.Web.Http; +using URLs = SpotifyAPI.Web.SpotifyUrls; + +namespace SpotifyAPI.Web +{ + public class SearchClient : APIClient, ISearchClient + { + public SearchClient(IAPIConnector apiConnector) : base(apiConnector) { } + + public Task Item(SearchRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.Search(), request.BuildQueryParams()); + } + } +} diff --git a/SpotifyAPI.Web/Clients/SpotifyClient.cs b/SpotifyAPI.Web/Clients/SpotifyClient.cs index 18bfcfae..d1d37039 100644 --- a/SpotifyAPI.Web/Clients/SpotifyClient.cs +++ b/SpotifyAPI.Web/Clients/SpotifyClient.cs @@ -19,6 +19,7 @@ namespace SpotifyAPI.Web Browse = new BrowseClient(_apiConnector); Shows = new ShowsClient(_apiConnector); Playlists = new PlaylistsClient(_apiConnector); + Search = new SearchClient(_apiConnector); } public IUserProfileClient UserProfile { get; } @@ -28,5 +29,7 @@ namespace SpotifyAPI.Web public IShowsClient Shows { get; } public IPlaylistsClient Playlists { get; } + + public ISearchClient Search { get; } } } diff --git a/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs b/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs index d1969215..1d42be28 100644 --- a/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs +++ b/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs @@ -43,8 +43,7 @@ namespace SpotifyAPI.Web internal IAPIConnector CreateAPIConnector() { Ensure.ArgumentNotNull(BaseAddress, nameof(BaseAddress)); - Ensure.ArgumentNotNull(Authenticator, nameof(Authenticator), - ". Use WithToken or WithAuthenticator to specify a authentication"); + Ensure.ArgumentNotNull(Authenticator, nameof(Authenticator)); Ensure.ArgumentNotNull(JSONSerializer, nameof(JSONSerializer)); Ensure.ArgumentNotNull(HTTPClient, nameof(HTTPClient)); diff --git a/SpotifyAPI.Web/Models/Request/PlaylistGetItemsRequest.cs b/SpotifyAPI.Web/Models/Request/PlaylistGetItemsRequest.cs index 5edba4dd..58569a3f 100644 --- a/SpotifyAPI.Web/Models/Request/PlaylistGetItemsRequest.cs +++ b/SpotifyAPI.Web/Models/Request/PlaylistGetItemsRequest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace SpotifyAPI.Web @@ -6,7 +7,7 @@ namespace SpotifyAPI.Web { public PlaylistGetItemsRequest() { - AdditionalTypes = new List() { "track", "episode" }; + AdditionalTypes = AdditionalType.All; } [QueryParam("fields")] @@ -26,6 +27,16 @@ namespace SpotifyAPI.Web /// /// [QueryParam("additional_types")] - public List AdditionalTypes { get; set; } + public AdditionalType AdditionalTypes { get; set; } + + [Flags] + public enum AdditionalType + { + [String("track")] + Track = 0, + [String("episode")] + Episode = 1, + All = Track | Episode + } } } diff --git a/SpotifyAPI.Web/Models/Request/PlaylistGetRequest.cs b/SpotifyAPI.Web/Models/Request/PlaylistGetRequest.cs index ef714aac..91162cac 100644 --- a/SpotifyAPI.Web/Models/Request/PlaylistGetRequest.cs +++ b/SpotifyAPI.Web/Models/Request/PlaylistGetRequest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace SpotifyAPI.Web @@ -6,7 +7,7 @@ namespace SpotifyAPI.Web { public PlaylistGetRequest() { - AdditionalTypes = new List { "track", "episode" }; + AdditionalTypes = AdditionalType.All; } /// @@ -14,6 +15,16 @@ namespace SpotifyAPI.Web /// /// [QueryParam("additional_types")] - public List AdditionalTypes { get; set; } + public AdditionalType AdditionalTypes { get; set; } + + [Flags] + public enum AdditionalType + { + [String("track")] + Track = 0, + [String("episode")] + Episode = 1, + All = Track | Episode + } } } diff --git a/SpotifyAPI.Web/Models/Request/PlaylistRemoveItemsRequest.cs b/SpotifyAPI.Web/Models/Request/PlaylistRemoveItemsRequest.cs index aa3db4f6..09c1fbe1 100644 --- a/SpotifyAPI.Web/Models/Request/PlaylistRemoveItemsRequest.cs +++ b/SpotifyAPI.Web/Models/Request/PlaylistRemoveItemsRequest.cs @@ -5,13 +5,9 @@ namespace SpotifyAPI.Web { public class PlaylistRemoveItemsRequest : RequestParams { - public PlaylistRemoveItemsRequest(List tracks) - { - Tracks = tracks; - } - [BodyParam("tracks")] public List Tracks { get; set; } + [BodyParam("snapshot_id")] public string SnapshotId { get; set; } @@ -26,8 +22,12 @@ namespace SpotifyAPI.Web { Uri = uri; } + [JsonProperty("uri")] public string Uri { get; set; } + + [JsonProperty("positions", NullValueHandling = NullValueHandling.Ignore)] + public List Positions { get; set; } } } } diff --git a/SpotifyAPI.Web/Models/Request/PlaylistReorderItemsRequest.cs b/SpotifyAPI.Web/Models/Request/PlaylistReorderItemsRequest.cs new file mode 100644 index 00000000..9878b299 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/PlaylistReorderItemsRequest.cs @@ -0,0 +1,23 @@ +namespace SpotifyAPI.Web +{ + public class PlaylistReorderItemsRequest : RequestParams + { + [BodyParam("range_start")] + public int? RangeStart { get; set; } + + [BodyParam("insert_before")] + public int? InsertBefore { get; set; } + + [BodyParam("range_length")] + public int? RangeLength { get; set; } + + [BodyParam("snapshot_id")] + public string SnapshotId { get; set; } + + protected override void CustomEnsure() + { + Ensure.ArgumentNotNull(RangeStart, nameof(RangeStart)); + Ensure.ArgumentNotNull(InsertBefore, nameof(InsertBefore)); + } + } +} diff --git a/SpotifyAPI.Web/Models/Request/RequestParams.cs b/SpotifyAPI.Web/Models/Request/RequestParams.cs index 48a50ac0..ccf77c8c 100644 --- a/SpotifyAPI.Web/Models/Request/RequestParams.cs +++ b/SpotifyAPI.Web/Models/Request/RequestParams.cs @@ -47,10 +47,31 @@ namespace SpotifyAPI.Web { if (value is List) { - List list = value as List; + var list = value as List; var str = string.Join(",", list); queryParams.Add(attribute.Key ?? prop.Name, str); } + else if (value is Enum) + { + var valueAsEnum = value as Enum; + var enumType = valueAsEnum.GetType(); + var valueList = new List(); + + foreach (Enum enumVal in Enum.GetValues(valueAsEnum.GetType())) + { + if (valueAsEnum.HasFlag(enumVal)) + { + if (enumType + .GetMember(enumVal.ToString())[0] + .GetCustomAttributes(typeof(StringAttribute)) + .FirstOrDefault() is StringAttribute stringAttr) + { + valueList.Add(stringAttr.Value); + } + } + } + queryParams.Add(attribute.Key ?? prop.Name, string.Join(",", valueList)); + } else { queryParams.Add(attribute.Key ?? prop.Name, value.ToString()); diff --git a/SpotifyAPI.Web/Models/Request/SearchRequest.cs b/SpotifyAPI.Web/Models/Request/SearchRequest.cs new file mode 100644 index 00000000..b07fb4e5 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/SearchRequest.cs @@ -0,0 +1,56 @@ +using System; + +namespace SpotifyAPI.Web +{ + public class SearchRequest : RequestParams + { + [QueryParam("type")] + public Type? Types { get; set; } + + [QueryParam("q")] + public string Query { get; set; } + + [QueryParam("market")] + public string Market { get; set; } + + [QueryParam("limit")] + public int? Limit { get; set; } + + [QueryParam("offset")] + public int? Offset { get; set; } + + [QueryParam("include_external")] + public External? IncludeExternal { get; set; } + + protected override void CustomEnsure() + { + Ensure.ArgumentNotNull(Types, nameof(Types)); + Ensure.ArgumentNotNullOrEmptyString(Query, nameof(Query)); + } + + [Flags] + public enum External + { + [String("audio")] + Audio = 0, + } + + [Flags] + public enum Type + { + [String("album")] + Album = 0, + [String("artist")] + Artist = 1, + [String("playlist")] + Playlist = 2, + [String("track")] + Track = 4, + [String("show")] + Show = 8, + [String("episode")] + Episode = 16, + All = Album | Artist | Playlist | Track | Show | Episode + } + } +} diff --git a/SpotifyAPI.Web/Models/Response/FullArtist.cs b/SpotifyAPI.Web/Models/Response/FullArtist.cs new file mode 100644 index 00000000..b0908318 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/FullArtist.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class FullArtist + { + public Dictionary ExternalUrls { get; set; } + public Followers Followers { get; set; } + public List Genres { get; set; } + public string Href { get; set; } + public string Id { get; set; } + public List Images { get; set; } + public string Name { get; set; } + public int Popularity { get; set; } + public string Type { get; set; } + public string Uri { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/SearchResponse.cs b/SpotifyAPI.Web/Models/Response/SearchResponse.cs new file mode 100644 index 00000000..b977d7ec --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/SearchResponse.cs @@ -0,0 +1,11 @@ +namespace SpotifyAPI.Web +{ + public class SearchResponse + { + public Paging Artists { get; set; } + public Paging Albums { get; set; } + public Paging Tracks { get; set; } + public Paging Shows { get; set; } + public Paging Episodes { get; set; } + } +} diff --git a/SpotifyAPI.Web/SpotifyUrls.cs b/SpotifyAPI.Web/SpotifyUrls.cs index 9bfed4c2..afb7aa44 100644 --- a/SpotifyAPI.Web/SpotifyUrls.cs +++ b/SpotifyAPI.Web/SpotifyUrls.cs @@ -41,6 +41,8 @@ namespace SpotifyAPI.Web public static Uri CurrentUserPlaylists() => EUri($"me/playlists"); + public static Uri Search() => EUri($"search"); + private static Uri EUri(FormattableString path) => new Uri(path.ToString(_provider), UriKind.Relative); } } diff --git a/SpotifyAPI.Web/Util/Ensure.cs b/SpotifyAPI.Web/Util/Ensure.cs index d1711f30..ff932334 100644 --- a/SpotifyAPI.Web/Util/Ensure.cs +++ b/SpotifyAPI.Web/Util/Ensure.cs @@ -14,15 +14,14 @@ namespace SpotifyAPI.Web /// /// The argument value to check /// The name of the argument - /// Additional Exception Text - public static void ArgumentNotNull(object value, string name, string additional = null) + public static void ArgumentNotNull(object value, string name) { if (value != null) { return; } - throw new ArgumentNullException($"{name}{additional}"); + throw new ArgumentNullException(name); } /// diff --git a/SpotifyAPI.Web/Util/StringAttribute.cs b/SpotifyAPI.Web/Util/StringAttribute.cs new file mode 100644 index 00000000..6f4b599b --- /dev/null +++ b/SpotifyAPI.Web/Util/StringAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace SpotifyAPI.Web +{ + public class StringAttribute : Attribute + { + public StringAttribute(string value) + { + Value = value; + } + + public string Value { get; set; } + } +}