您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动翻译文章题目材料, 解析听力材料无限听, 内置翻译助手英汉互译, 解除切屏限制, 解除右键菜单与划词限制
当前为
// ==UserScript== // @name unipus iTEST助手 // @namespace http://blog.z31.xyz/ // @version 2.1.6 // @description 自动翻译文章题目材料, 解析听力材料无限听, 内置翻译助手英汉互译, 解除切屏限制, 解除右键菜单与划词限制 // @author simonkimi // @match *://itestcloud.unipus.cn/itest-api/itest/s/answer/** // @match *://*/* // @grant none // @require https://cdn.staticfile.org/blueimp-md5/2.16.0/js/md5.min.js // ==/UserScript== (async () => { 'use strict'; await delay(2000); if (isItest()) { initCss(); debug(); disableSelect(); singleSelect(); select10from15(); article(); articleChoice(); listenTest(); setInterval(function () { if (window.onblur !== null) { window.onblur = null; } }, 5 * 1000) } /** * 判断是否为Itest平台, 为了防止部分学校定制 * @returns {boolean} */ function isItest() { return document.getElementById('all-content') !== null; } /** * 是否为本地网页, 解除本地网页限制 */ function debug() { if (window.location.href.indexOf("localhost") !== -1) { $("head").append(`<script> src="https://cdn.staticfile.org/blueimp-md5/2.16.0/js/md5.min.js"</script>`) $('.goup').removeClass('dis').on('click', function () { $('.itest-ques-set').each(function () { const $this = $(this); if ($this.css('display') === 'block' && $this.parent().css('display') === 'block') { if ($this.prev().is('.itest-ques-set')) { $this.prev().css('display', 'block') $this.css('display', 'none') } else if ($this.parent().prev().is('.itest-section')) { $this.parent().prev().css('display', 'block') $this.parent().css('display', 'none') } return false; } }) }) $('.goto').removeClass('dis').on('click', function () { $('.itest-ques-set').each(function () { const $this = $(this); if ($this.css('display') === 'block' && $this.parent().css('display') === 'block') { if ($this.next().is('.itest-ques-set')) { $this.next().css('display', 'block') $this.css('display', 'none') } else if ($this.parent().next().is('.itest-section')) { $this.parent().next().css('display', 'block') $this.parent().css('display', 'none') } return false; } }) }) } } /** * 封装的翻译api * @param obj * @returns {Promise<unknown>} */ async function translateAjaxApi(obj) { return new Promise((resolve, reject) => { $.ajax({ type: "post", async: false, url: "https://api.fanyi.baidu.com/api/trans/vip/translate", dataType: "jsonp", data: obj, success: function (data) { resolve(data) }, error: function () { reject(); } }); }) } /** * 调用翻译api * @param context_list * @param from * @param to * @returns {Promise<unknown>} */ async function translateAPI(context_list, from, to) { const trans_salt = (new Date).getTime(); const {appid, key} = getBaiduAPIKey() const trans_str = appid + context_list + trans_salt + key; const trans_sign = md5(trans_str); for (let i = 0; i < 5; i++) { const data = await translateAjaxApi({ q: context_list, from, to, appid: appid, salt: trans_salt, sign: trans_sign }) if (data.error_code) { const errmsg = { "52001": "请求超时", "52002": "系统错误", "52003": "未授权用户", "54003": "访问频率受限", "54004": "账户余额不足", "58002": "服务当前已关闭", "90107": "认证未通过或未生效" } if (parseInt(data.error_code) !== 54003) { alert(`错误代码${data.error_code} 信息:${errmsg[data.error_code.toString()]}`) throw new Error(`错误代码${data.error_code} 信息:${errmsg[data.error_code.toString()]}`) } else { await delay(1000); continue } } return data.trans_result; } alert("请求过于频繁") throw new Error("请求过于频繁"); } /** * 返回百度翻译的appid的, 本来打算用户自定义, 最后懒得搞了 * @returns {{appid: string, key: string}} */ function getBaiduAPIKey() { return {appid: "20200603000484959", key: "Fz6UttgcMXATCddMMZW1"} } /** * 解除选择复制粘贴限制 */ function disableSelect() { function hackClass(className) { for (const i of document.getElementsByClassName(className)) { hackItem(i); } } function hackItem(item) { item.onpaste = () => true; item.oncontextmenu = () => true; item.onselectstart = () => true; item.ondragstart = () => true; item.oncopy = () => true; item.onbeforecopy = () => true; item.style = ''; } hackClass('itest-ques'); hackClass('itest-direction'); hackItem(document.body); hackItem(document); } /** * async风格的延迟 * @param time * @returns {Promise<unknown>} */ async function delay(time) { return new Promise(resolve => { setTimeout(resolve, time) }) } /** * 单选题注入 */ function singleSelect() { $('.row').each(function () { if ($(this).find('.option').length !== 0) { $(this).prepend(`<button class="sk-tr-s sk-translate-btn sk-btn-primary sk-btn-p">翻译</button>`) } }) $('.sk-tr-s').on('click', function () { if ($(this).is('.sk-btn-p')) { $(this).parent().find('span').each(function () { $(this).remove(); }) const $this = $(this).parent(); const selectOption = []; $this.children('.option').each(function () { selectOption.push($(this).find('label')) }) const p = selectOption.map(value => value.text().replace('\n', '')).join('\n'); translateAPI(p, 'en', 'zh').then(value => { for (let i = 0; i < value.length; i++) { selectOption[i].append(`<span style="color: #5093df"><br/> ${value[i].dst}</span>`) } $(this).removeClass('sk-btn-p').addClass('sk-btn-g').html('清空'); }) } else { $(this).removeClass('sk-btn-g').addClass('sk-btn-p').html('翻译'); $(this).parent().find('span').each(function () { $(this).remove(); }) } }) } /** * 15选10注入 */ function select10from15() { $('.itest-15xuan10>.xxcontent').each(function () { $(this).prepend(`<button class="sk-tr-15p sk-translate-btn sk-btn-p" >翻译</button>`) }) $('.sk-tr-15p').on('click', function () { // 文章翻译 $(this).parent().find('span').each(function () { $(this).remove(); }) const $button = $(this); if ($(this).is('.sk-btn-p')) { const $passage = $(this).next(); const passage = $passage.text().replace(/\s+/g, ' '); translateAPI(passage, 'en', 'zh').then(value => { value.forEach(i => { $passage.append(`<span style="color: #5093df"><br><br>${i.dst}</span>`) }) $button.removeClass('sk-btn-p').addClass('sk-btn-g').html('清空'); }) } else { $(this).removeClass('sk-btn-g').addClass('sk-btn-p').html('翻译'); $(this).parent().find('span').each(function () { $(this).remove(); }) } }) $('.itest-15xuan10>.xx').each(function () { $(this).prepend(`<button class="sk-tr-15w sk-translate-btn sk-btn-p" style="float: left">翻译</button>`) }) $('.sk-tr-15w').on('click', function () { // 单词翻译 $(this).parent().find('span').each(function () { $(this).remove(); }) const $button = $(this); if ($(this).is('.sk-btn-p')) { const $words = $(this).parent().find('a') const wordList = []; $words.each(function () { wordList.push($(this)); }) const data = wordList.map(value => value.text().replace(/\s+/g, ' ')).join('\n'); translateAPI(data, 'en', 'zh').then(value => { for (let i = 0; i < value.length; i++) { wordList[i].append(`<span style="color: #5093df"><br/>${value[i].dst}</span>`) } $button.removeClass('sk-btn-p').addClass('sk-btn-g').html('清空'); }) } else { $(this).removeClass('sk-btn-g').addClass('sk-btn-p').html('翻译'); $(this).parent().find('span').each(function () { $(this).remove(); }) } }) } /** * 文章注入 */ function article() { $('.con-left>.article').each(function () { $(this).prepend(`<button class="sk-tr-art sk-translate-btn sk-btn-p" >翻译</button>`) }) $('.sk-tr-art').on('click', function () { const $button = $(this); if ($(this).is('.sk-btn-p')) { $(this).parent().find('span').each(function () { $(this).remove(); }) const $article = $(this).parent().find("div[style='text-align:justify']"); $article.children('br:even').remove(); $article.append('<br>') const $brs = []; $article.children('br').each(function () { $brs.push($(this)); }) const text = $article.html() .split('<br>') .map(value => value.trim().replace(/\s+/g, ' ').replace(' ', '')) .filter(value => value.length !== 0); (async () => { for (let i = 0; i < text.length; i++) { const data = await translateAPI(text[i], 'en', 'zh') $brs[i].before(`<span style="color: #5093df"><br/>${data[0].dst}</span>`) await delay(1000); } $button.removeClass('sk-btn-p').addClass('sk-btn-g').html('清空'); })() } else { $(this).removeClass('sk-btn-g').addClass('sk-btn-p').html('翻译'); $(this).parent().find('span').each(function () { $(this).remove(); }) } }) } /** * 文章单选题注入 */ function articleChoice() { $('.itest-need-layout').each(function () { if ($(this).find('span').length !== 0) { $(this).prepend(`<button class="sk-tr-art-r sk-translate-btn sk-btn-p" >翻译</button>`) } }) $('.sk-tr-art-r').on('click', function () { if ($(this).is('.sk-btn-p')) { const $button = $(this); const $spanList = [] $button.parent().find('span').each(function () { $spanList.push($(this)) }) const text = $spanList.map(value => value.text()) .map(value => value.trim().replace(/\s+/g, ' ').replace(' ', '')) .join('\n'); translateAPI(text, 'en', 'zh').then(value => { for (let i = 0; i < value.length; i++) { $spanList[i].append(`<label style="color: #5093df"><br/>${value[i].dst}</label>`) } $button.removeClass('sk-btn-p').addClass('sk-btn-g').html('清空'); }) } else { $(this).removeClass('sk-btn-g').addClass('sk-btn-p').html('翻译'); $(this).parent().find('label').each(function () { $(this).remove(); }) } }) } /** * 解析听力题 */ function listenTest() { $('.itest-hear-reslist-duration+.itest-ques').each(function () { const $this = $(this); const $urlNode = $this.parent().find('.itest-hear-reslist'); if ($urlNode.length !== 0) { const mp3List = JSON.parse($urlNode.html()); mp3List.reverse(); for (const url of mp3List) { if (url.indexOf('http') !== -1) { $this.children('.itest-danxuan').prepend(`<audio controls="controls" src=${url}>`) } } } }) } /** * 初始化CSS */ function initCss() { const styleNode = document.createElement("style"); styleNode.innerHTML = ` .sk-float-btn { z-index: 9999; position: fixed; bottom: 5%; right: 2%; width: 40px; height: 40px; border-radius: 50%; background-color: #00a7c8; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04); cursor: pointer; } .sk-float-btn span { display: inline-block; width: 40px; line-height: 40px; color: #fff; text-align: center; font-size: 20px; user-select: none; cursor: pointer; } .sk-float-container { z-index: 9999; position: absolute; width: 500px; height: 610px; left: -500px; top: -610px; background: #FAFAFA; display: none; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) } .sk-form-item { margin: 5px 20px; } .sk-form-item p { width: 100%; text-align: center; padding: 0; margin: 5px 0; } .sk-form-item label { display: inline-block; width: 50px; } .sk-form-item .sk-form-or { width: 97%; height: 250px; resize: none; border: none; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, 0.04) } .sk-form-item .sk-form-tr { width: 97%; height: 250px; resize: none; border: none; background-color: #EEEEEE; } .sk-form-item p { font-size: 18px; text-align: center; width: 100%; } .sk-form-item textarea { padding: 5px 10px; } .sk-translate-btn { color: #fff; padding: 5px 10px; border-radius: 20px; cursor: pointer; } .sk-btn-p { background-color: #409eff; border: 1px solid #409eff; } .sk-btn-p:hover { background-color: rgb(102, 177, 255); border: 1px solid rgb(102, 177, 255); } .sk-btn-g { background-color: #909399; border: 1px solid #909399; } .sk-btn-g:hover { background-color: rgb(166, 169, 173); border: 1px solid rgb(166, 169, 173); } `; document.head.appendChild(styleNode); $('body').append(` <div class="sk-float-btn"> <span>译</span> <div class="sk-float-container"> <div class="sk-form"> <div class="sk-form-item"> <p>翻译助手</p> </div> <div class="sk-form-item"> <button class="sk-btn-p sk-translate-btn btn-e-z">英 → 汉</button> <button class="sk-btn-p sk-translate-btn btn-z-e">汉 → 英</button> </div> <div class="sk-form-item"> <textarea id="sk-tx-f" class="sk-form-or" placeholder="等待翻译中..."></textarea> </div> <div class="sk-form-item"> <textarea id="sk-tx-t" class="sk-form-tr" readonly></textarea> </div> </div> </div> </div> `) $('.btn-e-z').on('click', function () { translateAPI($('#sk-tx-f').val(), 'en', 'zh').then(value => { $('#sk-tx-t').val(value.map(value => value.dst).join("")) }) }) $('.btn-z-e').on('click', function () { translateAPI($('#sk-tx-f').val(), 'zh', 'en').then(value => { $('#sk-tx-t').val(value.map(value => value.dst).join("")) }) }) $('.sk-float-btn span').on('click', function () { const $float = $('.sk-float-container'); $float.css('display', $float.css('display') === 'none' ? 'block' : 'none') }) } })()