ras / script.js
bhagvat's picture
Update script.js
eebcb8a verified
Raw
History Blame Contribute Delete
56.1 kB
document.addEventListener("DOMContentLoaded", function () {
const lastChapter = localStorage.getItem("lastAccessedChapter");
console.log("Last Save Chapter: "+ lastChapter)
if (lastChapter) {
const chapter = JSON.parse(lastChapter);
loadChapter({ chapterTitle: chapter.chapterTitle }); // Auto-load last accessed chapter
}
const loginLink = document.getElementById('login-link'); // Login button container
const userInfoDiv = document.getElementById('user-info'); // User info container (after login)
const logoutButton = document.getElementById('logout-button'); // Logout button
const userNameDisplay = document.getElementById('user-name'); // Where to display the username
const userButton = document.getElementById('user-button'); // User initials button
const token = localStorage.getItem('authToken'); // Get token from localStorage
const menuButton = document.getElementById("menuButton");
const sidebar = document.querySelector(".sidebar");
const overlay = document.querySelector(".overlay");
const content = document.querySelector("#content"); // Main content area
const nextBtn = document.getElementById('nextChapterButton');
if (nextBtn) nextBtn.addEventListener('click', loadNextChapter);
const loadingContainer = document.getElementById('loading-container'); // Loading container
const loadingBar = document.getElementById('loading-bar'); // Loading bar
const loadingText = document.getElementById('loading-text'); // Loading text
// Show loading bar when the page starts
loadingContainer.style.display = 'flex';
// Fetch and initialize data from MongoDB
fetch('https://thevera-botveradb.hf.space/get_chapter_titles')
// 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);
}
// Hide the loading bar after data is loaded
loadingContainer.style.display = 'none';
})
.catch(error => {
console.error('Error loading data:', error);
// Hide the loading bar in case of error
loadingContainer.style.display = 'none';
});
if (token) {
// Check token validity with backend
fetch('https://thevera-botveradb.hf.space/validate_token', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(data => {
if (data.message === "Token is valid!") {
// Token is valid, decode it to get user info
const userObject = jwt_decode(token); // Decode the token to get user info
const email = userObject.email; // Assuming the email is stored in the token
const username = email.split('@')[0]; // Extract username (first part of email)
// Update UI with user's info
userNameDisplay.innerText = username; // Display first part of email as username
userInfoDiv.style.display = 'block'; // Show user info section
// Change user button to show user's initials
const userInitials = username.charAt(0).toUpperCase(); // Get first letter of username
userButton.innerHTML = `<div class="user-initial">${userInitials}</div>`; // Display initials
// Show the logout button and hide the login link
logoutButton.style.display = 'inline';
loginLink.style.display = 'none';
// **Update UI for Mobile**
document.getElementById('user-info-mobile').style.display = 'block';
document.getElementById('user-initials').innerText = userInitials;
document.getElementById('user-name-mobile').innerText = email.split('@')[0];
document.getElementById('logout-button-mobile').style.display = 'block';
document.getElementById('loginButton').style.display = 'none';
} else {
// Token is invalid, clear invalid token
localStorage.removeItem('authToken');
console.log('Invalid token, user not logged in.');
loginLink.style.display = 'inline'; // Show login link
}
})
.catch(error => {
console.error('Error:', error);
// Handle the error (e.g., network issues)
localStorage.removeItem('authToken'); // Clear token in case of error
loginLink.style.display = 'inline'; // Show login link
});
} else {
// No token found, show login link
console.log('No token found, user not logged in.');
loginLink.style.display = 'inline';
}
// Logout functionality
if (logoutButton) {
logoutButton.onclick = function() {
localStorage.removeItem('authToken'); // Clear token
window.location.reload(); // Refresh page to update UI
};
}
// Optional: If you want to show the dropdown when clicking on the user initials button
if (userButton) {
userButton.addEventListener('click', () => {
const userDropdown = document.getElementById('user-dropdown');
userDropdown.style.display = userDropdown.style.display === 'block' ? 'none' : 'block';
});
}
// Sidebar toggle for mobile and desktop
menuButton.addEventListener("click", function () {
if (sidebar && overlay && content) {
sidebar.classList.toggle("shown");
overlay.classList.toggle("active");
// Adjust content margin when sidebar is visible
if (sidebar.classList.contains("shown")) {
content.style.marginLeft = "250px"; // Sidebar width
} else {
content.style.marginLeft = "0";
}
}
});
// Close sidebar on overlay click for mobile view
overlay.addEventListener("click", function () {
if (sidebar && overlay && content) {
sidebar.classList.remove("shown");
overlay.classList.remove("active");
content.style.marginLeft = "0"; // Reset content margin
}
});
});
// Mobile Menu Buttion js code
document.addEventListener("DOMContentLoaded", function () {
const menuButton = document.getElementById("menuButton");
const mobileMenu = document.getElementById("mobileMenu");
if (menuButton && mobileMenu) {
menuButton.addEventListener("click", function (event) {
event.stopPropagation(); // Prevents immediate close
mobileMenu.classList.toggle("show"); // Toggle menu visibility
});
// Close menu when clicking outside
document.addEventListener("click", function (event) {
if (!mobileMenu.contains(event.target) && !menuButton.contains(event.target)) {
mobileMenu.classList.remove("show");
}
});
} else {
console.error("Menu button or mobile menu not found in the DOM.");
}
});
// ===== Voice Manager (persisted TTS settings) =====
// const TTS_STORE_KEY = 'ttsSettings_v1';
// const defaultTTS = { voiceURI: null, rate: 0.9, pitch: 0.9 };
// function getTTSSettings(){
// try { return { ...defaultTTS, ...(JSON.parse(localStorage.getItem(TTS_STORE_KEY))||{}) }; }
// catch { return { ...defaultTTS }; }
// }
// function saveTTSSettings(patch){
// const now = { ...getTTSSettings(), ...(patch||{}) };
// localStorage.setItem(TTS_STORE_KEY, JSON.stringify(now));
// return now;
// }
// function waitForVoices(timeoutMs = 1500) {
// return new Promise(resolve => {
// const have = speechSynthesis.getVoices();
// if (have && have.length) return resolve(have);
// const onVoices = () => {
// const v = speechSynthesis.getVoices();
// if (v && v.length) {
// speechSynthesis.removeEventListener('voiceschanged', onVoices);
// resolve(v);
// }
// };
// speechSynthesis.addEventListener('voiceschanged', onVoices);
// setTimeout(() => {
// speechSynthesis.removeEventListener('voiceschanged', onVoices);
// resolve(speechSynthesis.getVoices() || []);
// }, timeoutMs);
// });
// }
// function preferredSort(a,b){
// // Prefer sa-IN > hi-IN > en-IN, then by name
// const rank = v => (/sa-IN/i.test(v.lang)?0:(/hi-IN/i.test(v.lang)?1:(/en-IN/i.test(v.lang)?2:3)));
// const r = rank(a)-rank(b);
// if (r!==0) return r; return a.name.localeCompare(b.name);
// }
// async function populateVoiceSelect(){
// const select = document.getElementById('voiceSelect');
// if (!select) return;
// select.innerHTML = '';
// const voices = await waitForVoices();
// voices.sort(preferredSort).forEach(v=>{
// const opt = document.createElement('option');
// opt.value = v.voiceURI; // persistable id
// opt.textContent = `${v.name} — ${v.lang}`;
// select.appendChild(opt);
// });
// const st = getTTSSettings();
// if (st.voiceURI){
// const found = [...select.options].some(o=>o.value===st.voiceURI);
// if (found) select.value = st.voiceURI;
// } else if (voices.length){
// // auto-pick first preferred
// saveTTSSettings({ voiceURI: voices[0].voiceURI });
// select.value = voices[0].voiceURI;
// }
// }
// function attachVoiceUI(){
// const select = document.getElementById('voiceSelect');
// const refresh = document.getElementById('voiceRefresh');
// const sample = document.getElementById('voiceSample');
// const rate = document.getElementById('voiceRate');
// const pitch = document.getElementById('voicePitch');
// const st = getTTSSettings();
// if (rate) rate.value = st.rate; if (pitch) pitch.value = st.pitch;
// if (select) select.addEventListener('change', ()=> saveTTSSettings({ voiceURI: select.value }));
// if (rate) rate.addEventListener('input', ()=> saveTTSSettings({ rate: parseFloat(rate.value) }));
// if (pitch) pitch.addEventListener('input', ()=> saveTTSSettings({ pitch: parseFloat(pitch.value) }));
// if (refresh) refresh.addEventListener('click', populateVoiceSelect);
// if (sample) sample.addEventListener('click', async ()=>{
// try { await speakClientSide("ॐ श्रीं नमः | यह एक नमूना आवाज़ है ।"); } catch(e){ console.warn(e); }
// });
// }
// function resolveSelectedVoice(voices){
// const st = getTTSSettings();
// let v = voices.find(v=>v.voiceURI===st.voiceURI);
// if (!v){
// // best-effort locale pick
// v = voices.sort(preferredSort)[0] || null;
// if (v) saveTTSSettings({ voiceURI: v.voiceURI });
// }
// return v;
// }
// Call once on load (safe no-op if controls are not present)
// (function initVoiceControls(){
// if (!('speechSynthesis' in window)) return;
// populateVoiceSelect();
// attachVoiceUI();
// })();
// Handle toggle for "Shastra Collection" header
document.getElementById('shastraHeader').addEventListener('click', function() {
const shastraList = document.getElementById('shastraList');
shastraList.classList.toggle('hidden'); // Toggle the 'hidden' class on the sidebar
});
let chaptersArray = [];
let currentChapterIndex = -1; // Initialize with -1 as default to indicate no chapter is loaded yet
let resumeTime = 0;
let player;
function initializePage(data) {
const shastraList = document.getElementById('shastraList');
if (!shastraList) {
console.error("Element with ID 'shastraList' not found.");
return;
}
Object.keys(data).forEach((collection) => {
// Create main group (e.g., Bhagwat Mahapuran)
const mainGroupItem = document.createElement('li');
mainGroupItem.classList.add('main-group');
mainGroupItem.innerHTML = `
<i class="fas fa-book" style="color:#4b6cb7;"></i>
<span class="group-title">${collection}</span>
`;
const itemList = document.createElement('ul');
itemList.classList.add('nested-list');
itemList.style.display = 'none';
// Toggle display of main group chapters
mainGroupItem.addEventListener('click', () => {
itemList.style.display = itemList.style.display === 'none' ? 'block' : 'none';
});
data[collection].forEach((item) => {
if (item.skandaTitle) {
// Create Skanda group with + icon
const skandaGroup = document.createElement('li');
skandaGroup.classList.add('skanda-group');
skandaGroup.innerHTML = `
<i class="fas fa-plus toggle-icon" style="color:#888;"></i>
<i class="fas fa-folder" style="color:#f4b400;"></i>
<span class="skanda-title">${item.skandaTitle}</span>
`;
const skandaChapterList = document.createElement('ul');
skandaChapterList.classList.add('nested-list');
skandaChapterList.style.display = 'none';
item.chapters.forEach((chapter) => {
const chapterItem = document.createElement('li');
chapterItem.classList.add('chapter-item');
chapterItem.innerHTML = `
<i class="fas fa-file-alt" style="color:#5e5e5e;"></i>
${chapter.chapterTitle}
`;
chapterItem.addEventListener('click', (event) => {
event.stopPropagation();
fetchChapterData(chapter.chapterTitle).then(chapterDetails => {
if (chapterDetails) {
loadChapter(chapterDetails);
closeSidebarOnMobile();
}
});
});
skandaChapterList.appendChild(chapterItem);
chaptersArray.push({ chapterTitle: chapter.chapterTitle });
});
skandaGroup.addEventListener('click', (event) => {
event.stopPropagation();
skandaChapterList.style.display = skandaChapterList.style.display === 'none' ? 'block' : 'none';
const toggleIcon = skandaGroup.querySelector('.toggle-icon');
if (toggleIcon) {
toggleIcon.classList.toggle('fa-plus');
toggleIcon.classList.toggle('fa-minus');
}
});
skandaGroup.appendChild(skandaChapterList);
itemList.appendChild(skandaGroup);
} else {
const chapterItem = document.createElement('li');
chapterItem.classList.add('chapter-item');
chapterItem.innerHTML = `<i class="fas fa-file-alt"></i> ${item.chapterTitle}`;
chapterItem.addEventListener('click', (event) => {
event.stopPropagation();
fetchChapterData(item.chapterTitle).then(chapterDetails => {
if (chapterDetails) {
loadChapter(chapterDetails);
closeSidebarOnMobile();
}
});
});
itemList.appendChild(chapterItem);
chaptersArray.push({ chapterTitle: item.chapterTitle });
}
});
mainGroupItem.appendChild(itemList);
shastraList.appendChild(mainGroupItem);
});
// Place this right after the forEach loop ends inside initializePage
if (!localStorage.getItem("menuTipShown")) {
const tip = document.createElement('div');
tip.innerText = "📚 Browse chapters here!";
tip.style.cssText = `
position: fixed;
left: 20px;
top: 70px;
background: #fff8e1;
padding: 8px 12px;
border-radius: 5px;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
z-index: 9999;
font-weight: bold;
`;
document.body.appendChild(tip);
setTimeout(() => {
tip.remove();
localStorage.setItem("menuTipShown", "true");
}, 4000);
}
}
function extractSkandaNumber(skandaTitle) {
// e.g. "Skanda 1" or "Skanda One" or "Skanda I"
const match = skandaTitle?.match(/(\d+)/);
return match ? parseInt(match[1], 10) : 0;
}
function initializePageOld(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.innerHTML = `<i class="fas fa-folder"></i> ${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.innerHTML = `<i class="fas fa-file-alt"></i> ${chapter.chapterTitle}`;
chapterItem.classList.add('chapter-item');
chapterItem.addEventListener('click', (event) => {
event.stopPropagation();
fetchChapterData(chapter.chapterTitle).then(chapterDetails => {
if (chapterDetails) {
loadChapter(chapterDetails);
closeSidebarOnMobile();
}
});
});
skandaChapterList.appendChild(chapterItem);
// Populate chaptersArray with chapter metadata (title only for now)
chaptersArray.push({ chapterTitle: chapter.chapterTitle });
});
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();
fetchChapterData(item.chapterTitle).then(chapterDetails => {
if (chapterDetails) {
loadChapter(chapterDetails);
closeSidebarOnMobile();
}
});
});
itemList.appendChild(chapterItem);
// Populate chaptersArray with chapter metadata (title only for now)
chaptersArray.push({ chapterTitle: item.chapterTitle });
}
});
mainGroupItem.addEventListener('click', () => {
itemList.style.display = itemList.style.display === 'none' ? 'block' : 'none';
});
mainGroupItem.appendChild(itemList);
shastraList.appendChild(mainGroupItem);
});
}
async function fetchChapterData(chapterTitle) {
try {
const response = await fetch(`https://thevera-botveradb.hf.space/get_chapter_details?chapterTitle=${encodeURIComponent(chapterTitle)}`);
const result = await response.json();
if (response.ok && result.success) {
return result.data; // Return chapter details
} else {
console.error("Error fetching chapter details:", result.message);
return null;
}
} catch (error) {
console.error("Error in fetchChapterData:", error);
return null;
}
}
// Function to fetch audio URL
async function fetchAudioUrl(chapterTitle) {
try {
const response = await fetch(`https://thevera-botveradb.hf.space/get_audio_url?chapterTitle=${encodeURIComponent(chapterTitle)}`);
const result = await response.json();
if (response.ok && result.success) {
return result.audioUrl;
} else {
console.error('Error fetching audio:', result.message);
return null;
}
} catch (error) {
console.error('Error fetching audio:', error);
return null;
}
}
async function loadChapter(chapter) {
console.log("Loading chapter...");
console.log(chapter.chapterTitle);
// Save the last accessed chapter in localStorage
localStorage.setItem("lastAccessedChapter", JSON.stringify({
chapterTitle: chapter.chapterTitle
}));
const chapterTitle = document.getElementById('chapterTitle');
const slokeContent = document.getElementById('slokeContent');
const videoPlayer = document.getElementById('videoPlayer');
const transcriptBlock = document.getElementById('transcript-content');
// Ensure the elements are loaded correctly
if (!chapterTitle || !slokeContent || !videoPlayer || !transcriptBlock) {
console.error("Missing elements in chapter display.");
return;
}
// Reset content
chapterTitle.textContent = 'Loading...'; // Temporary loading message
slokeContent.innerHTML = '';
videoPlayer.src = '';
transcriptBlock.innerHTML = ''; // Clear all transcript content
try {
// Fetch chapter details from the backend
const chapterDetails = await fetchChapterData(chapter.chapterTitle);
if (!chapterDetails) {
chapterTitle.textContent = 'Chapter details not found.';
return;
}
// Update UI with chapter details
chapterTitle.textContent = chapterDetails.chapterTitle + " / " + chapterDetails.about || 'Chapter Details';
// Process and display the slokes
const slokesArray = chapterDetails.slokes ? chapterDetails.slokes.split('\n') : [];
slokesArray.forEach((slokeText) => {
const slokeElement = document.createElement('p');
slokeElement.classList.add('sloke-text');
// slokeElement.innerHTML = slokeText.replace(/श्लोक \d+:/g, '<strong>$&</strong>');
slokeElement.innerHTML = slokeText.replace(/(श्लोक \d+:|अर्थ \d+:)/g, '<strong>$&</strong>');
const speakIcon = createSpeakIcon(slokeText);
slokeElement.appendChild(speakIcon);
slokeContent.appendChild(slokeElement);
});
// Update video and transcript blocks
// videoPlayer.src = chapterDetails.video || '';
loadYouTubeVideo(chapterDetails.video);
const transcriptArray = chapterDetails.transcript ? chapterDetails.transcript.split('\n') : [];
transcriptArray.forEach((transcriptText) => {
const transcriptElement = document.createElement('p');
transcriptElement.classList.add('transcript-text');
transcriptElement.textContent = transcriptText; // Add transcript text
transcriptBlock.appendChild(transcriptElement);
});
// Show the content blocks
document.querySelector('.main').classList.add('active');
document.querySelector('.sloke-block').classList.add('active');
document.querySelector('.video-block').classList.add('active');
document.querySelector('.transcript-block').classList.add('active');
// Setup play buttons
setupPlayAllButton(slokesArray);
setupPlayAllTranscriptButton(transcriptArray);
// Auto-click to minimize the sidebar group
const chapterGroup = document.querySelector(`.main-group`);
if (chapterGroup) {
chapterGroup.click(); // This simulates a click to collapse the group
}
// Update currentChapterIndex for "Next Chapter" functionality
currentChapterIndex = chaptersArray.findIndex(ch => ch.chapterTitle === chapter.chapterTitle);
console.log("Updated Current Index:", currentChapterIndex);
document.getElementById('shastraHeader').click(); // Simulate a click on the header
} catch (error) {
console.error("Error loading chapter details:", error);
chapterTitle.textContent = 'Failed to load chapter details. Please try again.';
}
}
function loadYouTubeVideo(videoUrl) {
if (!videoUrl) {
console.warn("[Video] No video URL provided");
return;
}
const videoIdMatch = videoUrl.match(/\/embed\/([a-zA-Z0-9_-]+)/);
if (!videoIdMatch) {
console.error("[Video] Invalid video URL format", videoUrl);
return;
}
const videoId = videoIdMatch[1];
currentVideoId = videoId;
const storageKey = `videoTime_${videoId}`;
// resumeTime = parseFloat(localStorage.getItem(storageKey)) || 0;
resumeTime = Math.max((parseFloat(localStorage.getItem(storageKey)) || 0) - 5, 0);
console.log(`[Video] Loading ID: ${videoId}, Resuming at: ${resumeTime}s`);
if (player) {
player.loadVideoById({ videoId, startSeconds: resumeTime });
} else {
player = new YT.Player('videoPlayer', {
height: '315',
width: '100%',
videoId,
playerVars: {
autoplay: 1,
controls: 1,
start: resumeTime
},
events: {
'onReady': (event) => {
console.log("[Player] onReady");
event.target.seekTo(resumeTime, true);
event.target.playVideo();
},
'onStateChange': onPlayerStateChange
}
});
}
}
function onPlayerStateChange(event) {
if (event.data === YT.PlayerState.PLAYING) {
console.log("[Player] Playing");
// Save playback time every 5 seconds
clearInterval(window.saveTimeInterval);
window.saveTimeInterval = setInterval(() => {
if (player && currentVideoId) {
const time = player.getCurrentTime();
localStorage.setItem(`videoTime_${currentVideoId}`, time);
console.log(`[Resume Save] ${currentVideoId}: ${time.toFixed(1)}s`);
}
}, 5000);
}
if (event.data === YT.PlayerState.ENDED) {
console.log("[Player] Video Ended. Clearing resume time.");
localStorage.removeItem(`videoTime_${currentVideoId}`);
clearInterval(window.saveTimeInterval);
}
}
function loadNextChapter() {
console.log("Next Chapter clicked...");
if (currentChapterIndex + 1 < chaptersArray.length) {
currentChapterIndex++; // Increment currentChapterIndex to move to the next chapter
// Auto-click to minimize the sidebar group
const chapterGroup = document.querySelector(`.main-group`);
if (chapterGroup) {
chapterGroup.click(); // This simulates a click to collapse the group
}
loadChapter(chaptersArray[currentChapterIndex]);
} else {
alert("This is the last chapter.");
}
}
function closeSidebarOnMobile() {
const sidebar = document.querySelector(".sidebar");
const overlay = document.querySelector(".overlay");
if (window.innerWidth < 768 && sidebar && overlay) {
sidebar.classList.remove("shown");
overlay.classList.remove("active");
}
}
// Other functions such as createSpeakIcon, cleanSlokText, playTTS, and setupPlayAllButton remain as you provided
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) {
// Regex to match and remove introductory (e.g., "श्लोक 1:") and ending markers (e.g., "१")
// return text.replace(/श्लोक \d+: /g, '').replace(/ \d+$/g, '');
return text.replace(/(श्लोक \d+:|अर्थ \d+:)/g,'').replace(/ \d+$/g, '');
}
let currentSlokeIndex = 0; // Track the current sloke index
const audioPlayer = document.getElementById('audioPlayer');
// Play all slokes function (replace your existing setupPlayAllButton function)
function setupPlayAllButton(slokesArray) {
const playAllButton = document.getElementById('playAllButton');
playAllButton.onclick = async () => {
currentSlokeIndex = 0; // Reset to start
playNextSloke(slokesArray);
};
}
// Function to play each sloke in sequence
async function playNextSloke(slokesArray) {
if (currentSlokeIndex >= slokesArray.length) {
return; // End if all slokes have been played
}
// Clean and highlight the current sloke text
// const slokeText = cleanSlokText(slokesArray[currentSlokeIndex]);
const slokeText = slokesArray[currentSlokeIndex];
highlightCurrentSloke(currentSlokeIndex);
// Generate TTS audio for the current sloke text
playTTS(slokeText).then(() => {
// Move to the next sloke after the current one finishes
currentSlokeIndex++;
playNextSloke(slokesArray);
});
}
// Function to highlight the current sloke and scroll it into view
function highlightCurrentSloke(index) {
const slokeElements = document.querySelectorAll('.sloke-text'); // Assume each sloke text has this class
// Remove previous highlights
slokeElements.forEach(el => el.classList.remove('highlight'));
// Highlight and scroll the current sloke
const currentSloke = slokeElements[index];
if (currentSloke) {
currentSloke.classList.add('highlight');
currentSloke.scrollIntoView({ behavior: "smooth", block: "center" });
}
}
let currentTranscriptIndex = 0; // Track the current transcript index
// Setup Play All for Transcript
function setupPlayAllTranscriptButton(transcriptArray) {
const playAllTranscriptButton = document.getElementById('playTranscriptButton');
playAllTranscriptButton.onclick = async () => {
currentTranscriptIndex = 0; // Reset to start
playNextTranscript(transcriptArray);
};
}
// Function to play each transcript in sequence
async function playNextTranscript(transcriptArray) {
if (currentTranscriptIndex >= transcriptArray.length) {
return; // End if all transcripts have been played
}
// Highlight the current transcript text
highlightCurrentTranscript(currentTranscriptIndex);
// Generate TTS audio for the current transcript text
const transcriptText = transcriptArray[currentTranscriptIndex];
playTTS(transcriptText).then(() => {
// Move to the next transcript after the current one finishes
currentTranscriptIndex++;
playNextTranscript(transcriptArray);
});
}
// Function to highlight the current transcript text
function highlightCurrentTranscript(index) {
const allTranscripts = document.querySelectorAll('.transcript-text');
allTranscripts.forEach((transcript, i) => {
if (i === index) {
transcript.classList.add('highlight'); // Add highlight class
} else {
transcript.classList.remove('highlight'); // Remove highlight class
}
});
}
let currentAudio; // Global variable to hold the audio object for server-generated audio
let isPlaying = false; // Track play/pause state for playback
let currentUtterance; // Track current SpeechSynthesisUtterance for sa-IN playback
// --- Voice helpers ---
function pickPreferredVoice(voices) {
const tests = [
v => /sa-IN/i.test(v.lang) && /(male|deep|bass|india)/i.test(v.name),
v => /sa-IN/i.test(v.lang),
v => /hi-IN/i.test(v.lang) && /(male|deep|bass|india)/i.test(v.name),
v => /hi-IN/i.test(v.lang),
v => /en-IN/i.test(v.lang) && /(male|deep|bass|india)/i.test(v.name),
v => /en-IN/i.test(v.lang),
];
for (const t of tests) {
const found = voices.find(t);
if (found) return found;
}
return voices[0] || null;
}
function waitForVoices(timeoutMs = 1500) {
return new Promise(resolve => {
const have = speechSynthesis.getVoices();
if (have && have.length) return resolve(have);
const onVoices = () => {
const v = speechSynthesis.getVoices();
if (v && v.length) {
speechSynthesis.removeEventListener('voiceschanged', onVoices);
resolve(v);
}
};
speechSynthesis.addEventListener('voiceschanged', onVoices);
setTimeout(() => {
speechSynthesis.removeEventListener('voiceschanged', onVoices);
resolve(speechSynthesis.getVoices() || []);
}, timeoutMs);
});
}
async function speakClientSide(text) {
const voices = await waitForVoices();
if (!voices.length) throw new Error('No TTS voices available');
const voice = pickPreferredVoice(voices);
const langFallback = voice?.lang || 'sa-IN';
// Stop any previous utterances
try { speechSynthesis.cancel(); } catch {}
// Split by pipe/comma and add small pauses after delimiters
const parts = text.split(/(\||,)/).map(s => s.trim()).filter(Boolean);
for (const chunk of parts) {
const u = new SpeechSynthesisUtterance(chunk);
if (voice) u.voice = voice;
u.lang = voice?.lang || langFallback;
u.rate = 0.9; // or your saved rate
u.pitch = 0.9; // or your saved pitch
u.volume = 1.0;
await new Promise((res, rej) => {
u.onend = res;
u.onerror = rej;
speechSynthesis.speak(u);
});
if (chunk === '|' || chunk === ',') {
await new Promise(r => setTimeout(r, 220));
}
}
}
// Speak text in segments (pauses at "|" and ",")
async function speakClientSideOld(text) {
const st = ttsGet();
const all = await getAllVoices();
if (!all.length) throw new Error('No TTS voices available');
// pick language preference sa-IN -> hi-IN -> en-IN
const prefLangs = ['sa-IN', 'hi-IN', 'en-IN'];
let chosenLang = prefLangs.find(l => st.byLang[l]?.voiceURI) || prefLangs.find(l => all.some(v => v.lang && v.lang.startsWith(l)));
if (!chosenLang) chosenLang = all[0].lang || 'hi-IN';
let voice = null;
const savedURI = st.byLang[chosenLang]?.voiceURI;
if (savedURI) voice = all.find(v => v.voiceURI === savedURI) || null;
if (!voice) {
const list = voicesForLang(all, chosenLang);
voice = list[0] || all[0] || null;
}
const parts = text.split(/(\||,)/).map(s => s.trim()).filter(Boolean);
for (const chunk of parts) {
const u = new SpeechSynthesisUtterance(chunk);
if (voice) u.voice = voice;
u.lang = voice?.lang || chosenLang;
u.rate = st.rate;
u.pitch = st.pitch;
await new Promise((res, rej)=>{ u.onend = res; u.onerror = rej; speechSynthesis.speak(u); });
if (chunk === '|' || chunk === ',') await new Promise(r=>setTimeout(r,220));
}
}
async function playTTS(text) {
console.log('Speaking mantra');
if (!text || text.trim() === '') {
console.error('No text provided');
return;
}
const cleanText = typeof cleanSlokText === 'function' ? cleanSlokText(text) : text;
// Helper to play a URL in your existing <audio id="audioPlayer">
async function playAudioUrl(audioUrl, revokeWhenDone = false) {
return new Promise((resolve, reject) => {
const audioPlayer = document.getElementById('audioPlayer');
if (!audioPlayer) return reject(new Error('audioPlayer not found'));
audioPlayer.onerror = (event) => reject(event);
audioPlayer.onended = () => {
try { if (revokeWhenDone && audioUrl.startsWith('blob:')) URL.revokeObjectURL(audioUrl); } catch {}
resolve();
};
audioPlayer.src = audioUrl;
audioPlayer.load();
audioPlayer.play().catch(reject);
});
}
// 1) Try saved audio (pass ORIGINAL text so backend can read “श्लोक N”)
try {
const savedUrl = await getAudioUrlForSloke(text);
if (savedUrl) {
console.log('Playing saved audio from:', savedUrl);
await playAudioUrl(savedUrl);
return; // done
}
} catch (e) {
console.warn('Saved audio lookup failed:', e);
// fall through to browser TTS
}
// 2) Browser TTS (client-side)
try {
if ('speechSynthesis' in window) {
await speakClientSide(cleanText); // uses your voice picker or preference
return; // done
}
} catch (e) {
console.warn('Client-side TTS failed, will try server fallback:', e);
}
// 3) Server-side fallback
try {
const serverUrl = "https://thevera-botveradb.hf.space/generate_sanskrit_audio";
const response = await fetch(serverUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cleanText })
});
if (!response.ok) throw new Error('Server TTS fetch failed');
const audioBlob = await response.blob();
const blobUrl = URL.createObjectURL(audioBlob);
await playAudioUrl(blobUrl, true);
} catch (e) {
console.error('Server TTS failed:', e);
}
}
async function playTTSold(text) {
console.log('Speaking mantra');
if (!text || text.trim() === '') { console.error('No text provided'); return; }
const cleanText = typeof cleanSlokText === 'function' ? cleanSlokText(text) : text;
// 1) Try saved audio first
try {
if (typeof getAudioUrlForSloke === 'function') {
const savedUrl = await getAudioUrlForSloke(text);
// const savedUrl = await getAudioUrlForSloke(cleanText);
if (savedUrl) {
console.log('Playing saved audio from:', savedUrl);
await new Promise((resolve, reject) => {
const audioPlayer = document.getElementById('audioPlayer');
audioPlayer.onerror = (event) => { console.error('Saved audio playback error:', event); reject(event); };
audioPlayer.onended = () => { isPlaying = false; if (savedUrl.startsWith('blob:')) URL.revokeObjectURL(savedUrl); resolve(); };
audioPlayer.src = savedUrl; audioPlayer.load(); isPlaying = true; audioPlayer.play();
});
return;
}
}
} catch (e) { console.warn('Saved audio not found, trying client TTS...', e); }
// 2) Browser TTS with selected voice
try {
if ('speechSynthesis' in window) { await speakClientSide(cleanText); return; }
} catch (e) { console.warn('Client-side TTS failed, trying server TTS...', e); }
// 3) Server fallback
console.warn('Using server-side TTS fallback.');
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({ cleanText }) });
if (!response.ok) throw new Error('Failed to fetch audio from server');
const audioBlob = await response.blob(); const blobUrl = URL.createObjectURL(audioBlob);
await new Promise((resolve, reject) => {
const audioPlayer = document.getElementById('audioPlayer');
audioPlayer.onerror = (event) => { console.error('Server-based TTS playback error:', event); reject(event); };
audioPlayer.onended = () => { isPlaying = false; URL.revokeObjectURL(blobUrl); resolve(); };
audioPlayer.src = blobUrl; isPlaying = true; audioPlayer.play();
});
} catch (error) { console.error('Error calling server:', error); }
}
// Function to fetch the audio URL for a given sloke
async function getAudioUrlForSlokeOld(text) {
try {
const response = await fetch(`https://thevera-botveradb.hf.space/get_audio_url?slokeText=${encodeURIComponent(text)}`);
if (!response.ok) {
throw new Error('Failed to fetch audio URL');
}
const data = await response.json();
return data.audioUrl; // Assuming the API returns { audioUrl: 'URL' }
} catch (error) {
console.error('Error fetching audio URL:', error);
return null; // Return null if an error occurs, so it falls back to server-side TTS
}
}
async function getAudioUrlForSloke(originalText) {
try {
const url = `https://thevera-botveradb.hf.space/get_audio_url?slokeText=${encodeURIComponent(originalText)}`;
const response = await fetch(url);
// 404 just means "no saved audio" — return null quietly
if (response.status === 404) return null;
if (!response.ok) {
// Other non-OK statuses: treat as no saved audio (no console noise)
return null;
}
const data = await response.json();
// API returns { success, audioUrl }
return data && data.success ? data.audioUrl : null;
} catch {
// Network or other errors → just say "no saved audio"
return null;
}
}
// Donate Model Function
// Get elements
const donateButton = document.getElementById('donateButton');
const donateModal = document.getElementById('donateModal');
const closeBtn = document.querySelector('.close');
const amountButtons = document.querySelectorAll('.amount-btn');
const customAmountInput = document.getElementById('customAmount');
const donateForm = document.getElementById('donateForm');
const openUpiAppButton = document.getElementById('openUpiApp');
// Donation amount logic
let selectedAmount = 0;
// Handle predefined amount buttons
amountButtons.forEach(button => {
button.addEventListener('click', () => {
selectedAmount = parseInt(button.dataset.amount); // Get amount from button's data attribute
customAmountInput.value = ''; // Clear custom amount input
amountButtons.forEach(btn => btn.classList.remove('selected')); // Deselect other buttons
button.classList.add('selected'); // Highlight selected button
});
});
// Handle custom amount input
customAmountInput.addEventListener('input', () => {
selectedAmount = parseInt(customAmountInput.value) || 0; // Set amount or default to 0
amountButtons.forEach(btn => btn.classList.remove('selected')); // Deselect predefined buttons
});
// Open modal
donateButton.onclick = function () {
donateModal.style.display = "block"; // Show the modal
}
// Close modal
closeBtn.onclick = function () {
donateModal.style.display = "none"; // Hide the modal
}
// Close modal when clicking outside it
window.onclick = function (event) {
if (event.target === donateModal) {
donateModal.style.display = "none";
}
}
// Submit form
donateForm.addEventListener('submit', async (e) => {
e.preventDefault();
// Get user details
const name = document.getElementById('name').value.trim();
const email = document.getElementById('email').value.trim();
// Validate inputs
if (!name || !email) {
alert("Please enter your name and email.");
return;
}
if (!selectedAmount || isNaN(selectedAmount) || selectedAmount <= 0) {
alert("Please select or enter a valid donation amount.");
return;
}
// Prepare donation data
const donationData = { name, email, amount: selectedAmount };
try {
logger.log(donationData)
console.log(donationData)
// Save to MongoDB via API
const response = await fetch('https://thevera-botveradb.hf.space/save-donation', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(donationData),
});
console.log(response)
if (response.ok) {
alert("Thank you for your donation!");
donateModal.style.display = "none";
} else {
const errorData = await response.json();
alert(`Error: ${errorData.error || "Something went wrong. Please try again."}`);
}
} catch (error) {
alert("Unable to process your donation. Please try again later.");
console.error(error);
}
});
// Open UPI payment app
openUpiAppButton.onclick = function () {
if (!selectedAmount || isNaN(selectedAmount) || selectedAmount <= 0) {
alert("Please select or enter a valid donation amount.");
return;
}
// UPI payment link with amount
const upiLink = `upi://pay?pa=sumandas24-4@okaxis&pn=Suman+Das&am=${selectedAmount}&cu=INR`;
window.open(upiLink, '_blank');
};
// Share App Function
function shareApp() {
const shareData = {
title: "BhagvatRas",
text: "Explore BhagvatRas - Spiritual Insights and Discussions!",
url: window.location.href
};
// ✅ Web Share API (For Mobile & Modern Browsers)
if (navigator.share) {
navigator.share(shareData)
.then(() => console.log("Shared successfully"))
.catch((error) => console.log("Error sharing:", error));
} else {
// ✅ Fallback: Manual share options
let shareURL = encodeURIComponent(shareData.url);
let shareText = encodeURIComponent(shareData.text);
let logoURL = encodeURIComponent("https://bhagvat-ras.static.hf.space/icon_bhagvatras1.png");
let shareOptions = `
<p>Share this app:</p>
<ul>
<li><a href="mailto:?subject=${shareData.title}&body=${shareText}%20${shareURL}" target="_blank">📧 Email</a></li>
<li><a href="https://api.whatsapp.com/send?text=${shareText}%20${shareURL}" target="_blank">📱 WhatsApp</a></li>
<li><a href="https://www.facebook.com/sharer/sharer.php?u=${shareURL}" target="_blank">🔵 Facebook</a></li>
<li><a href="https://twitter.com/intent/tweet?text=${shareText}&url=${shareURL}" target="_blank">🐦 Twitter</a></li>
<li><a href="https://www.linkedin.com/sharing/share-offsite/?url=${shareURL}" target="_blank">💼 LinkedIn</a></li>
</ul>
<img src="${logoURL}" alt="BhagvatRas Logo" style="width: 50px; margin-top: 10px;">
`;
// Show fallback share options
let shareDiv = document.createElement("div");
shareDiv.innerHTML = shareOptions;
shareDiv.style.position = "fixed";
shareDiv.style.top = "50px";
shareDiv.style.right = "20px";
shareDiv.style.background = "white";
shareDiv.style.padding = "10px";
shareDiv.style.border = "1px solid #ddd";
shareDiv.style.boxShadow = "0px 4px 6px rgba(0, 0, 0, 0.1)";
document.body.appendChild(shareDiv);
}
}
// Install Function
document.addEventListener("DOMContentLoaded", function () {
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
console.log("✅ beforeinstallprompt fired");
const installBtn = document.getElementById('installAppButton');
if (installBtn) {
installBtn.style.display = 'block';
localStorage.setItem("installPromptShown", "true");
}
});
const installBtn = document.getElementById('installAppButton');
if (installBtn) {
installBtn.addEventListener('click', () => {
if (deferredPrompt) {
deferredPrompt.prompt();
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('✅ User accepted the A2HS prompt');
} else {
console.log('❌ User dismissed the A2HS prompt');
}
deferredPrompt = null;
installBtn.style.display = 'none';
});
}
});
}
});
// ===== Voice Settings (popup) =====
// ===== Voice Settings (popup) — REPLACED & FIXED =====
const TTS_KEY = 'ttsSettings_v3';
// { byLang: { "hi-IN": {voiceURI, name}, ... }, rate, pitch, lastLang }
const TTS_DEFAULT = { byLang: {}, rate: 0.9, pitch: 0.9, lastLang: null };
const ttsGet = () => {
try { return { ...TTS_DEFAULT, ...(JSON.parse(localStorage.getItem(TTS_KEY)) || {}) }; }
catch { return { ...TTS_DEFAULT }; }
};
const ttsSave = (patch) => {
const next = { ...ttsGet(), ...(patch || {}) };
localStorage.setItem(TTS_KEY, JSON.stringify(next));
return next;
};
// Warm-up for mobile (iOS/Android) to force voices to load after a user gesture
async function ensureVoicesReady() {
let voices = speechSynthesis.getVoices();
if (voices && voices.length) return voices;
// speak a tiny silent utterance to trigger load on some browsers
try {
const u = new SpeechSynthesisUtterance(' ');
u.volume = 0; u.rate = 1; u.pitch = 1;
speechSynthesis.speak(u);
} catch {}
// wait for voiceschanged or timeout
voices = await new Promise(resolve => {
const handler = () => {
const all = speechSynthesis.getVoices();
if (all && all.length) {
speechSynthesis.removeEventListener('voiceschanged', handler);
resolve(all);
}
};
speechSynthesis.addEventListener('voiceschanged', handler);
setTimeout(() => {
speechSynthesis.removeEventListener('voiceschanged', handler);
resolve(speechSynthesis.getVoices() || []);
}, 2000);
});
return voices;
}
function rankLang(a) {
// Prefer IN locales, then Indic; otherwise alphabetical
const priority = [
'sa-IN','hi-IN','en-IN','bn-IN','mr-IN','gu-IN','ta-IN','te-IN','kn-IN','ml-IN','or-IN','pa-IN','as-IN'
];
const ia = priority.indexOf(a);
if (ia >= 0) return ia;
if (/-IN$/i.test(a)) return 50; // other India locales
return 100;
}
function uniqueLangs(voices) {
const set = new Set();
voices.forEach(v => v.lang && set.add(v.lang));
return [...set].sort((a,b) => {
const r = rankLang(a) - rankLang(b);
return r !== 0 ? r : a.localeCompare(b);
});
}
function voicesByLang(voices, lang) {
return voices
.filter(v => v.lang && v.lang.toLowerCase().startsWith(lang.toLowerCase()))
.sort((a,b) => a.name.localeCompare(b.name));
}
function openVoiceModal(){ document.getElementById('voiceModal')?.classList.add('show'); }
function closeVoiceModal(){ document.getElementById('voiceModal')?.classList.remove('show'); }
async function buildVoiceUI() {
if (!('speechSynthesis' in window)) return;
const langSel = document.getElementById('voiceLang');
const voiceSel = document.getElementById('voiceSelect');
const rate = document.getElementById('voiceRate');
const pitch = document.getElementById('voicePitch');
if (!langSel || !voiceSel) return;
// ensure voices are actually present (mobile)
let voices = await ensureVoicesReady();
if (!voices.length) {
// one more retry on user action
voices = await ensureVoicesReady();
}
// populate languages dynamically
const st = ttsGet();
const langs = uniqueLangs(voices);
langSel.innerHTML = '';
langs.forEach(l => {
const opt = document.createElement('option');
opt.value = l; opt.textContent = l;
langSel.appendChild(opt);
});
langSel.value = st.lastLang && langs.includes(st.lastLang)
? st.lastLang
: (langs.find(l => /-IN$/i.test(l)) || langs[0] || '');
// populate voices for the chosen language
function refreshVoiceList() {
const lang = langSel.value;
const list = voicesByLang(voices, lang);
voiceSel.innerHTML = '';
list.forEach(v => {
const opt = document.createElement('option');
opt.value = v.voiceURI;
opt.textContent = `${v.name}${v.lang}`;
voiceSel.appendChild(opt);
});
// restore saved choice if available
const savedUri = st.byLang[lang]?.voiceURI;
if (savedUri && [...voiceSel.options].some(o => o.value === savedUri)) {
voiceSel.value = savedUri;
} else if (list[0]) {
voiceSel.value = list[0].voiceURI;
}
}
rate.value = st.rate;
pitch.value = st.pitch;
langSel.onchange = () => { ttsSave({ lastLang: langSel.value }); refreshVoiceList(); };
refreshVoiceList();
// sample play
document.getElementById('voiceSample')?.addEventListener('click', async () => {
try {
const lang = langSel.value;
const uri = voiceSel.value;
const v = speechSynthesis.getVoices().find(x => x.voiceURI === uri) || null;
speechSynthesis.cancel();
const u = new SpeechSynthesisUtterance(
/en/i.test(lang) ? 'This is a sample voice.' : 'यह एक नमूना आवाज़ है | ॐ श्रीं नमः ।'
);
if (v) u.voice = v;
u.lang = v?.lang || lang;
u.rate = parseFloat(rate.value);
u.pitch = parseFloat(pitch.value);
speechSynthesis.speak(u);
} catch (e) { console.warn(e); }
});
// save
document.getElementById('voiceSave')?.addEventListener('click', () => {
const lang = langSel.value;
const uri = voiceSel.value;
const v = speechSynthesis.getVoices().find(x => x.voiceURI === uri) || null;
const byLang = { ...ttsGet().byLang, [lang]: { voiceURI: uri, name: v?.name || '' } };
ttsSave({ byLang, rate: parseFloat(rate.value), pitch: parseFloat(pitch.value), lastLang: lang });
closeVoiceModal();
});
// reset
document.getElementById('voiceReset')?.addEventListener('click', () => {
localStorage.removeItem(TTS_KEY);
closeVoiceModal();
});
}
// wire modal openers & close
function wireVoiceButtons() {
const btn1 = document.getElementById('voiceSettingsBtn');
const btn2 = document.getElementById('voiceSettingsBtnMobile');
const close = document.getElementById('voiceModalClose');
btn1?.addEventListener('click', () => { openVoiceModal(); buildVoiceUI(); });
btn2?.addEventListener('click', () => { openVoiceModal(); buildVoiceUI(); });
close?.addEventListener('click', closeVoiceModal);
document.getElementById('voiceModal')?.addEventListener('click', e => {
if (e.target && e.target.id === 'voiceModal') closeVoiceModal();
});
}
document.addEventListener('DOMContentLoaded', wireVoiceButtons);
// Make speakClientSide respect saved per-language voice, rate & pitch
async function speakClientSide(text) {
const st = ttsGet();
let voices = speechSynthesis.getVoices();
if (!voices || !voices.length) voices = await ensureVoicesReady();
if (!voices.length) throw new Error('No TTS voices available');
// preferred language: last used, else any -IN, else first
const lang = st.lastLang || voices.find(v => /-IN$/i.test(v.lang))?.lang || voices[0].lang;
let voice = null;
const savedUri = st.byLang[lang]?.voiceURI;
if (savedUri) voice = voices.find(v => v.voiceURI === savedUri) || null;
if (!voice) voice = voicesByLang(voices, lang)[0] || voices[0];
// speak with small pauses at | and ,
speechSynthesis.cancel();
const parts = text.split(/(\||,)/).map(s => s.trim()).filter(Boolean);
for (const chunk of parts) {
const u = new SpeechSynthesisUtterance(chunk);
if (voice) u.voice = voice;
u.lang = voice?.lang || lang;
u.rate = st.rate;
u.pitch = st.pitch;
await new Promise((res, rej) => {
u.onend = res; u.onerror = rej; speechSynthesis.speak(u);
});
if (chunk === '|' || chunk === ',') await new Promise(r => setTimeout(r, 220));
}
}
// ===== end Voice Settings (popup) =====
// Code for Satsang
function checkLoginAndOpenSatsang() {
const token = localStorage.getItem("authToken");
if (!token) {
alert("Please login to access the Daily Satsang.");
window.location.href = "login.html";
} else {
window.location.href = "satsang.html";
}
}