mirror of
https://github.com/Sarsoo/Spotify.NET.git
synced 2024-12-23 22:56:25 +00:00
Pagination implementation adapted - Less methods,more defaults #451
This commit is contained in:
parent
7445d3ca0e
commit
5ae126699c
@ -59,7 +59,7 @@ namespace Example.CLI.PersistentConfig
|
|||||||
var me = await spotify.UserProfile.Current();
|
var me = await spotify.UserProfile.Current();
|
||||||
Console.WriteLine($"Welcome {me.DisplayName} ({me.Id}), your authenticated!");
|
Console.WriteLine($"Welcome {me.DisplayName} ({me.Id}), your authenticated!");
|
||||||
|
|
||||||
var playlists = await spotify.PaginateAll(() => spotify.Playlists.CurrentUsers());
|
var playlists = await spotify.PaginateAll(spotify.Playlists.CurrentUsers());
|
||||||
Console.WriteLine($"Total Playlists in your Account: {playlists.Count}");
|
Console.WriteLine($"Total Playlists in your Account: {playlists.Count}");
|
||||||
|
|
||||||
_server.Dispose();
|
_server.Dispose();
|
||||||
|
@ -4,14 +4,60 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public interface IShowsClient
|
public interface IShowsClient
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get Spotify catalog information for a single show identified by its unique Spotify ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showId">The Spotify ID for the show.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-get-a-show
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns></returns>
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
|
||||||
Task<FullShow> Get(string showId);
|
Task<FullShow> Get(string showId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Spotify catalog information for a single show identified by its unique Spotify ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showId">The Spotify ID for the show.</param>
|
||||||
|
/// <param name="request">The request-model which contains required and optional parameters.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-get-a-show
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns></returns>
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716")]
|
||||||
Task<FullShow> Get(string showId, ShowRequest request);
|
Task<FullShow> Get(string showId, ShowRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Spotify catalog information for several shows based on their Spotify IDs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The request-model which contains required and optional parameters.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-get-multiple-shows
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns></returns>
|
||||||
Task<ShowsResponse> GetSeveral(ShowsRequest request);
|
Task<ShowsResponse> GetSeveral(ShowsRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Spotify catalog information about an show’s episodes.
|
||||||
|
/// Optional parameters can be used to limit the number of episodes returned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showId">The Spotify ID for the show.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-get-a-shows-episodes
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns></returns>
|
||||||
Task<Paging<SimpleEpisode>> GetEpisodes(string showId);
|
Task<Paging<SimpleEpisode>> GetEpisodes(string showId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Spotify catalog information about an show’s episodes.
|
||||||
|
/// Optional parameters can be used to limit the number of episodes returned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showId">The Spotify ID for the show.</param>
|
||||||
|
/// <param name="request">The request-model which contains required and optional parameters.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// https://developer.spotify.com/documentation/web-api/reference-beta/#endpoint-get-a-shows-episodes
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns></returns>
|
||||||
Task<Paging<SimpleEpisode>> GetEpisodes(string showId, ShowEpisodesRequest request);
|
Task<Paging<SimpleEpisode>> GetEpisodes(string showId, ShowEpisodesRequest request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Threading;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -7,56 +8,296 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public interface ISpotifyClient
|
public interface ISpotifyClient
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The default paginator used by the Paginator methods
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IPaginator DefaultPaginator { get; }
|
IPaginator DefaultPaginator { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify User Profiles
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IUserProfileClient UserProfile { get; }
|
IUserProfileClient UserProfile { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Browse Endpoints
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IBrowseClient Browse { get; }
|
IBrowseClient Browse { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Shows
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IShowsClient Shows { get; }
|
IShowsClient Shows { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Playlists
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IPlaylistsClient Playlists { get; }
|
IPlaylistsClient Playlists { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Search
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
ISearchClient Search { get; }
|
ISearchClient Search { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Follows
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IFollowClient Follow { get; }
|
IFollowClient Follow { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Tracks
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
ITracksClient Tracks { get; }
|
ITracksClient Tracks { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Player Endpoints
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IPlayerClient Player { get; }
|
IPlayerClient Player { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Albums
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IAlbumsClient Albums { get; }
|
IAlbumsClient Albums { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Artists
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IArtistsClient Artists { get; }
|
IArtistsClient Artists { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Personalization Endpoints
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IPersonalizationClient Personalization { get; }
|
IPersonalizationClient Personalization { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify Podcast Episodes
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IEpisodesClient Episodes { get; }
|
IEpisodesClient Episodes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operations related to Spotify User Library
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
ILibraryClient Library { get; }
|
ILibraryClient Library { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the last response received by an API call.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
IResponse? LastResponse { get; }
|
IResponse? LastResponse { get; }
|
||||||
|
|
||||||
Task<IList<T>> PaginateAll<T>(Paging<T> firstPage);
|
/// <summary>
|
||||||
Task<IList<T>> PaginateAll<T>(Paging<T> firstPage, IPaginator paginator);
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
Task<IList<T>> PaginateAll<T>(Func<Task<Paging<T>>> getFirstPage);
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
Task<IList<T>> PaginateAll<T>(Func<Task<Paging<T>>> getFirstPage, IPaginator paginator);
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">The first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
Task<IList<T>> PaginateAll<T>(Paging<T> firstPage, IPaginator? paginator = default!);
|
||||||
|
|
||||||
Task<IList<T>> PaginateAll<T, TNext>(Paging<T, TNext> firstPage, Func<TNext, Paging<T, TNext>> mapper);
|
/// <summary>
|
||||||
Task<IList<T>> PaginateAll<T, TNext>(Paging<T, TNext> firstPage, Func<TNext, Paging<T, TNext>> mapper, IPaginator paginator);
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
Task<IList<T>> PaginateAll<T, TNext>(Func<Task<Paging<T, TNext>>> getFirstPage, Func<TNext, Paging<T, TNext>> mapper);
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
Task<IList<T>> PaginateAll<T, TNext>(Func<Task<Paging<T, TNext>>> getFirstPage, Func<TNext, Paging<T, TNext>> mapper, IPaginator paginator);
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
Task<IList<T>> PaginateAll<T>(Func<Task<Paging<T>>> getFirstPage, IPaginator? paginator = default!);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
Task<IList<T>> PaginateAll<T>(Task<Paging<T>> firstPageTask, IPaginator? paginator = default!);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">A first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
Task<IList<T>> PaginateAll<T, TNext>(
|
||||||
|
Paging<T, TNext> firstPage,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = default!
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IList<T>> PaginateAll<T, TNext>(
|
||||||
|
Func<Task<Paging<T, TNext>>> getFirstPage,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = default!
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A Task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IList<T>> PaginateAll<T, TNext>(
|
||||||
|
Task<Paging<T, TNext>> firstPageTask,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = default!
|
||||||
|
);
|
||||||
|
|
||||||
#if NETSTANDARD2_1
|
#if NETSTANDARD2_1
|
||||||
IAsyncEnumerable<T> Paginate<T>(Paging<T> firstPage);
|
/// <summary>
|
||||||
IAsyncEnumerable<T> Paginate<T>(Paging<T> firstPage, IPaginator paginator);
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
IAsyncEnumerable<T> Paginate<T>(Func<Task<Paging<T>>> getFirstPage);
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
IAsyncEnumerable<T> Paginate<T>(Func<Task<Paging<T>>> getFirstPage, IPaginator paginator);
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">A first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>An iterable IAsyncEnumerable</returns>
|
||||||
|
IAsyncEnumerable<T> Paginate<T>(
|
||||||
|
Paging<T> firstPage,
|
||||||
|
IPaginator? paginator = default!,
|
||||||
|
CancellationToken cancellationToken = default!
|
||||||
|
);
|
||||||
|
|
||||||
IAsyncEnumerable<T> Paginate<T, TNext>(Paging<T, TNext> firstPage, Func<TNext, Paging<T, TNext>> mapper);
|
/// <summary>
|
||||||
IAsyncEnumerable<T> Paginate<T, TNext>(Paging<T, TNext> firstPage, Func<TNext, Paging<T, TNext>> mapper, IPaginator paginator);
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
IAsyncEnumerable<T> Paginate<T, TNext>(Func<Task<Paging<T, TNext>>> getFirstPage, Func<TNext, Paging<T, TNext>> mapper);
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
IAsyncEnumerable<T> Paginate<T, TNext>(Func<Task<Paging<T, TNext>>> getFirstPage, Func<TNext, Paging<T, TNext>> mapper, IPaginator paginator);
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A Function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>An iterable IAsyncEnumerable</returns>
|
||||||
|
IAsyncEnumerable<T> Paginate<T>(
|
||||||
|
Func<Task<Paging<T>>> getFirstPage,
|
||||||
|
IPaginator? paginator = default!,
|
||||||
|
CancellationToken cancellationToken = default!
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A Task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>An iterable IAsyncEnumerable</returns>
|
||||||
|
IAsyncEnumerable<T> Paginate<T>(
|
||||||
|
Task<Paging<T>> firstPageTask,
|
||||||
|
IPaginator? paginator = default!,
|
||||||
|
CancellationToken cancellationToken = default!
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">A first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
IAsyncEnumerable<T> Paginate<T, TNext>(
|
||||||
|
Paging<T, TNext> firstPage,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = default!,
|
||||||
|
CancellationToken cancellationToken = default!
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A Function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
IAsyncEnumerable<T> Paginate<T, TNext>(
|
||||||
|
Func<Task<Paging<T, TNext>>> getFirstPage,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = default!,
|
||||||
|
CancellationToken cancellationToken = default!
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A Task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
IAsyncEnumerable<T> Paginate<T, TNext>(
|
||||||
|
Task<Paging<T, TNext>> firstPageTask,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = default!,
|
||||||
|
CancellationToken cancellationToken = default!
|
||||||
|
);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SpotifyAPI.Web.Http;
|
using SpotifyAPI.Web.Http;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace SpotifyAPI.Web
|
namespace SpotifyAPI.Web
|
||||||
{
|
{
|
||||||
@ -80,157 +82,287 @@ namespace SpotifyAPI.Web
|
|||||||
|
|
||||||
public IResponse? LastResponse { get; private set; }
|
public IResponse? LastResponse { get; private set; }
|
||||||
|
|
||||||
public Task<IList<T>> PaginateAll<T>(Paging<T> firstPage)
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">The first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
public Task<IList<T>> PaginateAll<T>(Paging<T> firstPage, IPaginator? paginator = null)
|
||||||
{
|
{
|
||||||
return DefaultPaginator.PaginateAll(firstPage, _apiConnector);
|
return (paginator ?? DefaultPaginator).PaginateAll(firstPage, _apiConnector);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IList<T>> PaginateAll<T>(Paging<T> firstPage, IPaginator paginator)
|
/// <summary>
|
||||||
{
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
return paginator.PaginateAll(firstPage, _apiConnector);
|
/// </summary>
|
||||||
}
|
/// <param name="getFirstPage">A function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
public async Task<IList<T>> PaginateAll<T>(Func<Task<Paging<T>>> getFirstPage)
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
public async Task<IList<T>> PaginateAll<T>(Func<Task<Paging<T>>> getFirstPage, IPaginator? paginator = null)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
||||||
|
|
||||||
return await DefaultPaginator.PaginateAll(
|
var firstPage = await getFirstPage().ConfigureAwait(false);
|
||||||
await getFirstPage().ConfigureAwait(false), _apiConnector
|
return await (paginator ?? DefaultPaginator).PaginateAll(firstPage, _apiConnector).ConfigureAwait(false);
|
||||||
).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IList<T>> PaginateAll<T>(Func<Task<Paging<T>>> getFirstPage, IPaginator paginator)
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
|
public async Task<IList<T>> PaginateAll<T>(Task<Paging<T>> firstPageTask, IPaginator? paginator = null)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(firstPageTask, nameof(firstPageTask));
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
|
||||||
|
|
||||||
return await paginator.PaginateAll(
|
var firstPage = await firstPageTask.ConfigureAwait(false);
|
||||||
await getFirstPage().ConfigureAwait(false), _apiConnector
|
return await (paginator ?? DefaultPaginator).PaginateAll(firstPage, _apiConnector).ConfigureAwait(false);
|
||||||
).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IList<T>> PaginateAll<T, TNext>(
|
|
||||||
Paging<T, TNext> firstPage,
|
|
||||||
Func<TNext, Paging<T, TNext>> mapper
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return DefaultPaginator.PaginateAll(firstPage, mapper, _apiConnector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IList<T>> PaginateAll<T, TNext>(
|
|
||||||
Func<Task<Paging<T, TNext>>> getFirstPage,
|
|
||||||
Func<TNext, Paging<T, TNext>> mapper
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
|
||||||
|
|
||||||
return await DefaultPaginator.PaginateAll(await getFirstPage().ConfigureAwait(false), mapper, _apiConnector).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">A first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>A list containing all fetched pages</returns>
|
||||||
public Task<IList<T>> PaginateAll<T, TNext>(
|
public Task<IList<T>> PaginateAll<T, TNext>(
|
||||||
Paging<T, TNext> firstPage,
|
Paging<T, TNext> firstPage,
|
||||||
Func<TNext, Paging<T, TNext>> mapper,
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
IPaginator paginator)
|
IPaginator? paginator = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
return (paginator ?? DefaultPaginator).PaginateAll(firstPage, mapper, _apiConnector);
|
||||||
|
|
||||||
return paginator.PaginateAll(firstPage, mapper, _apiConnector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
public async Task<IList<T>> PaginateAll<T, TNext>(
|
public async Task<IList<T>> PaginateAll<T, TNext>(
|
||||||
Func<Task<Paging<T, TNext>>> getFirstPage,
|
Func<Task<Paging<T, TNext>>> getFirstPage,
|
||||||
Func<TNext, Paging<T, TNext>> mapper,
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
IPaginator paginator
|
IPaginator? paginator = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
|
||||||
|
|
||||||
return await paginator.PaginateAll(
|
var firstPage = await getFirstPage().ConfigureAwait(false);
|
||||||
await getFirstPage().ConfigureAwait(false), mapper, _apiConnector
|
return await (paginator ?? DefaultPaginator).PaginateAll(firstPage, mapper, _apiConnector).ConfigureAwait(false);
|
||||||
).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches all pages and returns them grouped in a list.
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A Task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IList<T>> PaginateAll<T, TNext>(
|
||||||
|
Task<Paging<T, TNext>> firstPageTask,
|
||||||
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
|
IPaginator? paginator = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Ensure.ArgumentNotNull(firstPageTask, nameof(firstPageTask));
|
||||||
|
|
||||||
|
var firstPage = await firstPageTask.ConfigureAwait(false);
|
||||||
|
return await (paginator ?? DefaultPaginator).PaginateAll(firstPage, mapper, _apiConnector).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
#if NETSTANDARD2_1
|
#if NETSTANDARD2_1
|
||||||
public IAsyncEnumerable<T> Paginate<T>(Paging<T> firstPage)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">A first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>An iterable IAsyncEnumerable</returns>
|
||||||
|
public IAsyncEnumerable<T> Paginate<T>(
|
||||||
|
Paging<T> firstPage,
|
||||||
|
IPaginator? paginator = null,
|
||||||
|
CancellationToken cancellationToken = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return DefaultPaginator.Paginate(firstPage, _apiConnector);
|
return (paginator ?? DefaultPaginator).Paginate(firstPage, _apiConnector, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAsyncEnumerable<T> Paginate<T>(Paging<T> firstPage, IPaginator paginator)
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A Function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>An iterable IAsyncEnumerable</returns>
|
||||||
|
public async IAsyncEnumerable<T> Paginate<T>(
|
||||||
|
Func<Task<Paging<T>>> getFirstPage,
|
||||||
|
IPaginator? paginator = null,
|
||||||
|
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
|
||||||
|
|
||||||
return paginator.Paginate(firstPage, _apiConnector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async IAsyncEnumerable<T> Paginate<T>(Func<Task<Paging<T>>> getFirstPage)
|
|
||||||
{
|
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
||||||
|
|
||||||
var firstPage = await getFirstPage().ConfigureAwait(false);
|
var firstPage = await getFirstPage().ConfigureAwait(false);
|
||||||
await foreach (var item in DefaultPaginator.Paginate(firstPage, _apiConnector))
|
await foreach (var item in (paginator ?? DefaultPaginator)
|
||||||
|
.Paginate(firstPage, _apiConnector)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async IAsyncEnumerable<T> Paginate<T>(Func<Task<Paging<T>>> getFirstPage, IPaginator paginator)
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A Task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <returns>An iterable IAsyncEnumerable</returns>
|
||||||
|
public async IAsyncEnumerable<T> Paginate<T>(
|
||||||
|
Task<Paging<T>> firstPageTask,
|
||||||
|
IPaginator? paginator = null,
|
||||||
|
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(firstPageTask, nameof(firstPageTask));
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
|
||||||
|
|
||||||
var firstPage = await getFirstPage().ConfigureAwait(false);
|
var firstPage = await firstPageTask.ConfigureAwait(false);
|
||||||
await foreach (var item in DefaultPaginator.Paginate(firstPage, _apiConnector))
|
await foreach (var item in (paginator ?? DefaultPaginator)
|
||||||
|
.Paginate(firstPage, _apiConnector)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAsyncEnumerable<T> Paginate<T, TNext>(Paging<T, TNext> firstPage, Func<TNext, Paging<T, TNext>> mapper)
|
/// <summary>
|
||||||
{
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
return DefaultPaginator.Paginate(firstPage, mapper, _apiConnector);
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
}
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPage">A first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
public IAsyncEnumerable<T> Paginate<T, TNext>(
|
public IAsyncEnumerable<T> Paginate<T, TNext>(
|
||||||
Paging<T, TNext> firstPage,
|
Paging<T, TNext> firstPage,
|
||||||
Func<TNext, Paging<T, TNext>> mapper,
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
IPaginator paginator
|
IPaginator? paginator = null,
|
||||||
|
CancellationToken cancellationToken = default
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
return (paginator ?? DefaultPaginator).Paginate(firstPage, mapper, _apiConnector, cancellationToken);
|
||||||
|
|
||||||
return paginator.Paginate(firstPage, mapper, _apiConnector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="getFirstPage">A Function to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
public async IAsyncEnumerable<T> Paginate<T, TNext>(
|
public async IAsyncEnumerable<T> Paginate<T, TNext>(
|
||||||
Func<Task<Paging<T, TNext>>> getFirstPage,
|
Func<Task<Paging<T, TNext>>> getFirstPage,
|
||||||
Func<TNext, Paging<T, TNext>> mapper
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
)
|
IPaginator? paginator = null,
|
||||||
|
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
||||||
|
|
||||||
var firstPage = await getFirstPage().ConfigureAwait(false);
|
var firstPage = await getFirstPage().ConfigureAwait(false);
|
||||||
await foreach (var item in DefaultPaginator.Paginate(firstPage, mapper, _apiConnector))
|
await foreach (var item in (paginator ?? DefaultPaginator)
|
||||||
|
.Paginate(firstPage, mapper, _apiConnector)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Paginate through pages by using IAsyncEnumerable, introduced in C# 8
|
||||||
|
/// Some responses (e.g search response) have the pagination nested in a JSON Property.
|
||||||
|
/// To workaround this limitation, the mapper is required and needs to point to the correct next pagination.
|
||||||
|
/// The default paginator will fetch all available resources without a delay between requests.
|
||||||
|
/// This can drain your request limit quite fast, so consider using a custom paginator with delays.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstPageTask">A Task to retrive the first page, will be included in the output list!</param>
|
||||||
|
/// <param name="mapper">A function which maps response objects to the next paging object</param>
|
||||||
|
/// <param name="paginator">Optional. If not supplied, DefaultPaginator will be used</param>
|
||||||
|
/// <param name="cancellationToken">An optional Cancellation Token</param>
|
||||||
|
/// <typeparam name="T">The Paging-Type</typeparam>
|
||||||
|
/// <typeparam name="TNext">The Response-Type</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
public async IAsyncEnumerable<T> Paginate<T, TNext>(
|
public async IAsyncEnumerable<T> Paginate<T, TNext>(
|
||||||
Func<Task<Paging<T, TNext>>> getFirstPage,
|
Task<Paging<T, TNext>> firstPageTask,
|
||||||
Func<TNext, Paging<T, TNext>> mapper,
|
Func<TNext, Paging<T, TNext>> mapper,
|
||||||
IPaginator paginator
|
IPaginator? paginator = null,
|
||||||
)
|
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNull(getFirstPage, nameof(getFirstPage));
|
Ensure.ArgumentNotNull(firstPageTask, nameof(firstPageTask));
|
||||||
Ensure.ArgumentNotNull(paginator, nameof(paginator));
|
|
||||||
|
|
||||||
var firstPage = await getFirstPage().ConfigureAwait(false);
|
var firstPage = await firstPageTask.ConfigureAwait(false);
|
||||||
await foreach (var item in paginator.Paginate(firstPage, mapper, _apiConnector))
|
await foreach (var item in (paginator ?? DefaultPaginator)
|
||||||
|
.Paginate(firstPage, mapper, _apiConnector)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,30 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public class ShowEpisodesRequest : RequestParams
|
public class ShowEpisodesRequest : RequestParams
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of episodes to return. Default: 20. Minimum: 1. Maximum: 50.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
[QueryParam("limit")]
|
[QueryParam("limit")]
|
||||||
public int? Limit { get; set; }
|
public int? Limit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The index of the first episode to return.
|
||||||
|
/// Default: 0 (the first object). Use with limit to get the next set of episodes.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
[QueryParam("offset")]
|
[QueryParam("offset")]
|
||||||
public int? Offset { get; set; }
|
public int? Offset { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An ISO 3166-1 alpha-2 country code. If a country code is specified, only shows and episodes
|
||||||
|
/// that are available in that market will be returned.
|
||||||
|
/// If a valid user access token is specified in the request header,
|
||||||
|
/// the country associated with the user account will take priority over this parameter.
|
||||||
|
/// Note: If neither market or user country are provided, the content is considered unavailable for the client.
|
||||||
|
/// Users can view the country that is associated with their account in the account settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
[QueryParam("market")]
|
[QueryParam("market")]
|
||||||
public string? Market { get; set; }
|
public string? Market { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,16 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public class ShowRequest : RequestParams
|
public class ShowRequest : RequestParams
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An ISO 3166-1 alpha-2 country code. If a country code is specified,
|
||||||
|
/// only shows and episodes that are available in that market will be returned.
|
||||||
|
/// If a valid user access token is specified in the request header,
|
||||||
|
/// the country associated with the user account will take priority over this parameter.
|
||||||
|
/// Note: If neither market or user country are provided, the content
|
||||||
|
/// is considered unavailable for the client.
|
||||||
|
/// Users can view the country that is associated with their account in the account settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
[QueryParam("market")]
|
[QueryParam("market")]
|
||||||
public string? Market { get; set; }
|
public string? Market { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,12 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public class ShowsRequest : RequestParams
|
public class ShowsRequest : RequestParams
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get Spotify catalog information for several shows based on their Spotify IDs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ids">
|
||||||
|
/// A comma-separated list of the Spotify IDs for the shows. Maximum: 50 IDs.
|
||||||
|
/// </param>
|
||||||
public ShowsRequest(IList<string> ids)
|
public ShowsRequest(IList<string> ids)
|
||||||
{
|
{
|
||||||
Ensure.ArgumentNotNullOrEmptyList(ids, nameof(ids));
|
Ensure.ArgumentNotNullOrEmptyList(ids, nameof(ids));
|
||||||
@ -11,9 +17,23 @@ namespace SpotifyAPI.Web
|
|||||||
Ids = ids;
|
Ids = ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A comma-separated list of the Spotify IDs for the shows. Maximum: 50 IDs.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
[QueryParam("ids")]
|
[QueryParam("ids")]
|
||||||
public IList<string> Ids { get; }
|
public IList<string> Ids { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An ISO 3166-1 alpha-2 country code. If a country code is specified, only shows and episodes
|
||||||
|
/// that are available in that market will be returned.
|
||||||
|
/// If a valid user access token is specified in the request header,
|
||||||
|
/// the country associated with the user account will take priority over this parameter.
|
||||||
|
/// Note: If neither market or user country are provided,
|
||||||
|
/// the content is considered unavailable for the client.
|
||||||
|
/// Users can view the country that is associated with their account in the account settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
[QueryParam("market")]
|
[QueryParam("market")]
|
||||||
public string? Market { get; set; }
|
public string? Market { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public class CategoriesResponse
|
public class CategoriesResponse
|
||||||
{
|
{
|
||||||
public Paging<Category> Categories { get; set; } = default!;
|
public Paging<Category, CategoriesResponse> Categories { get; set; } = default!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ namespace SpotifyAPI.Web
|
|||||||
{
|
{
|
||||||
public class CategoryPlaylistsResponse
|
public class CategoryPlaylistsResponse
|
||||||
{
|
{
|
||||||
public Paging<SimplePlaylist> Playlists { get; set; } = default!;
|
public Paging<SimplePlaylist, CategoryPlaylistsResponse> Playlists { get; set; } = default!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ namespace SpotifyAPI.Web
|
|||||||
public class FeaturedPlaylistsResponse
|
public class FeaturedPlaylistsResponse
|
||||||
{
|
{
|
||||||
public string Message { get; set; } = default!;
|
public string Message { get; set; } = default!;
|
||||||
public Paging<SimplePlaylist> Playlists { get; set; } = default!;
|
public Paging<SimplePlaylist, FeaturedPlaylistsResponse> Playlists { get; set; } = default!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ namespace SpotifyAPI.Web
|
|||||||
public class NewReleasesResponse
|
public class NewReleasesResponse
|
||||||
{
|
{
|
||||||
public string Message { get; set; } = default!;
|
public string Message { get; set; } = default!;
|
||||||
public Paging<SimpleAlbum> Albums { get; set; } = default!;
|
public Paging<SimpleAlbum, NewReleasesResponse> Albums { get; set; } = default!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user