- Upload de GIF/MP4/WebM comme animations de compte a rebours - Checkboxes pour activer/desactiver chaque animation (CSS + custom) - Si plusieurs actives, tirage aleatoire a chaque photo - Preview dans le backoffice avec tirage aleatoire - Suppression des animations custom importees - Les animations custom se jouent en plein ecran avant la capture Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
222 lines
5.6 KiB
JavaScript
222 lines
5.6 KiB
JavaScript
/* Module capture photo - Preview live, compte a rebours, declenchement */
|
|
|
|
let previewActif = false;
|
|
let previewInterval = null;
|
|
|
|
const EMOJI_CAR = { 3: '🤪', 2: '😱', 1: '🔥' };
|
|
|
|
// --- Preview live ---
|
|
|
|
function lancerPreview() {
|
|
if (previewActif) return;
|
|
previewActif = true;
|
|
|
|
previewInterval = setInterval(() => {
|
|
if (previewActif) wsEnvoyer({ type: 'preview' });
|
|
}, 100);
|
|
}
|
|
|
|
function arreterPreview() {
|
|
previewActif = false;
|
|
if (previewInterval) {
|
|
clearInterval(previewInterval);
|
|
previewInterval = null;
|
|
}
|
|
}
|
|
|
|
wsOnMessage('preview', (msg) => {
|
|
if (!previewActif) return;
|
|
const img = document.getElementById('img-preview');
|
|
if (img) img.src = msg.image;
|
|
});
|
|
|
|
// --- Capture ---
|
|
|
|
async function lancerCapture() {
|
|
photosSession = [];
|
|
lancerPreview();
|
|
majCompteurAccueil();
|
|
|
|
const nbPhotos = getNombrePhotos();
|
|
const compteurEl = document.getElementById('capture-compteur');
|
|
|
|
for (let i = 0; i < nbPhotos; i++) {
|
|
if (nbPhotos > 1) {
|
|
compteurEl.textContent = `Photo ${i + 1} / ${nbPhotos}`;
|
|
}
|
|
|
|
await compteARebours();
|
|
afficherFlash();
|
|
|
|
arreterPreview();
|
|
const resultat = await apiPost('/api/capturer');
|
|
|
|
if (resultat.erreur) {
|
|
// Limite atteinte ou erreur
|
|
allerA('accueil');
|
|
return;
|
|
}
|
|
|
|
if (resultat.nom) {
|
|
photosSession.push(resultat.nom);
|
|
}
|
|
|
|
if (i < nbPhotos - 1) {
|
|
lancerPreview();
|
|
await pause(500);
|
|
}
|
|
}
|
|
|
|
await traiterCapture();
|
|
}
|
|
|
|
function getNombrePhotos() {
|
|
if (modeActuel === 'simple') return 1;
|
|
if (modeActuel === 'multi') return config.multi_shot?.nombre_photos || 3;
|
|
return 1;
|
|
}
|
|
|
|
function choisirAnimationAleatoire() {
|
|
// Construire la liste de toutes les animations actives (CSS + custom)
|
|
const cssActives = config.camera?.animations_css_actives || ['classique'];
|
|
const customActives = config.animations_custom?.actives || [];
|
|
|
|
const pool = [
|
|
...cssActives.map(id => ({ type: 'css', id })),
|
|
...customActives.map(nom => ({ type: 'custom', nom })),
|
|
];
|
|
|
|
if (pool.length === 0) return { type: 'css', id: 'classique' };
|
|
return pool[Math.floor(Math.random() * pool.length)];
|
|
}
|
|
|
|
async function compteARebours() {
|
|
const conteneur = document.getElementById('compte-a-rebours');
|
|
const chiffre = document.getElementById('chiffre-car');
|
|
const duree = config.camera?.compte_a_rebours || 3;
|
|
|
|
// Choisir une animation au hasard parmi les actives
|
|
const anim = choisirAnimationAleatoire();
|
|
|
|
if (anim.type === 'custom') {
|
|
// Jouer une video/gif en plein ecran
|
|
await jouerAnimationCustom(anim.nom, duree);
|
|
} else {
|
|
// Animation CSS classique
|
|
conteneur.classList.remove('cache');
|
|
|
|
for (let i = duree; i > 0; i--) {
|
|
if (anim.id === 'emoji') {
|
|
chiffre.textContent = EMOJI_CAR[i] || i;
|
|
} else {
|
|
chiffre.textContent = i;
|
|
}
|
|
|
|
chiffre.className = 'anim-chiffre';
|
|
void chiffre.offsetWidth;
|
|
chiffre.classList.add('anim-' + anim.id);
|
|
|
|
await pause(1000);
|
|
}
|
|
|
|
conteneur.classList.add('cache');
|
|
}
|
|
}
|
|
|
|
async function jouerAnimationCustom(nom, duree) {
|
|
// Creer un overlay plein ecran pour la video/gif
|
|
const overlay = document.createElement('div');
|
|
overlay.className = 'video-countdown-overlay';
|
|
|
|
const ext = nom.split('.').pop().toLowerCase();
|
|
|
|
if (ext === 'gif') {
|
|
const img = document.createElement('img');
|
|
img.src = `/assets/animations/${nom}`;
|
|
overlay.appendChild(img);
|
|
document.body.appendChild(overlay);
|
|
await pause(duree * 1000);
|
|
} else {
|
|
const video = document.createElement('video');
|
|
video.src = `/assets/animations/${nom}`;
|
|
video.muted = true;
|
|
video.playsInline = true;
|
|
video.autoplay = true;
|
|
overlay.appendChild(video);
|
|
document.body.appendChild(overlay);
|
|
|
|
// Attendre la fin de la video ou le timeout
|
|
await Promise.race([
|
|
new Promise(resolve => { video.onended = resolve; }),
|
|
pause(duree * 1000 + 2000),
|
|
]);
|
|
}
|
|
|
|
overlay.remove();
|
|
}
|
|
|
|
function afficherFlash() {
|
|
const flash = document.getElementById('flash-blanc');
|
|
flash.classList.remove('cache');
|
|
flash.style.animation = 'none';
|
|
flash.offsetHeight;
|
|
flash.style.animation = 'flash 0.3s ease-out forwards';
|
|
setTimeout(() => flash.classList.add('cache'), 400);
|
|
}
|
|
|
|
async function traiterCapture() {
|
|
if (photosSession.length === 0) {
|
|
allerA('accueil');
|
|
return;
|
|
}
|
|
|
|
if (modeActuel === 'multi') {
|
|
const mode = config.multi_shot?.mode || 'strip';
|
|
let resultat;
|
|
if (mode === 'strip') {
|
|
resultat = await apiPost('/api/strip', { photos: photosSession });
|
|
} else {
|
|
resultat = await apiPost('/api/collage', { photos: photosSession });
|
|
}
|
|
if (resultat.nom) {
|
|
photoFinale = resultat.nom;
|
|
afficherPreviewPhoto('/data/exports/' + resultat.nom);
|
|
}
|
|
} else {
|
|
photoFinale = photosSession[0];
|
|
afficherPreviewPhoto('/data/photos/' + photosSession[0]);
|
|
}
|
|
|
|
allerA('preview');
|
|
}
|
|
|
|
function afficherPreviewPhoto(chemin) {
|
|
document.getElementById('photo-resultat').src = chemin;
|
|
document.getElementById('photo-partage').src = chemin;
|
|
|
|
if (modeActuel === 'simple' && config.fonctionnalites?.filtres) {
|
|
chargerFiltres();
|
|
}
|
|
if (config.fonctionnalites?.overlays) {
|
|
chargerOverlays();
|
|
}
|
|
}
|
|
|
|
// --- Compteur accueil ---
|
|
|
|
async function majCompteurAccueil() {
|
|
const etat = await apiGet('/api/compteur');
|
|
const el = document.getElementById('compteur-accueil');
|
|
if (etat.actif) {
|
|
el.classList.remove('cache');
|
|
document.getElementById('compteur-restant').textContent = etat.restantes;
|
|
document.getElementById('compteur-limite').textContent = etat.limite;
|
|
} else {
|
|
el.classList.add('cache');
|
|
}
|
|
}
|
|
|
|
function pause(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|