spotify-web-api-node
Version:
A Node.js wrapper for Spotify's Web API
1,373 lines (1,192 loc) • 46.3 kB
JavaScript
var AuthenticationRequest = require('./authentication-request'),
WebApiRequest = require('./webapi-request'),
HttpManager = require('./http-manager'),
PromiseImpl = require('promise');
function SpotifyWebApi(credentials) {
'use strict';
var _credentials = credentials || {};
function _addBodyParameters(request, options) {
if (options) {
for (var key in options) {
if (key !== 'credentials') {
request.addBodyParameter(key, options[key]);
}
}
}
}
function _addQueryParameters(request, options) {
if (!options) {
return;
}
for (var key in options) {
if (key !== 'credentials') {
request.addQueryParameter(key, options[key]);
}
}
}
function _performRequest(method, request) {
var promiseFunction = function(resolve, reject) {
method(request, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
};
return new PromiseImpl(promiseFunction);
}
function _addAccessToken(request, accessToken) {
if (accessToken) {
request.addHeaders({
'Authorization' : 'Bearer ' + accessToken
});
}
}
this.setCredentials = function(credentials) {
for (var key in credentials) {
if (credentials.hasOwnProperty(key)) {
_credentials[key] = credentials[key];
}
}
};
this.getCredentials = function() {
return _credentials;
};
this.resetCredentials = function() {
_credentials = null;
};
this.setClientId = function(clientId) {
_setCredential('clientId', clientId);
};
this.setClientSecret = function(clientSecret) {
_setCredential('clientSecret', clientSecret);
};
this.setAccessToken = function(accessToken) {
_setCredential('accessToken', accessToken);
};
this.setRefreshToken = function(refreshToken) {
_setCredential('refreshToken', refreshToken);
};
this.setRedirectURI = function(redirectUri) {
_setCredential('redirectUri', redirectUri);
};
this.getRedirectURI = function() {
return _getCredential('redirectUri');
};
this.getClientId = function() {
return _getCredential('clientId');
};
this.getClientSecret = function() {
return _getCredential('clientSecret');
};
this.getAccessToken = function() {
return _getCredential('accessToken');
};
this.getRefreshToken = function() {
return _getCredential('refreshToken');
};
this.resetClientId = function() {
_resetCredential('clientId');
};
this.resetClientSecret = function() {
_resetCredential('clientSecret');
};
this.resetAccessToken = function() {
_resetCredential('accessToken');
};
this.resetRefreshToken = function() {
_resetCredential('refreshToken');
};
this.resetRedirectURI = function() {
_resetCredential('redirectUri');
};
function _setCredential(credentialKey, value) {
_credentials = _credentials || {};
_credentials[credentialKey] = value;
}
function _getCredential(credentialKey) {
if (!_credentials) {
return;
} else {
return _credentials[credentialKey];
}
}
function _resetCredential(credentialKey) {
if (!_credentials) {
return;
} else {
_credentials[credentialKey] = null;
}
}
/**
* Look up a track.
* @param {string} trackId The track's ID.
* @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.
*/
this.getTrack = function(trackId, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/tracks/' + trackId)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Look up several tracks.
* @param {string[]} trackIds 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.
*/
this.getTracks = function(trackIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/tracks')
.withQueryParameters({
'ids' : trackIds.join(',')
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Look up an album.
* @param {string} albumId The album's ID.
* @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.
*/
this.getAlbum = function(albumId, callback) {
var request = WebApiRequest.builder().withPath('/v1/albums/' + albumId).build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Look up several albums.
* @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.
*/
this.getAlbums = function(albumIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/albums')
.withQueryParameters({
'ids' : albumIds.join(',')
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getArtist = function(artistId, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/artists/' + artistId)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getArtists = function(artistIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/artists')
.withQueryParameters({
'ids' : artistIds.join(',')
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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 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.
*/
this.searchAlbums = function(query, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/search/')
.withQueryParameters({
type : 'album',
q : query
})
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.searchArtists = function(query, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/search/')
.withQueryParameters({
type : 'artist',
q : query
})
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.searchTracks = function(query, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/search/')
.withQueryParameters({
type : 'track',
q : query
})
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getArtistAlbums = function(artistId, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/artists/' + artistId + '/albums')
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getAlbumTracks = function(albumId, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/albums/' + albumId + '/tracks')
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getArtistTopTracks = function(artistId, country, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/artists/' + artistId + '/top-tracks')
.withQueryParameters({
'country' : country
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getArtistRelatedArtists = function(artistId, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/artists/' + artistId + '/related-artists')
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getUser = function(userId, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/users/' + userId)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.getMe = function(callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me')
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Get a user's playlists.
* @param {string} userId The user ID.
* @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
* the a list of playlists. If rejected, it contains an error object. Not returned if a callback is given.
*/
this.getUserPlaylists = function(userId, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/users/' + userId + '/playlists')
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Get a playlist.
* @param {string} userId The playlist's owner's user ID.
* @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('thelinmichael', '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.
*/
this.getPlaylist = function(userId, playlistId, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/users/' + userId + '/playlists/' + playlistId)
.build();
_addAccessToken(request, this.getAccessToken());
_addQueryParameters(request, options);
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Get tracks in a playlist.
* @param {string} userId THe playlist's owner's user ID.
* @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('thelinmichael', '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.
*/
this.getPlaylistTracks = function(userId, playlistId, options, callback) {
var request = WebApiRequest.builder().
withPath('/v1/users/' + userId + '/playlists/' + playlistId + '/tracks').
withQueryParameters(options).
build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Create a playlist.
* @param {string} userId The playlist's owner's user ID.
* @param {string} playlistName The name of the playlist.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example createPlaylist('thelinmichael', 'My cool playlist!').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.
*/
this.createPlaylist = function(userId, playlistName, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/users/' + userId + '/playlists/')
.withHeaders({ 'Content-Type' : 'application/json' })
.withBodyParameters({ 'name' : playlistName })
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.post, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Change playlist details.
* @param {string} userId The playlist's owner's user ID
* @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('thelinmichael', '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.
*/
this.changePlaylistDetails = function(userId, playlistId, options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/users/' + userId + '/playlists/' + playlistId)
.withHeaders({ 'Content-Type' : 'application/json' })
.withBodyParameters(options)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.put, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Add tracks to a playlist.
* @param {string} userId The playlist's owner's user ID
* @param {string} playlistId The playlist's ID
* @param {string[]} tracks IDs 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('thelinmichael', '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.
*/
this.addTracksToPlaylist = function(userId, playlistId, tracks, options, callback) {
var tracksString;
if (typeof tracks === 'object') {
tracksString = tracks.join();
} else {
tracksString = tracks;
}
var request = WebApiRequest.builder()
.withPath('/v1/users/' + userId + '/playlists/' + playlistId + '/tracks')
.withHeaders({ 'Content-Type' : 'application/json' })
.withQueryParameters({
uris: tracksString
})
.build();
_addQueryParameters(request, options);
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.post, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Remove tracks from a playlist.
* @param {string} userId The playlist's owner's user ID
* @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
* a an optional property called positions (int[]).
* @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.
*/
this.removeTracksFromPlaylist = function(userId, playlistId, tracks, options, callback) {
var request = WebApiRequest.builder().
withPath('/v1/users/' + userId + '/playlists/' + playlistId + '/tracks').
withHeaders({ 'Content-Type' : 'application/json' }).
withBodyParameters({
'tracks': tracks
}).
build();
_addBodyParameters(request, options);
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.del, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Replace tracks in a playlist.
* @param {string} userId The playlist's owner's user ID
* @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.
*/
this.replaceTracksInPlaylist = function(userId, playlistId, uris, callback) {
var request = WebApiRequest.builder().
withPath('/v1/users/' + userId + '/playlists/' + playlistId + '/tracks').
withHeaders({ 'Content-Type' : 'application/json' }).
withBodyParameters({
'uris': uris
}).
build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.put, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Request an access token using the Client Credentials flow.
* Requires that client ID and client secret has been set previous to the call.
* @param {Object} options Options.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @returns {Promise|undefined} A promise that if successful, resolves into an object containing the access token,
* token type and time to expiration. If rejected, it contains an error object. Not returned if a callback is given.
*/
this.clientCredentialsGrant = function(options, callback) {
var request = AuthenticationRequest.builder()
.withPath('/api/token')
.withBodyParameters({
'grant_type' : 'client_credentials'
})
.withHeaders({
Authorization : ('Basic ' + new Buffer(this.getClientId() + ':' + this.getClientSecret()).toString('base64'))
})
.build();
_addBodyParameters(request, options);
var promise = _performRequest(HttpManager.post, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Request an access token using the Authorization Code flow.
* Requires that client ID, client secret, and redirect URI has been set previous to the call.
* @param {string} code The authorization code returned in the callback in the Authorization Code flow.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @returns {Promise|undefined} A promise that if successful, resolves into an object containing the access token,
* refresh token, token type and time to expiration. If rejected, it contains an error object.
* Not returned if a callback is given.
*/
this.authorizationCodeGrant = function(code, callback) {
var request = AuthenticationRequest.builder()
.withPath('/api/token')
.withBodyParameters({
'grant_type' : 'authorization_code',
'redirect_uri' : this.getRedirectURI(),
'code' : code,
'client_id' : this.getClientId(),
'client_secret' : this.getClientSecret()
})
.build();
var promise = _performRequest(HttpManager.post, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Refresh the access token given that it hasn't expired.
* Requires that client ID, client secret and refresh token has been set previous to the call.
* @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 the
* access token, time to expiration and token type. If rejected, it contains an error object.
* Not returned if a callback is given.
*/
this.refreshAccessToken = function(callback) {
var request = AuthenticationRequest.builder()
.withPath('/api/token')
.withBodyParameters({
'grant_type' : 'refresh_token',
'refresh_token' : this.getRefreshToken()
})
.withHeaders({
Authorization : ('Basic ' + new Buffer(this.getClientId() + ':' + this.getClientSecret()).toString('base64'))
})
.build();
var promise = _performRequest(HttpManager.post, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Retrieve a URL where the user can give the application permissions.
* @param {string[]} scopes The scopes corresponding to the permissions the application needs.
* @param {string} state A parameter that you can use to maintain a value between the request and the callback to redirect_uri.It is useful to prevent CSRF exploits.
* @returns {string} The URL where the user can give application permissions.
*/
this.createAuthorizeURL = function(scopes, state) {
var request = AuthenticationRequest.builder()
.withPath('/authorize')
.withQueryParameters({
'client_id' : this.getClientId(),
'response_type' : 'code',
'redirect_uri' : this.getRedirectURI(),
'scope' : scopes.join('%20'),
'state' : state
})
.build();
return request.getURL();
};
/**
* Retrieve the tracks that are saved to the authenticated users Your Music library.
* @param {Object} [options] Options, being 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.
*/
this.getMySavedTracks = function(options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/tracks')
.withQueryParameters(options)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.containsMySavedTracks = function(trackIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/tracks/contains')
.withQueryParameters({
'ids' : trackIds.join(',')
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.removeFromMySavedTracks = function(trackIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/tracks')
.withHeaders({ 'Content-Type' : 'application/json' })
.withBodyParameters(trackIds)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.del, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* 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.
*/
this.addToMySavedTracks = function(trackIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/tracks')
.withHeaders({ 'Content-Type' : 'application/json' })
.withBodyParameters(trackIds)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.put, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Add the current user as a follower of one or more other Spotify users.
* @param {string[]} userIds The IDs of the users to be followed.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example followUsers(['thelinmichael', 'wizzler']).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.
*/
this.followUsers = function(userIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/following')
.withQueryParameters({
ids: userIds.join(','),
type: 'user'
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.put, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Add the current user as a follower of one or more artists.
* @param {string[]} artistIds The IDs of the artists to be followed.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example followArtists(['0LcJLqbBmaGUft1e9Mm8HV', '3gqv1kgivAc92KnUm4elKv']).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.
*/
this.followArtists = function(artistIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/following')
.withQueryParameters({
ids: artistIds.join(','),
type: 'artist'
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.put, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Remove the current user as a follower of one or more other Spotify users.
* @param {string[]} userIds The IDs of the users to be unfollowed.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example unfollowUsers(['thelinmichael', 'wizzler']).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.
*/
this.unfollowUsers = function(userIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/following')
.withQueryParameters({
ids: userIds.join(','),
type: 'user'
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.del, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Remove the current user as a follower of one or more artists.
* @param {string[]} artistIds The IDs of the artists to be unfollowed.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example unfollowArtists(['0LcJLqbBmaGUft1e9Mm8HV', '3gqv1kgivAc92KnUm4elKv']).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.
*/
this.unfollowArtists = function(artistIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/following')
.withQueryParameters({
ids: artistIds.join(','),
type: 'artist'
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.del, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Check to see if the current user is following one or more other Spotify users.
* @param {string[]} userIds The IDs of the users to check if are followed by the current user.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example isFollowingUsers(['thelinmichael', 'wizzler']).then(...)
* @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 users IDs in the request.
* The boolean value of true indicates that the user is following that user, otherwise is not.
* Not returned if a callback is given.
*/
this.isFollowingUsers = function(userIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/following/contains')
.withQueryParameters({
ids: userIds.join(','),
type: 'user'
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Check to see if the current user is following one or more artists.
* @param {string[]} artistIds The IDs of the artists to check if are followed by the current user.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example isFollowingArtists(['0LcJLqbBmaGUft1e9Mm8HV', '3gqv1kgivAc92KnUm4elKv']).then(...)
* @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 artists IDs in the request.
* The boolean value of true indicates that the user is following that artist, otherwise is not.
* Not returned if a callback is given.
*/
this.isFollowingArtists = function(artistIds, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/following/contains')
.withQueryParameters({
ids: artistIds.join(','),
type: 'artist'
})
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Retrieve new releases
* @param {Object} [options] Options, being country, 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 contains
* album objects. Not returned if a callback is given.
*/
this.getNewReleases = function(options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/browse/new-releases')
.withHeaders({ 'Content-Type' : 'application/json' })
.withQueryParameters(options)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
/**
* Retrieve featured playlists
* @param {Object} [options] Options, being country, locale, timestamp, limit, 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 contains
* featured playlists. Not returned if a callback is given.
*/
this.getFeaturedPlaylists = function(options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/browse/featured-playlists')
.withHeaders({ 'Content-Type' : 'application/json' })
.withQueryParameters(options)
.build();
_addAccessToken(request, this.getAccessToken());
var promise = _performRequest(HttpManager.get, request);
if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
};
}
module.exports = SpotifyWebApi;