akmdmc / 翻译

// ==UserScript==
// @name         翻译
// @namespace    www.akmdc.com
// @version      0.1.0
// @description  阅读各文档时直接翻译!仅支持英译中!
// @require      https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js
// @require      http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js
// @license		 MIT
// @connect api.fanyi.baidu.com

// @grant GM_setValue

// @grant GM_getValue

// @grant GM_setClipboard

// @grant GM_log

// @grant GM_xmlhttpRequest

// @grant unsafeWindow

// @grant window.close

// @grant window.focus
// @author       akmdmc
// @match        https://*/*
// @icon         https://edu-wenku.bdimg.com/v1/pc/2020%E6%96%B0%E9%A6%96%E9%A1%B5/wenku-header-icon.ico
// ==/UserScript==

(
  function(){
         const body = document.querySelector('body')
  let nowTanslateBtn = null; //当前翻译按钮
  let nowTranslateContent = null; //当前翻译内容
  let curRregion = ""; //当前选中的文字

  // 一下需要自己去百度翻译申请appid和key
  const baiduAppId = ""; // 百度翻译appid
  const baiduKey = ""; // 百度翻译key

  // 流程 createStartBtn() -> translateBtn()  -> translateContent() -> baiduTranslate()

  //创建启动按钮
  createStartBtn();

  //获取选中的文字
  body.addEventListener('mouseup', (e) => {
    const selection = getSelection();
    curRregion = selection.toString();
  })
  //翻译按钮
  function translateBtn(x, y) {
    if (nowTanslateBtn) {
      nowTanslateBtn.remove();
    }
    if (!curRregion) return;
    body.appendChild(createTanslateBtn(x, y));
  }
  //翻译内容
  function translateContent(x, y) {
    if (nowTranslateContent) {
      nowTranslateContent.remove();
    }
    nowTranslateContent = createTanslateContent(x, y);
    body.appendChild(nowTranslateContent);
    baiduTranslate(curRregion);//翻译
  }
  //百度翻译
  async function baiduTranslate(string) {
    const salt = Math.random().toString(36).substr(3);
    let q = string;
    const str1 = baiduAppId + q + salt + baiduKey;
    let sign = md5(str1);
    const url = `http://api.fanyi.baidu.com/api/trans/vip/translate?q=${q}&from=en&to=zh&appid=${baiduAppId}&salt=${salt}&sign=${sign}`;
    await GM_xmlhttpRequest({
      method: 'GET',
      url: url,
      onload: async (r) => {
        try {
          nowTranslateContent.innerText = JSON.parse(r.responseText).trans_result[0].dst;
        }
        catch {
          nowTranslateContent.innerText = "翻译失败(少选点试试?)";
        }
        //关闭按钮
        nowTranslateContent.appendChild(createCloseBtn());
      }
    })
  }
  //创建翻译按钮
  function createTanslateBtn(x, y) {
    const div = document.createElement('button');
    div.style.position = 'fixed';
    div.style.left = x + 5 + 'px';
    div.style.top = y - 20 + 'px';
    div.style.backgroundColor = 'rgba(255,255,255,1)';
    div.style.width = '40px';
    div.style.height = '20px';
    div.style.textAlign = 'center';
    div.style.fontSize = 6 + 'px';
    div.style.border = "none";
    div.style.zIndex = 999999;
    div.innerText = "翻译"
    nowTanslateBtn = div;
    div.addEventListener("click", async (e) => {
      e.stopPropagation();
      await translateContent(x, y);
      if (nowTanslateBtn) {
        nowTanslateBtn.remove();
      }
    })
    return div;
  }
  //创建翻译内容
  function createTanslateContent(x, y) {
    const div = document.createElement('div');
    div.style.position = 'fixed';
    div.style.left = x + 5 + 'px';
    div.style.top = y + 5 + 'px';
    div.style.maxWidth = '200px';
    div.style.backgroundColor = 'rgba(255,255,255,1)';
    div.style.padding = '20px';
    div.style.textAlign = 'center';
    div.style.fontSize = 12 + 'px';
    div.style.border = "1px solid rgb(0,0,0,0)";
    div.style.borderRadius = "5px";
    div.style.boxShadow = "0 0 5px 2px rgba(0,0,0,0.2)";
    div.style.userSelect = "none";
    let chaX = 0;
    let chaY = 0;
    let start = false;
    div.addEventListener("mousedown", (e) => {
      e.stopPropagation();
      start = true;
      chaX = e.clientX - div.style.left.slice(0, div.style.left.length - 2)
      chaY = e.clientY - div.style.top.slice(0, div.style.top.length - 2)
    })
    window.addEventListener("mousemove", (e) => {
      if (!start) return;
      e.stopPropagation();
      div.style.left = e.clientX - chaX + 'px';
      div.style.top = e.clientY - chaY + 'px'
    })
    window.addEventListener("mouseup", (e) => {
      e.stopPropagation();
      start = false;
    })
    return div;
  }
  //创建关闭按钮
  function createCloseBtn() {
    const close = document.createElement('button');
    close.innerText = "X";
    close.style.position = 'absolute';
    close.style.right = 0;
    close.style.top = 0;
    close.style.width = '20px';
    close.style.padding = '2px';
    close.style.backgroundColor = 'rgba(255,255,255,1)';
    close.style.border = "none";
    close.style.fontSize = 10 + 'px';
    close.style.textAlign = 'center';
    close.style.borderRadius = "5px";
    close.addEventListener("mouseover", (e) => {
      e.stopPropagation();
      close.style.backgroundColor = 'rgba(255,0,0,1)';
      close.style.color = 'white';
    })
    close.addEventListener("mouseout", (e) => {
      e.stopPropagation();
      close.style.backgroundColor = 'rgba(255,255,255,1)';
      close.style.color = 'black';
    })
    close.addEventListener("click", (e) => {
      e.stopPropagation();
      if (nowTranslateContent) {
        nowTranslateContent.remove();
        nowTranslateContent = null;
      }
    })
    return close;
  }
  //创建启动按钮
  function createStartBtn() {
    let isStart = false;
    const div = document.createElement('button');
    div.style.position = 'fixed';
    div.style.left = -52 + 'px';
    div.style.top = '30%';
    div.style.backgroundColor = 'rgba(34, 24, 219,1)';
    div.style.color = 'white';
    div.style.width = '60px';
    div.style.height = '20px';
    div.style.textAlign = 'center';
    div.style.fontSize = 6 + 'px';
    div.style.border = "none"
    div.style.transition = "left 0.5s";
    div.innerText = "启动"
    div.classList.add("startBtn");
    div.addEventListener("mouseover", (e) => {
      e.stopPropagation();
      div.style.left = 0;
    })
    div.addEventListener("mouseout", (e) => {
      e.stopPropagation();
      div.style.left = -52 + 'px';
    })
    div.addEventListener("click", (e) => {
      e.stopPropagation();
      if (isStart) {
        window.removeEventListener('click', windowClick);
        div.innerText = "启动";
        div.style.backgroundColor = 'rgba(34, 24, 219,1)';
        isStart = false;
        return;
      }
      else {
        window.addEventListener('click', windowClick);
        div.innerText = "关闭";
        div.style.backgroundColor = 'rgba(219, 24, 24,1)';
        isStart = true;
        return;
      }
    })
    body.appendChild(div);
    return {
      isStart,
    }
  }
  //点击事件
  const windowClick = (e) => {
    if (nowTranslateContent) return;
    translateBtn(e.clientX, e.clientY)
  }

      }
)();