Added ResponsiveVoice.js for Arabic audio pronunciation

This commit is contained in:
Dauren777 2026-06-19 07:12:20 +00:00
parent 17ea76e786
commit 947fc39a17

View File

@ -6,6 +6,7 @@
<title>QuranReader — Читай Коран на арабском</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=Noto+Naskh+Arabic:wght@400;600;700&family=Amiri:wght@400;700&display=swap" rel="stylesheet">
<script src="https://code.responsivevoice.org/responsivevoice.js?key=FREE"></script>
<style>
[data-theme="light"] {
--ink: #0F1218; --bg: #FFFFFF; --bg-card: #F2F4F7; --bg-card-hover: #E8FCFF;
@ -1262,31 +1263,83 @@ function renderAlphabet() {
`).join('');
}
// Audio System - Multiple fallbacks
let voicesLoaded = false;
let arabicVoice = null;
// Audio System using ResponsiveVoice
function speakLetter(idx) {
const letter = alphabetData[idx].letter;
const name = alphabetData[idx].name;
playArabicAudio(letter, name);
}
// 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();
function playArabicAudio(text, label) {
showToast('🔊 ' + (label || text), 'info');
if (typeof responsiveVoice !== 'undefined' && responsiveVoice.voiceSupport()) {
responsiveVoice.speak(text, "Arabic Male", {
rate: 0.8,
pitch: 1,
volume: 1
});
} 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 = 'Проверка аудио...';
if (typeof responsiveVoice !== 'undefined' && responsiveVoice.voiceSupport()) {
statusEl.style.background = 'rgba(34,197,94,0.1)';
statusEl.style.color = 'var(--success)';
statusEl.textContent = '✅ Аудио поддерживается! Воспроизвожу тест...';
responsiveVoice.speak("بسم الله", "Arabic Male", {rate: 0.8});
} else {
statusEl.style.background = 'rgba(239,68,68,0.1)';
statusEl.style.color = 'var(--error)';
statusEl.textContent = '❌ Аудио не загружено. Обновите страницу и попробуйте снова.';
}
}
function playAllLetters() {
let index = 0;
const cards = document.querySelectorAll('.letter-card');
function playNext() {
if (index < alphabetData.length) {
const letter = alphabetData[index].letter;
const name = alphabetData[index].name;
cards.forEach(c => c.style.borderColor = 'var(--border)');
if (cards[index]) {
cards[index].style.borderColor = 'var(--quran-gold)';
cards[index].scrollIntoView({ behavior: 'smooth', block: 'center' });
}
showToast('Буква ' + name + ' (' + (index + 1) + '/28)', 'info');
if (typeof responsiveVoice !== 'undefined' && responsiveVoice.voiceSupport()) {
responsiveVoice.speak(letter, "Arabic Male", {
rate: 0.8,
onend: () => {
index++;
setTimeout(playNext, 500);
}
});
} else {
index++;
setTimeout(playNext, 1000);
}
} 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);
showToast('Все буквы прослушаны!', 'success');
cards.forEach(c => c.style.borderColor = 'var(--border)');
}
}
playNext();
}
});
}
@ -1699,8 +1752,8 @@ function speakFullSurah(name) {
ikhlas: 'قُلْ هُوَ اللَّهُ أَحَدٌ. اللَّهُ الصَّمَدُ. لَمْ يَلِدْ وَلَمْ يُولَدْ. وَلَمْ يَكُن لَّهُ كُفُوًا أَحَدٌ'
};
if (!('speechSynthesis' in window)) {
showToast('Ваш браузер не поддерживает аудио', 'error');
if (typeof responsiveVoice === 'undefined' || !responsiveVoice.voiceSupport()) {
showToast('Аудио не поддерживается', 'error');
return;
}
@ -1710,29 +1763,14 @@ function speakFullSurah(name) {
function speakNext() {
if (index < parts.length) {
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(parts[index]);
utterance.lang = 'ar-SA';
utterance.rate = 0.6;
utterance.pitch = 1;
utterance.volume = 1;
if (arabicVoice) {
utterance.voice = arabicVoice;
}
utterance.onend = () => {
index++;
setTimeout(speakNext, 400);
};
utterance.onerror = () => {
index++;
setTimeout(speakNext, 400);
};
window.speechSynthesis.speak(utterance);
showToast('Аят ' + (index + 1) + '/' + parts.length, 'info');
responsiveVoice.speak(parts[index], "Arabic Male", {
rate: 0.8,
onend: () => {
index++;
setTimeout(speakNext, 400);
}
});
} else {
showToast('Сура прослушана!', 'success');
}