wtf
All checks were successful
CI - Build Tonehaus Docker image / tonehaus-ci-build (push) Successful in 2m0s
All checks were successful
CI - Build Tonehaus Docker image / tonehaus-ci-build (push) Successful in 2m0s
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Repository\SettingRepository;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
@@ -77,6 +79,60 @@ class SpotifyClient
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches album metadata plus the full tracklist.
|
||||
*
|
||||
* @return array<mixed>|null
|
||||
*/
|
||||
public function getAlbumWithTracks(string $albumId): ?array
|
||||
{
|
||||
$album = $this->getAlbum($albumId);
|
||||
if ($album === null) {
|
||||
return null;
|
||||
}
|
||||
$tracks = $this->getAlbumTracks($albumId);
|
||||
if ($tracks !== []) {
|
||||
$album['tracks'] = $album['tracks'] ?? [];
|
||||
$album['tracks']['items'] = $tracks;
|
||||
$album['tracks']['total'] = count($tracks);
|
||||
$album['tracks']['limit'] = count($tracks);
|
||||
$album['tracks']['offset'] = 0;
|
||||
$album['tracks']['next'] = null;
|
||||
$album['tracks']['previous'] = null;
|
||||
}
|
||||
return $album;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the complete tracklist for an album.
|
||||
*
|
||||
* @return list<array<string,mixed>>
|
||||
*/
|
||||
public function getAlbumTracks(string $albumId): array
|
||||
{
|
||||
$accessToken = $this->getAccessToken();
|
||||
if ($accessToken === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = [];
|
||||
$limit = 50;
|
||||
$offset = 0;
|
||||
do {
|
||||
$page = $this->requestAlbumTracksPage($albumId, $accessToken, $limit, $offset);
|
||||
if ($page === null) {
|
||||
break;
|
||||
}
|
||||
$batch = (array) ($page['items'] ?? []);
|
||||
$items = array_merge($items, $batch);
|
||||
$offset += $limit;
|
||||
$total = isset($page['total']) ? (int) $page['total'] : null;
|
||||
$hasNext = isset($page['next']) && $page['next'] !== null;
|
||||
} while ($hasNext && ($total === null || $offset < $total));
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch multiple albums with one call.
|
||||
*
|
||||
@@ -132,18 +188,38 @@ class SpotifyClient
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>|null
|
||||
*/
|
||||
private function requestAlbumTracksPage(string $albumId, string $accessToken, int $limit, int $offset): ?array
|
||||
{
|
||||
$url = sprintf('https://api.spotify.com/v1/albums/%s/tracks', urlencode($albumId));
|
||||
$options = [
|
||||
'headers' => [ 'Authorization' => 'Bearer ' . $accessToken ],
|
||||
'query' => [ 'limit' => $limit, 'offset' => $offset ],
|
||||
];
|
||||
try {
|
||||
return $this->sendRequest('GET', $url, $options, 1200);
|
||||
} catch (\Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a cached access token or refreshes credentials when missing.
|
||||
*/
|
||||
private function getAccessToken(): ?string
|
||||
{
|
||||
return $this->cache->get('spotify_client_credentials_token', function ($item) {
|
||||
// Default to 1 hour, will adjust based on response
|
||||
$cacheKey = 'spotify_client_credentials_token';
|
||||
$token = $this->cache->get($cacheKey, function (ItemInterface $item) {
|
||||
// Default to ~1 hour, adjusted after Spotify response
|
||||
$item->expiresAfter(3500);
|
||||
|
||||
$clientId = $this->settings->getValue('SPOTIFY_CLIENT_ID', $this->clientId ?? '');
|
||||
$clientSecret = $this->settings->getValue('SPOTIFY_CLIENT_SECRET', $this->clientSecret ?? '');
|
||||
$clientId = trim((string) $this->settings->getValue('SPOTIFY_CLIENT_ID', $this->clientId ?? ''));
|
||||
$clientSecret = trim((string) $this->settings->getValue('SPOTIFY_CLIENT_SECRET', $this->clientSecret ?? ''));
|
||||
if ($clientId === '' || $clientSecret === '') {
|
||||
// surface the miss quickly so the cache can be recomputed on the next request
|
||||
$item->expiresAfter(60);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -158,6 +234,7 @@ class SpotifyClient
|
||||
$data = $response->toArray(false);
|
||||
|
||||
if (!isset($data['access_token'])) {
|
||||
$item->expiresAfter(60);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -168,6 +245,13 @@ class SpotifyClient
|
||||
|
||||
return $data['access_token'];
|
||||
});
|
||||
|
||||
if ($token === null) {
|
||||
// Remove failed entries so the next request retries instead of serving cached nulls.
|
||||
$this->cache->delete($cacheKey);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user