UNPKG

groove-music-js

Version:
523 lines (444 loc) 18.1 kB
'use strict'; var AuthenticationRequest = require('./authentication-request'), WebApiRequest = require('./web-api-request'), HttpManager = require('./http-wrapper'); function GrooveMusicWebApi(credentials) { this._credentials = credentials || {}; } GrooveMusicWebApi.prototype = { _addBodyParameters: function (request, options) { if (options) { for (var key in options) { if (key !== 'credentials') { request.addBodyParameter(key, options[key]); } } } }, _addQueryParameters: function (request, options) { if (!options) { return; } for (var key in options) { if (key !== 'credentials') { request.addQueryParameter(key, options[key]); } } }, _performRequest: function (method, request) { var promiseFunction = function (resolve, reject) { method(request, function (error, result) { if (error) { reject(error); } else { resolve(result); } }); }; return new Promise(promiseFunction); }, _addAccessToken: function (request, accessToken) { if (accessToken) { request.addHeaders({ 'Authorization': 'Bearer ' + accessToken }); } }, 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; } }, /** * Attempts to login with the client ID and client secret */ authenticateApp: function (callback) { var request = AuthenticationRequest.builder() .withBodyParameters({ client_id: this.getClientId(), "client_secret": this.getClientSecret(), "scope": "app.music.xboxlive.com", "grant_type": "client_credentials" }) .withHeaders({ "Content-Type": "application/x-www-form-urlencoded" }) .build(); var promise = this._performRequest(HttpManager.post, request); var self = this; promise.then(function (data) { if (data.body["token_type"] == "bearer") { self.setAccessToken(data.body.access_token); } callback(null, null); }, function (err) { callback(err); }); }, /** * 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) { // In case someone is using a version where options parameter did not exist. var actualCallback; if (typeof options === 'function') { actualCallback = options; _addAccessToken } else { actualCallback = callback; } var actualOptions = {}; if (typeof options === 'object') { Object.keys(options).forEach(function (key) { actualOptions[key] = options[key]; }); } var request = WebApiRequest.builder() .withPath('/1/content/' + trackId + "/lookup") .withQueryParameters(actualOptions) .build(); this._addAccessToken(request, this.getAccessToken()); var promise = this._performRequest(HttpManager.get, request); if (actualCallback) { promise.then(function (data) { actualCallback(null, data); }, function (err) { actualCallback(err); }); } else { return promise; } }, /** * 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) { // In case someone is using a version where options parameter did not exist. var actualCallback; if (typeof options === 'function') { actualCallback = options; } else { actualCallback = callback; } var actualOptions = {}; if (typeof options === 'object') { Object.keys(options).forEach(function (key) { actualOptions[key] = options[key]; }); } var request = WebApiRequest.builder() .withPath('/1/content/' + trackIds.join('+') + '/lookup') .build(); this._addAccessToken(request, this.getAccessToken()); this._addQueryParameters(request, actualOptions); var promise = this._performRequest(HttpManager.get, request); if (actualCallback) { promise.then(function (data) { actualCallback(null, data); }, function (err) { actualCallback(err); }); } else { return promise; } }, /** * 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) { // In case someone is using a version where options parameter did not exist. var actualCallback; if (typeof options === 'function') { actualCallback = options; } else { actualCallback = callback; } var actualOptions = {}; if (typeof options === 'object') { Object.keys(options).forEach(function (key) { actualOptions[key] = options[key]; }); } var request = WebApiRequest.builder() .withPath('/v1/albums/' + albumId) .withQueryParameters(actualOptions) .build(); this._addAccessToken(request, this.getAccessToken()); var promise = this._performRequest(HttpManager.get, request); if (actualCallback) { promise.then(function (data) { actualCallback(null, data); }, function (err) { actualCallback(err); }); } else { return promise; } }, /** * 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) { // In case someone is using a version where options parameter did not exist. var actualCallback; if (typeof options === 'function') { actualCallback = options; } else { actualCallback = callback; } var actualOptions = {}; if (typeof options === 'object') { Object.keys(options).forEach(function (key) { actualOptions[key] = options[key]; }); } var request = WebApiRequest.builder() .withPath('/v1/albums') .withQueryParameters({ 'ids': albumIds.join(',') }) .build(); this._addAccessToken(request, this.getAccessToken()); this._addQueryParameters(request, actualOptions); var promise = this._performRequest(HttpManager.get, request); if (actualCallback) { promise.then(function (data) { actualCallback(null, data); }, function (err) { actualCallback(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. */ getArtist: function (artistId, callback) { var request = WebApiRequest.builder() .withPath('/v1/artists/' + artistId) .build(); this._addAccessToken(request, this.getAccessToken()); var promise = this._performRequest(HttpManager.get, request); if (callback) { promise.then(function (data) { callback(null, data); }, function (err) { callback(err); }); } else { return promise; } }, /** * 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', and 'track'. * @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) { var request = WebApiRequest.builder() .withPath('/1/content/music/search') .withQueryParameters({ filters: types.join('+'), q: query }).build(); var actualOptions = {}; if (typeof options === 'object') { Object.keys(options).forEach(function (key) { actualOptions[key] = options[key]; }); } this._addQueryParameters(request, actualOptions); this._addAccessToken(request, this.getAccessToken()); this._addQueryParameters(request, options); var promise = this._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. */ searchTracks: function (query, options, callback) { return this.search(query, ['tracks'], options, 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) { var request = WebApiRequest.builder() .withPath('/v1/me') .build(); this._addAccessToken(request, this.getAccessToken()); var promise = this._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 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 { path = '/v1/me/playlists'; } var request = WebApiRequest.builder() .withPath(path) .build(); this._addAccessToken(request, this.getAccessToken()); this._addQueryParameters(request, options); var promise = this._performRequest(HttpManager.get, request); if (callback) { promise.then(function (data) { callback(null, data); }, function (err) { callback(err); }); } else { return promise; } }, }; module.exports = GrooveMusicWebApi;