UNPKG

spotify-web-api-node

Version:
1,166 lines (1,083 loc) 71.5 kB
'use strict'; var AuthenticationRequest = require('./authentication-request'), WebApiRequest = require('./webapi-request'), HttpManager = require('./http-manager'); function SpotifyWebApi(credentials) { this._credentials = credentials || {}; } SpotifyWebApi.prototype = { setCredentials: function(credentials) { for (var key in credentials) { if (credentials.hasOwnProperty(key)) { this._credentials[key] = credentials[key]; } } }, getCredentials: function() { return this._credentials; }, resetCredentials: function() { this._credentials = null; }, setClientId: function(clientId) { this._setCredential('clientId', clientId); }, setClientSecret: function(clientSecret) { this._setCredential('clientSecret', clientSecret); }, setAccessToken: function(accessToken) { this._setCredential('accessToken', accessToken); }, setRefreshToken: function(refreshToken) { this._setCredential('refreshToken', refreshToken); }, setRedirectURI: function(redirectUri) { this._setCredential('redirectUri', redirectUri); }, getRedirectURI: function() { return this._getCredential('redirectUri'); }, getClientId: function() { return this._getCredential('clientId'); }, getClientSecret: function() { return this._getCredential('clientSecret'); }, getAccessToken: function() { return this._getCredential('accessToken'); }, getRefreshToken: function() { return this._getCredential('refreshToken'); }, resetClientId: function() { this._resetCredential('clientId'); }, resetClientSecret: function() { this._resetCredential('clientSecret'); }, resetAccessToken: function() { this._resetCredential('accessToken'); }, resetRefreshToken: function() { this._resetCredential('refreshToken'); }, resetRedirectURI: function() { this._resetCredential('redirectUri'); }, _setCredential: function(credentialKey, value) { this._credentials = this._credentials || {}; this._credentials[credentialKey] = value; }, _getCredential: function(credentialKey) { if (!this._credentials) { return; } else { return this._credentials[credentialKey]; } }, _resetCredential: function(credentialKey) { if (!this._credentials) { return; } else { this._credentials[credentialKey] = null; } }, /** * Look up a track. * @param {string} trackId The track's ID. * @param {Object} [options] The possible options, currently only market. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getTrack('3Qm86XLflmIXVm1wcwkgDK').then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing information * about the track. Not returned if a callback is given. */ getTrack: function(trackId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/tracks/' + trackId) .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Look up several tracks. * @param {string[]} trackIds The IDs of the artists. * @param {Object} [options] The possible options, currently only market. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getArtists(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing information * about the artists. Not returned if a callback is given. */ getTracks: function(trackIds, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/tracks') .withQueryParameters( { ids: trackIds.join(',') }, options ) .build() .execute(HttpManager.get, callback); }, /** * Look up an album. * @param {string} albumId The album's ID. * @param {Object} [options] The possible options, currently only market. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAlbum('0sNOF9WDwhWunNAHPD3Baj').then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing information * about the album. Not returned if a callback is given. */ getAlbum: function(albumId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/albums/' + albumId) .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Look up several albums. * @param {string[]} albumIds The IDs of the albums. * @param {Object} [options] The possible options, currently only market. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAlbums(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing information * about the albums. Not returned if a callback is given. */ getAlbums: function(albumIds, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/albums') .withQueryParameters( { ids: albumIds.join(',') }, options ) .build() .execute(HttpManager.get, callback); }, /** * Look up an artist. * @param {string} artistId The artist's ID. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example api.getArtist('1u7kkVrr14iBvrpYnZILJR').then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing information * about the artist. Not returned if a callback is given. */ getArtist: function(artistId, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/artists/' + artistId) .build() .execute(HttpManager.get, callback); }, /** * Look up several artists. * @param {string[]} artistIds The IDs of the artists. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getArtists(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing information * about the artists. Not returned if a callback is given. */ getArtists: function(artistIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/artists') .withQueryParameters({ ids: artistIds.join(',') }) .build() .execute(HttpManager.get, callback); }, /** * Search for music entities of certain types. * @param {string} query The search query. * @param {string[]} types An array of item types to search across. * Valid types are: 'album', 'artist', 'playlist', 'track', 'show', and 'episode'. * @param {Object} [options] The possible options, e.g. limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example search('Abba', ['track', 'playlist'], { limit : 5, offset : 1 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * search results. The result is paginated. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ search: function(query, types, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/search/') .withQueryParameters( { type: types.join(','), q: query }, options ) .build() .execute(HttpManager.get, callback); }, /** * Search for an album. * @param {string} query The search query. * @param {Object} [options] The possible options, e.g. limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example searchAlbums('Space Oddity', { limit : 5, offset : 1 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * search results. The result is paginated. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ searchAlbums: function(query, options, callback) { return this.search(query, ['album'], options, callback); }, /** * Search for an artist. * @param {string} query The search query. * @param {Object} [options] The possible options, e.g. limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example searchArtists('David Bowie', { limit : 5, offset : 1 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * search results. The result is paginated. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ searchArtists: function(query, options, callback) { return this.search(query, ['artist'], options, callback); }, /** * Search for a track. * @param {string} query The search query. * @param {Object} [options] The possible options, e.g. limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example searchTracks('Mr. Brightside', { limit : 3, offset : 2 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * search results. The result is paginated. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ searchTracks: function(query, options, callback) { return this.search(query, ['track'], options, callback); }, /** * Search for playlists. * @param {string} query The search query. * @param {Object} options The possible options. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example searchPlaylists('workout', { limit : 1, offset : 0 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * search results. The result is paginated. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ searchPlaylists: function(query, options, callback) { return this.search(query, ['playlist'], options, callback); }, /** * Get an artist's albums. * @param {string} artistId The artist's ID. * @options {Object} [options] The possible options, e.g. limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getArtistAlbums('0oSGxfWSnnOXhD2fKuz2Gy', { album_type : 'album', country : 'GB', limit : 2, offset : 5 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the albums * for the given artist. The result is paginated. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ getArtistAlbums: function(artistId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/artists/' + artistId + '/albums') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get the tracks of an album. * @param albumId the album's ID. * @options {Object} [options] The possible options, e.g. limit. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ', { limit : 5, offset : 1 }).then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * tracks in the album. The result is paginated. If the promise is rejected. * it contains an error object. Not returned if a callback is given. */ getAlbumTracks: function(albumId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/albums/' + albumId + '/tracks') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get an artist's top tracks. * @param {string} artistId The artist's ID. * @param {string} country The country/territory where the tracks are most popular. (format: ISO 3166-1 alpha-2) * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy', 'GB').then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * artist's top tracks in the given country. If the promise is rejected, * it contains an error object. Not returned if a callback is given. */ getArtistTopTracks: function(artistId, country, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/artists/' + artistId + '/top-tracks') .withQueryParameters({ country: country }) .build() .execute(HttpManager.get, callback); }, /** * Get related artists. * @param {string} artistId The artist's ID. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getArtistRelatedArtists('0oSGxfWSnnOXhD2fKuz2Gy').then(...) * @returns {Promise|undefined} A promise that if successful, returns an object containing the * related artists. If the promise is rejected, it contains an error object. Not returned if a callback is given. */ getArtistRelatedArtists: function(artistId, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/artists/' + artistId + '/related-artists') .build() .execute(HttpManager.get, callback); }, /** * Get information about a user. * @param userId The user ID. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getUser('thelinmichael').then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object * containing information about the user. If the promise is * rejected, it contains an error object. Not returned if a callback is given. */ getUser: function(userId, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/users/' + encodeURIComponent(userId)) .build() .execute(HttpManager.get, callback); }, /** * Get information about the user that has signed in (the current user). * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getMe().then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object * containing information about the user. The amount of information * depends on the permissions given by the user. If the promise is * rejected, it contains an error object. Not returned if a callback is given. */ getMe: function(callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me') .build() .execute(HttpManager.get, callback); }, /** * Get a user's playlists. * @param {string} userId An optional id of the user. If you know the Spotify URI it is easy * to find the id (e.g. spotify:user:<here_is_the_id>). If not provided, the id of the user that granted * the permissions will be used. * @param {Object} [options] The options supplied to this request. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getUserPlaylists('thelinmichael').then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object containing * a list of playlists. If rejected, it contains an error object. Not returned if a callback is given. */ getUserPlaylists: function(userId, options, callback) { var path; if (typeof userId === 'string') { path = '/v1/users/' + encodeURIComponent(userId) + '/playlists'; } else if (typeof userId === 'object') { callback = options; options = userId; path = '/v1/me/playlists'; } /* undefined */ else { path = '/v1/me/playlists'; } return WebApiRequest.builder(this.getAccessToken()) .withPath(path) .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get a playlist. * @param {string} playlistId The playlist's ID. * @param {Object} [options] The options supplied to this request. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getPlaylist('3EsfV6XzCHU8SPNdbnFogK').then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object containing * the playlist. If rejected, it contains an error object. Not returned if a callback is given. */ getPlaylist: function(playlistId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId) .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get tracks in a playlist. * @param {string} playlistId The playlist's ID. * @param {Object} [options] Optional options, such as fields. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getPlaylistTracks('3ktAYNcRHpazJ9qecm3ptn').then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object that containing * the tracks in the playlist. If rejected, it contains an error object. Not returned if a callback is given. */ getPlaylistTracks: function(playlistId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/tracks') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Create a playlist. * @param {string} [name] The name of the playlist. * @param {Object} [options] The possible options, being description, collaborative and public. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example createPlaylist('My playlist', {''description': 'My description', 'collaborative' : false, 'public': true}).then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object containing information about the * created playlist. If rejected, it contains an error object. Not returned if a callback is given. */ createPlaylist: function(name, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/playlists') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters({ name : name, }, options) .build() .execute(HttpManager.post, callback); }, /** * Follow a playlist. * @param {string} playlistId The playlist's ID * @param {Object} [options] The possible options, currently only public. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected, * it contains an error object. Not returned if a callback is given. */ followPlaylist: function(playlistId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/followers') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters(options) .build() .execute(HttpManager.put, callback); }, /** * Unfollow a playlist. * @param {string} playlistId The playlist's ID * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected, * it contains an error object. Not returned if a callback is given. */ unfollowPlaylist: function(playlistId, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/followers') .build() .execute(HttpManager.del, callback); }, /** * Change playlist details. * @param {string} playlistId The playlist's ID * @param {Object} [options] The possible options, e.g. name, public. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example changePlaylistDetails('3EsfV6XzCHU8SPNdbnFogK', {name: 'New name', public: true}).then(...) * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected, * it contains an error object. Not returned if a callback is given. */ changePlaylistDetails: function(playlistId, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId) .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters(options) .build() .execute(HttpManager.put, callback); }, /** * Replace the image used to represent a specific playlist. * @param {string} playlistId The playlist's ID * @param {string} base64URI Base64 encoded JPEG image data, maximum payload size is 256 KB * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example uploadCustomPlaylistCoverImage('3EsfV6XzCHU8SPNdbnFogK', 'longbase64uri').then(...) * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected, * it contains an error object. Not returned if a callback is given. */ uploadCustomPlaylistCoverImage: function(playlistId, base64URI, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/images') .withHeaders({ 'Content-Type': 'image/jpeg' }) .withBodyParameters(base64URI) .build() .execute(HttpManager.put, callback); }, /** * Add tracks to a playlist. * @param {string} playlistId The playlist's ID * @param {string[]} tracks URIs of the tracks to add to the playlist. * @param {Object} [options] Options, position being the only one. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example addTracksToPlaylist('3EsfV6XzCHU8SPNdbnFogK', '["spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M"]').then(...) * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected, * it contains an error object. Not returned if a callback is given. */ addTracksToPlaylist: function(playlistId, tracks, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withQueryParameters(options) .withBodyParameters({ uris: tracks }) .build() .execute(HttpManager.post, callback); }, /** * Remove tracks from a playlist. * @param {string} playlistId The playlist's ID * @param {Object[]} tracks An array of objects containing a property called uri with the track URI (String), and * an optional property called positions (int[]), e.g. { uri : "spotify:track:491rM2JN8KvmV6p0oDDuJT", positions : [0, 15] } * @param {Object} options Options, snapshot_id being the only one. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected, * it contains an error object. Not returned if a callback is given. */ removeTracksFromPlaylist: function(playlistId, tracks, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters( { tracks: tracks }, options ) .build() .execute(HttpManager.del, callback); }, /** * Remove tracks from a playlist by position instead of specifying the tracks' URIs. * @param {string} playlistId The playlist's ID * @param {int[]} positions The positions of the tracks in the playlist that should be removed * @param {string} snapshot_id The snapshot ID, or version, of the playlist. Required * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected, * it contains an error object. Not returned if a callback is given. */ removeTracksFromPlaylistByPosition: function( playlistId, positions, snapshotId, callback ) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters({ positions: positions, snapshot_id: snapshotId }) .build() .execute(HttpManager.del, callback); }, /** * Replace tracks in a playlist. * @param {string} playlistId The playlist's ID * @param {Object[]} uris An array of track URIs (strings) * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns an empty object. If rejected, * it contains an error object. Not returned if a callback is given. */ replaceTracksInPlaylist: function(playlistId, uris, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters({ uris: uris }) .build() .execute(HttpManager.put, callback); }, /** * Reorder tracks in a playlist. * @param {string} playlistId The playlist's ID * @param {int} rangeStart The position of the first track to be reordered. * @param {int} insertBefore The position where the tracks should be inserted. * @param {Object} options Optional parameters, i.e. range_length and snapshot_id. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected, * it contains an error object. Not returned if a callback is given. */ reorderTracksInPlaylist: function( playlistId, rangeStart, insertBefore, options, callback ) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/playlists/' + playlistId + '/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters( { range_start: rangeStart, insert_before: insertBefore }, options ) .build() .execute(HttpManager.put, callback); }, /** * Get audio features for a single track identified by its unique Spotify ID. * @param {string} trackId The track ID * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAudioFeaturesForTrack('38P3Q4QcdjQALGF2Z92BmR').then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object * containing information about the audio features. If the promise is * rejected, it contains an error object. Not returned if a callback is given. */ getAudioFeaturesForTrack: function(trackId, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/audio-features/' + trackId) .build() .execute(HttpManager.get, callback); }, /** * Get audio analysis for a single track identified by its unique Spotify ID. * @param {string} trackId The track ID * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAudioAnalysisForTrack('38P3Q4QcdjQALGF2Z92BmR').then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object * containing information about the audio analysis. If the promise is * rejected, it contains an error object. Not returned if a callback is given. */ getAudioAnalysisForTrack: function(trackId, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/audio-analysis/' + trackId) .build() .execute(HttpManager.get, callback); }, /** * Get audio features for multiple tracks identified by their unique Spotify ID. * @param {string[]} trackIds The track IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAudioFeaturesForTracks(['38P3Q4QcdjQALGF2Z92BmR', '2HO2bnoMrpnZUbUqiilLHi']).then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object * containing information about the audio features for the tracks. If the promise is * rejected, it contains an error object. Not returned if a callback is given. */ getAudioFeaturesForTracks: function(trackIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/audio-features') .withQueryParameters({ ids: trackIds.join(',') }) .build() .execute(HttpManager.get, callback); }, /** * Create a playlist-style listening experience based on seed artists, tracks and genres. * @param {Object} [options] The options supplied to this request. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getRecommendations({ min_energy: 0.4, seed_artists: ['6mfK6Q2tzLMEchAr0e9Uzu', '4DYFVNKZ1uixa6SQTvzQwJ'], min_popularity: 50 }).then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object containing * a list of tracks and a list of seeds. If rejected, it contains an error object. Not returned if a callback is given. */ getRecommendations: function(options, callback) { var _opts = {}; var optionsOfTypeArray = ['seed_artists', 'seed_genres', 'seed_tracks']; for (var option in options) { if (options.hasOwnProperty(option)) { if ( optionsOfTypeArray.indexOf(option) !== -1 && Object.prototype.toString.call(options[option]) === '[object Array]' ) { _opts[option] = options[option].join(','); } else { _opts[option] = options[option]; } } } return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/recommendations') .withQueryParameters(_opts) .build() .execute(HttpManager.get, callback); }, /** * Retrieve a list of available genres seed parameter values for recommendations. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example getAvailableGenreSeeds().then(...) * @returns {Promise|undefined} A promise that if successful, resolves to an object containing * a list of available genres to be used as seeds for recommendations. * If rejected, it contains an error object. Not returned if a callback is given. */ getAvailableGenreSeeds: function(callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/recommendations/available-genre-seeds') .build() .execute(HttpManager.get, callback); }, /** * Retrieve the tracks that are saved to the authenticated users Your Music library. * @param {Object} [options] Options, being market, limit, and/or offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which in turn contains * playlist track objects. Not returned if a callback is given. */ getMySavedTracks: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/tracks') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library. * @param {string[]} trackIds The track IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order * of the returned array's elements correspond to the track ID in the request. * The boolean value of true indicates that the track is part of the user's library, otherwise false. * Not returned if a callback is given. */ containsMySavedTracks: function(trackIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/tracks/contains') .withQueryParameters({ ids: trackIds.join(',') }) .build() .execute(HttpManager.get, callback); }, /** * Remove a track from the authenticated user's Your Music library. * @param {string[]} trackIds The track IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. * Not returned if a callback is given. */ removeFromMySavedTracks: function(trackIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters({ ids: trackIds }) .build() .execute(HttpManager.del, callback); }, /** * Add a track from the authenticated user's Your Music library. * @param {string[]} trackIds The track IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. Not returned if a callback is given. */ addToMySavedTracks: function(trackIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/tracks') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters({ ids: trackIds }) .build() .execute(HttpManager.put, callback); }, /** * Remove an album from the authenticated user's Your Music library. * @param {string[]} albumIds The album IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. * Not returned if a callback is given. */ removeFromMySavedAlbums: function(albumIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/albums') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters(albumIds) .build() .execute(HttpManager.del, callback); }, /** * Add an album from the authenticated user's Your Music library. * @param {string[]} albumIds The track IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. Not returned if a callback is given. */ addToMySavedAlbums: function(albumIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/albums') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters(albumIds) .build() .execute(HttpManager.put, callback); }, /** * Retrieve the albums that are saved to the authenticated users Your Music library. * @param {Object} [options] Options, being market, limit, and/or offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which in turn contains * playlist album objects. Not returned if a callback is given. */ getMySavedAlbums: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/albums') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Check if one or more albums is already saved in the current Spotify user’s “Your Music” library. * @param {string[]} albumIds The album IDs * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order * of the returned array's elements correspond to the album ID in the request. * The boolean value of true indicates that the album is part of the user's library, otherwise false. * Not returned if a callback is given. */ containsMySavedAlbums: function(albumIds, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/albums/contains') .withQueryParameters({ ids: albumIds.join(',') }) .build() .execute(HttpManager.get, callback); }, /** * Get the current user's top artists based on calculated affinity. * @param {Object} [options] Options, being time_range, limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of artists, * otherwise an error. Not returned if a callback is given. */ getMyTopArtists: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/top/artists') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get the current user's top tracks based on calculated affinity. * @param {Object} [options] Options, being time_range, limit, offset. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks, * otherwise an error. Not returned if a callback is given. */ getMyTopTracks: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/top/tracks') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get the Current User's Recently Played Tracks * @param {Object} [options] Options, being type, after, limit, before. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of play history objects, * otherwise an error. Not returned if a callback is given. Note that the response will be empty * in case the user has enabled private session. */ getMyRecentlyPlayedTracks: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/recently-played') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Add track or episode to device queue * @param {string} [uri] uri of the track or episode to add * @param {Object} [options] Options, being device_id. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks, * otherwise an error. Not returned if a callback is given. */ addToQueue: function(uri, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/queue') .withQueryParameters( { uri: uri }, options ) .build() .execute(HttpManager.post, callback); }, /** * Get the Current User's Available Devices * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into an array of device objects, * otherwise an error. Not returned if a callback is given. */ getMyDevices: function(callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/devices') .build() .execute(HttpManager.get, callback); }, /** * Get the Current User's Currently Playing Track. * @param {Object} [options] Options, being market. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks, * otherwise an error. Not returned if a callback is given. */ getMyCurrentPlayingTrack: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/currently-playing') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Get Information About The User's Current Playback State * @param {Object} [options] Options, being market and additional_types. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks, * otherwise an error. Not returned if a callback is given. */ getMyCurrentPlaybackState: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player') .withQueryParameters(options) .build() .execute(HttpManager.get, callback); }, /** * Transfer a User's Playback * @param {string[]} [deviceIds] An _array_ containing a device ID on which playback should be started/transferred. * (NOTE: The API is currently only supporting a single device ID.) * @param {Object} [options] Options, the only one being 'play'. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @returns {Promise|undefined} A promise that if successful, resolves into an empty response, * otherwise an error. Not returned if a callback is given. */ transferMyPlayback: function(deviceIds, options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player') .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters( { device_ids: deviceIds, }, options ) .build() .execute(HttpManager.put, callback); }, /** * Starts o Resumes the Current User's Playback * @param {Object} [options] Options, being device_id, context_uri, offset, uris, position_ms. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example play({context_uri: 'spotify:album:5ht7ItJgpBH7W6vJ5BqpPr'}).then(...) * @returns {Promise|undefined} A promise that if successful, resolves into an empty response, * otherwise an error. Not returned if a callback is given. */ play: function(options, callback) { /*jshint camelcase: false */ var _options = options || {}; var queryParams = _options.device_id ? { device_id: _options.device_id } : null; var postData = {}; ['context_uri', 'uris', 'offset', 'position_ms'].forEach(function(field) { if (field in _options) { postData[field] = _options[field]; } }); return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/play') .withQueryParameters(queryParams) .withHeaders({ 'Content-Type': 'application/json' }) .withBodyParameters(postData) .build() .execute(HttpManager.put, callback); }, /** * Pauses the Current User's Playback * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example pause().then(...) * @returns {Promise|undefined} A promise that if successful, resolves into an empty response, * otherwise an error. Not returned if a callback is given. */ pause: function(options, callback) { return ( WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/pause') /*jshint camelcase: false */ .withQueryParameters( options && options.device_id ? { device_id: options.device_id } : null ) .withHeaders({ 'Content-Type': 'application/json' }) .build() .execute(HttpManager.put, callback) ); }, /** * Skip the Current User's Playback To Previous Track * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example skipToPrevious().then(...) * @returns {Promise|undefined} A promise that if successful, resolves into an empty response, * otherwise an error. Not returned if a callback is given. */ skipToPrevious: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/previous') .withQueryParameters( options && options.device_id ? { device_id: options.device_id } : null ) .build() .execute(HttpManager.post, callback); }, /** * Skip the Current User's Playback To Next Track * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example skipToNext().then(...) * @returns {Promise|undefined} A promise that if successful, resolves into an empty response, * otherwise an error. Not returned if a callback is given. */ skipToNext: function(options, callback) { return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/next') .withQueryParameters( options && options.device_id ? { device_id: options.device_id } : null ) .build() .execute(HttpManager.post, callback); }, /** * Seeks to the given position in the user’s currently playing track. * * @param {number} positionMs The position in milliseconds to seek to. Must be a positive number. * @param {Object} options Options, being device_id. If left empty will target the user's currently active device. * @param {function(Object,Object)} callback An optional callback that receives 2 parameters. The first * one is the error object (null if no error), and the second is the value if the request succeeded. * @return {Object} Null if a callback is provided, a `Promise` object otherwise */ seek: function(positionMs, options, callback) { var params = { /* jshint camelcase: false */ position_ms: positionMs }; if (options && 'device_id' in options) { /* jshint camelcase: false */ params.device_id = options.device_id; } return WebApiRequest.builder(this.getAccessToken()) .withPath('/v1/me/player/seek') .withQueryParameters(params) .build() .execute(HttpManager.put, callback); }, /** * Set Repeat Mode On The Current User's Playback * @param {string} [state] State (track, context, or off) * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device. * @param {requestCallback} [callback] Optional callback method to be called instead of the promise. * @example setRepeat('context', {}).then(...) * @returns {Promise|undefined} A promise that if successful, resolves into an empty response, * otherwise an error. Not returned if a callback is given. */ setRepeat: function(state, options, callback) { var params = { state: state }; if (options && 'device_id' in options) { /* jshint camelc