diff --git a/SpotifyAPI/Web/SpotifyWebAPI.cs b/SpotifyAPI/Web/SpotifyWebAPI.cs index 2960d665..79763111 100644 --- a/SpotifyAPI/Web/SpotifyWebAPI.cs +++ b/SpotifyAPI/Web/SpotifyWebAPI.cs @@ -5,7 +5,6 @@ using SpotifyAPI.Web.Models; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; namespace SpotifyAPI.Web @@ -88,13 +87,21 @@ namespace SpotifyAPI.Web /// public Paging GetAlbumTracks(String id, int limit = 20, int offset = 0, String market = "") { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/albums/" + id + "/tracks"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return DownloadData>(builder.ToString()); + return DownloadData>(_builder.GetAlbumTracks(id, limit, offset, market)); + } + + /// + /// Get Spotify catalog information about an album’s tracks asynchronously. Optional parameters can be used to limit the number of + /// tracks returned. + /// + /// The Spotify ID for the album. + /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first track to return. Default: 0 (the first object). + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + public Task> GetAlbumTracksAsync(String id, int limit = 20, int offset = 0, String market = "") + { + return DownloadDataAsync>(_builder.GetAlbumTracks(id, limit, offset, market)); } /// @@ -105,9 +112,18 @@ namespace SpotifyAPI.Web /// public FullAlbum GetAlbum(String id, String market = "") { - if (String.IsNullOrEmpty(market)) - return DownloadData(APIBase + "/albums/" + id); - return DownloadData(APIBase + "/albums/" + id + "?market=" + market); + return DownloadData(_builder.GetAlbum(id, market)); + } + + /// + /// Get Spotify catalog information for a single album asynchronously. + /// + /// The Spotify ID for the album. + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + public Task GetAlbumAsync(String id, String market = "") + { + return DownloadDataAsync(_builder.GetAlbum(id, market)); } /// @@ -118,9 +134,18 @@ namespace SpotifyAPI.Web /// public SeveralAlbums GetSeveralAlbums(List ids, String market = "") { - if (String.IsNullOrEmpty(market)) - return DownloadData(APIBase + "/albums?ids=" + string.Join(",", ids.Take(20))); - return DownloadData(APIBase + "/albums?market=" + market + "&ids=" + string.Join(",", ids.Take(20))); + return DownloadData(_builder.GetSeveralAlbums(ids, market)); + } + + /// + /// Get Spotify catalog information for multiple albums identified by their Spotify IDs asynchrously. + /// + /// A list of the Spotify IDs for the albums. Maximum: 20 IDs. + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + public Task GetSeveralAlbumsAsync(List ids, String market = "") + { + return DownloadDataAsync(_builder.GetSeveralAlbums(ids, market)); } #endregion Albums @@ -134,7 +159,17 @@ namespace SpotifyAPI.Web /// public FullArtist GetArtist(String id) { - return DownloadData(APIBase + "/artists/" + id); + return DownloadData(_builder.GetArtist(id)); + } + + /// + /// Get Spotify catalog information for a single artist identified by their unique Spotify ID asynchronously. + /// + /// The Spotify ID for the artist. + /// + public Task GetArtistAsync(String id) + { + return DownloadDataAsync(_builder.GetArtist(id)); } /// @@ -145,7 +180,18 @@ namespace SpotifyAPI.Web /// public SeveralArtists GetRelatedArtists(String id) { - return DownloadData(APIBase + "/artists/" + id + "/related-artists"); + return DownloadData(_builder.GetRelatedArtists(id)); + } + + /// + /// Get Spotify catalog information about artists similar to a given artist asynchronously. Similarity is based on analysis of the + /// Spotify community’s listening history. + /// + /// The Spotify ID for the artist. + /// + public Task GetRelatedArtistsAsync(String id) + { + return DownloadDataAsync(_builder.GetRelatedArtists(id)); } /// @@ -156,7 +202,18 @@ namespace SpotifyAPI.Web /// public SeveralTracks GetArtistsTopTracks(String id, String country) { - return DownloadData(APIBase + "/artists/" + id + "/top-tracks?country=" + country); + return DownloadData(_builder.GetArtistsTopTracks(id, country)); + } + + /// + /// Get Spotify catalog information about an artist’s top tracks by country asynchronously. + /// + /// The Spotify ID for the artist. + /// The country: an ISO 3166-1 alpha-2 country code. + /// + public Task GetArtistsTopTracksAsync(String id, String country) + { + return DownloadDataAsync(_builder.GetArtistsTopTracks(id, country)); } /// @@ -177,14 +234,28 @@ namespace SpotifyAPI.Web /// public Paging GetArtistsAlbums(String id, AlbumType type = AlbumType.All, int limit = 20, int offset = 0, String market = "") { - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/artists/" + id + "/albums"); - builder.Append("?type=" + type.GetStringAttribute(",")); - builder.Append("&limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return DownloadData>(builder.ToString()); + return DownloadData>(_builder.GetArtistsAlbums(id, type, limit, offset, market)); + } + + /// + /// Get Spotify catalog information about an artist’s albums asynchronously. Optional parameters can be specified in the query string + /// to filter and sort the response. + /// + /// The Spotify ID for the artist. + /// + /// A list of keywords that will be used to filter the response. If not supplied, all album types will + /// be returned + /// + /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first album to return. Default: 0 + /// + /// An ISO 3166-1 alpha-2 country code. Supply this parameter to limit the response to one particular + /// geographical market + /// + /// + public Task> GetArtistsAlbumsAsync(String id, AlbumType type = AlbumType.All, int limit = 20, int offset = 0, String market = "") + { + return DownloadDataAsync>(_builder.GetArtistsAlbums(id, type, limit, offset, market)); } /// @@ -194,7 +265,17 @@ namespace SpotifyAPI.Web /// public SeveralArtists GetSeveralArtists(List ids) { - return DownloadData(APIBase + "/artists?ids=" + string.Join(",", ids.Take(50))); + return DownloadData(_builder.GetSeveralArtists(ids)); + } + + /// + /// Get Spotify catalog information for several artists based on their Spotify IDs asynchronously. + /// + /// A list of the Spotify IDs for the artists. Maximum: 50 IDs. + /// + public Task GetSeveralArtistsAsync(List ids) + { + return DownloadDataAsync(_builder.GetSeveralArtists(ids)); } #endregion Artists @@ -217,17 +298,26 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetFeaturedPlaylists"); - limit = Math.Max(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/browse/featured-playlists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(locale)) - builder.Append("&locale=" + locale); - if (!String.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - if (timestamp != default(DateTime)) - builder.Append("×tamp=" + timestamp.ToString("yyyy-MM-ddTHH:mm:ss")); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetFeaturedPlaylists(locale, country, timestamp, limit, offset)); + } + + /// + /// Get a list of Spotify featured playlists asynchronously (shown, for example, on a Spotify player’s “Browse” tab). + /// + /// + /// The desired language, consisting of a lowercase ISO 639 language code and an uppercase ISO 3166-1 + /// alpha-2 country code, joined by an underscore. + /// + /// A country: an ISO 3166-1 alpha-2 country code. + /// A timestamp in ISO 8601 format + /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first item to return. Default: 0 + /// AUTH NEEDED + public Task GetFeaturedPlaylistsAsync(String locale = "", String country = "", DateTime timestamp = default(DateTime), int limit = 20, int offset = 0) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetFeaturedPlaylists"); + return DownloadDataAsync(_builder.GetFeaturedPlaylists(locale, country, timestamp, limit, offset)); } /// @@ -242,13 +332,22 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetNewAlbumReleases"); - limit = Math.Max(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/browse/new-releases"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetNewAlbumReleases(country, limit, offset)); + } + + /// + /// Get a list of new album releases featured in Spotify asynchronously (shown, for example, on a Spotify player’s “Browse” tab). + /// + /// A country: an ISO 3166-1 alpha-2 country code. + /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first item to return. Default: 0 + /// + /// AUTH NEEDED + public Task GetNewAlbumReleasesAsync(String country = "", int limit = 20, int offset = 0) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetNewAlbumReleases"); + return DownloadDataAsync(_builder.GetNewAlbumReleases(country, limit, offset)); } /// @@ -270,15 +369,29 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetCategories"); - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder(APIBase + "/browse/categories"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - if (!String.IsNullOrEmpty(locale)) - builder.Append("&locale=" + locale); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetCategories(country, locale, limit, offset)); + } + + /// + /// Get a list of categories used to tag items in Spotify asynchronously (on, for example, the Spotify player’s “Browse” tab). + /// + /// + /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want to narrow the + /// list of returned categories to those relevant to a particular country + /// + /// + /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country + /// code, joined by an underscore + /// + /// The maximum number of categories to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first item to return. Default: 0 (the first object). + /// + /// AUTH NEEDED + public Task GetCategoriesAsync(String country = "", String locale = "", int limit = 20, int offset = 0) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetCategories"); + return DownloadDataAsync(_builder.GetCategories(country, locale, limit, offset)); } /// @@ -297,12 +410,26 @@ namespace SpotifyAPI.Web /// AUTH NEEDED public Category GetCategory(String categoryId, String country = "", String locale = "") { - StringBuilder builder = new StringBuilder(APIBase + "/browse/categories/" + categoryId); - if (!String.IsNullOrEmpty(country)) - builder.Append("?country=" + country); - if (!String.IsNullOrEmpty(locale)) - builder.Append((country == "" ? "?locale=" : "&locale=") + locale); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetCategory(categoryId, country, locale)); + } + + /// + /// Get a single category used to tag items in Spotify asynchronously (on, for example, the Spotify player’s “Browse” tab). + /// + /// The Spotify category ID for the category. + /// + /// A country: an ISO 3166-1 alpha-2 country code. Provide this parameter to ensure that the category + /// exists for a particular country. + /// + /// + /// The desired language, consisting of an ISO 639 language code and an ISO 3166-1 alpha-2 country + /// code, joined by an underscore + /// + /// + /// AUTH NEEDED + public Task GetCategoryAsync(String categoryId, String country = "", String locale = "") + { + return DownloadDataAsync(_builder.GetCategory(categoryId, country, locale)); } /// @@ -316,13 +443,21 @@ namespace SpotifyAPI.Web /// AUTH NEEDED public CategoryPlaylist GetCategoryPlaylists(String categoryId, String country = "", int limit = 20, int offset = 0) { - limit = Math.Min(50, limit); - StringBuilder builder = new StringBuilder(APIBase + "/browse/categories/" + categoryId + "/playlists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(country)) - builder.Append("&country=" + country); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetCategoryPlaylists(categoryId, country, limit, offset)); + } + + /// + /// Get a list of Spotify playlists tagged with a particular category asynchronously. + /// + /// The Spotify category ID for the category. + /// A country: an ISO 3166-1 alpha-2 country code. + /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first item to return. Default: 0 + /// + /// AUTH NEEDED + public Task GetCategoryPlaylistsAsync(String categoryId, String country = "", int limit = 20, int offset = 0) + { + return DownloadDataAsync(_builder.GetCategoryPlaylists(categoryId, country, limit, offset)); } #endregion Browse @@ -332,21 +467,31 @@ namespace SpotifyAPI.Web /// /// Get the current user’s followed artists. /// + /// The ID type: currently only artist is supported. /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. /// The last artist ID retrieved from the previous request. /// /// AUTH NEEDED - public FollowedArtists GetFollowedArtists(int limit = 20, String after = "") + public FollowedArtists GetFollowedArtists(FollowType followType, int limit = 20, String after = "") { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetFollowedArtists"); - limit = Math.Max(limit, 50); - const FollowType followType = FollowType.Artist; //currently only artist is supported. - StringBuilder builder = new StringBuilder(APIBase + "/me/following?type=" + followType.GetStringAttribute("")); - builder.Append("&limit=" + limit); - if (!String.IsNullOrEmpty(after)) - builder.Append("&after=" + after); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetFollowedArtists(followType, limit, after)); + } + + /// + /// Get the current user’s followed artists asynchronously. + /// + /// The ID type: currently only artist is supported. + /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. + /// The last artist ID retrieved from the previous request. + /// + /// AUTH NEEDED + public Task GetFollowedArtistsAsync(FollowType followType, int limit = 20, String after = "") + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetFollowedArtists"); + return DownloadDataAsync(_builder.GetFollowedArtists(followType, limit, after)); } /// @@ -362,7 +507,25 @@ namespace SpotifyAPI.Web { {"ids", new JArray(ids)} }; - return UploadData(APIBase + "/me/following?type=" + followType.GetStringAttribute(""), ob.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + return UploadData(_builder.Follow(followType, ids), ob.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + } + + /// + /// Add the current user as a follower of one or more artists or other Spotify users asynchronously. + /// + /// The ID type: either artist or user. + /// A list of the artist or the user Spotify IDs + /// + /// AUTH NEEDED + public Task FollowAsync(FollowType followType, List ids) + { + JObject ob = new JObject + { + {"ids", new JArray(ids)} + }; + return + UploadDataAsync(_builder.Follow(followType, ids), + ob.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// @@ -377,6 +540,18 @@ namespace SpotifyAPI.Web return Follow(followType, new List { id }); } + /// + /// Add the current user as a follower of one or more artists or other Spotify users asynchronously. + /// + /// The ID type: either artist or user. + /// Artists or the Users Spotify ID + /// + /// AUTH NEEDED + public Task FollowAsync(FollowType followType, String id) + { + return FollowAsync(followType, new List { id }); + } + /// /// Remove the current user as a follower of one or more artists or other Spotify users. /// @@ -390,7 +565,23 @@ namespace SpotifyAPI.Web { {"ids", new JArray(ids)} }; - return UploadData(APIBase + "/me/following?type=" + followType.GetStringAttribute(""), ob.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); + return UploadData(_builder.Unfollow(followType, ids), ob.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); + } + + /// + /// Remove the current user as a follower of one or more artists or other Spotify users asynchronously. + /// + /// The ID type: either artist or user. + /// A list of the artist or the user Spotify IDs + /// + /// AUTH NEEDED + public Task UnfollowAsync(FollowType followType, List ids) + { + JObject ob = new JObject + { + {"ids", new JArray(ids)} + }; + return UploadDataAsync(_builder.Unfollow(followType, ids), ob.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); } /// @@ -405,6 +596,18 @@ namespace SpotifyAPI.Web return Unfollow(followType, new List { id }); } + /// + /// Remove the current user as a follower of one or more artists or other Spotify users asynchronously. + /// + /// The ID type: either artist or user. + /// Artists or the Users Spotify ID + /// + /// AUTH NEEDED + public Task UnfollowAsync(FollowType followType, String id) + { + return UnfollowAsync(followType, new List { id }); + } + /// /// Check to see if the current user is following one or more artists or other Spotify users. /// @@ -416,12 +619,30 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for IsFollowing"); - JToken res = DownloadData(APIBase + "/me/following/contains?type=" + followType.GetStringAttribute("") + "&ids=" + string.Join(",", ids)); + JToken res = DownloadData(_builder.IsFollowing(followType, ids)); if (res is JArray) return new ListResponse { List = res.ToObject>(), Error = null }; return new ListResponse { List = null, Error = res["error"].ToObject() }; } + /// + /// Check to see if the current user is following one or more artists or other Spotify users asynchronously. + /// + /// The ID type: either artist or user. + /// A list of the artist or the user Spotify IDs to check + /// + /// AUTH NEEDED + public Task> IsFollowingAsync(FollowType followType, List ids) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for IsFollowing"); + JToken res = DownloadDataAsync(_builder.IsFollowing(followType, ids)); +# Compilebreaker + if (res is JArray) //todo expression is always false + return Task.FromResult(new ListResponse { List = res.ToObject>(), Error = null }); + return Task.FromResult(new ListResponse { List = null, Error = res["error"].ToObject() }); + } + /// /// Check to see if the current user is following one artist or another Spotify user. /// @@ -434,6 +655,18 @@ namespace SpotifyAPI.Web return IsFollowing(followType, new List { id }); } + /// + /// Check to see if the current user is following one artist or another Spotify user asynchronously. + /// + /// The ID type: either artist or user. + /// Artists or the Users Spotify ID + /// + /// AUTH NEEDED + public Task> IsFollowingAsync(FollowType followType, String id) + { + return IsFollowingAsync(followType, new List { id }); + } + /// /// Add the current user as a follower of a playlist. /// @@ -454,7 +687,30 @@ namespace SpotifyAPI.Web { {"public", showPublic} }; - return UploadData(APIBase + "/users/" + ownerId + "/playlists/" + playlistId + "/followers", body.ToString(Formatting.None), "PUT"); + return UploadData(_builder.FollowPlaylist(ownerId, playlistId, showPublic), body.ToString(Formatting.None), "PUT"); + } + + /// + /// Add the current user as a follower of a playlist asynchronously. + /// + /// The Spotify user ID of the person who owns the playlist. + /// + /// The Spotify ID of the playlist. Any playlist can be followed, regardless of its public/private + /// status, as long as you know its playlist ID. + /// + /// + /// If true the playlist will be included in user's public playlists, if false it will remain + /// private. + /// + /// + /// AUTH NEEDED + public Task FollowPlaylistAsync(String ownerId, String playlistId, bool showPublic = true) + { + JObject body = new JObject + { + {"public", showPublic} + }; + return UploadDataAsync(_builder.FollowPlaylist(ownerId, playlistId, showPublic), body.ToString(Formatting.None), "PUT"); } /// @@ -466,7 +722,19 @@ namespace SpotifyAPI.Web /// AUTH NEEDED public ErrorResponse UnfollowPlaylist(String ownerId, String playlistId) { - return UploadData(APIBase + "/users/" + ownerId + "/playlists/" + playlistId + "/followers", "", "DELETE"); + return UploadData(_builder.UnfollowPlaylist(ownerId, playlistId), "", "DELETE"); + } + + /// + /// Remove the current user as a follower of a playlist asynchronously. + /// + /// The Spotify user ID of the person who owns the playlist. + /// The Spotify ID of the playlist that is to be no longer followed. + /// + /// AUTH NEEDED + public Task UnfollowPlaylistAsync(String ownerId, String playlistId) + { + return UploadDataAsync(_builder.UnfollowPlaylist(ownerId, playlistId), "", "DELETE"); } /// @@ -481,12 +749,31 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for IsFollowingPlaylist"); - JToken res = DownloadData(APIBase + "/users/" + ownerId + "/playlists/" + playlistId + "/followers/contains?ids=" + string.Join(",", ids)); + JToken res = DownloadData(_builder.IsFollowingPlaylist(ownerId, playlistId, ids)); if (res is JArray) return new ListResponse { List = res.ToObject>(), Error = null }; return new ListResponse { List = null, Error = res["error"].ToObject() }; } + /// + /// Check to see if one or more Spotify users are following a specified playlist asynchronously. + /// + /// The Spotify user ID of the person who owns the playlist. + /// The Spotify ID of the playlist. + /// A list of Spotify User IDs + /// + /// AUTH NEEDED + public Task> IsFollowingPlaylistAsync(String ownerId, String playlistId, List ids) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for IsFollowingPlaylist"); + JToken res = DownloadDataAsync(_builder.IsFollowingPlaylist(ownerId, playlistId, ids)); +# Compilebreaker + if (res is JArray) //todo expression is always false + return Task.FromResult(new ListResponse { List = res.ToObject>(), Error = null }); + return Task.FromResult(new ListResponse { List = null, Error = res["error"].ToObject() }); + } + /// /// Check to see if one or more Spotify users are following a specified playlist. /// @@ -500,6 +787,19 @@ namespace SpotifyAPI.Web return IsFollowingPlaylist(ownerId, playlistId, new List { id }); } + /// + /// Check to see if one or more Spotify users are following a specified playlist asynchronously. + /// + /// The Spotify user ID of the person who owns the playlist. + /// The Spotify ID of the playlist. + /// A Spotify User ID + /// + /// AUTH NEEDED + public Task> IsFollowingPlaylistAsync(String ownerId, String playlistId, String id) + { + return IsFollowingPlaylistAsync(ownerId, playlistId, new List { id }); + } + #endregion Follow #region Library @@ -513,7 +813,19 @@ namespace SpotifyAPI.Web public ErrorResponse SaveTracks(List ids) { JArray array = new JArray(ids); - return UploadData(APIBase + "/me/tracks/", array.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + return UploadData(_builder.SaveTracks(array.ToString(Formatting.None), "PUT") ?? new ErrorResponse()); + } + + /// + /// Save one or more tracks to the current user’s “Your Music” library asynchronously. + /// + /// A list of the Spotify IDs + /// + /// AUTH NEEDED + public Task SaveTracksAsync(List ids) + { + JArray array = new JArray(ids); + return UploadDataAsync(_builder.SaveTracks(array.ToString(Formatting.None), "PUT") ?? new ErrorResponse()); } /// @@ -527,6 +839,17 @@ namespace SpotifyAPI.Web return SaveTracks(new List { id }); } + /// + /// Save one track to the current user’s “Your Music” library asynchronously. + /// + /// A Spotify ID + /// + /// AUTH NEEDED + public Task SaveTrackAsync(String id) + { + return SaveTracksAsync(new List { id }); + } + /// /// Get a list of the songs saved in the current Spotify user’s “Your Music” library. /// @@ -539,13 +862,22 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetSavedTracks"); - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/me/tracks"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return DownloadData>(builder.ToString()); + return DownloadData>(_builder.GetSavedTracks(limit, offset, market)); + } + + /// + /// Get a list of the songs saved in the current Spotify user’s “Your Music” library asynchronously. + /// + /// The maximum number of objects to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first object to return. Default: 0 (i.e., the first object) + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + /// AUTH NEEDED + public Task> GetSavedTracksAsync(int limit = 20, int offset = 0, String market = "") + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetSavedTracks"); + return DownloadDataAsync>(_builder.GetSavedTracks(limit, offset, market)); } /// @@ -557,7 +889,19 @@ namespace SpotifyAPI.Web public ErrorResponse RemoveSavedTracks(List ids) { JArray array = new JArray(ids); - return UploadData(APIBase + "/me/tracks/", array.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); + return UploadData(_builder.RemoveSavedTracks(array.ToString(Formatting.None), "DELETE") ?? new ErrorResponse()); + } + + /// + /// Remove one or more tracks from the current user’s “Your Music” library asynchronously. + /// + /// A list of the Spotify IDs. + /// + /// AUTH NEEDED + public Task RemoveSavedTracksAsync(List ids) + { + JArray array = new JArray(ids); + return UploadDataAsync(_builder.RemoveSavedTracks(array.ToString(Formatting.None), "DELETE") ?? new ErrorResponse()); } /// @@ -570,12 +914,29 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for CheckSavedTracks"); - JToken res = DownloadData(APIBase + "/me/tracks/contains?ids=" + string.Join(",", ids)); + JToken res = DownloadData(_builder.CheckSavedTracks(ids)); if (res is JArray) return new ListResponse { List = res.ToObject>(), Error = null }; return new ListResponse { List = null, Error = res["error"].ToObject() }; } + /// + /// Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library asynchronously. + /// + /// A list of the Spotify IDs. + /// + /// AUTH NEEDED + public Task> CheckSavedTracksAsync(List ids) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for CheckSavedTracks"); + JToken res = DownloadDataAsync(_builder.CheckSavedTracks(ids)); +# Compilebreaker + if (res is JArray) //todo expression is always false + return Task.FromResult(new ListResponse { List = res.ToObject>(), Error = null }); + return Task.FromResult(new ListResponse { List = null, Error = res["error"].ToObject() }); + } + #endregion Library #region Playlists @@ -592,11 +953,22 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetUserPlaylists"); - limit = Math.Min(limit, 50); - StringBuilder builder = new StringBuilder(APIBase + "/users/" + userId + "/playlists"); - builder.Append("?limit=" + limit); - builder.Append("&offset=" + offset); - return DownloadData>(builder.ToString()); + return DownloadData>(_builder.GetUserPlaylists(userId, limit, offset)); + } + + /// + /// Get a list of the playlists owned or followed by a Spotify user asynchronously. + /// + /// The user's Spotify user ID. + /// The maximum number of playlists to return. Default: 20. Minimum: 1. Maximum: 50. + /// The index of the first playlist to return. Default: 0 (the first object) + /// + /// AUTH NEEDED + public Task> GetUserPlaylistsAsync(String userId, int limit = 20, int offset = 0) + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetUserPlaylists"); + return DownloadDataAsync>(_builder.GetUserPlaylists(userId, limit, offset)); } /// @@ -615,11 +987,26 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetPlaylist"); - StringBuilder builder = new StringBuilder(APIBase + "/users/" + userId + "/playlists/" + playlistId); - builder.Append("?fields=" + fields); - if (!String.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return DownloadData(builder.ToString()); + return DownloadData(_builder.GetPlaylist(userId, playlistId, fields, market)); + } + + /// + /// Get a playlist owned by a Spotify user asynchronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// + /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are + /// returned. + /// + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + /// AUTH NEEDED + public Task GetPlaylistAsync(String userId, String playlistId, String fields = "", String market = "") + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetPlaylist"); + return DownloadDataAsync(_builder.GetPlaylist(userId, playlistId, fields, market)); } /// @@ -640,14 +1027,28 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetPlaylistTracks"); - limit = Math.Max(limit, 100); - StringBuilder builder = new StringBuilder(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks"); - builder.Append("?fields=" + fields); - builder.Append("&limit=" + limit); - builder.Append("&offset=" + offset); - if (!String.IsNullOrEmpty(market)) - builder.Append("&market=" + market); - return DownloadData>(builder.ToString()); + return DownloadData>(_builder.GetPlaylistTracks(userId, playlistId, fields, limit, offset, market)); + } + + /// + /// Get full details of the tracks of a playlist owned by a Spotify user asyncronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// + /// Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are + /// returned. + /// + /// The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100. + /// The index of the first object to return. Default: 0 (i.e., the first object) + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + /// AUTH NEEDED + public Task> GetPlaylistTracksAsync(String userId, String playlistId, String fields = "", int limit = 100, int offset = 0, String market = "") + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetPlaylistTracks"); + return DownloadDataAsync>(_builder.GetPlaylistTracks(userId, playlistId, fields, limit, offset, market)); } /// @@ -671,7 +1072,31 @@ namespace SpotifyAPI.Web {"name", playlistName}, {"public", isPublic} }; - return UploadData(APIBase + "/users/" + userId + "/playlists", body.ToString(Formatting.None)); + return UploadData(_builder.CreatePlaylist(userId, playlistName, isPublic), body.ToString(Formatting.None)); + } + + /// + /// Create a playlist for a Spotify user asynchronously. (The playlist will be empty until you add tracks.) + /// + /// The user's Spotify user ID. + /// + /// The name for the new playlist, for example "Your Coolest Playlist". This name does not need + /// to be unique. + /// + /// + /// default true. If true the playlist will be public, if false it will be private. To be able to + /// create private playlists, the user must have granted the playlist-modify-private scope. + /// + /// + /// AUTH NEEDED + public Task CreatePlaylistAsync(String userId, String playlistName, Boolean isPublic = true) + { + JObject body = new JObject + { + {"name", playlistName}, + {"public", isPublic} + }; + return UploadDataAsync(_builder.CreatePlaylist(userId, playlistName, isPublic), body.ToString(Formatting.None)); } /// @@ -690,7 +1115,26 @@ namespace SpotifyAPI.Web body.Add("name", newName); if (newPublic != null) body.Add("public", newPublic); - return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId, body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + return UploadData(_builder.UpdatePlaylist(userId, playlistId, newName, newPublic), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + } + + /// + /// Change a playlist’s name and public/private state asynchronously. (The user must, of course, own the playlist.) + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// The new name for the playlist, for example "My New Playlist Title". + /// If true the playlist will be public, if false it will be private. + /// + /// AUTH NEEDED + public Task UpdatePlaylistAsync(String userId, String playlistId, String newName = null, Boolean? newPublic = null) + { + JObject body = new JObject(); + if (newName != null) + body.Add("name", newName); + if (newPublic != null) + body.Add("public", newPublic); + return UploadDataAsync(_builder.UpdatePlaylist(userId, playlistId, newName, newPublic), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// @@ -708,7 +1152,25 @@ namespace SpotifyAPI.Web { {"uris", new JArray(uris.Take(100))} }; - return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + return UploadData(_builder.ReplacePlaylistTracks(userId, playlistId, uris), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); + } + + /// + /// Replace all the tracks in a playlist asynchronously, overwriting its existing tracks. This powerful request can be useful for + /// replacing tracks, re-ordering existing tracks, or clearing the playlist. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// A list of Spotify track URIs to set. A maximum of 100 tracks can be set in one request. + /// + /// AUTH NEEDED + public Task ReplacePlaylistTracksAsync(String userId, String playlistId, List uris) + { + JObject body = new JObject + { + {"uris", new JArray(uris.Take(100))} + }; + return UploadDataAsync(_builder.ReplacePlaylistTracks(userId, playlistId, uris), body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// @@ -728,7 +1190,27 @@ namespace SpotifyAPI.Web { {"tracks", JArray.FromObject(uris.Take(100))} }; - return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); + return UploadData(_builder.RemovePlaylistTracks(userId, playlistId, uris), body.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); + } + + /// + /// Remove one or more tracks from a user’s playlist asynchronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// + /// array of objects containing Spotify URI strings (and their position in the playlist). A maximum of + /// 100 objects can be sent at once. + /// + /// + /// AUTH NEEDED + public Task RemovePlaylistTracksAsync(String userId, String playlistId, List uris) + { + JObject body = new JObject + { + {"tracks", JArray.FromObject(uris.Take(100))} + }; + return UploadDataAsync(_builder.RemovePlaylistTracks(userId, playlistId, uris), body.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); } /// @@ -744,6 +1226,19 @@ namespace SpotifyAPI.Web return RemovePlaylistTracks(userId, playlistId, new List { uri }); } + /// + /// Remove one or more tracks from a user’s playlist asynchronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// Spotify URI + /// + /// AUTH NEEDED + public Task RemovePlaylistTrackAsync(String userId, String playlistId, DeleteTrackUri uri) + { + return RemovePlaylistTracksAsync(userId, playlistId, new List { uri }); + } + /// /// Add one or more tracks to a user’s playlist. /// @@ -759,9 +1254,25 @@ namespace SpotifyAPI.Web { {"uris", JArray.FromObject(uris.Take(100))} }; - if (position == null) - return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None)) ?? new ErrorResponse(); - return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks?position=" + position, body.ToString(Formatting.None)) ?? new ErrorResponse(); + return UploadData(_builder.AddPlaylistTracks(userId, playlistId, uris, position), body.ToString(Formatting.None)) ?? new ErrorResponse(); + } + + /// + /// Add one or more tracks to a user’s playlist asynchronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// A list of Spotify track URIs to add + /// The position to insert the tracks, a zero-based index + /// + /// AUTH NEEDED + public Task AddPlaylistTracksAsync(String userId, String playlistId, List uris, int? position = null) + { + JObject body = new JObject + { + {"uris", JArray.FromObject(uris.Take(100))} + }; + return UploadDataAsync(_builder.AddPlaylistTracks(userId, playlistId, uris, position), body.ToString(Formatting.None)) ?? new ErrorResponse(); } /// @@ -778,6 +1289,20 @@ namespace SpotifyAPI.Web return AddPlaylistTracks(userId, playlistId, new List { uri }, position); } + /// + /// Add one or more tracks to a user’s playlist asynchronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// A Spotify Track URI + /// The position to insert the tracks, a zero-based index + /// + /// AUTH NEEDED + public Task AddPlaylistTrackAsync(String userId, String playlistId, String uri, int? position = null) + { + return AddPlaylistTracksAsync(userId, playlistId, new List { uri }, position); + } + /// /// Reorder a track or a group of tracks in a playlist. /// @@ -799,7 +1324,29 @@ namespace SpotifyAPI.Web }; if (!String.IsNullOrEmpty(snapshotId)) body.Add("snapshot_id", snapshotId); - return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None), "PUT"); + return UploadData(_builder.ReorderPlaylist(userId, playlistId, rangeStart, insertBefore, rangeLength, snapshotId), body.ToString(Formatting.None), "PUT"); + } + + /// + /// Reorder a track or a group of tracks in a playlist asynchronously. + /// + /// The user's Spotify user ID. + /// The Spotify ID for the playlist. + /// The position of the first track to be reordered. + /// The position where the tracks should be inserted. + /// The amount of tracks to be reordered. Defaults to 1 if not set. + /// The playlist's snapshot ID against which you want to make the changes. + /// + /// AUTH NEEDED + public Task ReorderPlaylistAsync(String userId, String playlistId, int rangeStart, int insertBefore, int rangeLength = 1, String snapshotId = "") + { + JObject body = new JObject + { + {"range_start", rangeStart}, + {"range_length", rangeLength}, + {"insert_before", insertBefore} + }; + return UploadDataAsync(_builder.ReorderPlaylist(userId, playlistId, rangeStart, insertBefore, rangeLength, snapshotId), body.ToString(Formatting.None), "PUT"); } #endregion Playlists @@ -815,7 +1362,19 @@ namespace SpotifyAPI.Web { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetPrivateProfile"); - return DownloadData(APIBase + "/me"); + return DownloadData(_builder.GetPrivateProfile()); + } + + /// + /// Get detailed profile information about the current user asynchronously (including the current user’s username). + /// + /// + /// AUTH NEEDED + public Task GetPrivateProfileAsync() + { + if (!UseAuth) + throw new InvalidOperationException("Auth is required for GetPrivateProfile"); + return DownloadDataAsync(_builder.GetPrivateProfile()); } /// @@ -825,7 +1384,17 @@ namespace SpotifyAPI.Web /// public PublicProfile GetPublicProfile(String userId) { - return DownloadData(APIBase + "/users/" + userId); + return DownloadData(_builder.GetPublicProfile(userId)); + } + + /// + /// Get public profile information about a Spotify user asynchronously. + /// + /// The user's Spotify user ID. + /// + public Task GetPublicProfileAsync(String userId) + { + return DownloadDataAsync(_builder.GetPublicProfile(userId)); } #endregion Profiles @@ -840,9 +1409,18 @@ namespace SpotifyAPI.Web /// public SeveralTracks GetSeveralTracks(List ids, String market = "") { - if (String.IsNullOrEmpty(market)) - return DownloadData(APIBase + "/tracks?ids=" + string.Join(",", ids.Take(50))); - return DownloadData(APIBase + "/tracks?market=" + market + "&ids=" + string.Join(",", ids.Take(50))); + return DownloadData(_builder.GetSeveralTracks(ids, market)); + } + + /// + /// Get Spotify catalog information for multiple tracks based on their Spotify IDs asynchronously. + /// + /// A list of the Spotify IDs for the tracks. Maximum: 50 IDs. + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + public Task GetSeveralTracksAsync(List ids, String market = "") + { + return DownloadDataAsync(_builder.GetSeveralTracks(ids, market)); } /// @@ -853,9 +1431,18 @@ namespace SpotifyAPI.Web /// public FullTrack GetTrack(String id, String market = "") { - if (String.IsNullOrEmpty(market)) - return DownloadData(APIBase + "/tracks/" + id); - return DownloadData(APIBase + "/tracks/" + id + "?market=" + market); + return DownloadData(_builder.GetTrack(id, market)); + } + + /// + /// Get Spotify catalog information for a single track identified by its unique Spotify ID asynchronously. + /// + /// The Spotify ID for the track. + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// + public Task GetTrackAsync(String id, String market = "") + { + return DownloadDataAsync(_builder.GetTrack(id, market)); } #endregion Tracks