// 1. Sélection des éléments du DOM const vinyl = document.getElementById('vinyl'); const audio = document.getElementById('audio'); const progress = document.getElementById('progress'); const currentTimeEl = document.getElementById('currentTime'); const durationEl = document.getElementById('duration'); const backwardBtn = document.getElementById('backward'); const forwardBtn = document.getElementById('forward'); const loopBtn = document.getElementById('loop'); // 2. Variables utiles let isPlaying = false; let isLooping = false; let idleTimeout = null; let lastPosition = null; let lastTime = null; // 3. Connexion Socket.io const socket = io(); socket.on('position', (position) => { const now = Date.now(); if (lastPosition !== null && lastTime !== null) { const deltaPos = position - lastPosition; const deltaTime = (now - lastTime) / 1000; const speed = deltaPos / deltaTime; clearTimeout(idleTimeout); if (Math.abs(speed) < 10) { stopPlayback(); return; } if (speed > 0) { controlForwardPlayback(speed); } else { controlRewind(Math.abs(speed)); } } lastPosition = position; lastTime = now; idleTimeout = setTimeout(() => { stopPlayback(); }, 300); }); // 4. Fonctions principales function controlForwardPlayback(speed) { const rate = 1 + speed * 0.0003; const playbackSpeed = Math.min(2, Math.max(0.5, rate)); vinyl.classList.remove('reverse'); vinyl.style.animationPlayState = 'running'; if (!isPlaying) { audio.play(); isPlaying = true; } audio.playbackRate = playbackSpeed; } function controlRewind(speed) { if (isPlaying) { audio.pause(); isPlaying = false; } const rewindAmount = Math.min(speed * 0.01, 1); audio.currentTime = Math.max(0, audio.currentTime - rewindAmount); vinyl.classList.add('reverse'); vinyl.style.animationPlayState = 'running'; } function stopPlayback() { if (isPlaying) { audio.pause(); isPlaying = false; } vinyl.classList.remove('reverse'); vinyl.style.animationPlayState = 'paused'; } // 5. Fonctions interface function togglePlay() { if (isPlaying) { audio.pause(); vinyl.style.animationPlayState = 'paused'; } else { audio.play(); vinyl.style.animationPlayState = 'running'; } isPlaying = !isPlaying; } function updateProgress() { const progressPercent = (audio.currentTime / audio.duration) * 100; progress.value = progressPercent; currentTimeEl.textContent = formatTime(audio.currentTime); } function formatTime(time) { const minutes = Math.floor(time / 60); const seconds = Math.floor(time % 60); return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; } function setProgress(e) { const width = progress.clientWidth; const clickX = e.offsetX; const duration = audio.duration; audio.currentTime = (clickX / width) * duration; } // 6. Événements manuels vinyl.addEventListener('click', togglePlay); audio.addEventListener('timeupdate', updateProgress); audio.addEventListener('loadedmetadata', () => { durationEl.textContent = formatTime(audio.duration); }); progress.addEventListener('click', setProgress); backwardBtn.addEventListener('click', () => { audio.currentTime = Math.max(0, audio.currentTime - 10); }); forwardBtn.addEventListener('click', () => { audio.currentTime = Math.min(audio.duration, audio.currentTime + 10); }); loopBtn.addEventListener('click', () => { isLooping = !isLooping; loopBtn.style.backgroundColor = isLooping ? 'white' : 'transparent'; loopBtn.style.color = isLooping ? '#18344b' : 'white'; }); audio.addEventListener('ended', () => { if (isLooping) { audio.currentTime = 0; audio.play(); } else { vinyl.style.animationPlayState = 'paused'; isPlaying = false; } });