Last active
January 8, 2025 06:40
-
-
Save dotproto/febf568f177dca9a7cf4ede329e53667 to your computer and use it in GitHub Desktop.
ES2015 Text to Speech bookmarklet (Alt+I). Set up: Copy and paste the contents of this gist into a new bookmark. Use: Select some text and click the bookmarklet to start speaking. Once activated on a page, you can use `Alt+I` or `Alt+1` to speak the selected text. Speech Synthesis API Info: https://developer.mozilla.org/en-US/docs/Web/API/Speech…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
if (window.runTTS === undefined) { | |
const MAX_TRIES = 20; | |
const TRY_DELAY = 100; | |
/* Adjust voice speed. Default = 1 */ | |
if (navigator.userAgent.includes("Macintosh")) { | |
window.ttsPlaybackSpeed = 1.2; | |
} else if (navigator.userAgent.includes("Windows")) { | |
window.ttsPlaybackSpeed = 5; | |
} else { | |
window.ttsPlaybackSpeed = 1; | |
} | |
/* Text to Speech function. Adjust the values of `ttsPlaybackSpeed` increase/decrease the playback speed. */ | |
function runTTS(tries = 0) { | |
const text = window.getSelection().toString().trim(); | |
/* Stop any currently playing TTS and empty the queue */ | |
if (speechSynthesis.speaking) { | |
return speechSynthesis.cancel(); | |
} | |
/* Only continue if the current selection contains text */ | |
if (!text) { | |
return; | |
} | |
/* Start speaking the currently selected text at the user-define speed*/ | |
const msg = new SpeechSynthesisUtterance(); | |
msg.rate = window.ttsPlaybackSpeed || 1; | |
msg.text = text; | |
if (navigator.userAgent.includes("Macintosh")) { | |
/* Chrome defaults to using "Samantha" but Firefox does not */ | |
for (const voice of speechSynthesis.getVoices()) { | |
if (voice.name == "Samantha") { | |
msg.voice = voice; | |
break; | |
} | |
} | |
/* Sometimes the full voice list won't load the first time it's retrieved (observed in Firefox on macOS) */ | |
if (msg.voice?.name !== "Samantha") { | |
if (tries < MAX_TRIES) { | |
setTimeout(() => runTTS(++tries), TRY_DELAY); | |
return; | |
} else { | |
console.log(`Voice did not load within ${MAX_TRIES * TRY_DELAY} ms.`); | |
return; | |
} | |
} else { | |
if (tries > 0) { | |
console.log(`Took ${tries} tries (${tries * TRY_DELAY} ms) to load desired voice.`) | |
} | |
} | |
} | |
speechSynthesis.speak(msg); | |
} | |
/* Speak the current selection when the user presses Alt+I (Mac: Option+I) or Alt+1 (Mac: Option+1) */ | |
document.addEventListener("keydown", (e) => { | |
if (!e.metaKey && !e.shiftKey && !e.ctrlKey && !e.repeat) { | |
if ( | |
(e.code === "Digit1" && e.altKey) || | |
(e.code === "KeyI" && e.altKey) | |
) { | |
e.preventDefault(); | |
e.stopPropagation(); | |
window.runTTS(); | |
} | |
} | |
}, { capture: true }); | |
window.runTTS = runTTS; | |
} | |
/* Start speaking the current selection when the bookmarklet is clicked */ | |
window.runTTS(); | |
} |
Good call, @rongjiecomputer. I've updated the script with that and a couple other tweaks.
- Change key bindings from Ctrl+S (typically used to save a page) to Alt+I or Alt+1
- Introduce per-OS default speech speed
- Make speech speed controllable at runtime by modifying
window.ttsPlaybackSpeed
- Default to using the "Samantha" voice on macOS
- Updated to improve behavior in Firefox
Changes in the latest revision
- Updated keyboard shortcut logic to ignore other modifier keys. This fixes a bug where Cmd+Opt+I would not open devtools after the bookmarklet was triggered.
- Adjusted timeouts to increase the likelihood that the desired voice is used in Firefox on macOS.
- Also added additional logging to help investigate when the desired voice is not used.
- Non-functional: moved initialization logic into the initial if check to see if
runTTS
is defined. This makes it so re-triggering the bookmarklet on a page where it has already been used only triggers the existing script to run again.
Hi, @dotproto! I just stumbled upon this bookmarklet you've created and figured you may find my service bookmarkl.ink helpful. You can make your bookmarklet a little easier to share using https://bookmarkl.ink/dotproto/febf568f177dca9a7cf4ede329e53667. Further, you can add a title and description using the following.
// bookmarklet-title: Selection TTS
// bookmarklet-about: Read the selected text aloud using Text to Speech (TTS).
Lastly, you could make the bookmarklet configurable by adding a speed variable.
// bookmarklet-var(number): speed
const adjusted = 1 + Math.max(-1.0, Math.min(1.0, (speed ?? 0) / 10)); // It may be helpful to massage this number
PS: You can use TypeScript if that's your cup of tea.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You should add
e.preventDefault()
inside if block at line 16 so that Ctrl+S does not trigger "save page" in Chrome.