Files
Atomcms-edit/app/Http/Controllers/Admin/RadioWizardController.php
T
root 5476dce882 Add multi-step radio wizard with Shoutcast/Icecast/AzureCast support and multi-language translations
- New 5-step RadioWizardController with session-based wizard flow
- Enhanced RadioStreamService with Shoutcast/Icecast/ AzureCast auto-detection
- Connection test functionality for stream, now-playing, and listeners
- Wizard views for all 5 steps with step indicator navigation
- All 21 language files updated with wizard translation keys (NL/EN + placeholders)
- Wizard link added to existing radio setup page
- Routes registered under /admin/radio/wizard/*
2026-05-24 13:12:57 +02:00

415 lines
17 KiB
PHP
Executable File

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Miscellaneous\WebsiteSetting;
use App\Models\RadioRank;
use App\Services\Community\RadioStreamService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\View\View;
class RadioWizardController extends Controller
{
private const SESSION_KEY = 'radio_wizard';
public function __construct(
private readonly RadioStreamService $streamService,
) {}
public function index(): View
{
$data = session()->get(self::SESSION_KEY);
if (! $data) {
session()->forget(self::SESSION_KEY);
}
return view('admin.radio.wizard.step-1', [
'step' => 1,
'selectedPlatform' => $data['platform'] ?? null,
]);
}
public function processStep1(Request $request): RedirectResponse
{
$validated = $request->validate([
'platform' => ['required', 'string', 'in:shoutcast,icecast,azurecast,other'],
]);
session()->put(self::SESSION_KEY . '.platform', $validated['platform']);
return redirect()->route('admin.radio.wizard.step', ['step' => 2]);
}
public function step(int $step): View|RedirectResponse
{
$data = session()->get(self::SESSION_KEY);
if (! $data && $step > 1) {
return redirect()->route('admin.radio.wizard');
}
return match ($step) {
2 => $this->step2($data),
3 => $this->step3($data),
4 => $this->step4($data),
5 => $this->step5($data),
default => redirect()->route('admin.radio.wizard'),
};
}
private function step2(array $data): View
{
$platform = $data['platform'] ?? 'other';
$platformLabels = [
'shoutcast' => 'SHOUTcast',
'icecast' => 'Icecast',
'azurecast' => 'AzureCast',
'other' => 'Anders',
];
return view('admin.radio.wizard.step-2', [
'step' => 2,
'platform' => $platform,
'platformLabel' => $platformLabels[$platform] ?? 'Onbekend',
'streamUrl' => session()->get(self::SESSION_KEY . '.stream_url', ''),
'streamName' => session()->get(self::SESSION_KEY . '.stream_name', ''),
'azurecastBaseUrl' => session()->get(self::SESSION_KEY . '.azurecast_base_url', ''),
'azurecastStationId' => session()->get(self::SESSION_KEY . '.azurecast_station_id', '1'),
]);
}
public function processStep2(Request $request): RedirectResponse
{
$platform = session()->get(self::SESSION_KEY . '.platform', 'other');
$rules = [
'stream_url' => ['required', 'string', 'max:500'],
'stream_name' => ['nullable', 'string', 'max:100'],
];
if ($platform === 'azurecast') {
$rules['azurecast_base_url'] = ['nullable', 'string', 'max:500'];
$rules['azurecast_station_id'] = ['nullable', 'integer', 'min:1'];
}
$validated = $request->validate($rules);
session()->put(self::SESSION_KEY . '.stream_url', $validated['stream_url']);
session()->put(self::SESSION_KEY . '.stream_name', $validated['stream_name'] ?? 'Mijn Radio');
if ($platform === 'azurecast') {
session()->put(self::SESSION_KEY . '.azurecast_base_url', $validated['azurecast_base_url'] ?? '');
session()->put(self::SESSION_KEY . '.azurecast_station_id', $validated['azurecast_station_id'] ?? '1');
}
return redirect()->route('admin.radio.wizard.step', ['step' => 3]);
}
private function step3(array $data): View
{
$platform = $data['platform'] ?? 'other';
$streamUrl = $data['stream_url'] ?? '';
$autoDetected = null;
if (! empty($streamUrl)) {
$autoDetected = $this->streamService->detectStreamType($streamUrl);
}
return view('admin.radio.wizard.step-3', [
'step' => 3,
'platform' => $platform,
'autoDetected' => $autoDetected,
'nowPlayingApi' => session()->get(self::SESSION_KEY . '.now_playing_api', $autoDetected['now_playing_api'] ?? ''),
'listenersApi' => session()->get(self::SESSION_KEY . '.listeners_api', $autoDetected['listeners_api'] ?? ''),
'enableNowPlaying' => session()->get(self::SESSION_KEY . '.enable_now_playing', true),
'enableListeners' => session()->get(self::SESSION_KEY . '.enable_listeners', true),
'enableCurrentDj' => session()->get(self::SESSION_KEY . '.enable_current_dj', true),
]);
}
public function processStep3(Request $request): RedirectResponse
{
$validated = $request->validate([
'now_playing_api' => ['nullable', 'string', 'max:500'],
'listeners_api' => ['nullable', 'string', 'max:500'],
'enable_now_playing' => ['nullable', 'boolean'],
'enable_listeners' => ['nullable', 'boolean'],
'enable_current_dj' => ['nullable', 'boolean'],
]);
session()->put(self::SESSION_KEY . '.now_playing_api', $validated['now_playing_api'] ?? '');
session()->put(self::SESSION_KEY . '.listeners_api', $validated['listeners_api'] ?? '');
session()->put(self::SESSION_KEY . '.enable_now_playing', (bool) ($validated['enable_now_playing'] ?? false));
session()->put(self::SESSION_KEY . '.enable_listeners', (bool) ($validated['enable_listeners'] ?? false));
session()->put(self::SESSION_KEY . '.enable_current_dj', (bool) ($validated['enable_current_dj'] ?? false));
return redirect()->route('admin.radio.wizard.step', ['step' => 4]);
}
private function step4(array $data): View
{
return view('admin.radio.wizard.step-4', [
'step' => 4,
'enableShouts' => session()->get(self::SESSION_KEY . '.enable_shouts', true),
'enableApplications' => session()->get(self::SESSION_KEY . '.enable_applications', true),
'enableWidget' => session()->get(self::SESSION_KEY . '.enable_widget', true),
'enableWidgetGlobally' => session()->get(self::SESSION_KEY . '.enable_widget_globally', true),
'enablePoints' => session()->get(self::SESSION_KEY . '.enable_points', true),
'enableRequests' => session()->get(self::SESSION_KEY . '.enable_requests', true),
'enableContests' => session()->get(self::SESSION_KEY . '.enable_contests', true),
'enableGiveaways' => session()->get(self::SESSION_KEY . '.enable_giveaways', false),
'enableDiscord' => session()->get(self::SESSION_KEY . '.enable_discord', false),
'discordWebhook' => session()->get(self::SESSION_KEY . '.discord_webhook', ''),
'widgetPosition' => session()->get(self::SESSION_KEY . '.widget_position', 'bottom-right'),
]);
}
public function processStep4(Request $request): RedirectResponse
{
$validated = $request->validate([
'enable_shouts' => ['nullable', 'boolean'],
'enable_applications' => ['nullable', 'boolean'],
'enable_widget' => ['nullable', 'boolean'],
'enable_widget_globally' => ['nullable', 'boolean'],
'enable_points' => ['nullable', 'boolean'],
'enable_requests' => ['nullable', 'boolean'],
'enable_contests' => ['nullable', 'boolean'],
'enable_giveaways' => ['nullable', 'boolean'],
'enable_discord' => ['nullable', 'boolean'],
'discord_webhook' => ['nullable', 'string', 'max:500'],
'widget_position' => ['nullable', 'string', 'in:bottom-right,bottom-left,top-right,top-left'],
]);
session()->put(self::SESSION_KEY . '.enable_shouts', (bool) ($validated['enable_shouts'] ?? false));
session()->put(self::SESSION_KEY . '.enable_applications', (bool) ($validated['enable_applications'] ?? false));
session()->put(self::SESSION_KEY . '.enable_widget', (bool) ($validated['enable_widget'] ?? false));
session()->put(self::SESSION_KEY . '.enable_widget_globally', (bool) ($validated['enable_widget_globally'] ?? false));
session()->put(self::SESSION_KEY . '.enable_points', (bool) ($validated['enable_points'] ?? false));
session()->put(self::SESSION_KEY . '.enable_requests', (bool) ($validated['enable_requests'] ?? false));
session()->put(self::SESSION_KEY . '.enable_contests', (bool) ($validated['enable_contests'] ?? false));
session()->put(self::SESSION_KEY . '.enable_giveaways', (bool) ($validated['enable_giveaways'] ?? false));
session()->put(self::SESSION_KEY . '.enable_discord', (bool) ($validated['enable_discord'] ?? false));
session()->put(self::SESSION_KEY . '.discord_webhook', $validated['discord_webhook'] ?? '');
session()->put(self::SESSION_KEY . '.widget_position', $validated['widget_position'] ?? 'bottom-right');
return redirect()->route('admin.radio.wizard.step', ['step' => 5]);
}
private function step5(array $data): View
{
$platform = $data['platform'] ?? 'other';
$streamUrl = $data['stream_url'] ?? '';
$platformLabels = [
'shoutcast' => 'SHOUTcast',
'icecast' => 'Icecast',
'azurecast' => 'AzureCast',
'other' => 'Anders',
];
$testResults = null;
if (! empty($streamUrl)) {
$testResults = $this->streamService->testStreamConnection(
$streamUrl,
$data['now_playing_api'] ?? null,
$data['listeners_api'] ?? null,
);
}
$settingsList = $this->buildSettingsList($data);
return view('admin.radio.wizard.step-5', [
'step' => 5,
'platform' => $platform,
'platformLabel' => $platformLabels[$platform] ?? 'Onbekend',
'data' => $data,
'testResults' => $testResults,
'settingsList' => $settingsList,
]);
}
public function runTest(): JsonResponse
{
$data = session()->get(self::SESSION_KEY);
if (! $data || empty($data['stream_url'])) {
return response()->json([
'success' => false,
'error' => 'Geen stream URL gevonden. Start de wizard opnieuw.',
]);
}
$testResults = $this->streamService->testStreamConnection(
$data['stream_url'],
$data['now_playing_api'] ?? null,
$data['listeners_api'] ?? null,
);
return response()->json([
'success' => true,
'results' => $testResults,
]);
}
public function complete(): RedirectResponse
{
$data = session()->get(self::SESSION_KEY);
if (! $data) {
return redirect()->route('admin.radio.wizard')
->with('error', 'Geen wizard data gevonden. Start opnieuw.');
}
try {
$this->saveAllSettings($data);
$this->createDefaultRanks();
Artisan::call('config:clear');
Artisan::call('cache:clear');
session()->forget(self::SESSION_KEY);
return redirect()->route('admin.radio.setup')
->with('success', 'Radio systeem is succesvol geïnstalleerd en geconfigureerd!');
} catch (\Exception $e) {
return redirect()->route('admin.radio.wizard.step', ['step' => 5])
->with('error', 'Fout tijdens opslaan: ' . $e->getMessage());
}
}
private function saveAllSettings(array $data): void
{
$platform = $data['platform'] ?? 'other';
$settings = [
'radio_enabled' => '1',
'radio_stream_url' => $data['stream_url'] ?? '',
'radio_stream_name' => $data['stream_name'] ?? 'Mijn Radio',
'radio_style' => 'dark',
'radio_auto_play' => '0',
'radio_stream_platform' => $platform,
'radio_now_playing_enabled' => ($data['enable_now_playing'] ?? true) ? '1' : '0',
'radio_listeners_enabled' => ($data['enable_listeners'] ?? true) ? '1' : '0',
'radio_show_current_dj' => ($data['enable_current_dj'] ?? true) ? '1' : '0',
'radio_shouts_enabled' => ($data['enable_shouts'] ?? true) ? '1' : '0',
'radio_applications_enabled' => ($data['enable_applications'] ?? true) ? '1' : '0',
'radio_widget_enabled' => ($data['enable_widget'] ?? true) ? '1' : '0',
'radio_widget_show_globally' => ($data['enable_widget_globally'] ?? true) ? '1' : '0',
'radio_widget_position' => $data['widget_position'] ?? 'bottom-right',
'radio_auto_dj_detection' => '1',
'radio_show_song_history' => '1',
'radio_show_schedule_preview' => '1',
'radio_word_filter_enabled' => '1',
];
if ($platform === 'azurecast') {
$settings['radio_azurecast_base_url'] = $data['azurecast_base_url'] ?? '';
$settings['radio_azurecast_station_id'] = $data['azurecast_station_id'] ?? '1';
}
if (! empty($data['now_playing_api'])) {
$settings['radio_now_playing_api_url'] = $data['now_playing_api'];
}
if (! empty($data['listeners_api'])) {
$settings['radio_listeners_api_url'] = $data['listeners_api'];
}
if ($data['enable_points'] ?? true) {
$settings['points_enabled'] = '1';
$settings['points_per_minute'] = '2';
$settings['max_points_per_day'] = '100';
$settings['points_for_request'] = '5';
$settings['points_for_vote'] = '2';
$settings['points_for_giveaway_win'] = '50';
$settings['points_for_contest_win'] = '100';
}
if ($data['enable_requests'] ?? true) {
$settings['radio_request_form_enabled'] = '1';
}
if ($data['enable_contests'] ?? true) {
$settings['radio_contests_enabled'] = '1';
}
if ($data['enable_giveaways'] ?? false) {
$settings['radio_giveaways_enabled'] = '1';
}
if ($data['enable_discord'] ?? false && ! empty($data['discord_webhook'])) {
$settings['radio_discord_enabled'] = '1';
$settings['radio_discord_webhook_url'] = $data['discord_webhook'];
$settings['radio_discord_dj_live'] = '1';
$settings['radio_discord_song_changes'] = '1';
}
foreach ($settings as $key => $value) {
WebsiteSetting::updateOrCreate(
['key' => $key],
['value' => (string) $value, 'comment' => 'Radio wizard configuratie'],
);
}
}
private function createDefaultRanks(): void
{
$ranks = [
['name' => 'Trainee DJ', 'level' => 1, 'is_active' => true, 'description' => 'Beginnende DJ'],
['name' => 'Junior DJ', 'level' => 2, 'is_active' => true, 'description' => 'Ervaren DJ'],
['name' => 'Senior DJ', 'level' => 3, 'is_active' => true, 'description' => 'Professionele DJ'],
['name' => 'Head DJ', 'level' => 4, 'is_active' => true, 'description' => 'Hoofd DJ'],
['name' => 'Radio Manager', 'level' => 5, 'is_active' => true, 'description' => 'Radio Manager'],
];
foreach ($ranks as $rank) {
RadioRank::updateOrCreate(
['name' => $rank['name']],
$rank,
);
}
}
private function buildSettingsList(array $data): array
{
$list = [];
$list['Stream URL'] = $data['stream_url'] ?? '-';
$list['Stream Naam'] = $data['stream_name'] ?? 'Mijn Radio';
$list['Platform'] = match ($data['platform'] ?? 'other') {
'shoutcast' => 'SHOUTcast',
'icecast' => 'Icecast',
'azurecast' => 'AzureCast',
default => 'Anders',
};
if (! empty($data['now_playing_api'])) {
$list['Now Playing API'] = $data['now_playing_api'];
}
if (! empty($data['listeners_api'])) {
$list['Listeners API'] = $data['listeners_api'];
}
$list['Nu Afspelen'] = ($data['enable_now_playing'] ?? true) ? 'Aan' : 'Uit';
$list['Luisteraars'] = ($data['enable_listeners'] ?? true) ? 'Aan' : 'Uit';
$list['Huidige DJ'] = ($data['enable_current_dj'] ?? true) ? 'Aan' : 'Uit';
$list['Shouts'] = ($data['enable_shouts'] ?? true) ? 'Aan' : 'Uit';
$list['DJ Aanmeldingen'] = ($data['enable_applications'] ?? true) ? 'Aan' : 'Uit';
$list['Radio Widget'] = ($data['enable_widget'] ?? true) ? 'Aan' : 'Uit';
$list['Widget Overal'] = ($data['enable_widget_globally'] ?? true) ? 'Ja' : 'Nee';
$list['Widget Positie'] = $data['widget_position'] ?? 'bottom-right';
$list['Punten Systeem'] = ($data['enable_points'] ?? true) ? 'Aan' : 'Uit';
$list['Song Verzoeken'] = ($data['enable_requests'] ?? true) ? 'Aan' : 'Uit';
$list['Contesten'] = ($data['enable_contests'] ?? true) ? 'Aan' : 'Uit';
$list['Giveaways'] = ($data['enable_giveaways'] ?? false) ? 'Aan' : 'Uit';
$list['Discord'] = ($data['enable_discord'] ?? false) ? 'Aan' : 'Uit';
return $list;
}
}