151 lines
4.1 KiB
JavaScript
151 lines
4.1 KiB
JavaScript
// 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) < 5) {
|
|
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;
|
|
}
|
|
let playbackSpeed = 0.5 + speed / 400;
|
|
playbackSpeed = Math.min(Math.max(playbackSpeed, 0.5), 1.5);
|
|
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;
|
|
}
|
|
});
|