🏠 Home 

Wanikani s2speak

Highlight the text, and press s to speak, anywhere on the website

// ==UserScript==
// @name         Wanikani s2speak
// @namespace    http://polvcode.dev/
// @version      0.1.1
// @description  Highlight the text, and press s to speak, anywhere on the website
// @author       Pacharapol Withayasakpunt
// @match        https://*.wanikani.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/xregexp-all.js
// @grant        none
// ==/UserScript==
(function () {
window.addEventListener("keydown", (ev) => {
if (ev.code === 'KeyS') {
const lang = 'ja'
const s = window.getSelection().toString();
if (s && XRegExp('[\\p{Han}\\p{Hiragana}\\p{Katakana}]').test(s)) {
speak(s, lang);
}
}
});
const allVoices = {}
speechSynthesis.getVoices().map(v => {
allVoices[v.lang] = v.lang
})
speechSynthesis.onvoiceschanged = () => {
speechSynthesis.getVoices().map(v => {
allVoices[v.lang] = v.lang
})
}
function speak (s, lang) {
const voices = Object.keys(allVoices)
const stage1 = () => voices.filter((v) => v === lang)[0]
const stage2 = () => {
const m1 = lang.substr(0, 2)
const m2 = lang.substr(3, 2)
const r1 = new RegExp(`^${m1}[-_]${m2}`, 'i')
return voices.filter((v) => r1.test(v))[0]
}
const stage3 = () => {
const m1 = lang.substr(0, 2).toLocaleLowerCase()
return voices.filter((v) => v.toLocaleLowerCase().startsWith(m1))[0]
}
lang = stage1() || stage2() || stage3() || ''
if (lang) {
const utterance = new SpeechSynthesisUtterance(s)
utterance.lang = lang
speechSynthesis.speak(utterance)
}
}
})()