diff --git a/SpotifyAPI/SpotifyAPI.csproj b/SpotifyAPI/SpotifyAPI.csproj
index 4adb37d7..63fd5480 100644
--- a/SpotifyAPI/SpotifyAPI.csproj
+++ b/SpotifyAPI/SpotifyAPI.csproj
@@ -63,8 +63,13 @@
+
+
+
+
+
diff --git a/SpotifyAPI/SpotifyWebAPI/AutorizationCodeAuth.cs b/SpotifyAPI/SpotifyWebAPI/AutorizationCodeAuth.cs
index 7f07275e..f11ff32f 100644
--- a/SpotifyAPI/SpotifyWebAPI/AutorizationCodeAuth.cs
+++ b/SpotifyAPI/SpotifyWebAPI/AutorizationCodeAuth.cs
@@ -67,7 +67,7 @@ namespace SpotifyAPI.SpotifyWebAPI
builder.Append("&response_type=code");
builder.Append("&redirect_uri=" + RedirectUri);
builder.Append("&state=" + State);
- builder.Append("&scope=" + Scope.GetScopeValue(" "));
+ builder.Append("&scope=" + Scope.GetStringAttribute(" "));
builder.Append("&show_dialog=" + ShowDialog.ToString());
return builder.ToString();
}
diff --git a/SpotifyAPI/SpotifyWebAPI/ClientCredentialsAuth.cs b/SpotifyAPI/SpotifyWebAPI/ClientCredentialsAuth.cs
index 192ac137..a6975f79 100644
--- a/SpotifyAPI/SpotifyWebAPI/ClientCredentialsAuth.cs
+++ b/SpotifyAPI/SpotifyWebAPI/ClientCredentialsAuth.cs
@@ -26,7 +26,7 @@ namespace SpotifyAPI.SpotifyWebAPI
NameValueCollection col = new NameValueCollection();
col.Add("grant_type","client_credentials");
- col.Add("scope", Scope.GetScopeValue(" "));
+ col.Add("scope", Scope.GetStringAttribute(" "));
byte[] data = null;
try
diff --git a/SpotifyAPI/SpotifyWebAPI/FollowType.cs b/SpotifyAPI/SpotifyWebAPI/FollowType.cs
new file mode 100644
index 00000000..75819674
--- /dev/null
+++ b/SpotifyAPI/SpotifyWebAPI/FollowType.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SpotifyAPI.SpotifyWebAPI
+{
+ [Flags]
+ public enum FollowType
+ {
+ [StringAttribute("artist")]
+ ARTIST = 1,
+ [StringAttribute("user")]
+ USER = 2
+ }
+}
diff --git a/SpotifyAPI/SpotifyWebAPI/ImplicitGrantAuth.cs b/SpotifyAPI/SpotifyWebAPI/ImplicitGrantAuth.cs
index ab92529b..241f7400 100644
--- a/SpotifyAPI/SpotifyWebAPI/ImplicitGrantAuth.cs
+++ b/SpotifyAPI/SpotifyWebAPI/ImplicitGrantAuth.cs
@@ -36,7 +36,7 @@ namespace SpotifyAPI.SpotifyWebAPI
builder.Append("&response_type=token");
builder.Append("&redirect_uri=" + RedirectUri);
builder.Append("&state=" + State);
- builder.Append("&scope=" + Scope.GetScopeValue(" "));
+ builder.Append("&scope=" + Scope.GetStringAttribute(" "));
builder.Append("&show_dialog=" + ShowDialog.ToString());
return builder.ToString();
}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/ArrayResponse.cs b/SpotifyAPI/SpotifyWebAPI/Models/ArrayResponse.cs
new file mode 100644
index 00000000..6245eb7a
--- /dev/null
+++ b/SpotifyAPI/SpotifyWebAPI/Models/ArrayResponse.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json.Linq;
+
+namespace SpotifyAPI.SpotifyWebAPI.Models
+{
+ public class ListResponse : BasicModel
+ {
+ public List List { get; set; }
+ }
+}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/Category.cs b/SpotifyAPI/SpotifyWebAPI/Models/Category.cs
new file mode 100644
index 00000000..2291f806
--- /dev/null
+++ b/SpotifyAPI/SpotifyWebAPI/Models/Category.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace SpotifyAPI.SpotifyWebAPI.Models
+{
+ public class Category : BasicModel
+ {
+ [JsonProperty("href")]
+ public String Href { get; set; }
+ [JsonProperty("icons")]
+ public List Icons { get; set; }
+ [JsonProperty("id")]
+ public String Id { get; set; }
+ [JsonProperty("name")]
+ public String Name { get; set; }
+ }
+}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/CategoryList.cs b/SpotifyAPI/SpotifyWebAPI/Models/CategoryList.cs
new file mode 100644
index 00000000..8d6e88d6
--- /dev/null
+++ b/SpotifyAPI/SpotifyWebAPI/Models/CategoryList.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace SpotifyAPI.SpotifyWebAPI.Models
+{
+ public class CategoryList : BasicModel
+ {
+ [JsonProperty("categories")]
+ public Paging Categories { get; set; }
+ }
+}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/CategoryPlaylist.cs b/SpotifyAPI/SpotifyWebAPI/Models/CategoryPlaylist.cs
new file mode 100644
index 00000000..5e14682e
--- /dev/null
+++ b/SpotifyAPI/SpotifyWebAPI/Models/CategoryPlaylist.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace SpotifyAPI.SpotifyWebAPI.Models
+{
+ public class CategoryPlaylist : BasicModel
+ {
+ [JsonProperty("playlists")]
+ public Paging Playlists { get; set; }
+ }
+}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/FullTrack.cs b/SpotifyAPI/SpotifyWebAPI/Models/FullTrack.cs
index b5b21584..a1b57b78 100644
--- a/SpotifyAPI/SpotifyWebAPI/Models/FullTrack.cs
+++ b/SpotifyAPI/SpotifyWebAPI/Models/FullTrack.cs
@@ -44,5 +44,17 @@ namespace SpotifyAPI.SpotifyWebAPI.Models
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
+
+ ///
+ /// Only filled when the "market"-parameter was supplied!
+ ///
+ [JsonProperty("is_playable")]
+ public Boolean? IsPlayable { get; set; }
+
+ ///
+ /// Only filled when the "market"-parameter was supplied!
+ ///
+ [JsonProperty("linked_from")]
+ public LinkedFrom LinkedFrom { get; set; }
}
}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/GeneralModels.cs b/SpotifyAPI/SpotifyWebAPI/Models/GeneralModels.cs
index 7eeb9ff9..cc9db476 100644
--- a/SpotifyAPI/SpotifyWebAPI/Models/GeneralModels.cs
+++ b/SpotifyAPI/SpotifyWebAPI/Models/GeneralModels.cs
@@ -100,8 +100,17 @@ namespace SpotifyAPI.SpotifyWebAPI.Models
public String Type { get; set; }
}
- public class CheckUserTracks : BasicModel
+ public class LinkedFrom
{
- public List Checked { get; set; }
+ [JsonProperty("external_urls")]
+ public Dictionary ExternalUrls { get; set; }
+ [JsonProperty("href")]
+ public String Href { get; set; }
+ [JsonProperty("id")]
+ public String Id { get; set; }
+ [JsonProperty("type")]
+ public String Type { get; set; }
+ [JsonProperty("uri")]
+ public String Uri { get; set; }
}
}
diff --git a/SpotifyAPI/SpotifyWebAPI/Models/PrivateProfile.cs b/SpotifyAPI/SpotifyWebAPI/Models/PrivateProfile.cs
index 7a88f9c9..72c347ed 100644
--- a/SpotifyAPI/SpotifyWebAPI/Models/PrivateProfile.cs
+++ b/SpotifyAPI/SpotifyWebAPI/Models/PrivateProfile.cs
@@ -9,6 +9,8 @@ namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class PrivateProfile : BasicModel
{
+ [JsonProperty("birthdate")]
+ public String Birthdate { get; set; }
[JsonProperty("country")]
public String Country { get; set; }
[JsonProperty("display_name")]
diff --git a/SpotifyAPI/SpotifyWebAPI/Scope.cs b/SpotifyAPI/SpotifyWebAPI/Scope.cs
index 0322d014..3b3373b0 100644
--- a/SpotifyAPI/SpotifyWebAPI/Scope.cs
+++ b/SpotifyAPI/SpotifyWebAPI/Scope.cs
@@ -26,6 +26,12 @@ namespace SpotifyAPI.SpotifyWebAPI
[StringAttribute("user-library-read")]
USER_LIBRARAY_READ = 128,
[StringAttribute("user-library-modify")]
- USER_LIBRARY_MODIFY = 256
+ USER_LIBRARY_MODIFY = 256,
+ [StringAttribute("user-follow-modify")]
+ USER_FOLLOW_MODIFY = 512,
+ [StringAttribute("user-follow-read")]
+ USER_FOLLOW_READ = 1024,
+ [StringAttribute("user-read-birthdate")]
+ USER_READ_BIRTHDATE = 2048
}
}
diff --git a/SpotifyAPI/SpotifyWebAPI/SpotifyWebAPIClass.cs b/SpotifyAPI/SpotifyWebAPI/SpotifyWebAPIClass.cs
index cc34708e..118e33bc 100644
--- a/SpotifyAPI/SpotifyWebAPI/SpotifyWebAPIClass.cs
+++ b/SpotifyAPI/SpotifyWebAPI/SpotifyWebAPIClass.cs
@@ -46,6 +46,36 @@ namespace SpotifyAPI.SpotifyWebAPI
return DownloadData("https://api.spotify.com/v1/users/" + userId);
}
+ public ErrorResponse Follow(FollowType followType, List ids)
+ {
+ JObject ob = new JObject();
+ ob.Add("ids", new JArray(ids.ToArray()));
+ return UploadData("https://api.spotify.com/v1/me/following?type=" + followType.GetStringAttribute(""), ob.ToString(Formatting.None), "PUT");
+ }
+
+ public ErrorResponse Unfollow(FollowType followType, List ids)
+ {
+ JObject ob = new JObject();
+ ob.Add("ids", new JArray(ids.ToArray()));
+ return UploadData("https://api.spotify.com/v1/me/following?type=" + followType.GetStringAttribute(""), ob.ToString(Formatting.None), "DELETE");
+ }
+
+ ///
+ ///
+ ///
+ public ListResponse IsFollowing(FollowType followType, List ids)
+ {
+ JToken res = DownloadData("https://api.spotify.com/v1/me/following/contains?type=" + followType.GetStringAttribute("") + "&ids=" + string.Join(",", ids));
+ if (res is JArray)
+ {
+ return new ListResponse { List = res.ToObject>(), ErrorResponse = null };
+ }
+ else
+ {
+ return new ListResponse { List = null, ErrorResponse = res.ToObject() };
+ }
+ }
+
#endregion
#region User-Library
@@ -54,26 +84,29 @@ namespace SpotifyAPI.SpotifyWebAPI
JArray array = new JArray(ids.ToArray());
return UploadData("https://api.spotify.com/v1/me/tracks/", array.ToString(Formatting.None), "PUT");
}
- public Paging GetSavedTracks()
+ public Paging GetSavedTracks(String market = "")
{
- return DownloadData>("https://api.spotify.com/v1/me/tracks");
+ if(market == "")
+ return DownloadData>("https://api.spotify.com/v1/me/tracks");
+ else
+ return DownloadData>("https://api.spotify.com/v1/me/tracks?market=" + market);
}
public ErrorResponse RemoveSavedTracks(List ids)
{
JArray array = new JArray(ids.ToArray());
return UploadData("https://api.spotify.com/v1/me/tracks/", array.ToString(Formatting.None), "DELETE");
}
- public CheckUserTracks CheckSavedTracks(List ids)
+ public ListResponse CheckSavedTracks(List ids)
{
String resp = DownloadString("https://api.spotify.com/v1/me/tracks/contains?ids=" + string.Join(",", ids));
JToken res = JToken.Parse(resp);
if (res is JArray)
{
- return new CheckUserTracks { Checked = res.ToObject>(), ErrorResponse = null };
+ return new ListResponse { List = res.ToObject>(), ErrorResponse = null };
}
else
{
- return new CheckUserTracks { Checked = null, ErrorResponse = res.ToObject() };
+ return new ListResponse { List = null, ErrorResponse = res.ToObject() };
}
}
#endregion
@@ -87,9 +120,12 @@ namespace SpotifyAPI.SpotifyWebAPI
{
return DownloadData("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId);
}
- public Paging GetPlaylistTracks(String userId, String playlistId)
+ public Paging GetPlaylistTracks(String userId, String playlistId, String market = "")
{
- return DownloadData>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId + "/tracks");
+ if(market == "")
+ return DownloadData>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId + "/tracks");
+ else
+ return DownloadData>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId + "/tracks?market=" + market);
}
public FullPlaylist CreatePlaylist(String userId, String playlistName, Boolean isPublic = true)
{
@@ -147,6 +183,28 @@ namespace SpotifyAPI.SpotifyWebAPI
builder.Append("×tamp=" + timestamp.ToString("yyyy-MM-ddTHH:mm:ss"));
return DownloadData(builder.ToString());
}
+
+ public ErrorResponse FollowPlaylist(String ownerId, String playlistId, bool showPublic)
+ {
+ JObject ob = new JObject();
+ ob.Add("public", showPublic);
+ return UploadData("https://api.spotify.com/v1/users/" + ownerId + "/playlists/" + playlistId + "/followers", ob.ToString(Formatting.None), "PUT");
+ }
+
+ public ErrorResponse UnfollowPlaylist(String ownerId, String playlistId)
+ {
+ return UploadData("https://api.spotify.com/v1/users/" + ownerId + "/playlists/" + playlistId + "/followers", "", "DELETE");
+ }
+
+ public ListResponse IsFollowingPlaylist(String ownerId, String playlistId, List ids)
+ {
+ JToken res = DownloadData("https://api.spotify.com/v1/users/" + ownerId + "/playlists/" + playlistId + "/followers/contains?ids=" + string.Join(",", ids));
+ if (res is JArray)
+ return new ListResponse() { List = res.ToObject>(), ErrorResponse = null };
+ else
+ return new ListResponse() { List = null, ErrorResponse = res.ToObject() };
+ }
+
#endregion
#region Search and Fetch
@@ -166,27 +224,36 @@ namespace SpotifyAPI.SpotifyWebAPI
limit = Math.Min(50, limit);
StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/search");
builder.Append("?q=" + q);
- builder.Append("&type=" + type.GetSearchValue(","));
+ builder.Append("&type=" + type.GetStringAttribute(","));
builder.Append("&limit=" + limit);
builder.Append("&offset=" + offset);
return DownloadData(builder.ToString());
}
- public SeveralTracks GetSeveralTracks(List ids)
+ public SeveralTracks GetSeveralTracks(List ids, String market = "")
{
- return DownloadData("https://api.spotify.com/v1/tracks?ids=" + string.Join(",", ids));
+ if(market == "")
+ return DownloadData("https://api.spotify.com/v1/tracks?ids=" + string.Join(",", ids));
+ else
+ return DownloadData("https://api.spotify.com/v1/tracks?market=" + market + "&ids=" + string.Join(",", ids));
}
- public SeveralAlbums GetSeveralAlbums(List ids)
+ public SeveralAlbums GetSeveralAlbums(List ids, String market = "")
{
- return DownloadData("https://api.spotify.com/v1/albums?ids=" + string.Join(",", ids));
+ if(market == "")
+ return DownloadData("https://api.spotify.com/v1/albums?ids=" + string.Join(",", ids));
+ else
+ return DownloadData("https://api.spotify.com/v1/albums?market=" + market + "&ids=" + string.Join(",", ids));
}
public SeveralArtists GetSeveralArtists(List ids)
{
return DownloadData("https://api.spotify.com/v1/artists?ids=" + string.Join(",", ids));
}
- public FullTrack GetTrack(String id)
+ public FullTrack GetTrack(String id, String market = "")
{
- return DownloadData("https://api.spotify.com/v1/tracks/" + id);
+ if(market == "")
+ return DownloadData("https://api.spotify.com/v1/tracks/" + id);
+ else
+ return DownloadData("https://api.spotify.com/v1/tracks/" + id + "?market=" + market);
}
public SeveralArtists GetRelatedArtists(String id)
{
@@ -200,7 +267,7 @@ namespace SpotifyAPI.SpotifyWebAPI
{
limit = Math.Min(50, limit);
StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/artists/" + id + "/albums");
- builder.Append("?type=" + type.GetAlbumValue(","));
+ builder.Append("?type=" + type.GetStringAttribute(","));
builder.Append("&limit=" + limit);
builder.Append("&offset=" + offset);
if (market != "")
@@ -211,20 +278,68 @@ namespace SpotifyAPI.SpotifyWebAPI
{
return DownloadData("https://api.spotify.com/v1/artists/" + id);
}
- public Paging GetAlbumTracks(String id, int limit = 20, int offset = 0)
+ public Paging GetAlbumTracks(String id, String market, int limit = 20, int offset = 0)
{
limit = Math.Min(50, limit);
StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/albums/" + id + "/tracks");
builder.Append("?limit=" + limit);
builder.Append("&offset=" + offset);
+ if (market != "")
+ builder.Append("&market=" + market);
return DownloadData>(builder.ToString());
}
- public FullAlbum GetAlbum(String id)
+ public FullAlbum GetAlbum(String id, String market = "")
{
- return DownloadData("https://api.spotify.com/v1/albums/" + id);
+ if(market == "")
+ return DownloadData("https://api.spotify.com/v1/albums/" + id);
+ else
+ return DownloadData("https://api.spotify.com/v1/albums/" + id + "?market=" + market);
}
#endregion
+ #region Category
+
+ public CategoryList GetCategories(String country = "", String locale = "", int limit = 20, int offset = 0)
+ {
+ limit = Math.Min(50, limit);
+ StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/browse/categories");
+ builder.Append("?limit=" + limit);
+ builder.Append("&offset=" + offset);
+ if (country != "")
+ builder.Append("&country=" + country);
+ if (locale != "")
+ builder.Append("&locale=" + locale);
+ return DownloadData(builder.ToString());
+ }
+
+ public Category GetCategory(String categoryId, String country = "", String locale = "")
+ {
+ StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/browse/categories/" + categoryId);
+ if(country != "")
+ builder.Append("?country=" + country);
+ if(locale != "")
+ {
+ if (country != "")
+ builder.Append("&locale=" + locale);
+ else
+ builder.Append("?locale=" + locale);
+ }
+ return DownloadData(builder.ToString());
+ }
+
+ public CategoryPlaylist GetCategoryPlaylists(String categoryId, String country = "", int limit = 20, int offset = 0)
+ {
+ limit = Math.Min(50, limit);
+ StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/browse/categories/" + categoryId + "/playlists");
+ builder.Append("?limit=" + limit);
+ builder.Append("&offset=" + offset);
+ if (country != "")
+ builder.Append("&country=" + country);
+ return DownloadData(builder.ToString());
+ }
+
+ #endregion
+
#region Util
public T UploadData(String url, String uploadData, String method = "POST")
{
@@ -263,7 +378,6 @@ namespace SpotifyAPI.SpotifyWebAPI
{
response = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
- Debug.WriteLine(response);
return response;
}
#endregion
diff --git a/SpotifyAPI/SpotifyWebAPI/Util.cs b/SpotifyAPI/SpotifyWebAPI/Util.cs
index 8d0e2978..27ef2ae3 100644
--- a/SpotifyAPI/SpotifyWebAPI/Util.cs
+++ b/SpotifyAPI/SpotifyWebAPI/Util.cs
@@ -10,41 +10,14 @@ namespace SpotifyAPI.SpotifyWebAPI
{
public static class Util
{
- public static string GetScopeValue(this Scope en,String separator)
+ public static string GetStringAttribute(this T en, String separator) where T : struct, IConvertible
{
+ Enum e = (Enum)(object)en;
IEnumerable attributes =
- Enum.GetValues(typeof(Scope))
- .Cast()
- .Where(v => en.HasFlag(v))
- .Select(v => typeof(Scope).GetField(v.ToString()))
- .Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0])
- .Cast();
-
- List list = new List();
- attributes.ToList().ForEach((element) => list.Add(element.Text));
- return string.Join(" ", list);
- }
- public static string GetSearchValue(this SearchType en, String separator)
- {
- IEnumerable attributes =
- Enum.GetValues(typeof(SearchType))
- .Cast()
- .Where(v => en.HasFlag(v))
- .Select(v => typeof(SearchType).GetField(v.ToString()))
- .Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0])
- .Cast();
-
- List list = new List();
- attributes.ToList().ForEach((element) => list.Add(element.Text));
- return string.Join(" ", list);
- }
- public static string GetAlbumValue(this AlbumType en, String separator)
- {
- IEnumerable attributes =
- Enum.GetValues(typeof(AlbumType))
- .Cast()
- .Where(v => en.HasFlag(v))
- .Select(v => typeof(AlbumType).GetField(v.ToString()))
+ Enum.GetValues(typeof(T))
+ .Cast()
+ .Where(v => e.HasFlag((Enum)(object)v))
+ .Select(v => typeof(T).GetField(v.ToString()))
.Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0])
.Cast();
diff --git a/SpotifyWebAPIExample/Program.cs b/SpotifyWebAPIExample/Program.cs
index 7e0bce1e..c8d6b7e8 100644
--- a/SpotifyWebAPIExample/Program.cs
+++ b/SpotifyWebAPIExample/Program.cs
@@ -25,6 +25,7 @@ namespace SpotifyWebAPIExample
RedirectUri = "http://localhost",
//How many permissions we need?
Scope = Scope.USER_READ_PRIVATE | Scope.USER_READ_EMAIL | Scope.PLAYLIST_READ_PRIVATE | Scope.USER_LIBRARAY_READ | Scope.USER_LIBRARY_MODIFY | Scope.USER_READ_PRIVATE
+ | Scope.USER_FOLLOW_MODIFY | Scope.USER_FOLLOW_READ | Scope.PLAYLIST_MODIFY_PRIVATE | Scope.USER_READ_BIRTHDATE
};
//Start the internal http server
auth.StartHttpServer();