This was a lot easier said than done but it would be nice to see this on every webpage one day
<button id=”enable-tts”>Play / Resume</button>
<button id=”pause-tts”>Pause</button>
<button id=”stop-tts”>Stop</button>
<script>
let audioEnabled = false;
let spoken = new WeakSet();
let currentUtterance = null;
document.getElementById(‘enable-tts’).onclick = () => {
audioEnabled = true;
// Resume if paused
if (speechSynthesis.paused) {
speechSynthesis.resume();
return;
}
// Start fresh
const text = document.querySelector(‘main’)?.innerText || document.body.innerText;
speak(text);
};
document.getElementById(‘pause-tts’).onclick = () => {
if (speechSynthesis.speaking && !speechSynthesis.paused) {
speechSynthesis.pause();
}
};
document.getElementById(‘stop-tts’).onclick = () => {
audioEnabled = false;
speechSynthesis.cancel();
};
function speak(text) {
if (!audioEnabled || !text) return;
speechSynthesis.cancel(); // stop previous
currentUtterance = new SpeechSynthesisUtterance(text);
speechSynthesis.speak(currentUtterance);
}
const observer = new MutationObserver(mutations => {
if (!audioEnabled) return;
mutations.forEach(m => {
m.addedNodes.forEach(node => {
if (node.nodeType === 1 && !spoken.has(node)) {
const text = node.innerText?.trim();
if (text && text.length > 30) {
spoken.add(node);
speak(text);
}
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
</script>


Leave a Reply