From cf95fea6c33e55131ee75f874eb64e7a74a059e3 Mon Sep 17 00:00:00 2001 From: retoor Date: Sun, 29 Jun 2025 20:08:13 +0200 Subject: [PATCH] Update tts/ --- src/snek/static/tts.js | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/snek/static/tts.js diff --git a/src/snek/static/tts.js b/src/snek/static/tts.js new file mode 100644 index 0000000..dbe5e5b --- /dev/null +++ b/src/snek/static/tts.js @@ -0,0 +1,69 @@ +class SnekSpeaker extends HTMLElement { + + _enabled = false + + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + + // Optionally show something in the DOM + this.shadowRoot.innerHTML = ``; + + this._utterance = new SpeechSynthesisUtterance(); + this._selectVoice(); + } + toggle() { + if (window.speechSynthesis.speaking) { + window.speechSynthesis.pause(); + } else { + window.speechSynthesis.resume(); + } + } + stop() { + window.speechSynthesis.cancel(); + } + disable() { + this._enabled = false + } + enable() { + this._enabled = true + } + set enabled(val) { + if (val) { + this.enable() + } else { + this.disable() + } + } + get enabled() { + return this._enabled + } + _selectVoice() { + const updateVoice = () => { + const voices = window.speechSynthesis.getVoices(); + const maleEnglishVoices = voices.filter(voice => + voice.lang.startsWith('en') && voice.name.toLowerCase().includes('male') + ); + if (maleEnglishVoices.length > 0) { + this._utterance.voice = maleEnglishVoices[0]; + } + }; + + updateVoice(); + // Some browsers load voices asynchronously + window.speechSynthesis.onvoiceschanged = updateVoice; + } + + speak(text) { + if(!this._enabled) return + + if (!text) return; + + this._utterance.text = text; + window.speechSynthesis.speak(this._utterance); + } +} + +// Define the element +customElements.define('snek-speaker', SnekSpeaker); +