diff --git a/SpotifyAPI.Web/Clients/EpisodesClient.cs b/SpotifyAPI.Web/Clients/EpisodesClient.cs new file mode 100644 index 00000000..f9bd117c --- /dev/null +++ b/SpotifyAPI.Web/Clients/EpisodesClient.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using SpotifyAPI.Web.Http; +using URLs = SpotifyAPI.Web.SpotifyUrls; + +namespace SpotifyAPI.Web +{ + public class EpisodesClient : APIClient, IEpisodesClient + { + public EpisodesClient(IAPIConnector apiConnector) : base(apiConnector) { } + + public Task Get(string episodeId) + { + Ensure.ArgumentNotNullOrEmptyString(episodeId, nameof(episodeId)); + + return API.Get(URLs.Episode(episodeId)); + } + + public Task Get(string episodeId, EpisodeRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(episodeId, nameof(episodeId)); + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.Episode(episodeId), request.BuildQueryParams()); + } + + public Task GetSeveral(EpisodesRequest request) + { + Ensure.ArgumentNotNull(request, nameof(request)); + + return API.Get(URLs.Episodes(), request.BuildQueryParams()); + } + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/IEpisodesClient.cs b/SpotifyAPI.Web/Clients/Interfaces/IEpisodesClient.cs new file mode 100644 index 00000000..b7acb70a --- /dev/null +++ b/SpotifyAPI.Web/Clients/Interfaces/IEpisodesClient.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; + +namespace SpotifyAPI.Web +{ + public interface IEpisodesClient + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")] + Task Get(string episodeId); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")] + Task Get(string episodeId, EpisodeRequest request); + + Task GetSeveral(EpisodesRequest request); + } +} diff --git a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs index 0c5a24ad..8c518c77 100644 --- a/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs +++ b/SpotifyAPI.Web/Clients/Interfaces/ISpotifyClient.cs @@ -30,6 +30,8 @@ namespace SpotifyAPI.Web IPersonalizationClient Personalization { get; } + IEpisodesClient Episodes { get; } + Task> Paginate(Paging firstPage); Task> Paginate(Paging firstPage, Func> mapper); Task> Paginate(Func>> getFirstPage); diff --git a/SpotifyAPI.Web/Clients/SpotifyClient.cs b/SpotifyAPI.Web/Clients/SpotifyClient.cs index 0324148c..b88df1d4 100644 --- a/SpotifyAPI.Web/Clients/SpotifyClient.cs +++ b/SpotifyAPI.Web/Clients/SpotifyClient.cs @@ -18,7 +18,7 @@ namespace SpotifyAPI.Web Ensure.ArgumentNotNull(config, nameof(config)); _apiConnector = config.CreateAPIConnector(); - DefaultPaginator = config.Paginator; + DefaultPaginator = config.DefaultPaginator; UserProfile = new UserProfileClient(_apiConnector); Browse = new BrowseClient(_apiConnector); Shows = new ShowsClient(_apiConnector); @@ -30,6 +30,7 @@ namespace SpotifyAPI.Web Albums = new AlbumsClient(_apiConnector); Artists = new ArtistsClient(_apiConnector); Personalization = new PersonalizationClient(_apiConnector); + Episodes = new EpisodesClient(_apiConnector); } public IPaginator DefaultPaginator { get; } @@ -56,6 +57,8 @@ namespace SpotifyAPI.Web public IPersonalizationClient Personalization { get; } + public IEpisodesClient Episodes { get; } + public Task> Paginate(Paging firstPage) { return DefaultPaginator.Paginate(firstPage, _apiConnector); diff --git a/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs b/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs index 01b73a89..46c8f88b 100644 --- a/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs +++ b/SpotifyAPI.Web/Clients/SpotifyClientConfig.cs @@ -5,19 +5,16 @@ namespace SpotifyAPI.Web { public class SpotifyClientConfig { - public Uri BaseAddress { get; } - public IAuthenticator Authenticator { get; } - public IJSONSerializer JSONSerializer { get; } - public IHTTPClient HTTPClient { get; } - public IHTTPLogger HTTPLogger { get; } - public IPaginator Paginator { get; set; } - - public IRetryHandler RetryHandler { get; } + public Uri BaseAddress { get; private set; } + public IAuthenticator Authenticator { get; private set; } + public IJSONSerializer JSONSerializer { get; private set; } + public IHTTPClient HTTPClient { get; private set; } + public IHTTPLogger HTTPLogger { get; private set; } + public IRetryHandler RetryHandler { get; private set; } + public IPaginator DefaultPaginator { get; private set; } /// /// This config spefies the internal parts of the SpotifyClient. - /// In apps where multiple different access tokens are used, one should create a default config and then use - /// or to specify the auth details. /// /// /// @@ -42,77 +39,92 @@ namespace SpotifyAPI.Web HTTPClient = httpClient; RetryHandler = retryHandler; HTTPLogger = httpLogger; - Paginator = paginator; + DefaultPaginator = paginator; } internal IAPIConnector CreateAPIConnector() { - Ensure.ArgumentNotNull(BaseAddress, nameof(BaseAddress)); - Ensure.ArgumentNotNull(Authenticator, nameof(Authenticator)); - Ensure.ArgumentNotNull(JSONSerializer, nameof(JSONSerializer)); - Ensure.ArgumentNotNull(HTTPClient, nameof(HTTPClient)); - - return new APIConnector(BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger); + return new APIConnector( + BaseAddress, + Authenticator, + JSONSerializer, + HTTPClient, + RetryHandler, + HTTPLogger + ); } - public SpotifyClientConfig WithToken(string token, string tokenType = "Bearer") + public void AddToken(string token, string tokenType = "Bearer") { Ensure.ArgumentNotNull(token, nameof(token)); - - return WithAuthenticator(new TokenHeaderAuthenticator(token, tokenType)); + Authenticator = new TokenHeaderAuthenticator(token, tokenType); } - public SpotifyClientConfig WithRetryHandler(IRetryHandler retryHandler) + public void AddRetryHandler(IRetryHandler retryHandler) { - return new SpotifyClientConfig( - BaseAddress, Authenticator, JSONSerializer, HTTPClient, retryHandler, HTTPLogger, Paginator); + RetryHandler = retryHandler; } - public SpotifyClientConfig WithAuthenticator(IAuthenticator authenticator) + public void AddAuthenticator(IAuthenticator authenticator) { - return new SpotifyClientConfig( - BaseAddress, authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger, Paginator); + Ensure.ArgumentNotNull(authenticator, nameof(authenticator)); + + Authenticator = authenticator; } - public SpotifyClientConfig WithHTTPLogger(IHTTPLogger httpLogger) + public void AddHTTPLogger(IHTTPLogger httpLogger) { - return new SpotifyClientConfig( - BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, httpLogger, Paginator); + HTTPLogger = httpLogger; } - public SpotifyClientConfig WithPaginator(IPaginator paginator) + public void AddHTTPClient(IHTTPClient httpClient) { - return new SpotifyClientConfig( - BaseAddress, Authenticator, JSONSerializer, HTTPClient, RetryHandler, HTTPLogger, paginator); + Ensure.ArgumentNotNull(httpClient, nameof(httpClient)); + + HTTPClient = httpClient; + } + + public void AddJSONSerializer(IJSONSerializer jsonSerializer) + { + Ensure.ArgumentNotNull(jsonSerializer, nameof(jsonSerializer)); + + JSONSerializer = jsonSerializer; + } + + + public void AddDefaultPaginator(IPaginator paginator) + { + DefaultPaginator = paginator; } public static SpotifyClientConfig CreateDefault(string token, string tokenType = "Bearer") { - Ensure.ArgumentNotNull(token, nameof(token)); - - return CreateDefault(new TokenHeaderAuthenticator(token, tokenType)); + return CreateDefault(options => + { + options.AddToken(token, tokenType); + }); } - /// - /// Creates a default configuration, which is not useable without calling or - /// - /// - public static SpotifyClientConfig CreateDefault() + public static SpotifyClientConfig CreateDefault(Action optionsCallback) { - return CreateDefault(null); - } + Ensure.ArgumentNotNull(optionsCallback, nameof(optionsCallback)); - public static SpotifyClientConfig CreateDefault(IAuthenticator authenticator) - { - return new SpotifyClientConfig( + var config = new SpotifyClientConfig( SpotifyUrls.APIV1, - authenticator, + null, new NewtonsoftJSONSerializer(), new NetHttpClient(), null, null, new SimplePaginator() ); + optionsCallback(config); + + if (config.Authenticator == null) + { + throw new NullReferenceException("The authenticator was not set after the options callback was run. Please specify a token with AddToken or AddAuthenticator"); + } + return config; } } } diff --git a/SpotifyAPI.Web/Models/Request/EpisodeRequest.cs b/SpotifyAPI.Web/Models/Request/EpisodeRequest.cs new file mode 100644 index 00000000..c4c178e4 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/EpisodeRequest.cs @@ -0,0 +1,8 @@ +namespace SpotifyAPI.Web +{ + public class EpisodeRequest : RequestParams + { + [QueryParam("market")] + public string Market { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Request/EpisodesRequest.cs b/SpotifyAPI.Web/Models/Request/EpisodesRequest.cs new file mode 100644 index 00000000..e58ed833 --- /dev/null +++ b/SpotifyAPI.Web/Models/Request/EpisodesRequest.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class EpisodesRequest : RequestParams + { + public EpisodesRequest(IList ids) + { + Ensure.ArgumentNotNullOrEmptyList(ids, nameof(ids)); + + Ids = ids; + } + + [QueryParam("ids")] + public IList Ids { get; set; } + + [QueryParam("market")] + public string Market { get; set; } + } +} diff --git a/SpotifyAPI.Web/Models/Response/EpisodesResponse.cs b/SpotifyAPI.Web/Models/Response/EpisodesResponse.cs new file mode 100644 index 00000000..2c8e00e5 --- /dev/null +++ b/SpotifyAPI.Web/Models/Response/EpisodesResponse.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace SpotifyAPI.Web +{ + public class EpisodesResponse + { + public List Episodes { get; set; } + } +} diff --git a/SpotifyAPI.Web/SpotifyUrls.cs b/SpotifyAPI.Web/SpotifyUrls.cs index c27598ab..403dd2c2 100644 --- a/SpotifyAPI.Web/SpotifyUrls.cs +++ b/SpotifyAPI.Web/SpotifyUrls.cs @@ -105,6 +105,10 @@ namespace SpotifyAPI.Web public static Uri PersonalizationTop(string type) => EUri($"me/top/{type}"); + public static Uri Episode(string episodeId) => EUri($"episodes/{episodeId}"); + + public static Uri Episodes() => EUri($"episodes"); + private static Uri EUri(FormattableString path) => new Uri(path.ToString(_provider), UriKind.Relative); } }