`).join('');
};
const showInfo = (message) => {
infoMessageDiv.textContent = message;
infoMessageDiv.classList.remove('hidden');
};
const formatTime = (seconds) => {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
};
// --- 5. PLAYER LOGIC ---
const selectTrack = (id) => {
stopPlayback();
currentTrack = relaxationScripts.find(s => s.id === id);
document.querySelectorAll('.playlist-item').forEach(item => {
item.classList.toggle('active', item.dataset.id === id);
});
currentTrackTitle.textContent = currentTrack.title;
currentTrackDuration.textContent = currentTrack.duration;
utterance = new SpeechSynthesisUtterance(currentTrack.script);
utterance.onend = handlePlaybackEnd;
utterance.onboundary = handleBoundary;
// A trick to get duration: estimate based on word count
const estimatedDuration = (currentTrack.script.split(' ').length / 2.5); // Avg 150 WPM
totalTimeEl.textContent = formatTime(estimatedDuration);
};
const handlePlayPause = () => {
if (!currentTrack) {
showInfo("Please select a session from the playlist first.");
return;
}
if (synth.speaking) {
if (synth.paused) {
synth.resume();
playIcon.classList.add('hidden');
pauseIcon.classList.remove('hidden');
} else {
synth.pause();
playIcon.classList.remove('hidden');
pauseIcon.classList.add('hidden');
}
} else {
synth.speak(utterance);
playIcon.classList.add('hidden');
pauseIcon.classList.remove('hidden');
startProgressTracker();
}
};
const stopPlayback = () => {
if (synth.speaking) synth.cancel();
handlePlaybackEnd();
};
const handlePlaybackEnd = () => {
playIcon.classList.remove('hidden');
pauseIcon.classList.add('hidden');
clearInterval(progressInterval);
progressBar.style.width = '0%';
currentTimeEl.textContent = '0:00';
};
const startProgressTracker = () => {
let elapsedTime = 0;
const estimatedDuration = (currentTrack.script.split(' ').length / 2.5);
progressInterval = setInterval(() => {
if (synth.speaking && !synth.paused) {
elapsedTime++;
const progress = (elapsedTime / estimatedDuration) * 100;
progressBar.style.width = `${Math.min(progress, 100)}%`;
currentTimeEl.textContent = formatTime(elapsedTime);
}
}, 1000);
};
const handleBoundary = (event) => {
// This event can be used for more advanced features like highlighting text
};
// --- 6. PDF GENERATION ---
const downloadScript = () => {
if (!currentTrack) {
showInfo("Please select a session to download its script.");
return;
}
const { jsPDF } = window.jspdf;
const pdf = new jsPDF();
pdf.setFontSize(18);
pdf.text(currentTrack.title, 20, 20);
pdf.setFontSize(12);
const textLines = pdf.splitTextToSize(currentTrack.script.replace(/\.\.\./g, '\n\n'), 170);
pdf.text(textLines, 20, 30);
pdf.save(`${currentTrack.title.replace(/ /g, '_')}_Script.pdf`);
};
// --- 7. EVENT LISTENERS ---
const setupEventListeners = () => {
playPauseBtn.addEventListener('click', handlePlayPause);
stopBtn.addEventListener('click', stopPlayback);
downloadBtn.addEventListener('click', downloadScript);
playlistContainer.addEventListener('click', (e) => {
const targetItem = e.target.closest('.playlist-item');
if (targetItem) {
selectTrack(targetItem.dataset.id);
}
});
};
// --- INITIALIZE THE PLAYER ---
init();
});
