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

jwilsson / spotify-web-api-php / 5713719944

pending completion
5713719944

push

github

jwilsson
Refactor Request class tests

Always mock the curl_* calls instead of relying on external HTTP services

743 of 753 relevant lines covered (98.67%)

10.45 hits per line

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

99.47
/src/SpotifyWebAPI.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace SpotifyWebAPI;
6

7
class SpotifyWebAPI
8
{
9
    protected string $accessToken = '';
10
    protected array $lastResponse = [];
11
    protected array $options = [
12
        'auto_refresh' => false,
13
        'auto_retry' => false,
14
        'return_assoc' => false,
15
    ];
16
    protected ?Request $request = null;
17
    protected ?Session $session = null;
18

19
    /**
20
     * Constructor
21
     * Set options and class instances to use.
22
     *
23
     * @param array|object $options Optional. Options to set.
24
     * @param Session $session Optional. The Session object to use.
25
     * @param Request $request Optional. The Request object to use.
26
     */
27
    public function __construct(array|object $options = [], ?Session $session = null, ?Request $request = null)
28
    {
29
        $this->setOptions($options);
188✔
30
        $this->setSession($session);
188✔
31

32
        $this->request = $request ?? new Request();
188✔
33
    }
34

35
    /**
36
     * Add authorization headers.
37
     *
38
     * @param $headers array. Optional. Additional headers to merge with the authorization headers.
39
     *
40
     * @return array Authorization headers, optionally merged with the passed ones.
41
     */
42
    protected function authHeaders(array $headers = []): array
43
    {
44
        $accessToken = $this->session ? $this->session->getAccessToken() : $this->accessToken;
180✔
45

46
        if ($accessToken) {
180✔
47
            $headers = array_merge($headers, [
4✔
48
                'Authorization' => 'Bearer ' . $accessToken,
4✔
49
            ]);
4✔
50
        }
51

52
        return $headers;
180✔
53
    }
54

55
    /**
56
     * Try to fetch a snapshot ID from a response.
57
     *
58
     * @param object|array $body The parsed response body.
59
     *
60
     * @return string|bool A snapshot ID or false if none exists.
61
     */
62
    protected function getSnapshotId(array|object $body): string|bool
63
    {
64
        $body = (array) $body;
8✔
65

66
        return $body['snapshot_id'] ?? null;
8✔
67
    }
68

69
    /**
70
     * Convert Spotify object IDs to URIs.
71
     *
72
     * @param string|array $ids ID(s) to convert.
73
     * @param string $type Spotify object type.
74
     *
75
     * @return string|array URI(s).
76
     */
77
    protected function idToUri(string|array $ids, string $type): string|array
78
    {
79
        $type = 'spotify:' . $type . ':';
10✔
80

81
        $ids = array_map(function ($id) use ($type) {
10✔
82
            if (substr($id, 0, strlen($type)) != $type && substr($id, 0, 7) != 'spotify') {
10✔
83
                $id = $type . $id;
8✔
84
            }
85

86
            return $id;
10✔
87
        }, (array) $ids);
10✔
88

89
        return count($ids) == 1 ? $ids[0] : $ids;
10✔
90
    }
91

92
    /**
93
     * Send a request to the Spotify API, automatically refreshing the access token as needed.
94
     *
95
     * @param string $method The HTTP method to use.
96
     * @param string $uri The URI to request.
97
     * @param string|array $parameters Optional. Query string parameters or HTTP body, depending on $method.
98
     * @param array $headers Optional. HTTP headers.
99
     *
100
     * @throws SpotifyWebAPIException
101
     * @throws SpotifyWebAPIAuthException
102
     *
103
     * @return array Response data.
104
     * - array|object body The response body. Type is controlled by the `return_assoc` option.
105
     * - array headers Response headers.
106
     * - int status HTTP status code.
107
     * - string url The requested URL.
108
     */
109
    protected function sendRequest(
110
        string $method,
111
        string $uri,
112
        string|array $parameters = [],
113
        array $headers = []
114
    ): array {
115
        $this->request->setOptions([
180✔
116
            'return_assoc' => $this->options['return_assoc'],
180✔
117
        ]);
180✔
118

119
        try {
120
            $headers = $this->authHeaders($headers);
180✔
121

122
            return $this->request->api($method, $uri, $parameters, $headers);
180✔
123
        } catch (SpotifyWebAPIException $e) {
4✔
124
            if ($this->options['auto_refresh'] && $e->hasExpiredToken()) {
4✔
125
                $result = $this->session->refreshAccessToken();
2✔
126

127
                if (!$result) {
2✔
128
                    throw new SpotifyWebAPIException('Could not refresh access token.');
×
129
                }
130

131
                return $this->sendRequest($method, $uri, $parameters, $headers);
2✔
132
            } elseif ($this->options['auto_retry'] && $e->isRateLimited()) {
2✔
133
                ['headers' => $lastHeaders] = $this->request->getLastResponse();
2✔
134

135
                sleep((int) $lastHeaders['retry-after']);
2✔
136

137
                return $this->sendRequest($method, $uri, $parameters, $headers);
2✔
138
            }
139

140
            throw $e;
×
141
        }
142
    }
143

144
    /**
145
     * Convert an array to a comma-separated string. If it's already a string, do nothing.
146
     *
147
     * @param array|string $value The value to convert.
148
     *
149
     * @return string A comma-separated string.
150
     */
151
    protected function toCommaString(string|array $value): string
152
    {
153
        if (is_array($value)) {
42✔
154
            return implode(',', $value);
42✔
155
        }
156

157
        return $value;
2✔
158
    }
159

160
    /**
161
     * Convert URIs to Spotify object IDs.
162
     *
163
     * @param string|array $uriIds URI(s) to convert.
164
     * @param string $type Spotify object type.
165
     *
166
     * @return string|array ID(s).
167
     */
168
    protected function uriToId(string|array $uriIds, string $type): string|array
169
    {
170
        $type = 'spotify:' . $type . ':';
114✔
171

172
        $uriIds = array_map(function ($id) use ($type) {
114✔
173
            return str_replace($type, '', $id);
114✔
174
        }, (array) $uriIds);
114✔
175

176
        return count($uriIds) == 1 ? $uriIds[0] : $uriIds;
114✔
177
    }
178

179
    /**
180
     * Add albums to the current user's Spotify library.
181
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/save-albums-user
182
     *
183
     * @param string|array $albums Album IDs or URIs to add.
184
     *
185
     * @return bool Whether the albums was successfully added.
186
     */
187
    public function addMyAlbums(string|array $albums): bool
188
    {
189
        $albums = $this->uriToId($albums, 'album');
2✔
190
        $albums = json_encode((array) $albums);
2✔
191

192
        $headers = [
2✔
193
            'Content-Type' => 'application/json',
2✔
194
        ];
2✔
195

196
        $uri = '/v1/me/albums';
2✔
197

198
        $this->lastResponse = $this->sendRequest('PUT', $uri, $albums, $headers);
2✔
199

200
        return $this->lastResponse['status'] == 200;
2✔
201
    }
202

203
    /**
204
     * Add episodes to the current user's Spotify library.
205
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/save-episodes-user
206
     *
207
     * @param string|array $episodes Episode IDs or URIs to add.
208
     *
209
     * @return bool Whether the episodes was successfully added.
210
     */
211
    public function addMyEpisodes(string|array $episodes): bool
212
    {
213
        $episodes = $this->uriToId($episodes, 'episode');
2✔
214
        $episodes = json_encode((array) $episodes);
2✔
215

216
        $headers = [
2✔
217
            'Content-Type' => 'application/json',
2✔
218
        ];
2✔
219

220
        $uri = '/v1/me/episodes';
2✔
221

222
        $this->lastResponse = $this->sendRequest('PUT', $uri, $episodes, $headers);
2✔
223

224
        return $this->lastResponse['status'] == 200;
2✔
225
    }
226

227
    /**
228
     * Add shows to the current user's Spotify library.
229
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/save-shows-user
230
     *
231
     * @param string|array $shows Show IDs or URIs to add.
232
     *
233
     * @return bool Whether the shows was successfully added.
234
     */
235
    public function addMyShows(string|array $shows): bool
236
    {
237
        $shows = $this->uriToId($shows, 'show');
2✔
238
        $shows = json_encode((array) $shows);
2✔
239

240
        $headers = [
2✔
241
            'Content-Type' => 'application/json',
2✔
242
        ];
2✔
243

244
        $uri = '/v1/me/shows';
2✔
245

246
        $this->lastResponse = $this->sendRequest('PUT', $uri, $shows, $headers);
2✔
247

248
        return $this->lastResponse['status'] == 200;
2✔
249
    }
250

251
    /**
252
     * Add tracks to the current user's Spotify library.
253
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/save-tracks-user
254
     *
255
     * @param string|array $tracks Track IDs or URIs to add.
256
     *
257
     * @return bool Whether the tracks was successfully added.
258
     */
259
    public function addMyTracks(string|array $tracks): bool
260
    {
261
        $tracks = $this->uriToId($tracks, 'track');
2✔
262
        $tracks = json_encode((array) $tracks);
2✔
263

264
        $headers = [
2✔
265
            'Content-Type' => 'application/json',
2✔
266
        ];
2✔
267

268
        $uri = '/v1/me/tracks';
2✔
269

270
        $this->lastResponse = $this->sendRequest('PUT', $uri, $tracks, $headers);
2✔
271

272
        return $this->lastResponse['status'] == 200;
2✔
273
    }
274

275
    /**
276
     * Add tracks to a playlist.
277
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/add-tracks-to-playlist
278
     *
279
     * @param string $playlistId ID of the playlist to add tracks to.
280
     * @param string|array $tracks Track IDs, track URIs, and episode URIs to add.
281
     * @param array|object $options Optional. Options for the new tracks.
282
     * - int position Optional. Zero-based track position in playlist. Tracks will be appended if omitted or false.
283
     *
284
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully added.
285
     */
286
    public function addPlaylistTracks(
287
        string $playlistId,
288
        string|array $tracks,
289
        array|object $options = []
290
    ): string|bool {
291
        $options = array_merge((array) $options, [
2✔
292
            'uris' => (array) $this->idToUri($tracks, 'track')
2✔
293
        ]);
2✔
294

295
        $options = json_encode($options);
2✔
296

297
        $headers = [
2✔
298
            'Content-Type' => 'application/json',
2✔
299
        ];
2✔
300

301
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
302

303
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
2✔
304

305
        $this->lastResponse = $this->sendRequest('POST', $uri, $options, $headers);
2✔
306

307
        return $this->getSnapshotId($this->lastResponse['body']);
2✔
308
    }
309

310
    /**
311
     * Change the current user's playback device.
312
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/transfer-a-users-playback
313
     *
314
     * @param array|object $options Options for the playback transfer.
315
     * - string|array device_ids Required. ID of the device to switch to.
316
     * - bool play Optional. Whether to start playing on the new device
317
     *
318
     * @return bool Whether the playback device was successfully changed.
319
     */
320
    public function changeMyDevice(array|object $options): bool
321
    {
322
        $options = array_merge((array) $options, [
2✔
323
            'device_ids' => (array) $options['device_ids'],
2✔
324
        ]);
2✔
325

326
        $options = json_encode($options);
2✔
327

328
        $headers = [
2✔
329
            'Content-Type' => 'application/json',
2✔
330
        ];
2✔
331

332
        $uri = '/v1/me/player';
2✔
333

334
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
2✔
335

336
        return $this->lastResponse['status'] == 204;
2✔
337
    }
338

339
    /**
340
     * Change playback volume for the current user.
341
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/set-volume-for-users-playback
342
     *
343
     * @param array|object $options Optional. Options for the playback volume.
344
     * - int volume_percent Required. The volume to set.
345
     * - string device_id Optional. ID of the device to target.
346
     *
347
     * @return bool Whether the playback volume was successfully changed.
348
     */
349
    public function changeVolume(array|object $options): bool
350
    {
351
        $options = http_build_query($options, '', '&');
2✔
352

353
        // We need to manually append data to the URI since it's a PUT request
354
        $uri = '/v1/me/player/volume?' . $options;
2✔
355

356
        $this->lastResponse = $this->sendRequest('PUT', $uri);
2✔
357

358
        return $this->lastResponse['status'] == 204;
2✔
359
    }
360

361
    /**
362
     * Create a new playlist.
363
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/create-playlist
364
     *
365
     * @param string $userId ID or URI of the user to create the playlist for.
366
     * @param array|object $options Options for the new playlist.
367
     * - string name Required. Name of the playlist.
368
     * - bool collaborative Optional. Whether the playlist should be collaborative or not.
369
     * - string description Optional. Description of the playlist.
370
     * - bool public Optional. Whether the playlist should be public or not.
371
     *
372
     * @return array|object The new playlist. Type is controlled by the `return_assoc` option.
373
     */
374
    public function createPlaylist(string|array|object $userId, array|object $options = []): array|object
375
    {
376
        if (is_array($userId) || is_object($userId)) {
4✔
377
            trigger_error(
2✔
378
                'Calling SpotifyWebAPI::createPlaylist() without a user ID is deprecated.',
2✔
379
                E_USER_DEPRECATED
2✔
380
            );
2✔
381

382
            $options = $userId;
2✔
383
            $userId = 'me';
2✔
384
        }
385

386
        $options = json_encode($options);
4✔
387

388
        $headers = [
4✔
389
            'Content-Type' => 'application/json',
4✔
390
        ];
4✔
391

392
        $userId = $this->uriToId($userId, 'user');
4✔
393
        $uri = '/v1/' . $userId . '/playlists';
4✔
394

395
        $this->lastResponse = $this->sendRequest('POST', $uri, $options, $headers);
4✔
396

397
        return $this->lastResponse['body'];
4✔
398
    }
399

400
    /**
401
     * Check to see if the current user is following one or more artists or other Spotify users.
402
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-current-user-follows
403
     *
404
     * @param string $type The type to check: either 'artist' or 'user'.
405
     * @param string|array $ids IDs or URIs of the users or artists to check for.
406
     *
407
     * @return array Whether each user or artist is followed.
408
     */
409
    public function currentUserFollows(string $type, string|array $ids): array
410
    {
411
        $ids = $this->uriToId($ids, $type);
2✔
412
        $ids = $this->toCommaString($ids);
2✔
413

414
        $options = [
2✔
415
            'ids' => $ids,
2✔
416
            'type' => $type,
2✔
417
        ];
2✔
418

419
        $uri = '/v1/me/following/contains';
2✔
420

421
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
422

423
        return $this->lastResponse['body'];
2✔
424
    }
425

426
    /**
427
     * Delete albums from the current user's Spotify library.
428
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-albums-user
429
     *
430
     * @param string|array $albums Album IDs or URIs to delete.
431
     *
432
     * @return bool Whether the albums was successfully deleted.
433
     */
434
    public function deleteMyAlbums(string|array $albums): bool
435
    {
436
        $albums = $this->uriToId($albums, 'album');
2✔
437
        $albums = json_encode((array) $albums);
2✔
438

439
        $headers = [
2✔
440
            'Content-Type' => 'application/json',
2✔
441
        ];
2✔
442

443
        $uri = '/v1/me/albums';
2✔
444

445
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $albums, $headers);
2✔
446

447
        return $this->lastResponse['status'] == 200;
2✔
448
    }
449

450
    /**
451
     * Delete episodes from the current user's Spotify library.
452
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-episodes-user
453
     *
454
     * @param string|array $episodes Episode IDs or URIs to delete.
455
     *
456
     * @return bool Whether the episodes was successfully deleted.
457
     */
458
    public function deleteMyEpisodes(string|array $episodes): bool
459
    {
460
        $episodes = $this->uriToId($episodes, 'episode');
2✔
461
        $episodes = json_encode((array) $episodes);
2✔
462

463
        $headers = [
2✔
464
            'Content-Type' => 'application/json',
2✔
465
        ];
2✔
466

467
        $uri = '/v1/me/episodes';
2✔
468

469
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $episodes, $headers);
2✔
470

471
        return $this->lastResponse['status'] == 200;
2✔
472
    }
473

474
    /**
475
     * Delete shows from the current user's Spotify library.
476
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-shows-user
477
     *
478
     * @param string|array $shows Show IDs or URIs to delete.
479
     *
480
     * @return bool Whether the shows was successfully deleted.
481
     */
482
    public function deleteMyShows(string|array $shows): bool
483
    {
484
        $shows = $this->uriToId($shows, 'show');
2✔
485
        $shows = json_encode((array) $shows);
2✔
486

487
        $headers = [
2✔
488
            'Content-Type' => 'application/json',
2✔
489
        ];
2✔
490

491
        $uri = '/v1/me/shows';
2✔
492

493
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $shows, $headers);
2✔
494

495
        return $this->lastResponse['status'] == 200;
2✔
496
    }
497

498
    /**
499
     * Delete tracks from the current user's Spotify library.
500
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-tracks-user
501
     *
502
     * @param string|array $tracks Track IDs or URIs to delete.
503
     *
504
     * @return bool Whether the tracks was successfully deleted.
505
     */
506
    public function deleteMyTracks(string|array $tracks): bool
507
    {
508
        $tracks = $this->uriToId($tracks, 'track');
2✔
509
        $tracks = json_encode((array) $tracks);
2✔
510

511
        $headers = [
2✔
512
            'Content-Type' => 'application/json',
2✔
513
        ];
2✔
514

515
        $uri = '/v1/me/tracks';
2✔
516

517
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $tracks, $headers);
2✔
518

519
        return $this->lastResponse['status'] == 200;
2✔
520
    }
521

522
    /**
523
     * Delete tracks from a playlist and retrieve a new snapshot ID.
524
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-tracks-playlist
525
     *
526
     * @param string $playlistId ID or URI of the playlist to delete tracks from.
527
     * @param array $tracks An array with the key "tracks" containing arrays or objects with tracks to delete.
528
     * Or an array with the key "positions" containing integer positions of the tracks to delete.
529
     * If the "tracks" key is used, the following fields are also available:
530
     * - string uri Required. Track ID, track URI, or episode URI.
531
     * - int|array positions Optional. The track's positions in the playlist.
532
     * @param string $snapshotId Required when `$tracks['positions']` is used, optional otherwise.
533
     * The playlist's snapshot ID.
534
     *
535
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully deleted.
536
     */
537
    public function deletePlaylistTracks(string $playlistId, array $tracks, string $snapshotId = ''): string|bool
538
    {
539
        $options = [];
4✔
540

541
        if ($snapshotId) {
4✔
542
            $options['snapshot_id'] = $snapshotId;
4✔
543
        }
544

545
        if (isset($tracks['positions'])) {
4✔
546
            $options['positions'] = $tracks['positions'];
2✔
547
        } else {
548
            $options['tracks'] = array_map(function ($track) {
2✔
549
                $track = (array) $track;
2✔
550

551
                if (isset($track['positions'])) {
2✔
552
                    $track['positions'] = (array) $track['positions'];
2✔
553
                }
554

555
                $track['uri'] = $this->idToUri($track['uri'], 'track');
2✔
556

557
                return $track;
2✔
558
            }, $tracks['tracks']);
2✔
559
        }
560

561
        $options = json_encode($options);
4✔
562

563
        $headers = [
4✔
564
            'Content-Type' => 'application/json',
4✔
565
        ];
4✔
566

567
        $playlistId = $this->uriToId($playlistId, 'playlist');
4✔
568

569
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
4✔
570

571
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $options, $headers);
4✔
572

573
        return $this->getSnapshotId($this->lastResponse['body']);
4✔
574
    }
575

576
    /**
577
     * Add the current user as a follower of one or more artists or other Spotify users.
578
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/follow-artists-users
579
     *
580
     * @param string $type The type of ID to follow: either 'artist' or 'user'.
581
     * @param string|array $ids IDs or URIs of the users or artists to follow.
582
     *
583
     * @return bool Whether the artist or user was successfully followed.
584
     */
585
    public function followArtistsOrUsers(string $type, string|array $ids): bool
586
    {
587
        $ids = $this->uriToId($ids, $type);
2✔
588
        $ids = json_encode([
2✔
589
            'ids' => (array) $ids,
2✔
590
        ]);
2✔
591

592
        $headers = [
2✔
593
            'Content-Type' => 'application/json',
2✔
594
        ];
2✔
595

596
        // We need to manually append data to the URI since it's a PUT request
597
        $uri = '/v1/me/following?type=' . $type;
2✔
598

599
        $this->lastResponse = $this->sendRequest('PUT', $uri, $ids, $headers);
2✔
600

601
        return $this->lastResponse['status'] == 204;
2✔
602
    }
603

604
    /**
605
     * Add the current user as a follower of a playlist.
606
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/follow-playlist
607
     *
608
     * @param string $playlistId ID or URI of the playlist to follow.
609
     * @param array|object $options Optional. Options for the followed playlist.
610
     * - bool public Optional. Whether the playlist should be followed publicly or not.
611
     *
612
     * @return bool Whether the playlist was successfully followed.
613
     */
614
    public function followPlaylist(string $playlistId, array|object $options = []): bool
615
    {
616
        $options = $options ? json_encode($options) : null;
2✔
617

618
        $headers = [
2✔
619
            'Content-Type' => 'application/json',
2✔
620
        ];
2✔
621

622
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
623

624
        $uri = '/v1/playlists/' . $playlistId . '/followers';
2✔
625

626
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
2✔
627

628
        return $this->lastResponse['status'] == 200;
2✔
629
    }
630

631
    /**
632
     * Get an album.
633
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-album
634
     *
635
     * @param string $albumId ID or URI of the album.
636
     * @param array|object $options Optional. Options for the album.
637
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
638
     *
639
     * @return array|object The requested album. Type is controlled by the `return_assoc` option.
640
     */
641
    public function getAlbum(string $albumId, array|object $options = []): array|object
642
    {
643
        $albumId = $this->uriToId($albumId, 'album');
2✔
644
        $uri = '/v1/albums/' . $albumId;
2✔
645

646
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
647

648
        return $this->lastResponse['body'];
2✔
649
    }
650

651
    /**
652
     * Get multiple albums.
653
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-albums
654
     *
655
     * @param array $albumIds IDs or URIs of the albums.
656
     * @param array|object $options Optional. Options for the albums.
657
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
658
     *
659
     * @return array|object The requested albums. Type is controlled by the `return_assoc` option.
660
     */
661
    public function getAlbums(array $albumIds, array|object $options = []): array|object
662
    {
663
        $albumIds = $this->uriToId($albumIds, 'album');
2✔
664
        $options = array_merge((array) $options, [
2✔
665
            'ids' => $this->toCommaString($albumIds),
2✔
666
        ]);
2✔
667

668
        $uri = '/v1/albums/';
2✔
669

670
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
671

672
        return $this->lastResponse['body'];
2✔
673
    }
674

675
    /**
676
     * Get an album's tracks.
677
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-albums-tracks
678
     *
679
     * @param string $albumId ID or URI of the album.
680
     * @param array|object $options Optional. Options for the tracks.
681
     * - int limit Optional. Limit the number of tracks.
682
     * - int offset Optional. Number of tracks to skip.
683
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
684
     *
685
     * @return array|object The requested album tracks. Type is controlled by the `return_assoc` option.
686
     */
687
    public function getAlbumTracks(string $albumId, array|object $options = []): array|object
688
    {
689
        $albumId = $this->uriToId($albumId, 'album');
2✔
690
        $uri = '/v1/albums/' . $albumId . '/tracks';
2✔
691

692
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
693

694
        return $this->lastResponse['body'];
2✔
695
    }
696

697
    /**
698
     * Get an artist.
699
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artist
700
     *
701
     * @param string $artistId ID or URI of the artist.
702
     *
703
     * @return array|object The requested artist. Type is controlled by the `return_assoc` option.
704
     */
705
    public function getArtist(string $artistId): array|object
706
    {
707
        $artistId = $this->uriToId($artistId, 'artist');
2✔
708
        $uri = '/v1/artists/' . $artistId;
2✔
709

710
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
711

712
        return $this->lastResponse['body'];
2✔
713
    }
714

715
    /**
716
     * Get multiple artists.
717
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-artists
718
     *
719
     * @param array $artistIds IDs or URIs of the artists.
720
     *
721
     * @return array|object The requested artists. Type is controlled by the `return_assoc` option.
722
     */
723
    public function getArtists(array $artistIds): array|object
724
    {
725
        $artistIds = $this->uriToId($artistIds, 'artist');
2✔
726
        $artistIds = $this->toCommaString($artistIds);
2✔
727

728
        $options = [
2✔
729
            'ids' => $artistIds,
2✔
730
        ];
2✔
731

732
        $uri = '/v1/artists/';
2✔
733

734
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
735

736
        return $this->lastResponse['body'];
2✔
737
    }
738

739
    /**
740
     * Get an artist's related artists.
741
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artists-related-artists
742
     *
743
     * @param string $artistId ID or URI of the artist.
744
     *
745
     * @return array|object The artist's related artists. Type is controlled by the `return_assoc` option.
746
     */
747
    public function getArtistRelatedArtists(string $artistId): array|object
748
    {
749
        $artistId = $this->uriToId($artistId, 'artist');
2✔
750
        $uri = '/v1/artists/' . $artistId . '/related-artists';
2✔
751

752
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
753

754
        return $this->lastResponse['body'];
2✔
755
    }
756

757
    /**
758
     * Get an artist's albums.
759
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artists-albums
760
     *
761
     * @param string $artistId ID or URI of the artist.
762
     * @param array|object $options Optional. Options for the albums.
763
     * - string market Optional. Limit the results to items that are playable in this country, for example SE.
764
     * - string|array include_groups Optional. Album types to return. If omitted, all album types will be returned.
765
     * - int limit Optional. Limit the number of albums.
766
     * - int offset Optional. Number of albums to skip.
767
     *
768
     * @return array|object The artist's albums. Type is controlled by the `return_assoc` option.
769
     */
770
    public function getArtistAlbums(string $artistId, array|object $options = []): array|object
771
    {
772
        $options = (array) $options;
2✔
773

774
        if (isset($options['include_groups'])) {
2✔
775
            $options['include_groups'] = $this->toCommaString($options['include_groups']);
2✔
776
        }
777

778
        $artistId = $this->uriToId($artistId, 'artist');
2✔
779
        $uri = '/v1/artists/' . $artistId . '/albums';
2✔
780

781
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
782

783
        return $this->lastResponse['body'];
2✔
784
    }
785

786
    /**
787
     * Get an artist's top tracks in a country.
788
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artists-top-tracks
789
     *
790
     * @param string $artistId ID or URI of the artist.
791
     * @param array|object $options Options for the tracks.
792
     * - string market Required. An ISO 3166-1 alpha-2 country code specifying the country to get the top tracks for.
793
     *
794
     * @return array|object The artist's top tracks. Type is controlled by the `return_assoc` option.
795
     */
796
    public function getArtistTopTracks(string $artistId, array|object $options): array|object
797
    {
798
        $artistId = $this->uriToId($artistId, 'artist');
2✔
799
        $uri = '/v1/artists/' . $artistId . '/top-tracks';
2✔
800

801
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
802

803
        return $this->lastResponse['body'];
2✔
804
    }
805

806
    /**
807
     * Get audio analysis for track.
808
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-audio-analysis
809
     *
810
     * @param string $trackId ID or URI of the track.
811
     *
812
     * @return array|object The track's audio analysis. Type is controlled by the `return_assoc` option.
813
     */
814
    public function getAudioAnalysis(string $trackId): array|object
815
    {
816
        $trackId = $this->uriToId($trackId, 'track');
2✔
817
        $uri = '/v1/audio-analysis/' . $trackId;
2✔
818

819
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
820

821
        return $this->lastResponse['body'];
2✔
822
    }
823

824
    /**
825
     * Get an audiobook.
826
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-audiobook
827
     *
828
     * @param string $audiobookId ID or URI of the audiobook.
829
     * @param array|object $options Optional. Options for the audiobook.
830
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to audiobooks available in that market.
831
     *
832
     * @return array|object The requested audiobook. Type is controlled by the `return_assoc` option.
833
     */
834
    public function getAudiobook(string $audiobookId, array|object $options = [])
835
    {
836
        $audiobookId = $this->uriToId($audiobookId, 'show');
2✔
837
        $uri = '/v1/audiobooks/' . $audiobookId;
2✔
838

839
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
840

841
        return $this->lastResponse['body'];
2✔
842
    }
843

844
    /**
845
     * Get multiple audiobooks.
846
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-audiobooks
847
     *
848
     * @param array $audiobookIds IDs or URIs of the audiobooks.
849
     * @param array|object $options Optional. Options for the audiobooks.
850
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to audiobooks available in that market.
851
     *
852
     * @return array|object The requested audiobooks. Type is controlled by the `return_assoc` option.
853
     */
854
    public function getAudiobooks(array $audiobookIds, array|object $options = [])
855
    {
856
        $audiobookIds = $this->uriToId($audiobookIds, 'show');
2✔
857
        $audiobookIds = $this->toCommaString($audiobookIds);
2✔
858

859
        $options = array_merge((array) $options, [
2✔
860
            'ids' => $this->toCommaString($audiobookIds),
2✔
861
        ]);
2✔
862

863
        $uri = '/v1/audiobooks/';
2✔
864

865
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
866

867
        return $this->lastResponse['body'];
2✔
868
    }
869

870
    /**
871
     * Get audio features of a single track.
872
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-audio-features
873
     *
874
     * @param string $trackId ID or URI of the track.
875
     *
876
     * @return array|object The track's audio features. Type is controlled by the `return_assoc` option.
877
     */
878
    public function getAudioFeatures(string $trackId): array|object
879
    {
880
        $trackId = $this->uriToId($trackId, 'track');
2✔
881
        $uri = '/v1/audio-features/' . $trackId;
2✔
882

883
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
884

885
        return $this->lastResponse['body'];
2✔
886
    }
887

888
    /**
889
     * Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s "Discover" tab).
890
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-categories
891
     *
892
     * @param array|object $options Optional. Options for the categories.
893
     * - string locale Optional. Language to show categories in, for example 'sv_SE'.
894
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show categories from this country.
895
     * - int limit Optional. Limit the number of categories.
896
     * - int offset Optional. Number of categories to skip.
897
     *
898
     * @return array|object The list of categories. Type is controlled by the `return_assoc` option.
899
     */
900
    public function getCategoriesList(array|object $options = []): array|object
901
    {
902
        $uri = '/v1/browse/categories';
2✔
903

904
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
905

906
        return $this->lastResponse['body'];
2✔
907
    }
908

909
    /**
910
     * Get a single category used to tag items in Spotify (on, for example, the Spotify player’s "Discover" tab).
911
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-category
912
     *
913
     * @param string $categoryId ID of the category.
914
     *
915
     * @param array|object $options Optional. Options for the category.
916
     * - string locale Optional. Language to show category in, for example 'sv_SE'.
917
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show category from this country.
918
     *
919
     * @return array|object The category. Type is controlled by the `return_assoc` option.
920
     */
921
    public function getCategory(string $categoryId, array|object $options = []): array|object
922
    {
923
        $uri = '/v1/browse/categories/' . $categoryId;
2✔
924

925
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
926

927
        return $this->lastResponse['body'];
2✔
928
    }
929

930
    /**
931
     * Get a list of Spotify playlists tagged with a particular category.
932
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-categories-playlists
933
     *
934
     * @param string $categoryId ID of the category.
935
     *
936
     * @param array|object $options Optional. Options for the category's playlists.
937
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show category playlists from this country.
938
     * - int limit Optional. Limit the number of playlists.
939
     * - int offset Optional. Number of playlists to skip.
940
     *
941
     * @return array|object The list of playlists. Type is controlled by the `return_assoc` option.
942
     */
943
    public function getCategoryPlaylists(string $categoryId, array|object $options = []): array|object
944
    {
945
        $uri = '/v1/browse/categories/' . $categoryId . '/playlists';
2✔
946

947
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
948

949
        return $this->lastResponse['body'];
2✔
950
    }
951

952
    /**
953
     * Get a chapter.
954
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-chapter
955
     *
956
     * @param string $chapterId ID or URI of the chapter.
957
     * @param array|object $options Optional. Options for the chapter.
958
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
959
     *
960
     * @return array|object The requested chapter. Type is controlled by the `return_assoc` option.
961
     */
962
    public function getChapter(string $chapterId, array|object $options = [])
963
    {
964
        $chapterId = $this->uriToId($chapterId, 'episode');
2✔
965
        $uri = '/v1/chapters/' . $chapterId;
2✔
966

967
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
968

969
        return $this->lastResponse['body'];
2✔
970
    }
971

972
    /**
973
     * Get multiple chapters.
974
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-chapters
975
     *
976
     * @param array $chapterIds IDs or URIs of the chapters.
977
     * @param array|object $options Optional. Options for the chapters.
978
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
979
     *
980
     * @return array|object The requested chapters. Type is controlled by the `return_assoc` option.
981
     */
982
    public function getChapters(array $chapterIds, array|object $options = [])
983
    {
984
        $chapterIds = $this->uriToId($chapterIds, 'episode');
2✔
985
        $options = array_merge((array) $options, [
2✔
986
            'ids' => $this->toCommaString($chapterIds),
2✔
987
        ]);
2✔
988

989
        $uri = '/v1/chapters/';
2✔
990

991
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
992

993
        return $this->lastResponse['body'];
2✔
994
    }
995

996
    /**
997
     * Get an episode.
998
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-episode
999
     *
1000
     * @param string $episodeId ID or URI of the episode.
1001
     * @param array|object $options Optional. Options for the episode.
1002
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1003
     *
1004
     * @return array|object The requested episode. Type is controlled by the `return_assoc` option.
1005
     */
1006
    public function getEpisode(string $episodeId, array|object $options = []): array|object
1007
    {
1008
        $episodeId = $this->uriToId($episodeId, 'episode');
2✔
1009
        $uri = '/v1/episodes/' . $episodeId;
2✔
1010

1011
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1012

1013
        return $this->lastResponse['body'];
2✔
1014
    }
1015

1016
    /**
1017
     * Get multiple episodes.
1018
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-episodes
1019
     *
1020
     * @param string|array $episodeIds IDs or URIs of the episodes.
1021
     * @param array|object $options Optional. Options for the episodes.
1022
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1023
     *
1024
     * @return array|object The requested episodes. Type is controlled by the `return_assoc` option.
1025
     */
1026
    public function getEpisodes(string|array $episodeIds, array|object $options = []): array|object
1027
    {
1028
        $episodeIds = $this->uriToId($episodeIds, 'episode');
2✔
1029
        $options = array_merge((array) $options, [
2✔
1030
            'ids' => $this->toCommaString($episodeIds),
2✔
1031
        ]);
2✔
1032

1033
        $uri = '/v1/episodes/';
2✔
1034

1035
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1036

1037
        return $this->lastResponse['body'];
2✔
1038
    }
1039

1040
    /**
1041
     * Get Spotify featured playlists.
1042
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-featured-playlists
1043
     *
1044
     * @param array|object $options Optional. Options for the playlists.
1045
     * - string locale Optional. Language to show playlists in, for example 'sv_SE'.
1046
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show playlists from this country.
1047
     * - string timestamp Optional. A ISO 8601 timestamp. Show playlists relevant to this date and time.
1048
     * - int limit Optional. Limit the number of playlists.
1049
     * - int offset Optional. Number of playlists to skip.
1050
     *
1051
     * @return array|object The featured playlists. Type is controlled by the `return_assoc` option.
1052
     */
1053
    public function getFeaturedPlaylists(array|object $options = []): array|object
1054
    {
1055
        $uri = '/v1/browse/featured-playlists';
2✔
1056

1057
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1058

1059
        return $this->lastResponse['body'];
2✔
1060
    }
1061

1062
    /**
1063
     * Get a list of possible seed genres.
1064
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-recommendation-genres
1065
     *
1066
     * @return array|object All possible seed genres. Type is controlled by the `return_assoc` option.
1067
     */
1068
    public function getGenreSeeds(): array|object
1069
    {
1070
        $uri = '/v1/recommendations/available-genre-seeds';
2✔
1071

1072
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
1073

1074
        return $this->lastResponse['body'];
2✔
1075
    }
1076

1077
    /**
1078
     * Get the latest full response from the Spotify API.
1079
     *
1080
     * @return array Response data.
1081
     * - array|object body The response body. Type is controlled by the `return_assoc` option.
1082
     * - array headers Response headers.
1083
     * - int status HTTP status code.
1084
     * - string url The requested URL.
1085
     */
1086
    public function getLastResponse(): array
1087
    {
1088
        return $this->lastResponse;
2✔
1089
    }
1090

1091
    /**
1092
     * Get all markets where Spotify is available.
1093
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-available-markets
1094
     *
1095
     * @return array|object All markets where Spotify is available. Type is controlled by the `return_assoc` option.
1096
     */
1097
    public function getMarkets(): array|object
1098
    {
1099
        $uri = '/v1/markets';
2✔
1100

1101
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
1102

1103
        return $this->lastResponse['body'];
2✔
1104
    }
1105

1106
    /**
1107
     * Get audio features of multiple tracks.
1108
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-audio-features
1109
     *
1110
     * @param string|array $trackIds IDs or URIs of the tracks.
1111
     *
1112
     * @return array|object The tracks' audio features. Type is controlled by the `return_assoc` option.
1113
     */
1114
    public function getMultipleAudioFeatures(string|array $trackIds): array|object
1115
    {
1116
        $trackIds = $this->uriToId($trackIds, 'track');
2✔
1117
        $options = [
2✔
1118
            'ids' => $this->toCommaString($trackIds),
2✔
1119
        ];
2✔
1120

1121
        $uri = '/v1/audio-features';
2✔
1122

1123
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1124

1125
        return $this->lastResponse['body'];
2✔
1126
    }
1127

1128
    /**
1129
     * Get the current user’s currently playing track.
1130
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-the-users-currently-playing-track
1131
     *
1132
     * @param array|object $options Optional. Options for the track.
1133
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1134
     * - string|array additional_types Optional. Types of media to return info about.
1135
     *
1136
     * @return array|object The user's currently playing track. Type is controlled by the `return_assoc` option.
1137
     */
1138
    public function getMyCurrentTrack(array|object $options = []): array|object
1139
    {
1140
        $uri = '/v1/me/player/currently-playing';
2✔
1141
        $options = (array) $options;
2✔
1142

1143
        if (isset($options['additional_types'])) {
2✔
1144
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
2✔
1145
        }
1146

1147
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1148

1149
        return $this->lastResponse['body'];
2✔
1150
    }
1151

1152
    /**
1153
     * Get the current user’s devices.
1154
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-users-available-devices
1155
     *
1156
     * @return array|object The user's devices. Type is controlled by the `return_assoc` option.
1157
     */
1158
    public function getMyDevices(): array|object
1159
    {
1160
        $uri = '/v1/me/player/devices';
2✔
1161

1162
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
1163

1164
        return $this->lastResponse['body'];
2✔
1165
    }
1166

1167
    /**
1168
     * Get the current user’s current playback information.
1169
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-information-about-the-users-current-playback
1170
     *
1171
     * @param array|object $options Optional. Options for the info.
1172
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1173
     * - string|array additional_types Optional. Types of media to return info about.
1174
     *
1175
     * @return array|object The user's playback information. Type is controlled by the `return_assoc` option.
1176
     */
1177
    public function getMyCurrentPlaybackInfo(array|object $options = []): array|object
1178
    {
1179
        $uri = '/v1/me/player';
2✔
1180
        $options = (array) $options;
2✔
1181

1182
        if (isset($options['additional_types'])) {
2✔
1183
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
2✔
1184
        }
1185

1186
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1187

1188
        return $this->lastResponse['body'];
2✔
1189
    }
1190

1191

1192
    /**
1193
     * Get the current user’s playlists.
1194
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-list-of-current-users-playlists
1195
     *
1196
     * @param array|object $options Optional. Options for the playlists.
1197
     * - int limit Optional. Limit the number of playlists.
1198
     * - int offset Optional. Number of playlists to skip.
1199
     *
1200
     * @return array|object The user's playlists. Type is controlled by the `return_assoc` option.
1201
     */
1202
    public function getMyPlaylists(array|object $options = []): array|object
1203
    {
1204
        $uri = '/v1/me/playlists';
2✔
1205

1206
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1207

1208
        return $this->lastResponse['body'];
2✔
1209
    }
1210

1211
    /**
1212
     * Get the current user’s queue.
1213
     *
1214
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-queue
1215
     *
1216
     * @return array|object The currently playing song and queue. Type is controlled by the `return_assoc` option.
1217
     */
1218
    public function getMyQueue()
1219
    {
1220
        $uri = '/v1/me/player/queue';
2✔
1221

1222
        $this->lastResponse = $this->sendRequest('GET', $uri, []);
2✔
1223

1224
        return $this->lastResponse['body'];
2✔
1225
    }
1226

1227
    /**
1228
      * Get the current user’s recently played tracks.
1229
      * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-recently-played
1230
      *
1231
      * @param array|object $options Optional. Options for the tracks.
1232
      * - int limit Optional. Number of tracks to return.
1233
      * - string after Optional. Unix timestamp in ms (13 digits). Returns all items after this position.
1234
      * - string before Optional. Unix timestamp in ms (13 digits). Returns all items before this position.
1235
      *
1236
      * @return array|object The most recently played tracks. Type is controlled by the `return_assoc` option.
1237
      */
1238
    public function getMyRecentTracks(array|object $options = []): array|object
1239
    {
1240
        $uri = '/v1/me/player/recently-played';
2✔
1241

1242
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1243

1244
        return $this->lastResponse['body'];
2✔
1245
    }
1246

1247
    /**
1248
     * Get the current user’s saved albums.
1249
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-saved-albums
1250
     *
1251
     * @param array|object $options Optional. Options for the albums.
1252
     * - int limit Optional. Number of albums to return.
1253
     * - int offset Optional. Number of albums to skip.
1254
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1255
     *
1256
     * @return array|object The user's saved albums. Type is controlled by the `return_assoc` option.
1257
     */
1258
    public function getMySavedAlbums(array|object $options = []): array|object
1259
    {
1260
        $uri = '/v1/me/albums';
2✔
1261

1262
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1263

1264
        return $this->lastResponse['body'];
2✔
1265
    }
1266

1267
    /**
1268
     * Get the current user’s saved episodes.
1269
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-saved-episodes
1270
     *
1271
     * @param array|object $options Optional. Options for the episodes.
1272
     * - int limit Optional. Number of episodes to return.
1273
     * - int offset Optional. Number of episodes to skip.
1274
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1275
     *
1276
     * @return array|object The user's saved episodes. Type is controlled by the `return_assoc` option.
1277
     */
1278
    public function getMySavedEpisodes(array|object $options = []): array|object
1279
    {
1280
        $uri = '/v1/me/episodes';
2✔
1281

1282
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1283

1284
        return $this->lastResponse['body'];
2✔
1285
    }
1286

1287
    /**
1288
     * Get the current user’s saved tracks.
1289
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-saved-tracks
1290
     *
1291
     * @param array|object $options Optional. Options for the tracks.
1292
     * - int limit Optional. Limit the number of tracks.
1293
     * - int offset Optional. Number of tracks to skip.
1294
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1295
     *
1296
     * @return array|object The user's saved tracks. Type is controlled by the `return_assoc` option.
1297
     */
1298
    public function getMySavedTracks(array|object $options = []): array|object
1299
    {
1300
        $uri = '/v1/me/tracks';
2✔
1301

1302
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1303

1304
        return $this->lastResponse['body'];
2✔
1305
    }
1306

1307
    /**
1308
     * Get the current user’s saved shows.
1309
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-saved-shows
1310
     *
1311
     * @param array|object $options Optional. Options for the shows.
1312
     * - int limit Optional. Limit the number of shows.
1313
     * - int offset Optional. Number of shows to skip.
1314
     *
1315
     * @return array|object The user's saved shows. Type is controlled by the `return_assoc` option.
1316
     */
1317
    public function getMySavedShows(array|object $options = []): array|object
1318
    {
1319
        $uri = '/v1/me/shows';
2✔
1320

1321
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1322

1323
        return $this->lastResponse['body'];
2✔
1324
    }
1325

1326
    /**
1327
     * Get the current user's top tracks or artists.
1328
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-top-artists-and-tracks
1329
     *
1330
     * @param string $type The type to fetch, either 'artists' or 'tracks'.
1331
     * @param array $options Optional. Options for the results.
1332
     * - int limit Optional. Limit the number of results.
1333
     * - int offset Optional. Number of results to skip.
1334
     * - string time_range Optional. Over what time frame the data is calculated. See Spotify API docs for more info.
1335
     *
1336
     * @return array|object A list of the requested top entity. Type is controlled by the `return_assoc` option.
1337
     */
1338
    public function getMyTop(string $type, array|object $options = []): array|object
1339
    {
1340
        $uri = '/v1/me/top/' . $type;
2✔
1341

1342
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1343

1344
        return $this->lastResponse['body'];
2✔
1345
    }
1346

1347
    /**
1348
     * Get new releases.
1349
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-new-releases
1350
     *
1351
     * @param array|object $options Optional. Options for the items.
1352
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show items relevant to this country.
1353
     * - int limit Optional. Limit the number of items.
1354
     * - int offset Optional. Number of items to skip.
1355
     *
1356
     * @return array|object The new releases. Type is controlled by the `return_assoc` option.
1357
     */
1358
    public function getNewReleases(array|object $options = []): array|object
1359
    {
1360
        $uri = '/v1/browse/new-releases';
2✔
1361

1362
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1363

1364
        return $this->lastResponse['body'];
2✔
1365
    }
1366

1367
    /**
1368
     * Get a specific playlist.
1369
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlist
1370
     *
1371
     * @param string $playlistId ID or URI of the playlist.
1372
     * @param array|object $options Optional. Options for the playlist.
1373
     * - string|array fields Optional. A list of fields to return. See Spotify docs for more info.
1374
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1375
     * - string|array additional_types Optional. Types of media to return info about.
1376
     *
1377
     * @return array|object The user's playlist. Type is controlled by the `return_assoc` option.
1378
     */
1379
    public function getPlaylist(string $playlistId, array|object $options = []): array|object
1380
    {
1381
        $options = (array) $options;
2✔
1382

1383
        if (isset($options['fields'])) {
2✔
1384
            $options['fields'] = $this->toCommaString($options['fields']);
2✔
1385
        }
1386

1387
        if (isset($options['additional_types'])) {
2✔
1388
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
×
1389
        }
1390

1391
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
1392

1393
        $uri = '/v1/playlists/' . $playlistId;
2✔
1394

1395
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1396

1397
        return $this->lastResponse['body'];
2✔
1398
    }
1399

1400
    /**
1401
     * Get a playlist's cover image.
1402
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlist-cover
1403
     *
1404
     * @param string $playlistId ID or URI of the playlist.
1405
     *
1406
     * @return array|object The playlist cover image. Type is controlled by the `return_assoc` option.
1407
     */
1408
    public function getPlaylistImage(string $playlistId): array|object
1409
    {
1410
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
1411

1412
        $uri = '/v1/playlists/' . $playlistId . '/images';
2✔
1413

1414
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
1415

1416
        return $this->lastResponse['body'];
2✔
1417
    }
1418

1419
    /**
1420
     * Get the tracks in a playlist.
1421
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlists-tracks
1422
     *
1423
     * @param string $playlistId ID or URI of the playlist.
1424
     * @param array|object $options Optional. Options for the tracks.
1425
     * - string|array fields Optional. A list of fields to return. See Spotify docs for more info.
1426
     * - int limit Optional. Limit the number of tracks.
1427
     * - int offset Optional. Number of tracks to skip.
1428
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1429
     * - string|array additional_types Optional. Types of media to return info about.
1430
     *
1431
     * @return array|object The tracks in the playlist. Type is controlled by the `return_assoc` option.
1432
     */
1433
    public function getPlaylistTracks(string $playlistId, array|object $options = []): array|object
1434
    {
1435
        $options = (array) $options;
2✔
1436

1437
        if (isset($options['fields'])) {
2✔
1438
            $options['fields'] = $this->toCommaString($options['fields']);
2✔
1439
        }
1440

1441
        if (isset($options['additional_types'])) {
2✔
1442
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
2✔
1443
        }
1444

1445
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
1446

1447
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
2✔
1448

1449
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1450

1451
        return $this->lastResponse['body'];
2✔
1452
    }
1453

1454
    /**
1455
     * Get recommendations based on artists, tracks, or genres.
1456
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-recommendations
1457
     *
1458
     * @param array|object $options Optional. Options for the recommendations.
1459
     * - int limit Optional. Limit the number of recommendations.
1460
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1461
     * - mixed max_* Optional. Max value for one of the tunable track attributes.
1462
     * - mixed min_* Optional. Min value for one of the tunable track attributes.
1463
     * - array seed_artists Artist IDs to seed by.
1464
     * - array seed_genres Genres to seed by. Call SpotifyWebAPI::getGenreSeeds() for a complete list.
1465
     * - array seed_tracks Track IDs to seed by.
1466
     * - mixed target_* Optional. Target value for one of the tunable track attributes.
1467
     *
1468
     * @return array|object The requested recommendations. Type is controlled by the `return_assoc` option.
1469
     */
1470
    public function getRecommendations(array|object $options = []): array|object
1471
    {
1472
        $options = (array) $options;
2✔
1473

1474
        array_walk($options, function (&$value, $key) {
2✔
1475
            if (substr($key, 0, 5) == 'seed_') {
2✔
1476
                $value = $this->toCommaString($value);
2✔
1477
            }
1478
        });
2✔
1479

1480
        $uri = '/v1/recommendations';
2✔
1481

1482
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1483

1484
        return $this->lastResponse['body'];
2✔
1485
    }
1486

1487
    /**
1488
     * Get the Request object in use.
1489
     *
1490
     * @return Request The Request object in use.
1491
     */
1492
    public function getRequest(): Request
1493
    {
1494
        return $this->request;
2✔
1495
    }
1496

1497
    /**
1498
     * Get a show.
1499
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-show
1500
     *
1501
     * @param string $showId ID or URI of the show.
1502
     * @param array|object $options Optional. Options for the show.
1503
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to shows available in that market.
1504
     *
1505
     * @return array|object The requested show. Type is controlled by the `return_assoc` option.
1506
     */
1507
    public function getShow(string $showId, array|object $options = []): array|object
1508
    {
1509
        $showId = $this->uriToId($showId, 'show');
2✔
1510
        $uri = '/v1/shows/' . $showId;
2✔
1511

1512
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1513

1514
        return $this->lastResponse['body'];
2✔
1515
    }
1516

1517
    /**
1518
     * Get a show's episodes.
1519
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-shows-episodes
1520
     *
1521
     * @param string $showId ID or URI of the album.
1522
     * @param array|object $options Optional. Options for the episodes.
1523
     * - int limit Optional. Limit the number of episodes.
1524
     * - int offset Optional. Number of episodes to skip.
1525
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1526
     *
1527
     * @return array|object The requested show episodes. Type is controlled by the `return_assoc` option.
1528
     */
1529
    public function getShowEpisodes(string $showId, array|object $options = []): array|object
1530
    {
1531
        $showId = $this->uriToId($showId, 'show');
2✔
1532
        $uri = '/v1/shows/' . $showId . '/episodes';
2✔
1533

1534
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1535

1536
        return $this->lastResponse['body'];
2✔
1537
    }
1538

1539
    /**
1540
     * Get multiple shows.
1541
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-shows
1542
     *
1543
     * @param string|array $showIds IDs or URIs of the shows.
1544
     * @param array|object $options Optional. Options for the shows.
1545
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to shows available in that market.
1546
     *
1547
     * @return array|object The requested shows. Type is controlled by the `return_assoc` option.
1548
     */
1549
    public function getShows(string|array $showIds, array|object $options = []): array|object
1550
    {
1551
        $showIds = $this->uriToId($showIds, 'show');
2✔
1552
        $options = array_merge((array) $options, [
2✔
1553
            'ids' => $this->toCommaString($showIds),
2✔
1554
        ]);
2✔
1555

1556
        $uri = '/v1/shows/';
2✔
1557

1558
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1559

1560
        return $this->lastResponse['body'];
2✔
1561
    }
1562

1563
    /**
1564
     * Get a track.
1565
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-track
1566
     *
1567
     * @param string $trackId ID or URI of the track.
1568
     * @param array|object $options Optional. Options for the track.
1569
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1570
     *
1571
     * @return array|object The requested track. Type is controlled by the `return_assoc` option.
1572
     */
1573
    public function getTrack(string $trackId, array|object $options = []): array|object
1574
    {
1575
        $trackId = $this->uriToId($trackId, 'track');
8✔
1576
        $uri = '/v1/tracks/' . $trackId;
8✔
1577

1578
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
8✔
1579

1580
        return $this->lastResponse['body'];
8✔
1581
    }
1582

1583
    /**
1584
     * Get multiple tracks.
1585
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-tracks
1586
     *
1587
     * @param array $trackIds IDs or URIs of the tracks.
1588
     * @param array|object $options Optional. Options for the tracks.
1589
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1590
     *
1591
     * @return array|object The requested tracks. Type is controlled by the `return_assoc` option.
1592
     */
1593
    public function getTracks(array $trackIds, array|object $options = []): array|object
1594
    {
1595
        $trackIds = $this->uriToId($trackIds, 'track');
2✔
1596
        $options = array_merge((array) $options, [
2✔
1597
            'ids' => $this->toCommaString($trackIds),
2✔
1598
        ]);
2✔
1599

1600
        $uri = '/v1/tracks/';
2✔
1601

1602
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1603

1604
        return $this->lastResponse['body'];
2✔
1605
    }
1606

1607
    /**
1608
     * Get a user.
1609
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-profile
1610
     *
1611
     * @param string $userId ID or URI of the user.
1612
     *
1613
     * @return array|object The requested user. Type is controlled by the `return_assoc` option.
1614
     */
1615
    public function getUser(string $userId): array|object
1616
    {
1617
        $userId = $this->uriToId($userId, 'user');
2✔
1618
        $uri = '/v1/users/' . $userId;
2✔
1619

1620
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
1621

1622
        return $this->lastResponse['body'];
2✔
1623
    }
1624

1625
    /**
1626
     * Get the artists followed by the current user.
1627
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-followed
1628
     *
1629
     * @param array|object $options Optional. Options for the artists.
1630
     * - int limit Optional. Limit the number of artists returned.
1631
     * - string after Optional. The last artist ID retrieved from the previous request.
1632
     *
1633
     * @return array|object A list of artists. Type is controlled by the `return_assoc` option.
1634
     */
1635
    public function getUserFollowedArtists(array|object $options = []): array|object
1636
    {
1637
        $options = (array) $options;
2✔
1638

1639
        if (!isset($options['type'])) {
2✔
1640
            $options['type'] = 'artist'; // Undocumented until more values are supported.
2✔
1641
        }
1642

1643
        $uri = '/v1/me/following';
2✔
1644

1645
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1646

1647
        return $this->lastResponse['body'];
2✔
1648
    }
1649

1650
    /**
1651
     * Get a user's playlists.
1652
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-list-users-playlists
1653
     *
1654
     * @param string $userId ID or URI of the user.
1655
     * @param array|object $options Optional. Options for the tracks.
1656
     * - int limit Optional. Limit the number of tracks.
1657
     * - int offset Optional. Number of tracks to skip.
1658
     *
1659
     * @return array|object The user's playlists. Type is controlled by the `return_assoc` option.
1660
     */
1661
    public function getUserPlaylists(string $userId, array|object $options = []): array|object
1662
    {
1663
        $userId = $this->uriToId($userId, 'user');
2✔
1664
        $uri = '/v1/users/' . $userId . '/playlists';
2✔
1665

1666
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1667

1668
        return $this->lastResponse['body'];
2✔
1669
    }
1670

1671
    /**
1672
     * Get the currently authenticated user.
1673
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
1674
     *
1675
     * @return array|object The currently authenticated user. Type is controlled by the `return_assoc` option.
1676
     */
1677
    public function me(): array|object
1678
    {
1679
        $uri = '/v1/me';
2✔
1680

1681
        $this->lastResponse = $this->sendRequest('GET', $uri);
2✔
1682

1683
        return $this->lastResponse['body'];
2✔
1684
    }
1685

1686
    /**
1687
     * Check if albums are saved in the current user's Spotify library.
1688
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-albums
1689
     *
1690
     * @param string|array $albums Album IDs or URIs to check for.
1691
     *
1692
     * @return array Whether each album is saved.
1693
     */
1694
    public function myAlbumsContains(string|array $albums): array
1695
    {
1696
        $albums = $this->uriToId($albums, 'album');
2✔
1697
        $albums = $this->toCommaString($albums);
2✔
1698

1699
        $options = [
2✔
1700
            'ids' => $albums,
2✔
1701
        ];
2✔
1702

1703
        $uri = '/v1/me/albums/contains';
2✔
1704

1705
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1706

1707
        return $this->lastResponse['body'];
2✔
1708
    }
1709

1710
    /**
1711
     * Check if episodes are saved in the current user's Spotify library.
1712
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-episodes
1713
     *
1714
     * @param string|array $episodes Episode IDs or URIs to check for.
1715
     *
1716
     * @return array Whether each episode is saved.
1717
     */
1718
    public function myEpisodesContains(string|array $episodes): array
1719
    {
1720
        $episodes = $this->uriToId($episodes, 'episode');
2✔
1721
        $episodes = $this->toCommaString($episodes);
2✔
1722

1723
        $options = [
2✔
1724
            'ids' => $episodes,
2✔
1725
        ];
2✔
1726

1727
        $uri = '/v1/me/episodes/contains';
2✔
1728

1729
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1730

1731
        return $this->lastResponse['body'];
2✔
1732
    }
1733

1734
    /**
1735
     * Check if shows are saved in the current user's Spotify library.
1736
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-shows
1737
     *
1738
     * @param string|array $shows Show IDs or URIs to check for.
1739
     *
1740
     * @return array Whether each show is saved.
1741
     */
1742
    public function myShowsContains(string|array $shows): array
1743
    {
1744
        $shows = $this->uriToId($shows, 'show');
2✔
1745
        $shows = $this->toCommaString($shows);
2✔
1746

1747
        $options = [
2✔
1748
            'ids' => $shows,
2✔
1749
        ];
2✔
1750

1751
        $uri = '/v1/me/shows/contains';
2✔
1752

1753
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1754

1755
        return $this->lastResponse['body'];
2✔
1756
    }
1757

1758
    /**
1759
     * Check if tracks are saved in the current user's Spotify library.
1760
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-tracks
1761
     *
1762
     * @param string|array $tracks Track IDs or URIs to check for.
1763
     *
1764
     * @return array Whether each track is saved.
1765
     */
1766
    public function myTracksContains(string|array $tracks): array
1767
    {
1768
        $tracks = $this->uriToId($tracks, 'track');
2✔
1769
        $tracks = $this->toCommaString($tracks);
2✔
1770

1771
        $options = [
2✔
1772
            'ids' => $tracks,
2✔
1773
        ];
2✔
1774

1775
        $uri = '/v1/me/tracks/contains';
2✔
1776

1777
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
1778

1779
        return $this->lastResponse['body'];
2✔
1780
    }
1781

1782
    /**
1783
     * Play the next track in the current users's queue.
1784
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/skip-users-playback-to-next-track
1785
     *
1786
     * @param string $deviceId Optional. ID of the device to target.
1787
     *
1788
     * @return bool Whether the track was successfully skipped.
1789
     */
1790
    public function next(string $deviceId = ''): bool
1791
    {
1792
        $uri = '/v1/me/player/next';
2✔
1793

1794
        // We need to manually append data to the URI since it's a POST request
1795
        if ($deviceId) {
2✔
1796
            $uri = $uri . '?device_id=' . $deviceId;
2✔
1797
        }
1798

1799
        $this->lastResponse = $this->sendRequest('POST', $uri);
2✔
1800

1801
        return $this->lastResponse['status'] == 204;
2✔
1802
    }
1803

1804
    /**
1805
     * Pause playback for the current user.
1806
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/pause-a-users-playback
1807
     *
1808
     * @param string $deviceId Optional. ID of the device to pause on.
1809
     *
1810
     * @return bool Whether the playback was successfully paused.
1811
     */
1812
    public function pause(string $deviceId = ''): bool
1813
    {
1814
        $uri = '/v1/me/player/pause';
2✔
1815

1816
        // We need to manually append data to the URI since it's a PUT request
1817
        if ($deviceId) {
2✔
1818
            $uri = $uri . '?device_id=' . $deviceId;
2✔
1819
        }
1820

1821
        $this->lastResponse = $this->sendRequest('PUT', $uri);
2✔
1822

1823
        return $this->lastResponse['status'] == 204;
2✔
1824
    }
1825

1826
    /**
1827
     * Start playback for the current user.
1828
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/start-a-users-playback
1829
     *
1830
     * @param string $deviceId Optional. ID of the device to play on.
1831
     * @param array|object $options Optional. Options for the playback.
1832
     * - string context_uri Optional. URI of the context to play, for example an album.
1833
     * - array uris Optional. Spotify track URIs to play.
1834
     * - object offset Optional. Indicates from where in the context playback should start.
1835
     * - int position_ms. Optional. Indicates the position to start playback from.
1836
     *
1837
     * @return bool Whether the playback was successfully started.
1838
     */
1839
    public function play(string $deviceId = '', array|object $options = []): bool
1840
    {
1841
        $options = $options ? json_encode($options) : null;
2✔
1842

1843
        $headers = [
2✔
1844
            'Content-Type' => 'application/json',
2✔
1845
        ];
2✔
1846

1847
        $uri = '/v1/me/player/play';
2✔
1848

1849
        // We need to manually append data to the URI since it's a PUT request
1850
        if ($deviceId) {
2✔
1851
            $uri = $uri . '?device_id=' . $deviceId;
2✔
1852
        }
1853

1854
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
2✔
1855

1856
        return $this->lastResponse['status'] == 204;
2✔
1857
    }
1858

1859
    /**
1860
     * Play the previous track in the current users's queue.
1861
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/skip-users-playback-to-previous-track
1862
     *
1863
     * @param string $deviceId Optional. ID of the device to target.
1864
     *
1865
     * @return bool Whether the track was successfully skipped.
1866
     */
1867
    public function previous(string $deviceId = ''): bool
1868
    {
1869
        $uri = '/v1/me/player/previous';
2✔
1870

1871
        // We need to manually append data to the URI since it's a POST request
1872
        if ($deviceId) {
2✔
1873
            $uri = $uri . '?device_id=' . $deviceId;
2✔
1874
        }
1875

1876
        $this->lastResponse = $this->sendRequest('POST', $uri);
2✔
1877

1878
        return $this->lastResponse['status'] == 204;
2✔
1879
    }
1880

1881
    /**
1882
     * Add an item to the queue.
1883
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/add-to-queue
1884
     *
1885
     * @param string $trackUri Required. Track ID, track URI or episode URI to queue.
1886
     * @param string $deviceId Optional. ID of the device to target.
1887
     *
1888
     * @return bool Whether the track was successfully queued.
1889
     */
1890
    public function queue(string $trackUri, string $deviceId = ''): bool
1891
    {
1892
        $uri = '/v1/me/player/queue?uri=' . $this->idToUri($trackUri, 'track');
4✔
1893

1894
        // We need to manually append data to the URI since it's a POST request
1895
        if ($deviceId) {
4✔
1896
            $uri = $uri . '&device_id=' . $deviceId;
4✔
1897
        }
1898

1899
        $this->lastResponse = $this->sendRequest('POST', $uri);
4✔
1900

1901
        return $this->lastResponse['status'] == 204;
4✔
1902
    }
1903

1904
    /**
1905
     * Reorder the tracks in a playlist.
1906
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/reorder-or-replace-playlists-tracks
1907
     *
1908
     * @param string $playlistId ID or URI of the playlist.
1909
     * @param array|object $options Options for the new tracks.
1910
     * - int range_start Required. Position of the first track to be reordered.
1911
     * - int range_length Optional. The amount of tracks to be reordered.
1912
     * - int insert_before Required. Position where the tracks should be inserted.
1913
     * - string snapshot_id Optional. The playlist's snapshot ID.
1914
     *
1915
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully reordered.
1916
     */
1917
    public function reorderPlaylistTracks(string $playlistId, array|object $options): string|bool
1918
    {
1919
        $options = json_encode($options);
2✔
1920

1921
        $headers = [
2✔
1922
            'Content-Type' => 'application/json',
2✔
1923
        ];
2✔
1924

1925
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
1926

1927
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
2✔
1928

1929
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
2✔
1930

1931
        return $this->getSnapshotId($this->lastResponse['body']);
2✔
1932
    }
1933

1934
    /**
1935
     * Set repeat mode for the current user’s playback.
1936
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/set-repeat-mode-on-users-playback
1937
     *
1938
     * @param array|object $options Optional. Options for the playback repeat mode.
1939
     * - string state Required. The repeat mode. See Spotify docs for possible values.
1940
     * - string device_id Optional. ID of the device to target.
1941
     *
1942
     * @return bool Whether the playback repeat mode was successfully changed.
1943
     */
1944
    public function repeat(array|object $options): bool
1945
    {
1946
        $options = http_build_query($options, '', '&');
2✔
1947

1948
        // We need to manually append data to the URI since it's a PUT request
1949
        $uri = '/v1/me/player/repeat?' . $options;
2✔
1950

1951
        $this->lastResponse = $this->sendRequest('PUT', $uri);
2✔
1952

1953
        return $this->lastResponse['status'] == 204;
2✔
1954
    }
1955

1956
    /**
1957
     * Replace all tracks in a playlist with new ones.
1958
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/reorder-or-replace-playlists-tracks
1959
     *
1960
     * @param string $playlistId ID or URI of the playlist.
1961
     * @param string|array $tracks IDs, track URIs, or episode URIs to replace with.
1962
     *
1963
     * @return bool Whether the tracks was successfully replaced.
1964
     */
1965
    public function replacePlaylistTracks(string $playlistId, string|array $tracks): bool
1966
    {
1967
        $tracks = $this->idToUri($tracks, 'track');
2✔
1968
        $tracks = json_encode([
2✔
1969
            'uris' => (array) $tracks,
2✔
1970
        ]);
2✔
1971

1972
        $headers = [
2✔
1973
            'Content-Type' => 'application/json',
2✔
1974
        ];
2✔
1975

1976
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
1977

1978
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
2✔
1979

1980
        $this->lastResponse = $this->sendRequest('PUT', $uri, $tracks, $headers);
2✔
1981

1982
        return $this->lastResponse['status'] == 201;
2✔
1983
    }
1984

1985
    /**
1986
     * Search for an item.
1987
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/search
1988
     *
1989
     * @param string $query The term to search for.
1990
     * @param string|array $type The type of item to search for.
1991
     * @param array|object $options Optional. Options for the search.
1992
     * - string market Optional. Limit the results to items that are playable in this market, for example SE.
1993
     * - int limit Optional. Limit the number of items.
1994
     * - int offset Optional. Number of items to skip.
1995
     * - string include_external Optional. Whether or not to mark externally hosted content as playable.
1996
     *
1997
     * @return array|object The search results. Type is controlled by the `return_assoc` option.
1998
     */
1999
    public function search(string $query, string|array $type, array|object $options = []): array|object
2000
    {
2001
        $options = array_merge((array) $options, [
2✔
2002
            'q' => $query,
2✔
2003
            'type' => $this->toCommaString($type),
2✔
2004
        ]);
2✔
2005

2006
        $uri = '/v1/search';
2✔
2007

2008
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
2009

2010
        return $this->lastResponse['body'];
2✔
2011
    }
2012

2013
    /**
2014
     * Change playback position for the current user.
2015
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/seek-to-position-in-currently-playing-track
2016
     *
2017
     * @param array|object $options Optional. Options for the playback seeking.
2018
     * - string position_ms Required. The position in milliseconds to seek to.
2019
     * - string device_id Optional. ID of the device to target.
2020
     *
2021
     * @return bool Whether the playback position was successfully changed.
2022
     */
2023
    public function seek(array|object $options): bool
2024
    {
2025
        $options = http_build_query($options, '', '&');
2✔
2026

2027
        // We need to manually append data to the URI since it's a PUT request
2028
        $uri = '/v1/me/player/seek?' . $options;
2✔
2029

2030
        $this->lastResponse = $this->sendRequest('PUT', $uri);
2✔
2031

2032
        return $this->lastResponse['status'] == 204;
2✔
2033
    }
2034

2035
    /**
2036
     * Set the access token to use.
2037
     *
2038
     * @param string $accessToken The access token.
2039
     *
2040
     * @return self
2041
     */
2042
    public function setAccessToken(string $accessToken): self
2043
    {
2044
        $this->accessToken = $accessToken;
4✔
2045

2046
        return $this;
4✔
2047
    }
2048

2049
    /**
2050
     * Set options
2051
     *
2052
     * @param array|object $options Options to set.
2053
     *
2054
     * @return self
2055
     */
2056
    public function setOptions(array|object $options): self
2057
    {
2058
        $this->options = array_merge($this->options, (array) $options);
188✔
2059

2060
        return $this;
188✔
2061
    }
2062

2063
    /**
2064
     * Set the Session object to use.
2065
     *
2066
     * @param Session $session The Session object.
2067
     *
2068
     * @return self
2069
     */
2070
    public function setSession(?Session $session): self
2071
    {
2072
        $this->session = $session;
188✔
2073

2074
        return $this;
188✔
2075
    }
2076

2077
    /**
2078
     * Set shuffle mode for the current user’s playback.
2079
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/toggle-shuffle-for-users-playback
2080
     *
2081
     * @param array|object $options Optional. Options for the playback shuffle mode.
2082
     * - bool state Required. The shuffle mode. See Spotify docs for possible values.
2083
     * - string device_id Optional. ID of the device to target.
2084
     *
2085
     * @return bool Whether the playback shuffle mode was successfully changed.
2086
     */
2087
    public function shuffle(array|object $options): bool
2088
    {
2089
        $options = array_merge((array) $options, [
2✔
2090
            'state' => $options['state'] ? 'true' : 'false',
2✔
2091
        ]);
2✔
2092

2093
        $options = http_build_query($options, '', '&');
2✔
2094

2095
        // We need to manually append data to the URI since it's a PUT request
2096
        $uri = '/v1/me/player/shuffle?' . $options;
2✔
2097

2098
        $this->lastResponse = $this->sendRequest('PUT', $uri);
2✔
2099

2100
        return $this->lastResponse['status'] == 204;
2✔
2101
    }
2102

2103
    /**
2104
     * Remove the current user as a follower of one or more artists or other Spotify users.
2105
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/unfollow-artists-users
2106
     *
2107
     * @param string $type The type to check: either 'artist' or 'user'.
2108
     * @param string|array $ids IDs or URIs of the users or artists to unfollow.
2109
     *
2110
     * @return bool Whether the artists or users were successfully unfollowed.
2111
     */
2112
    public function unfollowArtistsOrUsers(string $type, string|array $ids): bool
2113
    {
2114
        $ids = $this->uriToId($ids, $type);
2✔
2115
        $ids = json_encode([
2✔
2116
            'ids' => (array) $ids,
2✔
2117
        ]);
2✔
2118

2119
        $headers = [
2✔
2120
            'Content-Type' => 'application/json',
2✔
2121
        ];
2✔
2122

2123
        // We need to manually append data to the URI since it's a DELETE request
2124
        $uri = '/v1/me/following?type=' . $type;
2✔
2125

2126
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $ids, $headers);
2✔
2127

2128
        return $this->lastResponse['status'] == 204;
2✔
2129
    }
2130

2131
    /**
2132
     * Remove the current user as a follower of a playlist.
2133
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/unfollow-playlist
2134
     *
2135
     * @param string $playlistId ID or URI of the playlist to unfollow.
2136
     *
2137
     * @return bool Whether the playlist was successfully unfollowed.
2138
     */
2139
    public function unfollowPlaylist(string $playlistId): bool
2140
    {
2141
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
2142
        $uri = '/v1/playlists/' . $playlistId . '/followers';
2✔
2143

2144
        $this->lastResponse = $this->sendRequest('DELETE', $uri);
2✔
2145

2146
        return $this->lastResponse['status'] == 200;
2✔
2147
    }
2148

2149
    /**
2150
     * Update the details of a playlist.
2151
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/change-playlist-details
2152
     *
2153
     * @param string $playlistId ID or URI of the playlist to update.
2154
     * @param array|object $options Options for the playlist.
2155
     * - bool collaborative Optional. Whether the playlist should be collaborative or not.
2156
     * - string description Optional. Description of the playlist.
2157
     * - string name Optional. Name of the playlist.
2158
     * - bool public Optional. Whether the playlist should be public or not.
2159
     *
2160
     * @return bool Whether the playlist was successfully updated.
2161
     */
2162
    public function updatePlaylist(string $playlistId, array|object $options): bool
2163
    {
2164
        $options = json_encode($options);
2✔
2165

2166
        $headers = [
2✔
2167
            'Content-Type' => 'application/json',
2✔
2168
        ];
2✔
2169

2170
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
2171

2172
        $uri = '/v1/playlists/' . $playlistId;
2✔
2173

2174
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
2✔
2175

2176
        return $this->lastResponse['status'] == 200;
2✔
2177
    }
2178

2179
    /**
2180
     * Update the image of a playlist.
2181
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/upload-custom-playlist-cover
2182
     *
2183
     * @param string $playlistId ID or URI of the playlist to update.
2184
     * @param string $imageData Base64 encoded JPEG image data, maximum 256 KB in size.
2185
     *
2186
     * @return bool Whether the playlist was successfully updated.
2187
     */
2188
    public function updatePlaylistImage(string $playlistId, string $imageData): bool
2189
    {
2190
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
2191

2192
        $uri = '/v1/playlists/' . $playlistId . '/images';
2✔
2193

2194
        $this->lastResponse = $this->sendRequest('PUT', $uri, $imageData);
2✔
2195

2196
        return $this->lastResponse['status'] == 202;
2✔
2197
    }
2198

2199
    /**
2200
     * Check if a set of users are following a playlist.
2201
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-if-user-follows-playlist
2202
     *
2203
     * @param string $playlistId ID or URI of the playlist.
2204
     * @param array|object $options Options for the check.
2205
     * - ids string|array Required. IDs or URIs of the users to check for.
2206
     *
2207
     * @return array Whether each user is following the playlist.
2208
     */
2209
    public function usersFollowPlaylist(string $playlistId, array|object $options): array
2210
    {
2211
        $options = (array) $options;
2✔
2212

2213
        if (isset($options['ids'])) {
2✔
2214
            $options['ids'] = $this->uriToId($options['ids'], 'user');
2✔
2215
            $options['ids'] = $this->toCommaString($options['ids']);
2✔
2216
        }
2217

2218
        $playlistId = $this->uriToId($playlistId, 'playlist');
2✔
2219

2220
        $uri = '/v1/playlists/' . $playlistId . '/followers/contains';
2✔
2221

2222
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
2✔
2223

2224
        return $this->lastResponse['body'];
2✔
2225
    }
2226
}
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

© 2026 Coveralls, Inc