enlish
当前为
// ==UserScript==
// @name Read the section highlight
// @namespace http://tampermonkey.net/
// @version 2.4
// @license MIT
// @description enlish
// @author an vu an
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const menu = document.createElement("div");
menu.style.position = "fixed";
menu.style.bottom = "20px";
menu.style.right = "20px";
menu.style.zIndex = "9999";
menu.style.background = "#00000000";
menu.style.border = "1px solid #ccc";
menu.style.borderRadius = "8px";
menu.style.padding = "10px";
menu.style.fontSize = "14px";
menu.style.fontFamily = "sans-serif";
menu.style.boxShadow = "0 4px 12px rgba(0,0,0,0.3)";
document.body.appendChild(menu);
menu.innerHTML = `
<div style="margin-bottom:6px; font-weight:bold;">🔊 Read</div>
<button id="speakBtn">▶️ Read 1 time</button>
<button id="speakLoopBtn">🔁 Read continuously</button>
<button id="stopBtn">⏹ Stop</button>
`;
const speakBtn = menu.querySelector("#speakBtn");
const speakLoopBtn = menu.querySelector("#speakLoopBtn");
const stopBtn = menu.querySelector("#stopBtn");
let selectedVoice = null;
let loopMode = false;
function loadVoices() {
const voices = speechSynthesis.getVoices();
const vi = voices.find(v => v.lang.startsWith("vi"));
if (vi) {
selectedVoice = vi;
} else {
selectedVoice = voices[0]; // fallback
}
}
window.speechSynthesis.onvoiceschanged = loadVoices;
loadVoices();
function speakText(text) {
const synth = window.speechSynthesis;
synth.cancel();
text = text.replace(/[^\p{L}\p{N}\s.,!?]/gu, "");
if (!text) {
alert("❗ No valid content to read");
return;
}
const utter = new SpeechSynthesisUtterance(text);
if (selectedVoice) {
utter.voice = selectedVoice;
utter.lang = selectedVoice.lang;
} else {
utter.lang = "vi-VN";
}
utter.onend = () => {
if (loopMode) speakText(text);
};
synth.speak(utter);
}
speakBtn.addEventListener("click", () => {
loopMode = false;
const text = window.getSelection().toString().trim();
if (!text) {
alert("❗ Hãy bôi xanh văn bản để đọc");
return;
}
speakText(text);
});
speakLoopBtn.addEventListener("click", () => {
loopMode = true;
const text = window.getSelection().toString().trim();
if (!text) {
alert("❗ Highlight text to read");
return;
}
speakText(text);
});
stopBtn.addEventListener("click", () => {
loopMode = false;
window.speechSynthesis.cancel();
});
})();