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

jwilsson / spotify-web-api-php / 20206432806

14 Dec 2025 10:12AM UTC coverage: 97.919% (-0.8%) from 98.747%
20206432806

push

github

jwilsson
Fix faulty proxy header detection regex

1 of 1 new or added line in 1 file covered. (100.0%)

11 existing lines in 2 files now uncovered.

753 of 769 relevant lines covered (97.92%)

16.57 hits per line

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

97.92
/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
        'default_headers' => [],
15
        'return_assoc' => false,
16
    ];
17
    protected ?Request $request = null;
18
    protected ?Session $session = null;
19

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

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

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

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

53
        return $headers;
285✔
54
    }
55

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

67
        return $body['snapshot_id'] ?? false;
21✔
68
    }
69

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

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

87
            return $id;
15✔
88
        }, (array) $ids);
18✔
89

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

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

121
        try {
122
            $headers = $this->authHeaders($headers);
285✔
123

124
            return $this->request->api($method, $uri, $parameters, $headers);
285✔
UNCOV
125
        } catch (SpotifyWebAPIException $e) {
×
UNCOV
126
            if ($this->options['auto_refresh'] && $e->hasExpiredToken()) {
×
UNCOV
127
                $result = $this->session->refreshAccessToken();
×
128

UNCOV
129
                if (!$result) {
×
130
                    throw new SpotifyWebAPIException('Could not refresh access token.');
×
131
                }
132

UNCOV
133
                return $this->sendRequest($method, $uri, $parameters, $headers);
×
UNCOV
134
            } elseif ($this->options['auto_retry'] && $e->isRateLimited()) {
×
UNCOV
135
                ['headers' => $lastHeaders] = $this->request->getLastResponse();
×
136

UNCOV
137
                sleep((int) $lastHeaders['retry-after']);
×
138

UNCOV
139
                return $this->sendRequest($method, $uri, $parameters, $headers);
×
140
            }
141

142
            throw $e;
×
143
        }
144
    }
145

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

159
        return $value;
3✔
160
    }
161

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

174
        $uriIds = array_map(function ($id) use ($type) {
180✔
175
            return str_replace($type, '', $id);
180✔
176
        }, (array) $uriIds);
180✔
177

178
        return count($uriIds) == 1 ? $uriIds[0] : $uriIds;
180✔
179
    }
180

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

196
        $headers = [
3✔
197
            'Content-Type' => 'application/json',
3✔
198
        ];
3✔
199

200
        $uri = '/v1/me/albums';
3✔
201

202
        $this->lastResponse = $this->sendRequest('PUT', $uri, $albums, $headers);
3✔
203

204
        return $this->lastResponse['status'] == 200;
3✔
205
    }
206

207
    /**
208
     * Add episodes to the current user's Spotify library.
209
     * https://developer.spotify.com/documentation/web-api/reference/save-episodes-user
210
     *
211
     * @param string|array $episodes Episode IDs or URIs to add.
212
     *
213
     * @return bool Whether the episodes was successfully added.
214
     */
215
    public function addMyEpisodes(string|array $episodes): bool
216
    {
217
        $episodes = $this->uriToId($episodes, 'episode');
3✔
218
        $episodes = json_encode([
3✔
219
            'ids' => (array) $episodes,
3✔
220
        ]);
3✔
221

222
        $headers = [
3✔
223
            'Content-Type' => 'application/json',
3✔
224
        ];
3✔
225

226
        $uri = '/v1/me/episodes';
3✔
227

228
        $this->lastResponse = $this->sendRequest('PUT', $uri, $episodes, $headers);
3✔
229

230
        return $this->lastResponse['status'] == 200;
3✔
231
    }
232

233
    /**
234
     * Add shows to the current user's Spotify library.
235
     * https://developer.spotify.com/documentation/web-api/reference/save-shows-user
236
     *
237
     * @param string|array $shows Show IDs or URIs to add.
238
     *
239
     * @return bool Whether the shows was successfully added.
240
     */
241
    public function addMyShows(string|array $shows): bool
242
    {
243
        $shows = $this->uriToId($shows, 'show');
3✔
244
        $shows = json_encode([
3✔
245
            'ids' => (array) $shows,
3✔
246
        ]);
3✔
247

248
        $headers = [
3✔
249
            'Content-Type' => 'application/json',
3✔
250
        ];
3✔
251

252
        $uri = '/v1/me/shows';
3✔
253

254
        $this->lastResponse = $this->sendRequest('PUT', $uri, $shows, $headers);
3✔
255

256
        return $this->lastResponse['status'] == 200;
3✔
257
    }
258

259
    /**
260
     * Add tracks to the current user's Spotify library.
261
     * https://developer.spotify.com/documentation/web-api/reference/save-tracks-user
262
     *
263
     * @param array|object $tracks Track IDs or URIs to add. One of "ids" or "timestamped_ids" key must be present.
264
     * - array ids Optional. An array of track IDs or URIs.
265
     * - array timestamped_ids Optional. An array of objects containing track IDs or URIs and added_at timestamp.
266
     *
267
     * @return bool Whether the tracks was successfully added.
268
     */
269
    public function addMyTracks(array|object $tracks): bool
270
    {
271
        $tracks = (array) $tracks;
6✔
272

273
        if (isset($tracks['ids'])) {
6✔
274
            $tracks = (array) $this->uriToId($tracks['ids'], 'track');
3✔
275
            $options = json_encode([
3✔
276
                'ids' => $tracks,
3✔
277
            ]);
3✔
278
        } elseif (isset($tracks['timestamped_ids'])) {
3✔
279
            $tracks = array_map(function ($item) {
3✔
280
                $item['id'] = $this->uriToId($item['id'], 'track');
3✔
281

282
                return $item;
3✔
283
            }, $tracks['timestamped_ids']);
3✔
284

285
            $options = json_encode([
3✔
286
                'timestamped_ids' => $tracks,
3✔
287
            ]);
3✔
288
        }
289

290
        $headers = [
6✔
291
            'Content-Type' => 'application/json',
6✔
292
        ];
6✔
293

294
        $uri = '/v1/me/tracks';
6✔
295

296
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
6✔
297

298
        return $this->lastResponse['status'] == 200;
6✔
299
    }
300

301
    /**
302
     * Add tracks to a playlist.
303
     * https://developer.spotify.com/documentation/web-api/reference/add-tracks-to-playlist
304
     *
305
     * @param string $playlistId ID of the playlist to add tracks to.
306
     * @param string|array $tracks Track IDs, track URIs, and episode URIs to add.
307
     * @param array|object $options Optional. Options for the new tracks.
308
     * - int position Optional. Zero-based track position in playlist. Tracks will be appended if omitted or false.
309
     *
310
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully added.
311
     */
312
    public function addPlaylistTracks(
313
        string $playlistId,
314
        string|array $tracks,
315
        array|object $options = [],
316
    ): string|bool {
317
        $options = array_merge((array) $options, [
6✔
318
            'uris' => (array) $this->idToUri($tracks, 'track'),
6✔
319
        ]);
6✔
320

321
        $options = json_encode($options);
6✔
322

323
        $headers = [
6✔
324
            'Content-Type' => 'application/json',
6✔
325
        ];
6✔
326

327
        $playlistId = $this->uriToId($playlistId, 'playlist');
6✔
328

329
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
6✔
330

331
        $this->lastResponse = $this->sendRequest('POST', $uri, $options, $headers);
6✔
332

333
        return $this->getSnapshotId($this->lastResponse['body']);
6✔
334
    }
335

336
    /**
337
     * Change the current user's playback device.
338
     * https://developer.spotify.com/documentation/web-api/reference/transfer-a-users-playback
339
     *
340
     * @param array|object $options Options for the playback transfer.
341
     * - string|array device_ids Required. ID of the device to switch to.
342
     * - bool play Optional. Whether to start playing on the new device
343
     *
344
     * @return bool Whether the playback device was successfully changed.
345
     */
346
    public function changeMyDevice(array|object $options): bool
347
    {
348
        $options = array_merge((array) $options, [
3✔
349
            'device_ids' => (array) $options['device_ids'],
3✔
350
        ]);
3✔
351

352
        $options = json_encode($options);
3✔
353

354
        $headers = [
3✔
355
            'Content-Type' => 'application/json',
3✔
356
        ];
3✔
357

358
        $uri = '/v1/me/player';
3✔
359

360
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
3✔
361

362
        return $this->lastResponse['status'] == 204;
3✔
363
    }
364

365
    /**
366
     * Change playback volume for the current user.
367
     * https://developer.spotify.com/documentation/web-api/reference/set-volume-for-users-playback
368
     *
369
     * @param array|object $options Optional. Options for the playback volume.
370
     * - int volume_percent Required. The volume to set.
371
     * - string device_id Optional. ID of the device to target.
372
     *
373
     * @return bool Whether the playback volume was successfully changed.
374
     */
375
    public function changeVolume(array|object $options): bool
376
    {
377
        $options = http_build_query($options, '', '&');
3✔
378

379
        // We need to manually append data to the URI since it's a PUT request
380
        $uri = '/v1/me/player/volume?' . $options;
3✔
381

382
        $this->lastResponse = $this->sendRequest('PUT', $uri);
3✔
383

384
        return $this->lastResponse['status'] == 204;
3✔
385
    }
386

387
    /**
388
     * Create a new playlist.
389
     * https://developer.spotify.com/documentation/web-api/reference/create-playlist
390
     *
391
     * @param string $userId ID or URI of the user to create the playlist for.
392
     * @param array|object $options Options for the new playlist.
393
     * - string name Required. Name of the playlist.
394
     * - bool collaborative Optional. Whether the playlist should be collaborative or not.
395
     * - string description Optional. Description of the playlist.
396
     * - bool public Optional. Whether the playlist should be public or not.
397
     *
398
     * @return array|object The new playlist. Type is controlled by the `return_assoc` option.
399
     */
400
    public function createPlaylist(string|array|object $userId, array|object $options = []): array|object
401
    {
402
        $userId = $this->uriToId($userId, 'user');
3✔
403
        $uri = '/v1/users/' . $userId . '/playlists';
3✔
404

405
        $options = json_encode($options);
3✔
406

407
        $headers = [
3✔
408
            'Content-Type' => 'application/json',
3✔
409
        ];
3✔
410

411
        $this->lastResponse = $this->sendRequest('POST', $uri, $options, $headers);
3✔
412

413
        return $this->lastResponse['body'];
3✔
414
    }
415

416
    /**
417
     * Check to see if the current user is following one or more artists or other Spotify users.
418
     * https://developer.spotify.com/documentation/web-api/reference/check-current-user-follows
419
     *
420
     * @param string $type The type to check: either 'artist' or 'user'.
421
     * @param string|array $ids IDs or URIs of the users or artists to check for.
422
     *
423
     * @return array Whether each user or artist is followed.
424
     */
425
    public function currentUserFollows(string $type, string|array $ids): array
426
    {
427
        $ids = $this->uriToId($ids, $type);
3✔
428
        $ids = $this->toCommaString($ids);
3✔
429

430
        $options = [
3✔
431
            'ids' => $ids,
3✔
432
            'type' => $type,
3✔
433
        ];
3✔
434

435
        $uri = '/v1/me/following/contains';
3✔
436

437
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
438

439
        return $this->lastResponse['body'];
3✔
440
    }
441

442
    /**
443
     * Check if the current user is following a playlist.
444
     * https://developer.spotify.com/documentation/web-api/reference/check-if-user-follows-playlist
445
     *
446
     * @param string $playlistId ID or URI of the playlist to check.
447
     *
448
     * @return array Array containing one boolean describing whether the playlist is followed.
449
     */
450
    public function currentUserFollowsPlaylist(string $playlistId): array
451
    {
452
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
453

454
        $uri = '/v1/playlists/' . $playlistId . '/followers/contains';
3✔
455

456
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
457

458
        return $this->lastResponse['body'];
3✔
459
    }
460

461
    /**
462
     * Delete albums from the current user's Spotify library.
463
     * https://developer.spotify.com/documentation/web-api/reference/remove-albums-user
464
     *
465
     * @param string|array $albums Album IDs or URIs to delete.
466
     *
467
     * @return bool Whether the albums was successfully deleted.
468
     */
469
    public function deleteMyAlbums(string|array $albums): bool
470
    {
471
        $albums = $this->uriToId($albums, 'album');
3✔
472
        $albums = json_encode([
3✔
473
            'ids' => (array) $albums,
3✔
474
        ]);
3✔
475

476
        $headers = [
3✔
477
            'Content-Type' => 'application/json',
3✔
478
        ];
3✔
479

480
        $uri = '/v1/me/albums';
3✔
481

482
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $albums, $headers);
3✔
483

484
        return $this->lastResponse['status'] == 200;
3✔
485
    }
486

487
    /**
488
     * Delete episodes from the current user's Spotify library.
489
     * https://developer.spotify.com/documentation/web-api/reference/remove-episodes-user
490
     *
491
     * @param string|array $episodes Episode IDs or URIs to delete.
492
     *
493
     * @return bool Whether the episodes was successfully deleted.
494
     */
495
    public function deleteMyEpisodes(string|array $episodes): bool
496
    {
497
        $episodes = $this->uriToId($episodes, 'episode');
3✔
498
        $episodes = json_encode([
3✔
499
            'ids' => (array) $episodes,
3✔
500
        ]);
3✔
501

502
        $headers = [
3✔
503
            'Content-Type' => 'application/json',
3✔
504
        ];
3✔
505

506
        $uri = '/v1/me/episodes';
3✔
507

508
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $episodes, $headers);
3✔
509

510
        return $this->lastResponse['status'] == 200;
3✔
511
    }
512

513
    /**
514
     * Delete shows from the current user's Spotify library.
515
     * https://developer.spotify.com/documentation/web-api/reference/remove-shows-user
516
     *
517
     * @param string|array $shows Show IDs or URIs to delete.
518
     *
519
     * @return bool Whether the shows was successfully deleted.
520
     */
521
    public function deleteMyShows(string|array $shows): bool
522
    {
523
        $shows = $this->uriToId($shows, 'show');
3✔
524
        $shows = json_encode([
3✔
525
            'ids' => (array) $shows,
3✔
526
        ]);
3✔
527

528
        $headers = [
3✔
529
            'Content-Type' => 'application/json',
3✔
530
        ];
3✔
531

532
        $uri = '/v1/me/shows';
3✔
533

534
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $shows, $headers);
3✔
535

536
        return $this->lastResponse['status'] == 200;
3✔
537
    }
538

539
    /**
540
     * Delete tracks from the current user's Spotify library.
541
     * https://developer.spotify.com/documentation/web-api/reference/remove-tracks-user
542
     *
543
     * @param string|array $tracks Track IDs or URIs to delete.
544
     *
545
     * @return bool Whether the tracks was successfully deleted.
546
     */
547
    public function deleteMyTracks(string|array $tracks): bool
548
    {
549
        $tracks = $this->uriToId($tracks, 'track');
3✔
550
        $tracks = json_encode([
3✔
551
            'ids' => (array) $tracks,
3✔
552
        ]);
3✔
553

554
        $headers = [
3✔
555
            'Content-Type' => 'application/json',
3✔
556
        ];
3✔
557

558
        $uri = '/v1/me/tracks';
3✔
559

560
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $tracks, $headers);
3✔
561

562
        return $this->lastResponse['status'] == 200;
3✔
563
    }
564

565
    /**
566
     * Delete tracks from a playlist and retrieve a new snapshot ID.
567
     * https://developer.spotify.com/documentation/web-api/reference/remove-tracks-playlist
568
     *
569
     * @param string $playlistId ID or URI of the playlist to delete tracks from.
570
     * @param array $tracks An array with the key "tracks" containing arrays or objects with tracks to delete.
571
     * Or an array with the key "positions" containing integer positions of the tracks to delete.
572
     * If the "tracks" key is used, the following fields are also available:
573
     * - string uri Required. Track ID, track URI, or episode URI.
574
     * - int|array positions Optional. The track's positions in the playlist.
575
     * @param string $snapshotId Required when `$tracks['positions']` is used, optional otherwise.
576
     * The playlist's snapshot ID.
577
     *
578
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully deleted.
579
     */
580
    public function deletePlaylistTracks(string $playlistId, array $tracks, string $snapshotId = ''): string|bool
581
    {
582
        $options = [];
9✔
583

584
        if ($snapshotId) {
9✔
585
            $options['snapshot_id'] = $snapshotId;
6✔
586
        }
587

588
        if (isset($tracks['positions'])) {
9✔
589
            $options['positions'] = $tracks['positions'];
6✔
590
        } else {
591
            $options['tracks'] = array_map(function ($track) {
3✔
592
                $track = (array) $track;
3✔
593

594
                if (isset($track['positions'])) {
3✔
595
                    $track['positions'] = (array) $track['positions'];
3✔
596
                }
597

598
                $track['uri'] = $this->idToUri($track['uri'], 'track');
3✔
599

600
                return $track;
3✔
601
            }, $tracks['tracks']);
3✔
602
        }
603

604
        $options = json_encode($options);
9✔
605

606
        $headers = [
9✔
607
            'Content-Type' => 'application/json',
9✔
608
        ];
9✔
609

610
        $playlistId = $this->uriToId($playlistId, 'playlist');
9✔
611

612
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
9✔
613

614
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $options, $headers);
9✔
615

616
        return $this->getSnapshotId($this->lastResponse['body']);
9✔
617
    }
618

619
    /**
620
     * Add the current user as a follower of one or more artists or other Spotify users.
621
     * https://developer.spotify.com/documentation/web-api/reference/follow-artists-users
622
     *
623
     * @param string $type The type of ID to follow: either 'artist' or 'user'.
624
     * @param string|array $ids IDs or URIs of the users or artists to follow.
625
     *
626
     * @return bool Whether the artist or user was successfully followed.
627
     */
628
    public function followArtistsOrUsers(string $type, string|array $ids): bool
629
    {
630
        $ids = $this->uriToId($ids, $type);
3✔
631
        $ids = json_encode([
3✔
632
            'ids' => (array) $ids,
3✔
633
        ]);
3✔
634

635
        $headers = [
3✔
636
            'Content-Type' => 'application/json',
3✔
637
        ];
3✔
638

639
        // We need to manually append data to the URI since it's a PUT request
640
        $uri = '/v1/me/following?type=' . $type;
3✔
641

642
        $this->lastResponse = $this->sendRequest('PUT', $uri, $ids, $headers);
3✔
643

644
        return $this->lastResponse['status'] == 204;
3✔
645
    }
646

647
    /**
648
     * Add the current user as a follower of a playlist.
649
     * https://developer.spotify.com/documentation/web-api/reference/follow-playlist
650
     *
651
     * @param string $playlistId ID or URI of the playlist to follow.
652
     * @param array|object $options Optional. Options for the followed playlist.
653
     * - bool public Optional. Whether the playlist should be followed publicly or not.
654
     *
655
     * @return bool Whether the playlist was successfully followed.
656
     */
657
    public function followPlaylist(string $playlistId, array|object $options = []): bool
658
    {
659
        $options = $options ? json_encode($options) : '';
3✔
660

661
        $headers = [
3✔
662
            'Content-Type' => 'application/json',
3✔
663
        ];
3✔
664

665
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
666

667
        $uri = '/v1/playlists/' . $playlistId . '/followers';
3✔
668

669
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
3✔
670

671
        return $this->lastResponse['status'] == 200;
3✔
672
    }
673

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

689
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
690

691
        return $this->lastResponse['body'];
3✔
692
    }
693

694
    /**
695
     * Get multiple albums.
696
     * https://developer.spotify.com/documentation/web-api/reference/get-multiple-albums
697
     *
698
     * @param array $albumIds IDs or URIs of the albums.
699
     * @param array|object $options Optional. Options for the albums.
700
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
701
     *
702
     * @return array|object The requested albums. Type is controlled by the `return_assoc` option.
703
     */
704
    public function getAlbums(array $albumIds, array|object $options = []): array|object
705
    {
706
        $albumIds = $this->uriToId($albumIds, 'album');
3✔
707
        $options = array_merge((array) $options, [
3✔
708
            'ids' => $this->toCommaString($albumIds),
3✔
709
        ]);
3✔
710

711
        $uri = '/v1/albums/';
3✔
712

713
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
714

715
        return $this->lastResponse['body'];
3✔
716
    }
717

718
    /**
719
     * Get an album's tracks.
720
     * https://developer.spotify.com/documentation/web-api/reference/get-an-albums-tracks
721
     *
722
     * @param string $albumId ID or URI of the album.
723
     * @param array|object $options Optional. Options for the tracks.
724
     * - int limit Optional. Limit the number of tracks.
725
     * - int offset Optional. Number of tracks to skip.
726
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
727
     *
728
     * @return array|object The requested album tracks. Type is controlled by the `return_assoc` option.
729
     */
730
    public function getAlbumTracks(string $albumId, array|object $options = []): array|object
731
    {
732
        $albumId = $this->uriToId($albumId, 'album');
3✔
733
        $uri = '/v1/albums/' . $albumId . '/tracks';
3✔
734

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

737
        return $this->lastResponse['body'];
3✔
738
    }
739

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

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

755
        return $this->lastResponse['body'];
3✔
756
    }
757

758
    /**
759
     * Get multiple artists.
760
     * https://developer.spotify.com/documentation/web-api/reference/get-multiple-artists
761
     *
762
     * @param array $artistIds IDs or URIs of the artists.
763
     *
764
     * @return array|object The requested artists. Type is controlled by the `return_assoc` option.
765
     */
766
    public function getArtists(array $artistIds): array|object
767
    {
768
        $artistIds = $this->uriToId($artistIds, 'artist');
3✔
769
        $artistIds = $this->toCommaString($artistIds);
3✔
770

771
        $options = [
3✔
772
            'ids' => $artistIds,
3✔
773
        ];
3✔
774

775
        $uri = '/v1/artists/';
3✔
776

777
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
778

779
        return $this->lastResponse['body'];
3✔
780
    }
781

782
    /**
783
     * Get an artist's related artists.
784
     * https://developer.spotify.com/documentation/web-api/reference/get-an-artists-related-artists
785
     *
786
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
787
     *
788
     * @param string $artistId ID or URI of the artist.
789
     *
790
     * @return array|object The artist's related artists. Type is controlled by the `return_assoc` option.
791
     */
792
    public function getArtistRelatedArtists(string $artistId): array|object
793
    {
794
        $artistId = $this->uriToId($artistId, 'artist');
3✔
795
        $uri = '/v1/artists/' . $artistId . '/related-artists';
3✔
796

797
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
798

799
        return $this->lastResponse['body'];
3✔
800
    }
801

802
    /**
803
     * Get an artist's albums.
804
     * https://developer.spotify.com/documentation/web-api/reference/get-an-artists-albums
805
     *
806
     * @param string $artistId ID or URI of the artist.
807
     * @param array|object $options Optional. Options for the albums.
808
     * - string market Optional. Limit the results to items that are playable in this country, for example SE.
809
     * - string|array include_groups Optional. Album types to return. If omitted, all album types will be returned.
810
     * - int limit Optional. Limit the number of albums.
811
     * - int offset Optional. Number of albums to skip.
812
     *
813
     * @return array|object The artist's albums. Type is controlled by the `return_assoc` option.
814
     */
815
    public function getArtistAlbums(string $artistId, array|object $options = []): array|object
816
    {
817
        $options = (array) $options;
3✔
818

819
        if (isset($options['include_groups'])) {
3✔
820
            $options['include_groups'] = $this->toCommaString($options['include_groups']);
3✔
821
        }
822

823
        $artistId = $this->uriToId($artistId, 'artist');
3✔
824
        $uri = '/v1/artists/' . $artistId . '/albums';
3✔
825

826
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
827

828
        return $this->lastResponse['body'];
3✔
829
    }
830

831
    /**
832
     * Get an artist's top tracks in a country.
833
     * https://developer.spotify.com/documentation/web-api/reference/get-an-artists-top-tracks
834
     *
835
     * @param string $artistId ID or URI of the artist.
836
     * @param array|object $options Options for the tracks.
837
     * - string market Required. An ISO 3166-1 alpha-2 country code specifying the country to get the top tracks for.
838
     *
839
     * @return array|object The artist's top tracks. Type is controlled by the `return_assoc` option.
840
     */
841
    public function getArtistTopTracks(string $artistId, array|object $options): array|object
842
    {
843
        $artistId = $this->uriToId($artistId, 'artist');
3✔
844
        $uri = '/v1/artists/' . $artistId . '/top-tracks';
3✔
845

846
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
847

848
        return $this->lastResponse['body'];
3✔
849
    }
850

851
    /**
852
     * Get audio analysis for track.
853
     * https://developer.spotify.com/documentation/web-api/reference/get-audio-analysis
854
     *
855
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
856
     *
857
     * @param string $trackId ID or URI of the track.
858
     *
859
     * @return array|object The track's audio analysis. Type is controlled by the `return_assoc` option.
860
     */
861
    public function getAudioAnalysis(string $trackId): array|object
862
    {
863
        $trackId = $this->uriToId($trackId, 'track');
3✔
864
        $uri = '/v1/audio-analysis/' . $trackId;
3✔
865

866
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
867

868
        return $this->lastResponse['body'];
3✔
869
    }
870

871
    /**
872
     * Get an audiobook.
873
     * https://developer.spotify.com/documentation/web-api/reference/get-an-audiobook
874
     *
875
     * @param string $audiobookId ID or URI of the audiobook.
876
     * @param array|object $options Optional. Options for the audiobook.
877
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to audiobooks available in that market.
878
     *
879
     * @return array|object The requested audiobook. Type is controlled by the `return_assoc` option.
880
     */
881
    public function getAudiobook(string $audiobookId, array|object $options = [])
882
    {
883
        $audiobookId = $this->uriToId($audiobookId, 'show');
3✔
884
        $uri = '/v1/audiobooks/' . $audiobookId;
3✔
885

886
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
887

888
        return $this->lastResponse['body'];
3✔
889
    }
890

891
    /**
892
     * Get multiple audiobooks.
893
     * https://developer.spotify.com/documentation/web-api/reference/get-multiple-audiobooks
894
     *
895
     * @param array $audiobookIds IDs or URIs of the audiobooks.
896
     * @param array|object $options Optional. Options for the audiobooks.
897
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to audiobooks available in that market.
898
     *
899
     * @return array|object The requested audiobooks. Type is controlled by the `return_assoc` option.
900
     */
901
    public function getAudiobooks(array $audiobookIds, array|object $options = [])
902
    {
903
        $audiobookIds = $this->uriToId($audiobookIds, 'show');
3✔
904
        $audiobookIds = $this->toCommaString($audiobookIds);
3✔
905

906
        $options = array_merge((array) $options, [
3✔
907
            'ids' => $this->toCommaString($audiobookIds),
3✔
908
        ]);
3✔
909

910
        $uri = '/v1/audiobooks/';
3✔
911

912
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
913

914
        return $this->lastResponse['body'];
3✔
915
    }
916

917
    /**
918
     * Get audio features of a single track.
919
     * https://developer.spotify.com/documentation/web-api/reference/get-audio-features
920
     *
921
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
922
     *
923
     * @param string $trackId ID or URI of the track.
924
     *
925
     * @return array|object The track's audio features. Type is controlled by the `return_assoc` option.
926
     */
927
    public function getAudioFeatures(string $trackId): array|object
928
    {
929
        $trackId = $this->uriToId($trackId, 'track');
3✔
930
        $uri = '/v1/audio-features/' . $trackId;
3✔
931

932
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
933

934
        return $this->lastResponse['body'];
3✔
935
    }
936

937
    /**
938
     * Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s "Discover" tab).
939
     * https://developer.spotify.com/documentation/web-api/reference/get-categories
940
     *
941
     * @param array|object $options Optional. Options for the categories.
942
     * - string locale Optional. Language to show categories in, for example 'sv_SE'.
943
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show categories from this country.
944
     * - int limit Optional. Limit the number of categories.
945
     * - int offset Optional. Number of categories to skip.
946
     *
947
     * @return array|object The list of categories. Type is controlled by the `return_assoc` option.
948
     */
949
    public function getCategoriesList(array|object $options = []): array|object
950
    {
951
        $uri = '/v1/browse/categories';
3✔
952

953
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
954

955
        return $this->lastResponse['body'];
3✔
956
    }
957

958
    /**
959
     * Get a single category used to tag items in Spotify (on, for example, the Spotify player’s "Discover" tab).
960
     * https://developer.spotify.com/documentation/web-api/reference/get-a-category
961
     *
962
     * @param string $categoryId ID of the category.
963
     *
964
     * @param array|object $options Optional. Options for the category.
965
     * - string locale Optional. Language to show category in, for example 'sv_SE'.
966
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show category from this country.
967
     *
968
     * @return array|object The category. Type is controlled by the `return_assoc` option.
969
     */
970
    public function getCategory(string $categoryId, array|object $options = []): array|object
971
    {
972
        $uri = '/v1/browse/categories/' . $categoryId;
3✔
973

974
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
975

976
        return $this->lastResponse['body'];
3✔
977
    }
978

979
    /**
980
     * Get a list of Spotify playlists tagged with a particular category.
981
     * https://developer.spotify.com/documentation/web-api/reference/get-a-categories-playlists
982
     *
983
     * @param string $categoryId ID of the category.
984
     *
985
     * @param array|object $options Optional. Options for the category's playlists.
986
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show category playlists from this country.
987
     * - int limit Optional. Limit the number of playlists.
988
     * - int offset Optional. Number of playlists to skip.
989
     *
990
     * @return array|object The list of playlists. Type is controlled by the `return_assoc` option.
991
     */
992
    public function getCategoryPlaylists(string $categoryId, array|object $options = []): array|object
993
    {
994
        $uri = '/v1/browse/categories/' . $categoryId . '/playlists';
3✔
995

996
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
997

998
        return $this->lastResponse['body'];
3✔
999
    }
1000

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

1016
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1017

1018
        return $this->lastResponse['body'];
3✔
1019
    }
1020

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

1038
        $uri = '/v1/chapters/';
3✔
1039

1040
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1041

1042
        return $this->lastResponse['body'];
3✔
1043
    }
1044

1045
    /**
1046
     * Get an episode.
1047
     * https://developer.spotify.com/documentation/web-api/reference/get-an-episode
1048
     *
1049
     * @param string $episodeId ID or URI of the episode.
1050
     * @param array|object $options Optional. Options for the episode.
1051
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1052
     *
1053
     * @return array|object The requested episode. Type is controlled by the `return_assoc` option.
1054
     */
1055
    public function getEpisode(string $episodeId, array|object $options = []): array|object
1056
    {
1057
        $episodeId = $this->uriToId($episodeId, 'episode');
3✔
1058
        $uri = '/v1/episodes/' . $episodeId;
3✔
1059

1060
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1061

1062
        return $this->lastResponse['body'];
3✔
1063
    }
1064

1065
    /**
1066
     * Get multiple episodes.
1067
     * https://developer.spotify.com/documentation/web-api/reference/get-multiple-episodes
1068
     *
1069
     * @param string|array $episodeIds IDs or URIs of the episodes.
1070
     * @param array|object $options Optional. Options for the episodes.
1071
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1072
     *
1073
     * @return array|object The requested episodes. Type is controlled by the `return_assoc` option.
1074
     */
1075
    public function getEpisodes(string|array $episodeIds, array|object $options = []): array|object
1076
    {
1077
        $episodeIds = $this->uriToId($episodeIds, 'episode');
3✔
1078
        $options = array_merge((array) $options, [
3✔
1079
            'ids' => $this->toCommaString($episodeIds),
3✔
1080
        ]);
3✔
1081

1082
        $uri = '/v1/episodes/';
3✔
1083

1084
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1085

1086
        return $this->lastResponse['body'];
3✔
1087
    }
1088

1089
    /**
1090
     * Get Spotify featured playlists.
1091
     * https://developer.spotify.com/documentation/web-api/reference/get-featured-playlists
1092
     *
1093
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
1094
     *
1095
     * @param array|object $options Optional. Options for the playlists.
1096
     * - string locale Optional. Language to show playlists in, for example 'sv_SE'.
1097
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show playlists from this country.
1098
     * - string timestamp Optional. A ISO 8601 timestamp. Show playlists relevant to this date and time.
1099
     * - int limit Optional. Limit the number of playlists.
1100
     * - int offset Optional. Number of playlists to skip.
1101
     *
1102
     * @return array|object The featured playlists. Type is controlled by the `return_assoc` option.
1103
     */
1104
    public function getFeaturedPlaylists(array|object $options = []): array|object
1105
    {
1106
        $uri = '/v1/browse/featured-playlists';
3✔
1107

1108
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1109

1110
        return $this->lastResponse['body'];
3✔
1111
    }
1112

1113
    /**
1114
     * Get a list of possible seed genres.
1115
     * https://developer.spotify.com/documentation/web-api/reference/get-recommendation-genres
1116
     *
1117
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
1118
     *
1119
     * @return array|object All possible seed genres. Type is controlled by the `return_assoc` option.
1120
     */
1121
    public function getGenreSeeds(): array|object
1122
    {
1123
        $uri = '/v1/recommendations/available-genre-seeds';
3✔
1124

1125
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
1126

1127
        return $this->lastResponse['body'];
3✔
1128
    }
1129

1130
    /**
1131
     * Get the latest full response from the Spotify API.
1132
     *
1133
     * @return array Response data.
1134
     * - array|object body The response body. Type is controlled by the `return_assoc` option.
1135
     * - array headers Response headers.
1136
     * - int status HTTP status code.
1137
     * - string url The requested URL.
1138
     */
1139
    public function getLastResponse(): array
1140
    {
1141
        return $this->lastResponse;
3✔
1142
    }
1143

1144
    /**
1145
     * Get all markets where Spotify is available.
1146
     * https://developer.spotify.com/documentation/web-api/reference/get-available-markets
1147
     *
1148
     * @return array|object All markets where Spotify is available. Type is controlled by the `return_assoc` option.
1149
     */
1150
    public function getMarkets(): array|object
1151
    {
1152
        $uri = '/v1/markets';
3✔
1153

1154
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
1155

1156
        return $this->lastResponse['body'];
3✔
1157
    }
1158

1159
    /**
1160
     * Get audio features of multiple tracks.
1161
     * https://developer.spotify.com/documentation/web-api/reference/get-several-audio-features
1162
     *
1163
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
1164
     *
1165
     * @param string|array $trackIds IDs or URIs of the tracks.
1166
     *
1167
     * @return array|object The tracks' audio features. Type is controlled by the `return_assoc` option.
1168
     */
1169
    public function getMultipleAudioFeatures(string|array $trackIds): array|object
1170
    {
1171
        $trackIds = $this->uriToId($trackIds, 'track');
3✔
1172
        $options = [
3✔
1173
            'ids' => $this->toCommaString($trackIds),
3✔
1174
        ];
3✔
1175

1176
        $uri = '/v1/audio-features';
3✔
1177

1178
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1179

1180
        return $this->lastResponse['body'];
3✔
1181
    }
1182

1183
    /**
1184
     * Get the current user’s currently playing track.
1185
     * https://developer.spotify.com/documentation/web-api/reference/get-the-users-currently-playing-track
1186
     *
1187
     * @param array|object $options Optional. Options for the track.
1188
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1189
     * - string|array additional_types Optional. Types of media to return info about.
1190
     *
1191
     * @return array|object|null The user's currently playing track or null if nothing's currently playing.
1192
     * Type is controlled by the `return_assoc` option.
1193
     */
1194
    public function getMyCurrentTrack(array|object $options = []): array|object|null
1195
    {
1196
        $uri = '/v1/me/player/currently-playing';
6✔
1197
        $options = (array) $options;
6✔
1198

1199
        if (isset($options['additional_types'])) {
6✔
1200
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
3✔
1201
        }
1202

1203
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
6✔
1204

1205
        return $this->lastResponse['body'];
6✔
1206
    }
1207

1208
    /**
1209
     * Get the current user’s devices.
1210
     * https://developer.spotify.com/documentation/web-api/reference/get-a-users-available-devices
1211
     *
1212
     * @return array|object The user's devices. Type is controlled by the `return_assoc` option.
1213
     */
1214
    public function getMyDevices(): array|object
1215
    {
1216
        $uri = '/v1/me/player/devices';
3✔
1217

1218
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
1219

1220
        return $this->lastResponse['body'];
3✔
1221
    }
1222

1223
    /**
1224
     * Get the current user’s current playback information.
1225
     * https://developer.spotify.com/documentation/web-api/reference/get-information-about-the-users-current-playback
1226
     *
1227
     * @param array|object $options Optional. Options for the info.
1228
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1229
     * - string|array additional_types Optional. Types of media to return info about.
1230
     *
1231
     * @return array|object|null The user's playback information or null if nothing's currently playing.
1232
     * Type is controlled by the `return_assoc` option.
1233
     */
1234
    public function getMyCurrentPlaybackInfo(array|object $options = []): array|object|null
1235
    {
1236
        $uri = '/v1/me/player';
6✔
1237
        $options = (array) $options;
6✔
1238

1239
        if (isset($options['additional_types'])) {
6✔
1240
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
3✔
1241
        }
1242

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

1245
        return $this->lastResponse['body'];
6✔
1246
    }
1247

1248

1249
    /**
1250
     * Get the current user’s playlists.
1251
     * https://developer.spotify.com/documentation/web-api/reference/get-a-list-of-current-users-playlists
1252
     *
1253
     * @param array|object $options Optional. Options for the playlists.
1254
     * - int limit Optional. Limit the number of playlists.
1255
     * - int offset Optional. Number of playlists to skip.
1256
     *
1257
     * @return array|object The user's playlists. Type is controlled by the `return_assoc` option.
1258
     */
1259
    public function getMyPlaylists(array|object $options = []): array|object
1260
    {
1261
        $uri = '/v1/me/playlists';
3✔
1262

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

1265
        return $this->lastResponse['body'];
3✔
1266
    }
1267

1268
    /**
1269
     * Get the current user’s queue.
1270
     *
1271
     * https://developer.spotify.com/documentation/web-api/reference/get-queue
1272
     *
1273
     * @return array|object The currently playing song and queue. Type is controlled by the `return_assoc` option.
1274
     */
1275
    public function getMyQueue()
1276
    {
1277
        $uri = '/v1/me/player/queue';
3✔
1278

1279
        $this->lastResponse = $this->sendRequest('GET', $uri, []);
3✔
1280

1281
        return $this->lastResponse['body'];
3✔
1282
    }
1283

1284
    /**
1285
      * Get the current user’s recently played tracks.
1286
      * https://developer.spotify.com/documentation/web-api/reference/get-recently-played
1287
      *
1288
      * @param array|object $options Optional. Options for the tracks.
1289
      * - int limit Optional. Number of tracks to return.
1290
      * - string after Optional. Unix timestamp in ms (13 digits). Returns all items after this position.
1291
      * - string before Optional. Unix timestamp in ms (13 digits). Returns all items before this position.
1292
      *
1293
      * @return array|object The most recently played tracks. Type is controlled by the `return_assoc` option.
1294
      */
1295
    public function getMyRecentTracks(array|object $options = []): array|object
1296
    {
1297
        $uri = '/v1/me/player/recently-played';
3✔
1298

1299
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1300

1301
        return $this->lastResponse['body'];
3✔
1302
    }
1303

1304
    /**
1305
     * Get the current user’s saved albums.
1306
     * https://developer.spotify.com/documentation/web-api/reference/get-users-saved-albums
1307
     *
1308
     * @param array|object $options Optional. Options for the albums.
1309
     * - int limit Optional. Number of albums to return.
1310
     * - int offset Optional. Number of albums to skip.
1311
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1312
     *
1313
     * @return array|object The user's saved albums. Type is controlled by the `return_assoc` option.
1314
     */
1315
    public function getMySavedAlbums(array|object $options = []): array|object
1316
    {
1317
        $uri = '/v1/me/albums';
3✔
1318

1319
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1320

1321
        return $this->lastResponse['body'];
3✔
1322
    }
1323

1324
    /**
1325
     * Get the current user’s saved episodes.
1326
     * https://developer.spotify.com/documentation/web-api/reference/get-users-saved-episodes
1327
     *
1328
     * @param array|object $options Optional. Options for the episodes.
1329
     * - int limit Optional. Number of episodes to return.
1330
     * - int offset Optional. Number of episodes to skip.
1331
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1332
     *
1333
     * @return array|object The user's saved episodes. Type is controlled by the `return_assoc` option.
1334
     */
1335
    public function getMySavedEpisodes(array|object $options = []): array|object
1336
    {
1337
        $uri = '/v1/me/episodes';
3✔
1338

1339
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1340

1341
        return $this->lastResponse['body'];
3✔
1342
    }
1343

1344
    /**
1345
     * Get the current user’s saved tracks.
1346
     * https://developer.spotify.com/documentation/web-api/reference/get-users-saved-tracks
1347
     *
1348
     * @param array|object $options Optional. Options for the tracks.
1349
     * - int limit Optional. Limit the number of tracks.
1350
     * - int offset Optional. Number of tracks to skip.
1351
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1352
     *
1353
     * @return array|object The user's saved tracks. Type is controlled by the `return_assoc` option.
1354
     */
1355
    public function getMySavedTracks(array|object $options = []): array|object
1356
    {
1357
        $uri = '/v1/me/tracks';
3✔
1358

1359
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1360

1361
        return $this->lastResponse['body'];
3✔
1362
    }
1363

1364
    /**
1365
     * Get the current user’s saved shows.
1366
     * https://developer.spotify.com/documentation/web-api/reference/get-users-saved-shows
1367
     *
1368
     * @param array|object $options Optional. Options for the shows.
1369
     * - int limit Optional. Limit the number of shows.
1370
     * - int offset Optional. Number of shows to skip.
1371
     *
1372
     * @return array|object The user's saved shows. Type is controlled by the `return_assoc` option.
1373
     */
1374
    public function getMySavedShows(array|object $options = []): array|object
1375
    {
1376
        $uri = '/v1/me/shows';
3✔
1377

1378
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1379

1380
        return $this->lastResponse['body'];
3✔
1381
    }
1382

1383
    /**
1384
     * Get the current user's top tracks or artists.
1385
     * https://developer.spotify.com/documentation/web-api/reference/get-users-top-artists-and-tracks
1386
     *
1387
     * @param string $type The type to fetch, either 'artists' or 'tracks'.
1388
     * @param array $options Optional. Options for the results.
1389
     * - int limit Optional. Limit the number of results.
1390
     * - int offset Optional. Number of results to skip.
1391
     * - string time_range Optional. Over what time frame the data is calculated. See Spotify API docs for more info.
1392
     *
1393
     * @return array|object A list of the requested top entity. Type is controlled by the `return_assoc` option.
1394
     */
1395
    public function getMyTop(string $type, array|object $options = []): array|object
1396
    {
1397
        $uri = '/v1/me/top/' . $type;
3✔
1398

1399
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1400

1401
        return $this->lastResponse['body'];
3✔
1402
    }
1403

1404
    /**
1405
     * Get new releases.
1406
     * https://developer.spotify.com/documentation/web-api/reference/get-new-releases
1407
     *
1408
     * @param array|object $options Optional. Options for the items.
1409
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show items relevant to this country.
1410
     * - int limit Optional. Limit the number of items.
1411
     * - int offset Optional. Number of items to skip.
1412
     *
1413
     * @return array|object The new releases. Type is controlled by the `return_assoc` option.
1414
     */
1415
    public function getNewReleases(array|object $options = []): array|object
1416
    {
1417
        $uri = '/v1/browse/new-releases';
3✔
1418

1419
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1420

1421
        return $this->lastResponse['body'];
3✔
1422
    }
1423

1424
    /**
1425
     * Get a specific playlist.
1426
     * https://developer.spotify.com/documentation/web-api/reference/get-playlist
1427
     *
1428
     * @param string $playlistId ID or URI of the playlist.
1429
     * @param array|object $options Optional. Options for the playlist.
1430
     * - string|array fields Optional. A list of fields to return. See Spotify docs for more info.
1431
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1432
     * - string|array additional_types Optional. Types of media to return info about.
1433
     *
1434
     * @return array|object The user's playlist. Type is controlled by the `return_assoc` option.
1435
     */
1436
    public function getPlaylist(string $playlistId, array|object $options = []): array|object
1437
    {
1438
        $options = (array) $options;
3✔
1439

1440
        if (isset($options['fields'])) {
3✔
1441
            $options['fields'] = $this->toCommaString($options['fields']);
3✔
1442
        }
1443

1444
        if (isset($options['additional_types'])) {
3✔
UNCOV
1445
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
×
1446
        }
1447

1448
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1449

1450
        $uri = '/v1/playlists/' . $playlistId;
3✔
1451

1452
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1453

1454
        return $this->lastResponse['body'];
3✔
1455
    }
1456

1457
    /**
1458
     * Get a playlist's cover image.
1459
     * https://developer.spotify.com/documentation/web-api/reference/get-playlist-cover
1460
     *
1461
     * @param string $playlistId ID or URI of the playlist.
1462
     *
1463
     * @return array|object The playlist cover image. Type is controlled by the `return_assoc` option.
1464
     */
1465
    public function getPlaylistImage(string $playlistId): array|object
1466
    {
1467
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1468

1469
        $uri = '/v1/playlists/' . $playlistId . '/images';
3✔
1470

1471
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
1472

1473
        return $this->lastResponse['body'];
3✔
1474
    }
1475

1476
    /**
1477
     * Get the tracks in a playlist.
1478
     * https://developer.spotify.com/documentation/web-api/reference/get-playlists-tracks
1479
     *
1480
     * @param string $playlistId ID or URI of the playlist.
1481
     * @param array|object $options Optional. Options for the tracks.
1482
     * - string|array fields Optional. A list of fields to return. See Spotify docs for more info.
1483
     * - int limit Optional. Limit the number of tracks.
1484
     * - int offset Optional. Number of tracks to skip.
1485
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1486
     * - string|array additional_types Optional. Types of media to return info about.
1487
     *
1488
     * @return array|object The tracks in the playlist. Type is controlled by the `return_assoc` option.
1489
     */
1490
    public function getPlaylistTracks(string $playlistId, array|object $options = []): array|object
1491
    {
1492
        $options = (array) $options;
3✔
1493

1494
        if (isset($options['fields'])) {
3✔
1495
            $options['fields'] = $this->toCommaString($options['fields']);
3✔
1496
        }
1497

1498
        if (isset($options['additional_types'])) {
3✔
1499
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
3✔
1500
        }
1501

1502
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1503

1504
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
3✔
1505

1506
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1507

1508
        return $this->lastResponse['body'];
3✔
1509
    }
1510

1511
    /**
1512
     * Get recommendations based on artists, tracks, or genres.
1513
     * https://developer.spotify.com/documentation/web-api/reference/get-recommendations
1514
     *
1515
     * @deprecated See https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api
1516
     *
1517
     * @param array|object $options Optional. Options for the recommendations.
1518
     * - int limit Optional. Limit the number of recommendations.
1519
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1520
     * - mixed max_* Optional. Max value for one of the tunable track attributes.
1521
     * - mixed min_* Optional. Min value for one of the tunable track attributes.
1522
     * - array seed_artists Artist IDs to seed by.
1523
     * - array seed_genres Genres to seed by. Call SpotifyWebAPI::getGenreSeeds() for a complete list.
1524
     * - array seed_tracks Track IDs to seed by.
1525
     * - mixed target_* Optional. Target value for one of the tunable track attributes.
1526
     *
1527
     * @return array|object The requested recommendations. Type is controlled by the `return_assoc` option.
1528
     */
1529
    public function getRecommendations(array|object $options = []): array|object
1530
    {
1531
        $options = (array) $options;
3✔
1532

1533
        array_walk($options, function (&$value, $key) {
3✔
1534
            if (substr($key, 0, 5) == 'seed_') {
3✔
1535
                $value = $this->toCommaString($value);
3✔
1536
            }
1537
        });
3✔
1538

1539
        $uri = '/v1/recommendations';
3✔
1540

1541
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1542

1543
        return $this->lastResponse['body'];
3✔
1544
    }
1545

1546
    /**
1547
     * Get the Request object in use.
1548
     *
1549
     * @return Request The Request object in use.
1550
     */
1551
    public function getRequest(): Request
1552
    {
1553
        return $this->request;
3✔
1554
    }
1555

1556
    /**
1557
     * Get a show.
1558
     * https://developer.spotify.com/documentation/web-api/reference/get-a-show
1559
     *
1560
     * @param string $showId ID or URI of the show.
1561
     * @param array|object $options Optional. Options for the show.
1562
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to shows available in that market.
1563
     *
1564
     * @return array|object The requested show. Type is controlled by the `return_assoc` option.
1565
     */
1566
    public function getShow(string $showId, array|object $options = []): array|object
1567
    {
1568
        $showId = $this->uriToId($showId, 'show');
3✔
1569
        $uri = '/v1/shows/' . $showId;
3✔
1570

1571
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1572

1573
        return $this->lastResponse['body'];
3✔
1574
    }
1575

1576
    /**
1577
     * Get a show's episodes.
1578
     * https://developer.spotify.com/documentation/web-api/reference/get-a-shows-episodes
1579
     *
1580
     * @param string $showId ID or URI of the album.
1581
     * @param array|object $options Optional. Options for the episodes.
1582
     * - int limit Optional. Limit the number of episodes.
1583
     * - int offset Optional. Number of episodes to skip.
1584
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1585
     *
1586
     * @return array|object The requested show episodes. Type is controlled by the `return_assoc` option.
1587
     */
1588
    public function getShowEpisodes(string $showId, array|object $options = []): array|object
1589
    {
1590
        $showId = $this->uriToId($showId, 'show');
3✔
1591
        $uri = '/v1/shows/' . $showId . '/episodes';
3✔
1592

1593
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1594

1595
        return $this->lastResponse['body'];
3✔
1596
    }
1597

1598
    /**
1599
     * Get multiple shows.
1600
     * https://developer.spotify.com/documentation/web-api/reference/get-multiple-shows
1601
     *
1602
     * @param string|array $showIds IDs or URIs of the shows.
1603
     * @param array|object $options Optional. Options for the shows.
1604
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to shows available in that market.
1605
     *
1606
     * @return array|object The requested shows. Type is controlled by the `return_assoc` option.
1607
     */
1608
    public function getShows(string|array $showIds, array|object $options = []): array|object
1609
    {
1610
        $showIds = $this->uriToId($showIds, 'show');
3✔
1611
        $options = array_merge((array) $options, [
3✔
1612
            'ids' => $this->toCommaString($showIds),
3✔
1613
        ]);
3✔
1614

1615
        $uri = '/v1/shows/';
3✔
1616

1617
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1618

1619
        return $this->lastResponse['body'];
3✔
1620
    }
1621

1622
    /**
1623
     * Get a track.
1624
     * https://developer.spotify.com/documentation/web-api/reference/get-track
1625
     *
1626
     * @param string $trackId ID or URI of the track.
1627
     * @param array|object $options Optional. Options for the track.
1628
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1629
     *
1630
     * @return array|object The requested track. Type is controlled by the `return_assoc` option.
1631
     */
1632
    public function getTrack(string $trackId, array|object $options = []): array|object
1633
    {
1634
        $trackId = $this->uriToId($trackId, 'track');
12✔
1635
        $uri = '/v1/tracks/' . $trackId;
12✔
1636

1637
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
12✔
1638

1639
        return $this->lastResponse['body'];
12✔
1640
    }
1641

1642
    /**
1643
     * Get multiple tracks.
1644
     * https://developer.spotify.com/documentation/web-api/reference/get-several-tracks
1645
     *
1646
     * @param array $trackIds IDs or URIs of the tracks.
1647
     * @param array|object $options Optional. Options for the tracks.
1648
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1649
     *
1650
     * @return array|object The requested tracks. Type is controlled by the `return_assoc` option.
1651
     */
1652
    public function getTracks(array $trackIds, array|object $options = []): array|object
1653
    {
1654
        $trackIds = $this->uriToId($trackIds, 'track');
3✔
1655
        $options = array_merge((array) $options, [
3✔
1656
            'ids' => $this->toCommaString($trackIds),
3✔
1657
        ]);
3✔
1658

1659
        $uri = '/v1/tracks/';
3✔
1660

1661
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1662

1663
        return $this->lastResponse['body'];
3✔
1664
    }
1665

1666
    /**
1667
     * Get a user.
1668
     * https://developer.spotify.com/documentation/web-api/reference/get-users-profile
1669
     *
1670
     * @param string $userId ID or URI of the user.
1671
     *
1672
     * @return array|object The requested user. Type is controlled by the `return_assoc` option.
1673
     */
1674
    public function getUser(string $userId): array|object
1675
    {
1676
        $userId = $this->uriToId($userId, 'user');
3✔
1677
        $uri = '/v1/users/' . $userId;
3✔
1678

1679
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
1680

1681
        return $this->lastResponse['body'];
3✔
1682
    }
1683

1684
    /**
1685
     * Get the artists followed by the current user.
1686
     * https://developer.spotify.com/documentation/web-api/reference/get-followed
1687
     *
1688
     * @param array|object $options Optional. Options for the artists.
1689
     * - int limit Optional. Limit the number of artists returned.
1690
     * - string after Optional. The last artist ID retrieved from the previous request.
1691
     *
1692
     * @return array|object A list of artists. Type is controlled by the `return_assoc` option.
1693
     */
1694
    public function getUserFollowedArtists(array|object $options = []): array|object
1695
    {
1696
        $options = (array) $options;
3✔
1697

1698
        if (!isset($options['type'])) {
3✔
1699
            $options['type'] = 'artist'; // Undocumented until more values are supported.
3✔
1700
        }
1701

1702
        $uri = '/v1/me/following';
3✔
1703

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

1706
        return $this->lastResponse['body'];
3✔
1707
    }
1708

1709
    /**
1710
     * Get a user's playlists.
1711
     * https://developer.spotify.com/documentation/web-api/reference/get-list-users-playlists
1712
     *
1713
     * @param string $userId ID or URI of the user.
1714
     * @param array|object $options Optional. Options for the tracks.
1715
     * - int limit Optional. Limit the number of tracks.
1716
     * - int offset Optional. Number of tracks to skip.
1717
     *
1718
     * @return array|object The user's playlists. Type is controlled by the `return_assoc` option.
1719
     */
1720
    public function getUserPlaylists(string $userId, array|object $options = []): array|object
1721
    {
1722
        $userId = $this->uriToId($userId, 'user');
3✔
1723
        $uri = '/v1/users/' . $userId . '/playlists';
3✔
1724

1725
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1726

1727
        return $this->lastResponse['body'];
3✔
1728
    }
1729

1730
    /**
1731
     * Get the currently authenticated user.
1732
     * https://developer.spotify.com/documentation/web-api/reference/get-current-users-profile
1733
     *
1734
     * @return array|object The currently authenticated user. Type is controlled by the `return_assoc` option.
1735
     */
1736
    public function me(): array|object
1737
    {
1738
        $uri = '/v1/me';
3✔
1739

1740
        $this->lastResponse = $this->sendRequest('GET', $uri);
3✔
1741

1742
        return $this->lastResponse['body'];
3✔
1743
    }
1744

1745
    /**
1746
     * Check if albums are saved in the current user's Spotify library.
1747
     * https://developer.spotify.com/documentation/web-api/reference/check-users-saved-albums
1748
     *
1749
     * @param string|array $albums Album IDs or URIs to check for.
1750
     *
1751
     * @return array Whether each album is saved.
1752
     */
1753
    public function myAlbumsContains(string|array $albums): array
1754
    {
1755
        $albums = $this->uriToId($albums, 'album');
3✔
1756
        $albums = $this->toCommaString($albums);
3✔
1757

1758
        $options = [
3✔
1759
            'ids' => $albums,
3✔
1760
        ];
3✔
1761

1762
        $uri = '/v1/me/albums/contains';
3✔
1763

1764
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1765

1766
        return $this->lastResponse['body'];
3✔
1767
    }
1768

1769
    /**
1770
     * Check if episodes are saved in the current user's Spotify library.
1771
     * https://developer.spotify.com/documentation/web-api/reference/check-users-saved-episodes
1772
     *
1773
     * @param string|array $episodes Episode IDs or URIs to check for.
1774
     *
1775
     * @return array Whether each episode is saved.
1776
     */
1777
    public function myEpisodesContains(string|array $episodes): array
1778
    {
1779
        $episodes = $this->uriToId($episodes, 'episode');
3✔
1780
        $episodes = $this->toCommaString($episodes);
3✔
1781

1782
        $options = [
3✔
1783
            'ids' => $episodes,
3✔
1784
        ];
3✔
1785

1786
        $uri = '/v1/me/episodes/contains';
3✔
1787

1788
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1789

1790
        return $this->lastResponse['body'];
3✔
1791
    }
1792

1793
    /**
1794
     * Check if shows are saved in the current user's Spotify library.
1795
     * https://developer.spotify.com/documentation/web-api/reference/check-users-saved-shows
1796
     *
1797
     * @param string|array $shows Show IDs or URIs to check for.
1798
     *
1799
     * @return array Whether each show is saved.
1800
     */
1801
    public function myShowsContains(string|array $shows): array
1802
    {
1803
        $shows = $this->uriToId($shows, 'show');
3✔
1804
        $shows = $this->toCommaString($shows);
3✔
1805

1806
        $options = [
3✔
1807
            'ids' => $shows,
3✔
1808
        ];
3✔
1809

1810
        $uri = '/v1/me/shows/contains';
3✔
1811

1812
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1813

1814
        return $this->lastResponse['body'];
3✔
1815
    }
1816

1817
    /**
1818
     * Check if tracks are saved in the current user's Spotify library.
1819
     * https://developer.spotify.com/documentation/web-api/reference/check-users-saved-tracks
1820
     *
1821
     * @param string|array $tracks Track IDs or URIs to check for.
1822
     *
1823
     * @return array Whether each track is saved.
1824
     */
1825
    public function myTracksContains(string|array $tracks): array
1826
    {
1827
        $tracks = $this->uriToId($tracks, 'track');
3✔
1828
        $tracks = $this->toCommaString($tracks);
3✔
1829

1830
        $options = [
3✔
1831
            'ids' => $tracks,
3✔
1832
        ];
3✔
1833

1834
        $uri = '/v1/me/tracks/contains';
3✔
1835

1836
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
1837

1838
        return $this->lastResponse['body'];
3✔
1839
    }
1840

1841
    /**
1842
     * Play the next track in the current users's queue.
1843
     * https://developer.spotify.com/documentation/web-api/reference/skip-users-playback-to-next-track
1844
     *
1845
     * @param string $deviceId Optional. ID of the device to target.
1846
     *
1847
     * @return bool Whether the track was successfully skipped.
1848
     */
1849
    public function next(string $deviceId = ''): bool
1850
    {
1851
        $uri = '/v1/me/player/next';
3✔
1852

1853
        // We need to manually append data to the URI since it's a POST request
1854
        if ($deviceId) {
3✔
1855
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1856
        }
1857

1858
        $this->lastResponse = $this->sendRequest('POST', $uri);
3✔
1859

1860
        return $this->lastResponse['status'] == 204;
3✔
1861
    }
1862

1863
    /**
1864
     * Pause playback for the current user.
1865
     * https://developer.spotify.com/documentation/web-api/reference/pause-a-users-playback
1866
     *
1867
     * @param string $deviceId Optional. ID of the device to pause on.
1868
     *
1869
     * @return bool Whether the playback was successfully paused.
1870
     */
1871
    public function pause(string $deviceId = ''): bool
1872
    {
1873
        $uri = '/v1/me/player/pause';
3✔
1874

1875
        // We need to manually append data to the URI since it's a PUT request
1876
        if ($deviceId) {
3✔
1877
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1878
        }
1879

1880
        $this->lastResponse = $this->sendRequest('PUT', $uri);
3✔
1881

1882
        return $this->lastResponse['status'] == 204;
3✔
1883
    }
1884

1885
    /**
1886
     * Start playback for the current user.
1887
     * https://developer.spotify.com/documentation/web-api/reference/start-a-users-playback
1888
     *
1889
     * @param string $deviceId Optional. ID of the device to play on.
1890
     * @param array|object $options Optional. Options for the playback.
1891
     * - string context_uri Optional. URI of the context to play, for example an album.
1892
     * - array uris Optional. Spotify track URIs to play.
1893
     * - object offset Optional. Indicates from where in the context playback should start.
1894
     * - int position_ms. Optional. Indicates the position to start playback from.
1895
     *
1896
     * @return bool Whether the playback was successfully started.
1897
     */
1898
    public function play(string $deviceId = '', array|object $options = []): bool
1899
    {
1900
        $options = $options ? json_encode($options) : '';
3✔
1901

1902
        $headers = [
3✔
1903
            'Content-Type' => 'application/json',
3✔
1904
        ];
3✔
1905

1906
        $uri = '/v1/me/player/play';
3✔
1907

1908
        // We need to manually append data to the URI since it's a PUT request
1909
        if ($deviceId) {
3✔
1910
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1911
        }
1912

1913
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
3✔
1914

1915
        return $this->lastResponse['status'] == 204;
3✔
1916
    }
1917

1918
    /**
1919
     * Play the previous track in the current users's queue.
1920
     * https://developer.spotify.com/documentation/web-api/reference/skip-users-playback-to-previous-track
1921
     *
1922
     * @param string $deviceId Optional. ID of the device to target.
1923
     *
1924
     * @return bool Whether the track was successfully skipped.
1925
     */
1926
    public function previous(string $deviceId = ''): bool
1927
    {
1928
        $uri = '/v1/me/player/previous';
3✔
1929

1930
        // We need to manually append data to the URI since it's a POST request
1931
        if ($deviceId) {
3✔
1932
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1933
        }
1934

1935
        $this->lastResponse = $this->sendRequest('POST', $uri);
3✔
1936

1937
        return $this->lastResponse['status'] == 204;
3✔
1938
    }
1939

1940
    /**
1941
     * Add an item to the queue.
1942
     * https://developer.spotify.com/documentation/web-api/reference/add-to-queue
1943
     *
1944
     * @param string $trackUri Required. Track ID, track URI or episode URI to queue.
1945
     * @param string $deviceId Optional. ID of the device to target.
1946
     *
1947
     * @return bool Whether the track was successfully queued.
1948
     */
1949
    public function queue(string $trackUri, string $deviceId = ''): bool
1950
    {
1951
        $uri = '/v1/me/player/queue?uri=' . $this->idToUri($trackUri, 'track');
6✔
1952

1953
        // We need to manually append data to the URI since it's a POST request
1954
        if ($deviceId) {
6✔
1955
            $uri = $uri . '&device_id=' . $deviceId;
6✔
1956
        }
1957

1958
        $this->lastResponse = $this->sendRequest('POST', $uri);
6✔
1959

1960
        return $this->lastResponse['status'] == 204;
6✔
1961
    }
1962

1963
    /**
1964
     * Reorder the tracks in a playlist.
1965
     * https://developer.spotify.com/documentation/web-api/reference/reorder-or-replace-playlists-tracks
1966
     *
1967
     * @param string $playlistId ID or URI of the playlist.
1968
     * @param array|object $options Options for the new tracks.
1969
     * - int range_start Required. Position of the first track to be reordered.
1970
     * - int range_length Optional. The amount of tracks to be reordered.
1971
     * - int insert_before Required. Position where the tracks should be inserted.
1972
     * - string snapshot_id Optional. The playlist's snapshot ID.
1973
     *
1974
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully reordered.
1975
     */
1976
    public function reorderPlaylistTracks(string $playlistId, array|object $options): string|bool
1977
    {
1978
        $options = json_encode($options);
6✔
1979

1980
        $headers = [
6✔
1981
            'Content-Type' => 'application/json',
6✔
1982
        ];
6✔
1983

1984
        $playlistId = $this->uriToId($playlistId, 'playlist');
6✔
1985

1986
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
6✔
1987

1988
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
6✔
1989

1990
        return $this->getSnapshotId($this->lastResponse['body']);
6✔
1991
    }
1992

1993
    /**
1994
     * Set repeat mode for the current user’s playback.
1995
     * https://developer.spotify.com/documentation/web-api/reference/set-repeat-mode-on-users-playback
1996
     *
1997
     * @param array|object $options Optional. Options for the playback repeat mode.
1998
     * - string state Required. The repeat mode. See Spotify docs for possible values.
1999
     * - string device_id Optional. ID of the device to target.
2000
     *
2001
     * @return bool Whether the playback repeat mode was successfully changed.
2002
     */
2003
    public function repeat(array|object $options): bool
2004
    {
2005
        $options = http_build_query($options, '', '&');
3✔
2006

2007
        // We need to manually append data to the URI since it's a PUT request
2008
        $uri = '/v1/me/player/repeat?' . $options;
3✔
2009

2010
        $this->lastResponse = $this->sendRequest('PUT', $uri);
3✔
2011

2012
        return $this->lastResponse['status'] == 204;
3✔
2013
    }
2014

2015
    /**
2016
     * Replace all tracks in a playlist with new ones.
2017
     * https://developer.spotify.com/documentation/web-api/reference/reorder-or-replace-playlists-tracks
2018
     *
2019
     * @param string $playlistId ID or URI of the playlist.
2020
     * @param string|array $tracks IDs, track URIs, or episode URIs to replace with.
2021
     *
2022
     * @return bool Whether the tracks was successfully replaced.
2023
     */
2024
    public function replacePlaylistTracks(string $playlistId, string|array $tracks): bool
2025
    {
2026
        $tracks = $this->idToUri($tracks, 'track');
3✔
2027
        $tracks = json_encode([
3✔
2028
            'uris' => (array) $tracks,
3✔
2029
        ]);
3✔
2030

2031
        $headers = [
3✔
2032
            'Content-Type' => 'application/json',
3✔
2033
        ];
3✔
2034

2035
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2036

2037
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
3✔
2038

2039
        $this->lastResponse = $this->sendRequest('PUT', $uri, $tracks, $headers);
3✔
2040

2041
        return $this->lastResponse['status'] == 200;
3✔
2042
    }
2043

2044
    /**
2045
     * Search for an item.
2046
     * https://developer.spotify.com/documentation/web-api/reference/search
2047
     *
2048
     * @param string $query The term to search for.
2049
     * @param string|array $type The type of item to search for.
2050
     * @param array|object $options Optional. Options for the search.
2051
     * - string market Optional. Limit the results to items that are playable in this market, for example SE.
2052
     * - int limit Optional. Limit the number of items.
2053
     * - int offset Optional. Number of items to skip.
2054
     * - string include_external Optional. Whether or not to mark externally hosted content as playable.
2055
     *
2056
     * @return array|object The search results. Type is controlled by the `return_assoc` option.
2057
     */
2058
    public function search(string $query, string|array $type, array|object $options = []): array|object
2059
    {
2060
        $options = array_merge((array) $options, [
3✔
2061
            'q' => $query,
3✔
2062
            'type' => $this->toCommaString($type),
3✔
2063
        ]);
3✔
2064

2065
        $uri = '/v1/search';
3✔
2066

2067
        $this->lastResponse = $this->sendRequest('GET', $uri, $options);
3✔
2068

2069
        return $this->lastResponse['body'];
3✔
2070
    }
2071

2072
    /**
2073
     * Change playback position for the current user.
2074
     * https://developer.spotify.com/documentation/web-api/reference/seek-to-position-in-currently-playing-track
2075
     *
2076
     * @param array|object $options Optional. Options for the playback seeking.
2077
     * - string position_ms Required. The position in milliseconds to seek to.
2078
     * - string device_id Optional. ID of the device to target.
2079
     *
2080
     * @return bool Whether the playback position was successfully changed.
2081
     */
2082
    public function seek(array|object $options): bool
2083
    {
2084
        $options = http_build_query($options, '', '&');
3✔
2085

2086
        // We need to manually append data to the URI since it's a PUT request
2087
        $uri = '/v1/me/player/seek?' . $options;
3✔
2088

2089
        $this->lastResponse = $this->sendRequest('PUT', $uri);
3✔
2090

2091
        return $this->lastResponse['status'] == 204;
3✔
2092
    }
2093

2094
    /**
2095
     * Set the access token to use.
2096
     *
2097
     * @param string $accessToken The access token.
2098
     *
2099
     * @return self
2100
     */
2101
    public function setAccessToken(string $accessToken): self
2102
    {
2103
        $this->accessToken = $accessToken;
6✔
2104

2105
        return $this;
6✔
2106
    }
2107

2108
    /**
2109
     * Set options
2110
     *
2111
     * @param array|object $options Options to set.
2112
     *
2113
     * @return self
2114
     */
2115
    public function setOptions(array|object $options): self
2116
    {
2117
        $this->options = array_merge($this->options, (array) $options);
297✔
2118

2119
        return $this;
297✔
2120
    }
2121

2122
    /**
2123
     * Set the Session object to use.
2124
     *
2125
     * @param Session $session The Session object.
2126
     *
2127
     * @return self
2128
     */
2129
    public function setSession(?Session $session): self
2130
    {
2131
        $this->session = $session;
297✔
2132

2133
        return $this;
297✔
2134
    }
2135

2136
    /**
2137
     * Set shuffle mode for the current user’s playback.
2138
     * https://developer.spotify.com/documentation/web-api/reference/toggle-shuffle-for-users-playback
2139
     *
2140
     * @param array|object $options Optional. Options for the playback shuffle mode.
2141
     * - bool state Required. The shuffle mode. See Spotify docs for possible values.
2142
     * - string device_id Optional. ID of the device to target.
2143
     *
2144
     * @return bool Whether the playback shuffle mode was successfully changed.
2145
     */
2146
    public function shuffle(array|object $options): bool
2147
    {
2148
        $options = array_merge((array) $options, [
3✔
2149
            'state' => $options['state'] ? 'true' : 'false',
3✔
2150
        ]);
3✔
2151

2152
        $options = http_build_query($options, '', '&');
3✔
2153

2154
        // We need to manually append data to the URI since it's a PUT request
2155
        $uri = '/v1/me/player/shuffle?' . $options;
3✔
2156

2157
        $this->lastResponse = $this->sendRequest('PUT', $uri);
3✔
2158

2159
        return $this->lastResponse['status'] == 204;
3✔
2160
    }
2161

2162
    /**
2163
     * Remove the current user as a follower of one or more artists or other Spotify users.
2164
     * https://developer.spotify.com/documentation/web-api/reference/unfollow-artists-users
2165
     *
2166
     * @param string $type The type to check: either 'artist' or 'user'.
2167
     * @param string|array $ids IDs or URIs of the users or artists to unfollow.
2168
     *
2169
     * @return bool Whether the artists or users were successfully unfollowed.
2170
     */
2171
    public function unfollowArtistsOrUsers(string $type, string|array $ids): bool
2172
    {
2173
        $ids = $this->uriToId($ids, $type);
3✔
2174
        $ids = json_encode([
3✔
2175
            'ids' => (array) $ids,
3✔
2176
        ]);
3✔
2177

2178
        $headers = [
3✔
2179
            'Content-Type' => 'application/json',
3✔
2180
        ];
3✔
2181

2182
        // We need to manually append data to the URI since it's a DELETE request
2183
        $uri = '/v1/me/following?type=' . $type;
3✔
2184

2185
        $this->lastResponse = $this->sendRequest('DELETE', $uri, $ids, $headers);
3✔
2186

2187
        return $this->lastResponse['status'] == 204;
3✔
2188
    }
2189

2190
    /**
2191
     * Remove the current user as a follower of a playlist.
2192
     * https://developer.spotify.com/documentation/web-api/reference/unfollow-playlist
2193
     *
2194
     * @param string $playlistId ID or URI of the playlist to unfollow.
2195
     *
2196
     * @return bool Whether the playlist was successfully unfollowed.
2197
     */
2198
    public function unfollowPlaylist(string $playlistId): bool
2199
    {
2200
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2201
        $uri = '/v1/playlists/' . $playlistId . '/followers';
3✔
2202

2203
        $this->lastResponse = $this->sendRequest('DELETE', $uri);
3✔
2204

2205
        return $this->lastResponse['status'] == 200;
3✔
2206
    }
2207

2208
    /**
2209
     * Update the details of a playlist.
2210
     * https://developer.spotify.com/documentation/web-api/reference/change-playlist-details
2211
     *
2212
     * @param string $playlistId ID or URI of the playlist to update.
2213
     * @param array|object $options Options for the playlist.
2214
     * - bool collaborative Optional. Whether the playlist should be collaborative or not.
2215
     * - string description Optional. Description of the playlist.
2216
     * - string name Optional. Name of the playlist.
2217
     * - bool public Optional. Whether the playlist should be public or not.
2218
     *
2219
     * @return bool Whether the playlist was successfully updated.
2220
     */
2221
    public function updatePlaylist(string $playlistId, array|object $options): bool
2222
    {
2223
        $options = json_encode($options);
3✔
2224

2225
        $headers = [
3✔
2226
            'Content-Type' => 'application/json',
3✔
2227
        ];
3✔
2228

2229
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2230

2231
        $uri = '/v1/playlists/' . $playlistId;
3✔
2232

2233
        $this->lastResponse = $this->sendRequest('PUT', $uri, $options, $headers);
3✔
2234

2235
        return $this->lastResponse['status'] == 200;
3✔
2236
    }
2237

2238
    /**
2239
     * Update the image of a playlist.
2240
     * https://developer.spotify.com/documentation/web-api/reference/upload-custom-playlist-cover
2241
     *
2242
     * @param string $playlistId ID or URI of the playlist to update.
2243
     * @param string $imageData Base64 encoded JPEG image data, maximum 256 KB in size.
2244
     *
2245
     * @return bool Whether the playlist was successfully updated.
2246
     */
2247
    public function updatePlaylistImage(string $playlistId, string $imageData): bool
2248
    {
2249
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2250

2251
        $uri = '/v1/playlists/' . $playlistId . '/images';
3✔
2252

2253
        $this->lastResponse = $this->sendRequest('PUT', $uri, $imageData);
3✔
2254

2255
        return $this->lastResponse['status'] == 202;
3✔
2256
    }
2257
}
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