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

jwilsson / spotify-web-api-php / 11261332500

09 Oct 2024 06:59PM UTC coverage: 98.701% (+0.03%) from 98.674%
11261332500

push

github

jwilsson
Correct SpotifyWebAPI::deleteMy* request bodies

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

1 existing line in 1 file now uncovered.

760 of 770 relevant lines covered (98.7%)

15.99 hits per line

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

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

3
declare(strict_types=1);
4

5
namespace SpotifyWebAPI;
6

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

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

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

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

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

52
        return $headers;
285✔
53
    }
54

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

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

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

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

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

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

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

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

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

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

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

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

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

140
            throw $e;
×
141
        }
142
    }
143

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

157
        return $value;
3✔
158
    }
159

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

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

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

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

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

198
        $uri = '/v1/me/albums';
3✔
199

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

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

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

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

224
        $uri = '/v1/me/episodes';
3✔
225

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

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

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

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

250
        $uri = '/v1/me/shows';
3✔
251

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

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

257
    /**
258
     * Add tracks to the current user's Spotify library.
259
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/save-tracks-user
260
     *
261
     * @param string|array $tracks Track IDs or URIs to add.
262
     *
263
     * @return bool Whether the tracks was successfully added.
264
     */
265
    public function addMyTracks(string|array $tracks): bool
266
    {
267
        $tracks = $this->uriToId($tracks, 'track');
3✔
268
        $tracks = json_encode([
3✔
269
            'ids' => (array) $tracks,
3✔
270
        ]);
3✔
271

272
        $headers = [
3✔
273
            'Content-Type' => 'application/json',
3✔
274
        ];
3✔
275

276
        $uri = '/v1/me/tracks';
3✔
277

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

280
        return $this->lastResponse['status'] == 200;
3✔
281
    }
282

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

303
        $options = json_encode($options);
6✔
304

305
        $headers = [
6✔
306
            'Content-Type' => 'application/json',
6✔
307
        ];
6✔
308

309
        $playlistId = $this->uriToId($playlistId, 'playlist');
6✔
310

311
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
6✔
312

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

315
        return $this->getSnapshotId($this->lastResponse['body']);
6✔
316
    }
317

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

334
        $options = json_encode($options);
3✔
335

336
        $headers = [
3✔
337
            'Content-Type' => 'application/json',
3✔
338
        ];
3✔
339

340
        $uri = '/v1/me/player';
3✔
341

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

344
        return $this->lastResponse['status'] == 204;
3✔
345
    }
346

347
    /**
348
     * Change playback volume for the current user.
349
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/set-volume-for-users-playback
350
     *
351
     * @param array|object $options Optional. Options for the playback volume.
352
     * - int volume_percent Required. The volume to set.
353
     * - string device_id Optional. ID of the device to target.
354
     *
355
     * @return bool Whether the playback volume was successfully changed.
356
     */
357
    public function changeVolume(array|object $options): bool
358
    {
359
        $options = http_build_query($options, '', '&');
3✔
360

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

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

366
        return $this->lastResponse['status'] == 204;
3✔
367
    }
368

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

390
            $options = $userId;
3✔
391
            $uri = '/v1/me/playlists';
3✔
392
        } else {
393
            $userId = $this->uriToId($userId, 'user');
3✔
394
            $uri = '/v1/users/' . $userId . '/playlists';
3✔
395
        }
396

397
        $options = json_encode($options);
6✔
398

399
        $headers = [
6✔
400
            'Content-Type' => 'application/json',
6✔
401
        ];
6✔
402

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

405
        return $this->lastResponse['body'];
6✔
406
    }
407

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

422
        $options = [
3✔
423
            'ids' => $ids,
3✔
424
            'type' => $type,
3✔
425
        ];
3✔
426

427
        $uri = '/v1/me/following/contains';
3✔
428

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

431
        return $this->lastResponse['body'];
3✔
432
    }
433

434
    /**
435
     * Delete albums from the current user's Spotify library.
436
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-albums-user
437
     *
438
     * @param string|array $albums Album IDs or URIs to delete.
439
     *
440
     * @return bool Whether the albums was successfully deleted.
441
     */
442
    public function deleteMyAlbums(string|array $albums): bool
443
    {
444
        $albums = $this->uriToId($albums, 'album');
3✔
445
        $albums = json_encode([
3✔
446
            'ids' => (array) $albums,
3✔
447
        ]);
3✔
448

449
        $headers = [
3✔
450
            'Content-Type' => 'application/json',
3✔
451
        ];
3✔
452

453
        $uri = '/v1/me/albums';
3✔
454

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

457
        return $this->lastResponse['status'] == 200;
3✔
458
    }
459

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

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

479
        $uri = '/v1/me/episodes';
3✔
480

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

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

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

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

505
        $uri = '/v1/me/shows';
3✔
506

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

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

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

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

531
        $uri = '/v1/me/tracks';
3✔
532

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

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

538
    /**
539
     * Delete tracks from a playlist and retrieve a new snapshot ID.
540
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-tracks-playlist
541
     *
542
     * @param string $playlistId ID or URI of the playlist to delete tracks from.
543
     * @param array $tracks An array with the key "tracks" containing arrays or objects with tracks to delete.
544
     * Or an array with the key "positions" containing integer positions of the tracks to delete.
545
     * If the "tracks" key is used, the following fields are also available:
546
     * - string uri Required. Track ID, track URI, or episode URI.
547
     * - int|array positions Optional. The track's positions in the playlist.
548
     * @param string $snapshotId Required when `$tracks['positions']` is used, optional otherwise.
549
     * The playlist's snapshot ID.
550
     *
551
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully deleted.
552
     */
553
    public function deletePlaylistTracks(string $playlistId, array $tracks, string $snapshotId = ''): string|bool
554
    {
555
        $options = [];
9✔
556

557
        if ($snapshotId) {
9✔
558
            $options['snapshot_id'] = $snapshotId;
6✔
559
        }
560

561
        if (isset($tracks['positions'])) {
9✔
562
            $options['positions'] = $tracks['positions'];
6✔
563
        } else {
564
            $options['tracks'] = array_map(function ($track) {
3✔
565
                $track = (array) $track;
3✔
566

567
                if (isset($track['positions'])) {
3✔
568
                    $track['positions'] = (array) $track['positions'];
3✔
569
                }
570

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

573
                return $track;
3✔
574
            }, $tracks['tracks']);
3✔
575
        }
576

577
        $options = json_encode($options);
9✔
578

579
        $headers = [
9✔
580
            'Content-Type' => 'application/json',
9✔
581
        ];
9✔
582

583
        $playlistId = $this->uriToId($playlistId, 'playlist');
9✔
584

585
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
9✔
586

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

589
        return $this->getSnapshotId($this->lastResponse['body']);
9✔
590
    }
591

592
    /**
593
     * Add the current user as a follower of one or more artists or other Spotify users.
594
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/follow-artists-users
595
     *
596
     * @param string $type The type of ID to follow: either 'artist' or 'user'.
597
     * @param string|array $ids IDs or URIs of the users or artists to follow.
598
     *
599
     * @return bool Whether the artist or user was successfully followed.
600
     */
601
    public function followArtistsOrUsers(string $type, string|array $ids): bool
602
    {
603
        $ids = $this->uriToId($ids, $type);
3✔
604
        $ids = json_encode([
3✔
605
            'ids' => (array) $ids,
3✔
606
        ]);
3✔
607

608
        $headers = [
3✔
609
            'Content-Type' => 'application/json',
3✔
610
        ];
3✔
611

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

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

617
        return $this->lastResponse['status'] == 204;
3✔
618
    }
619

620
    /**
621
     * Add the current user as a follower of a playlist.
622
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/follow-playlist
623
     *
624
     * @param string $playlistId ID or URI of the playlist to follow.
625
     * @param array|object $options Optional. Options for the followed playlist.
626
     * - bool public Optional. Whether the playlist should be followed publicly or not.
627
     *
628
     * @return bool Whether the playlist was successfully followed.
629
     */
630
    public function followPlaylist(string $playlistId, array|object $options = []): bool
631
    {
632
        $options = $options ? json_encode($options) : '';
3✔
633

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

638
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
639

640
        $uri = '/v1/playlists/' . $playlistId . '/followers';
3✔
641

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

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

647
    /**
648
     * Get an album.
649
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-album
650
     *
651
     * @param string $albumId ID or URI of the album.
652
     * @param array|object $options Optional. Options for the album.
653
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
654
     *
655
     * @return array|object The requested album. Type is controlled by the `return_assoc` option.
656
     */
657
    public function getAlbum(string $albumId, array|object $options = []): array|object
658
    {
659
        $albumId = $this->uriToId($albumId, 'album');
3✔
660
        $uri = '/v1/albums/' . $albumId;
3✔
661

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

664
        return $this->lastResponse['body'];
3✔
665
    }
666

667
    /**
668
     * Get multiple albums.
669
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-albums
670
     *
671
     * @param array $albumIds IDs or URIs of the albums.
672
     * @param array|object $options Optional. Options for the albums.
673
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
674
     *
675
     * @return array|object The requested albums. Type is controlled by the `return_assoc` option.
676
     */
677
    public function getAlbums(array $albumIds, array|object $options = []): array|object
678
    {
679
        $albumIds = $this->uriToId($albumIds, 'album');
3✔
680
        $options = array_merge((array) $options, [
3✔
681
            'ids' => $this->toCommaString($albumIds),
3✔
682
        ]);
3✔
683

684
        $uri = '/v1/albums/';
3✔
685

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

688
        return $this->lastResponse['body'];
3✔
689
    }
690

691
    /**
692
     * Get an album's tracks.
693
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-albums-tracks
694
     *
695
     * @param string $albumId ID or URI of the album.
696
     * @param array|object $options Optional. Options for the tracks.
697
     * - int limit Optional. Limit the number of tracks.
698
     * - int offset Optional. Number of tracks to skip.
699
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
700
     *
701
     * @return array|object The requested album tracks. Type is controlled by the `return_assoc` option.
702
     */
703
    public function getAlbumTracks(string $albumId, array|object $options = []): array|object
704
    {
705
        $albumId = $this->uriToId($albumId, 'album');
3✔
706
        $uri = '/v1/albums/' . $albumId . '/tracks';
3✔
707

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

710
        return $this->lastResponse['body'];
3✔
711
    }
712

713
    /**
714
     * Get an artist.
715
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artist
716
     *
717
     * @param string $artistId ID or URI of the artist.
718
     *
719
     * @return array|object The requested artist. Type is controlled by the `return_assoc` option.
720
     */
721
    public function getArtist(string $artistId): array|object
722
    {
723
        $artistId = $this->uriToId($artistId, 'artist');
3✔
724
        $uri = '/v1/artists/' . $artistId;
3✔
725

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

728
        return $this->lastResponse['body'];
3✔
729
    }
730

731
    /**
732
     * Get multiple artists.
733
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-artists
734
     *
735
     * @param array $artistIds IDs or URIs of the artists.
736
     *
737
     * @return array|object The requested artists. Type is controlled by the `return_assoc` option.
738
     */
739
    public function getArtists(array $artistIds): array|object
740
    {
741
        $artistIds = $this->uriToId($artistIds, 'artist');
3✔
742
        $artistIds = $this->toCommaString($artistIds);
3✔
743

744
        $options = [
3✔
745
            'ids' => $artistIds,
3✔
746
        ];
3✔
747

748
        $uri = '/v1/artists/';
3✔
749

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

752
        return $this->lastResponse['body'];
3✔
753
    }
754

755
    /**
756
     * Get an artist's related artists.
757
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artists-related-artists
758
     *
759
     * @param string $artistId ID or URI of the artist.
760
     *
761
     * @return array|object The artist's related artists. Type is controlled by the `return_assoc` option.
762
     */
763
    public function getArtistRelatedArtists(string $artistId): array|object
764
    {
765
        $artistId = $this->uriToId($artistId, 'artist');
3✔
766
        $uri = '/v1/artists/' . $artistId . '/related-artists';
3✔
767

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

770
        return $this->lastResponse['body'];
3✔
771
    }
772

773
    /**
774
     * Get an artist's albums.
775
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artists-albums
776
     *
777
     * @param string $artistId ID or URI of the artist.
778
     * @param array|object $options Optional. Options for the albums.
779
     * - string market Optional. Limit the results to items that are playable in this country, for example SE.
780
     * - string|array include_groups Optional. Album types to return. If omitted, all album types will be returned.
781
     * - int limit Optional. Limit the number of albums.
782
     * - int offset Optional. Number of albums to skip.
783
     *
784
     * @return array|object The artist's albums. Type is controlled by the `return_assoc` option.
785
     */
786
    public function getArtistAlbums(string $artistId, array|object $options = []): array|object
787
    {
788
        $options = (array) $options;
3✔
789

790
        if (isset($options['include_groups'])) {
3✔
791
            $options['include_groups'] = $this->toCommaString($options['include_groups']);
3✔
792
        }
793

794
        $artistId = $this->uriToId($artistId, 'artist');
3✔
795
        $uri = '/v1/artists/' . $artistId . '/albums';
3✔
796

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

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

802
    /**
803
     * Get an artist's top tracks in a country.
804
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-artists-top-tracks
805
     *
806
     * @param string $artistId ID or URI of the artist.
807
     * @param array|object $options Options for the tracks.
808
     * - string market Required. An ISO 3166-1 alpha-2 country code specifying the country to get the top tracks for.
809
     *
810
     * @return array|object The artist's top tracks. Type is controlled by the `return_assoc` option.
811
     */
812
    public function getArtistTopTracks(string $artistId, array|object $options): array|object
813
    {
814
        $artistId = $this->uriToId($artistId, 'artist');
3✔
815
        $uri = '/v1/artists/' . $artistId . '/top-tracks';
3✔
816

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

819
        return $this->lastResponse['body'];
3✔
820
    }
821

822
    /**
823
     * Get audio analysis for track.
824
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-audio-analysis
825
     *
826
     * @param string $trackId ID or URI of the track.
827
     *
828
     * @return array|object The track's audio analysis. Type is controlled by the `return_assoc` option.
829
     */
830
    public function getAudioAnalysis(string $trackId): array|object
831
    {
832
        $trackId = $this->uriToId($trackId, 'track');
3✔
833
        $uri = '/v1/audio-analysis/' . $trackId;
3✔
834

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

837
        return $this->lastResponse['body'];
3✔
838
    }
839

840
    /**
841
     * Get an audiobook.
842
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-audiobook
843
     *
844
     * @param string $audiobookId ID or URI of the audiobook.
845
     * @param array|object $options Optional. Options for the audiobook.
846
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to audiobooks available in that market.
847
     *
848
     * @return array|object The requested audiobook. Type is controlled by the `return_assoc` option.
849
     */
850
    public function getAudiobook(string $audiobookId, array|object $options = [])
851
    {
852
        $audiobookId = $this->uriToId($audiobookId, 'show');
3✔
853
        $uri = '/v1/audiobooks/' . $audiobookId;
3✔
854

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

857
        return $this->lastResponse['body'];
3✔
858
    }
859

860
    /**
861
     * Get multiple audiobooks.
862
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-audiobooks
863
     *
864
     * @param array $audiobookIds IDs or URIs of the audiobooks.
865
     * @param array|object $options Optional. Options for the audiobooks.
866
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to audiobooks available in that market.
867
     *
868
     * @return array|object The requested audiobooks. Type is controlled by the `return_assoc` option.
869
     */
870
    public function getAudiobooks(array $audiobookIds, array|object $options = [])
871
    {
872
        $audiobookIds = $this->uriToId($audiobookIds, 'show');
3✔
873
        $audiobookIds = $this->toCommaString($audiobookIds);
3✔
874

875
        $options = array_merge((array) $options, [
3✔
876
            'ids' => $this->toCommaString($audiobookIds),
3✔
877
        ]);
3✔
878

879
        $uri = '/v1/audiobooks/';
3✔
880

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

883
        return $this->lastResponse['body'];
3✔
884
    }
885

886
    /**
887
     * Get audio features of a single track.
888
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-audio-features
889
     *
890
     * @param string $trackId ID or URI of the track.
891
     *
892
     * @return array|object The track's audio features. Type is controlled by the `return_assoc` option.
893
     */
894
    public function getAudioFeatures(string $trackId): array|object
895
    {
896
        $trackId = $this->uriToId($trackId, 'track');
3✔
897
        $uri = '/v1/audio-features/' . $trackId;
3✔
898

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

901
        return $this->lastResponse['body'];
3✔
902
    }
903

904
    /**
905
     * Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s "Discover" tab).
906
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-categories
907
     *
908
     * @param array|object $options Optional. Options for the categories.
909
     * - string locale Optional. Language to show categories in, for example 'sv_SE'.
910
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show categories from this country.
911
     * - int limit Optional. Limit the number of categories.
912
     * - int offset Optional. Number of categories to skip.
913
     *
914
     * @return array|object The list of categories. Type is controlled by the `return_assoc` option.
915
     */
916
    public function getCategoriesList(array|object $options = []): array|object
917
    {
918
        $uri = '/v1/browse/categories';
3✔
919

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

922
        return $this->lastResponse['body'];
3✔
923
    }
924

925
    /**
926
     * Get a single category used to tag items in Spotify (on, for example, the Spotify player’s "Discover" tab).
927
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-category
928
     *
929
     * @param string $categoryId ID of the category.
930
     *
931
     * @param array|object $options Optional. Options for the category.
932
     * - string locale Optional. Language to show category in, for example 'sv_SE'.
933
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show category from this country.
934
     *
935
     * @return array|object The category. Type is controlled by the `return_assoc` option.
936
     */
937
    public function getCategory(string $categoryId, array|object $options = []): array|object
938
    {
939
        $uri = '/v1/browse/categories/' . $categoryId;
3✔
940

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

943
        return $this->lastResponse['body'];
3✔
944
    }
945

946
    /**
947
     * Get a list of Spotify playlists tagged with a particular category.
948
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-categories-playlists
949
     *
950
     * @param string $categoryId ID of the category.
951
     *
952
     * @param array|object $options Optional. Options for the category's playlists.
953
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show category playlists from this country.
954
     * - int limit Optional. Limit the number of playlists.
955
     * - int offset Optional. Number of playlists to skip.
956
     *
957
     * @return array|object The list of playlists. Type is controlled by the `return_assoc` option.
958
     */
959
    public function getCategoryPlaylists(string $categoryId, array|object $options = []): array|object
960
    {
961
        $uri = '/v1/browse/categories/' . $categoryId . '/playlists';
3✔
962

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

965
        return $this->lastResponse['body'];
3✔
966
    }
967

968
    /**
969
     * Get a chapter.
970
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-chapter
971
     *
972
     * @param string $chapterId ID or URI of the chapter.
973
     * @param array|object $options Optional. Options for the chapter.
974
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
975
     *
976
     * @return array|object The requested chapter. Type is controlled by the `return_assoc` option.
977
     */
978
    public function getChapter(string $chapterId, array|object $options = [])
979
    {
980
        $chapterId = $this->uriToId($chapterId, 'episode');
3✔
981
        $uri = '/v1/chapters/' . $chapterId;
3✔
982

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

985
        return $this->lastResponse['body'];
3✔
986
    }
987

988
    /**
989
     * Get multiple chapters.
990
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-chapters
991
     *
992
     * @param array $chapterIds IDs or URIs of the chapters.
993
     * @param array|object $options Optional. Options for the chapters.
994
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
995
     *
996
     * @return array|object The requested chapters. Type is controlled by the `return_assoc` option.
997
     */
998
    public function getChapters(array $chapterIds, array|object $options = [])
999
    {
1000
        $chapterIds = $this->uriToId($chapterIds, 'episode');
3✔
1001
        $options = array_merge((array) $options, [
3✔
1002
            'ids' => $this->toCommaString($chapterIds),
3✔
1003
        ]);
3✔
1004

1005
        $uri = '/v1/chapters/';
3✔
1006

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

1009
        return $this->lastResponse['body'];
3✔
1010
    }
1011

1012
    /**
1013
     * Get an episode.
1014
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-an-episode
1015
     *
1016
     * @param string $episodeId ID or URI of the episode.
1017
     * @param array|object $options Optional. Options for the episode.
1018
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1019
     *
1020
     * @return array|object The requested episode. Type is controlled by the `return_assoc` option.
1021
     */
1022
    public function getEpisode(string $episodeId, array|object $options = []): array|object
1023
    {
1024
        $episodeId = $this->uriToId($episodeId, 'episode');
3✔
1025
        $uri = '/v1/episodes/' . $episodeId;
3✔
1026

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

1029
        return $this->lastResponse['body'];
3✔
1030
    }
1031

1032
    /**
1033
     * Get multiple episodes.
1034
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-multiple-episodes
1035
     *
1036
     * @param string|array $episodeIds IDs or URIs of the episodes.
1037
     * @param array|object $options Optional. Options for the episodes.
1038
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1039
     *
1040
     * @return array|object The requested episodes. Type is controlled by the `return_assoc` option.
1041
     */
1042
    public function getEpisodes(string|array $episodeIds, array|object $options = []): array|object
1043
    {
1044
        $episodeIds = $this->uriToId($episodeIds, 'episode');
3✔
1045
        $options = array_merge((array) $options, [
3✔
1046
            'ids' => $this->toCommaString($episodeIds),
3✔
1047
        ]);
3✔
1048

1049
        $uri = '/v1/episodes/';
3✔
1050

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

1053
        return $this->lastResponse['body'];
3✔
1054
    }
1055

1056
    /**
1057
     * Get Spotify featured playlists.
1058
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-featured-playlists
1059
     *
1060
     * @param array|object $options Optional. Options for the playlists.
1061
     * - string locale Optional. Language to show playlists in, for example 'sv_SE'.
1062
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show playlists from this country.
1063
     * - string timestamp Optional. A ISO 8601 timestamp. Show playlists relevant to this date and time.
1064
     * - int limit Optional. Limit the number of playlists.
1065
     * - int offset Optional. Number of playlists to skip.
1066
     *
1067
     * @return array|object The featured playlists. Type is controlled by the `return_assoc` option.
1068
     */
1069
    public function getFeaturedPlaylists(array|object $options = []): array|object
1070
    {
1071
        $uri = '/v1/browse/featured-playlists';
3✔
1072

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

1075
        return $this->lastResponse['body'];
3✔
1076
    }
1077

1078
    /**
1079
     * Get a list of possible seed genres.
1080
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-recommendation-genres
1081
     *
1082
     * @return array|object All possible seed genres. Type is controlled by the `return_assoc` option.
1083
     */
1084
    public function getGenreSeeds(): array|object
1085
    {
1086
        $uri = '/v1/recommendations/available-genre-seeds';
3✔
1087

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

1090
        return $this->lastResponse['body'];
3✔
1091
    }
1092

1093
    /**
1094
     * Get the latest full response from the Spotify API.
1095
     *
1096
     * @return array Response data.
1097
     * - array|object body The response body. Type is controlled by the `return_assoc` option.
1098
     * - array headers Response headers.
1099
     * - int status HTTP status code.
1100
     * - string url The requested URL.
1101
     */
1102
    public function getLastResponse(): array
1103
    {
1104
        return $this->lastResponse;
3✔
1105
    }
1106

1107
    /**
1108
     * Get all markets where Spotify is available.
1109
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-available-markets
1110
     *
1111
     * @return array|object All markets where Spotify is available. Type is controlled by the `return_assoc` option.
1112
     */
1113
    public function getMarkets(): array|object
1114
    {
1115
        $uri = '/v1/markets';
3✔
1116

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

1119
        return $this->lastResponse['body'];
3✔
1120
    }
1121

1122
    /**
1123
     * Get audio features of multiple tracks.
1124
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-audio-features
1125
     *
1126
     * @param string|array $trackIds IDs or URIs of the tracks.
1127
     *
1128
     * @return array|object The tracks' audio features. Type is controlled by the `return_assoc` option.
1129
     */
1130
    public function getMultipleAudioFeatures(string|array $trackIds): array|object
1131
    {
1132
        $trackIds = $this->uriToId($trackIds, 'track');
3✔
1133
        $options = [
3✔
1134
            'ids' => $this->toCommaString($trackIds),
3✔
1135
        ];
3✔
1136

1137
        $uri = '/v1/audio-features';
3✔
1138

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

1141
        return $this->lastResponse['body'];
3✔
1142
    }
1143

1144
    /**
1145
     * Get the current user’s currently playing track.
1146
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-the-users-currently-playing-track
1147
     *
1148
     * @param array|object $options Optional. Options for the track.
1149
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1150
     * - string|array additional_types Optional. Types of media to return info about.
1151
     *
1152
     * @return array|object|null The user's currently playing track or null if nothing's currently playing.
1153
     * Type is controlled by the `return_assoc` option.
1154
     */
1155
    public function getMyCurrentTrack(array|object $options = []): array|object|null
1156
    {
1157
        $uri = '/v1/me/player/currently-playing';
6✔
1158
        $options = (array) $options;
6✔
1159

1160
        if (isset($options['additional_types'])) {
6✔
1161
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
3✔
1162
        }
1163

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

1166
        return $this->lastResponse['body'];
6✔
1167
    }
1168

1169
    /**
1170
     * Get the current user’s devices.
1171
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-users-available-devices
1172
     *
1173
     * @return array|object The user's devices. Type is controlled by the `return_assoc` option.
1174
     */
1175
    public function getMyDevices(): array|object
1176
    {
1177
        $uri = '/v1/me/player/devices';
3✔
1178

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

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

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

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

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

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

1209

1210
    /**
1211
     * Get the current user’s playlists.
1212
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-list-of-current-users-playlists
1213
     *
1214
     * @param array|object $options Optional. Options for the playlists.
1215
     * - int limit Optional. Limit the number of playlists.
1216
     * - int offset Optional. Number of playlists to skip.
1217
     *
1218
     * @return array|object The user's playlists. Type is controlled by the `return_assoc` option.
1219
     */
1220
    public function getMyPlaylists(array|object $options = []): array|object
1221
    {
1222
        $uri = '/v1/me/playlists';
3✔
1223

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

1226
        return $this->lastResponse['body'];
3✔
1227
    }
1228

1229
    /**
1230
     * Get the current user’s queue.
1231
     *
1232
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-queue
1233
     *
1234
     * @return array|object The currently playing song and queue. Type is controlled by the `return_assoc` option.
1235
     */
1236
    public function getMyQueue()
1237
    {
1238
        $uri = '/v1/me/player/queue';
3✔
1239

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

1242
        return $this->lastResponse['body'];
3✔
1243
    }
1244

1245
    /**
1246
      * Get the current user’s recently played tracks.
1247
      * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-recently-played
1248
      *
1249
      * @param array|object $options Optional. Options for the tracks.
1250
      * - int limit Optional. Number of tracks to return.
1251
      * - string after Optional. Unix timestamp in ms (13 digits). Returns all items after this position.
1252
      * - string before Optional. Unix timestamp in ms (13 digits). Returns all items before this position.
1253
      *
1254
      * @return array|object The most recently played tracks. Type is controlled by the `return_assoc` option.
1255
      */
1256
    public function getMyRecentTracks(array|object $options = []): array|object
1257
    {
1258
        $uri = '/v1/me/player/recently-played';
3✔
1259

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

1262
        return $this->lastResponse['body'];
3✔
1263
    }
1264

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

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

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

1285
    /**
1286
     * Get the current user’s saved episodes.
1287
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-saved-episodes
1288
     *
1289
     * @param array|object $options Optional. Options for the episodes.
1290
     * - int limit Optional. Number of episodes to return.
1291
     * - int offset Optional. Number of episodes to skip.
1292
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1293
     *
1294
     * @return array|object The user's saved episodes. Type is controlled by the `return_assoc` option.
1295
     */
1296
    public function getMySavedEpisodes(array|object $options = []): array|object
1297
    {
1298
        $uri = '/v1/me/episodes';
3✔
1299

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

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

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

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

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

1325
    /**
1326
     * Get the current user’s saved shows.
1327
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-saved-shows
1328
     *
1329
     * @param array|object $options Optional. Options for the shows.
1330
     * - int limit Optional. Limit the number of shows.
1331
     * - int offset Optional. Number of shows to skip.
1332
     *
1333
     * @return array|object The user's saved shows. Type is controlled by the `return_assoc` option.
1334
     */
1335
    public function getMySavedShows(array|object $options = []): array|object
1336
    {
1337
        $uri = '/v1/me/shows';
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 top tracks or artists.
1346
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-top-artists-and-tracks
1347
     *
1348
     * @param string $type The type to fetch, either 'artists' or 'tracks'.
1349
     * @param array $options Optional. Options for the results.
1350
     * - int limit Optional. Limit the number of results.
1351
     * - int offset Optional. Number of results to skip.
1352
     * - string time_range Optional. Over what time frame the data is calculated. See Spotify API docs for more info.
1353
     *
1354
     * @return array|object A list of the requested top entity. Type is controlled by the `return_assoc` option.
1355
     */
1356
    public function getMyTop(string $type, array|object $options = []): array|object
1357
    {
1358
        $uri = '/v1/me/top/' . $type;
3✔
1359

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

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

1365
    /**
1366
     * Get new releases.
1367
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-new-releases
1368
     *
1369
     * @param array|object $options Optional. Options for the items.
1370
     * - string country Optional. ISO 3166-1 alpha-2 country code. Show items relevant to this country.
1371
     * - int limit Optional. Limit the number of items.
1372
     * - int offset Optional. Number of items to skip.
1373
     *
1374
     * @return array|object The new releases. Type is controlled by the `return_assoc` option.
1375
     */
1376
    public function getNewReleases(array|object $options = []): array|object
1377
    {
1378
        $uri = '/v1/browse/new-releases';
3✔
1379

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

1382
        return $this->lastResponse['body'];
3✔
1383
    }
1384

1385
    /**
1386
     * Get a specific playlist.
1387
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlist
1388
     *
1389
     * @param string $playlistId ID or URI of the playlist.
1390
     * @param array|object $options Optional. Options for the playlist.
1391
     * - string|array fields Optional. A list of fields to return. See Spotify docs for more info.
1392
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1393
     * - string|array additional_types Optional. Types of media to return info about.
1394
     *
1395
     * @return array|object The user's playlist. Type is controlled by the `return_assoc` option.
1396
     */
1397
    public function getPlaylist(string $playlistId, array|object $options = []): array|object
1398
    {
1399
        $options = (array) $options;
3✔
1400

1401
        if (isset($options['fields'])) {
3✔
1402
            $options['fields'] = $this->toCommaString($options['fields']);
3✔
1403
        }
1404

1405
        if (isset($options['additional_types'])) {
3✔
UNCOV
1406
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
×
1407
        }
1408

1409
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1410

1411
        $uri = '/v1/playlists/' . $playlistId;
3✔
1412

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

1415
        return $this->lastResponse['body'];
3✔
1416
    }
1417

1418
    /**
1419
     * Get a playlist's cover image.
1420
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlist-cover
1421
     *
1422
     * @param string $playlistId ID or URI of the playlist.
1423
     *
1424
     * @return array|object The playlist cover image. Type is controlled by the `return_assoc` option.
1425
     */
1426
    public function getPlaylistImage(string $playlistId): array|object
1427
    {
1428
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1429

1430
        $uri = '/v1/playlists/' . $playlistId . '/images';
3✔
1431

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

1434
        return $this->lastResponse['body'];
3✔
1435
    }
1436

1437
    /**
1438
     * Get the tracks in a playlist.
1439
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlists-tracks
1440
     *
1441
     * @param string $playlistId ID or URI of the playlist.
1442
     * @param array|object $options Optional. Options for the tracks.
1443
     * - string|array fields Optional. A list of fields to return. See Spotify docs for more info.
1444
     * - int limit Optional. Limit the number of tracks.
1445
     * - int offset Optional. Number of tracks to skip.
1446
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1447
     * - string|array additional_types Optional. Types of media to return info about.
1448
     *
1449
     * @return array|object The tracks in the playlist. Type is controlled by the `return_assoc` option.
1450
     */
1451
    public function getPlaylistTracks(string $playlistId, array|object $options = []): array|object
1452
    {
1453
        $options = (array) $options;
3✔
1454

1455
        if (isset($options['fields'])) {
3✔
1456
            $options['fields'] = $this->toCommaString($options['fields']);
3✔
1457
        }
1458

1459
        if (isset($options['additional_types'])) {
3✔
1460
            $options['additional_types'] = $this->toCommaString($options['additional_types']);
3✔
1461
        }
1462

1463
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1464

1465
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
3✔
1466

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

1469
        return $this->lastResponse['body'];
3✔
1470
    }
1471

1472
    /**
1473
     * Get recommendations based on artists, tracks, or genres.
1474
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-recommendations
1475
     *
1476
     * @param array|object $options Optional. Options for the recommendations.
1477
     * - int limit Optional. Limit the number of recommendations.
1478
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1479
     * - mixed max_* Optional. Max value for one of the tunable track attributes.
1480
     * - mixed min_* Optional. Min value for one of the tunable track attributes.
1481
     * - array seed_artists Artist IDs to seed by.
1482
     * - array seed_genres Genres to seed by. Call SpotifyWebAPI::getGenreSeeds() for a complete list.
1483
     * - array seed_tracks Track IDs to seed by.
1484
     * - mixed target_* Optional. Target value for one of the tunable track attributes.
1485
     *
1486
     * @return array|object The requested recommendations. Type is controlled by the `return_assoc` option.
1487
     */
1488
    public function getRecommendations(array|object $options = []): array|object
1489
    {
1490
        $options = (array) $options;
3✔
1491

1492
        array_walk($options, function (&$value, $key) {
3✔
1493
            if (substr($key, 0, 5) == 'seed_') {
3✔
1494
                $value = $this->toCommaString($value);
3✔
1495
            }
1496
        });
3✔
1497

1498
        $uri = '/v1/recommendations';
3✔
1499

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

1502
        return $this->lastResponse['body'];
3✔
1503
    }
1504

1505
    /**
1506
     * Get the Request object in use.
1507
     *
1508
     * @return Request The Request object in use.
1509
     */
1510
    public function getRequest(): Request
1511
    {
1512
        return $this->request;
3✔
1513
    }
1514

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

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

1532
        return $this->lastResponse['body'];
3✔
1533
    }
1534

1535
    /**
1536
     * Get a show's episodes.
1537
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-shows-episodes
1538
     *
1539
     * @param string $showId ID or URI of the album.
1540
     * @param array|object $options Optional. Options for the episodes.
1541
     * - int limit Optional. Limit the number of episodes.
1542
     * - int offset Optional. Number of episodes to skip.
1543
     * - string market Optional. ISO 3166-1 alpha-2 country code, limit results to episodes available in that market.
1544
     *
1545
     * @return array|object The requested show episodes. Type is controlled by the `return_assoc` option.
1546
     */
1547
    public function getShowEpisodes(string $showId, array|object $options = []): array|object
1548
    {
1549
        $showId = $this->uriToId($showId, 'show');
3✔
1550
        $uri = '/v1/shows/' . $showId . '/episodes';
3✔
1551

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

1554
        return $this->lastResponse['body'];
3✔
1555
    }
1556

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

1574
        $uri = '/v1/shows/';
3✔
1575

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

1578
        return $this->lastResponse['body'];
3✔
1579
    }
1580

1581
    /**
1582
     * Get a track.
1583
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-track
1584
     *
1585
     * @param string $trackId ID or URI of the track.
1586
     * @param array|object $options Optional. Options for the track.
1587
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1588
     *
1589
     * @return array|object The requested track. Type is controlled by the `return_assoc` option.
1590
     */
1591
    public function getTrack(string $trackId, array|object $options = []): array|object
1592
    {
1593
        $trackId = $this->uriToId($trackId, 'track');
12✔
1594
        $uri = '/v1/tracks/' . $trackId;
12✔
1595

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

1598
        return $this->lastResponse['body'];
12✔
1599
    }
1600

1601
    /**
1602
     * Get multiple tracks.
1603
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-several-tracks
1604
     *
1605
     * @param array $trackIds IDs or URIs of the tracks.
1606
     * @param array|object $options Optional. Options for the tracks.
1607
     * - string market Optional. ISO 3166-1 alpha-2 country code, provide this if you wish to apply Track Relinking.
1608
     *
1609
     * @return array|object The requested tracks. Type is controlled by the `return_assoc` option.
1610
     */
1611
    public function getTracks(array $trackIds, array|object $options = []): array|object
1612
    {
1613
        $trackIds = $this->uriToId($trackIds, 'track');
3✔
1614
        $options = array_merge((array) $options, [
3✔
1615
            'ids' => $this->toCommaString($trackIds),
3✔
1616
        ]);
3✔
1617

1618
        $uri = '/v1/tracks/';
3✔
1619

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

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

1625
    /**
1626
     * Get a user.
1627
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-users-profile
1628
     *
1629
     * @param string $userId ID or URI of the user.
1630
     *
1631
     * @return array|object The requested user. Type is controlled by the `return_assoc` option.
1632
     */
1633
    public function getUser(string $userId): array|object
1634
    {
1635
        $userId = $this->uriToId($userId, 'user');
3✔
1636
        $uri = '/v1/users/' . $userId;
3✔
1637

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

1640
        return $this->lastResponse['body'];
3✔
1641
    }
1642

1643
    /**
1644
     * Get the artists followed by the current user.
1645
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-followed
1646
     *
1647
     * @param array|object $options Optional. Options for the artists.
1648
     * - int limit Optional. Limit the number of artists returned.
1649
     * - string after Optional. The last artist ID retrieved from the previous request.
1650
     *
1651
     * @return array|object A list of artists. Type is controlled by the `return_assoc` option.
1652
     */
1653
    public function getUserFollowedArtists(array|object $options = []): array|object
1654
    {
1655
        $options = (array) $options;
3✔
1656

1657
        if (!isset($options['type'])) {
3✔
1658
            $options['type'] = 'artist'; // Undocumented until more values are supported.
3✔
1659
        }
1660

1661
        $uri = '/v1/me/following';
3✔
1662

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

1665
        return $this->lastResponse['body'];
3✔
1666
    }
1667

1668
    /**
1669
     * Get a user's playlists.
1670
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-list-users-playlists
1671
     *
1672
     * @param string $userId ID or URI of the user.
1673
     * @param array|object $options Optional. Options for the tracks.
1674
     * - int limit Optional. Limit the number of tracks.
1675
     * - int offset Optional. Number of tracks to skip.
1676
     *
1677
     * @return array|object The user's playlists. Type is controlled by the `return_assoc` option.
1678
     */
1679
    public function getUserPlaylists(string $userId, array|object $options = []): array|object
1680
    {
1681
        $userId = $this->uriToId($userId, 'user');
3✔
1682
        $uri = '/v1/users/' . $userId . '/playlists';
3✔
1683

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

1686
        return $this->lastResponse['body'];
3✔
1687
    }
1688

1689
    /**
1690
     * Get the currently authenticated user.
1691
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
1692
     *
1693
     * @return array|object The currently authenticated user. Type is controlled by the `return_assoc` option.
1694
     */
1695
    public function me(): array|object
1696
    {
1697
        $uri = '/v1/me';
3✔
1698

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

1701
        return $this->lastResponse['body'];
3✔
1702
    }
1703

1704
    /**
1705
     * Check if albums are saved in the current user's Spotify library.
1706
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-albums
1707
     *
1708
     * @param string|array $albums Album IDs or URIs to check for.
1709
     *
1710
     * @return array Whether each album is saved.
1711
     */
1712
    public function myAlbumsContains(string|array $albums): array
1713
    {
1714
        $albums = $this->uriToId($albums, 'album');
3✔
1715
        $albums = $this->toCommaString($albums);
3✔
1716

1717
        $options = [
3✔
1718
            'ids' => $albums,
3✔
1719
        ];
3✔
1720

1721
        $uri = '/v1/me/albums/contains';
3✔
1722

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

1725
        return $this->lastResponse['body'];
3✔
1726
    }
1727

1728
    /**
1729
     * Check if episodes are saved in the current user's Spotify library.
1730
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-episodes
1731
     *
1732
     * @param string|array $episodes Episode IDs or URIs to check for.
1733
     *
1734
     * @return array Whether each episode is saved.
1735
     */
1736
    public function myEpisodesContains(string|array $episodes): array
1737
    {
1738
        $episodes = $this->uriToId($episodes, 'episode');
3✔
1739
        $episodes = $this->toCommaString($episodes);
3✔
1740

1741
        $options = [
3✔
1742
            'ids' => $episodes,
3✔
1743
        ];
3✔
1744

1745
        $uri = '/v1/me/episodes/contains';
3✔
1746

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

1749
        return $this->lastResponse['body'];
3✔
1750
    }
1751

1752
    /**
1753
     * Check if shows are saved in the current user's Spotify library.
1754
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-shows
1755
     *
1756
     * @param string|array $shows Show IDs or URIs to check for.
1757
     *
1758
     * @return array Whether each show is saved.
1759
     */
1760
    public function myShowsContains(string|array $shows): array
1761
    {
1762
        $shows = $this->uriToId($shows, 'show');
3✔
1763
        $shows = $this->toCommaString($shows);
3✔
1764

1765
        $options = [
3✔
1766
            'ids' => $shows,
3✔
1767
        ];
3✔
1768

1769
        $uri = '/v1/me/shows/contains';
3✔
1770

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

1773
        return $this->lastResponse['body'];
3✔
1774
    }
1775

1776
    /**
1777
     * Check if tracks are saved in the current user's Spotify library.
1778
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-tracks
1779
     *
1780
     * @param string|array $tracks Track IDs or URIs to check for.
1781
     *
1782
     * @return array Whether each track is saved.
1783
     */
1784
    public function myTracksContains(string|array $tracks): array
1785
    {
1786
        $tracks = $this->uriToId($tracks, 'track');
3✔
1787
        $tracks = $this->toCommaString($tracks);
3✔
1788

1789
        $options = [
3✔
1790
            'ids' => $tracks,
3✔
1791
        ];
3✔
1792

1793
        $uri = '/v1/me/tracks/contains';
3✔
1794

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

1797
        return $this->lastResponse['body'];
3✔
1798
    }
1799

1800
    /**
1801
     * Play the next track in the current users's queue.
1802
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/skip-users-playback-to-next-track
1803
     *
1804
     * @param string $deviceId Optional. ID of the device to target.
1805
     *
1806
     * @return bool Whether the track was successfully skipped.
1807
     */
1808
    public function next(string $deviceId = ''): bool
1809
    {
1810
        $uri = '/v1/me/player/next';
3✔
1811

1812
        // We need to manually append data to the URI since it's a POST request
1813
        if ($deviceId) {
3✔
1814
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1815
        }
1816

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

1819
        return $this->lastResponse['status'] == 204;
3✔
1820
    }
1821

1822
    /**
1823
     * Pause playback for the current user.
1824
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/pause-a-users-playback
1825
     *
1826
     * @param string $deviceId Optional. ID of the device to pause on.
1827
     *
1828
     * @return bool Whether the playback was successfully paused.
1829
     */
1830
    public function pause(string $deviceId = ''): bool
1831
    {
1832
        $uri = '/v1/me/player/pause';
3✔
1833

1834
        // We need to manually append data to the URI since it's a PUT request
1835
        if ($deviceId) {
3✔
1836
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1837
        }
1838

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

1841
        return $this->lastResponse['status'] == 204;
3✔
1842
    }
1843

1844
    /**
1845
     * Start playback for the current user.
1846
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/start-a-users-playback
1847
     *
1848
     * @param string $deviceId Optional. ID of the device to play on.
1849
     * @param array|object $options Optional. Options for the playback.
1850
     * - string context_uri Optional. URI of the context to play, for example an album.
1851
     * - array uris Optional. Spotify track URIs to play.
1852
     * - object offset Optional. Indicates from where in the context playback should start.
1853
     * - int position_ms. Optional. Indicates the position to start playback from.
1854
     *
1855
     * @return bool Whether the playback was successfully started.
1856
     */
1857
    public function play(string $deviceId = '', array|object $options = []): bool
1858
    {
1859
        $options = $options ? json_encode($options) : '';
3✔
1860

1861
        $headers = [
3✔
1862
            'Content-Type' => 'application/json',
3✔
1863
        ];
3✔
1864

1865
        $uri = '/v1/me/player/play';
3✔
1866

1867
        // We need to manually append data to the URI since it's a PUT request
1868
        if ($deviceId) {
3✔
1869
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1870
        }
1871

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

1874
        return $this->lastResponse['status'] == 204;
3✔
1875
    }
1876

1877
    /**
1878
     * Play the previous track in the current users's queue.
1879
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/skip-users-playback-to-previous-track
1880
     *
1881
     * @param string $deviceId Optional. ID of the device to target.
1882
     *
1883
     * @return bool Whether the track was successfully skipped.
1884
     */
1885
    public function previous(string $deviceId = ''): bool
1886
    {
1887
        $uri = '/v1/me/player/previous';
3✔
1888

1889
        // We need to manually append data to the URI since it's a POST request
1890
        if ($deviceId) {
3✔
1891
            $uri = $uri . '?device_id=' . $deviceId;
3✔
1892
        }
1893

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

1896
        return $this->lastResponse['status'] == 204;
3✔
1897
    }
1898

1899
    /**
1900
     * Add an item to the queue.
1901
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/add-to-queue
1902
     *
1903
     * @param string $trackUri Required. Track ID, track URI or episode URI to queue.
1904
     * @param string $deviceId Optional. ID of the device to target.
1905
     *
1906
     * @return bool Whether the track was successfully queued.
1907
     */
1908
    public function queue(string $trackUri, string $deviceId = ''): bool
1909
    {
1910
        $uri = '/v1/me/player/queue?uri=' . $this->idToUri($trackUri, 'track');
6✔
1911

1912
        // We need to manually append data to the URI since it's a POST request
1913
        if ($deviceId) {
6✔
1914
            $uri = $uri . '&device_id=' . $deviceId;
6✔
1915
        }
1916

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

1919
        return $this->lastResponse['status'] == 204;
6✔
1920
    }
1921

1922
    /**
1923
     * Reorder the tracks in a playlist.
1924
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/reorder-or-replace-playlists-tracks
1925
     *
1926
     * @param string $playlistId ID or URI of the playlist.
1927
     * @param array|object $options Options for the new tracks.
1928
     * - int range_start Required. Position of the first track to be reordered.
1929
     * - int range_length Optional. The amount of tracks to be reordered.
1930
     * - int insert_before Required. Position where the tracks should be inserted.
1931
     * - string snapshot_id Optional. The playlist's snapshot ID.
1932
     *
1933
     * @return string|bool A new snapshot ID or false if the tracks weren't successfully reordered.
1934
     */
1935
    public function reorderPlaylistTracks(string $playlistId, array|object $options): string|bool
1936
    {
1937
        $options = json_encode($options);
6✔
1938

1939
        $headers = [
6✔
1940
            'Content-Type' => 'application/json',
6✔
1941
        ];
6✔
1942

1943
        $playlistId = $this->uriToId($playlistId, 'playlist');
6✔
1944

1945
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
6✔
1946

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

1949
        return $this->getSnapshotId($this->lastResponse['body']);
6✔
1950
    }
1951

1952
    /**
1953
     * Set repeat mode for the current user’s playback.
1954
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/set-repeat-mode-on-users-playback
1955
     *
1956
     * @param array|object $options Optional. Options for the playback repeat mode.
1957
     * - string state Required. The repeat mode. See Spotify docs for possible values.
1958
     * - string device_id Optional. ID of the device to target.
1959
     *
1960
     * @return bool Whether the playback repeat mode was successfully changed.
1961
     */
1962
    public function repeat(array|object $options): bool
1963
    {
1964
        $options = http_build_query($options, '', '&');
3✔
1965

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

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

1971
        return $this->lastResponse['status'] == 204;
3✔
1972
    }
1973

1974
    /**
1975
     * Replace all tracks in a playlist with new ones.
1976
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/reorder-or-replace-playlists-tracks
1977
     *
1978
     * @param string $playlistId ID or URI of the playlist.
1979
     * @param string|array $tracks IDs, track URIs, or episode URIs to replace with.
1980
     *
1981
     * @return bool Whether the tracks was successfully replaced.
1982
     */
1983
    public function replacePlaylistTracks(string $playlistId, string|array $tracks): bool
1984
    {
1985
        $tracks = $this->idToUri($tracks, 'track');
3✔
1986
        $tracks = json_encode([
3✔
1987
            'uris' => (array) $tracks,
3✔
1988
        ]);
3✔
1989

1990
        $headers = [
3✔
1991
            'Content-Type' => 'application/json',
3✔
1992
        ];
3✔
1993

1994
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
1995

1996
        $uri = '/v1/playlists/' . $playlistId . '/tracks';
3✔
1997

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

2000
        return $this->lastResponse['status'] == 200;
3✔
2001
    }
2002

2003
    /**
2004
     * Search for an item.
2005
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/search
2006
     *
2007
     * @param string $query The term to search for.
2008
     * @param string|array $type The type of item to search for.
2009
     * @param array|object $options Optional. Options for the search.
2010
     * - string market Optional. Limit the results to items that are playable in this market, for example SE.
2011
     * - int limit Optional. Limit the number of items.
2012
     * - int offset Optional. Number of items to skip.
2013
     * - string include_external Optional. Whether or not to mark externally hosted content as playable.
2014
     *
2015
     * @return array|object The search results. Type is controlled by the `return_assoc` option.
2016
     */
2017
    public function search(string $query, string|array $type, array|object $options = []): array|object
2018
    {
2019
        $options = array_merge((array) $options, [
3✔
2020
            'q' => $query,
3✔
2021
            'type' => $this->toCommaString($type),
3✔
2022
        ]);
3✔
2023

2024
        $uri = '/v1/search';
3✔
2025

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

2028
        return $this->lastResponse['body'];
3✔
2029
    }
2030

2031
    /**
2032
     * Change playback position for the current user.
2033
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/seek-to-position-in-currently-playing-track
2034
     *
2035
     * @param array|object $options Optional. Options for the playback seeking.
2036
     * - string position_ms Required. The position in milliseconds to seek to.
2037
     * - string device_id Optional. ID of the device to target.
2038
     *
2039
     * @return bool Whether the playback position was successfully changed.
2040
     */
2041
    public function seek(array|object $options): bool
2042
    {
2043
        $options = http_build_query($options, '', '&');
3✔
2044

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

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

2050
        return $this->lastResponse['status'] == 204;
3✔
2051
    }
2052

2053
    /**
2054
     * Set the access token to use.
2055
     *
2056
     * @param string $accessToken The access token.
2057
     *
2058
     * @return self
2059
     */
2060
    public function setAccessToken(string $accessToken): self
2061
    {
2062
        $this->accessToken = $accessToken;
6✔
2063

2064
        return $this;
6✔
2065
    }
2066

2067
    /**
2068
     * Set options
2069
     *
2070
     * @param array|object $options Options to set.
2071
     *
2072
     * @return self
2073
     */
2074
    public function setOptions(array|object $options): self
2075
    {
2076
        $this->options = array_merge($this->options, (array) $options);
297✔
2077

2078
        return $this;
297✔
2079
    }
2080

2081
    /**
2082
     * Set the Session object to use.
2083
     *
2084
     * @param Session $session The Session object.
2085
     *
2086
     * @return self
2087
     */
2088
    public function setSession(?Session $session): self
2089
    {
2090
        $this->session = $session;
297✔
2091

2092
        return $this;
297✔
2093
    }
2094

2095
    /**
2096
     * Set shuffle mode for the current user’s playback.
2097
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/toggle-shuffle-for-users-playback
2098
     *
2099
     * @param array|object $options Optional. Options for the playback shuffle mode.
2100
     * - bool state Required. The shuffle mode. See Spotify docs for possible values.
2101
     * - string device_id Optional. ID of the device to target.
2102
     *
2103
     * @return bool Whether the playback shuffle mode was successfully changed.
2104
     */
2105
    public function shuffle(array|object $options): bool
2106
    {
2107
        $options = array_merge((array) $options, [
3✔
2108
            'state' => $options['state'] ? 'true' : 'false',
3✔
2109
        ]);
3✔
2110

2111
        $options = http_build_query($options, '', '&');
3✔
2112

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

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

2118
        return $this->lastResponse['status'] == 204;
3✔
2119
    }
2120

2121
    /**
2122
     * Remove the current user as a follower of one or more artists or other Spotify users.
2123
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/unfollow-artists-users
2124
     *
2125
     * @param string $type The type to check: either 'artist' or 'user'.
2126
     * @param string|array $ids IDs or URIs of the users or artists to unfollow.
2127
     *
2128
     * @return bool Whether the artists or users were successfully unfollowed.
2129
     */
2130
    public function unfollowArtistsOrUsers(string $type, string|array $ids): bool
2131
    {
2132
        $ids = $this->uriToId($ids, $type);
3✔
2133
        $ids = json_encode([
3✔
2134
            'ids' => (array) $ids,
3✔
2135
        ]);
3✔
2136

2137
        $headers = [
3✔
2138
            'Content-Type' => 'application/json',
3✔
2139
        ];
3✔
2140

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

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

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

2149
    /**
2150
     * Remove the current user as a follower of a playlist.
2151
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/unfollow-playlist
2152
     *
2153
     * @param string $playlistId ID or URI of the playlist to unfollow.
2154
     *
2155
     * @return bool Whether the playlist was successfully unfollowed.
2156
     */
2157
    public function unfollowPlaylist(string $playlistId): bool
2158
    {
2159
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2160
        $uri = '/v1/playlists/' . $playlistId . '/followers';
3✔
2161

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

2164
        return $this->lastResponse['status'] == 200;
3✔
2165
    }
2166

2167
    /**
2168
     * Update the details of a playlist.
2169
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/change-playlist-details
2170
     *
2171
     * @param string $playlistId ID or URI of the playlist to update.
2172
     * @param array|object $options Options for the playlist.
2173
     * - bool collaborative Optional. Whether the playlist should be collaborative or not.
2174
     * - string description Optional. Description of the playlist.
2175
     * - string name Optional. Name of the playlist.
2176
     * - bool public Optional. Whether the playlist should be public or not.
2177
     *
2178
     * @return bool Whether the playlist was successfully updated.
2179
     */
2180
    public function updatePlaylist(string $playlistId, array|object $options): bool
2181
    {
2182
        $options = json_encode($options);
3✔
2183

2184
        $headers = [
3✔
2185
            'Content-Type' => 'application/json',
3✔
2186
        ];
3✔
2187

2188
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2189

2190
        $uri = '/v1/playlists/' . $playlistId;
3✔
2191

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

2194
        return $this->lastResponse['status'] == 200;
3✔
2195
    }
2196

2197
    /**
2198
     * Update the image of a playlist.
2199
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/upload-custom-playlist-cover
2200
     *
2201
     * @param string $playlistId ID or URI of the playlist to update.
2202
     * @param string $imageData Base64 encoded JPEG image data, maximum 256 KB in size.
2203
     *
2204
     * @return bool Whether the playlist was successfully updated.
2205
     */
2206
    public function updatePlaylistImage(string $playlistId, string $imageData): bool
2207
    {
2208
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2209

2210
        $uri = '/v1/playlists/' . $playlistId . '/images';
3✔
2211

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

2214
        return $this->lastResponse['status'] == 202;
3✔
2215
    }
2216

2217
    /**
2218
     * Check if a set of users are following a playlist.
2219
     * https://developer.spotify.com/documentation/web-api/reference/#/operations/check-if-user-follows-playlist
2220
     *
2221
     * @param string $playlistId ID or URI of the playlist.
2222
     * @param array|object $options Options for the check.
2223
     * - ids string|array Required. IDs or URIs of the users to check for.
2224
     *
2225
     * @return array Whether each user is following the playlist.
2226
     */
2227
    public function usersFollowPlaylist(string $playlistId, array|object $options): array
2228
    {
2229
        $options = (array) $options;
3✔
2230

2231
        if (isset($options['ids'])) {
3✔
2232
            $options['ids'] = $this->uriToId($options['ids'], 'user');
3✔
2233
            $options['ids'] = $this->toCommaString($options['ids']);
3✔
2234
        }
2235

2236
        $playlistId = $this->uriToId($playlistId, 'playlist');
3✔
2237

2238
        $uri = '/v1/playlists/' . $playlistId . '/followers/contains';
3✔
2239

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

2242
        return $this->lastResponse['body'];
3✔
2243
    }
2244
}
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