Файловый менеджер - Редактировать - /home/gqdcvggs/imators.systems/train/index.php
Назад
<?php $trains = json_decode(file_get_contents('stock.json'), true)['trains']; ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Départs des Trains</title> <script src="https://cdn.tailwindcss.com"></script> </head> <body class="bg-black text-white"> <!-- Affichage normal --> <div class="container mx-auto p-4"> <header class="flex justify-between items-center mb-8"> <h1 class="text-2xl font-light">Départs</h1> <div class="text-right"> <div id="clock" class="text-4xl font-light"></div> <div id="date" class="text-gray-500 text-sm"></div> </div> </header> <div id="trains" class="space-y-3"></div> </div> <!-- Animation plein écran pour l'annonce --> <div id="announcement" class="fixed inset-0 bg-black/95 backdrop-blur-sm transform translate-y-full transition-all duration-700 flex items-center justify-center"> <div class="text-center p-8 scale-90 opacity-0 transition-all duration-700" id="announcement-content"> <div class="text-blue-500"> <div class="text-2xl mb-2">VOIE</div> <div class="text-8xl font-light mb-8" id="announcement-voie"></div> </div> <div class="text-5xl font-light mb-4" id="announcement-train"></div> <div class="text-3xl font-light mb-6" id="announcement-destination"></div> <div class="text-2xl font-light text-gray-400" id="announcement-time"></div> </div> </div> <!-- Audio --> <audio id="jingle" src="jingle.mp3" preload="auto"></audio> <audio id="tts-audio" preload="auto"></audio> <script> let lastAnnouncedIds = new Set(); // Fonction pour générer l'audio TTS via OpenAI async function generateTTS(text) { try { const response = await fetch('tts.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ text: text }) }); if (!response.ok) { throw new Error('Erreur lors de la génération TTS'); } const data = await response.json(); if (data.success && data.audio_url) { const audio = document.getElementById('tts-audio'); audio.src = data.audio_url; return audio; } else { throw new Error(data.message || 'Erreur inconnue'); } } catch (error) { console.error('Erreur TTS:', error); return null; } } // Fonction pour jouer l'audio TTS avec promesse function playTTS(text) { return new Promise(async (resolve) => { try { const audio = await generateTTS(text); if (!audio) { console.error('Impossible de générer l\'audio'); resolve(); return; } audio.onended = () => resolve(); audio.onerror = () => { console.error('Erreur de lecture audio'); resolve(); }; audio.play(); } catch (e) { console.error('Erreur lors de la lecture TTS:', e); resolve(); } }); } async function showAnnouncement(train, timeLeft) { const announcement = document.getElementById('announcement'); const content = document.getElementById('announcement-content'); const jingle = document.getElementById('jingle'); // Prépare l'annonce document.getElementById('announcement-voie').textContent = train.platform; document.getElementById('announcement-train').textContent = `${train.type} ${train.line}`; document.getElementById('announcement-destination').textContent = train.destination; document.getElementById('announcement-time').textContent = new Date(train.arrival).toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit'}); // Montre l'annonce avec animation announcement.classList.remove('translate-y-full'); // Animation du contenu setTimeout(() => { content.classList.remove('scale-90', 'opacity-0'); }, 100); try { // 1. Jouer le jingle jingle.currentTime = 0; await new Promise((resolve) => { jingle.onended = resolve; jingle.play(); }); // 2. Petite pause après le jingle await new Promise(resolve => setTimeout(resolve, 500)); // 3. Faire l'annonce vocale avec OpenAI TTS const status = timeLeft <= 0 ? "entre en gare" : "arrive dans quelques instants"; const message = `Le ${train.type} ${train.line} à destination de ${train.destination}, voie ${train.platform}, ${status}.`; console.log('Message vocal:', message); await playTTS(message); } catch (e) { console.error('Erreur audio:', e); } // Cache l'annonce après la fin de la voix + 2 secondes setTimeout(() => { content.classList.add('scale-90', 'opacity-0'); setTimeout(() => { announcement.classList.add('translate-y-full'); }, 700); }, 10000); } function updateClock() { const now = new Date(); document.getElementById('clock').textContent = now.toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit'}); document.getElementById('date').textContent = now.toLocaleDateString('fr-FR', {weekday: 'long', day: 'numeric', month: 'long'}); } function updateTrains() { fetch('stock.json?' + Date.now()) .then(response => response.json()) .then(data => { const trains = data.trains; const trainsDiv = document.getElementById('trains'); const now = new Date(); trainsDiv.innerHTML = ''; trains.forEach(train => { const arrival = new Date(train.arrival); const timeLeft = (arrival - now) / 1000; // Ne pas afficher les trains partis depuis plus de 20 secondes if (timeLeft < -20) return; // Annonce 30 secondes avant l'arrivée if (timeLeft <= 30 && timeLeft > 29 && !lastAnnouncedIds.has(train.id)) { lastAnnouncedIds.add(train.id); showAnnouncement(train, timeLeft); } // Création de la carte du train const div = document.createElement('div'); div.className = `bg-gray-900 p-4 rounded-lg flex items-center justify-between ${timeLeft <= 30 ? 'border-l-4 border-yellow-500' : ''} ${timeLeft <= 0 ? 'border-l-4 border-green-500' : ''} ${timeLeft < -10 ? 'opacity-50' : ''}`; const timeDisplay = getTimeDisplay(timeLeft); div.innerHTML = ` <div class="flex items-center gap-8"> <div class="w-24"> <div class="text-2xl font-light">${arrival.toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit'})}</div> <div class="text-sm text-gray-500">${timeDisplay}</div> </div> <div> <div class="flex items-center gap-3"> <div class="px-3 py-1 bg-blue-900 rounded text-sm">${train.type} ${train.line}</div> <div class="font-light">${train.destination}</div> </div> <div class="text-sm text-gray-500 mt-1"> Voie ${train.platform} </div> </div> </div> <div class="flex items-center gap-2"> <div class="w-2 h-2 rounded-full ${train.status === 'on-time' ? 'bg-green-500' : 'bg-yellow-500'}"></div> <span class="text-sm text-gray-500">${train.status === 'on-time' ? 'À l\'heure' : 'Retardé'}</span> </div> `; trainsDiv.appendChild(div); }); }); } function getTimeDisplay(seconds) { if (seconds < 0) return "À quai"; if (seconds < 60) return Math.ceil(seconds) + "s"; if (seconds < 3600) return Math.ceil(seconds / 60) + " min"; const hours = Math.floor(seconds / 3600); const mins = Math.ceil((seconds % 3600) / 60); return `${hours}h${mins.toString().padStart(2, '0')}`; } // Activation du son au premier clic document.addEventListener('click', () => { document.getElementById('jingle').play().catch(() => {}); }); // Initialisation et mises à jour updateClock(); updateTrains(); setInterval(updateClock, 1000); setInterval(updateTrains, 1000); </script> </body> </html>
| ver. 1.6 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка