Files
tonehaus/src/Service/ExternalProviderManager.php
T
2026-04-02 13:46:07 +01:00

205 lines
6.0 KiB
PHP

<?php
namespace App\Service;
use App\Repository\SettingRepository;
use Psr\Log\LoggerInterface;
/**
* ExternalProviderManager resolves active provider state and enforces catalog reset rules.
*/
class ExternalProviderManager
{
public const PROVIDER_LASTFM = 'lastfm';
public const PROVIDER_MUSICBRAINZ = 'musicbrainz';
public const PROVIDER_TIDAL = 'tidal';
public const SETTING_PROVIDER = 'EXTERNAL_ALBUM_PROVIDER';
public const SETTING_ACTIVE_PROVIDER = 'EXTERNAL_ALBUM_PROVIDER_ACTIVE';
private const VALID_PROVIDERS = [
self::PROVIDER_LASTFM,
self::PROVIDER_MUSICBRAINZ,
self::PROVIDER_TIDAL,
];
public function __construct(
private readonly SettingRepository $settings,
private readonly CatalogResetService $catalogResetService,
private readonly LoggerInterface $logger,
) {
}
/**
* @return list<string>
*/
public function getValidProviders(): array
{
return self::VALID_PROVIDERS;
}
public function isValidProvider(?string $provider): bool
{
return $this->normalizeProvider($provider) !== null;
}
public function getStoredProvider(): string
{
$stored = $this->normalizeProvider($this->settings->getValue(self::SETTING_PROVIDER));
return $stored ?? self::PROVIDER_LASTFM;
}
public function getEnvOverrideProvider(): ?string
{
$raw = $_ENV['EXTERNAL_ALBUM_PROVIDER'] ?? $_SERVER['EXTERNAL_ALBUM_PROVIDER'] ?? null;
return $this->normalizeProvider(is_string($raw) ? $raw : null);
}
public function isEnvOverrideActive(): bool
{
return $this->getEnvOverrideProvider() !== null;
}
public function getEffectiveProvider(): string
{
$override = $this->getEnvOverrideProvider();
return $override ?? $this->getStoredProvider();
}
public function getActiveProvider(): string
{
$active = $this->normalizeProvider($this->settings->getValue(self::SETTING_ACTIVE_PROVIDER));
return $active ?? $this->getStoredProvider();
}
public function getProviderLabel(string $provider): string
{
return match ($provider) {
self::PROVIDER_MUSICBRAINZ => 'MusicBrainz',
self::PROVIDER_TIDAL => 'TIDAL',
default => 'Last.fm',
};
}
/**
* Applies provider state at startup and resets catalog if effective provider changed.
*
* @return array{
* effective_provider:string,
* previous_provider:string,
* changed:bool,
* reset:bool,
* albums:int,
* reviews:int
* }
*/
public function syncEffectiveProviderAtStartup(): array
{
$effective = $this->getEffectiveProvider();
$previous = $this->getActiveProvider();
if ($effective === $previous) {
$this->settings->setValues([
self::SETTING_ACTIVE_PROVIDER => $effective,
]);
return [
'effective_provider' => $effective,
'previous_provider' => $previous,
'changed' => false,
'reset' => false,
'albums' => 0,
'reviews' => 0,
];
}
$reset = $this->catalogResetService->resetCatalog();
$this->settings->setValues([
self::SETTING_ACTIVE_PROVIDER => $effective,
]);
$this->logger->warning('External provider changed between starts; catalog reset applied.', [
'previous_provider' => $previous,
'effective_provider' => $effective,
'deleted_albums' => $reset['albums'],
'deleted_reviews' => $reset['reviews'],
]);
return [
'effective_provider' => $effective,
'previous_provider' => $previous,
'changed' => true,
'reset' => true,
'albums' => (int) $reset['albums'],
'reviews' => (int) $reset['reviews'],
];
}
/**
* Persists admin-selected provider and resets catalog only when effective provider changes.
*
* @return array{
* effective_provider:string,
* previous_provider:string,
* changed:bool,
* reset:bool,
* albums:int,
* reviews:int,
* env_override_active:bool
* }
*/
public function applyAdminSelectedProvider(string $selectedProvider): array
{
$normalizedSelected = $this->normalizeProvider($selectedProvider);
if ($normalizedSelected === null) {
throw new \InvalidArgumentException('Unsupported provider selected.');
}
$previous = $this->getActiveProvider();
$override = $this->getEnvOverrideProvider();
$effective = $override ?? $normalizedSelected;
$updates = [
self::SETTING_PROVIDER => $normalizedSelected,
];
$deletedAlbums = 0;
$deletedReviews = 0;
$didReset = false;
if ($effective !== $previous) {
$reset = $this->catalogResetService->resetCatalog();
$deletedAlbums = (int) $reset['albums'];
$deletedReviews = (int) $reset['reviews'];
$didReset = true;
$updates[self::SETTING_ACTIVE_PROVIDER] = $effective;
} else {
$updates[self::SETTING_ACTIVE_PROVIDER] = $previous;
}
$this->settings->setValues($updates);
return [
'effective_provider' => $effective,
'previous_provider' => $previous,
'changed' => $effective !== $previous,
'reset' => $didReset,
'albums' => $deletedAlbums,
'reviews' => $deletedReviews,
'env_override_active' => $override !== null,
];
}
private function normalizeProvider(?string $provider): ?string
{
if ($provider === null) {
return null;
}
$normalized = mb_strtolower(trim($provider));
if ($normalized === '') {
return null;
}
return in_array($normalized, self::VALID_PROVIDERS, true) ? $normalized : null;
}
}