205 lines
6.0 KiB
PHP
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;
|
|
}
|
|
}
|