Título: Delivery of €13 million in submarine cables for the Shanhaiguan offshore project Data: 2025-09-28 10:08:08 Autor: Inteligência Against Invaders URL: https://datalake.azaeo.com/news-againstinvaders-com/07dd3cac6e2b9d2afc210bb6db0142d1/delivery-of-e13-million-in-submarine-cables-for-the-shanhaiguan-offshore-project/1505/ document.addEventListener(‘DOMContentLoaded’, function() { const buttons = document.querySelectorAll(‘.wpcode-tts-button’); if (!buttons.length || !(‘speechSynthesis’ in window)) return; const ajaxUrl = ‘https://www.redhotcyber.com/wp-admin/admin-ajax.php’; function recordAudioView(postId) { fetch(ajaxUrl, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/x-www-form-urlencoded’ }, body: ‘action=wpcode_tts_view&post_id=’ + encodeURIComponent(postId) }) .then(response => response.json()) .then(data => { if (!data.success) { console.error(‘Errore logico AJAX:’, data.data); } }) .catch(error => console.error(‘Errore di rete AJAX:’, error)); } let voices = []; let voicesLoaded = false; function loadVoices() { voices = speechSynthesis.getVoices(); if (voices.length > 0) { voicesLoaded = true; } } // Tentativo di caricamento iniziale loadVoices(); // Assicurati che le voci vengano ricaricate quando l’elenco cambia (evento cruciale) if (speechSynthesis.onvoiceschanged !== undefined) { speechSynthesis.onvoiceschanged = loadVoices; } /** * Funzione principale per avviare la sintesi vocale, con logica di retry. * @param {HTMLElement} button L’elemento del pulsante. * @param {number} attempt Contatore dei tentativi (max 2). */ function startSpeaking(button, attempt = 1) { const text = button.getAttribute(‘data-article’); const lang = button.getAttribute(‘data-lang’) || ‘it-IT’; const pref = button.getAttribute(‘data-voice-pref’) || ”; const rate = parseFloat(button.getAttribute(‘data-rate’)) || 1; const pitch = parseFloat(button.getAttribute(‘data-pitch’)) || 1; if (!text) { console.error(‘Testo mancante o vuoto.’); return; } // *** LOGICA DI RETRY PER IL CARICAMENTO DELLE VOCI *** if (!voicesLoaded && attempt === 1) { loadVoices(); // Riprova a caricare if (!voicesLoaded) { console.warn(“Voci non caricate al 1° tentativo. Riprovo in 500ms.”); button.textContent = “⏳ Caricamento vocale… (Riprovo)”; // Riprova dopo 500ms setTimeout(() => startSpeaking(button, 2), 500); return; } } else if (!voicesLoaded && attempt === 2) { console.error(“Voci non caricate al 2° tentativo. L’API TTS non è disponibile.”); button.textContent = “🔊 API vocale non disponibile ❌”; setTimeout(() => { if (button.getAttribute(‘data-speaking’) !== ‘true’) { button.textContent=”🔊 Ascolta l’articolo”; } }, 3000); return; } // *** FINE LOGICA DI RETRY *** // Cancella eventuali letture precedenti e setta lo stato speechSynthesis.cancel(); document.querySelectorAll(‘.wpcode-tts-button’).forEach(b => { if (b !== button) { b.setAttribute(‘data-speaking’, ‘false’); b.textContent = “🔊 Ascolta l’articolo”; } }); const utter = new SpeechSynthesisUtterance(text); utter.lang = lang; utter.rate = rate; utter.pitch = pitch; // Selezione voce migliorata let selectedVoice = null; if (voices.length) { const italianVoices = voices.filter(v => v.lang.startsWith(“it”)); // Priorità 1: Voci di alta qualità if (pref === ‘female’) { selectedVoice = italianVoices.find(v => v.name.includes(“Google”) && /(it-IT|Italian)/i.test(v.lang) && /(female|femmina|alessia|lucia|carla)/i.test(v.name)) || italianVoices.find(v => v.name.includes(“Microsoft”) && /(female|femmina)/i.test(v.name)); } else if (pref === ‘male’) { selectedVoice = italianVoices.find(v => v.name.includes(“Google”) && /(it-IT|Italian)/i.test(v.lang) && /(male|maschio|luca|paolo)/i.test(v.name)) || italianVoices.find(v => v.name.includes(“Microsoft”) && /(male|maschio)/i.test(v.name)); } // Priorità 2 & 3: Fallback if (!selectedVoice) { if (pref === ‘female’) selectedVoice = italianVoices.find(v => /(female|femmina|alessia|lucia|carla)/i.test(v.name)); else if (pref === ‘male’) selectedVoice = italianVoices.find(v => /(male|maschio|luca|paolo|giorgio)/i.test(v.name)); } if (!selectedVoice && italianVoices.length) selectedVoice = italianVoices[0]; } if (selectedVoice) utter.voice = selectedVoice; // Handlers utter.onstart = function(){ button.setAttribute(‘data-speaking’,’true’); button.textContent=”⏹️ Ferma la lettura”; }; utter.onend = function(){ button.setAttribute(‘data-speaking’,’false’); button.textContent=”🔊 Ascolta l’articolo”; }; utter.onerror = function(e){ console.error(‘TTS error – Codice:’, e.error, ‘dettaglio:’, e); button.setAttribute(‘data-speaking’,’false’); //button.textContent=”🔊 Errore di lettura 😞”; setTimeout(() => { if (button.getAttribute(‘data-speaking’) !== ‘true’) { button.textContent=”🔊 Ascolta l’articolo”; } }, 3000); }; speechSynthesis.speak(utter); button.setAttribute(‘data-speaking’,’true’); // Setta lo stato qui per evitare click multipli } buttons.forEach(function(button) { button.addEventListener(‘click’, function() { const speaking = button.getAttribute(‘data-speaking’) === ‘true’; // Se stiamo parlando, ferma e resetta. Non contare il click di stop. if (speaking) { speechSynthesis.cancel(); button.setAttribute(‘data-speaking’,’false’); button.textContent=”🔊 Ascolta l’articolo”; return; } // *** LOGICA DI CONTEGGIO E AVVIO *** // 1. Registra la vista (se non stiamo già parlando) const postId = button.getAttribute(‘data-post-id’); if (postId) { recordAudioView(postId); } // 2. Avvia la sintesi vocale con logica di retry startSpeaking(button); // ********************************** }); }); }); const lazyloadRunObserver = () => { const lazyloadBackgrounds = document.querySelectorAll( `.e-con.e-parent:not(.e-lazyloaded)` ); const lazyloadBackgroundObserver = new IntersectionObserver( ( entries ) => { entries.forEach( ( entry ) => { if ( entry.isIntersecting ) { let lazyloadBackground = entry.target; if( lazyloadBackground ) { lazyloadBackground.classList.add( ‘e-lazyloaded’ ); } lazyloadBackgroundObserver.unobserve( entry.target ); } }); }, { rootMargin: ‘200px 0px 200px 0px’ } ); lazyloadBackgrounds.forEach( ( lazyloadBackground ) => { lazyloadBackgroundObserver.observe( lazyloadBackground ); } ); }; const events = [ ‘DOMContentLoaded’, ‘elementor/lazyload/observe’, ]; events.forEach( ( event ) => { document.addEventListener( event, lazyloadRunObserver ); } );