using System; using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SpotifyAPI.Web.Enums; using SpotifyAPI.Web.Models; namespace SpotifyAPI.Web { public sealed class SpotifyWebAPI : IDisposable { public const String APIBase = "https://api.spotify.com/v1"; public SpotifyWebAPI() { UseAuth = true; WebClient = new SpotifyWebClient { JsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, TypeNameHandling = TypeNameHandling.All } }; } public String TokenType { get; set; } public String AccessToken { get; set; } public Boolean UseAuth { get; set; } public IClient WebClient { get; set; } public void Dispose() { WebClient.Dispose(); GC.SuppressFinalize(this); } #region Search /// /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string. /// /// The search query's keywords (and optional field filters and operators), for example q=roadhouse+blues. /// A list of item types to search across. /// The maximum number of items to return. Default: 20. Minimum: 1. Maximum: 50. /// The index of the first result to return. Default: 0 /// An ISO 3166-1 alpha-2 country code or the string from_token. /// public SearchItem SearchItems(String q, SearchType type, int limit = 20, int offset = 0, String market = "") { limit = Math.Min(50, limit); StringBuilder builder = new StringBuilder(APIBase + "/search"); builder.Append("?q=" + q); 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()); } #endregion #region Albums /// /// Get Spotify catalog information about an album’s tracks. 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 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()); } /// /// Get Spotify catalog information for a single album. /// /// 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 FullAlbum GetAlbum(String id, String market = "") { if (String.IsNullOrEmpty(market)) return DownloadData(APIBase + "/albums/" + id); return DownloadData(APIBase + "/albums/" + id + "?market=" + market); } /// /// Get Spotify catalog information for multiple albums identified by their Spotify IDs. /// /// 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 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))); } #endregion #region Artists /// /// Get Spotify catalog information for a single artist identified by their unique Spotify ID. /// /// The Spotify ID for the artist. /// public FullArtist GetArtist(String id) { return DownloadData(APIBase + "/artists/" + id); } /// /// Get Spotify catalog information about artists similar to a given artist. Similarity is based on analysis of the /// Spotify community’s listening history. /// /// The Spotify ID for the artist. /// public SeveralArtists GetRelatedArtists(String id) { return DownloadData(APIBase + "/artists/" + id + "/related-artists"); } /// /// Get Spotify catalog information about an artist’s top tracks by country. /// /// The Spotify ID for the artist. /// The country: an ISO 3166-1 alpha-2 country code. /// public SeveralTracks GetArtistsTopTracks(String id, String country) { return DownloadData(APIBase + "/artists/" + id + "/top-tracks?country=" + country); } /// /// Get Spotify catalog information about an artist’s albums. 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 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()); } /// /// Get Spotify catalog information for several artists based on their Spotify IDs. /// /// A list of the Spotify IDs for the artists. Maximum: 50 IDs. /// public SeveralArtists GetSeveralArtists(List ids) { return DownloadData(APIBase + "/artists?ids=" + string.Join(",", ids.Take(50))); } #endregion #region Browse /// /// Get a list of Spotify featured playlists (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 FeaturedPlaylists GetFeaturedPlaylists(String locale = "", String country = "", DateTime timestamp = default(DateTime), int limit = 20, int offset = 0) { 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()); } /// /// Get a list of new album releases featured in Spotify (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 NewAlbumReleases GetNewAlbumReleases(String country = "", int limit = 20, int offset = 0) { 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()); } /// /// Get a list of categories used to tag items in Spotify (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 CategoryList GetCategories(String country = "", String locale = "", int limit = 20, int offset = 0) { 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()); } /// /// Get a single category used to tag items in Spotify (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 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()); } /// /// Get a list of Spotify playlists tagged with a particular category. /// /// 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 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()); } #endregion #region Follow /// /// Get the current user’s followed artists. /// /// 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 = "") { 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()); } /// /// Add the current user as a follower of one or more artists or other Spotify users. /// /// The ID type: either artist or user. /// A list of the artist or the user Spotify IDs /// /// AUTH NEEDED public ErrorResponse Follow(FollowType followType, List ids) { JObject ob = new JObject { {"ids", new JArray(ids)} }; return UploadData(APIBase + "/me/following?type=" + followType.GetStringAttribute(""), ob.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// /// Add the current user as a follower of one or more artists or other Spotify users. /// /// The ID type: either artist or user. /// Artists or the Users Spotify ID /// /// AUTH NEEDED public ErrorResponse Follow(FollowType followType, String id) { return Follow(followType, new List {id}); } /// /// Remove the current user as a follower of one or more artists or other Spotify users. /// /// The ID type: either artist or user. /// A list of the artist or the user Spotify IDs /// /// AUTH NEEDED public ErrorResponse Unfollow(FollowType followType, List ids) { JObject ob = new JObject { {"ids", new JArray(ids)} }; return UploadData(APIBase + "/me/following?type=" + followType.GetStringAttribute(""), ob.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); } /// /// Remove the current user as a follower of one or more artists or other Spotify users. /// /// The ID type: either artist or user. /// Artists or the Users Spotify ID /// /// AUTH NEEDED public ErrorResponse Unfollow(FollowType followType, String id) { return Unfollow(followType, new List {id}); } /// /// Check to see if the current user is following one or more artists or other Spotify users. /// /// The ID type: either artist or user. /// A list of the artist or the user Spotify IDs to check /// /// AUTH NEEDED public ListResponse IsFollowing(FollowType followType, List ids) { if (!UseAuth) throw new InvalidOperationException("Auth is required for IsFollowing"); JToken res = DownloadData(APIBase + "/me/following/contains?type=" + followType.GetStringAttribute("") + "&ids=" + string.Join(",", 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 artist or another Spotify user. /// /// The ID type: either artist or user. /// Artists or the Users Spotify ID /// /// AUTH NEEDED public ListResponse IsFollowing(FollowType followType, String id) { return IsFollowing(followType, new List {id}); } /// /// Add the current user as a follower of a playlist. /// /// 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 ErrorResponse FollowPlaylist(String ownerId, String playlistId, bool showPublic = true) { JObject body = new JObject { {"public", showPublic} }; return UploadData(APIBase + "/users/" + ownerId + "/playlists/" + playlistId + "/followers", body.ToString(Formatting.None), "PUT"); } /// /// Remove the current user as a follower of a playlist. /// /// 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 ErrorResponse UnfollowPlaylist(String ownerId, String playlistId) { return UploadData(APIBase + "/users/" + ownerId + "/playlists/" + playlistId + "/followers", "", "DELETE"); } /// /// Check to see if one or more Spotify users are following a specified playlist. /// /// 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 ListResponse IsFollowingPlaylist(String ownerId, String playlistId, List ids) { if (!UseAuth) throw new InvalidOperationException("Auth is required for IsFollowingPlaylist"); JToken res = DownloadData(APIBase + "/users/" + ownerId + "/playlists/" + playlistId + "/followers/contains?ids=" + string.Join(",", 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. /// /// The Spotify user ID of the person who owns the playlist. /// The Spotify ID of the playlist. /// A Spotify User ID /// /// AUTH NEEDED public ListResponse IsFollowingPlaylist(String ownerId, String playlistId, String id) { return IsFollowingPlaylist(ownerId, playlistId, new List {id}); } #endregion #region Library /// /// Save one or more tracks to the current user’s “Your Music” library. /// /// A list of the Spotify IDs /// /// AUTH NEEDED public ErrorResponse SaveTracks(List ids) { JArray array = new JArray(ids); return UploadData(APIBase + "/me/tracks/", array.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// /// Save one track to the current user’s “Your Music” library. /// /// A Spotify ID /// /// AUTH NEEDED public ErrorResponse SaveTrack(String id) { return SaveTracks(new List {id}); } /// /// Get a list of the songs saved in the current Spotify user’s “Your Music” library. /// /// 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 Paging GetSavedTracks(int limit = 20, int offset = 0, String market = "") { 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()); } /// /// Remove one or more tracks from the current user’s “Your Music” library. /// /// A list of the Spotify IDs. /// /// AUTH NEEDED public ErrorResponse RemoveSavedTracks(List ids) { JArray array = new JArray(ids); return UploadData(APIBase + "/me/tracks/", array.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); } /// /// Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library. /// /// A list of the Spotify IDs. /// /// AUTH NEEDED public ListResponse CheckSavedTracks(List ids) { if (!UseAuth) throw new InvalidOperationException("Auth is required for CheckSavedTracks"); JToken res = DownloadData(APIBase + "/me/tracks/contains?ids=" + string.Join(",", ids)); if (res is JArray) return new ListResponse {List = res.ToObject>(), Error = null}; return new ListResponse {List = null, Error = res["error"].ToObject()}; } #endregion #region Playlists /// /// Get a list of the playlists owned or followed by a Spotify user. /// /// 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 Paging GetUserPlaylists(String userId, int limit = 20, int offset = 0) { 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()); } /// /// Get a playlist owned by a Spotify user. /// /// 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 FullPlaylist GetPlaylist(String userId, String playlistId, String fields = "", String market = "") { 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()); } /// /// Get full details of the tracks of a playlist owned by a Spotify user. /// /// 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 Paging GetPlaylistTracks(String userId, String playlistId, String fields = "", int limit = 100, int offset = 0, String market = "") { 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()); } /// /// Create a playlist for a Spotify user. (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 FullPlaylist CreatePlaylist(String userId, String playlistName, Boolean isPublic = true) { JObject body = new JObject { {"name", playlistName}, {"public", isPublic} }; return UploadData(APIBase + "/users/" + userId + "/playlists", body.ToString(Formatting.None)); } /// /// Change a playlist’s name and public/private state. (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 ErrorResponse UpdatePlaylist(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 UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId, body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// /// Replace all the tracks in a playlist, 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 ErrorResponse ReplacePlaylistTracks(String userId, String playlistId, List uris) { JObject body = new JObject { {"uris", new JArray(uris.Take(100))} }; return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None), "PUT") ?? new ErrorResponse(); } /// /// Remove one or more tracks from a user’s playlist. /// /// 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 ErrorResponse RemovePlaylistTracks(String userId, String playlistId, List uris) { JObject body = new JObject { {"tracks", JArray.FromObject(uris.Take(100))} }; return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None), "DELETE") ?? new ErrorResponse(); } /// /// Remove one or more tracks from a user’s playlist. /// /// The user's Spotify user ID. /// The Spotify ID for the playlist. /// Spotify URI /// /// AUTH NEEDED public ErrorResponse RemovePlaylistTrack(String userId, String playlistId, DeleteTrackUri uri) { return RemovePlaylistTracks(userId, playlistId, new List {uri}); } /// /// Add one or more tracks to a user’s playlist. /// /// 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 ErrorResponse AddPlaylistTracks(String userId, String playlistId, List uris, int? position = null) { JObject body = new JObject { {"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(); } /// /// Add one or more tracks to a user’s playlist. /// /// 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 ErrorResponse AddPlaylistTrack(String userId, String playlistId, String uri, int? position = null) { return AddPlaylistTracks(userId, playlistId, new List {uri}, position); } /// /// Reorder a track or a group of tracks in a playlist. /// /// 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 Snapshot ReorderPlaylist(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} }; if (!String.IsNullOrEmpty(snapshotId)) body.Add("snapshot_id", snapshotId); return UploadData(APIBase + "/users/" + userId + "/playlists/" + playlistId + "/tracks", body.ToString(Formatting.None), "PUT"); } #endregion #region Profiles /// /// Get detailed profile information about the current user (including the current user’s username). /// /// /// AUTH NEEDED public PrivateProfile GetPrivateProfile() { if (!UseAuth) throw new InvalidOperationException("Auth is required for GetPrivateProfile"); return DownloadData(APIBase + "/me"); } /// /// Get public profile information about a Spotify user. /// /// The user's Spotify user ID. /// public PublicProfile GetPublicProfile(String userId) { return DownloadData(APIBase + "/users/" + userId); } #endregion #region Tracks /// /// Get Spotify catalog information for multiple tracks based on their Spotify IDs. /// /// 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 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))); } /// /// Get Spotify catalog information for a single track identified by its unique Spotify ID. /// /// 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 FullTrack GetTrack(String id, String market = "") { if (String.IsNullOrEmpty(market)) return DownloadData(APIBase + "/tracks/" + id); return DownloadData(APIBase + "/tracks/" + id + "?market=" + market); } #endregion #region Util public T UploadData(String url, String uploadData, String method = "POST") { if (!UseAuth) throw new InvalidOperationException("Auth is required for all Upload-Actions"); WebClient.SetHeader("Authorization", TokenType + " " + AccessToken); WebClient.SetHeader("Content-Type", "application/json"); return WebClient.UploadJson(url, uploadData, method); } public T DownloadData(String url) { if (UseAuth) WebClient.SetHeader("Authorization", TokenType + " " + AccessToken); else WebClient.RemoveHeader("Authorization"); return WebClient.DownloadJson(url); } #endregion } }