Skip to content

Commit

Permalink
Playblack control (#150)
Browse files Browse the repository at this point in the history
* adds playback control (play, pause, prev, next)
* adds shuffle and repeat to playback control
  • Loading branch information
JoseMCO authored and JMPerez committed Aug 31, 2017
1 parent f3d4ff3 commit 1f2ba8a
Show file tree
Hide file tree
Showing 3 changed files with 338 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ It includes helper functions to do the following:
- Get a user's available devices
- Get information about the user's current playback
- Transfer a user's playback
- Resume a user's playback
- Skip a user's playback to next track
- Skip a user's playback to previous track
- Set a user's shuffle mode
- Set a user's repeat mode

All methods require authentication, which can be done using these flows:

Expand Down
181 changes: 181 additions & 0 deletions src/spotify-web-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,187 @@ SpotifyWebApi.prototype = {
}
},

/**
* Resumes the Current User's Playback
* @param {Object} [options] Options, being context_uri, offset, uris.
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example playbackResume({context_uri: 'spotify:album:5ht7ItJgpBH7W6vJ5BqpPr'}).then(...)
* @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.
*/
playbackResume: function(options, callback) {

var actualOptions = {};
if (typeof options === 'object') {
Object.keys(options).forEach(function(key) {
actualOptions[key] = options[key];
});
}

var request = WebApiRequest.builder()
.withPath('/v1/me/player/play')
.withHeaders({ 'Content-Type' : 'application/json' })
.withBodyParameters(actualOptions)
.build();

this._addAccessToken(request, this.getAccessToken());

var promise = this._performRequest(HttpManager.put, request);

if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
},

/**
* Pauses the Current User's Playback
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example playbackPause().then(...)
* @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.
*/
playbackPause: function(callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/player/pause')
.build();

this._addAccessToken(request, this.getAccessToken());

var promise = this._performRequest(HttpManager.put, request);

if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
},

/**
* Skip the Current User's Playback To Previous Track
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example playbackPrevious().then(...)
* @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.
*/
playbackPrevious: function(callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/player/previous')
.build();

this._addAccessToken(request, this.getAccessToken());

var promise = this._performRequest(HttpManager.post, request);

if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
},

/**
* Skip the Current User's Playback To Next Track
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example playbackNext().then(...)
* @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.
*/
playbackNext: function(callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/player/next')
.build();

this._addAccessToken(request, this.getAccessToken());

var promise = this._performRequest(HttpManager.post, request);

if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
},

/**
* Set Repeat Mode On The Current User's Playback
* @param {Object} [options] Options, being state (track, context, off).
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example playbackRepeat({state: 'context'}).then(...)
* @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.
*/
playbackRepeat: function(options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/player/repeat')
.withQueryParameters({
'state': options.state || 'off'
})
.build();

this._addAccessToken(request, this.getAccessToken());

var promise = this._performRequest(HttpManager.put, request);

if (callback) {
promise.then(function(data) {
callback(null, data);
}, function(err) {
callback(err);
});
} else {
return promise;
}
},

/**
* Set Shuffle Mode On The Current User's Playback
* @param {Object} [options] Options, being state (true, false).
* @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
* @example playbackShuffle({state: 'false'}).then(...)
* @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.
*/
playbackShuffle: function(options, callback) {
var request = WebApiRequest.builder()
.withPath('/v1/me/player/shuffle')
.withQueryParameters({
'state': options.state || 'false'
})
.build();

this._addAccessToken(request, this.getAccessToken());

var promise = this._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.
Expand Down
152 changes: 152 additions & 0 deletions test/spotify-web-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,158 @@ describe('Spotify Web API', function() {

});

it('should resume the user\'s playback', function(done) {

sinon.stub(HttpManager, '_makeRequest', function(method, options, uri, callback) {
method.should.equal(superagent.put);
uri.should.equal('https://api.spotify.com/v1/me/player/play');
should.not.exist(options.query);
callback();
});

var accessToken = 'myAccessToken';

var api = new SpotifyWebApi({
accessToken : accessToken
});

api.playbackResume()
.then(function(data) {
done();
}, function(err) {
console.log(err);
done(err);
});

});

it('should pause the user\'s playback', function(done) {

sinon.stub(HttpManager, '_makeRequest', function(method, options, uri, callback) {
method.should.equal(superagent.put);
uri.should.equal('https://api.spotify.com/v1/me/player/pause');
should.not.exist(options.query);
callback();
});

var accessToken = 'myAccessToken';

var api = new SpotifyWebApi({
accessToken : accessToken
});

api.playbackPause()
.then(function(data) {
done();
}, function(err) {
console.log(err);
done(err);
});

});

it('should skip the user\'s playback to next track', function(done) {

sinon.stub(HttpManager, '_makeRequest', function(method, options, uri, callback) {
method.should.equal(superagent.post);
uri.should.equal('https://api.spotify.com/v1/me/player/next');
should.not.exist(options.query);
callback();
});

var accessToken = 'myAccessToken';

var api = new SpotifyWebApi({
accessToken : accessToken
});

api.playbackNext()
.then(function(data) {
done();
}, function(err) {
console.log(err);
done(err);
});

});

it('should skip the user\'s playback to previous track', function(done) {

sinon.stub(HttpManager, '_makeRequest', function(method, options, uri, callback) {
method.should.equal(superagent.post);
uri.should.equal('https://api.spotify.com/v1/me/player/previous');
should.not.exist(options.query);
callback();
});

var accessToken = 'myAccessToken';

var api = new SpotifyWebApi({
accessToken : accessToken
});

api.playbackPrevious()
.then(function(data) {
done();
}, function(err) {
console.log(err);
done(err);
});

});

it('should set the user\'s playback repeat mode', function(done) {

sinon.stub(HttpManager, '_makeRequest', function(method, options, uri, callback) {
method.should.equal(superagent.put);
uri.should.equal('https://api.spotify.com/v1/me/player/repeat');
should.exist(options.query);
should.not.exist(options.body);
callback();
});

var accessToken = 'myAccessToken';

var api = new SpotifyWebApi({
accessToken : accessToken
});

api.playbackRepeat({state: 'off'})
.then(function(data) {
done();
}, function(err) {
console.log(err);
done(err);
});

});

it('should set the user\'s playback shuffle mode', function(done) {

sinon.stub(HttpManager, '_makeRequest', function(method, options, uri, callback) {
method.should.equal(superagent.put);
uri.should.equal('https://api.spotify.com/v1/me/player/shuffle');
should.exist(options.query);
should.not.exist(options.body);
callback();
});

var accessToken = 'myAccessToken';

var api = new SpotifyWebApi({
accessToken : accessToken
});

api.playbackShuffle({state: 'false'})
.then(function(data) {
done();
}, function(err) {
console.log(err);
done(err);
});

});

it.skip("should retrieve an access token using the client credentials flow", function(done) {
var clientId = 'someClientId',
clientSecret = 'someClientSecret';
Expand Down

0 comments on commit 1f2ba8a

Please sign in to comment.