*/ 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; } }