loop/node-server/assets/script.js
2025-06-07 13:20:10 +02:00

196 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}
});