Skip to content

Instantly share code, notes, and snippets.

@scysys
Last active December 31, 2025 15:56
Show Gist options
  • Select an option

  • Save scysys/68ed6fde9dc9f0a03ac6309a9d8576c0 to your computer and use it in GitHub Desktop.

Select an option

Save scysys/68ed6fde9dc9f0a03ac6309a9d8576c0 to your computer and use it in GitHub Desktop.
Radio Status Display for SPCast – HTML, PHP 7.4+ for PHP-Fusion 7.x
opentable("Ihr hört gerade"); echo '
<script>
var loadbalancerDomain = "andys-musikbox.sp.radio.fm";
</script>
<script src="https://andys-musikbox.sp.radio.fm/scripts/js/details.min.js"></script>
<style>
.container {
text-align: center;
width: 100%;
}
/* DJ + Cover nebeneinander, gleiche Größe, volle Breite */
.cover-wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
gap: 60px; /* Abstand zwischen DJ-Bild und Cover */
margin: 20px 0;
}
#dj-container {
text-align: center;
width: 150px;
height: 150px;
}
#dj-container img {
width: 150px;
height: 150px;
border-radius: 8px;
object-fit: cover;
box-shadow: 0 0 10px rgba(255,255,255,0.4);
}
.cover-container {
display: flex;
justify-content: center;
align-items: center;
width: 150px;
height: 150px;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
cursor: pointer;
}
.cover-container img {
width: 150px;
height: 150px;
object-fit: contain;
}
.visualizer-container {
width: 100%;
max-width: 500px;
height: 80px;
margin: 20px auto;
background: transparent;
display: flex;
align-items: center;
justify-content: center;
}
.visualizer-canvas {
width: 100%;
height: 80px;
}
.audio-container {
display: flex;
align-items: center;
justify-content: center;
background: #002b5e;
padding: 15px;
border-radius: 10px;
box-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
max-width: 500px;
margin: auto;
}
.spcasteu_streaminfo {
width: 64px;
height: 64px;
object-fit: cover;
margin-right: 15px;
}
.player-icons {
display: flex;
justify-content: center;
gap: 10px;
margin: 10px 0;
}
.player-icons img {
width: 35px;
height: 35px;
}
marquee {
font-size: 20px;
margin-top: 10px;
}
#modalInfos {
display: none;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.7);
}
#modalContent {
background: rgba(255, 255, 255, 0.85);
margin: 10% auto;
padding: 20px;
width: 80%;
max-width: 600px;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
color: #000;
text-align: center;
backdrop-filter: blur(6px);
}
#modalContent h2 {
color: #002b5e;
margin-top: 0;
}
#modalContent button {
background-color: #47bf1f;
border: none;
padding: 8px 20px;
color: #fff;
border-radius: 5px;
cursor: pointer;
margin-top: 15px;
}
#modalContent button:hover {
background-color: #3ca618;
}
</style>
<script>
var defaultCover = "https://andys-musikbox.de/infusions/sendeplan/images/dj-avatars/0.gif";
var coverOnlySize = "medium";
var numberOfCovers = 1;
</script>
<script src="https://andys-musikbox.sp.radio.fm/scripts/js/cover.php"></script>
<script>
function parseSongText(text) {
let splitted = text.split(" - ");
let trackArtist = splitted[0] ? splitted[0].trim() : "Unbekannter Artist";
let trackTitle = splitted[1] ? splitted[1].trim() : "Unbekannter Titel";
let sendedj = "der AutoDJ";
let displayTitle = trackTitle;
if (trackTitle.includes(" | ")) {
let parts = trackTitle.split(" | ");
displayTitle = parts[0].trim();
sendedj = parts[1].trim();
}
return { trackArtist, displayTitle, sendedj };
}
async function fetchCurrentSong() {
try {
let response = await fetch("https://andys-musikbox.spcast.eu/currentSong.txt?nocache=" + new Date().getTime());
let text = await response.text();
let { trackArtist, displayTitle, sendedj } = parseSongText(text);
document.getElementById("currentArtist").innerText = (sendedj !== "der AutoDJ" ? sendedj + " OnAir" : sendedj);
let cc = document.querySelector(".cover-container");
cc.querySelector(".artist").innerText = trackArtist;
cc.querySelector(".song").innerText = displayTitle;
document.getElementById("spCoverImageOnly1").alt = "Cover von " + trackArtist + " - " + displayTitle;
} catch (e) {
document.getElementById("currentArtist").innerText = "der AutoDJ";
}
}
setInterval(fetchCurrentSong, 10000);
fetchCurrentSong();
async function updateDJ() {
try {
const response = await fetch("https://www.andys-musikbox.de/includes/sp/spExtractModeratorActive.php");
const data = await response.json();
const djContainer = document.getElementById("dj-container");
if (!data.dj || data.dj.toLowerCase() === "autodj" || data.dj === "") {
djContainer.innerHTML = "";
return;
}
const imgTag = data.image ? `<img src="${data.image}" alt="${data.dj}" />` : "";
djContainer.innerHTML = `<div>${imgTag}</div>`;
} catch (err) {
console.error("Fehler beim Laden des DJ:", err);
document.getElementById("dj-container").innerHTML = "";
}
}
setInterval(updateDJ, 10000);
updateDJ();
</script>
<div class="container">
<div class="radio-info">
<hr class="side-hr" role="presentation" aria-hidden="true" />
Für euch auf Sendung ist aktuell <span id="currentArtist">Loading...</span>
<hr class="side-hr" role="presentation" aria-hidden="true" />
</div>
<div class="cover-wrapper">
<div id="dj-container"></div>
<div class="cover-container" role="button" tabindex="0" aria-label="Songinformationen anzeigen" onclick="openModal(this)">
<span class="artist" style="display: none">der AutoDJ</span>
<span class="song" style="display: none">Unbekannter Titel</span>
<img class="background-image" alt="Cover" id="spCoverImageOnly1" />
</div>
</div>
<div class="player-icons">
<a href="https://andys-musikbox.spcast.eu/" target="_blank" rel="noopener" title="HTML5-Player">
<img src="/infusions/gr_radiostatus_panel/images/flash.png" alt="HTML5-Player öffnen" />
</a>
<a href="https://andys-musikbox.sp.radio.fm/listen.pls" title="Für Winamp oder VLC">
<img src="/infusions/gr_radiostatus_panel/images/winamp.png" alt="Download .pls für Winamp/VLC" />
</a>
<a href="https://andys-musikbox.sp.radio.fm/listen.asx" title="Windows Media Player">
<img src="/infusions/gr_radiostatus_panel/images/wmp.png" alt="Link für Windows Media Player" />
</a>
<a href="https://andys-musikbox.sp.radio.fm/listen.ram" title="Realplayer">
<img src="/infusions/gr_radiostatus_panel/images/realplayer.png" alt="Link für Realplayer" />
</a>
<a href="https://www.laut.fm/andy-radio" target="_blank" rel="noopener" title="Laut.fm Station">
<img src="/infusions/gr_radiostatus_panel/images/lautfm.png" alt="Zur Laut.fm Station wechseln" />
</a>
</div>
<div class="radio-info">
<strong>Aktueller Titel</strong><br />
<marquee behavior="scroll" scrollamount="2" scrolldelay="80" width="85%" onmouseover="this.stop()" onmouseout="this.start()" aria-live="polite">
<span class="spcasteu_streaminfo" data-type="live_dj_title" data-fallback="mounts./stream_live.metadata.now_playing" data-fallback-last="mounts./autodj.metadata.now_playing" data-error="Error loading song text">
Songtext wird geladen...
</span>
</marquee>
</div>
<div class="visualizer-container">
<canvas id="visualizer" class="visualizer-canvas" aria-hidden="true"></canvas>
</div>
<div class="audio-container">
<audio id="spAudioPlayer" controls="controls" preload="none"></audio>
</div>
</div>
<script src="https://andys-musikbox.sp.radio.fm/js/mse/spAudioPlayer.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
let audioElement = document.getElementById("spAudioPlayer");
let canvas = document.getElementById("visualizer");
let ctx = canvas.getContext("2d");
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
let analyser = audioCtx.createAnalyser();
analyser.fftSize = 256;
let source = audioCtx.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioCtx.destination);
function draw() {
requestAnimationFrame(draw);
let bufferLength = analyser.frequencyBinCount;
let dataArray = new Uint8Array(bufferLength);
analyser.getByteFrequencyData(dataArray);
ctx.clearRect(0, 0, canvas.width, canvas.height);
let barWidth = (canvas.width / bufferLength) * 2.5;
let barHeight;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
barHeight = dataArray[i] / 2;
let hue = (i / bufferLength) * 360;
ctx.fillStyle = "hsl(" + hue + ",100%,50%)";
ctx.fillRect(x, canvas.height - barHeight / 2, barWidth, barHeight);
x += barWidth + 1;
}
}
audioElement.onplay = function () {
if (audioCtx.state === "suspended") {
audioCtx.resume();
}
draw();
};
});
function openModal(element) {
var parent = element.parentElement;
var artist = parent.querySelector(".artist").innerText;
var song = parent.querySelector(".song").innerText;
var url = "https://playlist.spcast.eu/g/generate_info.php?artist=" + encodeURIComponent(artist) + "&title=" + encodeURIComponent(song);
var modal = document.getElementById("modalInfos");
var modalTitle = document.getElementById("infosSong");
var modalBody = document.getElementById("info");
modalTitle.innerText = artist + " - " + song;
modal.style.display = "block";
fetch(url)
.then(function (response) { return response.text(); })
.then(function (data) { modalBody.innerHTML = data; })
.catch(function () { modalBody.innerHTML = "Fehler beim Laden des Inhalts."; });
}
function closeModal() {
document.getElementById("modalInfos").style.display = "none";
}
</script>
<div id="modalInfos" role="dialog" aria-modal="true" aria-labelledby="infosSong">
<div id="modalContent">
<h2 id="infosSong"></h2>
<div id="info"></div>
<button onclick="closeModal()" aria-label="Fenster schließen">Schließen</button>
</div>
</div>
<div class="small2" align="center">
<hr class="side-hr" role="presentation" aria-hidden="true" />
<font color="#47bf1f">
Radiostatus für
<a href="https://www.spcast.eu/" target="_blank" rel="noopener">SPCast</a>.<br />
Der Quellcode kann
<a href="https://gist.github.com/scysys/68ed6fde9dc9f0a03ac6309a9d8576c0" target="_blank" rel="noopener">hier</a> eingesehen werden.
</font>
<hr class="side-hr" role="presentation" aria-hidden="true" />
</div>
'; closetable();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment