右下角出现一个一键翻译的按钮,点击即可一键翻译当前页面
- // ==UserScript==
- // @name Yandex一键翻译
- // @namespace http://tampermonkey.net/
- // @version 0.0.3
- // @description 右下角出现一个一键翻译的按钮,点击即可一键翻译当前页面
- // @author thunder-sword
- // @match *://*/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=yandex.com
- // @license MIT
- // @grant GM_xmlhttpRequest
- // @grant GM_setValue
- // @grant GM_getValue
- // @connect translate.yandex.com
- // ==/UserScript==
- //系统变量
- var g###ode='';
- class NetworkError extends Error {
- constructor(message) {
- super(message);
- this.name = "NetworkError";
- }
- }
- // 封装GM_xmlhttpRequest为Promise
- function httpRequest(options) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- ...options,
- onload: response => resolve(response),
- onerror: error => reject(error)
- });
- });
- }
- //作用:生成toast,让其在toast_container中,显示在页面中上部,会永久性向页面添加一个id为ths_toast_container的div标签
- function showStackToast(message, backcolor='rgb(76, 175, 80)', timeout=3000){
- //没有容器则生成容器
- let box=document.querySelector("body > div#ths_toast_container");
- if(!box){
- box=document.createElement('div');
- box.id="ths_toast_container";
- box.style.cssText = `
- position: fixed;
- top: 10px;
- left: 50%;
- transform: translateX(-50%);
- right: 10px;
- width: 300px;
- height: auto;
- display: flex;
- z-index: 9999;
- flex-direction: column-reverse;`;
- document.body.appendChild(box);
- }
- //创建toast
- const toast = document.createElement('div');
- toast.innerText = message;
- toast.style.cssText = `
- padding: 10px;
- background-color: ${backcolor};
- color: rgb(255, 255, 255);
- border-radius: 10px;
- font-size: 24px;
- font-weight: bold;
- text-align: center;
- box-shadow: rgb(0 0 0 / 30%) 0px 5px 10px;
- opacity: 1;
- transition: opacity 0.3s ease-in-out 0s;
- z-index: 9999;
- margin: 5px;
- `;
- box.appendChild(toast);
- toast.style.opacity = 1;
- if(timeout > 0){
- setTimeout(() => {
- toast.style.opacity = 0;
- setTimeout(() => {
- box.removeChild(toast);
- }, 300);
- }, timeout);
- }
- return toast;
- }
- //作用:获取gpc
- async function getGCP(){
- console.log("尝试获取token……");
- showStackToast("尝试获取token……");
- const data = await httpRequest({
- url: 'https://translate.yandex.com/',
- }).then(function(response) {
- return response.responseText;
- }).catch(error => {
- if (error instanceof NetworkError) {
- console.error("Network error: ", error.message);
- } else {
- console.error("Other error: ", error);
- alert("获取数据失败,请联系开发者");
- }
- });
- let fIndex=data.indexOf('GC_STRING');
- if(-1===fIndex){
- console.log(data);
- console.log("没有找到GC_STRING");
- showStackToast("获取token失败,请联系开发者", "red");
- }
- let gStart=fIndex+13;
- g###ode=data.substr(gStart, data.indexOf("'", gStart)-gStart);
- showStackToast("获取token成功");
- //设置到全局变量中
- GM_setValue("g###ode", g###ode);
- }
- //作用:翻译一个页面
- async function translatePage(url){
- if(!g###ode){
- if(!GM_getValue("g###ode")){
- await getGCP();
- } else{
- g###ode=GM_getValue("g###ode");
- }
- }
- //尝试使用g###ode打开翻译页面
- window.open(`https://translate.yandex.com/translate?view=compact&lang=en-zh&gcp=${g###ode}&url=${url}`);
- }
- //版本号:v0.0.2
- //作用:创建一个在右下角出现的悬浮窗按钮,多个按钮会自动排序,点击即可执行对应函数
- function createFloatButton(name, func){
- //没有容器则生成容器
- let box=document.querySelector("body > div#ths_button_container");
- if(!box){
- box=document.createElement('div');
- box.id="ths_button_container";
- box.style.cssText = `
- position: fixed;
- bottom: 10px;
- right: 10px;
- min-height: 30px; /* 设置一个最小高度,确保容器有一定高度 */
- display: flex;
- z-index: 9999;
- flex-direction: column;
- `;
- document.body.appendChild(box);
- }
- // 创建一个 div 元素
- var floatWindow = document.createElement('div');
- // 设置 div 的内容
- //floatWindow.innerHTML = '点我执行代码';
- floatWindow.innerHTML = name;
- // 设置 div 的样式
- floatWindow.style.cssText = `
- padding: 5px;
- background-color: #333;
- color: #fff;
- border-radius: 5px;
- font-size: 16px;
- text-align: center;
- opacity: 1;
- z-index: 9999;
- margin: 5px;
- cursor: pointer; /* 鼠标可以选中 */
- `;
- // 将悬浮窗的优先级提高
- floatWindow.style.zIndex = "99999";
- var isDragging = false;
- var currentX;
- var currentY;
- var initialX;
- var initialY;
- var xOffset = 0;
- var yOffset = 0;
- var cursorX;
- var cursorY;
- floatWindow.addEventListener("mousedown", function(e) {
- if (!isDragging) {
- cursorX = e.clientX;
- cursorY = e.clientY;
- initialX = cursorX - xOffset;
- initialY = cursorY - yOffset;
- isDragging = true;
- }
- });
- floatWindow.addEventListener("mousemove", function(e) {
- if (isDragging) {
- e.preventDefault();
- currentX = e.clientX - initialX;
- currentY = e.clientY - initialY;
- xOffset = currentX;
- yOffset = currentY;
- setTranslate(currentX, currentY, floatWindow);
- }
- });
- floatWindow.addEventListener("mouseup", async function(e) {
- initialX = currentX;
- initialY = currentY;
- isDragging = false;
- // 如果点击时鼠标的位置没有改变,就认为是真正的点击
- if (cursorX === e.clientX && cursorY === e.clientY) {
- await func();
- }
- });
- // 为悬浮窗添加事件处理程序,用来监听触摸开始和触摸移动事件
- // 这些事件处理程序的实现方式与上面的鼠标事件处理程序类似
- floatWindow.addEventListener('touchstart', (event) => {
- if (!isDragging) {
- cursorX = event.touches[0].clientX;
- cursorY = event.touches[0].clientY;
- initialX = cursorX - xOffset;
- initialY = cursorY - yOffset;
- isDragging = true;
- }
- });
- floatWindow.addEventListener('touchmove', (event) => {
- if (isDragging) {
- currentX = event.touches[0].clientX - initialX;
- currentY = event.touches[0].clientY - initialY;
- xOffset = currentX;
- yOffset = currentY;
- setTranslate(currentX, currentY, floatWindow);
- }
- });
- // 为悬浮窗添加事件处理程序,用来监听触摸结束事件
- // 这个事件处理程序的实现方式与上面的鼠标事件处理程序类似
- floatWindow.addEventListener('touchend', async () => {
- initialX = currentX;
- initialY = currentY;
- isDragging = false;
- // 如果点击时鼠标的位置没有改变,就认为是真正的点击
- if (cursorX === event.touches[0].clientX && cursorY === event.touches[0].clientY) {
- await func();
- }
- });
- function setTranslate(xPos, yPos, el) {
- el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
- }
- //将悬浮窗添加到box元素中
- box.appendChild(floatWindow);
- }
- //作用:主函数,添加翻译当前页面的按钮
- function mainFunction(){
- createFloatButton("一键翻译", ()=>{
- translatePage(window.location.href);
- });
- }
- (function() {
- 'use strict';
- mainFunction();
- })();