diff --git a/SpotifyAPI.Web/Clients/FollowClient.cs b/SpotifyAPI.Web/Clients/FollowClient.cs new file mode 100644 index 00000000..5045966f --- /dev/null +++ b/SpotifyAPI.Web/Clients/FollowClient.cs @@ -0,0 +1,83 @@ +using System.Net; +using System.Collections.Generic; +using System.Threading.Tasks; +using SpotifyAPI.Web.Http; +using URLs = SpotifyAPI.Web.SpotifyUrls; + +namespace SpotifyAPI.Web +{ + public class FollowClient : APIClient, IFollowClient + { + public FollowClient(IAPIConnector apiConnector) : base(apiConnector) { } + + public Task> CheckCurrentUser(FollowCheckCurrentUserRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get>(URLs.CurrentUserFollowerContains(), request.BuildQueryParams()); + } + + public Task> CheckPlaylist(string playlistId, FollowCheckPlaylistRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(playlistId, nameof(playlistId)); + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get>(URLs.PlaylistFollowersContains(playlistId), request.BuildQueryParams()); + } + + public async Task Follow(FollowRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + var statusCode = await API.Put(URLs.CurrentUserFollower(), request.BuildQueryParams(), request.BuildBodyParams()); + return statusCode == HttpStatusCode.OK; + } + + public async Task FollowPlaylist(string playlistId) + { + Ensure.ArgumentNotNullOrEmptyString(playlistId, nameof(playlistId)); + + var statusCode = await API.Put(URLs.PlaylistFollowers(playlistId), null, null); + return statusCode == HttpStatusCode.OK; + } + + public async Task FollowPlaylist(string playlistId, FollowPlaylistRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(playlistId, nameof(playlistId)); + Ensure.ArgumentNotNull(request, nameof(request)); + + var statusCode = await API.Put(URLs.PlaylistFollowers(playlistId), null, request.BuildBodyParams()); + return statusCode == HttpStatusCode.OK; + } + + public Task OfCurrentUser() + { + var request = new FollowOfCurrentUserRequest(); + + return API.Get(URLs.CurrentUserFollower(), request.BuildQueryParams()); + } + + public Task OfCurrentUser(FollowOfCurrentUserRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.CurrentUserFollower()); + } + + public async Task Unfollow(UnfollowRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + var statusCode = await API.Delete(URLs.CurrentUserFollower(), request.BuildQueryParams(), request.BuildBodyParams()); + return statusCode == HttpStatusCode.NoContent; + } + + public async Task UnfollowPlaylist(string playlistId) + { + Ensure.ArgumentNotNullOrEmptyString(playlistId, nameof(playlistId)); + + var statusCode = await API.Delete(URLs.PlaylistFollowers(playlistId), null, null); + return statusCode == HttpStatusCode.OK; + } + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/IFollowClient.cs b/SpotifyAPI.Web/Clients/Interfaces/IFollowClient.cs new file mode 100644 index 00000000..a4cccbdc --- /dev/null +++ b/SpotifyAPI.Web/Clients/Interfaces/IFollowClient.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace SpotifyAPI.Web +{ + public interface IFollowClient + { + Task> CheckCurrentUser(FollowCheckCurrentUserRequest request); + + Task> CheckPlaylist(string playlistId, FollowCheckPlaylistRequest request); + + Task Follow(FollowRequest request); + + Task FollowPlaylist(string playlistId); + Task FollowPlaylist(string playlistId, FollowPlaylistRequest request); + + Task OfCurrentUser(); + Task OfCurrentUser(FollowOfCurrentUserRequest request); + + Task Unfollow(UnfollowRequest request); + + Task UnfollowPlaylist(string playlistId); + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs index 97eeb7ea..dd82dedc 100644 --- a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs +++ b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs @@ -11,5 +11,7 @@ namespace SpotifyAPI.Web IPlaylistsClient Playlists { get; } ISearchClient Search { get; } + + IFollowClient Follow { get; } } } diff --git a/SpotifyAPI.Web/Clients/SpotifyClient.cs b/SpotifyAPI.Web/Clients/SpotifyClient.cs index d1d37039..6140a126 100644 --- a/SpotifyAPI.Web/Clients/SpotifyClient.cs +++ b/SpotifyAPI.Web/Clients/SpotifyClient.cs @@ -20,6 +20,7 @@ namespace SpotifyAPI.Web Shows = new ShowsClient(_apiConnector); Playlists = new PlaylistsClient(_apiConnector); Search = new SearchClient(_apiConnector); + Follow = new FollowClient(_apiConnector); } public IUserProfileClient UserProfile { get; } @@ -31,5 +32,7 @@ namespace SpotifyAPI.Web public IPlaylistsClient Playlists { get; } public ISearchClient Search { get; } + + public IFollowClient Follow { get; } } } diff --git a/SpotifyAPI.Web/Http/APIConnector.cs b/SpotifyAPI.Web/Http/APIConnector.cs index c349731c..b5dc6eee 100644 --- a/SpotifyAPI.Web/Http/APIConnector.cs +++ b/SpotifyAPI.Web/Http/APIConnector.cs @@ -55,6 +55,14 @@ namespace SpotifyAPI.Web.Http return SendAPIRequest(uri, HttpMethod.Delete, parameters, body); } + public async Task Delete(Uri uri, IDictionary parameters, object body) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + var response = await SendAPIRequestDetailed(uri, HttpMethod.Delete, parameters, body); + return response.StatusCode; + } + public Task Get(Uri uri) { Ensure.ArgumentNotNull(uri, nameof(uri)); @@ -90,6 +98,14 @@ namespace SpotifyAPI.Web.Http return SendAPIRequest(uri, HttpMethod.Post, parameters, body); } + public async Task Post(Uri uri, IDictionary parameters, object body) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + + var response = await SendAPIRequestDetailed(uri, HttpMethod.Post, parameters, body); + return response.StatusCode; + } + public Task Put(Uri uri) { Ensure.ArgumentNotNull(uri, nameof(uri)); diff --git a/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs b/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs index 74b75148..858173cd 100644 --- a/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs +++ b/SpotifyAPI.Web/Http/Interfaces/IAPIConnector.cs @@ -20,6 +20,7 @@ namespace SpotifyAPI.Web.Http Task Post(Uri uri); Task Post(Uri uri, IDictionary parameters); Task Post(Uri uri, IDictionary parameters, object body); + Task Post(Uri uri, IDictionary parameters, object body); Task Put(Uri uri); Task Put(Uri uri, IDictionary parameters); @@ -30,6 +31,7 @@ namespace SpotifyAPI.Web.Http Task Delete(Uri uri); Task Delete(Uri uri, IDictionary parameters); Task Delete(Uri uri, IDictionary parameters, object body); + Task Delete(Uri uri, IDictionary parameters, object body); Task SendAPIRequest(Uri uri, HttpMethod method, IDictionary parameters = null, object body = null); diff --git a/SpotifyAPI.Web/Models/Request/FollowCheckCurrentUserRequest.cs b/SpotifyAPI.Web/Models/Request/FollowCheckCurrentUserRequest.cs new file mode 100644 index 00000000..7002e968 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/FollowCheckCurrentUserRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class FollowCheckCurrentUserRequest : RequestParams + { + [QueryParam("type")] + public Types? Type { get; set; } + + [QueryParam("ids")] + public List Ids { get; set; } + + protected override void CustomEnsure() + { + Ensure.ArgumentNotNull(Type, nameof(Type)); + Ensure.ArgumentNotNullOrEmptyList(Ids, nameof(Ids)); + } + + public enum Types + { + [String("artist")] + Artist, + [String("user")] + User + } + } +} diff --git a/SpotifyAPI.Web/Models/Request/FollowCheckPlaylistRequest.cs b/SpotifyAPI.Web/Models/Request/FollowCheckPlaylistRequest.cs new file mode 100644 index 00000000..709e287b --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/FollowCheckPlaylistRequest.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class FollowCheckPlaylistRequest : RequestParams + { + [QueryParam("ids")] + public List Ids { get; set; } + + protected override void CustomEnsure() + { + Ensure.ArgumentNotNullOrEmptyList(Ids, nameof(Ids)); + } + } +} diff --git a/SpotifyAPI.Web/Models/Request/FollowGetCurrentUserRequest.cs b/SpotifyAPI.Web/Models/Request/FollowGetCurrentUserRequest.cs new file mode 100644 index 00000000..2c755735 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/FollowGetCurrentUserRequest.cs @@ -0,0 +1,26 @@ +namespace SpotifyAPI.Web +{ + public class FollowOfCurrentUserRequest : RequestParams + { + public FollowOfCurrentUserRequest() + { + Type = Types.Artist; + } + + + [QueryParam("type")] + public Types Type { get; set; } + + [QueryParam("limit")] + public int? Limit { get; set; } + + [QueryParam("after")] + public string After { get; set; } + + public enum Types + { + [String("artist")] + Artist + } + } +} diff --git a/SpotifyAPI.Web/Models/Request/FollowPlaylistRequest.cs b/SpotifyAPI.Web/Models/Request/FollowPlaylistRequest.cs new file mode 100644 index 00000000..79c79ebb --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/FollowPlaylistRequest.cs @@ -0,0 +1,8 @@ +namespace SpotifyAPI.Web +{ + public class FollowPlaylistRequest : RequestParams + { + [BodyParam("public")] + public bool Public { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Request/FollowRequest.cs b/SpotifyAPI.Web/Models/Request/FollowRequest.cs new file mode 100644 index 00000000..600563c6 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/FollowRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class FollowRequest : RequestParams + { + [QueryParam("type")] + public Types? Type { get; set; } + + [BodyParam("ids")] + public List Ids { get; set; } + + protected override void CustomEnsure() + { + Ensure.ArgumentNotNull(Type, nameof(Type)); + Ensure.ArgumentNotNullOrEmptyList(Ids, nameof(Ids)); + } + + public enum Types + { + [String("artist")] + Artist, + [String("user")] + User + } + } +} diff --git a/SpotifyAPI.Web/Models/Request/UnfollowRequest.cs b/SpotifyAPI.Web/Models/Request/UnfollowRequest.cs new file mode 100644 index 00000000..a2a7bf98 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/UnfollowRequest.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +namespace SpotifyAPI.Web +{ + public class UnfollowRequest : RequestParams + { + [QueryParam("type")] + public Types? Type { get; set; } + + [BodyParam("ids")] + public List Ids { get; set; } + + protected override void CustomEnsure() + { + Ensure.ArgumentNotNull(Type, nameof(Type)); + Ensure.ArgumentNotNullOrEmptyList(Ids, nameof(Ids)); + } + + public enum Types + { + [String("artist")] + Artist, + [String("user")] + User + } + } +} diff --git a/SpotifyAPI.Web/Models/Response/Cursor.cs b/SpotifyAPI.Web/Models/Response/Cursor.cs new file mode 100644 index 00000000..c49a5fca --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/Cursor.cs @@ -0,0 +1,8 @@ +namespace SpotifyAPI.Web +{ + public class Cursor + { + public string Before { get; set; } + public string After { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/CursorPaging.cs b/SpotifyAPI.Web/Models/Response/CursorPaging.cs new file mode 100644 index 00000000..f996b94a --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/CursorPaging.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class CursorPaging + { + public string Href { get; set; } + public List Items { get; set; } + public int Limit { get; set; } + public string Next { get; set; } + public Cursor Cursors { get; set; } + public int Total { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/FollowedArtistsResponse.cs b/SpotifyAPI.Web/Models/Response/FollowedArtistsResponse.cs new file mode 100644 index 00000000..36947a3f --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/FollowedArtistsResponse.cs @@ -0,0 +1,7 @@ +namespace SpotifyAPI.Web +{ + public class FollowedArtistsResponse + { + public CursorPaging Artists { get; set; } + } +} diff --git a/SpotifyAPI.Web/SpotifyUrls.cs b/SpotifyAPI.Web/SpotifyUrls.cs index afb7aa44..5a77424c 100644 --- a/SpotifyAPI.Web/SpotifyUrls.cs +++ b/SpotifyAPI.Web/SpotifyUrls.cs @@ -43,6 +43,14 @@ namespace SpotifyAPI.Web public static Uri Search() => EUri($"search"); + public static Uri CurrentUserFollowerContains() => EUri($"me/following/contains"); + + public static Uri PlaylistFollowersContains(string playlistId) => EUri($"playlists/{playlistId}/followers/contains"); + + public static Uri CurrentUserFollower() => EUri($"me/following"); + + public static Uri PlaylistFollowers(string playlistId) => EUri($"playlists/{playlistId}/followers"); + private static Uri EUri(FormattableString path) => new Uri(path.ToString(_provider), UriKind.Relative); } }