Files
Atomcms-edit/resources/themes/atom/views/components/radio-player.blade.php
T
2026-05-09 17:32:17 +02:00

236 lines
7.4 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@props(['classes' => ''])
@php
$style = cache()->remember('radio_style_value', 300, fn() => \App\Models\Miscellaneous\WebsiteSetting::where('key', 'radio_style')->value('value')) ?? 'dark';
$bgColor = match($style) {
'light' => 'bg-white/90',
'blue' => 'bg-blue-900/90',
default => 'bg-black/90',
};
$textColor = match($style) {
'light' => 'text-gray-900',
default => 'text-white',
};
$accentColor = match($style) {
'light' => 'text-blue-600',
'blue' => 'text-yellow-400',
default => 'text-[var(--color-primary)]',
};
@endphp
<div class="fixed bottom-4 right-4 z-50 flex flex-col gap-2 {{ $classes }}">
<div id="radio-player" class="{{ $bgColor }} backdrop-blur-sm rounded-lg p-3 {{ $textColor }} shadow-lg w-72 sm:w-96">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div id="radio-status" class="w-3 h-3 rounded-full bg-green-500 animate-pulse"></div>
<div class="flex flex-col">
<span class="text-xs font-semibold {{ $accentColor }}">Radio</span>
<span id="current-dj" class="text-xs font-medium">Laden...</span>
</div>
</div>
<div class="flex items-center gap-2">
<button id="radio-toggle" onclick="toggleRadio()" class="{{ $accentColor }} hover:opacity-80 transition">
<span id="play-icon"></span>
<span id="pause-icon" class="hidden"></span>
</button>
<input type="range" id="volume-control" min="0" max="100" value="50" class="w-16 h-1 rounded cursor-pointer accent-{{ $accentColor }}" onchange="changeVolume(this.value)">
</div>
</div>
<div id="now-playing" class="mt-2 text-xs text-center py-1 px-2 bg-black/20 rounded">
<span id="song-title">Laden...</span>
</div>
<div class="mt-2 flex items-center justify-between text-xs">
<span id="listeners" class="flex items-center gap-1">
<span>👥</span>
<span id="listeners-count">--</span>
</span>
<button onclick="toggleShouts()" class="{{ $accentColor }} hover:underline">
🔊 Shouts
</button>
</div>
</div>
<div id="shouts-panel" class="hidden {{ $bgColor }} backdrop-blur-sm rounded-lg p-3 {{ $textColor }} shadow-lg w-80 sm:w-full max-h-64 overflow-y-auto">
<div class="flex justify-between items-center mb-2">
<span class="text-xs font-semibold {{ $accentColor }}">Live Shouts</span>
<button onclick="toggleShouts()" class="text-gray-400 hover:text-white text-xs">×</button>
</div>
<div id="shouts-list" class="space-y-2">
<p class="text-xs text-gray-400">Shouts laden...</p>
</div>
</div>
<input type="hidden" id="radio-stream-url" value="">
<audio id="radio-audio" preload="none"></audio>
</div>
<script>
let isPlaying = false;
let shoutsPanelOpen = false;
function toggleRadio() {
const audio = document.getElementById('radio-audio');
const playIcon = document.getElementById('play-icon');
const pauseIcon = document.getElementById('pause-icon');
const radioStatus = document.getElementById('radio-status');
if (isPlaying) {
audio.pause();
playIcon.classList.remove('hidden');
pauseIcon.classList.add('hidden');
radioStatus.classList.remove('bg-green-500', 'animate-pulse');
radioStatus.classList.add('bg-gray-500');
isPlaying = false;
} else {
fetch('/api/radio/config')
.then(r => r.json())
.then(config => {
if (config.stream_url) {
audio.src = config.stream_url;
audio.play().then(() => {
playIcon.classList.add('hidden');
pauseIcon.classList.remove('hidden');
radioStatus.classList.add('bg-green-500', 'animate-pulse');
radioStatus.classList.remove('bg-gray-500');
isPlaying = true;
}).catch(e => {
console.error('Audio play failed:', e);
alert('Kan radio niet afspelen. Controleer je browser instellingen en probeer het opnieuw.');
});
} else {
alert('Geen stream URL beschikbaar. Radio is mogelijk offline.');
}
})
.catch(e => {
console.error('Failed to fetch radio config:', e);
alert('Kan radio configuratie niet laden. Probeer het later opnieuw.');
});
}
}
function changeVolume(value) {
const audio = document.getElementById('radio-audio');
audio.volume = value / 100;
}
function toggleShouts() {
const panel = document.getElementById('shouts-panel');
shoutsPanelOpen = !shoutsPanelOpen;
panel.classList.toggle('hidden', !shoutsPanelOpen);
if (shoutsPanelOpen) {
loadShouts();
}
}
function loadShouts() {
fetch('/api/radio/shouts')
.then(response => {
if (!response.ok) {
throw new Error('Shouts niet beschikbaar');
}
return response.json();
})
.then(data => {
const shoutsList = document.getElementById('shouts-list');
if (data.error) {
shoutsList.innerHTML = `<p class="text-xs text-red-400">${data.error}</p>`;
} else if (data.shouts && data.shouts.length > 0) {
shoutsList.innerHTML = data.shouts.map(shout => `
<div class="text-xs border-b border-gray-700 pb-1 mb-1">
<span class="font-semibold ${shout.username === 'Anoniem' ? 'text-gray-400' : '{{ $accentColor }}'}">${shout.username}:</span>
<span class="text-gray-300 ml-1">${shout.message}</span>
<span class="text-gray-500 text-xs block">${shout.created_at}</span>
</div>
`).join('');
} else {
shoutsList.innerHTML = '<p class="text-xs text-gray-400">Nog geen shouts... Wees de eerste!</p>';
}
})
.catch(error => {
console.error('Shouts load error:', error);
document.getElementById('shouts-list').innerHTML = '<p class="text-xs text-red-400">Fout bij laden van shouts...</p>';
});
}
function getCurrentDJ() {
fetch('/api/radio/current-dj')
.then(response => response.json())
.then(data => {
const djElement = document.getElementById('current-dj');
if (data.error) {
djElement.textContent = 'Error: ' + data.error;
} else if (data.dj) {
const djName = (typeof data.dj === 'object' && data.dj !== null)
? (data.dj.username || data.dj.show_name || 'DJ')
: data.dj;
djElement.textContent = djName;
} else {
djElement.textContent = 'Geen DJ actief';
}
})
.catch(error => {
console.error('DJ info error:', error);
document.getElementById('current-dj').textContent = '--';
});
}
function getNowPlaying() {
fetch('/api/radio/now-playing')
.then(response => response.json())
.then(data => {
const songElement = document.getElementById('song-title');
if (data.error) {
songElement.textContent = 'Error: ' + data.error;
} else if (data.song) {
songElement.textContent = data.song + (data.artist ? ' - ' + data.artist : '');
} else if (data.artist && data.title) {
songElement.textContent = data.artist + ' - ' + data.title;
} else if (typeof data.now_playing === 'object' && data.now_playing !== null) {
const np = data.now_playing;
if (np.song) {
songElement.textContent = np.song + (np.artist ? ' - ' + np.artist : '');
} else if (np.artist && np.title) {
songElement.textContent = np.artist + ' - ' + np.title;
} else {
songElement.textContent = 'Live radio';
}
} else {
songElement.textContent = 'Live radio';
}
})
.catch(error => {
console.error('Now playing error:', error);
document.getElementById('song-title').textContent = 'Niet beschikbaar';
});
}
function getListeners() {
fetch('/api/radio/listeners')
.then(response => response.json())
.then(data => {
const countElement = document.getElementById('listeners-count');
if (data.error) {
countElement.textContent = 'Error';
} else {
countElement.textContent = data.count ? data.count.toLocaleString() : '0';
}
})
.catch(error => {
console.error('Listeners error:', error);
document.getElementById('listeners-count').textContent = '--';
});
}
setInterval(getListeners, 30000);
setInterval(getNowPlaying, 30000);
setInterval(getCurrentDJ, 30000);
if (shoutsPanelOpen) {
setInterval(loadShouts, 15000);
}
getCurrentDJ();
getNowPlaying();
getListeners();
</script>