yandex-music-api
Version:
A Node.js wrapper for the Yandex.Music API (Unofficial) http://music.yandex.ru
364 lines (299 loc) • 11.7 kB
JavaScript
var AuthRequest = require('./auth-request'),
ApiRequest = require('./api-request'),
Promise = require('promise'),
rest = require('./rest');
function YandexMusicApi() {
/* *******************************************
* C O N F I G
* *******************************************/
var _config = {
ouath_code: {
CLIENT_ID: '0618394846eb4d9589a602f80ce013d6',
CLIENT_SECRET: 'c13b3de8d9f5492caf321467c3520358',
},
oauth_token: {
CLIENT_ID: '23cabbbdc6cd418abb4b39c32c41195d',
CLIENT_SECRET: '53bc75238f0c4d08a118e51fe9203300',
},
fake_device: {
DEVICE_ID: '377c5ae26b09fccd72deae0a95425559',
UUID: '3cfccdaf75dcf98b917a54afe50447ba',
PACKAGE_NAME: 'ru.yandex.music'
},
user: {
USERNAME: null,
PASSWORD: null,
TOKEN: null,
UID: null
},
}
/* *******************************************
* P R I V A T E
* *******************************************/
function _performRequest(method, request)
{
var promise = new Promise(function(resolve, reject) {
method(request, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
return promise;
}
function _getAuthHeader()
{
return { 'Authorization' : 'OAuth ' + _config.user.TOKEN };
}
/* *******************************************
* P U B L I C
* *******************************************/
/**
* Authentication:
* Step one: Get an authorization code.
* Step two: Exchange code to receive an access_token for the user.
* @returns {Promise}
*/
this.init = function(config)
{
_config.user.USERNAME = config.username;
_config.user.PASSWORD = config.password;
// Authorization: step one
var request = AuthRequest.get()
.setPath('/1/token')
.setBodyData({
'grant_type': 'password',
'username': _config.user.USERNAME,
'password': _config.user.PASSWORD,
'client_id': _config.ouath_code.CLIENT_ID,
'client_secret': _config.ouath_code.CLIENT_SECRET
});
return _performRequest(rest.post, request).then(function(data) {
// Authorization: step two
var request = AuthRequest.get()
.setPath('/1/token')
.setQuery({
'device_id': _config.fake_device.DEVICE_ID,
'uuid': _config.fake_device.UUID,
'package_name': _config.fake_device.PACKAGE_NAME
})
.setBodyData({
'grant_type': 'x-token',
'access_token': data.access_token,
'client_id': _config.oauth_token.CLIENT_ID,
'client_secret': _config.oauth_token.CLIENT_SECRET
})
return _performRequest(rest.post, request).then(function(token) {
// Store user token and uid for other requests
_config.user.TOKEN = token.access_token;
_config.user.UID = token.uid;
return token
});
});
}
/* *******************************************
* E N D P O I N T S
* *******************************************/
/**
* GET: /account/status
* Get account status for curren user
* @returns {Promise}
*/
this.getAccountStatus = function() {
var request = ApiRequest.get()
.setPath('/account/status')
.addHeaders(_getAuthHeader());
return _performRequest(rest.get, request);
}
/**
* GET: /feed
* Get the user's feed
* @returns {Promise}
*/
this.getFeed = function() {
var request = ApiRequest.get()
.setPath('/feed')
.addHeaders(_getAuthHeader());
return _performRequest(rest.get, request);
}
/**
* GET: /genres
* Get a list of music genres
* @returns {Promise}
*/
this.getGenres = function() {
var request = ApiRequest.get()
.setPath('/genres')
.addHeaders(_getAuthHeader());
return _performRequest(rest.get, request);
}
/**
* GET: /search
* Search artists, tracks, albums.
* @param {String} query The search query.
* @param {Object} [options] Options: type {String} (artist|album|track|all),
page {Int},
nococrrect {Boolean}
* @returns {Promise}
*/
this.search = function(query, options) {
var opts = options || {};
var request = ApiRequest.get()
.setPath('/search')
.addHeaders(_getAuthHeader())
.setQuery({
'type': opts['type'] || 'all',
'text': query,
'page': opts['page'] || 0,
'nococrrect': opts['nococrrect'] || false
});
return _performRequest(rest.get, request);
}
/**
* GET: /users/[user_id]/playlists/list
* Get a user's playlists.
* @param {String} userId The user ID, if null then equal to current user id
* @returns {Promise}
*/
this.getUserPlaylists = function(userId) {
var request = ApiRequest.get()
.setPath('/users/' + (userId || _config.user.UID) + '/playlists/list')
.addHeaders(_getAuthHeader());
return _performRequest(rest.get, request);
}
/**
* GET: /users/[user_id]/playlists/[playlist_kind]
* Get a playlist without tracks
* @param {String} userId The user ID, if null then equal to current user id
* @param {String} playlistKind The playlist ID.
* @returns {Promise}
*/
this.getPlaylist = function(userId, playlistKind) {
var request = ApiRequest.get()
.setPath('/users/' + (userId || _config.user.UID) + '/playlists/' + playlistKind)
.addHeaders(_getAuthHeader());
return _performRequest(rest.get, request);
}
/**
* GET: /users/[user_id]/playlists
* Get an array of playlists with tracks
* @param {String} userId The user ID, if null then equal to current user id
* @param {String} playlistKind The playlist ID.
* @param {Object} [options] Options: mixed {Boolean}, rich-tracks {Boolean}
* @returns {Promise}
*/
this.getPlaylists = function(userId, playlists, options) {
var opts = options || {};
var request = ApiRequest.get()
.setPath('/users/' + (userId || _config.user.UID) + '/playlists')
.addHeaders(_getAuthHeader())
.setQuery({
'kinds': playlists.join(),
'mixed': opts['mixed'] || false,
'rich-tracks': opts['rich-tracks'] || false
});
return _performRequest(rest.get, request);
}
/**
* POST: /users/[user_id]/playlists/create
* Create a new playlist
* @param {String} name The name of the playlist
* @param {Object} [options] Options: visibility {String} (public|private)
* @returns {Promise}
*/
this.createPlaylist = function(name, options) {
var opts = options || {};
var request = ApiRequest.get()
.setPath('/users/' + _config.user.UID + '/playlists/create')
.addHeaders(_getAuthHeader())
.setBodyData({
'title': name,
'visibility': opts.visibility || 'private'
});
return _performRequest(rest.post, request);
}
/**
* POST: /users/[user_id]/playlists/[playlist_kind]/delete
* Remove a playlist
* @param {String} userId The user ID, if null then equal to current user id
* @param {String} playlistKind The playlist ID.
* @returns {Promise}
*/
this.removePlaylist = function(playlistKind) {
var request = ApiRequest.get()
.setPath('/users/' + _config.user.UID + '/playlists/' + playlistKind + '/delete')
.addHeaders(_getAuthHeader());
return _performRequest(rest.post, request);
}
/**
* POST: /users/[user_id]/playlists/[playlist_kind]/name
* Change playlist name
* @param {String} playlistKind The playlist ID.
* @param {String} name New playlist name.
* @returns {Promise}
*/
this.renamePlaylist = function(playlistKind, name) {
var request = ApiRequest.get()
.setPath('/users/' + _config.user.UID + '/playlists/' + playlistKind + '/name')
.addHeaders(_getAuthHeader())
.setBodyData({'value': name});
return _performRequest(rest.post, request);
}
/**
* POST: /users/[user_id]/playlists/[playlist_kind]/change-relative
* Add tracks to the playlist
* @param {String} playlistKind The playlist's ID.
* @param {Object[]} tracks An array of objects containing a track info:
track id and album id for the track.
Example: [{id:'20599729', albumId:'2347459'}]
* @param {String} revision Operation id for that request
* @param {Object} [options] Options: at {Int}
* @returns {Promise}
*/
this.addTracksToPlaylist = function(playlistKind, tracks, revision, options) {
var opts = options || {};
var request = ApiRequest.get()
.setPath('/users/' + _config.user.UID + '/playlists/' + playlistKind + '/change-relative')
.addHeaders(_getAuthHeader())
.setBodyData({
'diff': JSON.stringify([{
'op': 'insert',
'at': opts.at || 0,
'tracks': tracks
}]),
'revision': revision
});
return _performRequest(rest.post, request);
}
/**
* POST: /users/[user_id]/playlists/[playlist_kind]/change-relative
* Remove tracks from the playlist
* @param {String} playlistKind The playlist's ID.
* @param {Object[]} tracks An array of objects containing a track info:
track id and album id for the track.
Example: [{id:'20599729', albumId:'2347459'}]
* @param {String} revision Operation id for that request
* @param {Object} [options] Options: from {Int},
to {Int}
* @returns {Promise}
*/
this.removeTracksFromPlaylist = function(playlistKind, tracks, revision, options) {
var opts = options || {};
var request = ApiRequest.get()
.setPath('/users/' + _config.user.UID + '/playlists/' + playlistKind + '/change-relative')
.addHeaders(_getAuthHeader())
.setBodyData({
'diff': JSON.stringify([{
'op': 'delete',
'from': opts['from'] || 0,
'to': opts['to'] || tracks.length,
'tracks': tracks
}]),
'revision': revision
});
return _performRequest(rest.post, request);
}
}
module.exports = YandexMusicApi;