You've already forked Atomcms-edit
81e99933e4
- DRY FurniEditorController: extract duplicate try/catch blocks into handleApiError(), formatItemData(), buildUpdateData(), buildInsertData(), castValue() methods - ProfileController: replace 45 lines of manual date formatting with Carbon's diffForHumans() - Replace custom Password rule (180 lines) with Laravel's built-in Password::min() rule - RadioController: extract RadioStreamService and RadioScheduleService, reducing from 608 to 323 lines - Add RadioSettings enum to replace magic strings throughout radio feature - Add CurrencyTypes::columnName() helper method - Add consistent return types (JsonResponse, View, RedirectResponse) to all controller methods
205 lines
6.1 KiB
PHP
Executable File
205 lines
6.1 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Services\Community;
|
|
|
|
use App\Enums\RadioSettings;
|
|
use App\Models\Miscellaneous\WebsiteSetting;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
class RadioStreamService
|
|
{
|
|
public function checkOnline(string $streamUrl): bool
|
|
{
|
|
if ($streamUrl === '' || $streamUrl === '0') {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
return Http::timeout(2)
|
|
->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_*');
|
|
}
|
|
}
|