// 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 reverseInterval = null; let reverseAudioLoaded = false; // 3. Variables pour vitesse let lastPosition = null; let lastTime = null; // 4. Connexion socket const socket = io(); // 5. Sauvegarder les sources const originalSrc = audio.getAttribute('src'); const reverseSrc = audio.dataset.reverseSrc || null; // 6. SOCKET – gestion de la position envoyée 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) < 15) { stopPlayback(); return; } const isReverse = speed < 0; if (isReverse) { simulateReverse(Math.abs(speed)); } else { stopReverse(); let playbackSpeed = 1 + speed * 0.0003; playbackSpeed = Math.max(0.5, Math.min(1.5, playbackSpeed)); controlPlayback(playbackSpeed); } } lastPosition = position; lastTime = now; idleTimeout = setTimeout(() => { stopPlayback(); }, 300); }); // 7. Fonctions 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; } function controlPlayback(speed) { stopReverse(); if (speed > 0) { if (!isPlaying) { audio.play(); vinyl.style.animationPlayState = 'running'; isPlaying = true; } audio.playbackRate = speed; } } function stopPlayback() { audio.pause(); vinyl.style.animationPlayState = 'paused'; isPlaying = false; } // Simule la lecture en reverse via décrémentation du currentTime function simulateReverse(speed) { const reverseSpeed = Math.min(speed * 0.01, 2); if (!reverseSrc) return; if (!reverseInterval) { reverseInterval = setInterval(() => { if (audio.currentTime > 0.05) { audio.currentTime -= reverseSpeed * 0.1; vinyl.style.animationPlayState = 'running'; } else { stopPlayback(); } }, 100); if (!reverseAudioLoaded) { const currentTime = audio.currentTime; audio.src = reverseSrc; audio.load(); audio.addEventListener('loadedmetadata', () => { const newTime = Math.min(currentTime, audio.duration - 0.1); audio.currentTime = newTime; }, { once: true }); reverseAudioLoaded = true; } isPlaying = true; audio.pause(); } } function stopReverse() { if (reverseInterval) { clearInterval(reverseInterval); reverseInterval = null; } if (reverseAudioLoaded) { const currentTime = audio.currentTime; audio.src = originalSrc; audio.load(); audio.addEventListener('loadedmetadata', () => { audio.currentTime = Math.min(currentTime, audio.duration - 0.1); }, { once: true }); reverseAudioLoaded = false; } } // 8. Événements utilisateur 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; } });