Initial commit

This commit is contained in:
root
2026-05-09 17:28:23 +02:00
commit 9d73f82529
5575 changed files with 281989 additions and 0 deletions
@@ -0,0 +1,235 @@
@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>