public void ArtistUri_ArtistUriWhitespaceString_ThrowsArgumentException() { // arrange const string uri = " "; // act SpotifyUriHelper.ArtistUri(uri); }
public async Task <T> GetPlaylist <T>(string playlistId, string accessToken = null) { if (string.IsNullOrEmpty(playlistId)) { throw new ArgumentNullException(nameof(playlistId)); } return(await GetModel <T>($"{BaseUrl}/playlists/{SpotifyUriHelper.PlaylistId(playlistId)}", accessToken)); }
public void ArtistUri_ArtistUriNull_ThrowsArgumentException() { // arrange const string uri = null; // act SpotifyUriHelper.ArtistUri(uri); }
public void ArtistUri_ArtistUriLeadingWhitespace_ThrowsArgumentException() { // arrange const string uri = " spotify:album:0TnOYISbd1XYRBk9myaseg"; // act SpotifyUriHelper.ArtistUri(uri); }
/// <summary> /// BETA. Play an Artist on the user’s active device. /// </summary> /// <param name="artistId">Spotify Album Id to play</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service. /// The access token must have been issued on behalf of a user. The access token must have the /// `user-modify-playback-state` scope authorized in order to control playback. <seealso cref="UserAccountsService"/> /// </param> /// <param name="deviceId">Optional. The id of the device this command is targeting. If not supplied, the user’s /// currently active device is the target.</param> /// <param name="positionMs">Optional. Indicates from what position to start playback. 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> /// <remarks> /// https://developer.spotify.com/documentation/web-api/reference/player/start-a-users-playback/ /// </remarks> public async Task PlayArtist(string artistId, string accessToken = null, string deviceId = null, long positionMs = 0) { if (string.IsNullOrEmpty(artistId)) { throw new ArgumentNullException(nameof(artistId)); } dynamic data = JObject.FromObject(new { context_uri = SpotifyUriHelper.ArtistUri(artistId) }); await Play(data, accessToken, deviceId, positionMs); }
/// <summary> /// Get Spotify catalog information for a single album. /// </summary> /// <param name="albumId">The Spotify ID for the album.</param> /// <param name="market">Optional. An ISO 3166-1 alpha-2 country code or the string `from_token` /// (See <see cref="SpotifyCountryCodes"/>). Provide this parameter if you want to apply Track Relinking.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>A Task that, once successfully completed, returns a Model of T.</returns> /// <remarks>https://developer.spotify.com/documentation/web-api/reference/albums/get-album/</remarks> public async Task <T> GetAlbum <T>(string albumId, string market = null, string accessToken = null) { string url = $"{BaseUrl}/albums/{SpotifyUriHelper.AlbumId(albumId)}"; if (!string.IsNullOrEmpty(market)) { url += $"?market={market}"; } return(await GetModel <T>(url, accessToken)); }
public void PlaylistUri_ValidPlaylistUri_ReturnsPlaylistUri() { // arrange const string uri = "spotify:playlist:0TnOYISbd1XYRBk9myaseg"; // act string result = SpotifyUriHelper.PlaylistUri(uri); // assert Assert.AreSame(uri, result); }
public void ArtistUri_UserCollectionArtist_ReturnsCollectionUri() { // arrange const string collectionUri = "spotify:user:daniellarsennz:collection:artist:65XA3lk0aG9XejO8y37jjD"; // act string uri = SpotifyUriHelper.ArtistUri(collectionUri); // assert Assert.AreEqual(collectionUri, uri); }
public void PlaylistUri_NumericUsername_ExtractsValidUri() { // arrange const string fullUri = "spotify:user:1298341199:playlist:6RTNx0BJWjbmJuEfvMau3r"; // act string uri = SpotifyUriHelper.PlaylistUri(fullUri); // assert Assert.AreEqual(fullUri, uri); }
public void TrackUri_ValidTrackUri_ReturnsTrackUri() { // arrange const string uri = "spotify:track:0TnOYISbd1XYRBk9myaseg"; // act string result = SpotifyUriHelper.TrackUri(uri); // assert Assert.AreSame(uri, result); }
public void PlaylistUri_NumericUserIdInUri_ReturnsPlaylistUri() { // arrange const string uri = "spotify:user:122740800:playlist:6CI5ScAEKJdHMmQsfjHOmY"; // act string result = SpotifyUriHelper.PlaylistUri(uri); // assert Assert.AreSame(uri, result); }
public void PlaylistUri_DashInUserUri_ReturnsPlaylistUri() { // arrange const string uri = "spotify:user:trojan-records:playlist:0HHuexBIs4gdPZ2WeNGDt3"; // act string result = SpotifyUriHelper.PlaylistUri(uri); // assert Assert.AreSame(uri, result); }
public void PlaylistUri_UnderscoreInUri_ReturnsPlaylistUri() { // arrange const string uri = "spotify:user:catstevens_islanduk:playlist:4DgyX0TYmDJvjKlAVtkRxo"; //spotify:user:122740800:playlist:6CI5ScAEKJdHMmQsfjHOmY // act string result = SpotifyUriHelper.PlaylistUri(uri); // assert Assert.AreSame(uri, result); }
public void ArtistId_UserCollectionArtistUri_ReturnsArtistId() { // arrange const string artistId = "65XA3lk0aG9XejO8y37jjD"; string collectionUri = $"spotify:user:daniellarsennz:collection:artist:{artistId}"; // act string id = SpotifyUriHelper.ArtistId(collectionUri); // assert Assert.AreEqual(artistId, id); }
public void PlaylistUri_PlaylistUriMoreThan3Parts_ExtractsValidUri() { // arrange const string playlistUri = "spotify:playlist:0TnOYISbd1XYRBk9myaseg"; string fullUri = $"spotify:user:{playlistUri}"; // act string uri = SpotifyUriHelper.PlaylistUri(fullUri); // assert Assert.AreEqual(playlistUri, uri); }
/// <summary> /// Get Spotify catalog information about an artist’s top tracks by country. /// </summary> /// <param name="artistId">The Spotify ID for the artist.</param> /// <param name="market">Required. An ISO 3166-1 alpha-2 country code (<see cref="SpotifyCountryCodes"/>) /// or the string `from_token`.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service, /// used for this call only. See constructors for more ways to provide access tokens.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>Task of T. The Spotify response is deserialised as T.</returns> public async Task <T> GetArtistsTopTracks <T>(string artistId, string market, string accessToken = null) { if (string.IsNullOrWhiteSpace(artistId)) { throw new ArgumentNullException("artistId"); } if (string.IsNullOrWhiteSpace(market)) { throw new ArgumentNullException("market"); } return(await GetModelFromProperty <T>($"{BaseUrl}/artists/{SpotifyUriHelper.ArtistId(artistId)}/top-tracks?country={market}", "tracks", accessToken)); }
/// <summary> /// BETA. Play a Playlist on the user’s active device. /// </summary> /// <param name="playlistId">Spotify Playlist Id to play</param> /// <param name="offsetPosition">From where in the Playlist playback should start, i.e. Track number</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service. /// The access token must have been issued on behalf of a user. The access token must have the /// `user-modify-playback-state` scope authorized in order to control playback. <seealso cref="UserAccountsService"/> /// </param> /// <param name="deviceId">Optional. The id of the device this command is targeting. If not supplied, the user’s /// currently active device is the target.</param> /// <param name="positionMs">Optional. Indicates from what position to start playback. 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> /// <remarks> /// https://developer.spotify.com/documentation/web-api/reference/player/start-a-users-playback/ /// </remarks> public async Task PlayPlaylistOffset( string playlistId, int offsetPosition, string accessToken = null, string deviceId = null, long positionMs = 0) { dynamic data = JObject.FromObject(new { context_uri = SpotifyUriHelper.PlaylistUri(playlistId) }); if (offsetPosition > 0) { data.offset = JObject.FromObject(new { position = offsetPosition }); } await Play(data, accessToken, deviceId, positionMs); }
/// <summary> /// BETA. Play an Album from a Track offset on the user’s active device. /// </summary> /// <param name="albumId">Spotify Album Id to play</param> /// <param name="offsetTrackId">Id of the Track to start at</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service. /// The access token must have been issued on behalf of a user. The access token must have the /// `user-modify-playback-state` scope authorized in order to control playback. <seealso cref="UserAccountsService"/> /// </param> /// <param name="deviceId">Optional. The id of the device this command is targeting. If not supplied, the user’s /// currently active device is the target.</param> /// <param name="positionMs">Optional. Indicates from what position to start playback. 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> /// <remarks> /// https://developer.spotify.com/documentation/web-api/reference/player/start-a-users-playback/ /// </remarks> public async Task PlayAlbumOffset( string albumId, string offsetTrackId, string accessToken = null, string deviceId = null, long positionMs = 0) { dynamic data = JObject.FromObject(new { context_uri = SpotifyUriHelper.AlbumUri(albumId) }); if (offsetTrackId != null) { data.offset = JObject.FromObject(new { uri = SpotifyUriHelper.TrackUri(offsetTrackId) }); } await Play(data, accessToken, deviceId, positionMs); }
/// <summary> /// Get a playlist owned by a Spotify user. /// </summary> /// <param name="playlistId">The Spotify ID for the playlist.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service. /// <param name="fields">Optional. Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are returned. See docs for examples.</param> /// <param name="additionalTypes">Optional. A comma-separated list of item types that your /// client supports besides the default track type. Valid types are: `track` and `episode`. /// Note: This parameter was introduced to allow existing clients to maintain their current /// behaviour and might be deprecated in the future. In addition to providing this parameter, /// make sure that your client properly handles cases of new types in the future by checking /// against the type field of each object.</param> /// <param name="market">Optional. An <see cref="SpotifyCountryCodes"/> or the string <see cref="SpotifyCountryCodes._From_Token"/>. /// Provide this parameter if you want to apply Track Relinking.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>Task of T</returns> public async Task <T> GetPlaylist <T>( string playlistId, string accessToken = null, string fields = null, string[] additionalTypes = null, string market = null) { if (string.IsNullOrEmpty(playlistId)) { throw new ArgumentNullException(nameof(playlistId)); } var builder = new UriBuilder($"{BaseUrl}/playlists/{SpotifyUriHelper.PlaylistId(playlistId)}"); builder.AppendToQueryIfValueNotNullOrWhiteSpace("fields", fields); builder.AppendToQueryAsCsv("additional_types", additionalTypes); builder.AppendToQueryIfValueNotNullOrWhiteSpace("market", market); return(await GetModel <T>(builder.Uri, accessToken : accessToken)); }
/// <summary> /// Get full details of the tracks of a playlist owned by a Spotify user. /// </summary> /// <param name="playlistId">The Spotify ID for the playlist.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service. /// <param name="fields">Optional. Filters for the query: a comma-separated list of the fields to return. If omitted, all fields are returned. See docs for examples.</param> /// <param name="limit">Optional. The maximum number of tracks to return. Default: 100. Minimum: 1. Maximum: 100.</param> /// <param name="offset">Optional. The index of the first track to return. Default: 0 (the first object).</param> /// <param name="market">Optional. An <see cref="SpotifyCountryCodes"/> or the string <see cref="SpotifyCountryCodes._From_Token"/>. /// Provide this parameter if you want to apply Track Relinking.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>Task of T</returns> /// <remarks> /// https://developer.spotify.com/documentation/web-api/reference/playlists/get-playlists-tracks/ /// </remarks> public async Task <T> GetTracks <T>( string playlistId, string accessToken = null, string fields = null, int?limit = null, int offset = 0, string market = null) { if (string.IsNullOrEmpty(playlistId)) { throw new ArgumentNullException(nameof(playlistId)); } string url = $"{BaseUrl}/playlists/{SpotifyUriHelper.PlaylistId(playlistId)}/tracks"; if (!string.IsNullOrEmpty(fields) || (limit ?? 0) > 0 || offset > 0 || !string.IsNullOrEmpty(market)) { url += "?"; if (!string.IsNullOrEmpty(fields)) { url += $"fields={fields}&"; } if ((limit ?? 0) > 0) { url += $"limit={limit.Value}&"; } if (offset > 0) { url += $"offset={offset}&"; } if (!string.IsNullOrEmpty(market)) { url += $"market={market}"; } } return(await GetModel <T>(url, accessToken)); }
public async Task <T> NewGetAlbumTracks <T>( string albumId, int?limit = null, int offset = 0, string market = null, string accessToken = null) { var url = "https://api.spotify.com/v1/albums/" + SpotifyUriHelper.AlbumId(albumId) + "/tracks"; if (limit.HasValue || !string.IsNullOrEmpty(market)) { url += "?"; } if (limit.HasValue) { url += $"limit={limit.Value}&offset={offset}&"; } if (!string.IsNullOrEmpty(market)) { url = url + "market=" + market; } return(await GetModelFromProperty <T>(url, "items", accessToken)); }
/// <summary> /// Get Spotify catalog information about an album’s tracks. Optional parameters can be used to limit the number of tracks returned. /// </summary> /// <param name="albumId">The Spotify ID for the album.</param> /// <param name="limit">Optional. The maximum number of tracks to return. Default: 20. Minimum: 1. Maximum: 50.</param> /// <param name="offset">Optional. The index of the first track to return. Default: 0 (the first /// object). Use with limit to get the next set of tracks.</param> /// <param name="market">Optional. An ISO 3166-1 alpha-2 country code or the string `from_token` /// (See <see cref="SpotifyCountryCodes"/>). Provide this parameter if you want to apply Track Relinking.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>A Task that, once successfully completed, returns a Model of T.</returns> /// <remarks>https://developer.spotify.com/documentation/web-api/reference/albums/get-albums-tracks/</remarks> public async Task <T> GetAlbumTracks <T>( string albumId, int?limit = null, int offset = 0, string market = null, string accessToken = null) { string url = $"{BaseUrl}/albums/{SpotifyUriHelper.AlbumId(albumId)}/tracks"; if (limit.HasValue || !string.IsNullOrEmpty(market)) { url += "?"; } if (limit.HasValue) { url += $"limit={limit.Value}&offset={offset}&"; } if (!string.IsNullOrEmpty(market)) { url += $"market={market}"; } return(await GetModel <T>(url, accessToken)); }
/// <summary> /// Get Spotify catalog information about artists similar to a given artist. Similarity is /// based on analysis of the Spotify community’s listening history. /// </summary> /// <param name="artistId">The Spotify ID for the artist.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service, /// used for this call only. See constructors for more ways to provide access tokens.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>Task of T. The Spotify response is deserialised as T.</returns> public async Task <T> GetRelatedArtists <T>(string artistId, string accessToken = null) => await GetModel <T>($"{BaseUrl}/artists/{SpotifyUriHelper.ArtistId(artistId)}/related-artists", accessToken);
/// <summary> /// Get Spotify catalog information for a single artist identified by their unique Spotify ID. /// </summary> /// <param name="artistId">The Spotify ID for the artist.</param> /// <param name="accessToken">Optional. A valid access token from the Spotify Accounts service, /// used for this call only. See constructors for more ways to provide access tokens.</param> /// <typeparam name="T">Optionally provide your own type to deserialise Spotify's response to.</typeparam> /// <returns>Task of T. The Spotify response is deserialised as T.</returns> public async Task <T> GetArtist <T>(string artistId, string accessToken = null) => await GetModel <T>(new Uri($"{BaseUrl}/artists/{SpotifyUriHelper.ArtistId(artistId)}"), accessToken);
public async Task <bool> JoinPlaylist( string query, string token, Station station, string stationToken, CancellationToken cancellationToken) { // is the station playing? // default the position to what was returned by get info var info = await GetUserNowPlaying(stationToken); if ( info == null || !info.IsPlaying || info.Context == null || SpotifyUriHelper.NormalizeUri(info.Context.Uri) != SpotifyUriHelper.NormalizeUri(station.SpotifyUri)) { _logger.LogInformation($"JoinPlaylist: No longer playing station {station}"); _logger.LogDebug($"JoinPlaylist: station.SpotifyUri = {station.SpotifyUri}"); _logger.LogDebug($"JoinPlaylist: info = {JsonConvert.SerializeObject(info)}"); return(false); } (string itemId, (long positionMs, DateTime atUtc)position)itemPosition = (info.Item?.Id, (info.ProgressMs ?? 0, DateTime.UtcNow)); if (!SupportedSpotifyItemTypes.Contains(station.SpotifyContextType)) { throw new NotSupportedException($"\"{station.SpotifyContextType}\" is not a supported Spotify context type"); } var offset = await GetOffset(stationToken); if (offset.success) { // reset position to Station position itemPosition.itemId = offset.itemId; itemPosition.position = offset.position; } await TurnOffShuffleRepeat(token, info); try { // mute joining player await Volume(token, 0, info.Device.Id); // play from offset switch (station.SpotifyContextType) { case "album": await RetryHelper.RetryAsync( () => _player.PlayAlbumOffset( info.Context.Uri, info.Item.Id, accessToken: token, positionMs: PositionMsNow(itemPosition.position).positionMs), logger : _logger, cancellationToken : cancellationToken); break; case "playlist": await RetryHelper.RetryAsync( () => _player.PlayPlaylistOffset( info.Context.Uri, info.Item.Id, accessToken: token, positionMs: PositionMsNow(itemPosition.position).positionMs), logger : _logger, cancellationToken : cancellationToken); break; } if (offset.success) { await SyncJoiningPlayer(stationToken : stationToken, joiningToken : token); } } finally { // unmute joining player await Volume(token, (int)info.Device.VolumePercent, info.Device.Id); } return(true); }