智能语音点读机
// ==UserScript==
// @name 智能语音点读机
// @namespace https://bbs.tampermonkey.net.cn/
// @version 0.4.4
// @description 哪里不会点哪里~!选中文本自动语音播报~!语音翻译功能需自行申请翻译api,填写正确后开启翻译即可(开启后选中文本在鼠标附近会出现翻译按钮)~!
// @author 张仨
// @match *://*/*
// @run-at document-end
// @grant unsafeWindow
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @connect fanyi-api.baidu.com
// @require https://cdn.jsdelivr.net/npm/ddkr-zhangsan@1.0.0/md5.js
// @require https://cdn.jsdelivr.net/npm/menu-zhangsan@1.0.0/registermenucommand.js
// ==/UserScript==
(function () {
'use strict';
var pitch = GM_getValue('mypitch') || 1;
var rate = GM_getValue('myrate') || 0.7;
function speak(sentence) {
var utterance = new SpeechSynthesisUtterance(sentence);
utterance.pitch = pitch;
utterance.rate = rate;
window.speechSynthesis.speak(utterance);
};
window.addEventListener('mouseup', () => {
var txt = window.getSelection();
speak(txt, pitch, rate)
});
function newAjax() {
var appid = GM_getValue('myappid');
var key = GM_getValue('mykey');
var salt = (new Date).getTime();
var query = window.getSelection().toString();
var from = 'auto';
var pattern = new RegExp("[\u4E00-\u9FA5]+");
var to = pattern.test(query) ? 'en' : 'zh';
var str1 = appid + query + salt + key;
var sign = MD5(str1);
GM_xmlhttpRequest({
method: "POST",
responseType: "json",
headers: {
"Content-type": "application/x-www-form-urlencoded"
},
data: `q=${encodeURI(query)}&from=${from}&to=${to}&appid=${appid}&salt=${salt}&sign=${sign}`,
url: "https://fanyi-api.baidu.com/api/trans/vip/translate?",
onload: function (xhr) {
if (xhr.response.error_code) {
var flag = confirm("请检查你的appid与密钥是否正确,如未申请API可点击对话框中的确定按钮跳转到百度翻译开放平台进行申请通用翻译API");
if (flag) {
window.open("https://api.fanyi.baidu.com/product/11");
}
} else {
var TextTranslate = xhr.response.trans_result[0].dst;
speak(TextTranslate, pitch, rate);
}
}
});
};
var translate = GM_getValue('mytranslate');
if (translate) {
var TranslationButton = document.body.appendChild(document.createElement("button"));
TranslationButton.id = "speech-translation";
TranslationButton.innerHTML = `
<span id='btn-translation'>翻译</span>
<style>
#speech-translation{
position: fixed;
width: 60px;
height: 30px;
cursor: pointer;
z-index: 9999999;
border-style: none !important;
outline: none !important;
border-radius: 50px !important;
background: #36c8b0 !important;
box-shadow: 6px 6px 13px #79e6d3,
-6px -6px 13px #ffffff !important;
display: none;
}
#btn-translation{
color: #0078d4 !important;
font-size: 18px !important;
text-align: center !important;
white-space: nowrap !important;
font-family: Playball, cursive;
}
</style>
`;
TranslationButton.addEventListener('mouseup', function (e) {
e.stopPropagation();
});
TranslationButton.onclick = function () {
newAjax();
};
document.addEventListener("mouseup", (event) => {
event = event || window.event;
var left = event.clientX;
var top = event.clientY;
var LeftOffset = GM_getValue('myleftOffset') || 50;
var UpOffset = GM_getValue('myupOffset') || 0;
var getSelection = window.getSelection().toString();
if (getSelection != '') {
TranslationButton.style.display = 'block';
TranslationButton.style.left = left + LeftOffset + "px";
TranslationButton.style.top = top + UpOffset + "px";
} else {
TranslationButton.style.display = 'none';
};
});
};
var myFormBox = document.createElement("div");
if (window.top == window.self) {
document.body.appendChild(myFormBox);
};
myFormBox.className = 'myform-box';
myFormBox.innerHTML = `
<form>
<p>百度翻译api</p>
<input type="text" placeholder="appid"><br>
<input type="text" placeholder="key"><br>
<input type="button" value="保存"><br>
</form>
<style>
.myform-box {
position: fixed;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
z-index: 99999;
display: none;
}
.myform-box form {
padding: 3em;
border-radius: 20px;
border-left: 1px solid rgba(255, 255, 255, 0.3);
border-top: 1px solid rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
box-shadow: 20px 20px 40px -6px rgba(0, 0, 0, 0.2);
text-align: center;
position: relative;
transition: all 0.2s ease-in-out;
background: linear-gradient(90deg, #e70cd99a, #0314fc8e);
}
.myform-box p {
font-weight: 500;
color: #fff;
opacity: 0.7;
font-size: 26px;
margin-top: 0;
margin-bottom: 60px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}
.myform-box input {
background: transparent;
width: 200px;
padding: 1em;
margin-bottom: 2em;
border: none;
border-left: 1px solid rgba(255, 255, 255, 0.3);
border-top: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 5000px;
backdrop-filter: blur(5px);
box-shadow: 4px 4px 60px rgba(0, 0, 0, 0.2);
color: #fff;
font-family: Montserrat, sans-serif;
font-weight: 500;
transition: all 0.2s ease-in-out;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}
.myform-box input:hover {
background: rgba(255, 255, 255, 0.1);
box-shadow: 4px 4px 60px 8px rgba(0, 0, 0, 0.2);
}
.myform-box input[type=email]:focus,
.myform-box input[type=password]:focus {
background: rgba(255, 255, 255, 0.1);
box-shadow: 4px 4px 60px 8px rgba(0, 0, 0, 0.2);
}
.myform-box input[type=button] {
margin-top: 10px;
width: 150px;
font-size: 16px;
cursor: pointer;
}
.myform-box input[type=button]:active {
background: rgba(255, 255, 255, 0.2);
}
.myform-box input::placeholder {
font-family: Montserrat, sans-serif;
font-weight: 400;
color: #fff;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
}
.myform-box input:focus,
.myform-box button:focus {
outline: none;
}
</style>`
GM_createMenu.add([
{
on: {
name: "✅ 开启语音翻译功能",
accessKey: 'Y',
callback: function () {
translate = true;
GM_setValue('mytranslate', translate);
}
},
off: {
name: "❌ 关闭语音翻译功能",
accessKey: 'X',
callback: function () {
translate = false;
GM_setValue('mytranslate', translate);
}
}
},
{
name: "🔑 填写百度翻译api",
accessKey: 'H',
callback: function () {
var myform = document.querySelectorAll('.myform-box input');
myFormBox.style.display = 'block';
myform[2].addEventListener('click', () => {
if (myform[0].value != '' && myform[1].value != '') {
GM_setValue('myappid', myform[0].value);
GM_setValue('mykey', myform[1].value);
}
myFormBox.style.display = 'none';
});
}
},
{
name: "🎤 调整音调",
accessKey: 'E',
callback: function () {
var mypitch = prompt("音调,取值范围(0 - 2) 默认值: 1");
if (mypitch != null && mypitch != "") {
GM_setValue('mypitch', mypitch);
}
}
},
{
name: "🎵 调整语速",
accessKey: 'W',
callback: function () {
var myrate = prompt("语速,取值范围(0.1 - 10) 默认值: 0.7");
if (myrate != null && myrate != "") {
GM_setValue('myrate', myrate);
}
}
},
{
name: "🔧 调整翻译按钮水平偏移量",
accessKey: 'T',
callback: function () {
var myleftOffset = prompt("翻译按钮偏移量,数值越大越往右偏移,默认值:50");
if (myleftOffset != null && myleftOffset != "") {
GM_setValue('myleftOffset', parseInt(myleftOffset));
}
}
},
{
name: "🔧 调整翻译按钮垂直偏移量",
accessKey: 'G',
callback: function () {
var myupOffset = prompt("翻译按钮偏移量,数值越大越往下偏移,默认值:0");
if (myupOffset != null && myupOffset != "") {
GM_setValue('myupOffset', parseInt(myupOffset));
}
}
}
]);
GM_createMenu.create({ storage: true });
})();