withOptions(['verify' => false]) ->head($streamUrl) ->successful(); } catch (\Exception) { return false; } } public function getNowPlaying(?string $apiUrl): array { if (! $apiUrl) { return ['enabled' => true, 'song' => null, 'artist' => null]; } try { $response = Http::timeout(5)->get($apiUrl); if ($response->successful()) { $data = $response->json(); if (isset($data['now_playing'])) { $song = $data['now_playing']['song'] ?? $data['now_playing']; return [ 'enabled' => true, 'song' => $song['title'] ?? $song['text'] ?? null, 'artist' => $song['artist'] ?? null, ]; } return [ 'enabled' => true, 'song' => $data['song'] ?? $data['title'] ?? $data['now_playing'] ?? null, 'artist' => $data['artist'] ?? null, ]; } } catch (\Exception) { // Silent fail } return ['enabled' => true, 'song' => null, 'artist' => null]; } public function getListenersCount(?string $apiUrl): int { if (! $apiUrl) { return 0; } try { $response = Http::timeout(5)->get($apiUrl); if ($response->successful()) { $data = $response->json(); return $data['listeners']['total'] ?? $data['listeners']['current'] ?? $data['listeners'] ?? $data['count'] ?? $data['total'] ?? 0; } } catch (\Exception) { // Silent fail } return 0; } public function formatStreamUrl(string $url): string { if ($url === '' || $url === '0') { return $url; } $url = str_replace('http://', 'https://', $url); if (preg_match('/^(https?:\/\/[^\/]+):(\d+)\/(.+)$/', $url, $matches)) { $baseUrl = $matches[1]; $port = $matches[2]; $path = $matches[3]; if (in_array($port, ['8000', '8010', '8020', '8030', '8040', '8050'])) { return $baseUrl . '/radio/' . $port . '/' . $path; } } return $url; } public function detectAzureCast(): array { $baseUrl = $this->getSetting(RadioSettings::AzureCastBaseUrl); if (! empty($baseUrl)) { return ['detected' => true, 'base_url' => $baseUrl]; } $streamUrl = $this->getSetting(RadioSettings::StreamUrl, ''); if (empty($streamUrl)) { return ['detected' => false]; } $parsed = parse_url((string) $streamUrl); if (! $parsed) { return ['detected' => false]; } $scheme = $parsed['scheme'] ?? 'https'; $host = $parsed['host'] ?? ''; $testUrl = $scheme . '://' . $host . '/api/nowplaying'; try { $response = Http::timeout(3)->get($testUrl); if ($response->successful()) { $data = $response->json(); if (is_array($data) && (isset($data[0]['station']) || isset($data['station']))) { $stationId = $data[0]['station']['id'] ?? $data['station']['id'] ?? 1; $detectedBaseUrl = $scheme . '://' . $host; $this->autoConfigureAzureCast($detectedBaseUrl, $stationId); return ['detected' => true, 'base_url' => $detectedBaseUrl, 'station_id' => $stationId]; } } } catch (\Exception) { // Not AzureCast } return ['detected' => false]; } public function getAzureCastApiUrl(): ?string { $baseUrl = $this->getSetting(RadioSettings::AzureCastBaseUrl); $stationId = $this->getSetting(RadioSettings::AzureCastStationId, '1'); if (! empty($baseUrl)) { return rtrim((string) $baseUrl, '/') . '/api/nowplaying/' . $stationId; } $streamUrl = $this->getSetting(RadioSettings::StreamUrl); if (! $streamUrl) { return null; } $parsed = parse_url((string) $streamUrl); if (! $parsed) { return null; } $scheme = $parsed['scheme'] ?? 'https'; $host = $parsed['host'] ?? ''; return $scheme . '://' . $host . '/api/nowplaying/' . $stationId; } private function getSetting(RadioSettings $setting, mixed $default = null): mixed { return Cache::remember("setting_{$setting->value}", 60, function () use ($setting, $default): mixed { $websiteSetting = WebsiteSetting::where('key', $setting->value)->first(); return $websiteSetting?->value ?? $default; }); } private function autoConfigureAzureCast(string $baseUrl, int $stationId): void { $settings = [ RadioSettings::AzureCastBaseUrl->value => $baseUrl, RadioSettings::AzureCastStationId->value => $stationId, RadioSettings::NowPlayingEnabled->value => '1', RadioSettings::ListenersEnabled->value => '1', RadioSettings::ShowCurrentDj->value => '1', RadioSettings::WidgetEnabled->value => '1', RadioSettings::WidgetShowGlobally->value => '1', ]; foreach ($settings as $key => $value) { WebsiteSetting::updateOrCreate( ['key' => $key], ['value' => $value, 'comment' => 'Auto-configured'], ); } Cache::forget('radio_settings_*'); } }