• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Zaptyp / spotify-web-api-node / 14459668359

15 Apr 2025 02:05AM UTC coverage: 95.264%. Remained the same
14459668359

Pull #16

travis-ci

web-flow
Bump actions/setup-node from 4.3.0 to 4.4.0

Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4.3.0...v4.4.0)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #16: Bump actions/setup-node from 4.3.0 to 4.4.0

170 of 185 branches covered (91.89%)

Branch coverage included in aggregate %.

353 of 364 relevant lines covered (96.98%)

70.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.76
/src/spotify-web-api.js
1
'use strict';
2

3
var AuthenticationRequest = require('./authentication-request'),
2✔
4
  WebApiRequest = require('./webapi-request'),
2✔
5
  HttpManager = require('./http-manager');
2✔
6

7
function SpotifyWebApi(credentials) {
8
  this._credentials = credentials || {};
274✔
9
}
10

11
SpotifyWebApi.prototype = {
2✔
12
  setCredentials: function (credentials) {
13
    for (var key in credentials) {
2✔
14
      if (credentials.hasOwnProperty(key)) {
10!
15
        this._credentials[key] = credentials[key];
10✔
16
      }
17
    }
18
  },
19

20
  getCredentials: function () {
21
    return this._credentials;
10✔
22
  },
23

24
  resetCredentials: function () {
25
    this._credentials = null;
2✔
26
  },
27

28
  setClientId: function (clientId) {
29
    this._setCredential('clientId', clientId);
2✔
30
  },
31

32
  setClientSecret: function (clientSecret) {
33
    this._setCredential('clientSecret', clientSecret);
2✔
34
  },
35

36
  setAccessToken: function (accessToken) {
37
    this._setCredential('accessToken', accessToken);
38✔
38
  },
39

40
  setRefreshToken: function (refreshToken) {
41
    this._setCredential('refreshToken', refreshToken);
2✔
42
  },
43

44
  setRedirectURI: function (redirectUri) {
45
    this._setCredential('redirectUri', redirectUri);
2✔
46
  },
47

48
  getRedirectURI: function () {
49
    return this._getCredential('redirectUri');
18✔
50
  },
51

52
  getClientId: function () {
53
    return this._getCredential('clientId');
22✔
54
  },
55

56
  getClientSecret: function () {
57
    return this._getCredential('clientSecret');
16✔
58
  },
59

60
  getAccessToken: function () {
61
    return this._getCredential('accessToken');
262✔
62
  },
63

64
  getRefreshToken: function () {
65
    return this._getCredential('refreshToken');
12✔
66
  },
67

68
  resetClientId: function () {
69
    this._resetCredential('clientId');
2✔
70
  },
71

72
  resetClientSecret: function () {
73
    this._resetCredential('clientSecret');
2✔
74
  },
75

76
  resetAccessToken: function () {
77
    this._resetCredential('accessToken');
2✔
78
  },
79

80
  resetRefreshToken: function () {
81
    this._resetCredential('refreshToken');
2✔
82
  },
83

84
  resetRedirectURI: function () {
85
    this._resetCredential('redirectUri');
2✔
86
  },
87

88
  _setCredential: function (credentialKey, value) {
89
    this._credentials = this._credentials || {};
46!
90
    this._credentials[credentialKey] = value;
46✔
91
  },
92

93
  _getCredential: function (credentialKey) {
94
    if (!this._credentials) {
330✔
95
      return;
2✔
96
    } else {
97
      return this._credentials[credentialKey];
328✔
98
    }
99
  },
100

101
  _resetCredential: function (credentialKey) {
102
    if (!this._credentials) {
10!
103
      return;
×
104
    } else {
105
      this._credentials[credentialKey] = null;
10✔
106
    }
107
  },
108

109
  /**
110
   * Returns an object containing the playlist cover image.
111
   * @param {string} playlistId The ID of the associated playlist. 
112
   * @param {requestCallback} callback Optional callback method to be called instead of the promise. 
113
   * @returns {Promise|undefined} A promise that, if successful, returns an object containing the 
114
   *          Playlist Cover image alongside its dimensions 
115
  */
116
   getPlaylistCoverImage: function(playlistId, callback) {
117
    return WebApiRequest.builder(this.getAccessToken())
2✔
118
    .withPath("/v1/playlists/" + playlistId + "/images")
119
    .withHeaders({"Content-Type": 'application/json'})
120
    .build()
121
    .execute(HttpManager.get, callback);
122
  },
123
  
124

125
 /**
126
   * Adds an item to the users playback queue. 
127
   * @param {string} uri The URI of the song you wish to add. 
128
   * @param {requestCallback} callback Optional callback method to be called instead of the promise. 
129
   * @returns {Promise|undefined} A promise that, if successful, returns a 204 response and adds
130
   *          the associated song to the user's playback queue
131
  */
132
  addToPlaybackQueue: function(uri, callback) {
133
    var baseUrl = "/v1/me"
2✔
134
    var path = "/player/queue"
2✔
135
    return WebApiRequest.builder(this.getAccessToken())
2✔
136
      .withPath(baseUrl + path)
137
      .withQueryParameters({ uri: JSON.stringify(uri) })
138
      .build()
139
      .execute(HttpManager.post, callback);
140
  },
141

142
 /**
143
   * Gets the available markets  
144
   * @param {requestCallback} callback Optional callback method to be called instead of the promise. 
145
   * @returns {Promise|undefined} A promise that, if successful, returns an array of objects containing
146
   *          Country abbreviations 
147
  */
148
  getAvailableMarkets: function(callback) {
149
    var path = "/v1/markets"
2✔
150
    return WebApiRequest.builder(this.getAccessToken())
2✔
151
      .withPath(path)
152
      .withHeaders({ 'Content-Type': 'application/json' })
153
      .build()
154
      .execute(HttpManager.get, callback);  
155
  },
156

157
  /**
158
   * Look up a track.
159
   * @param {string} trackId The track's ID.
160
   * @param {Object} [options] The possible options, currently only market.
161
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
162
   * @example getTrack('3Qm86XLflmIXVm1wcwkgDK').then(...)
163
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
164
   *          about the track. Not returned if a callback is given.
165
   */
166
  getTrack: function (trackId, options, callback) {
167
    return WebApiRequest.builder(this.getAccessToken())
10✔
168
      .withPath('/v1/tracks/' + trackId)
169
      .withQueryParameters(options)
170
      .build()
171
      .execute(HttpManager.get, callback);
172
  },
173

174
  /**
175
   * Look up several tracks.
176
   * @param {string[]} trackIds The IDs of the artists.
177
   * @param {Object} [options] The possible options, currently only market.
178
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
179
   * @example getArtists(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...)
180
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
181
   *          about the artists. Not returned if a callback is given.
182
   */
183
  getTracks: function (trackIds, options, callback) {
184
    return WebApiRequest.builder(this.getAccessToken())
2✔
185
      .withPath('/v1/tracks')
186
      .withQueryParameters(
187
        {
188
          ids: trackIds.join(',')
189
        },
190
        options
191
      )
192
      .build()
193
      .execute(HttpManager.get, callback);
194
  },
195

196
  /**
197
   * Look up an album.
198
   * @param {string} albumId The album's ID.
199
   * @param {Object} [options] The possible options, currently only market.
200
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
201
   * @example getAlbum('0sNOF9WDwhWunNAHPD3Baj').then(...)
202
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
203
   *          about the album. Not returned if a callback is given.
204
   */
205
  getAlbum: function (albumId, options, callback) {
206
    return WebApiRequest.builder(this.getAccessToken())
6✔
207
      .withPath('/v1/albums/' + albumId)
208
      .withQueryParameters(options)
209
      .build()
210
      .execute(HttpManager.get, callback);
211
  },
212

213
  /**
214
   * Look up several albums.
215
   * @param {string[]} albumIds The IDs of the albums.
216
   * @param {Object} [options] The possible options, currently only market.
217
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
218
   * @example getAlbums(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...)
219
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
220
   *          about the albums. Not returned if a callback is given.
221
   */
222
  getAlbums: function (albumIds, options, callback) {
223
    return WebApiRequest.builder(this.getAccessToken())
4✔
224
      .withPath('/v1/albums')
225
      .withQueryParameters(
226
        {
227
          ids: albumIds.join(',')
228
        },
229
        options
230
      )
231
      .build()
232
      .execute(HttpManager.get, callback);
233
  },
234

235
  /**
236
   * Look up an artist.
237
   * @param {string} artistId The artist's ID.
238
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
239
   * @example api.getArtist('1u7kkVrr14iBvrpYnZILJR').then(...)
240
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
241
   *          about the artist. Not returned if a callback is given.
242
   */
243
  getArtist: function (artistId, callback) {
244
    return WebApiRequest.builder(this.getAccessToken())
4✔
245
      .withPath('/v1/artists/' + artistId)
246
      .build()
247
      .execute(HttpManager.get, callback);
248
  },
249

250
  /**
251
   * Look up several artists.
252
   * @param {string[]} artistIds The IDs of the artists.
253
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
254
   * @example getArtists(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...)
255
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
256
   *          about the artists. Not returned if a callback is given.
257
   */
258
  getArtists: function (artistIds, callback) {
259
    return WebApiRequest.builder(this.getAccessToken())
4✔
260
      .withPath('/v1/artists')
261
      .withQueryParameters({
262
        ids: artistIds.join(',')
263
      })
264
      .build()
265
      .execute(HttpManager.get, callback);
266
  },
267

268
  /**
269
   * Search for music entities of certain types.
270
   * @param {string} query The search query.
271
   * @param {string[]} types An array of item types to search across.
272
   * Valid types are: 'album', 'artist', 'playlist', 'track', 'show', and 'episode'.
273
   * @param {Object} [options] The possible options, e.g. limit, offset.
274
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
275
   * @example search('Abba', ['track', 'playlist'], { limit : 5, offset : 1 }).then(...)
276
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
277
   *          search results. The result is paginated. If the promise is rejected,
278
   *          it contains an error object. Not returned if a callback is given.
279
   */
280
  search: function (query, types, options, callback) {
281
    return WebApiRequest.builder(this.getAccessToken())
20✔
282
      .withPath('/v1/search/')
283
      .withQueryParameters(
284
        {
285
          type: types.join(','),
286
          q: query
287
        },
288
        options
289
      )
290
      .build()
291
      .execute(HttpManager.get, callback);
292
  },
293

294
  /**
295
   * Search for an album.
296
   * @param {string} query The search query.
297
   * @param {Object} [options] The possible options, e.g. limit, offset.
298
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
299
   * @example searchAlbums('Space Oddity', { limit : 5, offset : 1 }).then(...)
300
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
301
   *          search results. The result is paginated. If the promise is rejected,
302
   *          it contains an error object. Not returned if a callback is given.
303
   */
304
  searchAlbums: function (query, options, callback) {
305
    return this.search(query, ['album'], options, callback);
4✔
306
  },
307

308
  /**
309
   * Search for an artist.
310
   * @param {string} query The search query.
311
   * @param {Object} [options] The possible options, e.g. limit, offset.
312
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
313
   * @example searchArtists('David Bowie', { limit : 5, offset : 1 }).then(...)
314
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
315
   *          search results. The result is paginated. If the promise is rejected,
316
   *          it contains an error object. Not returned if a callback is given.
317
   */
318
  searchArtists: function (query, options, callback) {
319
    return this.search(query, ['artist'], options, callback);
4✔
320
  },
321

322
  /**
323
   * Search for a track.
324
   * @param {string} query The search query.
325
   * @param {Object} [options] The possible options, e.g. limit, offset.
326
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
327
   * @example searchTracks('Mr. Brightside', { limit : 3, offset : 2 }).then(...)
328
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
329
   *          search results. The result is paginated. If the promise is rejected,
330
   *          it contains an error object. Not returned if a callback is given.
331
   */
332
  searchTracks: function (query, options, callback) {
333
    return this.search(query, ['track'], options, callback);
4✔
334
  },
335

336
  /**
337
   * Search for playlists.
338
   * @param {string} query The search query.
339
   * @param {Object} options The possible options.
340
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
341
   * @example searchPlaylists('workout', { limit : 1, offset : 0 }).then(...)
342
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
343
   *          search results. The result is paginated. If the promise is rejected,
344
   *          it contains an error object. Not returned if a callback is given.
345
   */
346
  searchPlaylists: function (query, options, callback) {
347
    return this.search(query, ['playlist'], options, callback);
2✔
348
  },
349

350
  /**
351
   * Get an artist's albums.
352
   * @param {string} artistId The artist's ID.
353
   * @options {Object} [options] The possible options, e.g. limit, offset.
354
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
355
   * @example getArtistAlbums('0oSGxfWSnnOXhD2fKuz2Gy', { album_type : 'album', country : 'GB', limit : 2, offset : 5 }).then(...)
356
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the albums
357
   *          for the given artist. The result is paginated. If the promise is rejected,
358
   *          it contains an error object. Not returned if a callback is given.
359
   */
360
  getArtistAlbums: function (artistId, options, callback) {
361
    return WebApiRequest.builder(this.getAccessToken())
4✔
362
      .withPath('/v1/artists/' + artistId + '/albums')
363
      .withQueryParameters(options)
364
      .build()
365
      .execute(HttpManager.get, callback);
366
  },
367

368
  /**
369
   * Get the tracks of an album.
370
   * @param albumId the album's ID.
371
   * @options {Object} [options] The possible options, e.g. limit.
372
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
373
   * @example getAlbumTracks('41MnTivkwTO3UUJ8DrqEJJ', { limit : 5, offset : 1 }).then(...)
374
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
375
   *                    tracks in the album. The result is paginated. If the promise is rejected.
376
   *                    it contains an error object. Not returned if a callback is given.
377
   */
378
  getAlbumTracks: function (albumId, options, callback) {
379
    return WebApiRequest.builder(this.getAccessToken())
4✔
380
      .withPath('/v1/albums/' + albumId + '/tracks')
381
      .withQueryParameters(options)
382
      .build()
383
      .execute(HttpManager.get, callback);
384
  },
385

386
  /**
387
   * Get an artist's top tracks.
388
   * @param {string} artistId The artist's ID.
389
   * @param {string} country The country/territory where the tracks are most popular. (format: ISO 3166-1 alpha-2)
390
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
391
   * @example getArtistTopTracks('0oSGxfWSnnOXhD2fKuz2Gy', 'GB').then(...)
392
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
393
   *          artist's top tracks in the given country. If the promise is rejected,
394
   *          it contains an error object. Not returned if a callback is given.
395
   */
396
  getArtistTopTracks: function (artistId, country, callback) {
397
    return WebApiRequest.builder(this.getAccessToken())
4✔
398
      .withPath('/v1/artists/' + artistId + '/top-tracks')
399
      .withQueryParameters({
400
        country: country
401
      })
402
      .build()
403
      .execute(HttpManager.get, callback);
404
  },
405

406
  /**
407
   * Get related artists.
408
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
409
   * @param {string} artistId The artist's ID.
410
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
411
   * @example getArtistRelatedArtists('0oSGxfWSnnOXhD2fKuz2Gy').then(...)
412
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
413
   *          related artists. If the promise is rejected, it contains an error object. Not returned if a callback is given.
414
   */
415
  getArtistRelatedArtists: function (artistId, callback) {
416
    console.warn(
4✔
417
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
418
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
419
    );
420
    
421
    return WebApiRequest.builder(this.getAccessToken())
4✔
422
      .withPath('/v1/artists/' + artistId + '/related-artists')
423
      .build()
424
      .execute(HttpManager.get, callback);
425
  },
426

427
  /**
428
   * Get information about a user.
429
   * @param userId The user ID.
430
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
431
   * @example getUser('thelinmichael').then(...)
432
   * @returns {Promise|undefined} A promise that if successful, resolves to an object
433
   *          containing information about the user. If the promise is
434
   *          rejected, it contains an error object. Not returned if a callback is given.
435
   */
436
  getUser: function (userId, callback) {
437
    return WebApiRequest.builder(this.getAccessToken())
6✔
438
      .withPath('/v1/users/' + encodeURIComponent(userId))
439
      .build()
440
      .execute(HttpManager.get, callback);
441
  },
442

443
  /**
444
   * Get information about the user that has signed in (the current user).
445
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
446
   * @example getMe().then(...)
447
   * @returns {Promise|undefined} A promise that if successful, resolves to an object
448
   *          containing information about the user. The amount of information
449
   *          depends on the permissions given by the user. If the promise is
450
   *          rejected, it contains an error object. Not returned if a callback is given.
451
   */
452
  getMe: function (callback) {
453
    return WebApiRequest.builder(this.getAccessToken())
4✔
454
      .withPath('/v1/me')
455
      .build()
456
      .execute(HttpManager.get, callback);
457
  },
458

459
  /**
460
   * Get a user's playlists.
461
   * @param {string} userId An optional id of the user. If you know the Spotify URI it is easy
462
   * to find the id (e.g. spotify:user:<here_is_the_id>). If not provided, the id of the user that granted
463
   * the permissions will be used.
464
   * @param {Object} [options] The options supplied to this request.
465
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
466
   * @example getUserPlaylists('thelinmichael').then(...)
467
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing
468
   *          a list of playlists. If rejected, it contains an error object. Not returned if a callback is given.
469
   */
470
  getUserPlaylists: function (userId, options, callback) {
471
    var path;
472
    if (typeof userId === 'string') {
6✔
473
      path = '/v1/users/' + encodeURIComponent(userId) + '/playlists';
2✔
474
    } else if (typeof userId === 'object') {
4✔
475
      callback = options;
2✔
476
      options = userId;
2✔
477
      path = '/v1/me/playlists';
2✔
478
    } /* undefined */ else {
479
      path = '/v1/me/playlists';
2✔
480
    }
481

482
    return WebApiRequest.builder(this.getAccessToken())
6✔
483
      .withPath(path)
484
      .withQueryParameters(options)
485
      .build()
486
      .execute(HttpManager.get, callback);
487
  },
488

489
  /**
490
   * Get a playlist.
491
   * @param {string} playlistId The playlist's ID.
492
   * @param {Object} [options] The options supplied to this request.
493
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
494
   * @example getPlaylist('3EsfV6XzCHU8SPNdbnFogK').then(...)
495
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing
496
   *          the playlist. If rejected, it contains an error object. Not returned if a callback is given.
497
   */
498
  getPlaylist: function (playlistId, options, callback) {
499
    return WebApiRequest.builder(this.getAccessToken())
2✔
500
      .withPath('/v1/playlists/' + playlistId)
501
      .withQueryParameters(options)
502
      .build()
503
      .execute(HttpManager.get, callback);
504
  },
505

506
  /**
507
   * Get tracks in a playlist.
508
   * @param {string} playlistId The playlist's ID.
509
   * @param {Object} [options] Optional options, such as fields.
510
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
511
   * @example getPlaylistTracks('3ktAYNcRHpazJ9qecm3ptn').then(...)
512
   * @returns {Promise|undefined} A promise that if successful, resolves to an object that containing
513
   * the tracks in the playlist. If rejected, it contains an error object. Not returned if a callback is given.
514
   */
515
  getPlaylistTracks: function (playlistId, options, callback) {
516
    return WebApiRequest.builder(this.getAccessToken())
2✔
517
      .withPath('/v1/playlists/' + playlistId + '/tracks')
518
      .withQueryParameters(options)
519
      .build()
520
      .execute(HttpManager.get, callback);
521
  },
522

523
  /**
524
   * Create a playlist.
525
   * @param {string} [name] The name of the playlist.
526
   * @param {Object} [options] The possible options, being description, collaborative and public.
527
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
528
   * @example createPlaylist('My playlist', {''description': 'My description', 'collaborative' : false, 'public': true}).then(...)
529
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing information about the
530
   *          created playlist. If rejected, it contains an error object. Not returned if a callback is given.
531
   */
532
  createPlaylist: function (name, options, callback) {
533
    return WebApiRequest.builder(this.getAccessToken())
4✔
534
      .withPath('/v1/me/playlists')
535
      .withHeaders({ 'Content-Type': 'application/json' })
536
      .withBodyParameters(
537
        {
538
          name: name
539
        },
540
        options
541
      )
542
      .build()
543
      .execute(HttpManager.post, callback);
544
  },
545

546
  /**
547
   * Follow a playlist.
548
   * @param {string} playlistId The playlist's ID
549
   * @param {Object} [options] The possible options, currently only public.
550
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
551
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
552
   * it contains an error object. Not returned if a callback is given.
553
   */
554
  followPlaylist: function (playlistId, options, callback) {
555
    return WebApiRequest.builder(this.getAccessToken())
2✔
556
      .withPath('/v1/playlists/' + playlistId + '/followers')
557
      .withHeaders({ 'Content-Type': 'application/json' })
558
      .withBodyParameters(options)
559
      .build()
560
      .execute(HttpManager.put, callback);
561
  },
562

563
  /**
564
   * Unfollow a playlist.
565
   * @param {string} playlistId The playlist's ID
566
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
567
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
568
   * it contains an error object. Not returned if a callback is given.
569
   */
570
  unfollowPlaylist: function (playlistId, callback) {
571
    return WebApiRequest.builder(this.getAccessToken())
2✔
572
      .withPath('/v1/playlists/' + playlistId + '/followers')
573
      .build()
574
      .execute(HttpManager.del, callback);
575
  },
576

577
  /**
578
   * Change playlist details.
579
   * @param {string} playlistId The playlist's ID
580
   * @param {Object} [options] The possible options, e.g. name, public.
581
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
582
   * @example changePlaylistDetails('3EsfV6XzCHU8SPNdbnFogK', {name: 'New name', public: true}).then(...)
583
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
584
   * it contains an error object. Not returned if a callback is given.
585
   */
586
  changePlaylistDetails: function (playlistId, options, callback) {
587
    return WebApiRequest.builder(this.getAccessToken())
2✔
588
      .withPath('/v1/playlists/' + playlistId)
589
      .withHeaders({ 'Content-Type': 'application/json' })
590
      .withBodyParameters(options)
591
      .build()
592
      .execute(HttpManager.put, callback);
593
  },
594

595
  /**
596
   * Replace the image used to represent a specific playlist.
597
   * @param {string} playlistId The playlist's ID
598
   * @param {string} base64URI Base64 encoded JPEG image data, maximum payload size is 256 KB
599
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
600
   * @example uploadCustomPlaylistCoverImage('3EsfV6XzCHU8SPNdbnFogK', 'longbase64uri').then(...)
601
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
602
   * it contains an error object. Not returned if a callback is given.
603
   */
604
  uploadCustomPlaylistCoverImage: function (playlistId, base64URI, callback) {
605
    return WebApiRequest.builder(this.getAccessToken())
2✔
606
      .withPath('/v1/playlists/' + playlistId + '/images')
607
      .withHeaders({ 'Content-Type': 'image/jpeg' })
608
      .withBodyParameters(base64URI)
609
      .build()
610
      .execute(HttpManager.put, callback);
611
  },
612

613
  /**
614
     * Add tracks to a playlist.
615
     * @param {string} playlistId The playlist's ID
616
     * @param {string[]} tracks URIs of the tracks to add to the playlist.
617
     * @param {Object} [options] Options, position being the only one.
618
     * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
619
     * @example addTracksToPlaylist('3EsfV6XzCHU8SPNdbnFogK',
620
                '["spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "spotify:track:1301WleyT98MSxVHPZCA6M"]').then(...)
621
     * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected,
622
     * it contains an error object. Not returned if a callback is given.
623
     */
624
  addTracksToPlaylist: function (playlistId, tracks, options, callback) {
625
    return WebApiRequest.builder(this.getAccessToken())
8✔
626
      .withPath('/v1/playlists/' + playlistId + '/tracks')
627
      .withHeaders({ 'Content-Type': 'application/json' })
628
      .withQueryParameters(options)
629
      .withBodyParameters({
630
        uris: tracks
631
      })
632
      .build()
633
      .execute(HttpManager.post, callback);
634
  },
635

636
  /**
637
   * Remove tracks from a playlist.
638
   * @param {string} playlistId The playlist's ID
639
   * @param {Object[]} tracks An array of objects containing a property called uri with the track URI (String), and
640
   * an optional property called positions (int[]), e.g. { uri : "spotify:track:491rM2JN8KvmV6p0oDDuJT", positions : [0, 15] }
641
   * @param {Object} options Options, snapshot_id being the only one.
642
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
643
   * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected,
644
   * it contains an error object. Not returned if a callback is given.
645
   */
646
  removeTracksFromPlaylist: function (playlistId, tracks, options, callback) {
647
    return WebApiRequest.builder(this.getAccessToken())
2✔
648
      .withPath('/v1/playlists/' + playlistId + '/tracks')
649
      .withHeaders({ 'Content-Type': 'application/json' })
650
      .withBodyParameters(
651
        {
652
          tracks: tracks
653
        },
654
        options
655
      )
656
      .build()
657
      .execute(HttpManager.del, callback);
658
  },
659

660
  /**
661
   * Remove tracks from a playlist by position instead of specifying the tracks' URIs.
662
   * @param {string} playlistId The playlist's ID
663
   * @param {int[]} positions The positions of the tracks in the playlist that should be removed
664
   * @param {string} snapshot_id The snapshot ID, or version, of the playlist. Required
665
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
666
   * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected,
667
   * it contains an error object. Not returned if a callback is given.
668
   */
669
  removeTracksFromPlaylistByPosition: function (
670
    playlistId,
671
    positions,
672
    snapshotId,
673
    callback
674
  ) {
675
    return WebApiRequest.builder(this.getAccessToken())
2✔
676
      .withPath('/v1/playlists/' + playlistId + '/tracks')
677
      .withHeaders({ 'Content-Type': 'application/json' })
678
      .withBodyParameters({
679
        positions: positions,
680
        snapshot_id: snapshotId
681
      })
682
      .build()
683
      .execute(HttpManager.del, callback);
684
  },
685

686
  /**
687
   * Replace tracks in a playlist.
688
   * @param {string} playlistId The playlist's ID
689
   * @param {Object[]} uris An array of track URIs (strings)
690
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
691
   * @returns {Promise|undefined} A promise that if successful returns an empty object. If rejected,
692
   * it contains an error object. Not returned if a callback is given.
693
   */
694
  replaceTracksInPlaylist: function (playlistId, uris, callback) {
695
    return WebApiRequest.builder(this.getAccessToken())
2✔
696
      .withPath('/v1/playlists/' + playlistId + '/tracks')
697
      .withHeaders({ 'Content-Type': 'application/json' })
698
      .withBodyParameters({
699
        uris: uris
700
      })
701
      .build()
702
      .execute(HttpManager.put, callback);
703
  },
704

705
  /**
706
   * Reorder tracks in a playlist.
707
   * @param {string} playlistId The playlist's ID
708
   * @param {int} rangeStart The position of the first track to be reordered.
709
   * @param {int} insertBefore The position where the tracks should be inserted.
710
   * @param {Object} options Optional parameters, i.e. range_length and snapshot_id.
711
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
712
   * @returns {Promise|undefined} A promise that if successful returns an object containing a snapshot_id. If rejected,
713
   * it contains an error object. Not returned if a callback is given.
714
   */
715
  reorderTracksInPlaylist: function (
716
    playlistId,
717
    rangeStart,
718
    insertBefore,
719
    options,
720
    callback
721
  ) {
722
    return WebApiRequest.builder(this.getAccessToken())
2✔
723
      .withPath('/v1/playlists/' + playlistId + '/tracks')
724
      .withHeaders({ 'Content-Type': 'application/json' })
725
      .withBodyParameters(
726
        {
727
          range_start: rangeStart,
728
          insert_before: insertBefore
729
        },
730
        options
731
      )
732
      .build()
733
      .execute(HttpManager.put, callback);
734
  },
735

736
  /**
737
   * Get audio features for a single track identified by its unique Spotify ID.
738
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
739
   * @param {string} trackId The track ID
740
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
741
   * @example getAudioFeaturesForTrack('38P3Q4QcdjQALGF2Z92BmR').then(...)
742
   * @returns {Promise|undefined} A promise that if successful, resolves to an object
743
   *          containing information about the audio features. If the promise is
744
   *          rejected, it contains an error object. Not returned if a callback is given.
745
   */
746
  getAudioFeaturesForTrack: function (trackId, callback) {
747
    console.warn(
2✔
748
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
749
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
750
    );
751
    
752
    return WebApiRequest.builder(this.getAccessToken())
2✔
753
      .withPath('/v1/audio-features/' + trackId)
754
      .build()
755
      .execute(HttpManager.get, callback);
756
  },
757

758
  /**
759
   * Get audio analysis for a single track identified by its unique Spotify ID.
760
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
761
   * @param {string} trackId The track ID
762
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
763
   * @example getAudioAnalysisForTrack('38P3Q4QcdjQALGF2Z92BmR').then(...)
764
   * @returns {Promise|undefined} A promise that if successful, resolves to an object
765
   *          containing information about the audio analysis. If the promise is
766
   *          rejected, it contains an error object. Not returned if a callback is given.
767
   */
768
  getAudioAnalysisForTrack: function (trackId, callback) {
769
    console.warn(
2✔
770
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
771
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
772
    );
773
    
774
    return WebApiRequest.builder(this.getAccessToken())
2✔
775
      .withPath('/v1/audio-analysis/' + trackId)
776
      .build()
777
      .execute(HttpManager.get, callback);
778
  },
779

780
  /**
781
   * Get audio features for multiple tracks identified by their unique Spotify ID.
782
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
783
   * @param {string[]} trackIds The track IDs
784
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
785
   * @example getAudioFeaturesForTracks(['38P3Q4QcdjQALGF2Z92BmR', '2HO2bnoMrpnZUbUqiilLHi']).then(...)
786
   * @returns {Promise|undefined} A promise that if successful, resolves to an object
787
   *          containing information about the audio features for the tracks. If the promise is
788
   *          rejected, it contains an error object. Not returned if a callback is given.
789
   */
790
  getAudioFeaturesForTracks: function (trackIds, callback) {
791
    console.warn(
2✔
792
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
793
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
794
    );
795
    
796
    return WebApiRequest.builder(this.getAccessToken())
2✔
797
      .withPath('/v1/audio-features')
798
      .withQueryParameters({
799
        ids: trackIds.join(',')
800
      })
801
      .build()
802
      .execute(HttpManager.get, callback);
803
  },
804

805
  /**
806
   * Create a playlist-style listening experience based on seed artists, tracks and genres.
807
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
808
   * @param {Object} [options] The options supplied to this request.
809
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
810
   * @example getRecommendations({ min_energy: 0.4, seed_artists: ['6mfK6Q2tzLMEchAr0e9Uzu', '4DYFVNKZ1uixa6SQTvzQwJ'], min_popularity: 50 }).then(...)
811
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing
812
   *          a list of tracks and a list of seeds. If rejected, it contains an error object. Not returned if a callback is given.
813
   */
814
  getRecommendations: function (options, callback) {
815
    console.warn(
4✔
816
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
817
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
818
    );
819
    
820
    var _opts = {};
4✔
821
    var optionsOfTypeArray = ['seed_artists', 'seed_genres', 'seed_tracks'];
4✔
822
    for (var option in options) {
4✔
823
      if (options.hasOwnProperty(option)) {
20!
824
        if (
20✔
825
          optionsOfTypeArray.indexOf(option) !== -1 &&
12✔
826
          Object.prototype.toString.call(options[option]) === '[object Array]'
827
        ) {
828
          _opts[option] = options[option].join(',');
2✔
829
        } else {
830
          _opts[option] = options[option];
18✔
831
        }
832
      }
833
    }
834

835
    return WebApiRequest.builder(this.getAccessToken())
4✔
836
      .withPath('/v1/recommendations')
837
      .withQueryParameters(_opts)
838
      .build()
839
      .execute(HttpManager.get, callback);
840
  },
841

842
  /**
843
   * Retrieve a list of available genres seed parameter values for recommendations.
844
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
845
   * @example getAvailableGenreSeeds().then(...)
846
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing
847
   *          a list of available genres to be used as seeds for recommendations.
848
   *          If rejected, it contains an error object. Not returned if a callback is given.
849
   */
850
  getAvailableGenreSeeds: function (callback) {
851
    return WebApiRequest.builder(this.getAccessToken())
2✔
852
      .withPath('/v1/recommendations/available-genre-seeds')
853
      .build()
854
      .execute(HttpManager.get, callback);
855
  },
856

857
  /**
858
   * Retrieve the tracks that are saved to the authenticated users Your Music library.
859
   * @param {Object} [options] Options, being market, limit, and/or offset.
860
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
861
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which in turn contains
862
   *          playlist track objects. Not returned if a callback is given.
863
   */
864
  getMySavedTracks: function (options, callback) {
865
    return WebApiRequest.builder(this.getAccessToken())
2✔
866
      .withPath('/v1/me/tracks')
867
      .withQueryParameters(options)
868
      .build()
869
      .execute(HttpManager.get, callback);
870
  },
871

872
  /**
873
   * Check if one or more tracks is already saved in the current Spotify user’s “Your Music” library.
874
   * @param {string[]} trackIds The track IDs
875
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
876
   * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order
877
   * of the returned array's elements correspond to the track ID in the request.
878
   * The boolean value of true indicates that the track is part of the user's library, otherwise false.
879
   * Not returned if a callback is given.
880
   */
881
  containsMySavedTracks: function (trackIds, callback) {
882
    return WebApiRequest.builder(this.getAccessToken())
2✔
883
      .withPath('/v1/me/tracks/contains')
884
      .withQueryParameters({
885
        ids: trackIds.join(',')
886
      })
887
      .build()
888
      .execute(HttpManager.get, callback);
889
  },
890

891
  /**
892
   * Remove a track from the authenticated user's Your Music library.
893
   * @param {string[]} trackIds The track IDs
894
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
895
   * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error.
896
   * Not returned if a callback is given.
897
   */
898
  removeFromMySavedTracks: function (trackIds, callback) {
899
    return WebApiRequest.builder(this.getAccessToken())
2✔
900
      .withPath('/v1/me/tracks')
901
      .withHeaders({ 'Content-Type': 'application/json' })
902
      .withBodyParameters({ ids: trackIds })
903
      .build()
904
      .execute(HttpManager.del, callback);
905
  },
906

907
  /**
908
   * Add a track from the authenticated user's Your Music library.
909
   * @param {string[]} trackIds The track IDs
910
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
911
   * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. Not returned if a callback is given.
912
   */
913
  addToMySavedTracks: function (trackIds, callback) {
914
    return WebApiRequest.builder(this.getAccessToken())
4✔
915
      .withPath('/v1/me/tracks')
916
      .withHeaders({ 'Content-Type': 'application/json' })
917
      .withBodyParameters({ ids: trackIds })
918
      .build()
919
      .execute(HttpManager.put, callback);
920
  },
921

922
  /**
923
   * Remove an album from the authenticated user's Your Music library.
924
   * @param {string[]} albumIds The album IDs
925
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
926
   * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error.
927
   * Not returned if a callback is given.
928
   */
929
  removeFromMySavedAlbums: function (albumIds, callback) {
930
    return WebApiRequest.builder(this.getAccessToken())
2✔
931
      .withPath('/v1/me/albums')
932
      .withHeaders({ 'Content-Type': 'application/json' })
933
      .withBodyParameters(albumIds)
934
      .build()
935
      .execute(HttpManager.del, callback);
936
  },
937

938
  /**
939
   * Add an album from the authenticated user's Your Music library.
940
   * @param {string[]} albumIds The track IDs
941
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
942
   * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. Not returned if a callback is given.
943
   */
944
  addToMySavedAlbums: function (albumIds, callback) {
945
    return WebApiRequest.builder(this.getAccessToken())
2✔
946
      .withPath('/v1/me/albums')
947
      .withHeaders({ 'Content-Type': 'application/json' })
948
      .withBodyParameters(albumIds)
949
      .build()
950
      .execute(HttpManager.put, callback);
951
  },
952

953
  /**
954
   * Retrieve the albums that are saved to the authenticated users Your Music library.
955
   * @param {Object} [options] Options, being market, limit, and/or offset.
956
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
957
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which in turn contains
958
   *          playlist album objects. Not returned if a callback is given.
959
   */
960
  getMySavedAlbums: function (options, callback) {
961
    return WebApiRequest.builder(this.getAccessToken())
2✔
962
      .withPath('/v1/me/albums')
963
      .withQueryParameters(options)
964
      .build()
965
      .execute(HttpManager.get, callback);
966
  },
967

968
  /**
969
   * Check if one or more albums is already saved in the current Spotify user’s “Your Music” library.
970
   * @param {string[]} albumIds The album IDs
971
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
972
   * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order
973
   * of the returned array's elements correspond to the album ID in the request.
974
   * The boolean value of true indicates that the album is part of the user's library, otherwise false.
975
   * Not returned if a callback is given.
976
   */
977
  containsMySavedAlbums: function (albumIds, callback) {
978
    return WebApiRequest.builder(this.getAccessToken())
2✔
979
      .withPath('/v1/me/albums/contains')
980
      .withQueryParameters({
981
        ids: albumIds.join(',')
982
      })
983
      .build()
984
      .execute(HttpManager.get, callback);
985
  },
986

987
  /**
988
   * Get the current user's top artists based on calculated affinity.
989
   * @param {Object} [options] Options, being time_range, limit, offset.
990
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
991
   * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of artists,
992
   *          otherwise an error. Not returned if a callback is given.
993
   */
994
  getMyTopArtists: function (options, callback) {
995
    return WebApiRequest.builder(this.getAccessToken())
2✔
996
      .withPath('/v1/me/top/artists')
997
      .withQueryParameters(options)
998
      .build()
999
      .execute(HttpManager.get, callback);
1000
  },
1001

1002
  /**
1003
   * Get the current user's top tracks based on calculated affinity.
1004
   * @param {Object} [options] Options, being time_range, limit, offset.
1005
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1006
   * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks,
1007
   *          otherwise an error. Not returned if a callback is given.
1008
   */
1009
  getMyTopTracks: function (options, callback) {
1010
    return WebApiRequest.builder(this.getAccessToken())
2✔
1011
      .withPath('/v1/me/top/tracks')
1012
      .withQueryParameters(options)
1013
      .build()
1014
      .execute(HttpManager.get, callback);
1015
  },
1016

1017
  /**
1018
   * Get the Current User's Recently Played Tracks
1019
   * @param {Object} [options] Options, being type, after, limit, before.
1020
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1021
   * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of play history objects,
1022
   *          otherwise an error. Not returned if a callback is given. Note that the response will be empty
1023
   *          in case the user has enabled private session.
1024
   */
1025
  getMyRecentlyPlayedTracks: function (options, callback) {
1026
    return WebApiRequest.builder(this.getAccessToken())
2✔
1027
      .withPath('/v1/me/player/recently-played')
1028
      .withQueryParameters(options)
1029
      .build()
1030
      .execute(HttpManager.get, callback);
1031
  },
1032

1033
  /**
1034
   * Add track or episode to device queue
1035
   * @param {string} [uri] uri of the track or episode to add
1036
   * @param {Object} [options] Options, being device_id.
1037
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1038
   * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks,
1039
   *          otherwise an error. Not returned if a callback is given.
1040
   */
1041
  addToQueue: function (uri, options, callback) {
1042
    return WebApiRequest.builder(this.getAccessToken())
2✔
1043
      .withPath('/v1/me/player/queue')
1044
      .withQueryParameters(
1045
        {
1046
          uri: uri
1047
        },
1048
        options
1049
      )
1050
      .build()
1051
      .execute(HttpManager.post, callback);
1052
  },
1053

1054

1055

1056

1057
  /** 
1058
   * Get the Current User's Available Devices
1059
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1060
   * @returns {Promise|undefined} A promise that if successful, resolves into an array of device objects,
1061
   *          otherwise an error. Not returned if a callback is given.
1062
   */
1063
  getMyDevices: function (callback) {
1064
    return WebApiRequest.builder(this.getAccessToken())
2✔
1065
      .withPath('/v1/me/player/devices')
1066
      .build()
1067
      .execute(HttpManager.get, callback);
1068
  },
1069

1070
  
1071
  /**
1072
   * Get the Current User's Currently Playing Track.
1073
   * @param {Object} [options] Options, being market.
1074
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1075
   * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks,
1076
   *          otherwise an error. Not returned if a callback is given.
1077
   */
1078
  getMyCurrentPlayingTrack: function (options, callback) {
1079
    return WebApiRequest.builder(this.getAccessToken())
2✔
1080
      .withPath('/v1/me/player/currently-playing')
1081
      .withQueryParameters(options)
1082
      .build()
1083
      .execute(HttpManager.get, callback);
1084
  },
1085

1086
  /**
1087
   * Get Information About The User's Current Playback State
1088
   * @param {Object} [options] Options, being market and additional_types.
1089
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1090
   * @returns {Promise|undefined} A promise that if successful, resolves into a paging object of tracks,
1091
   *          otherwise an error. Not returned if a callback is given.
1092
   */
1093
  getMyCurrentPlaybackState: function (options, callback) {
1094
    return WebApiRequest.builder(this.getAccessToken())
2✔
1095
      .withPath('/v1/me/player')
1096
      .withQueryParameters(options)
1097
      .build()
1098
      .execute(HttpManager.get, callback);
1099
  },
1100

1101
  /**
1102
   * Transfer a User's Playback
1103
   * @param {string[]} [deviceIds] An _array_ containing a device ID on which playback should be started/transferred.
1104
   * (NOTE: The API is currently only supporting a single device ID.)
1105
   * @param {Object} [options] Options, the only one being 'play'.
1106
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1107
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1108
   *          otherwise an error. Not returned if a callback is given.
1109
   */
1110
  transferMyPlayback: function (deviceIds, options, callback) {
1111
    return WebApiRequest.builder(this.getAccessToken())
4✔
1112
      .withPath('/v1/me/player')
1113
      .withHeaders({ 'Content-Type': 'application/json' })
1114
      .withBodyParameters(
1115
        {
1116
          device_ids: deviceIds
1117
        },
1118
        options
1119
      )
1120
      .build()
1121
      .execute(HttpManager.put, callback);
1122
  },
1123

1124
  /**
1125
   * Starts o Resumes the Current User's Playback
1126
   * @param {Object} [options] Options, being device_id, context_uri, offset, uris, position_ms.
1127
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1128
   * @example play({context_uri: 'spotify:album:5ht7ItJgpBH7W6vJ5BqpPr'}).then(...)
1129
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1130
   *          otherwise an error. Not returned if a callback is given.
1131
   */
1132
  play: function (options, callback) {
1133
    /*jshint camelcase: false */
1134
    var _options = options || {};
4✔
1135
    var queryParams = _options.device_id
4✔
1136
      ? { device_id: _options.device_id }
1137
      : null;
1138
    var postData = {};
4✔
1139
    ['context_uri', 'uris', 'offset', 'position_ms'].forEach(function (field) {
4✔
1140
      if (field in _options) {
16✔
1141
        postData[field] = _options[field];
4✔
1142
      }
1143
    });
1144
    return WebApiRequest.builder(this.getAccessToken())
4✔
1145
      .withPath('/v1/me/player/play')
1146
      .withQueryParameters(queryParams)
1147
      .withHeaders({ 'Content-Type': 'application/json' })
1148
      .withBodyParameters(postData)
1149
      .build()
1150
      .execute(HttpManager.put, callback);
1151
  },
1152

1153
  /**
1154
   * Pauses the Current User's Playback
1155
   * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device.
1156
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1157
   * @example pause().then(...)
1158
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1159
   *          otherwise an error. Not returned if a callback is given.
1160
   */
1161
  pause: function (options, callback) {
1162
    return (
4✔
1163
      WebApiRequest.builder(this.getAccessToken())
1164
        .withPath('/v1/me/player/pause')
1165
        /*jshint camelcase: false */
1166
        .withQueryParameters(
1167
          options && options.device_id ? { device_id: options.device_id } : null
5✔
1168
        )
1169
        .withHeaders({ 'Content-Type': 'application/json' })
1170
        .build()
1171
        .execute(HttpManager.put, callback)
1172
    );
1173
  },
1174

1175
  /**
1176
   * Skip the Current User's Playback To Previous Track
1177
   * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device.
1178
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1179
   * @example skipToPrevious().then(...)
1180
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1181
   *          otherwise an error. Not returned if a callback is given.
1182
   */
1183
  skipToPrevious: function (options, callback) {
1184
    return WebApiRequest.builder(this.getAccessToken())
2✔
1185
      .withPath('/v1/me/player/previous')
1186
      .withQueryParameters(
1187
        options && options.device_id ? { device_id: options.device_id } : null
2!
1188
      )
1189
      .build()
1190
      .execute(HttpManager.post, callback);
1191
  },
1192

1193
  /**
1194
   * Skip the Current User's Playback To Next Track
1195
   * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device.
1196
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1197
   * @example skipToNext().then(...)
1198
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1199
   *          otherwise an error. Not returned if a callback is given.
1200
   */
1201
  skipToNext: function (options, callback) {
1202
    return WebApiRequest.builder(this.getAccessToken())
2✔
1203
      .withPath('/v1/me/player/next')
1204
      .withQueryParameters(
1205
        options && options.device_id ? { device_id: options.device_id } : null
2!
1206
      )
1207
      .build()
1208
      .execute(HttpManager.post, callback);
1209
  },
1210

1211
  /**
1212
   * Seeks to the given position in the user’s currently playing track.
1213
   *
1214
   * @param {number} positionMs The position in milliseconds to seek to. Must be a positive number.
1215
   * @param {Object} options Options, being device_id. If left empty will target the user's currently active device.
1216
   * @param {function(Object,Object)} callback An optional callback that receives 2 parameters. The first
1217
   * one is the error object (null if no error), and the second is the value if the request succeeded.
1218
   * @return {Object} Null if a callback is provided, a `Promise` object otherwise
1219
   */
1220
  seek: function (positionMs, options, callback) {
1221
    var params = {
4✔
1222
      /* jshint camelcase: false */
1223
      position_ms: positionMs
1224
    };
1225
    if (options && 'device_id' in options) {
4✔
1226
      /* jshint camelcase: false */
1227
      params.device_id = options.device_id;
2✔
1228
    }
1229
    return WebApiRequest.builder(this.getAccessToken())
4✔
1230
      .withPath('/v1/me/player/seek')
1231
      .withQueryParameters(params)
1232
      .build()
1233
      .execute(HttpManager.put, callback);
1234
  },
1235

1236
  /**
1237
   * Set Repeat Mode On The Current User's Playback
1238
   * @param {string} [state] State (track, context, or off)
1239
   * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device.
1240
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1241
   * @example setRepeat('context', {}).then(...)
1242
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1243
   *          otherwise an error. Not returned if a callback is given.
1244
   */
1245
  setRepeat: function (state, options, callback) {
1246
    var params = {
4✔
1247
      state: state
1248
    };
1249
    if (options && 'device_id' in options) {
4✔
1250
      /* jshint camelcase: false */
1251
      params.device_id = options.device_id;
2✔
1252
    }
1253
    return WebApiRequest.builder(this.getAccessToken())
4✔
1254
      .withPath('/v1/me/player/repeat')
1255
      .withQueryParameters(params)
1256
      .build()
1257
      .execute(HttpManager.put, callback);
1258
  },
1259

1260
  /**
1261
   * Set Shuffle Mode On The Current User's Playback
1262
   * @param {boolean} [state] State
1263
   * @param {Object} [options] Options, being device_id. If left empty will target the user's currently active device.
1264
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1265
   * @example setShuffle({state: 'false'}).then(...)
1266
   * @returns {Promise|undefined} A promise that if successful, resolves into an empty response,
1267
   *          otherwise an error. Not returned if a callback is given.
1268
   */
1269
  setShuffle: function (state, options, callback) {
1270
    var params = {
4✔
1271
      state: state
1272
    };
1273
    if (options && 'device_id' in options) {
4✔
1274
      /* jshint camelcase: false */
1275
      params.device_id = options.device_id;
2✔
1276
    }
1277
    return WebApiRequest.builder(this.getAccessToken())
4✔
1278
      .withPath('/v1/me/player/shuffle')
1279
      .withQueryParameters(params)
1280
      .build()
1281
      .execute(HttpManager.put, callback);
1282
  },
1283

1284
  /**
1285
   * Set the volume for the user’s current playback device.
1286
   * @param {number} volumePercent The volume to set. Must be a value from 0 to 100.
1287
   * @param {Object} options Options, being device_id. If left empty will target the user's currently active device.
1288
   * @param {function(Object,Object)} callback An optional callback that receives 2 parameters. The first
1289
   * one is the error object (null if no error), and the second is the value if the request succeeded.
1290
   * @return {Object} Null if a callback is provided, a `Promise` object otherwise
1291
   */
1292
  setVolume: function (volumePercent, options, callback) {
1293
    var params = {
4✔
1294
      /* jshint camelcase: false */
1295
      volume_percent: volumePercent
1296
    };
1297
    if (options && 'device_id' in options) {
4✔
1298
      /* jshint camelcase: false */
1299
      params.device_id = options.device_id;
2✔
1300
    }
1301
    return WebApiRequest.builder(this.getAccessToken())
4✔
1302
      .withPath('/v1/me/player/volume')
1303
      .withQueryParameters(params)
1304
      .build()
1305
      .execute(HttpManager.put, callback);
1306
  },
1307

1308
  /**
1309
   * Add the current user as a follower of one or more other Spotify users.
1310
   * @param {string[]} userIds The IDs of the users to be followed.
1311
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1312
   * @example followUsers(['thelinmichael', 'wizzler']).then(...)
1313
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
1314
   *          it contains an error object. Not returned if a callback is given.
1315
   */
1316
  followUsers: function (userIds, callback) {
1317
    return WebApiRequest.builder(this.getAccessToken())
4✔
1318
      .withPath('/v1/me/following')
1319
      .withQueryParameters({
1320
        ids: userIds.join(','),
1321
        type: 'user'
1322
      })
1323
      .build()
1324
      .execute(HttpManager.put, callback);
1325
  },
1326

1327
  /**
1328
   * Add the current user as a follower of one or more artists.
1329
   * @param {string[]} artistIds The IDs of the artists to be followed.
1330
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1331
   * @example followArtists(['0LcJLqbBmaGUft1e9Mm8HV', '3gqv1kgivAc92KnUm4elKv']).then(...)
1332
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
1333
   *          it contains an error object. Not returned if a callback is given.
1334
   */
1335
  followArtists: function (artistIds, callback) {
1336
    return WebApiRequest.builder(this.getAccessToken())
4✔
1337
      .withPath('/v1/me/following')
1338
      .withQueryParameters({
1339
        ids: artistIds.join(','),
1340
        type: 'artist'
1341
      })
1342
      .build()
1343
      .execute(HttpManager.put, callback);
1344
  },
1345

1346
  /**
1347
   * Remove the current user as a follower of one or more other Spotify users.
1348
   * @param {string[]} userIds The IDs of the users to be unfollowed.
1349
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1350
   * @example unfollowUsers(['thelinmichael', 'wizzler']).then(...)
1351
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
1352
   *          it contains an error object. Not returned if a callback is given.
1353
   */
1354
  unfollowUsers: function (userIds, callback) {
1355
    return WebApiRequest.builder(this.getAccessToken())
4✔
1356
      .withPath('/v1/me/following')
1357
      .withQueryParameters({
1358
        ids: userIds.join(','),
1359
        type: 'user'
1360
      })
1361
      .build()
1362
      .execute(HttpManager.del, callback);
1363
  },
1364

1365
  /**
1366
   * Remove the current user as a follower of one or more artists.
1367
   * @param {string[]} artistIds The IDs of the artists to be unfollowed.
1368
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1369
   * @example unfollowArtists(['0LcJLqbBmaGUft1e9Mm8HV', '3gqv1kgivAc92KnUm4elKv']).then(...)
1370
   * @returns {Promise|undefined} A promise that if successful, simply resolves to an empty object. If rejected,
1371
   *          it contains an error object. Not returned if a callback is given.
1372
   */
1373
  unfollowArtists: function (artistIds, callback) {
1374
    return WebApiRequest.builder(this.getAccessToken())
4✔
1375
      .withPath('/v1/me/following')
1376
      .withQueryParameters({
1377
        ids: artistIds.join(','),
1378
        type: 'artist'
1379
      })
1380
      .build()
1381
      .execute(HttpManager.del, callback);
1382
  },
1383

1384
  /**
1385
   * Check to see if the current user is following one or more other Spotify users.
1386
   * @param {string[]} userIds The IDs of the users to check if are followed by the current user.
1387
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1388
   * @example isFollowingUsers(['thelinmichael', 'wizzler']).then(...)
1389
   * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order
1390
   *          of the returned array's elements correspond to the users IDs in the request.
1391
   *          The boolean value of true indicates that the user is following that user, otherwise is not.
1392
   *          Not returned if a callback is given.
1393
   */
1394
  isFollowingUsers: function (userIds, callback) {
1395
    return WebApiRequest.builder(this.getAccessToken())
4✔
1396
      .withPath('/v1/me/following/contains')
1397
      .withQueryParameters({
1398
        ids: userIds.join(','),
1399
        type: 'user'
1400
      })
1401
      .build()
1402
      .execute(HttpManager.get, callback);
1403
  },
1404

1405
  /**
1406
   * Get the current user's followed artists.
1407
   * @param {Object} [options] Options, being after and limit.
1408
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1409
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which contains
1410
   * album objects. Not returned if a callback is given.
1411
   */
1412
  getFollowedArtists: function (options, callback) {
1413
    return WebApiRequest.builder(this.getAccessToken())
4✔
1414
      .withPath('/v1/me/following')
1415
      .withQueryParameters(
1416
        {
1417
          type: 'artist'
1418
        },
1419
        options
1420
      )
1421
      .build()
1422
      .execute(HttpManager.get, callback);
1423
  },
1424

1425
  /**
1426
   * Check if users are following a playlist.
1427
   * @param {string} userId The playlist's owner's user ID
1428
   * @param {string} playlistId The playlist's ID
1429
   * @param {String[]} User IDs of the following users
1430
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1431
   * @returns {Promise|undefined} A promise that if successful returns an array of booleans. If rejected,
1432
   * it contains an error object. Not returned if a callback is given.
1433
   */
1434
  areFollowingPlaylist: function (userId, playlistId, followerIds, callback) {
1435
    return WebApiRequest.builder(this.getAccessToken())
2✔
1436
      .withPath(
1437
        '/v1/users/' +
1438
          encodeURIComponent(userId) +
1439
          '/playlists/' +
1440
          playlistId +
1441
          '/followers/contains'
1442
      )
1443
      .withQueryParameters({
1444
        ids: followerIds.join(',')
1445
      })
1446
      .build()
1447
      .execute(HttpManager.get, callback);
1448
  },
1449

1450
  /**
1451
   * Check to see if the current user is following one or more artists.
1452
   * @param {string[]} artistIds The IDs of the artists to check if are followed by the current user.
1453
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1454
   * @example isFollowingArtists(['0LcJLqbBmaGUft1e9Mm8HV', '3gqv1kgivAc92KnUm4elKv']).then(...)
1455
   * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order
1456
   *          of the returned array's elements correspond to the artists IDs in the request.
1457
   *          The boolean value of true indicates that the user is following that artist, otherwise is not.
1458
   *          Not returned if a callback is given.
1459
   */
1460
  isFollowingArtists: function (artistIds, callback) {
1461
    return WebApiRequest.builder(this.getAccessToken())
4✔
1462
      .withPath('/v1/me/following/contains')
1463
      .withQueryParameters({
1464
        ids: artistIds.join(','),
1465
        type: 'artist'
1466
      })
1467
      .build()
1468
      .execute(HttpManager.get, callback);
1469
  },
1470

1471
  /**
1472
   * Retrieve new releases
1473
   * @param {Object} [options] Options, being country, limit and/or offset.
1474
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1475
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which contains
1476
   * album objects. Not returned if a callback is given.
1477
   */
1478
  getNewReleases: function (options, callback) {
1479
    return WebApiRequest.builder(this.getAccessToken())
2✔
1480
      .withPath('/v1/browse/new-releases')
1481
      .withQueryParameters(options)
1482
      .build()
1483
      .execute(HttpManager.get, callback);
1484
  },
1485

1486
  /**
1487
   * Retrieve featured playlists
1488
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
1489
   * @param {Object} [options] Options, being country, locale, timestamp, limit, offset.
1490
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1491
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which contains
1492
   * featured playlists. Not returned if a callback is given.
1493
   */
1494
  getFeaturedPlaylists: function (options, callback) {
1495
    console.warn(
4✔
1496
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
1497
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
1498
    );
1499
    
1500
    return WebApiRequest.builder(this.getAccessToken())
4✔
1501
      .withPath('/v1/browse/featured-playlists')
1502
      .withQueryParameters(options)
1503
      .build()
1504
      .execute(HttpManager.get, callback);
1505
  },
1506

1507
  /**
1508
   * Retrieve a list of categories used to tag items in Spotify (e.g. in the 'Browse' tab)
1509
   * @param {Object} [options] Options, being country, locale, limit, offset.
1510
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1511
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object of categories.
1512
   * Not returned if a callback is given.
1513
   */
1514
  getCategories: function (options, callback) {
1515
    return WebApiRequest.builder(this.getAccessToken())
2✔
1516
      .withPath('/v1/browse/categories')
1517
      .withQueryParameters(options)
1518
      .build()
1519
      .execute(HttpManager.get, callback);
1520
  },
1521

1522
  /**
1523
   * Retrieve a category.
1524
   * @param {string} categoryId The id of the category to retrieve.
1525
   * @param {Object} [options] Options, being country, locale.
1526
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1527
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a category object.
1528
   * Not returned if a callback is given.
1529
   */
1530
  getCategory: function (categoryId, options, callback) {
1531
    return WebApiRequest.builder(this.getAccessToken())
2✔
1532
      .withPath('/v1/browse/categories/' + categoryId)
1533
      .withQueryParameters(options)
1534
      .build()
1535
      .execute(HttpManager.get, callback);
1536
  },
1537

1538
  /**
1539
   * Retrieve playlists for a category.
1540
   * @deprecated As of November 27 Spotify DEPRECATED this ENDPOINT and can be removed in future. (https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api)
1541
   * @param {string} categoryId The id of the category to retrieve playlists for.
1542
   * @param {Object} [options] Options, being country, limit, offset.
1543
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1544
   * @returns {Promise|undefined} A promise that if successful, resolves to a paging object containing simple playlists.
1545
   * Not returned if a callback is given.
1546
   */
1547
  getPlaylistsForCategory: function (categoryId, options, callback) {
1548
    console.warn(
2✔
1549
      "IMPORTANT: As of November 27, 2024, Spotify has DEPRECATED this endpoint. It may be removed in future updates. " +
1550
      "For more details, visit: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
1551
    );
1552
    return WebApiRequest.builder(this.getAccessToken())
2✔
1553
      .withPath('/v1/browse/categories/' + categoryId + '/playlists')
1554
      .withQueryParameters(options)
1555
      .build()
1556
      .execute(HttpManager.get, callback);
1557
  },
1558

1559
  /**
1560
   * Get a show.
1561
   * @param {string} showId The show's ID.
1562
   * @param {Object} [options] The possible options, currently only market.
1563
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1564
   * @example getShow('3Qm86XLflmIXVm1wcwkgDK').then(...)
1565
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
1566
   *          about the show. Not returned if a callback is given.
1567
   */
1568
  getShow: function (showId, options, callback) {
1569
    return WebApiRequest.builder(this.getAccessToken())
2✔
1570
      .withPath('/v1/shows/' + showId)
1571
      .withQueryParameters(options)
1572
      .build()
1573
      .execute(HttpManager.get, callback);
1574
  },
1575

1576
  /**
1577
   * Look up several shows.
1578
   * @param {string[]} showIds The IDs of the shows.
1579
   * @param {Object} [options] The possible options, currently only market.
1580
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1581
   * @example getShows(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...)
1582
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
1583
   *          about the shows. Not returned if a callback is given.
1584
   */
1585
  getShows: function (showIds, options, callback) {
1586
    return WebApiRequest.builder(this.getAccessToken())
2✔
1587
      .withPath('/v1/shows')
1588
      .withQueryParameters(
1589
        {
1590
          ids: showIds.join(',')
1591
        },
1592
        options
1593
      )
1594
      .build()
1595
      .execute(HttpManager.get, callback);
1596
  },
1597

1598
  /**
1599
   * Check if one or more shows is already saved in the current Spotify user’s “Your Music” library.
1600
   * @param {string[]} showIds The show IDs
1601
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1602
   * @returns {Promise|undefined} A promise that if successful, resolves into an array of booleans. The order
1603
   * of the returned array's elements correspond to the show ID in the request.
1604
   * The boolean value of true indicates that the show is part of the user's library, otherwise false.
1605
   * Not returned if a callback is given.
1606
   */
1607
  containsMySavedShows: function (showIds, callback) {
1608
    return WebApiRequest.builder(this.getAccessToken())
2✔
1609
      .withPath('/v1/me/shows/contains')
1610
      .withQueryParameters({
1611
        ids: showIds.join(',')
1612
      })
1613
      .build()
1614
      .execute(HttpManager.get, callback);
1615
  },
1616

1617
  /**
1618
   * Remove an show from the authenticated user's Your Music library.
1619
   * @param {string[]} showIds The show IDs
1620
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1621
   * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error.
1622
   * Not returned if a callback is given.
1623
   */
1624
  removeFromMySavedShows: function (showIds, callback) {
1625
    return WebApiRequest.builder(this.getAccessToken())
2✔
1626
      .withPath('/v1/me/shows')
1627
      .withHeaders({ 'Content-Type': 'application/json' })
1628
      .withQueryParameters({
1629
        ids: showIds.join(',')
1630
      })
1631
      .build()
1632
      .execute(HttpManager.del, callback);
1633
  },
1634

1635
  /**
1636
   * Add a show from the authenticated user's Your Music library.
1637
   * @param {string[]} showIds The show IDs
1638
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1639
   * @returns {Promise|undefined} A promise that if successful returns null, otherwise an error. Not returned if a callback is given.
1640
   */
1641
  addToMySavedShows: function (showIds, callback) {
1642
    return WebApiRequest.builder(this.getAccessToken())
2✔
1643
      .withPath('/v1/me/shows')
1644
      .withHeaders({ 'Content-Type': 'application/json' })
1645
      .withBodyParameters(showIds)
1646
      .build()
1647
      .execute(HttpManager.put, callback);
1648
  },
1649

1650
  /**
1651
   * Retrieve the shows that are saved to the authenticated users Your Music library.
1652
   * @param {Object} [options] Options, being market, limit, and/or offset.
1653
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1654
   * @returns {Promise|undefined} A promise that if successful, resolves to an object containing a paging object which in turn contains
1655
   *          playlist show objects. Not returned if a callback is given.
1656
   */
1657
  getMySavedShows: function (options, callback) {
1658
    return WebApiRequest.builder(this.getAccessToken())
2✔
1659
      .withPath('/v1/me/shows')
1660
      .withQueryParameters(options)
1661
      .build()
1662
      .execute(HttpManager.get, callback);
1663
  },
1664

1665
  /**
1666
   * Get the episodes of an show.
1667
   * @param showId the show's ID.
1668
   * @options {Object} [options] The possible options, being limit, offset, and market.
1669
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1670
   * @example getShowEpisodes('41MnTivkwTO3UUJ8DrqEJJ', { limit : 5, offset : 1 }).then(...)
1671
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
1672
   *                    episodes in the album. The result is paginated. If the promise is rejected.
1673
   *                    it contains an error object. Not returned if a callback is given.
1674
   */
1675
  getShowEpisodes: function (showId, options, callback) {
1676
    return WebApiRequest.builder(this.getAccessToken())
2✔
1677
      .withPath('/v1/shows/' + showId + '/episodes')
1678
      .withQueryParameters(options)
1679
      .build()
1680
      .execute(HttpManager.get, callback);
1681
  },
1682

1683
  /**
1684
   * Search for a show.
1685
   * @param {string} query The search query.
1686
   * @param {Object} [options] The possible options, e.g. limit, offset.
1687
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1688
   * @example searchShows('Space Oddity', { limit : 5, offset : 1 }).then(...)
1689
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
1690
   *          search results. The result is paginated. If the promise is rejected,
1691
   *          it contains an error object. Not returned if a callback is given.
1692
   */
1693
  searchShows: function (query, options, callback) {
1694
    return this.search(query, ['show'], options, callback);
2✔
1695
  },
1696

1697
  /**
1698
   * Search for an episode.
1699
   * @param {string} query The search query.
1700
   * @param {Object} [options] The possible options, e.g. limit, offset.
1701
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1702
   * @example searchEpisodes('Space Oddity', { limit : 5, offset : 1 }).then(...)
1703
   * @returns {Promise|undefined} A promise that if successful, returns an object containing the
1704
   *          search results. The result is paginated. If the promise is rejected,
1705
   *          it contains an error object. Not returned if a callback is given.
1706
   */
1707
  searchEpisodes: function (query, options, callback) {
1708
    return this.search(query, ['episode'], options, callback);
2✔
1709
  },
1710

1711
  /**
1712
   * Look up an episode.
1713
   * @param {string} episodeId The episode's ID.
1714
   * @param {Object} [options] The possible options, currently only market.
1715
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1716
   * @example getEpisode('3Qm86XLflmIXVm1wcwkgDK').then(...)
1717
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
1718
   *          about the episode. Not returned if a callback is given.
1719
   */
1720
  getEpisode: function (episodeId, options, callback) {
1721
    return WebApiRequest.builder(this.getAccessToken())
2✔
1722
      .withPath('/v1/episodes/' + episodeId)
1723
      .withQueryParameters(options)
1724
      .build()
1725
      .execute(HttpManager.get, callback);
1726
  },
1727

1728
  /**
1729
   * Look up several episodes.
1730
   * @param {string[]} episodeIds The IDs of the episodes.
1731
   * @param {Object} [options] The possible options, currently only market.
1732
   * @param {requestCallback} [callback] Optional callback method to be called instead of the promise.
1733
   * @example getEpisodes(['0oSGxfWSnnOXhD2fKuz2Gy', '3dBVyJ7JuOMt4GE9607Qin']).then(...)
1734
   * @returns {Promise|undefined} A promise that if successful, returns an object containing information
1735
   *          about the episodes. Not returned if a callback is given.
1736
   */
1737
  getEpisodes: function (episodeIds, options, callback) {
1738
    return WebApiRequest.builder(this.getAccessToken())
2✔
1739
      .withPath('/v1/episodes')
1740
      .withQueryParameters(
1741
        {
1742
          ids: episodeIds.join(',')
1743
        },
1744
        options
1745
      )
1746
      .build()
1747
      .execute(HttpManager.get, callback);
1748
  }
1749
};
1750

1751
SpotifyWebApi._addMethods = function (methods) {
2✔
1752
  for (var i in methods) {
2✔
1753
    if (methods.hasOwnProperty(i)) {
8!
1754
      this.prototype[i] = methods[i];
8✔
1755
    }
1756
  }
1757
};
1758

1759
module.exports = SpotifyWebApi;
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc