| document.addEventListener("DOMContentLoaded", function () { |
| const menuButton = document.querySelector(".menu-button"); |
| const sidebar = document.querySelector(".sidebar"); |
| |
|
|
| menuButton.addEventListener("click", function () { |
| sidebar.classList.toggle("shown"); |
| }); |
| }); |
|
|
|
|
| |
| fetch('https://thevera-botveradb.hf.space/get_chapters') |
| .then(response => response.json()) |
| .then(responseData => { |
| if (responseData.success) { |
| initializePage(responseData.data); |
| } else { |
| console.error('Error loading data:', responseData.message); |
| } |
| }) |
| .catch(error => console.error('Error loading data:', error)); |
|
|
|
|
| function initializePage(data) { |
| const shastraList = document.getElementById('shastraList'); |
| if (!shastraList) { |
| console.error("Element with ID 'shastraList' not found."); |
| return; |
| } |
|
|
| |
| Object.keys(data).forEach((collection) => { |
| const mainGroupItem = document.createElement('li'); |
| mainGroupItem.textContent = collection; |
| mainGroupItem.classList.add('main-group'); |
|
|
| |
| const itemList = document.createElement('ul'); |
| itemList.classList.add('nested-list'); |
| itemList.style.display = 'none'; |
|
|
| |
| data[collection].forEach((item) => { |
| if (item.skandaTitle) { |
| |
| const skandaGroup = document.createElement('li'); |
| skandaGroup.textContent = item.skandaTitle; |
| skandaGroup.classList.add('skanda-group'); |
|
|
| const skandaChapterList = document.createElement('ul'); |
| skandaChapterList.classList.add('nested-list'); |
| skandaChapterList.style.display = 'none'; |
|
|
| item.chapters.forEach((chapter) => { |
| const chapterItem = document.createElement('li'); |
| chapterItem.textContent = chapter.chapterTitle; |
| chapterItem.classList.add('chapter-item'); |
| chapterItem.addEventListener('click', (event) => { |
| event.stopPropagation(); |
| loadChapter(chapter); |
| }); |
| skandaChapterList.appendChild(chapterItem); |
| }); |
| skandaGroup.addEventListener('click', (event) => { |
| event.stopPropagation(); |
| skandaChapterList.style.display = skandaChapterList.style.display === 'none' ? 'block' : 'none'; |
| }); |
| |
| skandaGroup.appendChild(skandaChapterList); |
| itemList.appendChild(skandaGroup); |
| } else { |
| |
| const chapterItem = document.createElement('li'); |
| chapterItem.textContent = item.chapterTitle; |
| chapterItem.classList.add('chapter-item'); |
| chapterItem.addEventListener('click', (event) => { |
| event.stopPropagation(); |
| loadChapter(item); |
| }); |
| itemList.appendChild(chapterItem); |
| } |
| }); |
|
|
| mainGroupItem.addEventListener('click', () => { |
| itemList.style.display = itemList.style.display === 'none' ? 'block' : 'none'; |
| }); |
| mainGroupItem.appendChild(itemList); |
| shastraList.appendChild(mainGroupItem); |
| }); |
| } |
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| function loadChapter(chapter) { |
| const chapterTitle = document.getElementById('chapterTitle'); |
| const slokeContent = document.getElementById('slokeContent'); |
| const videoPlayer = document.getElementById('videoPlayer'); |
| const transcriptElement = document.getElementById('transcript'); |
|
|
| if (!chapterTitle || !slokeContent || !videoPlayer || !transcriptElement) { |
| console.error("One or more elements with IDs 'slokeContent', 'videoPlayer', or 'transcript' not found."); |
| return; |
| } |
|
|
| |
| chapterTitle.textContent = chapter.about || 'Select a chapter to view details.'; |
| |
| |
| slokeContent.innerHTML = ''; |
| videoPlayer.src = ''; |
| transcriptElement.textContent = ''; |
|
|
| |
| const chapterTitleElement = document.createElement('h2'); |
| chapterTitleElement.textContent = chapter.chapterTitle; |
| slokeContent.appendChild(chapterTitleElement); |
|
|
| |
| const slokesArray = chapter.slokes.split('\n'); |
| slokesArray.forEach((slokeText) => { |
| const slokeElement = document.createElement('p'); |
| slokeElement.classList.add('sloke-text'); |
| slokeElement.innerHTML = slokeText.replace(/श्लोक \d+:/g, '<strong>$&</strong>'); |
|
|
| const speakIcon = createSpeakIcon(slokeText); |
| slokeElement.appendChild(speakIcon); |
| slokeContent.appendChild(slokeElement); |
| }); |
|
|
| |
| videoPlayer.src = chapter.video; |
|
|
| |
| transcriptElement.textContent = chapter.transcript; |
|
|
| |
| setupPlayAllButton(slokesArray); |
| } |
|
|
| function createSpeakIcon(slokeText) { |
| const speakIcon = document.createElement('i'); |
| speakIcon.classList.add('fas', 'fa-volume-up', 'speak-icon'); |
| speakIcon.setAttribute('title', 'Speak Slok'); |
| speakIcon.addEventListener('click', () => { |
| console.log(`Speaking: ${slokeText}`); |
| playTTS(slokeText); |
| }); |
| return speakIcon; |
| } |
|
|
| function cleanSlokText(text) { |
| |
| return text.replace(/श्लोक \d+: /g, '').replace(/ \d+$/g, ''); |
| } |
|
|
| let currentSlokeIndex = 0; |
| const audioPlayer = document.getElementById('audioPlayer'); |
|
|
| |
| function setupPlayAllButton(slokesArray) { |
| const playAllButton = document.getElementById('playAllButton'); |
| |
| playAllButton.onclick = async () => { |
| currentSlokeIndex = 0; |
| playNextSloke(slokesArray); |
| }; |
| } |
|
|
| |
| async function playNextSloke(slokesArray) { |
| if (currentSlokeIndex >= slokesArray.length) { |
| return; |
| } |
|
|
| |
| const slokeText = cleanSlokText(slokesArray[currentSlokeIndex]); |
| highlightCurrentSloke(currentSlokeIndex); |
|
|
| |
| playTTS(slokeText).then(() => { |
| |
| currentSlokeIndex++; |
| playNextSloke(slokesArray); |
| }); |
| } |
|
|
| |
| function highlightCurrentSloke(index) { |
| const slokeElements = document.querySelectorAll('.sloke-text'); |
|
|
| |
| slokeElements.forEach(el => el.classList.remove('highlight')); |
|
|
| |
| const currentSloke = slokeElements[index]; |
| if (currentSloke) { |
| currentSloke.classList.add('highlight'); |
| currentSloke.scrollIntoView({ behavior: "smooth", block: "center" }); |
| } |
| } |
|
|
| let currentAudio; |
| let isPlaying = false; |
| let currentUtterance; |
|
|
| async function playTTS(text) { |
| console.log('Speaking mantra'); |
| text = cleanSlokText(text); |
| |
| if (!text || text.trim() === '') { |
| console.error('No text provided'); |
| return; |
| } |
|
|
| const synth = window.speechSynthesis; |
| let voices = synth.getVoices(); |
|
|
| if (voices.length === 0) { |
| voices = await new Promise(resolve => { |
| const id = setInterval(() => { |
| voices = synth.getVoices(); |
| if (voices.length > 0) { |
| clearInterval(id); |
| resolve(voices); |
| } |
| }, 10); |
| }); |
| } |
|
|
| const sanskritVoice = voices.find(voice => voice.lang === 'sa-IN'); |
| |
| if (sanskritVoice) { |
| |
| currentUtterance = new SpeechSynthesisUtterance(text); |
| currentUtterance.voice = sanskritVoice; |
| currentUtterance.lang = 'sa-IN'; |
| currentUtterance.rate = 0.8; |
| currentUtterance.pitch = 1.0; |
|
|
| synth.cancel(); |
|
|
| return new Promise((resolve, reject) => { |
| currentUtterance.onend = () => { |
| isPlaying = false; |
| resolve(); |
| }; |
| currentUtterance.onerror = (event) => { |
| console.error('TTS playback error:', event); |
| reject(event); |
| }; |
|
|
| synth.speak(currentUtterance); |
| isPlaying = true; |
| }); |
| } else { |
| |
| console.warn('sa-IN voice not available, using server.'); |
|
|
| const serverUrl = "https://thevera-botveradb.hf.space/generate_sanskrit_audio"; |
| try { |
| const response = await fetch(serverUrl, { |
| method: "POST", |
| headers: { "Content-Type": "application/json" }, |
| body: JSON.stringify({ text }) |
| }); |
|
|
| if (!response.ok) { |
| throw new Error('Failed to fetch audio from server'); |
| } |
|
|
| const audioBlob = await response.blob(); |
| const audioUrl = URL.createObjectURL(audioBlob); |
|
|
| return new Promise((resolve, reject) => { |
| |
| const audioPlayer = document.getElementById('audioPlayer'); |
| audioPlayer.src = audioUrl; |
| audioPlayer.play(); |
|
|
| |
| audioPlayer.onended = () => { |
| isPlaying = false; |
| URL.revokeObjectURL(audioUrl); |
| resolve(); |
| }; |
|
|
| |
| audioPlayer.onerror = (event) => { |
| console.error('Server-based TTS playback error:', event); |
| reject(event); |
| }; |
|
|
| isPlaying = true; |
| }); |
| } catch (error) { |
| console.error('Error calling server:', error); |
| throw error; |
| } |
| } |
| } |
|
|
|
|
|
|