mirror of
https://gitlab.com/deeplydrumming/DeemixFix.git
synced 2026-01-15 16:32:59 -03:00
reverted to spotify-web-api-node (local) and applied Buffer fix.
This commit is contained in:
5
spotify-web-api-node/.travis.yml
Normal file
5
spotify-web-api-node/.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 14
|
||||
after_success:
|
||||
- npm run travis
|
||||
213
spotify-web-api-node/CHANGELOG.md
Normal file
213
spotify-web-api-node/CHANGELOG.md
Normal file
@@ -0,0 +1,213 @@
|
||||
## Change log
|
||||
|
||||
#### 5.0.2 (Jan 2021)
|
||||
|
||||
* Fix: Make `transferMyPlayback` not require the `options` object, since it should be optional. Thanks for the heads-up [@Simber1](https://github.com/Simber1)!
|
||||
|
||||
#### 5.0.1 (Jan 2021)
|
||||
|
||||
* Fix error handling in the HTTP client. Thanks [@yamadapc](https://github.com/yamadapc)!
|
||||
* This package can currently not be built on **Node 15 on Linux**, due to a dependency not being available yet. Issue can be followed on the [node-canvas](https://github.com/Automattic/node-canvas/issues/1688) issue tracker. In the mean time, Travis CI will run on earlier versions of Node.
|
||||
|
||||
#### 5.0.0 (Oct 2020)
|
||||
|
||||
* **BREAKING CHANGES**.
|
||||
* Arguments for some API methods have changed, causing incorrect behaviour using argument order from version 4.x. See the `README.md` for examples of how the methods can be used.
|
||||
* Create Playlist (`createPlaylist`) method no longer accepts a `userId` string as its first argument.
|
||||
* Transfer A User's Playback (`transferMyPlayback`) method takes a `deviceIds` array as its first argument.
|
||||
* Skip to Previous (`skipToPrevious`) method takes an `options` object as its first argument.
|
||||
* Skip to Next (`skipToNext`) method takes an `options` object as its first argument.
|
||||
* Set Repeat Mode on the Current User's Playback (`setRepeat`) method takes a `state` string as its first argument.
|
||||
* Set Shuffle Mode on the Current User's Playback (`setShuffle`) method takes a `state` string as its first argument.
|
||||
|
||||
Cheers [@marinacrachi](https://github.com/marinacrachi) for the createPlaylist update.
|
||||
* Removed legacy support for not passing an `options` object while providing a callback method. This was only supported on a few of the older endpoints, and could lead to tricky bugs. The affected endpoints are `getTrack`, `getTracks`, `getAlbum`, `getAlbums`, and `createPlaylist`. Again, check the `README.md` for examples on how these methods can be used if needed.
|
||||
* Removed `options` argument for retrieving an access token using the Client Credentials flow, `clientCredentialsGrant`.
|
||||
* API errors come in five different flavours.
|
||||
* WebapiRegularError - For errors returned by most API endpoints.
|
||||
* WebapiPlayerError - For errors returned by the Player API. These contain a bit more information.
|
||||
* WebapiAuthenticationError - For errors related to authentication.
|
||||
* WebapiError - For errors that come from the Web API that didn't fit into one of the above.
|
||||
* TimeoutError - For network timeout errors.
|
||||
|
||||
More importantly, errors now contain the response body, headers, and status code. One side-effect of this is that rate limited requests can be handled by checking the `Retry-After` header. Thanks for the PRs [@kauffecup](https://github.com/kauffecup), [@lantelyes](https://github.com/lantelyes), [@dkliemsch](https://github.com/dkliemsch), and [@erezny](https://github.com/erezny).
|
||||
|
||||
Much appreciated [@konstantinjdobler](https://github.com/konstantinjdobler) for updates to the Player API errors.
|
||||
* Added support for [Implicit Grant flow](https://developer.spotify.com/documentation/general/guides/authorization-guide/#implicit-grant-flow) - Thanks [@gaganza](https://github.com/gaganza), [@reblws](https://github.com/reblws) and [@noahp78](https://github.com/noahp78)!
|
||||
* Starts or Resumes the Current User's Playback (`play`) method now supports the `position_ms` option. Thanks [@alqubo](https://github.com/alqubo), [@koflin](https://github.com/koflin), [@DoctorFishy](https://github.com/DoctorFishy). Thanks [@carmilso](https://github.com/carmilso) for general improvements to the Player API methods.
|
||||
* Binding for [Add an Item to the User's Playback Queue](https://developer.spotify.com/documentation/web-api/reference/player/add-to-queue/) endpoint added. Thanks [@thattomperson](https://github.com/thattomperson) and [@AriciducaZagaria](https://github.com/AriciducaZagaria)!
|
||||
* Binding for all [Shows and Episodes endpoints](https://developer.spotify.com/console/shows/). Thanks a _lot_ [@andyruwruw](https://github.com/andyruwruw)!
|
||||
* Documentation updates to keep up to date with ES6, thanks [@dandv](https://github.com/dandv)! Other documentation improvements by [@terensu-desu](https://github.com/terensu-desu), and examples by [@dersimn](https://github.com/dersimn). Thanks!
|
||||
* Bumped dependencies to resolve critical security issues.
|
||||
* Finally, hat off to [@dersimn](https://github.com/dersimn). Thanks for collecting all of the lingering PRs and merging them into a working and up-to-date fork. You really stepped up.
|
||||
|
||||
Likely more changes coming before release to npm, which will happen shortly.
|
||||
|
||||
#### 4.0.0 (14 Sep 2018)
|
||||
|
||||
* Modified functions that operate on playlists to drop the user id parameter. This is a breaking change. [PR](https://github.com/thelinmichael/spotify-web-api-node/pull/243)
|
||||
* Updated superagent to fix a security warning [PR](https://github.com/thelinmichael/spotify-web-api-node/pull/211)
|
||||
* Fixed a bug by which an empty user was not handled properly in getUserPlaylists(). [PR](https://github.com/thelinmichael/spotify-web-api-node/pull/244)
|
||||
|
||||
#### 3.1.1 (29 Apr 2018)
|
||||
|
||||
* Modernized stack for a better developer experience. Integrated [prettier](https://github.com/thelinmichael/spotify-web-api-node/pull/205) and [jest](https://github.com/thelinmichael/spotify-web-api-node/pull/206). This simplifies the amount of dev dependencies.
|
||||
* Improved calls to save and remove saved tracks by adding a key as specified in the Spotify docs (See [PR](https://github.com/thelinmichael/spotify-web-api-node/pull/207)). Thanks to [@yanniz0r](https://github.com/yanniz0r) and [@adcar](https://github.com/adcar) for bringing it up.
|
||||
|
||||
#### 3.1.0 (26 Apr 2018)
|
||||
|
||||
* Added support for seeking and setting volume. Thanks to [@isokar](https://github.com/isokar), [@jamesemwallis](https://github.com/jamesemwallis), [@ashthespy](https://github.com/ashthespy), and [@vanderlin](https://github.com/vanderlin) for your PRs.
|
||||
|
||||
#### 3.0.0 (8 Mar 2018)
|
||||
|
||||
* @DalerAsrorov added support for uploading a custom image to a playlist in [this PR](https://github.com/thelinmichael/spotify-web-api-node/pull/169).
|
||||
* You can now pass a `device_id` when playing and pausing playback. @pfftdammitchris started [a PR to add device_id to the play() method](https://github.com/thelinmichael/spotify-web-api-node/pull/185). The changes served to another PR where we included the functionality. Thanks!
|
||||
* Added documentation in the README for `getMyCurrentPlaybackState()`. Thanks @PanMan for [your PR](https://github.com/thelinmichael/spotify-web-api-node/pull/160)!
|
||||
* @brodin realized we there was a lot of duplicated code and refactored it in a [great PR](https://github.com/thelinmichael/spotify-web-api-node/pull/123).
|
||||
|
||||
#### 2.5.0 (4 Sep 2017)
|
||||
|
||||
* Change README to reflect new authorization. Thanks [@arirawr](https://github.com/arirawr) for the [PR](https://github.com/thelinmichael/spotify-web-api-node/pull/146).
|
||||
* Add support for 'show_dialog' parameter when creating authorization url. Thanks [@ajhaupt7](https://github.com/ajhaupt7) for [the PR](https://github.com/thelinmichael/spotify-web-api-node/pull/101).
|
||||
* Add support for playback control (play, pause, prev, next), shuffle and repeat. Thanks [@JoseMCO](https://github.com/JoseMCO) for [the PR](https://github.com/thelinmichael/spotify-web-api-node/pull/150).
|
||||
* Add support for currently playing. Thanks [@dustinblackman](https://github.com/dustinblackman) for [the PR](https://github.com/thelinmichael/spotify-web-api-node/pull/145).
|
||||
* Fix to remove unnecessary deviceIds parameter from request to transfer playback. Thanks [@philnash](https://github.com/philnash) for [the PR](https://github.com/thelinmichael/spotify-web-api-node/pull/154).
|
||||
|
||||
#### 2.4.0 (2 May 2017)
|
||||
|
||||
* Change `addTracksToPlaylist` to pass the data in the body, preventing an issue with a long URL when passing many tracks. Thanks [@dolcalmi](https://github.com/dolcalmi) for [the PR](https://github.com/thelinmichael/spotify-web-api-node/pull/117)
|
||||
* Add support for fetching [recently played tracks](https://developer.spotify.com/web-api/console/get-recently-played/). Thanks [@jeremyboles](https://github.com/jeremyboles) for [the PR](https://github.com/thelinmichael/spotify-web-api-node/pull/111).
|
||||
|
||||
#### 2.3.6 (15 October 2016)
|
||||
|
||||
* Add language bindings for the **[Get Audio Analysis for a Track](https://developer.spotify.com/web-api/get-audio-analysis/)** endpoint.
|
||||
|
||||
#### 2.3.5 (20 July 2016)
|
||||
|
||||
* Use `encodeURIComponent` instead of `encodeURI` to encode the user's id. 'encodeURI' wasn't encoding characters like `/` or `#` that were generating an invalid endpoint url. Thanks [@jgranstrom](https://github.com/jgranstrom) for the PR.
|
||||
|
||||
#### 2.3.4 (18 July 2016)
|
||||
|
||||
* Fixed a bug in `clientCredentialsGrant()`.
|
||||
|
||||
#### 2.3.3 (18 July 2016)
|
||||
|
||||
* Migrated to the `superagent` request library to support Node.JS and browsers. Thanks [@SomeoneWeird](https://github.com/SomeoneWeird) for the PR to add it, and [@erezny](https://github.com/erezny) for reporting bugs.
|
||||
|
||||
#### 2.3.2 (10 July 2016)
|
||||
|
||||
* Add language bindings for **[Get a List of Current User's Playlists](https://developer.spotify.com/web-api/get-a-list-of-current-users-playlists/)**. Thanks [@JMPerez](https://github.com/JMPerez) and [@vinialbano](https://github.com/vinialbano).
|
||||
|
||||
#### 2.3.1 (3 July 2016)
|
||||
|
||||
* Fix for `getRecomendations` method causing client error response from the API when making the request. Thanks [@kyv](https://github.com/kyv) for reporting, and [@Boberober](https://github.com/Boberober) and [@JMPerez](https://github.com/JMPerez) for providing fixes.
|
||||
|
||||
#### 2.3.0 (2 April 2016)
|
||||
|
||||
* Add language bindings for **[Get Recommendations Based on Seeds](https://developer.spotify.com/web-api/get-recommendations/)**, **[Get a User's Top Artists and Tracks](https://developer.spotify.com/web-api/get-users-top-artists-and-tracks/)**, **[Get Audio Features for a Track](https://developer.spotify.com/web-api/get-audio-features/)**, and **[Get Audio Features for Several Tracks](https://developer.spotify.com/web-api/get-several-audio-features/)**. Read more about the endpoints in the links above or in this [blog post](https://developer.spotify.com/news-stories/2016/03/29/api-improvements-update/).
|
||||
* Add generic search method enabling searches for several types at once, e.g. search for both tracks and albums in a single request, instead of one request for track results and one request for album results.
|
||||
|
||||
#### 2.2.0 (23 November 2015)
|
||||
|
||||
* Add language bindings for **[Get User's Saved Albums](https://developer.spotify.com/web-api/get-users-saved-albums/)** and other endpoints related to the user's saved albums.
|
||||
|
||||
#### 2.1.1 (23 November 2015)
|
||||
|
||||
* Username encoding bugfix.
|
||||
|
||||
#### 2.1.0 (16 July 2015)
|
||||
|
||||
* Add language binding for **[Get Followed Artists](https://developer.spotify.com/web-api/get-followed-artists/)**
|
||||
|
||||
#### 2.0.2 (11 May 2015)
|
||||
|
||||
* Bugfix for retrieving an access token through the Client Credentials flow. (Thanks [Nate Wilkins](https://github.com/Nate-Wilkins)!)
|
||||
* Add test coverage and Travis CI.
|
||||
|
||||
#### 2.0.1 (2 Mar 2015)
|
||||
|
||||
* Return WebApiError objects if error occurs during authentication.
|
||||
|
||||
#### 2.0.0 (27 Feb 2015)
|
||||
|
||||
* **Breaking change**: Response object changed. Add headers and status code to all responses to enable users to implement caching.
|
||||
|
||||
#### 1.3.13 (26 Feb 2015)
|
||||
|
||||
* Add language binding for **[Reorder tracks in a Playlist](https://developer.spotify.com/web-api/reorder-playlists-tracks/)**
|
||||
|
||||
#### 1.3.12 (22 Feb 2015)
|
||||
|
||||
* Add language binding for **[Remove tracks in a Playlist by Position](https://developer.spotify.com/web-api/remove-tracks-playlist/)**
|
||||
|
||||
#### 1.3.11
|
||||
|
||||
* Add **[Search for Playlists](https://developer.spotify.com/web-api/search-item/)** endpoint.
|
||||
|
||||
#### 1.3.10
|
||||
|
||||
* Add market parameter to endpoints supporting **[Track Relinking](https://developer.spotify.com/web-api/track-relinking-guide/)**.
|
||||
* Improve SEO by adding keywords to the package.json file. ;-)
|
||||
|
||||
#### 1.3.8
|
||||
|
||||
* Add **[Get a List of Categories](https://developer.spotify.com/web-api/get-list-categories/)**, **[Get a Category](https://developer.spotify.com/web-api/get-category/)**, and **[Get A Category's Playlists](https://developer.spotify.com/web-api/get-categorys-playlists/)** endpoints.
|
||||
|
||||
#### 1.3.7
|
||||
|
||||
* Add **[Check if Users are Following Playlist](https://developer.spotify.com/web-api/check-user-following-playlist/)** endpoint.
|
||||
|
||||
#### 1.3.5
|
||||
|
||||
* Add missing options parameter in createPlaylist (issue #19). Thanks for raising this [allinallin](https://github.com/allinallin).
|
||||
|
||||
#### 1.3.4
|
||||
|
||||
* Add **[Follow Playlist](https://developer.spotify.com/web-api/follow-playlist/)** and **[Unfollow Playlist](https://developer.spotify.com/web-api/unfollow-playlist/)** endpoints.
|
||||
|
||||
#### 1.3.3
|
||||
|
||||
* [Fix](https://github.com/thelinmichael/spotify-web-api-node/pull/18) error format. Thanks [extrakt](https://github.com/extrakt).
|
||||
|
||||
#### 1.3.2
|
||||
|
||||
* Add ability to use callback methods instead of promise.
|
||||
|
||||
#### 1.2.2
|
||||
|
||||
* Bugfix. api.addTracksToPlaylist tracks parameter can be a string or an array. Thanks [ofagbemi](https://github.com/ofagbemi)!
|
||||
|
||||
#### 1.2.1
|
||||
|
||||
* Add **[Follow endpoints](https://developer.spotify.com/web-api/web-api-follow-endpoints/)**. Great work [JMPerez](https://github.com/JMPerez).
|
||||
|
||||
#### 1.1.0
|
||||
|
||||
* Add **[Browse endpoints](https://developer.spotify.com/web-api/browse-endpoints/)**. Thanks [fsahin](https://github.com/fsahin).
|
||||
|
||||
#### 1.0.2
|
||||
|
||||
* Specify module's git repository. Thanks [vincentorback](https://github.com/vincentorback).
|
||||
|
||||
#### 1.0.1
|
||||
|
||||
* Allow options to be set when retrieving a user's playlists. Thanks [EaterOfCode](https://github.com/EaterOfCode).
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
* Add **[Replace tracks in a Playlist](https://developer.spotify.com/web-api/replace-playlists-tracks/)** endpoint
|
||||
* Add **[Remove tracks in a Playlist](https://developer.spotify.com/web-api/remove-tracks-playlist/)** endpoint
|
||||
* Return errors as Error objects instead of unparsed JSON. Thanks [niftylettuce](https://github.com/niftylettuce).
|
||||
|
||||
#### 0.0.11
|
||||
|
||||
* Add **[Change Playlist details](https://developer.spotify.com/web-api/change-playlist-details/)** endpoint (change published status and name). Gracias [JMPerez](https://github.com/JMPerez).
|
||||
|
||||
#### 0.0.10
|
||||
|
||||
* Add Your Music Endpoints (**[Add tracks](https://developer.spotify.com/web-api/save-tracks-user/)**, **[Remove tracks](https://developer.spotify.com/web-api/remove-tracks-user/)**, **[Contains tracks](https://developer.spotify.com/web-api/check-users-saved-tracks/)**, **[Get tracks](https://developer.spotify.com/web-api/get-users-saved-tracks/)**).
|
||||
* Documentation updates (change scope name of playlist-modify to playlist-modify-public, and a fix to a parameter type). Thanks [JMPerez](https://github.com/JMPerez) and [matiassingers](https://github.com/matiassingers).
|
||||
|
||||
#### 0.0.9
|
||||
|
||||
* Add **[Related artists](https://developer.spotify.com/web-api/get-related-artists/)** endpoint
|
||||
21
spotify-web-api-node/LICENSE
Normal file
21
spotify-web-api-node/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2021 Michael Thelin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1245
spotify-web-api-node/README.md
Normal file
1245
spotify-web-api-node/README.md
Normal file
File diff suppressed because it is too large
Load Diff
86
spotify-web-api-node/examples/access-token-refresh.js
Normal file
86
spotify-web-api-node/examples/access-token-refresh.js
Normal file
@@ -0,0 +1,86 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example refreshes an access token. Refreshing access tokens is only possible access tokens received using the
|
||||
* Authorization Code flow, documented here: https://developer.spotify.com/spotify-web-api/authorization-guide/#authorization_code_flow
|
||||
*/
|
||||
|
||||
/* Retrieve an authorization code as documented here:
|
||||
* https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow
|
||||
* or in the Authorization section of the README.
|
||||
*
|
||||
* Codes are given for a set of scopes. For this example, the scopes are user-read-private and user-read-email.
|
||||
* Scopes are documented here:
|
||||
* https://developer.spotify.com/documentation/general/guides/scopes/
|
||||
*/
|
||||
const authorizationCode =
|
||||
'<insert authorization code with user-read-private and user-read-email scopes>';
|
||||
|
||||
/**
|
||||
* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>',
|
||||
redirectUri: '<insert redirect URI>'
|
||||
});
|
||||
|
||||
// When our access token will expire
|
||||
let tokenExpirationEpoch;
|
||||
|
||||
// First retrieve an access token
|
||||
spotifyApi.authorizationCodeGrant(authorizationCode).then(
|
||||
function(data) {
|
||||
// Set the access token and refresh token
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
spotifyApi.setRefreshToken(data.body['refresh_token']);
|
||||
|
||||
// Save the amount of seconds until the access token expired
|
||||
tokenExpirationEpoch =
|
||||
new Date().getTime() / 1000 + data.body['expires_in'];
|
||||
console.log(
|
||||
'Retrieved token. It expires in ' +
|
||||
Math.floor(tokenExpirationEpoch - new Date().getTime() / 1000) +
|
||||
' seconds!'
|
||||
);
|
||||
},
|
||||
function(err) {
|
||||
console.log(
|
||||
'Something went wrong when retrieving the access token!',
|
||||
err.message
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Continually print out the time left until the token expires..
|
||||
let numberOfTimesUpdated = 0;
|
||||
|
||||
setInterval(function() {
|
||||
console.log(
|
||||
'Time left: ' +
|
||||
Math.floor(tokenExpirationEpoch - new Date().getTime() / 1000) +
|
||||
' seconds left!'
|
||||
);
|
||||
|
||||
// OK, we need to refresh the token. Stop printing and refresh.
|
||||
if (++numberOfTimesUpdated > 5) {
|
||||
clearInterval(this);
|
||||
|
||||
// Refresh token and print the new time to expiration.
|
||||
spotifyApi.refreshAccessToken().then(
|
||||
function(data) {
|
||||
tokenExpirationEpoch =
|
||||
new Date().getTime() / 1000 + data.body['expires_in'];
|
||||
console.log(
|
||||
'Refreshed token. It now expires in ' +
|
||||
Math.floor(tokenExpirationEpoch - new Date().getTime() / 1000) +
|
||||
' seconds!'
|
||||
);
|
||||
},
|
||||
function(err) {
|
||||
console.log('Could not refresh the token!', err.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
}, 1000);
|
||||
@@ -0,0 +1,32 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example retrieves an access token using the Client Credentials Flow, documented at:
|
||||
* https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>'
|
||||
});
|
||||
|
||||
// Retrieve an access token
|
||||
spotifyApi.clientCredentialsGrant().then(
|
||||
function(data) {
|
||||
console.log('The access token expires in ' + data.body['expires_in']);
|
||||
console.log('The access token is ' + data.body['access_token']);
|
||||
|
||||
// Save the access token so that it's used in future calls
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
},
|
||||
function(err) {
|
||||
console.log(
|
||||
'Something went wrong when retrieving an access token',
|
||||
err.message
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,84 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example demonstrates adding tracks, removing tracks, and replacing tracks in a playlist. At the time of writing this
|
||||
* documentation, this is the available playlist track modification feature in the Spotify Web API.
|
||||
*
|
||||
* Since authorization is required, this example retrieves an access token using the Authorization Code Grant flow,
|
||||
* documented here: https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow
|
||||
*
|
||||
* Codes are given for a set of scopes. For this example, the scopes are playlist-modify-public.
|
||||
* Scopes are documented here:
|
||||
* https://developer.spotify.com/documentation/general/guides/scopes/
|
||||
*/
|
||||
|
||||
/* Obtain the `authorizationCode` below as described in the Authorization section of the README.
|
||||
*/
|
||||
const authorizationCode =
|
||||
'<insert authorization code with playlist-modify-public scope>';
|
||||
|
||||
/**
|
||||
* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>',
|
||||
redirectUri: '<insert redirect URI>'
|
||||
});
|
||||
|
||||
let playlistId;
|
||||
|
||||
// First retrieve an access token
|
||||
spotifyApi
|
||||
.authorizationCodeGrant(authorizationCode)
|
||||
.then(function(data) {
|
||||
// Save the access token so that it's used in future requests
|
||||
spotifyApi.setAccessToken(data['access_token']);
|
||||
|
||||
// Create a playlist
|
||||
return spotifyApi.createPlaylist(
|
||||
'thelinmichael',
|
||||
'My New Awesome Playlist'
|
||||
);
|
||||
})
|
||||
.then(function(data) {
|
||||
console.log('Ok. Playlist created!');
|
||||
playlistId = data.body['id'];
|
||||
|
||||
// Add tracks to the playlist
|
||||
return spotifyApi.addTracksToPlaylist(playlistId, [
|
||||
'spotify:track:4iV5W9uYEdYUVa79Axb7Rh',
|
||||
'spotify:track:6tcfwoGcDjxnSc6etAkDRR',
|
||||
'spotify:track:4iV5W9uYEdYUVa79Axb7Rh'
|
||||
]);
|
||||
})
|
||||
.then(function(data) {
|
||||
console.log('Ok. Tracks added!');
|
||||
|
||||
// Woops! Made a duplicate. Remove one of the duplicates from the playlist
|
||||
return spotifyApi.removeTracksFromPlaylist('thelinmichael', playlistId, [
|
||||
{
|
||||
uri: 'spotify:track:4iV5W9uYEdYUVa79Axb7Rh',
|
||||
positions: [0]
|
||||
}
|
||||
]);
|
||||
})
|
||||
.then(function(data) {
|
||||
console.log('Ok. Tracks removed!');
|
||||
|
||||
// Actually, lets just replace all tracks in the playlist with something completely different
|
||||
return spotifyApi.replaceTracksInPlaylist('thelinmichael', playlistId, [
|
||||
'spotify:track:5Wd2bfQ7wc6GgSa32OmQU3',
|
||||
'spotify:track:4r8lRYnoOGdEi6YyI5OC1o',
|
||||
'spotify:track:4TZZvblv2yzLIBk2JwJ6Un',
|
||||
'spotify:track:2IA4WEsWAYpV9eKkwR2UYv',
|
||||
'spotify:track:6hDH3YWFdcUNQjubYztIsG'
|
||||
]);
|
||||
})
|
||||
.then(function(data) {
|
||||
console.log('Ok. Tracks replaced!');
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log('Something went wrong:', err.message);
|
||||
});
|
||||
49
spotify-web-api-node/examples/add-tracks-to-a-playlist.js
Normal file
49
spotify-web-api-node/examples/add-tracks-to-a-playlist.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example demonstrates adding tracks to a specified position in a playlist.
|
||||
*
|
||||
* Since authorization is required, this example retrieves an access token using the Authorization Code Grant flow,
|
||||
* documented here: https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow
|
||||
*
|
||||
* Codes are given for a set of scopes. For this example, the scopes are playlist-modify-public.
|
||||
* Scopes are documented here:
|
||||
* https://developer.spotify.com/documentation/general/guides/scopes/
|
||||
*/
|
||||
|
||||
/* Obtain the `authorizationCode` below as described in the Authorization section of the README.
|
||||
*/
|
||||
const authorizationCode = '<insert authorization code>';
|
||||
|
||||
/**
|
||||
* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>',
|
||||
redirectUri: '<insert redirect URI>'
|
||||
});
|
||||
|
||||
// First retrieve an access token
|
||||
spotifyApi
|
||||
.authorizationCodeGrant(authorizationCode)
|
||||
.then(function(data) {
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
return spotifyApi.addTracksToPlaylist(
|
||||
'5ieJqeLJjjI8iJWaxeBLuK',
|
||||
[
|
||||
'spotify:track:4iV5W9uYEdYUVa79Axb7Rh',
|
||||
'spotify:track:1301WleyT98MSxVHPZCA6M'
|
||||
],
|
||||
{
|
||||
position: 10
|
||||
}
|
||||
);
|
||||
})
|
||||
.then(function(data) {
|
||||
console.log('Added tracks to the playlist!');
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log('Something went wrong:', err.message);
|
||||
});
|
||||
26
spotify-web-api-node/examples/client-credentials.js
Normal file
26
spotify-web-api-node/examples/client-credentials.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const { util } = require('prettier');
|
||||
var SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example uses the Client Credentials authorization flow.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<Client ID>',
|
||||
clientSecret: '<Client Secret>'
|
||||
});
|
||||
|
||||
// Retrieve an access token using your credentials
|
||||
spotifyApi.clientCredentialsGrant().
|
||||
then(function(result) {
|
||||
console.log('It worked! Your access token is: ' + result.body.access_token);
|
||||
}).catch(function(err) {
|
||||
console.log('If this is printed, it probably means that you used invalid ' +
|
||||
'clientId and clientSecret values. Please check!');
|
||||
console.log('Hint: ');
|
||||
console.log(err);
|
||||
});
|
||||
54
spotify-web-api-node/examples/get-info-about-current-user.js
Normal file
54
spotify-web-api-node/examples/get-info-about-current-user.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example retrieves information about the 'current' user. The current user is the user that has
|
||||
* authorized the application to access its data.
|
||||
*/
|
||||
|
||||
/* Retrieve a code as documented here:
|
||||
* https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow
|
||||
*
|
||||
* Codes are given for a set of scopes. For this example, the scopes are user-read-private and user-read-email.
|
||||
* Scopes are documented here:
|
||||
* https://developer.spotify.com/documentation/general/guides/scopes/
|
||||
*/
|
||||
const authorizationCode =
|
||||
'<insert authorization code with user-read-private and user-read-email scopes>';
|
||||
|
||||
/* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>',
|
||||
redirectUri: '<insert redirect URI>'
|
||||
});
|
||||
|
||||
// First retrieve an access token
|
||||
spotifyApi
|
||||
.authorizationCodeGrant(authorizationCode)
|
||||
.then(function(data) {
|
||||
console.log('Retrieved access token', data.body['access_token']);
|
||||
|
||||
// Set the access token
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
|
||||
// Use the access token to retrieve information about the user connected to it
|
||||
return spotifyApi.getMe();
|
||||
})
|
||||
.then(function(data) {
|
||||
// "Retrieved data for Faruk Sahin"
|
||||
console.log('Retrieved data for ' + data.body['display_name']);
|
||||
|
||||
// "Email is farukemresahin@gmail.com"
|
||||
console.log('Email is ' + data.body.email);
|
||||
|
||||
// "Image URL is http://media.giphy.com/media/Aab07O5PYOmQ/giphy.gif"
|
||||
console.log('Image URL is ' + data.body.images[0].url);
|
||||
|
||||
// "This user has a premium account"
|
||||
console.log('This user has a ' + data.body.product + ' account');
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log('Something went wrong:', err.message);
|
||||
});
|
||||
49
spotify-web-api-node/examples/get-related-artists.js
Normal file
49
spotify-web-api-node/examples/get-related-artists.js
Normal file
@@ -0,0 +1,49 @@
|
||||
var SpotifyWebApi = require('../');
|
||||
|
||||
/*
|
||||
* This example shows how to get artists related to another artists. The endpoint is documented here:
|
||||
* https://developer.spotify.com/web-api/get-related-artists/
|
||||
|
||||
* Please note that authorization is now required and so this example retrieves an access token using the Authorization Code Flow,
|
||||
* documented here: https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow
|
||||
*/
|
||||
|
||||
var authorizationCode =
|
||||
'AQAgjS78s64u1axMCBCRA0cViW_ZDDU0pbgENJ_-WpZr3cEO7V5O-JELcEPU6pGLPp08SfO3dnHmu6XJikKqrU8LX9W6J11NyoaetrXtZFW-Y58UGeV69tuyybcNUS2u6eyup1EgzbTEx4LqrP_eCHsc9xHJ0JUzEhi7xcqzQG70roE4WKM_YrlDZO-e7GDRMqunS9RMoSwF_ov-gOMpvy9OMb7O58nZoc3LSEdEwoZPCLU4N4TTJ-IF6YsQRhQkEOJK';
|
||||
|
||||
/* Set the credentials given on Spotify's My Applications page.
|
||||
* https://developer.spotify.com/my-applications
|
||||
*/
|
||||
var spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>',
|
||||
redirectUri: '<insert redirect URI>'
|
||||
});
|
||||
|
||||
var artistId = '0qeei9KQnptjwb8MgkqEoy';
|
||||
|
||||
spotifyApi
|
||||
.authorizationCodeGrant(authorizationCode)
|
||||
.then(function(data) {
|
||||
console.log('Retrieved access token', data.body['access_token']);
|
||||
|
||||
// Set the access token
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
|
||||
// Use the access token to retrieve information about the user connected to it
|
||||
return spotifyApi.getArtistRelatedArtists(artistId);
|
||||
})
|
||||
.then(function(data) {
|
||||
if (data.body.artists.length) {
|
||||
// Print the number of similar artists
|
||||
console.log('I got ' + data.body.artists.length + ' similar artists!');
|
||||
|
||||
console.log('The most similar one is ' + data.body.artists[0].name);
|
||||
} else {
|
||||
console.log("I didn't find any similar artists.. Sorry.");
|
||||
}
|
||||
},
|
||||
function(err) {
|
||||
console.log('Something went wrong:', err.message);
|
||||
}
|
||||
);
|
||||
56
spotify-web-api-node/examples/get-top-tracks-for-artist.js
Normal file
56
spotify-web-api-node/examples/get-top-tracks-for-artist.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/**
|
||||
* This example retrieves the top tracks for an artist.
|
||||
* https://developer.spotify.com/documentation/web-api/reference/artists/get-artists-top-tracks/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This endpoint doesn't require an access token, but it's beneficial to use one as it
|
||||
* gives the application a higher rate limit.
|
||||
*
|
||||
* Since it's not necessary to get an access token connected to a specific user, this example
|
||||
* uses the Client Credentials flow. This flow uses only the client ID and the client secret.
|
||||
* https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>'
|
||||
});
|
||||
|
||||
// Retrieve an access token
|
||||
spotifyApi
|
||||
.clientCredentialsGrant()
|
||||
.then(function(data) {
|
||||
// Set the access token on the API object so that it's used in all future requests
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
|
||||
// Get the most popular tracks by David Bowie in Great Britain
|
||||
return spotifyApi.getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy', 'GB');
|
||||
})
|
||||
.then(function(data) {
|
||||
console.log('The most popular tracks for David Bowie is..');
|
||||
console.log('Drum roll..');
|
||||
console.log('...');
|
||||
|
||||
/*
|
||||
* 1. Space Oddity - 2009 Digital Remaster (popularity is 51)
|
||||
* 2. Heroes - 1999 Digital Remaster (popularity is 33)
|
||||
* 3. Let's Dance - 1999 Digital Remaster (popularity is 20)
|
||||
* 4. ...
|
||||
*/
|
||||
data.body.tracks.forEach(function(track, index) {
|
||||
console.log(
|
||||
index +
|
||||
1 +
|
||||
'. ' +
|
||||
track.name +
|
||||
' (popularity is ' +
|
||||
track.popularity +
|
||||
')'
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log('Unfortunately, something has gone wrong.', err.message);
|
||||
});
|
||||
55
spotify-web-api-node/examples/search-for-tracks.js
Normal file
55
spotify-web-api-node/examples/search-for-tracks.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const SpotifyWebApi = require('../');
|
||||
|
||||
/*
|
||||
* This example shows how to search for a track. The endpoint is documented here:
|
||||
* https://developer.spotify.com/documentation/web-api/reference/search/
|
||||
|
||||
* Since authorization is now required, this example retrieves an access token using the Authorization Code Grant flow,
|
||||
* documented here: https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow
|
||||
*
|
||||
* Obtain the `authorizationCode` below as described in the Authorization section of the README.
|
||||
*/
|
||||
|
||||
const authorizationCode = '<insert authorization code>';
|
||||
|
||||
/**
|
||||
* Get the credentials from Spotify's Dashboard page.
|
||||
* https://developer.spotify.com/dashboard/applications
|
||||
*/
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
clientId: '<insert client id>',
|
||||
clientSecret: '<insert client secret>',
|
||||
redirectUri: '<insert redirect URI>'
|
||||
});
|
||||
|
||||
spotifyApi
|
||||
.authorizationCodeGrant(authorizationCode)
|
||||
.then(function(data) {
|
||||
console.log('Retrieved access token', data.body['access_token']);
|
||||
|
||||
// Set the access token
|
||||
spotifyApi.setAccessToken(data.body['access_token']);
|
||||
|
||||
// Use the access token to retrieve information about the user connected to it
|
||||
return spotifyApi.searchTracks('Love');
|
||||
})
|
||||
.then(function(data) {
|
||||
// Print some information about the results
|
||||
console.log('I got ' + data.body.tracks.total + ' results!');
|
||||
|
||||
// Go through the first page of results
|
||||
var firstPage = data.body.tracks.items;
|
||||
console.log('The tracks in the first page are (popularity in parentheses):');
|
||||
|
||||
/*
|
||||
* 0: All of Me (97)
|
||||
* 1: My Love (91)
|
||||
* 2: I Love This Life (78)
|
||||
* ...
|
||||
*/
|
||||
firstPage.forEach(function(track, index) {
|
||||
console.log(index + ': ' + track.name + ' (' + track.popularity + ')');
|
||||
});
|
||||
}).catch(function(err) {
|
||||
console.log('Something went wrong:', err.message);
|
||||
});
|
||||
101
spotify-web-api-node/examples/tutorial/00-get-access-token.js
Normal file
101
spotify-web-api-node/examples/tutorial/00-get-access-token.js
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* This example is using the Authorization Code flow.
|
||||
*
|
||||
* In root directory run
|
||||
*
|
||||
* npm install express
|
||||
*
|
||||
* then run with the followinng command. If you don't have a client_id and client_secret yet,
|
||||
* create an application on Create an application here: https://developer.spotify.com/my-applications to get them.
|
||||
* Make sure you whitelist the correct redirectUri in line 26.
|
||||
*
|
||||
* node access-token-server.js "<Client ID>" "<Client Secret>"
|
||||
*
|
||||
* and visit <http://localhost:8888/login> in your Browser.
|
||||
*/
|
||||
const SpotifyWebApi = require('../../');
|
||||
const express = require('../../node_modules/express');
|
||||
|
||||
const scopes = [
|
||||
'ugc-image-upload',
|
||||
'user-read-playback-state',
|
||||
'user-modify-playback-state',
|
||||
'user-read-currently-playing',
|
||||
'streaming',
|
||||
'app-remote-control',
|
||||
'user-read-email',
|
||||
'user-read-private',
|
||||
'playlist-read-collaborative',
|
||||
'playlist-modify-public',
|
||||
'playlist-read-private',
|
||||
'playlist-modify-private',
|
||||
'user-library-modify',
|
||||
'user-library-read',
|
||||
'user-top-read',
|
||||
'user-read-playback-position',
|
||||
'user-read-recently-played',
|
||||
'user-follow-read',
|
||||
'user-follow-modify'
|
||||
];
|
||||
|
||||
const spotifyApi = new SpotifyWebApi({
|
||||
redirectUri: 'http://localhost:8888/callback',
|
||||
clientId: process.argv.slice(2)[0],
|
||||
clientSecret: process.argv.slice(2)[1]
|
||||
});
|
||||
|
||||
const app = express();
|
||||
|
||||
app.get('/login', (req, res) => {
|
||||
res.redirect(spotifyApi.createAuthorizeURL(scopes));
|
||||
});
|
||||
|
||||
app.get('/callback', (req, res) => {
|
||||
const error = req.query.error;
|
||||
const code = req.query.code;
|
||||
const state = req.query.state;
|
||||
|
||||
if (error) {
|
||||
console.error('Callback Error:', error);
|
||||
res.send(`Callback Error: ${error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
spotifyApi
|
||||
.authorizationCodeGrant(code)
|
||||
.then(data => {
|
||||
const access_token = data.body['access_token'];
|
||||
const refresh_token = data.body['refresh_token'];
|
||||
const expires_in = data.body['expires_in'];
|
||||
|
||||
spotifyApi.setAccessToken(access_token);
|
||||
spotifyApi.setRefreshToken(refresh_token);
|
||||
|
||||
console.log('access_token:', access_token);
|
||||
console.log('refresh_token:', refresh_token);
|
||||
|
||||
console.log(
|
||||
`Sucessfully retreived access token. Expires in ${expires_in} s.`
|
||||
);
|
||||
res.send('Success! You can now close the window.');
|
||||
|
||||
setInterval(async () => {
|
||||
const data = await spotifyApi.refreshAccessToken();
|
||||
const access_token = data.body['access_token'];
|
||||
|
||||
console.log('The access token has been refreshed!');
|
||||
console.log('access_token:', access_token);
|
||||
spotifyApi.setAccessToken(access_token);
|
||||
}, expires_in / 2 * 1000);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error getting Tokens:', error);
|
||||
res.send(`Error getting Tokens: ${error}`);
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(8888, () =>
|
||||
console.log(
|
||||
'HTTP Server up. Now go to http://localhost:8888/login in your browser.'
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,11 @@
|
||||
const SpotifyWebApi = require('../../../');
|
||||
|
||||
const spotifyApi = new SpotifyWebApi();
|
||||
spotifyApi.setAccessToken(process.env.SPOTIFY_ACCESS_TOKEN);
|
||||
|
||||
(async () => {
|
||||
const me = await spotifyApi.getMe();
|
||||
console.log(me);
|
||||
})().catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
17
spotify-web-api-node/examples/tutorial/README.md
Normal file
17
spotify-web-api-node/examples/tutorial/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
Execute all commands from the root folder of this repository.
|
||||
|
||||
Start with
|
||||
|
||||
git clone <this repo url>
|
||||
cd spotify-web-api-node
|
||||
npm install
|
||||
npm install express
|
||||
node examples/tutorial/00-get-access-token.js "<Client ID>" "<Client Secret>"
|
||||
|
||||
and visit <http://localhost:8888/login> in your browser to get an `access_token`.
|
||||
If you don't have a `client_id` and `client_secret` yet, create an application here: <https://developer.spotify.com/my-applications> to get them. Make sure you whitelist the correct redirectUri when creating your application, which is `http://localhost:8888/callback`.
|
||||
|
||||
After you got the `access_token`, call all other examples with this token in ENV variable `SPOTIFY_ACCESS_TOKEN`. The easiest way is to call:
|
||||
|
||||
export SPOTIFY_ACCESS_TOKEN="<Token content here>"
|
||||
node examples/tutorial/01-basics/01-get-info-about-current-user.js
|
||||
69
spotify-web-api-node/package.json
Normal file
69
spotify-web-api-node/package.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "spotify-web-api-node",
|
||||
"version": "5.0.3",
|
||||
"homepage": "https://github.com/thelinmichael/spotify-web-api-node",
|
||||
"description": "A Node.js wrapper for Spotify's Web API",
|
||||
"main": "./src/server.js",
|
||||
"author": "Michael Thelin",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "José M. Perez",
|
||||
"url": "https://github.com/JMPerez"
|
||||
},
|
||||
{
|
||||
"name": "Deeplydrumming",
|
||||
"url": "https://gitlab.com/deeplydrumming"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thelinmichael/spotify-web-api-node.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"travis": "npm test -- --coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
|
||||
"precommit": "lint-staged"
|
||||
},
|
||||
"jest": {
|
||||
"verbose": true,
|
||||
"testURL": "http://localhost/"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,json,css,md}": [
|
||||
"prettier --single-quote --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"superagent": "^6.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^3.1.0",
|
||||
"husky": "^4.3.0",
|
||||
"jest": "^26.6.3",
|
||||
"lint-staged": "^10.4.0",
|
||||
"prettier": "^2.1.2",
|
||||
"sinon": "^9.0.3",
|
||||
"canvas": "^2.6.1",
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2",
|
||||
"jest-resolve": "^26.6.2",
|
||||
"minimist": "^1.2.5",
|
||||
"set-value": ">=2.0.1",
|
||||
"mixin-deep": ">=1.3.2",
|
||||
"ini": ">=1.3.6"
|
||||
},
|
||||
"keywords": [
|
||||
"spotify",
|
||||
"echonest",
|
||||
"music",
|
||||
"api",
|
||||
"wrapper",
|
||||
"client",
|
||||
"web api"
|
||||
],
|
||||
"browser": {
|
||||
"./src/server.js": "./src/client.js"
|
||||
}
|
||||
}
|
||||
14
spotify-web-api-node/src/authentication-request.js
Normal file
14
spotify-web-api-node/src/authentication-request.js
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const Request = require('./base-request')
|
||||
|
||||
const DEFAULT_HOST = 'accounts.spotify.com'
|
||||
const DEFAULT_PORT = 443
|
||||
const DEFAULT_SCHEME = 'https'
|
||||
|
||||
module.exports.builder = function () {
|
||||
return Request.builder()
|
||||
.withHost(DEFAULT_HOST)
|
||||
.withPort(DEFAULT_PORT)
|
||||
.withScheme(DEFAULT_SCHEME)
|
||||
}
|
||||
165
spotify-web-api-node/src/base-request.js
Normal file
165
spotify-web-api-node/src/base-request.js
Normal file
@@ -0,0 +1,165 @@
|
||||
'use strict'
|
||||
|
||||
const Request = function (builder) {
|
||||
if (!builder) {
|
||||
throw new Error('No builder supplied to constructor')
|
||||
}
|
||||
|
||||
this.host = builder.host
|
||||
this.port = builder.port
|
||||
this.scheme = builder.scheme
|
||||
this.queryParameters = builder.queryParameters
|
||||
this.bodyParameters = builder.bodyParameters
|
||||
this.headers = builder.headers
|
||||
this.path = builder.path
|
||||
}
|
||||
|
||||
Request.prototype._getter = function (key) {
|
||||
return function () {
|
||||
return this[key]
|
||||
}
|
||||
}
|
||||
|
||||
Request.prototype.getHost = Request.prototype._getter('host')
|
||||
|
||||
Request.prototype.getPort = Request.prototype._getter('port')
|
||||
|
||||
Request.prototype.getScheme = Request.prototype._getter('scheme')
|
||||
|
||||
Request.prototype.getPath = Request.prototype._getter('path')
|
||||
|
||||
Request.prototype.getQueryParameters = Request.prototype._getter(
|
||||
'queryParameters'
|
||||
)
|
||||
|
||||
Request.prototype.getBodyParameters = Request.prototype._getter(
|
||||
'bodyParameters'
|
||||
)
|
||||
|
||||
Request.prototype.getHeaders = Request.prototype._getter('headers')
|
||||
|
||||
Request.prototype.getURI = function () {
|
||||
if (!this.scheme || !this.host || !this.port) {
|
||||
throw new Error('Missing components necessary to construct URI')
|
||||
}
|
||||
let uri = this.scheme + '://' + this.host
|
||||
if (
|
||||
(this.scheme === 'http' && this.port !== 80) ||
|
||||
(this.scheme === 'https' && this.port !== 443)
|
||||
) {
|
||||
uri += ':' + this.port
|
||||
}
|
||||
if (this.path) {
|
||||
uri += this.path
|
||||
}
|
||||
return uri
|
||||
}
|
||||
|
||||
Request.prototype.getURL = function () {
|
||||
const uri = this.getURI()
|
||||
if (this.getQueryParameters()) {
|
||||
return uri + this.getQueryParameterString(this.getQueryParameters())
|
||||
} else {
|
||||
return uri
|
||||
}
|
||||
}
|
||||
|
||||
Request.prototype.getQueryParameterString = function () {
|
||||
const queryParameters = this.getQueryParameters()
|
||||
if (queryParameters) {
|
||||
return (
|
||||
'?' +
|
||||
Object.keys(queryParameters)
|
||||
.filter(function (key) {
|
||||
return queryParameters[key] !== undefined
|
||||
})
|
||||
.map(function (key) {
|
||||
return key + '=' + queryParameters[key]
|
||||
})
|
||||
.join('&')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Request.prototype.execute = function (method, callback) {
|
||||
if (callback) {
|
||||
method(this, callback)
|
||||
return
|
||||
}
|
||||
const _self = this
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
method(_self, function (error, result) {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const Builder = function () {}
|
||||
|
||||
Builder.prototype._setter = function (key) {
|
||||
return function (value) {
|
||||
this[key] = value
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.withHost = Builder.prototype._setter('host')
|
||||
|
||||
Builder.prototype.withPort = Builder.prototype._setter('port')
|
||||
|
||||
Builder.prototype.withScheme = Builder.prototype._setter('scheme')
|
||||
|
||||
Builder.prototype.withPath = Builder.prototype._setter('path')
|
||||
|
||||
Builder.prototype._assigner = function (key) {
|
||||
return function () {
|
||||
for (let i = 0; i < arguments.length; i++) {
|
||||
this[key] = this._assign(this[key], arguments[i])
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.withQueryParameters = Builder.prototype._assigner(
|
||||
'queryParameters'
|
||||
)
|
||||
|
||||
Builder.prototype.withBodyParameters = Builder.prototype._assigner(
|
||||
'bodyParameters'
|
||||
)
|
||||
|
||||
Builder.prototype.withHeaders = Builder.prototype._assigner('headers')
|
||||
|
||||
Builder.prototype.withAuth = function (accessToken) {
|
||||
if (accessToken) {
|
||||
this.withHeaders({ Authorization: 'Bearer ' + accessToken })
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
Builder.prototype._assign = function (src, obj) {
|
||||
if (obj && Array.isArray(obj)) {
|
||||
return obj
|
||||
}
|
||||
if (obj && typeof obj === 'string') {
|
||||
return obj
|
||||
}
|
||||
if (obj && Object.keys(obj).length > 0) {
|
||||
return Object.assign(src || {}, obj)
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
Builder.prototype.build = function () {
|
||||
return new Request(this)
|
||||
}
|
||||
|
||||
module.exports.builder = function () {
|
||||
return new Builder()
|
||||
}
|
||||
1
spotify-web-api-node/src/client.js
Normal file
1
spotify-web-api-node/src/client.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./spotify-web-api')
|
||||
134
spotify-web-api-node/src/http-manager.js
Normal file
134
spotify-web-api-node/src/http-manager.js
Normal file
@@ -0,0 +1,134 @@
|
||||
'use strict'
|
||||
|
||||
const superagent = require('superagent')
|
||||
const {
|
||||
TimeoutError,
|
||||
WebapiError,
|
||||
WebapiRegularError,
|
||||
WebapiAuthenticationError,
|
||||
WebapiPlayerError
|
||||
} = require('./response-error')
|
||||
|
||||
const HttpManager = {}
|
||||
|
||||
/* Create superagent options from the base request */
|
||||
const _getParametersFromRequest = function (request) {
|
||||
const options = {}
|
||||
|
||||
if (request.getQueryParameters()) {
|
||||
options.query = request.getQueryParameters()
|
||||
}
|
||||
|
||||
if (request.getHeaders() && request.getHeaders()['Content-Type'] === 'application/json') {
|
||||
options.data = JSON.stringify(request.getBodyParameters())
|
||||
} else if (request.getBodyParameters()) {
|
||||
options.data = request.getBodyParameters()
|
||||
}
|
||||
|
||||
if (request.getHeaders()) {
|
||||
options.headers = request.getHeaders()
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
const _toError = function (response) {
|
||||
if (typeof response.body === 'object' && response.body.error && typeof response.body.error === 'object' && response.body.error.reason) {
|
||||
return new WebapiPlayerError(response.body, response.headers, response.statusCode)
|
||||
}
|
||||
|
||||
if (typeof response.body === 'object' && response.body.error && typeof response.body.error === 'object') {
|
||||
return new WebapiRegularError(response.body, response.headers, response.statusCode)
|
||||
}
|
||||
|
||||
if (typeof response.body === 'object' && response.body.error && typeof response.body.error === 'string') {
|
||||
return new WebapiAuthenticationError(response.body, response.headers, response.statusCode)
|
||||
}
|
||||
|
||||
/* Other type of error, or unhandled Web API error format */
|
||||
return new WebapiError(response.body, response.headers, response.statusCode, response.body)
|
||||
}
|
||||
|
||||
/* Make the request to the Web API */
|
||||
HttpManager._makeRequest = function (method, options, uri, callback) {
|
||||
const req = method.bind(superagent)(uri)
|
||||
|
||||
if (options.query) {
|
||||
req.query(options.query)
|
||||
}
|
||||
|
||||
if (options.headers) {
|
||||
req.set(options.headers)
|
||||
}
|
||||
|
||||
if (options.data) {
|
||||
req.send(options.data)
|
||||
}
|
||||
|
||||
req.end(function (err, response) {
|
||||
if (err) {
|
||||
if (err.timeout) {
|
||||
return callback(new TimeoutError())
|
||||
} else if (err.response) {
|
||||
return callback(_toError(err.response))
|
||||
} else {
|
||||
return callback(err)
|
||||
}
|
||||
}
|
||||
|
||||
return callback(null, {
|
||||
body: response.body,
|
||||
headers: response.headers,
|
||||
statusCode: response.statusCode
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP GET request.
|
||||
* @param {BaseRequest} The request.
|
||||
* @param {Function} The callback function.
|
||||
*/
|
||||
HttpManager.get = function (request, callback) {
|
||||
const options = _getParametersFromRequest(request)
|
||||
const method = superagent.get
|
||||
|
||||
HttpManager._makeRequest(method, options, request.getURI(), callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP POST request.
|
||||
* @param {BaseRequest} The request.
|
||||
* @param {Function} The callback function.
|
||||
*/
|
||||
HttpManager.post = function (request, callback) {
|
||||
const options = _getParametersFromRequest(request)
|
||||
const method = superagent.post
|
||||
|
||||
HttpManager._makeRequest(method, options, request.getURI(), callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP DELETE request.
|
||||
* @param {BaseRequest} The request.
|
||||
* @param {Function} The callback function.
|
||||
*/
|
||||
HttpManager.del = function (request, callback) {
|
||||
const options = _getParametersFromRequest(request)
|
||||
const method = superagent.del
|
||||
|
||||
HttpManager._makeRequest(method, options, request.getURI(), callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP PUT request.
|
||||
* @param {BaseRequest} The request.
|
||||
* @param {Function} The callback function.
|
||||
*/
|
||||
HttpManager.put = function (request, callback) {
|
||||
const options = _getParametersFromRequest(request)
|
||||
const method = superagent.put
|
||||
|
||||
HttpManager._makeRequest(method, options, request.getURI(), callback)
|
||||
}
|
||||
|
||||
module.exports = HttpManager
|
||||
64
spotify-web-api-node/src/response-error.js
Normal file
64
spotify-web-api-node/src/response-error.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/* Timeout */
|
||||
class NamedError extends Error {
|
||||
get name () {
|
||||
return this.constructor.name
|
||||
}
|
||||
}
|
||||
|
||||
class TimeoutError extends NamedError {
|
||||
constructor () {
|
||||
const message = 'A timeout occurred while communicating with Spotify\'s Web API.'
|
||||
super(message)
|
||||
}
|
||||
}
|
||||
|
||||
/* Web API Parent and fallback error */
|
||||
class WebapiError extends NamedError {
|
||||
constructor (body, headers, statusCode, message) {
|
||||
super(message)
|
||||
this.body = body
|
||||
this.headers = headers
|
||||
this.statusCode = statusCode
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular Error
|
||||
* { status : <integer>, message : <string> }
|
||||
*/
|
||||
class WebapiRegularError extends WebapiError {
|
||||
constructor (body, headers, statusCode) {
|
||||
const message = 'An error occurred while communicating with Spotify\'s Web API.\n' +
|
||||
'Details: ' + body.error.message + '.'
|
||||
|
||||
super(body, headers, statusCode, message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication Error
|
||||
* { error : <string>, error_description : <string> }
|
||||
*/
|
||||
class WebapiAuthenticationError extends WebapiError {
|
||||
constructor (body, headers, statusCode) {
|
||||
const message = 'An authentication error occurred while communicating with Spotify\'s Web API.\n' +
|
||||
'Details: ' + body.error + (body.error_description ? ' ' + body.error_description + '.' : '.')
|
||||
|
||||
super(body, headers, statusCode, message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Player Error
|
||||
* { status : <integer>, message : <string>, reason : <string> }
|
||||
*/
|
||||
class WebapiPlayerError extends WebapiError {
|
||||
constructor (body, headers, statusCode) {
|
||||
const message = 'An error occurred while communicating with Spotify\'s Web API.\n' +
|
||||
'Details: ' + body.error.message + (body.error.reason ? ' ' + body.error.reason + '.' : '.')
|
||||
|
||||
super(body, headers, statusCode, message)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { WebapiError, TimeoutError, WebapiRegularError, WebapiAuthenticationError, WebapiPlayerError }
|
||||
106
spotify-web-api-node/src/server-methods.js
Normal file
106
spotify-web-api-node/src/server-methods.js
Normal file
@@ -0,0 +1,106 @@
|
||||
'use strict'
|
||||
|
||||
const AuthenticationRequest = require('./authentication-request')
|
||||
const HttpManager = require('./http-manager')
|
||||
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param {boolean} showDialog A parameter that you can use to force the user to approve the app on each login rather than being automatically redirected.
|
||||
* @param {string} responseType An optional parameter that you can use to specify the code response based on the authentication type - can be set to 'code' or 'token'. Default 'code' to ensure backwards compatability.
|
||||
* @returns {string} The URL where the user can give application permissions.
|
||||
*/
|
||||
createAuthorizeURL: function (scopes, state, showDialog, responseType = 'code') {
|
||||
return AuthenticationRequest.builder()
|
||||
.withPath('/authorize')
|
||||
.withQueryParameters({
|
||||
client_id: this.getClientId(),
|
||||
response_type: responseType,
|
||||
redirect_uri: this.getRedirectURI(),
|
||||
scope: scopes.join('%20'),
|
||||
state,
|
||||
show_dialog: showDialog && !!showDialog
|
||||
})
|
||||
.build()
|
||||
.getURL()
|
||||
},
|
||||
|
||||
/**
|
||||
* Request an access token using the Client Credentials flow.
|
||||
* Requires that client ID and client secret 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 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.
|
||||
*/
|
||||
clientCredentialsGrant: function (callback) {
|
||||
return AuthenticationRequest.builder()
|
||||
.withPath('/api/token')
|
||||
.withBodyParameters({
|
||||
grant_type: 'client_credentials'
|
||||
})
|
||||
.withHeaders({
|
||||
Authorization:
|
||||
'Basic ' +
|
||||
Buffer.from(
|
||||
this.getClientId() + ':' + this.getClientSecret()
|
||||
).toString('base64'),
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
})
|
||||
.build()
|
||||
.execute(HttpManager.post, callback)
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
authorizationCodeGrant: function (code, callback) {
|
||||
return AuthenticationRequest.builder()
|
||||
.withPath('/api/token')
|
||||
.withBodyParameters({
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: this.getRedirectURI(),
|
||||
code,
|
||||
client_id: this.getClientId(),
|
||||
client_secret: this.getClientSecret()
|
||||
})
|
||||
.withHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' })
|
||||
.build()
|
||||
.execute(HttpManager.post, callback)
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
refreshAccessToken: function (callback) {
|
||||
return AuthenticationRequest.builder()
|
||||
.withPath('/api/token')
|
||||
.withBodyParameters({
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: this.getRefreshToken()
|
||||
})
|
||||
.withHeaders({
|
||||
Authorization:
|
||||
'Basic ' +
|
||||
Buffer.from(
|
||||
this.getClientId() + ':' + this.getClientSecret()
|
||||
).toString('base64'),
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
})
|
||||
.build()
|
||||
.execute(HttpManager.post, callback)
|
||||
}
|
||||
}
|
||||
4
spotify-web-api-node/src/server.js
Normal file
4
spotify-web-api-node/src/server.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const SpotifyWebApi = require('./spotify-web-api')
|
||||
const ServerMethods = require('./server-methods')
|
||||
SpotifyWebApi._addMethods(ServerMethods)
|
||||
module.exports = SpotifyWebApi
|
||||
1661
spotify-web-api-node/src/spotify-web-api.js
Normal file
1661
spotify-web-api-node/src/spotify-web-api.js
Normal file
File diff suppressed because it is too large
Load Diff
15
spotify-web-api-node/src/webapi-request.js
Normal file
15
spotify-web-api-node/src/webapi-request.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
const Request = require('./base-request')
|
||||
|
||||
const DEFAULT_HOST = 'api.spotify.com'
|
||||
const DEFAULT_PORT = 443
|
||||
const DEFAULT_SCHEME = 'https'
|
||||
|
||||
module.exports.builder = function (accessToken) {
|
||||
return Request.builder()
|
||||
.withHost(DEFAULT_HOST)
|
||||
.withPort(DEFAULT_PORT)
|
||||
.withScheme(DEFAULT_SCHEME)
|
||||
.withAuth(accessToken)
|
||||
}
|
||||
Reference in New Issue
Block a user