Added new player endpoints

This commit is contained in:
Jonas Dellinger 2017-05-29 23:17:15 +02:00
parent 7e6dab63c5
commit 2543ed2f2f
10 changed files with 421 additions and 11 deletions

View File

@ -37,8 +37,6 @@ namespace SpotifyAPI.Example
return; return;
} }
var test = _spotify.GetUsersRecentlyPlayedTracks();
authButton.Enabled = false; authButton.Enabled = false;
_profile = _spotify.GetPrivateProfile(); _profile = _spotify.GetPrivateProfile();
@ -111,7 +109,7 @@ namespace SpotifyAPI.Example
"26d287105e31491889f3cd293d85bfea", "26d287105e31491889f3cd293d85bfea",
Scope.UserReadPrivate | Scope.UserReadEmail | Scope.PlaylistReadPrivate | Scope.UserLibraryRead | Scope.UserReadPrivate | Scope.UserReadEmail | Scope.PlaylistReadPrivate | Scope.UserLibraryRead |
Scope.UserReadPrivate | Scope.UserFollowRead | Scope.UserReadBirthdate | Scope.UserTopRead | Scope.PlaylistReadCollaborative | Scope.UserReadPrivate | Scope.UserFollowRead | Scope.UserReadBirthdate | Scope.UserTopRead | Scope.PlaylistReadCollaborative |
Scope.UserReadRecentlyPlayed); Scope.UserReadRecentlyPlayed | Scope.UserReadPlaybackState | Scope.UserModifyPlaybackState);
try try
{ {

View File

@ -42,6 +42,7 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Web" /> <Reference Include="System.Web" />
@ -59,6 +60,7 @@
<Compile Include="Local\Models\SpotifyUri.cs" /> <Compile Include="Local\Models\SpotifyUri.cs" />
<Compile Include="Local\VolumeMixerControl.cs" /> <Compile Include="Local\VolumeMixerControl.cs" />
<Compile Include="Web\Auth\WebAPIFactory.cs" /> <Compile Include="Web\Auth\WebAPIFactory.cs" />
<Compile Include="Web\Enums\RepeatState.cs" />
<Compile Include="Web\Enums\TimeRangeType.cs" /> <Compile Include="Web\Enums\TimeRangeType.cs" />
<Compile Include="Web\IClient.cs" /> <Compile Include="Web\IClient.cs" />
<Compile Include="Local\Models\CFID.cs" /> <Compile Include="Local\Models\CFID.cs" />
@ -79,17 +81,20 @@
<Compile Include="Web\Auth\ImplicitGrantAuth.cs" /> <Compile Include="Web\Auth\ImplicitGrantAuth.cs" />
<Compile Include="Web\Models\ArrayResponse.cs" /> <Compile Include="Web\Models\ArrayResponse.cs" />
<Compile Include="Web\Models\AudioFeatures.cs" /> <Compile Include="Web\Models\AudioFeatures.cs" />
<Compile Include="Web\Models\AvailabeDevices.cs" />
<Compile Include="Web\Models\BasicModel.cs" /> <Compile Include="Web\Models\BasicModel.cs" />
<Compile Include="Web\Models\Category.cs" /> <Compile Include="Web\Models\Category.cs" />
<Compile Include="Web\Models\CategoryList.cs" /> <Compile Include="Web\Models\CategoryList.cs" />
<Compile Include="Web\Models\CategoryPlaylist.cs" /> <Compile Include="Web\Models\CategoryPlaylist.cs" />
<Compile Include="Web\Models\CursorPaging.cs" /> <Compile Include="Web\Models\CursorPaging.cs" />
<Compile Include="Web\Models\Device.cs" />
<Compile Include="Web\Models\FeaturedPlaylists.cs" /> <Compile Include="Web\Models\FeaturedPlaylists.cs" />
<Compile Include="Web\Models\FollowedArtists.cs" /> <Compile Include="Web\Models\FollowedArtists.cs" />
<Compile Include="Web\Models\FullAlbum.cs" /> <Compile Include="Web\Models\FullAlbum.cs" />
<Compile Include="Web\Models\FullArtist.cs" /> <Compile Include="Web\Models\FullArtist.cs" />
<Compile Include="Web\Models\FullTrack.cs" /> <Compile Include="Web\Models\FullTrack.cs" />
<Compile Include="Web\Models\NewAlbumReleases.cs" /> <Compile Include="Web\Models\NewAlbumReleases.cs" />
<Compile Include="Web\Models\PlaybackContext.cs" />
<Compile Include="Web\Models\PlayHistory.cs" /> <Compile Include="Web\Models\PlayHistory.cs" />
<Compile Include="Web\Models\Recommendations.cs" /> <Compile Include="Web\Models\Recommendations.cs" />
<Compile Include="Web\Models\RecommendationSeed .cs" /> <Compile Include="Web\Models\RecommendationSeed .cs" />

View File

@ -0,0 +1,17 @@
using System;
namespace SpotifyAPI.Web.Enums
{
[Flags]
public enum RepeatState
{
[String("track")]
Track = 1,
[String("context")]
Context = 2,
[String("off")]
Off = 4
}
}

View File

@ -48,6 +48,12 @@ namespace SpotifyAPI.Web.Enums
PlaylistReadCollaborative = 8192, PlaylistReadCollaborative = 8192,
[String("user-read-recently-played")] [String("user-read-recently-played")]
UserReadRecentlyPlayed = 16384 UserReadRecentlyPlayed = 16384,
[String("user-read-playback-state")]
UserReadPlaybackState = 32768,
[String("user-modify-playback-state")]
UserModifyPlaybackState = 65536
} }
} }

View File

@ -0,0 +1,11 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class AvailabeDevices : BasicModel
{
[JsonProperty("devices")]
public List<Device> Devices { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using Newtonsoft.Json;
namespace SpotifyAPI.Web.Models
{
public class Device
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("is_active")]
public bool IsActive { get; set; }
[JsonProperty("is_restricted")]
public bool IsRestricted { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("volume_percent")]
public int VolumePercent { get; set; }
}
}

View File

@ -0,0 +1,35 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using SpotifyAPI.Web.Enums;
namespace SpotifyAPI.Web.Models
{
public class PlaybackContext : BasicModel
{
[JsonProperty("device")]
public Device Device { get; set; }
[JsonProperty("repeat_state")]
[JsonConverter(typeof(StringEnumConverter))]
public RepeatState RepeatState { get; set; }
[JsonProperty("shuffle_state")]
public bool ShuffleState { get; set; }
[JsonProperty("context")]
public Context Context { get; set; }
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
[JsonProperty("progress_ms")]
public int ProgressMs { get; set; }
[JsonProperty("is_playing")]
public bool IsPlaying { get; set; }
[JsonProperty("item")]
public FullTrack Item { get; set; }
}
}

View File

@ -4,6 +4,7 @@ using SpotifyAPI.Web.Enums;
using SpotifyAPI.Web.Models; using SpotifyAPI.Web.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Dynamic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
@ -1825,6 +1826,170 @@ namespace SpotifyAPI.Web
#endregion Tracks #endregion Tracks
#region Player
/// <summary>
/// Get information about a users available devices.
/// </summary>
/// <returns></returns>
public AvailabeDevices GetDevices()
{
return DownloadData<AvailabeDevices>(_builder.GetDevices());
}
/// <summary>
/// Get information about the users current playback state, including track, track progress, and active device.
/// </summary>
/// <param name="market">An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.</param>
/// <returns></returns>
public PlaybackContext GetPlayback(string market = "")
{
return DownloadData<PlaybackContext>(_builder.GetPlayback(market));
}
/// <summary>
/// Get the object currently being played on the users Spotify account.
/// </summary>
/// <param name="market">An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.</param>
/// <returns></returns>
public PlaybackContext GetPlayingTrack(string market = "")
{
return DownloadData<PlaybackContext>(_builder.GetPlayingTrack(market));
}
/// <summary>
/// Transfer playback to a new device and determine if it should start playing.
/// </summary>
/// <param name="deviceId">ID of the device on which playback should be started/transferred to</param>
/// <param name="play">
/// true: ensure playback happens on new device.
/// false or not provided: keep the current playback state.
/// </param>
/// <returns></returns>
public ErrorResponse TransferPlayback(string deviceId, bool play = false) => TransferPlayback(
new List<string> { deviceId }, play);
/// <summary>
/// Transfer playback to a new device and determine if it should start playing.
/// NOTE: Although an array is accepted, only a single device_id is currently supported. Supplying more than one will return 400 Bad Request
/// </summary>
/// <param name="deviceIds">A array containing the ID of the device on which playback should be started/transferred.</param>
/// <param name="play">
/// true: ensure playback happens on new device.
/// false or not provided: keep the current playback state.
/// </param>
/// <returns></returns>
public ErrorResponse TransferPlayback(List<string> deviceIds, bool play = false)
{
JObject ob = new JObject()
{
{ "play", play },
{ "device_ids", new JArray(deviceIds) }
};
return UploadData<ErrorResponse>(_builder.TransferPlayback(), ob.ToString(Formatting.None), "PUT");
}
/// <summary>
/// Start a new context or resume current playback on the users active device.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <param name="contextUri">Spotify URI of the context to play.</param>
/// <param name="uris">A JSON array of the Spotify track URIs to play.</param>
/// <param name="offset">Indicates from where in the context playback should start.
/// Only available when context_uri corresponds to an album or playlist object, or when the uris parameter is used.</param>
/// <returns></returns>
public ErrorResponse ResumePlayback(string deviceId = "", string contextUri = "", List<string> uris = null,
int? offset = null)
{
JObject ob = new JObject();
if(!string.IsNullOrEmpty(contextUri))
ob.Add("context_uri", contextUri);
if(uris != null)
ob.Add("uris", new JArray(uris));
if(offset != null)
ob.Add("offset", offset);
return UploadData<ErrorResponse>(_builder.ResumePlayback(deviceId), ob.ToString(Formatting.None), "PUT");
}
/// <summary>
/// Pause playback on the users account.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse PausePlayback(string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.PausePlayback(deviceId), string.Empty, "PUT");
}
/// <summary>
/// Skips to next track in the users queue.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse SkipPlaybackToNext(string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.SkipPlaybackToNext(deviceId), string.Empty);
}
/// <summary>
/// Skips to previous track in the users queue.
/// Note that this will ALWAYS skip to the previous track, regardless of the current tracks progress.
/// Returning to the start of the current track should be performed using the https://api.spotify.com/v1/me/player/seek endpoint.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse SkipPlaybackToPrevious(string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.SkipPlaybackToPrevious(deviceId), string.Empty);
}
/// <summary>
/// Seeks to the given position in the users currently playing track.
/// </summary>
/// <param name="positionMs">The position in milliseconds to seek to. Must be a positive number.
/// Passing in a position that is greater than the length of the track will cause the player to start playing the next song.</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse SeekPlayback(int positionMs, string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.SeekPlayback(positionMs, deviceId), string.Empty);
}
/// <summary>
/// Set the repeat mode for the users playback. Options are repeat-track, repeat-context, and off.
/// </summary>
/// <param name="state">track, context or off. </param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse SetRepeatMode(RepeatState state, string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.SetRepeatMode(state, deviceId), string.Empty);
}
/// <summary>
/// Set the volume for the users current playback device.
/// </summary>
/// <param name="volumePercent">Integer. The volume to set. Must be a value from 0 to 100 inclusive.</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse SetVolume(int volumePercent, string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.SetVolume(volumePercent, deviceId), string.Empty);
}
/// <summary>
/// Toggle shuffle on or off for users playback.
/// </summary>
/// <param name="shuffle">True or False</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public ErrorResponse SetShuffle(bool shuffle, string deviceId = "")
{
return UploadData<ErrorResponse>(_builder.SetShuffle(shuffle, deviceId), string.Empty);
}
#endregion
#region Util #region Util
public TOut GetNextPage<TOut, TIn>(Paging<TIn> paging) where TOut : BasicModel public TOut GetNextPage<TOut, TIn>(Paging<TIn> paging) where TOut : BasicModel

View File

@ -354,7 +354,7 @@ namespace SpotifyAPI.Web
{ {
limit = Math.Min(limit, 50); limit = Math.Min(limit, 50);
const FollowType followType = FollowType.Artist; //currently only artist is supported. const FollowType followType = FollowType.Artist; //currently only artist is supported.
StringBuilder builder = new StringBuilder(APIBase + "/me/following?type=" + followType.GetStringAttribute("")); StringBuilder builder = new StringBuilder(APIBase + "/me/following?type=" + followType.GetStringAttribute());
builder.Append("&limit=" + limit); builder.Append("&limit=" + limit);
if (!string.IsNullOrEmpty(after)) if (!string.IsNullOrEmpty(after))
builder.Append("&after=" + after); builder.Append("&after=" + after);
@ -369,7 +369,7 @@ namespace SpotifyAPI.Web
/// <remarks>AUTH NEEDED</remarks> /// <remarks>AUTH NEEDED</remarks>
public string Follow(FollowType followType) public string Follow(FollowType followType)
{ {
return $"{APIBase}/me/following?type={followType.GetStringAttribute("")}"; return $"{APIBase}/me/following?type={followType.GetStringAttribute()}";
} }
/// <summary> /// <summary>
@ -380,7 +380,7 @@ namespace SpotifyAPI.Web
/// <remarks>AUTH NEEDED</remarks> /// <remarks>AUTH NEEDED</remarks>
public string Unfollow(FollowType followType) public string Unfollow(FollowType followType)
{ {
return $"{APIBase}/me/following?type={followType.GetStringAttribute("")}"; return $"{APIBase}/me/following?type={followType.GetStringAttribute()}";
} }
/// <summary> /// <summary>
@ -392,7 +392,7 @@ namespace SpotifyAPI.Web
/// <remarks>AUTH NEEDED</remarks> /// <remarks>AUTH NEEDED</remarks>
public string IsFollowing(FollowType followType, List<string> ids) public string IsFollowing(FollowType followType, List<string> ids)
{ {
return $"{APIBase}/me/following/contains?type={followType.GetStringAttribute("")}&ids={string.Join(",", ids)}"; return $"{APIBase}/me/following/contains?type={followType.GetStringAttribute()}&ids={string.Join(",", ids)}";
} }
/// <summary> /// <summary>
@ -563,7 +563,7 @@ namespace SpotifyAPI.Web
StringBuilder builder = new StringBuilder($"{APIBase}/me/top/tracks"); StringBuilder builder = new StringBuilder($"{APIBase}/me/top/tracks");
builder.Append("?limit=" + limit); builder.Append("?limit=" + limit);
builder.Append("&offset=" + offest); builder.Append("&offset=" + offest);
builder.Append("&time_range=" + timeRange.GetStringAttribute("")); builder.Append("&time_range=" + timeRange.GetStringAttribute());
return builder.ToString(); return builder.ToString();
} }
@ -583,7 +583,7 @@ namespace SpotifyAPI.Web
StringBuilder builder = new StringBuilder($"{APIBase}/me/top/artists"); StringBuilder builder = new StringBuilder($"{APIBase}/me/top/artists");
builder.Append("?limit=" + limit); builder.Append("?limit=" + limit);
builder.Append("&offset=" + offest); builder.Append("&offset=" + offest);
builder.Append("&time_range=" + timeRange.GetStringAttribute("")); builder.Append("&time_range=" + timeRange.GetStringAttribute());
return builder.ToString(); return builder.ToString();
} }
@ -840,5 +840,153 @@ namespace SpotifyAPI.Web
} }
#endregion Tracks #endregion Tracks
#region Player
/// <summary>
/// Get information about a users available devices.
/// </summary>
/// <returns></returns>
public string GetDevices()
{
return $"{APIBase}/me/player/devices";
}
/// <summary>
/// Get information about the users current playback state, including track, track progress, and active device.
/// </summary>
/// <param name="market">An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.</param>
/// <returns></returns>
public string GetPlayback(string market = "")
{
if (string.IsNullOrEmpty(market))
return $"{APIBase}/me/player";
return $"{APIBase}/me/player?market={market}";
}
/// <summary>
/// Get the object currently being played on the users Spotify account.
/// </summary>
/// <param name="market">An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.</param>
/// <returns></returns>
public string GetPlayingTrack(string market = "")
{
if (string.IsNullOrEmpty(market))
return $"{APIBase}/me/player/currently-playing";
return $"{APIBase}/me/player/currently-playing?market={market}";
}
/// <summary>
/// Transfer playback to a new device and determine if it should start playing.
/// </summary>
/// <returns></returns>
public string TransferPlayback()
{
return $"{APIBase}/me/player";
}
/// <summary>
/// Start a new context or resume current playback on the users active device.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string ResumePlayback(string deviceId = "")
{
if(string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/play";
return $"{APIBase}/me/player/play?device_id={deviceId}";
}
/// <summary>
/// Pause playback on the users account.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string PausePlayback(string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/pause";
return $"{APIBase}/me/player/pause?device_id={deviceId}";
}
/// <summary>
/// Skips to next track in the users queue.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string SkipPlaybackToNext(string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/next";
return $"{APIBase}/me/player/next?device_id={deviceId}";
}
/// <summary>
/// Skips to previous track in the users queue.
/// Note that this will ALWAYS skip to the previous track, regardless of the current tracks progress.
/// Returning to the start of the current track should be performed using the https://api.spotify.com/v1/me/player/seek endpoint.
/// </summary>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string SkipPlaybackToPrevious(string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/previous";
return $"{APIBase}/me/player/previous?device_id={deviceId}";
}
/// <summary>
/// Seeks to the given position in the users currently playing track.
/// </summary>
/// <param name="positionMs">The position in milliseconds to seek to. Must be a positive number.
/// Passing in a position that is greater than the length of the track will cause the player to start playing the next song.</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string SeekPlayback(int positionMs, string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/seek?position_ms={positionMs}";
return $"{APIBase}/me/player/seek?position_ms={positionMs}&device_id={deviceId}";
}
/// <summary>
/// Set the repeat mode for the users playback. Options are repeat-track, repeat-context, and off.
/// </summary>
/// <param name="repeatState">track, context or off.</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string SetRepeatMode(RepeatState repeatState, string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/repeat?state={repeatState.GetStringAttribute()}";
return $"{APIBase}/me/player/repeat?state={repeatState.GetStringAttribute()}&device_id={deviceId}";
}
/// <summary>
/// Set the volume for the users current playback device.
/// </summary>
/// <param name="volumePercent">Integer. The volume to set. Must be a value from 0 to 100 inclusive.</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string SetVolume(int volumePercent, string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/volume?volume_percent={volumePercent}";
return $"{APIBase}/me/player/volume?volume_percent={volumePercent}&device_id={deviceId}";
}
/// <summary>
/// Toggle shuffle on or off for users playback.
/// </summary>
/// <param name="shuffle">True of False.</param>
/// <param name="deviceId">The id of the device this command is targeting. If not supplied, the user's currently active device is the target.</param>
/// <returns></returns>
public string SetShuffle(bool shuffle, string deviceId = "")
{
if (string.IsNullOrEmpty(deviceId))
return $"{APIBase}/me/player/shuffle?state={shuffle}";
return $"{APIBase}/me/player/shuffle?state={shuffle}&device_id={deviceId}";
}
#endregion
} }
} }

View File

@ -7,7 +7,7 @@ namespace SpotifyAPI.Web
{ {
public static class Util public static class Util
{ {
public static string GetStringAttribute<T>(this T en, string separator) where T : struct, IConvertible public static string GetStringAttribute<T>(this T en, string separator = "") where T : struct, IConvertible
{ {
Enum e = (Enum)(object)en; Enum e = (Enum)(object)en;
IEnumerable<StringAttribute> attributes = IEnumerable<StringAttribute> attributes =