您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
[SNOLAB] Speak latest telegram message With TTS technology just in your browser. 1. Speak latest message your received 2. Speak what you just send. 3. Send what you saying
// ==UserScript== // @deprecated Use my new script [SNOLAB] [Mulango] Telegram Translator // @name [SNOLAB] I Heard Telegram Speaking // @namespace [email protected] // @author [email protected] // @version 0.3.1 // @description [SNOLAB] Speak latest telegram message With TTS technology just in your browser. 1. Speak latest message your received 2. Speak what you just send. 3. Send what you saying // @match https://*.telegram.org/z/ // @grant none // @run-at document-start // @license GPL-3.0+ // @supportURL https://github.com/snomiao/userscript.js/issues // @contributionURL https://snomiao.com/donate // ==/UserScript== /** * 1. Speak latest message your received * 2. Speak what you just send. * 3. Send what you saying */ main(); async function main() { if (!globalThis.speechSynthesis) return alert( "unable to access speechSynthesis service, please update your browser" ); // polyfill and error detect globalThis.SpeechRecognition = globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition || globalThis.mozillaSpeechRecognition; if (!globalThis.SpeechRecognition) return alert( "unable to access speechSynthesis service, please update your browser" ); listeningLooper().then(); speakingLooper().then(); speakingMySelfLooper().then(); } async function listeningLooper() { while (1) await tgSend( await messageSendingConfirmed(await heard(await userLangGet())) ); } async function speakingLooper() { const changed = edger(""); while (1) { await speak(changed(latestMessage())); await delay1s(); } } async function speakingMySelfLooper() { const changed = edger(""); while (1) { await speak2nd(changed(latestMyMessage())); await delay1s(); } } // async function titleLooper(){ // const titleGet = ()=>document.querySelector('.selected h3').innerHTML // const titleUpdate = (t)=>t&& // while (1) {await titleUpdate(changed(titleGet())); await delay1s()} // } async function heard(lang = "en-US") { globalThis.SpeechRecognition = globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition || globalThis.mozillaSpeechRecognition; console.log("listening"); const result = await new Promise((resolve, reject) => { const sr = new globalThis.SpeechRecognition(); sr.continuous = true; sr.lang = lang; sr.onresult = (e) => { const result = e?.results?.[0]?.[0]?.transcript || ""; resolve(result); }; sr.onerror = () => resolve(""); sr.start(); }); console.log("heard", result); if (tgMessageEmptyQ()) await tgMessageInput(result + " //heard"); await new Promise((r) => setTimeout(r, 64)); return result; } async function messageSendingConfirmed(s = "") { const r = s.match(/^(话说|話說|你看|呼叫|CQ |もし)(?:\1)(?<msg>.*)$/i) ?.groups?.msg; if (!r) return; await speak("发送 " + r); return r; } async function speak(s) { if (!s) return; // console.error('say empty msg') console.log("saying " + s); await waitFor(voicesAvailiable); const utter = new SpeechSynthesisUtterance(s); utter.voice = await userVoiceGet(); utter.rate = Math.min(Math.max(1, s.length / 60), 4); if (speechSynthesis.speaking) speechSynthesis.cancel(); speechSynthesis.speak(utter); } async function speak2nd(s) { if (!s) return; // console.error('say empty msg') if (speechSynthesis.speaking) return; // low priority console.log("saying " + s); await waitFor(voicesAvailiable); const utter = new SpeechSynthesisUtterance(s); utter.voice = await userVoiceGet2nd(); utter.rate = Math.min(Math.max(1, s.length / 60), 4); if (speechSynthesis.speaking) speechSynthesis.cancel(); speechSynthesis.speak(utter); } function voicesAvailiable() { return globalThis.speechSynthesis.getVoices().length !== 0; } function latestMessage() { return [...document.querySelectorAll(".Message:not(.own) .text-content")] .map((e) => e.textContent) .reverse()[0]; } function latestMyMessage() { return [...document.querySelectorAll(".Message.own .text-content")] .map((e) => e.textContent) .reverse()[0]; } function edger(init) { return (e) => (e !== init ? (init = e) : undefined); } async function tgSend(s) { if (!s) return; await tgMessageInput(s); await new Promise((r) => setTimeout(r, 1e3)); document.querySelector("#editable-message-text").dispatchEvent( new KeyboardEvent("keydown", { bubbles: true, cancellable: true, composed: true, key: "Enter", code: "Enter", }) ); } function tgMessageEmptyQ() { const content = document.querySelector("#editable-message-text").innerHTML; return content === "" || content.endsWith(" //heard"); } async function tgMessageInput(s) { document.querySelector("#editable-message-text").innerHTML = s; await new Promise((r) => setTimeout(r, 1e3)); document.querySelector("#editable-message-text").dispatchEvent( new InputEvent("input", { bubbles: true, cancellable: false, inputType: "insertText", composed: true, }) ); } async function waitFor(cond) { while (!cond()) await delay1s(); } async function delay1s() { await new Promise((r) => setTimeout(r, 1e3)); } async function userLangGet() { return (await userVoiceGet()).lang; } async function userVoiceGet() { return (await voicesForUserLang())[0]; } async function userVoiceGet2nd() { const ls = await voicesForUserLang(); return ls[1] || ls[0]; } async function voicesForUserLang() { await waitFor(voicesAvailiable); return navigator.languages .map((nlang) => globalThis.speechSynthesis .getVoices() .filter(({ lang }) => lang.startsWith(nlang)) .reverse() ) .flat(); // return globalThis.speechSynthesis.getVoices().filter(({ lang }) => navigator.languages.find(nlang => lang.startsWith(nlang))).reverse(); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址