diff --git a/SpotifyAPI.Example/WebControl.cs b/SpotifyAPI.Example/WebControl.cs index 7670ee2a..0f6b7c57 100644 --- a/SpotifyAPI.Example/WebControl.cs +++ b/SpotifyAPI.Example/WebControl.cs @@ -4,6 +4,7 @@ using SpotifyAPI.Web.Enums; using SpotifyAPI.Web.Models; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Net; @@ -68,6 +69,15 @@ namespace SpotifyAPI.Example return; } + TuneableTrack asd = new TuneableTrack + { + Acousticness = 0.0029f + }; + List artists = new List() { "0daugAjUgbJSqdlyYNwIbT" }; + + Recommendations reco = _spotify.GetRecommendations(target:asd, artistSeed:artists); + RecommendationSeedGenres genres = _spotify.GetRecommendationSeedsGenres(); + authButton.Enabled = false; _profile = _spotify.GetPrivateProfile(); diff --git a/SpotifyAPI/SpotifyAPI.csproj b/SpotifyAPI/SpotifyAPI.csproj index 02d7c164..8d35cf74 100644 --- a/SpotifyAPI/SpotifyAPI.csproj +++ b/SpotifyAPI/SpotifyAPI.csproj @@ -88,6 +88,9 @@ + + + @@ -106,6 +109,7 @@ + diff --git a/SpotifyAPI/Web/Models/RecommendationSeed .cs b/SpotifyAPI/Web/Models/RecommendationSeed .cs new file mode 100644 index 00000000..b0cd94a1 --- /dev/null +++ b/SpotifyAPI/Web/Models/RecommendationSeed .cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace SpotifyAPI.Web.Models +{ + public class RecommendationSeed + { + [JsonProperty("afterFilteringSize")] + public int AfterFilteringSize { get; set; } + + [JsonProperty("afterRelinkingSize")] + public int AfterRelinkingSize { get; set; } + + [JsonProperty("href")] + public string Href { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("initialPoolSize")] + public int InitialPoolSize { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI/Web/Models/RecommendationSeedGenres.cs b/SpotifyAPI/Web/Models/RecommendationSeedGenres.cs new file mode 100644 index 00000000..663c8bf7 --- /dev/null +++ b/SpotifyAPI/Web/Models/RecommendationSeedGenres.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace SpotifyAPI.Web.Models +{ + public class RecommendationSeedGenres : BasicModel + { + [JsonProperty("genres")] + public List Genres { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI/Web/Models/Recommendations.cs b/SpotifyAPI/Web/Models/Recommendations.cs new file mode 100644 index 00000000..229be912 --- /dev/null +++ b/SpotifyAPI/Web/Models/Recommendations.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace SpotifyAPI.Web.Models +{ + public class Recommendations : BasicModel + { + [JsonProperty("seeds")] + public List Seeds { get; set; } + + [JsonProperty("tracks")] + public List Tracks { get; set; } + } +} \ No newline at end of file diff --git a/SpotifyAPI/Web/Models/TuneableTrack.cs b/SpotifyAPI/Web/Models/TuneableTrack.cs new file mode 100644 index 00000000..9cdbe180 --- /dev/null +++ b/SpotifyAPI/Web/Models/TuneableTrack.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; + +namespace SpotifyAPI.Web.Models +{ + public class TuneableTrack + { + [String("acousticness")] + public float? Acousticness { get; set; } + + [String("danceability")] + public float? Danceability { get; set; } + + [String("duration_ms")] + public int? DurationMs { get; set; } + + [String("energy")] + public float? Energy { get; set; } + + [String("instrumentalness")] + public float? Instrumentalness { get; set; } + + [String("key")] + public int? Key { get; set; } + + [String("liveness")] + public float? Liveness { get; set; } + + [String("loudness")] + public float? Loudness { get; set; } + + [String("mode")] + public int? Mode { get; set; } + + [String("popularity")] + public int? Popularity { get; set; } + + [String("speechiness")] + public float? Speechiness { get; set; } + + [String("tempo")] + public float? Tempo { get; set; } + + [String("time_signature")] + public int? TimeSignature { get; set; } + + [String("valence")] + public float? Valence { get; set; } + + public string BuildUrlParams(string prefix) + { + List urlParams = new List(); + foreach (PropertyInfo info in GetType().GetProperties()) + { + object value = info.GetValue(this); + string name = info.GetCustomAttribute()?.Text; + if(name == null || value == null) + continue; + if (value is float) + urlParams.Add($"{prefix}_{name}={((float)value).ToString(CultureInfo.InvariantCulture)}"); + else + urlParams.Add($"{prefix}_{name}={value}"); + } + if (urlParams.Count > 0) + return "&" + string.Join("&", urlParams); + return ""; + } + } +} \ No newline at end of file diff --git a/SpotifyAPI/Web/SpotifyWebAPI.cs b/SpotifyAPI/Web/SpotifyWebAPI.cs index 902da178..c51fdbcd 100644 --- a/SpotifyAPI/Web/SpotifyWebAPI.cs +++ b/SpotifyAPI/Web/SpotifyWebAPI.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; namespace SpotifyAPI.Web { + // ReSharper disable once InconsistentNaming public sealed class SpotifyWebAPI : IDisposable { [Obsolete("This Property will be removed soon. Please use SpotifyWebBuilder.APIBase")] @@ -461,6 +462,82 @@ namespace SpotifyAPI.Web return await DownloadDataAsync(_builder.GetCategoryPlaylists(categoryId, country, limit, offset)); } + /// + /// Create a playlist-style listening experience based on seed artists, tracks and genres. + /// + /// A comma separated list of Spotify IDs for seed artists. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// A comma separated list of any genres in the set of available genre seeds. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// A comma separated list of Spotify IDs for a seed track. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// Tracks with the attribute values nearest to the target values will be preferred. + /// For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided + /// For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided + /// The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100. + /// For seeds with unusually small pools or when highly restrictive filtering is applied, it may be impossible to generate the requested number of recommended tracks. + /// + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// Because min_*, max_* and target_* are applied to pools before relinking, the generated results may not precisely match the filters applied. + /// + /// AUTH NEEDED + public Recommendations GetRecommendations(List artistSeed = null, List genreSeed = null, List trackSeed = null, + TuneableTrack target = null, TuneableTrack min = null, TuneableTrack max = null, int limit = 20, string market = "") + { + return DownloadData(_builder.GetRecommendations(artistSeed, genreSeed, trackSeed, target, min, max, limit, market)); + } + + /// + /// Create a playlist-style listening experience based on seed artists, tracks and genres asynchronously. + /// + /// A comma separated list of Spotify IDs for seed artists. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// A comma separated list of any genres in the set of available genre seeds. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// A comma separated list of Spotify IDs for a seed track. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// Tracks with the attribute values nearest to the target values will be preferred. + /// For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided + /// For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided + /// The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100. + /// For seeds with unusually small pools or when highly restrictive filtering is applied, it may be impossible to generate the requested number of recommended tracks. + /// + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// Because min_*, max_* and target_* are applied to pools before relinking, the generated results may not precisely match the filters applied. + /// + /// AUTH NEEDED + public async Task GetRecommendationsAsync(List artistSeed = null, List genreSeed = null, List trackSeed = null, + TuneableTrack target = null, TuneableTrack min = null, TuneableTrack max = null, int limit = 20, string market = "") + { + return await DownloadDataAsync(_builder.GetRecommendations(artistSeed, genreSeed, trackSeed, target, min, max, limit, market)); + } + + /// + /// Retrieve a list of available genres seed parameter values for recommendations. + /// + /// + /// AUTH NEEDED + public RecommendationSeedGenres GetRecommendationSeedsGenres() + { + return DownloadData(_builder.GetRecommendationSeedsGenres()); + } + + /// + /// Retrieve a list of available genres seed parameter values for recommendations asynchronously. + /// + /// + /// AUTH NEEDED + public async Task GetRecommendationSeedsGenresAsync() + { + return await DownloadDataAsync(_builder.GetRecommendationSeedsGenres()); + } + #endregion Browse #region Follow diff --git a/SpotifyAPI/Web/SpotifyWebBuilder.cs b/SpotifyAPI/Web/SpotifyWebBuilder.cs index 29e6c8c1..5106f4c0 100644 --- a/SpotifyAPI/Web/SpotifyWebBuilder.cs +++ b/SpotifyAPI/Web/SpotifyWebBuilder.cs @@ -284,6 +284,61 @@ namespace SpotifyAPI.Web return builder.ToString(); } + /// + /// Create a playlist-style listening experience based on seed artists, tracks and genres. + /// + /// A comma separated list of Spotify IDs for seed artists. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// A comma separated list of any genres in the set of available genre seeds. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// A comma separated list of Spotify IDs for a seed track. + /// Up to 5 seed values may be provided in any combination of seed_artists, seed_tracks and seed_genres. + /// + /// Tracks with the attribute values nearest to the target values will be preferred. + /// For each tunable track attribute, a hard floor on the selected track attribute’s value can be provided + /// For each tunable track attribute, a hard ceiling on the selected track attribute’s value can be provided + /// The target size of the list of recommended tracks. Default: 20. Minimum: 1. Maximum: 100. + /// For seeds with unusually small pools or when highly restrictive filtering is applied, it may be impossible to generate the requested number of recommended tracks. + /// + /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking. + /// Because min_*, max_* and target_* are applied to pools before relinking, the generated results may not precisely match the filters applied. + /// + /// AUTH NEEDED + public string GetRecommendations(List artistSeed = null, List genreSeed = null, List trackSeed = null, + TuneableTrack target = null, TuneableTrack min = null, TuneableTrack max = null, int limit = 20, string market = "") + { + limit = Math.Min(100, limit); + StringBuilder builder = new StringBuilder($"{APIBase}/recommendations"); + builder.Append("?limit=" + limit); + if (artistSeed?.Count > 0) + builder.Append("&seed_artists=" + string.Join(",", artistSeed)); + if (genreSeed?.Count > 0) + builder.Append("&seed_genres=" + string.Join(",", genreSeed)); + if (trackSeed?.Count > 0) + builder.Append("&seed_tracks=" + string.Join(",", trackSeed)); + if (target != null) + builder.Append(target.BuildUrlParams("target")); + if (min != null) + builder.Append(min.BuildUrlParams("min")); + if (max != null) + builder.Append(max.BuildUrlParams("max")); + if (!string.IsNullOrEmpty(market)) + builder.Append("&market=" + market); + return builder.ToString(); + } + + /// + /// Retrieve a list of available genres seed parameter values for recommendations. + /// + /// + /// AUTH NEEDED + public string GetRecommendationSeedsGenres() + { + return $"{APIBase}/recommendations/available-genre-seeds"; + } + #endregion Browse #region Follow