// 1. Sélection des éléments 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; const rotationsPerTrack = 3; // tours complets du vinyle sur toute la durée let currentRotation = 0; // rotation en degrés actuelle du vinyle // 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; // vitesse de rotation clearTimeout(idleTimeout); // Seuil de mouvement pour arrêt if (Math.abs(speed) < 2) { stopPlayback(); return; } if (speed < 0) { // Rotation inverse : on recule la timeline audio.pause(); isPlaying = false; // recule proportionnellement à la vitesse (sensibilité ajustable) audio.currentTime = Math.max(0, audio.currentTime + speed * 0.0025); } else { // Rotation avant : jouer la piste et ajuster vitesse if (!isPlaying) { audio.play(); isPlaying = true; } // SENSIBILITÉ : le facteur diviseur est plus grand → plus doux let playbackSpeed = 0.5 + speed / 900; playbackSpeed = Math.min(Math.max(playbackSpeed, 0.5), 1.1); // plage limitée à x1 max audio.playbackRate = playbackSpeed; } } lastPosition = position; lastTime = now; // Détection d'inactivité idleTimeout = setTimeout(() => { stopPlayback(); }, 300); }); // 4. Fonctions function togglePlay() { if (isPlaying) { audio.pause(); } else { audio.play(); } isPlaying = !isPlaying; } function updateProgress() { if (!isNaN(audio.duration)) { const progressPercent = (audio.currentTime / audio.duration) * 100; progress.value = progressPercent; currentTimeEl.textContent = formatTime(audio.currentTime); durationEl.textContent = formatTime(audio.duration); updateVinylRotation(); } } 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 stopPlayback() { audio.pause(); isPlaying = false; audio.playbackRate = 1; } // La rotation est synchronisée avec la timeline audio function updateVinylRotation() { if (audio.duration && audio.currentTime >= 0) { // Rotation proportionnelle au temps courant currentRotation = (audio.currentTime / audio.duration) * 360 * rotationsPerTrack; vinyl.style.transform = `rotate(${currentRotation}deg)`; console.log('Rotation:', currentRotation); // Debug } } // 5. Événements vinyl.addEventListener('click', togglePlay); audio.addEventListener('timeupdate', updateProgress); audio.addEventListener('loadedmetadata', () => { durationEl.textContent = formatTime(audio.duration); console.log('Audio duration:', 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 { isPlaying = false; } });