135 lines
4.1 KiB
JavaScript
135 lines
4.1 KiB
JavaScript
const audio = document.getElementById('audio');
|
|
const playBtn = document.getElementById('playBtn');
|
|
const stopBtn = document.getElementById('stopBtn');
|
|
const vol = document.getElementById('vol');
|
|
const muteBtn = document.getElementById('muteBtn');
|
|
const statusEl = document.getElementById('status');
|
|
const metaEl = document.getElementById('meta');
|
|
const streamUrlEl = document.getElementById('streamUrl');
|
|
|
|
//streamUrlEl.textContent = ICECAST_URL;
|
|
audio.src = ICECAST_URL;
|
|
audio.crossOrigin = "anonymous"; // utile si vous souhaitez analyser l'audio plus tard
|
|
|
|
let reconnectDelay = 3000;
|
|
let reconnectTimeout = null;
|
|
let userStopped = true;
|
|
|
|
function setStatus(txt){
|
|
statusEl.textContent = txt;
|
|
}
|
|
|
|
function startStream(){
|
|
userStopped = false;
|
|
setStatus("Connexion...");
|
|
audio.load();
|
|
const playPromise = audio.play();
|
|
if (playPromise !== undefined) {
|
|
playPromise.then(()=> {
|
|
setStatus("En direct");
|
|
playBtn.innerHTML = "<img src='img/pause.png' width='64'>";
|
|
}).catch(err => {
|
|
setStatus("<Erreur de lecture");
|
|
console.warn("Erreur lecture:", err);
|
|
});
|
|
}
|
|
}
|
|
|
|
function pauseStream(){
|
|
audio.pause();
|
|
setStatus("En pause");
|
|
playBtn.innerHTML = "<img src='img/play.png' width='64'>";
|
|
}
|
|
|
|
function stopStream(){
|
|
userStopped = true;
|
|
audio.pause();
|
|
audio.currentTime = 0;
|
|
setStatus("Arrêté");
|
|
playBtn.innerHTML = "<img src='img/play.png' width='64'>";
|
|
if (reconnectTimeout)
|
|
{
|
|
clearTimeout(reconnectTimeout); reconnectTimeout = null;
|
|
}
|
|
}
|
|
|
|
// Play / Pause toggle
|
|
playBtn.addEventListener('click', ()=>{
|
|
if (audio.paused){
|
|
startStream();
|
|
} else {
|
|
pauseStream();
|
|
}
|
|
});
|
|
|
|
stopBtn.addEventListener('click', stopStream);
|
|
|
|
// Volume & mute
|
|
audio.volume = parseFloat(vol.value);
|
|
vol.addEventListener('input', ()=> {
|
|
audio.volume = parseFloat(vol.value);
|
|
if (audio.volume === 0) muteBtn.textContent = "🔇"; else muteBtn.textContent = "🔊";
|
|
});
|
|
muteBtn.addEventListener('click', ()=> {
|
|
audio.muted = !audio.muted;
|
|
muteBtn.textContent = audio.muted ? "🔇" : "🔊";
|
|
});
|
|
|
|
// Reconnexion automatique en cas d'erreur réseau
|
|
audio.addEventListener('error', (e)=>{
|
|
console.warn("Audio error", e);
|
|
setStatus("Reconnexion dans 3s");
|
|
scheduleReconnect();
|
|
});
|
|
|
|
audio.addEventListener('stalled', ()=>{
|
|
setStatus("Reconnexion dans 3s");
|
|
scheduleReconnect();
|
|
});
|
|
|
|
audio.addEventListener('waiting', ()=>{
|
|
setStatus("Connexion...");
|
|
});
|
|
|
|
audio.addEventListener('playing', ()=>{
|
|
setStatus("En direct");
|
|
});
|
|
|
|
audio.addEventListener('pause', ()=>{
|
|
if (!userStopped) setStatus("En pause");
|
|
});
|
|
|
|
function scheduleReconnect(){
|
|
if (userStopped) return;
|
|
if (reconnectTimeout) clearTimeout(reconnectTimeout);
|
|
reconnectTimeout = setTimeout(()=>{
|
|
setStatus("Reconnexion...");
|
|
audio.load();
|
|
const p = audio.play();
|
|
if (p && typeof p.then === 'function') p.catch(()=>{ / ignore / });
|
|
}, reconnectDelay);
|
|
}
|
|
|
|
// Lecture automatique si l'utilisateur lance la page (après interaction requise sur certains navigateurs)
|
|
// Ne pas lancer automatiquement sans interaction pour éviter blocage; démarrer sur clic utilisateur.
|
|
|
|
// Tentative simple d'afficher metadata ICY via une requête HEAD vers le serveur Icecast (peut nécessiter CORS)
|
|
// Si votre Icecast autorise CORS, décommentez la fonction fetchMetadata() et ajustez l'URL.
|
|
|
|
// async function fetchMetadata(){
|
|
// try {
|
|
// const resp = await fetch(ICECAST_URL, { method: 'GET', mode: 'cors' });
|
|
// const txt = await resp.text();
|
|
// tentatif: chercher "icy-name" ou "<title>" dans la page de mount
|
|
// const m = txt.match(/<title>([^<]+)<\/title>/i) || txt.match(/icy-name:\s*([^\r\n]+)/i);
|
|
// if (m) metaEl.textContent = "Meta: " + m[1].trim();
|
|
// else metaEl.textContent = "Meta: —";
|
|
// } catch(err){
|
|
// metaEl.textContent = "Meta: indisponible (CORS ou non supporté)";
|
|
// }
|
|
// }
|
|
//fetchMetadata();
|
|
|
|
// Initialisation visuelle
|
|
setStatus("Arrêté");
|