From 9e4cfabb944faed869a313551aaaea6ed2b0bf34 Mon Sep 17 00:00:00 2001 From: Command_String Date: Fri, 28 Jul 2023 13:30:34 -0400 Subject: [PATCH 1/8] csf --- .php-cs-fixer.dist.php | 4 +--- src/Http.php | 2 +- src/Rest/Endpoint.php | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index a149c03..419da94 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -27,7 +27,7 @@ // Remove extra spaces in a nullable typehint. 'compact_nullable_typehint' => true, // Concatenation should be spaced according to configuration. - 'concat_space' => ['spacing' => 'none'], + 'concat_space' => ['spacing' => 'one'], // The PHP constants `true`, `false`, and `null` MUST be written using the correct casing. 'constant_case' => ['case' => 'lower'], // The body of each control structure MUST be enclosed within braces. @@ -208,8 +208,6 @@ 'short_scalar_cast' => true, // A PHP file without end tag must always end with a single empty line feed. 'single_blank_line_at_eof' => true, - // There should be exactly one blank line before a namespace declaration. - 'single_blank_line_before_namespace' => true, // There MUST NOT be more than one property or constant declared per statement. 'single_class_element_per_statement' => ['elements' => ['const', 'property']], // There MUST be one use keyword per declaration. diff --git a/src/Http.php b/src/Http.php index 81cc56e..832d3a8 100644 --- a/src/Http.php +++ b/src/Http.php @@ -44,7 +44,7 @@ public function getAuthenticationToken(): AccessToken 'grant_type=client_credentials', [ 'content-type' => 'application/x-www-form-urlencoded', - 'authorization' => 'Basic '.base64_encode("{$this->id}:{$this->secret}"), + 'authorization' => 'Basic ' . base64_encode("{$this->id}:{$this->secret}"), ] ); } diff --git a/src/Rest/Endpoint.php b/src/Rest/Endpoint.php index 54b1406..017c84b 100644 --- a/src/Rest/Endpoint.php +++ b/src/Rest/Endpoint.php @@ -23,7 +23,7 @@ class Endpoint public static function bind(string $endpoint, array $params = [], array $getParams = [], ?string $market = null): string { - $endpoint = self::BASE.$endpoint; + $endpoint = self::BASE . $endpoint; foreach ($params as $key => $value) { $endpoint = str_replace(":{$key}:", $value, $endpoint); @@ -34,7 +34,7 @@ public static function bind(string $endpoint, array $params = [], array $getPara } if (!empty($getParams)) { - $endpoint .= '?'.http_build_query($getParams, '', '&'); + $endpoint .= '?' . http_build_query($getParams, '', '&'); } return $endpoint; From 452335b029bc705d72ba712754a0f7ad4701cafc Mon Sep 17 00:00:00 2001 From: Command_String Date: Mon, 31 Jul 2023 02:12:25 -0400 Subject: [PATCH 2/8] Started audiobook endpoint bindings --- src/Abstractions/Audiobook/Audiobook.php | 51 +++++++++++++++++++ src/Abstractions/Audiobook/Chapters.php | 18 +++++++ src/Abstractions/Audiobook/Narrator.php | 8 +++ .../Audiobook/SimplifiedChapter.php | 44 ++++++++++++++++ src/Client.php | 9 ++-- src/Rest/Audiobooks.php | 44 ++++++++++++++++ 6 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 src/Abstractions/Audiobook/Audiobook.php create mode 100644 src/Abstractions/Audiobook/Chapters.php create mode 100644 src/Abstractions/Audiobook/Narrator.php create mode 100644 src/Abstractions/Audiobook/SimplifiedChapter.php create mode 100644 src/Rest/Audiobooks.php diff --git a/src/Abstractions/Audiobook/Audiobook.php b/src/Abstractions/Audiobook/Audiobook.php new file mode 100644 index 0000000..d5f5140 --- /dev/null +++ b/src/Abstractions/Audiobook/Audiobook.php @@ -0,0 +1,51 @@ +$name; + if ($name === 'http') { + return $this->http; } $rest = [ @@ -35,6 +35,7 @@ public function __get(string $name): mixed 'tracks' => Tracks::class, 'artists' => Artists::class, 'playlists' => Playlists::class, + 'audiobooks' => Audiobooks::class, ]; if (!isset($rest[$name])) { diff --git a/src/Rest/Audiobooks.php b/src/Rest/Audiobooks.php new file mode 100644 index 0000000..a519005 --- /dev/null +++ b/src/Rest/Audiobooks.php @@ -0,0 +1,44 @@ +http->mapRequest( + Audiobook::class, + Method::GET, + Endpoint::bind(Endpoint::AUDIOBOOKS_ID, compact('id'), market: $market), + headers: $this->http->mergeHeaders() + ); + } + + /** @return Audiobook[] */ + public function getSeveral(array $ids, ?string $market = null): array + { + $ids = implode(',', $ids); + + return $this->http->arrayMapRequest( + Audiobook::class, + Method::GET, + Endpoint::bind(Endpoint::AUDIOBOOKS, getParams: compact('ids'), market: $market), + headers: $this->http->mergeHeaders(), + callback: static fn (array $res) => $res['audiobooks'] + ); + } + + public function getChapters(string $id, int $limit = 20, int $offset = 0, ?string $market = null): Chapters + { + return $this->http->mapRequest( + Chapters::class, + Method::GET, + Endpoint::bind(Endpoint::AUDIOBOOKS_CHAPTERS, compact('id'), getParams: compact('limit', 'offset'), market: $market), + headers: $this->http->mergeHeaders() + ); + } +} From 5b1637fa993da66585bbfddc782c41f434ed7f07 Mon Sep 17 00:00:00 2001 From: Command_String Date: Mon, 31 Jul 2023 02:12:53 -0400 Subject: [PATCH 3/8] Added missing properties to playlist abstraction --- src/Abstractions/Playlist/Playlist.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Abstractions/Playlist/Playlist.php b/src/Abstractions/Playlist/Playlist.php index 810aa0f..4059b03 100644 --- a/src/Abstractions/Playlist/Playlist.php +++ b/src/Abstractions/Playlist/Playlist.php @@ -6,6 +6,7 @@ use Tnapf\JsonMapper\Attributes\SnakeToCamelCase; use Tnapf\Spotify\Abstractions\Artist\ExternalUrls; use Tnapf\Spotify\Abstractions\Common\Image; +use Tnapf\Spotify\Abstractions\User\User; #[SnakeToCamelCase] class Playlist @@ -20,7 +21,11 @@ class Playlist #[ObjectArrayType('images', Image::class)] public array $images; + public string $name; + public User $owner; public bool $public; public string $snapshotId; public Tracks $tracks; + public string $type; + public string $uri; } From 010b1a17b20ad00e21e45f838ede9a7409f49558 Mon Sep 17 00:00:00 2001 From: Command_String Date: Mon, 31 Jul 2023 02:13:07 -0400 Subject: [PATCH 4/8] Renamed Users namespace to User --- src/Abstractions/Playlist/Track.php | 2 +- src/Abstractions/{Users => User}/User.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Abstractions/{Users => User}/User.php (90%) diff --git a/src/Abstractions/Playlist/Track.php b/src/Abstractions/Playlist/Track.php index 4b96d30..b8f753e 100644 --- a/src/Abstractions/Playlist/Track.php +++ b/src/Abstractions/Playlist/Track.php @@ -3,7 +3,7 @@ namespace Tnapf\Spotify\Abstractions\Playlist; use Tnapf\JsonMapper\Attributes\SnakeToCamelCase; -use Tnapf\Spotify\Abstractions\Users\User; +use Tnapf\Spotify\Abstractions\User\User; use Tnapf\Spotify\Abstractions\Track\Track as TrackObject; #[SnakeToCamelCase] diff --git a/src/Abstractions/Users/User.php b/src/Abstractions/User/User.php similarity index 90% rename from src/Abstractions/Users/User.php rename to src/Abstractions/User/User.php index e6fe5b4..6d23348 100644 --- a/src/Abstractions/Users/User.php +++ b/src/Abstractions/User/User.php @@ -1,6 +1,6 @@ Date: Mon, 31 Jul 2023 02:13:20 -0400 Subject: [PATCH 5/8] Added audiobook uris --- src/Rest/Endpoint.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Rest/Endpoint.php b/src/Rest/Endpoint.php index 017c84b..8f5e64f 100644 --- a/src/Rest/Endpoint.php +++ b/src/Rest/Endpoint.php @@ -20,6 +20,9 @@ class Endpoint public const TRACK_AUDIO_FEATURES = '/audio-features'; public const TRACK_AUDIO_FEATURES_ID = '/audio-features/:id:'; public const PLAYLISTS_ID = '/playlists/:id:'; + public const AUDIOBOOKS_ID = '/audiobooks/:id:'; + public const AUDIOBOOKS_CHAPTERS = '/audiobooks/:id:/chapters'; + public const AUDIOBOOKS = '/audiobooks'; public static function bind(string $endpoint, array $params = [], array $getParams = [], ?string $market = null): string { From 05d5463d1f34dc9ff7e3f348c63db21190d84d96 Mon Sep 17 00:00:00 2001 From: Command_String Date: Mon, 31 Jul 2023 02:13:30 -0400 Subject: [PATCH 6/8] Created scope constants --- src/Abstractions/Authorization/Scope.php | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/Abstractions/Authorization/Scope.php diff --git a/src/Abstractions/Authorization/Scope.php b/src/Abstractions/Authorization/Scope.php new file mode 100644 index 0000000..526e9c4 --- /dev/null +++ b/src/Abstractions/Authorization/Scope.php @@ -0,0 +1,48 @@ + Date: Mon, 31 Jul 2023 02:13:53 -0400 Subject: [PATCH 7/8] started changeDetails binding --- src/Rest/Playlists.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Rest/Playlists.php b/src/Rest/Playlists.php index 1b0db6b..5154bb2 100644 --- a/src/Rest/Playlists.php +++ b/src/Rest/Playlists.php @@ -27,9 +27,8 @@ public function changeDetails(string $id, ?string $name = null, ?bool $public = $this->http->request( Method::PUT, Endpoint::bind(Endpoint::PLAYLISTS_ID, compact('id')), - body: compact('name', 'public', 'collaborative', 'description'), + body: json_encode($body), headers: $this->http->mergeHeaders() ); - } } From 61c8bb7ed7c089847b2e2a56ec0bbb5aa514e683 Mon Sep 17 00:00:00 2001 From: Command_String Date: Sat, 24 Feb 2024 05:55:47 -0500 Subject: [PATCH 8/8] more endpoints --- src/Abstractions/Album/Tracks.php | 10 +-- src/Abstractions/Artist/Artists.php | 13 +++ .../Authorization/AccessToken.php | 1 + src/Abstractions/Common/Pages.php | 13 +++ src/Abstractions/Playback/Actions.php | 20 +++++ src/Abstractions/Playback/ContentType.php | 11 +++ src/Abstractions/Playback/Context.php | 13 +++ src/Abstractions/Playback/Device.php | 18 +++++ src/Abstractions/Playback/RepeatState.php | 10 +++ src/Abstractions/Playback/State.php | 20 +++++ src/Abstractions/Playlist/Playlist.php | 2 +- src/Abstractions/Playlist/Playlists.php | 13 +++ .../Playlist/SimplifiedPlaylist.php | 30 +++++++ .../Playlist/SimplifiedPlaylistTracks.php | 9 +++ .../Playlist/SimplifiedPlaylists.php | 13 +++ src/Abstractions/Playlist/Tracks.php | 10 +-- src/Abstractions/Track/Tracks.php | 13 +++ src/Abstractions/User/ExplicitContent.php | 12 +++ src/Abstractions/User/TopItemTimeRange.php | 10 +++ src/Abstractions/User/TopItemType.php | 9 +++ src/Abstractions/User/User.php | 11 ++- src/Client.php | 6 ++ src/Http.php | 79 ++++++++++++++++++- src/Rest/Albums.php | 2 +- src/Rest/Artists.php | 6 +- src/Rest/Audiobooks.php | 2 +- src/Rest/Endpoint.php | 5 ++ src/Rest/Player.php | 28 +++++++ src/Rest/Playlists.php | 10 +++ src/Rest/Tracks.php | 4 +- src/Rest/Users.php | 45 +++++++++++ 31 files changed, 419 insertions(+), 29 deletions(-) create mode 100644 src/Abstractions/Artist/Artists.php create mode 100644 src/Abstractions/Common/Pages.php create mode 100644 src/Abstractions/Playback/Actions.php create mode 100644 src/Abstractions/Playback/ContentType.php create mode 100644 src/Abstractions/Playback/Context.php create mode 100644 src/Abstractions/Playback/Device.php create mode 100644 src/Abstractions/Playback/RepeatState.php create mode 100644 src/Abstractions/Playback/State.php create mode 100644 src/Abstractions/Playlist/Playlists.php create mode 100644 src/Abstractions/Playlist/SimplifiedPlaylist.php create mode 100644 src/Abstractions/Playlist/SimplifiedPlaylistTracks.php create mode 100644 src/Abstractions/Playlist/SimplifiedPlaylists.php create mode 100644 src/Abstractions/Track/Tracks.php create mode 100644 src/Abstractions/User/ExplicitContent.php create mode 100644 src/Abstractions/User/TopItemTimeRange.php create mode 100644 src/Abstractions/User/TopItemType.php create mode 100644 src/Rest/Player.php create mode 100644 src/Rest/Users.php diff --git a/src/Abstractions/Album/Tracks.php b/src/Abstractions/Album/Tracks.php index dc3732d..a076b90 100644 --- a/src/Abstractions/Album/Tracks.php +++ b/src/Abstractions/Album/Tracks.php @@ -3,17 +3,11 @@ namespace Tnapf\Spotify\Abstractions\Album; use Tnapf\JsonMapper\Attributes\ObjectArrayType; +use Tnapf\Spotify\Abstractions\Common\Pages; use Tnapf\Spotify\Abstractions\Track\SimplifiedTrack; -class Tracks +class Tracks extends Pages { - public string $href; - public int $limit; - public ?string $next; - public int $offset; - public ?string $previous; - public int $total; - /** @var SimplifiedTrack[] */ #[ObjectArrayType(name: 'items', class: SimplifiedTrack::class)] public array $items; diff --git a/src/Abstractions/Artist/Artists.php b/src/Abstractions/Artist/Artists.php new file mode 100644 index 0000000..e76b82e --- /dev/null +++ b/src/Abstractions/Artist/Artists.php @@ -0,0 +1,13 @@ + Artists::class, 'playlists' => Playlists::class, 'audiobooks' => Audiobooks::class, + 'users' => Users::class, + 'player' => Player::class ]; if (!isset($rest[$name])) { diff --git a/src/Http.php b/src/Http.php index 832d3a8..4c9418a 100644 --- a/src/Http.php +++ b/src/Http.php @@ -11,11 +11,13 @@ use Throwable; use Tnapf\JsonMapper\MapperException; use Tnapf\Spotify\Abstractions\Authorization\AccessToken; +use Tnapf\Spotify\Abstractions\Authorization\Scope; use Tnapf\Spotify\Abstractions\Errors\AuthenticationError; use Tnapf\Spotify\Abstractions\Errors\Error; use Tnapf\Spotify\Enums\Method; use Tnapf\Spotify\Exceptions\HttpException; use Tnapf\JsonMapper\MapperInterface; +use ValueError; class Http { @@ -32,7 +34,13 @@ public function __construct( protected readonly string $id, protected readonly string $secret ) { - $this->token = $this->getAuthenticationToken(); + $this->withAccessToken($this->getAuthenticationToken()); + } + + public function withAccessToken(AccessToken $token): self + { + $this->token = $token; + return $this; } public function getAuthenticationToken(): AccessToken @@ -41,10 +49,65 @@ public function getAuthenticationToken(): AccessToken AccessToken::class, Method::POST, 'https://accounts.spotify.com/api/token', - 'grant_type=client_credentials', + "grant_type=client_credentials&client_id={$this->id}&client_secret={$this->secret}", + [ + 'content-type' => 'application/x-www-form-urlencoded', + 'authorization' => 'Basic ' . base64_encode("{$this->id}:{$this->secret}"), + ] + ); + } + + public function requestUserAuthorization(string $redirectUri, array $scopes = []): string + { + foreach ($scopes as $scope) { + if (!$scope instanceof Scope) { + throw new ValueError('Scopes must be an instance of ' . Scope::class); + } + } + + $scopes = array_map(static fn (Scope $scope) => $scope->value, $scopes); + $base = 'https://accounts.spotify.com/authorize'; + $query = http_build_query([ + 'client_id' => $this->id, + 'response_type' => 'code', + 'redirect_uri' => $redirectUri, + 'scope' => implode(' ', $scopes), + ]); + + return "{$base}?{$query}"; + } + + public function requestUserAccessToken(string $code, string $redirectUri): AccessToken + { + return $this->mapRequest( + AccessToken::class, + Method::POST, + 'https://accounts.spotify.com/api/token', + http_build_query([ + 'grant_type' => 'authorization_code', + 'code' => $code, + 'redirect_uri' => $redirectUri, + ]), [ + 'authorization' => 'Basic ' . base64_encode("{$this->id}:{$this->secret}"), 'content-type' => 'application/x-www-form-urlencoded', + ] + ); + } + + public function requestRefreshedAccessToken(string $refreshToken): AccessToken + { + return $this->mapRequest( + AccessToken::class, + Method::POST, + 'https://accounts.spotify.com/api/token', + http_build_query([ + 'grant_type' => 'refresh_token', + 'refresh_token' => $refreshToken, + ]), + [ 'authorization' => 'Basic ' . base64_encode("{$this->id}:{$this->secret}"), + 'content-type' => 'application/x-www-form-urlencoded', ] ); } @@ -67,11 +130,15 @@ public function mapRequest(string $class, Method $method, string $uri, ?string $ * @template T * * @param class-string $class - * @param Closure(array): array $callback You can modify the array before the loop to map it + * @param Method $method + * @param string $uri + * @param string|null $body + * @param array $headers + * @param Closure|null $callback You can modify the array before the loop to map it * * @return T[] */ - public function arrayMapRequest(string $class, Method $method, string $uri, ?string $body = null, array $headers = [], ?Closure $callback = null): array + public function mapArrayRequest(string $class, Method $method, string $uri, ?string $body = null, array $headers = [], ?Closure $callback = null): array { $response = $this->request($method, $uri, $body, $headers); $mapped = []; @@ -100,6 +167,10 @@ protected function throwIfNotOkay(ResponseInterface $response): void $json = json_decode($response->getBody()->getContents(), true); + if ($json === null) { + return; + } + if (isset($json['error']['status'])) { $error = $this->mapper->map(Error::class, $json['error']); } else { diff --git a/src/Rest/Albums.php b/src/Rest/Albums.php index 201f724..4a2a18a 100644 --- a/src/Rest/Albums.php +++ b/src/Rest/Albums.php @@ -29,7 +29,7 @@ public function getSeveral(array $ids, ?string $market = null): array { $ids = implode(',', $ids); - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( Album::class, Method::GET, Endpoint::bind(Endpoint::ALBUMS, [], compact('ids'), market: $market), diff --git a/src/Rest/Artists.php b/src/Rest/Artists.php index 8bc9953..99e06e9 100644 --- a/src/Rest/Artists.php +++ b/src/Rest/Artists.php @@ -24,7 +24,7 @@ public function getSeveral(array $ids): array { $ids = implode(',', $ids); - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( Artist::class, Method::GET, Endpoint::bind(Endpoint::ARTISTS, getParams: compact('ids')), @@ -62,7 +62,7 @@ public function getAlbums(string $id, array $includeGroups = [], ?string $market /** @return Track[] */ public function getTopTracks(string $id, string $market = 'US'): array { - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( Track::class, Method::GET, Endpoint::bind(Endpoint::ARTISTS_ID_TOP_TRACKS, compact('id'), market: $market), @@ -74,7 +74,7 @@ public function getTopTracks(string $id, string $market = 'US'): array /** @return Artist[] */ public function getRelatedArtists(string $id): array { - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( Artist::class, Method::GET, Endpoint::bind(Endpoint::ARTISTS_ID_RELATED_ARTISTS, compact('id')), diff --git a/src/Rest/Audiobooks.php b/src/Rest/Audiobooks.php index a519005..2dba509 100644 --- a/src/Rest/Audiobooks.php +++ b/src/Rest/Audiobooks.php @@ -23,7 +23,7 @@ public function getSeveral(array $ids, ?string $market = null): array { $ids = implode(',', $ids); - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( Audiobook::class, Method::GET, Endpoint::bind(Endpoint::AUDIOBOOKS, getParams: compact('ids'), market: $market), diff --git a/src/Rest/Endpoint.php b/src/Rest/Endpoint.php index 8f5e64f..d8a747b 100644 --- a/src/Rest/Endpoint.php +++ b/src/Rest/Endpoint.php @@ -23,6 +23,11 @@ class Endpoint public const AUDIOBOOKS_ID = '/audiobooks/:id:'; public const AUDIOBOOKS_CHAPTERS = '/audiobooks/:id:/chapters'; public const AUDIOBOOKS = '/audiobooks'; + public const USERS_ME = '/me'; + public const USERS_ME_TOP_ARTISTS = '/me/top/artists'; + public const USERS_ME_TOP_TRACKS = '/me/top/tracks'; + public const USERS_ME_PLAYLISTS = '/me/playlists'; + public const USERS_ME_PLAYBACK = '/me/player'; public static function bind(string $endpoint, array $params = [], array $getParams = [], ?string $market = null): string { diff --git a/src/Rest/Player.php b/src/Rest/Player.php new file mode 100644 index 0000000..2b1feb1 --- /dev/null +++ b/src/Rest/Player.php @@ -0,0 +1,28 @@ +http->request( + Method::GET, + Endpoint::bind(Endpoint::USERS_ME_PLAYBACK), + headers: $this->http->mergeHeaders() + ); + + $body = json_decode($request->getBody()->getContents(), true); + + if (!$body) { + return null; + } + + return map(State::class, $body); + } +} \ No newline at end of file diff --git a/src/Rest/Playlists.php b/src/Rest/Playlists.php index 5154bb2..6691d38 100644 --- a/src/Rest/Playlists.php +++ b/src/Rest/Playlists.php @@ -3,6 +3,7 @@ namespace Tnapf\Spotify\Rest; use Tnapf\Spotify\Abstractions\Playlist\Playlist; +use Tnapf\Spotify\Abstractions\Playlist\SimplifiedPlaylists; use Tnapf\Spotify\Enums\Method; class Playlists extends RestBase @@ -17,6 +18,15 @@ public function get(string $id, ?string $market = null, ?string $fields = null, ); } + public function getCurrentUserPlaylists(int $limit = 20, $offset = 0): SimplifiedPlaylists { + return $this->http->mapRequest( + SimplifiedPlaylists::class, + Method::GET, + Endpoint::bind(Endpoint::USERS_ME_PLAYLISTS, getParams: compact('limit', 'offset')), + headers: $this->http->mergeHeaders() + ); + } + public function changeDetails(string $id, ?string $name = null, ?bool $public = null, ?bool $collaborative = null, ?string $description = null): bool { $body = array_filter( diff --git a/src/Rest/Tracks.php b/src/Rest/Tracks.php index 6ca70c4..9ec482e 100644 --- a/src/Rest/Tracks.php +++ b/src/Rest/Tracks.php @@ -24,7 +24,7 @@ public function getSeveral(array $ids, ?string $market = null): array { $ids = implode(',', $ids); - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( Track::class, Method::GET, Endpoint::bind(Endpoint::TRACKS, getParams: compact('ids'), market: $market), @@ -48,7 +48,7 @@ public function getSeveralAudioFeatures(array $ids): array { $ids = implode(',', $ids); - return $this->http->arrayMapRequest( + return $this->http->mapArrayRequest( AudioFeatures::class, Method::GET, Endpoint::bind(Endpoint::TRACK_AUDIO_FEATURES, getParams: compact('ids')), diff --git a/src/Rest/Users.php b/src/Rest/Users.php new file mode 100644 index 0000000..7e4bb4d --- /dev/null +++ b/src/Rest/Users.php @@ -0,0 +1,45 @@ +http->mapRequest( + User::class, + Method::GET, + Endpoint::bind(Endpoint::USERS_ME), + headers: $this->http->mergeHeaders() + ); + } + + public function getTopItems(TopItemType $type, TopItemTimeRange $timeRange = TopItemTimeRange::MEDIUM_TERM, int $limit = 20, int $offset = 0): Tracks|Artists + { + $class = match($type) { + TopItemType::TRACKS => Tracks::class, + TopItemType::ARTISTS => Artists::class, + }; + + $url = match($type) { + TopItemType::TRACKS => Endpoint::USERS_ME_TOP_TRACKS, + TopItemType::ARTISTS => Endpoint::USERS_ME_TOP_ARTISTS, + }; + + $time_range = $timeRange->value; + + return $this->http->mapRequest( + $class, + Method::GET, + Endpoint::bind($url, getParams: compact('time_range', 'limit', 'offset')), + headers: $this->http->mergeHeaders() + ); + } +} \ No newline at end of file