From 17ea76e7869cfefbbb9e583d02f4700836e6a59a Mon Sep 17 00:00:00 2001 From: Dauren777 Date: Fri, 19 Jun 2026 07:05:15 +0000 Subject: [PATCH] Improved audio system with voice detection and test button --- index.html | 205 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 74 deletions(-) diff --git a/index.html b/index.html index 3bd24e9..2d5e31d 100644 --- a/index.html +++ b/index.html @@ -699,8 +699,12 @@ body {
ШАГ 1

Арабский алфавит

28 букв — основа чтения Корана

- -

Нажмите на букву или 🔊 чтобы услышать произношение

+
+ + +
+

Нажмите «Тест звука» чтобы проверить работает ли аудио

+
@@ -1258,7 +1262,36 @@ function renderAlphabet() { `).join(''); } -let currentAudio = null; +// Audio System - Multiple fallbacks +let voicesLoaded = false; +let arabicVoice = null; + +// Load voices +function loadVoices() { + return new Promise((resolve) => { + const voices = speechSynthesis.getVoices(); + if (voices.length > 0) { + arabicVoice = voices.find(v => v.lang.startsWith('ar')) || voices.find(v => v.lang.includes('ar')) || null; + voicesLoaded = true; + resolve(); + } else { + speechSynthesis.onvoiceschanged = () => { + const voices = speechSynthesis.getVoices(); + arabicVoice = voices.find(v => v.lang.startsWith('ar')) || voices.find(v => v.lang.includes('ar')) || null; + voicesLoaded = true; + resolve(); + }; + // Timeout fallback + setTimeout(() => { + voicesLoaded = true; + resolve(); + }, 2000); + } + }); +} + +// Initialize voices +loadVoices(); function speakLetter(idx) { const letter = alphabetData[idx].letter; @@ -1267,50 +1300,66 @@ function speakLetter(idx) { } function playArabicAudio(text, label) { - // Stop any currently playing audio - if (currentAudio) { - currentAudio.pause(); - currentAudio = null; + showToast('🔊 ' + (label || text), 'info'); + + // Try Web Speech API first + if ('speechSynthesis' in window) { + window.speechSynthesis.cancel(); + + const utterance = new SpeechSynthesisUtterance(text); + utterance.lang = 'ar-SA'; + utterance.rate = 0.6; + utterance.pitch = 1; + utterance.volume = 1; + + if (arabicVoice) { + utterance.voice = arabicVoice; + } + + utterance.onerror = (e) => { + console.error('Speech error:', e); + showToast('Ошибка воспроизведения. Попробуйте другой браузер.', 'error'); + }; + + window.speechSynthesis.speak(utterance); + } else { + showToast('Ваш браузер не поддерживает аудио', 'error'); + } +} + +function testAudio() { + const statusEl = document.getElementById('audioStatus'); + statusEl.style.display = 'block'; + statusEl.style.background = 'var(--bg-card)'; + statusEl.style.color = 'var(--text-secondary)'; + statusEl.textContent = 'Проверка аудио...'; + + // Check speech synthesis support + if (!('speechSynthesis' in window)) { + statusEl.style.background = 'rgba(239,68,68,0.1)'; + statusEl.style.color = 'var(--error)'; + statusEl.textContent = '❌ Ваш браузер не поддерживает синтез речи. Попробуйте Chrome или Edge.'; + return; } - // Use Google Translate TTS (free, public API) - const encoded = encodeURIComponent(text); - const url = `https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=${encoded}&tl=ar`; + // Check voices + const voices = speechSynthesis.getVoices(); + const arVoice = voices.find(v => v.lang.startsWith('ar')); - currentAudio = new Audio(url); - currentAudio.crossOrigin = 'anonymous'; + if (arVoice) { + statusEl.textContent = '✅ Арабский голос найден: ' + arVoice.name + '. Воспроизвожу тест...'; + } else if (voices.length > 0) { + statusEl.textContent = '⚠️ Арабский голос не найден. Используется стандартный голос. Голосов доступно: ' + voices.length; + } else { + statusEl.textContent = '⏳ Голоса загружаются... Попробуйте ещё раз через секунду.'; + } - currentAudio.onplay = () => { - showToast('🔊 ' + (label || text), 'info'); - }; - - currentAudio.onerror = () => { - // Fallback to Web Speech API - if ('speechSynthesis' in window) { - window.speechSynthesis.cancel(); - const utterance = new SpeechSynthesisUtterance(text); - utterance.lang = 'ar-SA'; - utterance.rate = 0.5; - window.speechSynthesis.speak(utterance); - } - showToast('🔊 ' + (label || text), 'info'); - }; - - currentAudio.play().catch(() => { - // Fallback to Web Speech API - if ('speechSynthesis' in window) { - window.speechSynthesis.cancel(); - const utterance = new SpeechSynthesisUtterance(text); - utterance.lang = 'ar-SA'; - utterance.rate = 0.5; - window.speechSynthesis.speak(utterance); - } - showToast('🔊 ' + (label || text), 'info'); - }); + playArabicAudio('بسم الله الرحمن الرحيم', 'Тест'); } function playAllLetters() { let index = 0; + const cards = document.querySelectorAll('.letter-card'); function playNext() { if (index < alphabetData.length) { @@ -1318,7 +1367,6 @@ function playAllLetters() { const name = alphabetData[index].name; // Highlight current letter - const cards = document.querySelectorAll('.letter-card'); cards.forEach(c => c.style.borderColor = 'var(--border)'); if (cards[index]) { cards[index].style.borderColor = 'var(--quran-gold)'; @@ -1327,29 +1375,30 @@ function playAllLetters() { showToast('Буква ' + name + ' (' + (index + 1) + '/28)', 'info'); - const encoded = encodeURIComponent(letter); - const url = `https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=${encoded}&tl=ar`; - - const audio = new Audio(url); - audio.crossOrigin = 'anonymous'; - - audio.onended = () => { + if ('speechSynthesis' in window) { + window.speechSynthesis.cancel(); + const utterance = new SpeechSynthesisUtterance(letter); + utterance.lang = 'ar-SA'; + utterance.rate = 0.6; + if (arabicVoice) utterance.voice = arabicVoice; + + utterance.onend = () => { + index++; + setTimeout(playNext, 500); + }; + + utterance.onerror = () => { + index++; + setTimeout(playNext, 500); + }; + + window.speechSynthesis.speak(utterance); + } else { index++; - setTimeout(playNext, 500); - }; - - audio.onerror = () => { - index++; - setTimeout(playNext, 500); - }; - - audio.play().catch(() => { - index++; - setTimeout(playNext, 500); - }); + setTimeout(playNext, 1000); + } } else { showToast('Все буквы прослушаны!', 'success'); - const cards = document.querySelectorAll('.letter-card'); cards.forEach(c => c.style.borderColor = 'var(--border)'); } } @@ -1650,38 +1699,46 @@ function speakFullSurah(name) { ikhlas: 'قُلْ هُوَ اللَّهُ أَحَدٌ. اللَّهُ الصَّمَدُ. لَمْ يَلِدْ وَلَمْ يُولَدْ. وَلَمْ يَكُن لَّهُ كُفُوًا أَحَدٌ' }; + if (!('speechSynthesis' in window)) { + showToast('Ваш браузер не поддерживает аудио', 'error'); + return; + } + const text = surahs[name]; const parts = text.split('. '); let index = 0; - function playNext() { + function speakNext() { if (index < parts.length) { - const encoded = encodeURIComponent(parts[index]); - const url = `https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=${encoded}&tl=ar`; + window.speechSynthesis.cancel(); + const utterance = new SpeechSynthesisUtterance(parts[index]); + utterance.lang = 'ar-SA'; + utterance.rate = 0.6; + utterance.pitch = 1; + utterance.volume = 1; - const audio = new Audio(url); - audio.crossOrigin = 'anonymous'; + if (arabicVoice) { + utterance.voice = arabicVoice; + } - audio.onended = () => { + utterance.onend = () => { index++; - setTimeout(playNext, 400); + setTimeout(speakNext, 400); }; - audio.onerror = () => { + utterance.onerror = () => { index++; - setTimeout(playNext, 400); + setTimeout(speakNext, 400); }; - audio.play().catch(() => { - index++; - setTimeout(playNext, 400); - }); + window.speechSynthesis.speak(utterance); + showToast('Аят ' + (index + 1) + '/' + parts.length, 'info'); } else { showToast('Сура прослушана!', 'success'); } } - playNext(); + speakNext(); } function markSurahPracticed(id) {