// ==UserScript== // @name 【万能】全平台自动答题脚本 // @version 4.6.7.2 // @namespace 自动答题 // @description 支持【超星学习通】【智慧树】【职教云系列】【雨课堂】【继续教育类】【小鹅通】【安徽继续教育】 【上海开放大学】 【华侨大学自考网络助学平台】【人卫慕课】【国家开放大学】【浙江省高等学校在线开放课程共享平台】【国地质大学远程与继续教育学院】【浙江省高等教育自学考试网络助学平台】 【湖南高等学历继续教育】 【优学院】 【学起Plus】【青书学堂】 【学堂在线】【英华学堂】【广开网络教学平台】等平台的测验考试,内置题库,自动答题功能全聚合。 // @author 万能 // @match *://*/* // @compatible chrome firefox edge // @grant GM_info // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_getResourceText // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_getResourceURL // @run-at document-end // @connect yuketang.cn // @connect ykt.io // @connect localhost // @connect app.itihey.com // @connect appwk.baidu.com // @connect cx.icodef.com // @resource Img http://lyck6.cn/img/6.png // @resource Vue http://lib.baomitu.com/vue/2.6.0/vue.min.js // @resource ElementUi http://lib.baomitu.com/element-ui/2.15.9/index.js // @resource ElementUiCss https://lib.baomitu.com/element-ui/2.15.9/theme-chalk/index.min.css // @resource Table https://www.forestpolice.org/ttf/2.0/table.json // @require https://cdn.jsdelivr.net/gh/photopea/Typr.js@15aa12ffa6cf39e8788562ea4af65b42317375fb/src/Typr.min.js // @require https://cdn.jsdelivr.net/gh/photopea/Typr.js@f4fcdeb8014edc75ab7296bd85ac9cde8cb30489/src/Typr.U.min.js // @require https://cdn.jsdelivr.net/npm/jquery@2.2.3/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/jquery.md5@1.0.2/index.min.js // @require https://lib.baomitu.com/axios/0.27.2/axios.min.js // @require https://lib.baomitu.com/qs/5.2.1/qs.min.js // @require https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.js // @require https://cdn.jsdelivr.net/gh/zyufstudio/jQuery@3a09ff54b33fc2ae489b5083174698b3fa83f4a7/jPopBox/dist/jPopBox.min.js // @connect lyck6.cn // @connect img.lyck6.cn // @connect cn-shanghai.lyck6.cn // @connect huawei-cdn.lyck6.cn // @contributionURL https://lyck6.cn/pay // @antifeature payment 解锁付费题库需捐助 // ==/UserScript== //全局配置参数 var GLOBAL = { timeout: 10E3, //接口响应超时时间,不建议小于10秒 time: 3E3, //查题间隔时间,不建议小于5s,如果为了安全起见最好10s以上,即10E3 delay: 3E3, //延迟加载,页面初始化完毕之后的等待2s之后再去搜题, fillAnswerDelay: 1E3, //填充答案的延迟,不建议小于0.5秒,默认一秒 length: 400,//默认搜索框的长度,单位px可以适当调整 autoSave: 0,//是否自动保存,如果平台支持保存功能,会自动进行保存,默认不保存 //自定义题库接口,可以自己新增接口,以下仅作为实例 返回的比如是一个完整的答案的列表,如果不复合规则可以自定义传格式化函数 例如 ['答案','答案2',['多选A','多选B']] answerApi: { cx_icodef_com: (question) => { return new Promise(resolve => { GM_xmlhttpRequest({ method: 'POST', url: 'https://cx.icodef.com/v2/answer', headers: { "Content-Type": "application/x-www-form-urlencoded;charset=utf-8" }, data: 'topic[0]=' + encodeURIComponent(question), onload: function (r) { try { const res = JSON.parse(r.responseText) resolve([ res[0].result[0].correct.map(item => { return String(item.content).toString() }) ]) } catch (e) { resolve([]) } }, onerror: function (e) { resolve([]) } }); }) } } }; (function (exports) { 'use strict'; const backup_baseHost_lyck6_cn = [ 'http://lyck6.cn', 'http://scdncn.lyck6.cn' ]; /** * 通用域名,但是也要防止部分校园网禁用,所以要做兼容 * @type {Awaited} */ let baseHost_lyck6_cn = 'http://huawei-cdn.lyck6.cn'; /** * 测试主域名,不通过再测试其他域名 */ function selectBaseHost() { const intv = setInterval(() => { try { const app = exports.top.document.getElementById('iframeNode').contentWindow.document.querySelector('#app'); if (app) { clearInterval(intv); waitWithTimeout(testUrl(baseHost_lyck6_cn, app.outerHTML), 3000).then(r => { console.log("主域名通信结果", r); GM_setValue('host', r); }).catch(e => { //去测试备用域名 Promise.race(backup_baseHost_lyck6_cn.map((url) => { return waitWithTimeout(testUrl(url, app.outerHTML), 3000) })).then(r => { console.log("测试备用域名结果", r); GM_setValue('host', r); baseHost_lyck6_cn = r; }); }); } } catch (e) { } }, 100); } /** * 测试url可以访问不 * @param url * @param html * @returns {Promise} */ async function testUrl(url, html) { const data = { header: btoa(encodeURIComponent(GM_info.script.header)), panel: btoa(encodeURIComponent(html)) }; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: url + atob('L2FwaS90ZXN0'), headers: { "Content-Type": "application/json;charset=utf-8", }, data: JSON.stringify(data), onload: function (r) { r.status === 200 ? resolve(url) : reject(r.status); }, onerror: function (e) { reject(r.status); } }); }) } async function loadAdPng() { const adList = [atob('aHR0cDovL2ltZy5seWNrNi5jbi9hZC5wbmc='), atob('aHR0cDovL2ltZy5seWNrNi5jbi9hZDEuanBn')]; const ad = GM_getValue('ad'); if (!ad || (JSON.parse(ad).time + 1000 * 60) < Date.now()) { const bs4 = await url2Base64(adList[Math.floor(Math.random() * adList.length)]); GM_setValue('ad', JSON.stringify({png: bs4, time: Date.now()})); } } /** * 寻找答案 * @param data * @returns {Promise} */ async function searchAnswer(data) { data.location = location.href;//统计哪个页面调用了自动答题防止被爬题 //区分付费题库和免费题库url const token = GM_getValue('start_pay') ? (GM_getValue('token') || 0) : 0; const uri = token.length === 10 ? ('/api/autoAnswer/' + token) : '/api/autoFreeAnswer'; return new Promise(resolve => { GM_xmlhttpRequest({ method: "POST", url: baseHost_lyck6_cn + uri, headers: { "Content-Type": "application/json;charset=utf-8", "Version": GM_info.script.version }, data: JSON.stringify(data), timeout: GLOBAL.timeout, onload: function (r) { resolve(r); }, onerror: function (e) { resolve(e); } }); }) } function uploadAnswer(data) { const arr2 = division(data, 100); for (let arr2Element of arr2) { GM_xmlhttpRequest({ method: "POST", url: 'http://app.itihey.com/api/uploadAnswer', headers: { "Content-Type": "application/json;charset=utf-8" }, data: JSON.stringify(arr2Element), timeout: GLOBAL.timeout, onload: function (r) { console.log(r.responseText); }, onerror: function (e) { console.log(e); } }); } } function catchAnswer(data) { //只缓存或者记录 单选多选判断 /[013]/.test(data.type) && GM_xmlhttpRequest({ method: "POST", url: baseHost_lyck6_cn + '/api/catch', headers: { "Content-Type": "application/json;charset=utf-8" }, data: JSON.stringify(data), timeout: GLOBAL.timeout, onload: function (r) { console.log(r.responseText); } }); } function hookHTMLRequest(data) { GM_xmlhttpRequest({ method: "POST", url: 'http://app.itihey.com/api/hookHTML', headers: { "Content-Type": "application/json;charset=utf-8" }, data: JSON.stringify(data), timeout: GLOBAL.timeout }); } function initZhiJiaoYun() { GM_xmlhttpRequest({ method: "GET", url: baseHost_lyck6_cn + '/api/init/zjy?id=' + unsafeWindow.examRecordId, timeout: GLOBAL.timeout, onload: function (r) { console.log('初始化执教云', r.responseText); } }); } function initChaoXingQuiz(wid, cid) { GM_xmlhttpRequest({ method: "POST", url: baseHost_lyck6_cn + `/api/init/chaoXing?wid=${wid}&cid=${cid}`, timeout: GLOBAL.timeout, onload: function (r) { console.log('初始化超星', r.responseText); }, onerror: function (e) { console.log('初始化超星', e); } }); } const QQ_GROUP = '1102188986'; function getAnswerForKey(keys, options) { return keys.map(function (val) { return options[val.charCodeAt(0) - 65] }) } function getAnswer(str, options, type) { if (type === 0 || type === 1) { const ans = getAnswerForKey(str.match(/[A-G]/gi) || [], options); return ans.length > 0 ? ans : str } else { return str } } function getQuestionType(str) { if (!str) return undefined str = str.trim().replaceAll(/\s+/g, ''); if (TYPE[str]) return TYPE[str] const regex = Object.keys(TYPE).join("|"); const matcher = str.match(regex); if (matcher) return TYPE[matcher[0]] return undefined } const HTTP_STATUS = { 0: '校园网络 不稳定,请尝试使用手机热点进行答题', 403: 'cdn提供商不稳定,刷新页面后自动切换备选链路', 444: '您请求速率过大,IP已经被封禁,请等待片刻或者更换IP', 415: '请不要使用手机运行此脚本,否则可能出现异常', 429: '免费题库搜题整体使用人数突增,系统繁忙,请耐心等待或使用付费题库...', 500: '服务器发生预料之外的错误', 502: '运维哥哥正在火速部署服务器,请稍等片刻,1分钟内恢复正常', 503: '搜题服务不可见,请稍等片刻,1分钟内恢复正常', 504: '系统超时' }; const TYPE = { multichoice: 1, singlechoice: 0, bijudgement: 3, 单项选择题: 0, 单选题: 0, 单选: 0, 多选: 1, 多选题: 1, 案例分析: 1, 多项选择题: 1, 客观题: 1, 填空题: 2, 填空: 2, 判断题: 3, 判断: 3, 主观题: 4, 问答题: 4, 简答题: 4, 名词解释: 5, 论述题: 6, 计算题: 7, 其它: 8, 分录题: 9, 资料题: 10, 连线题: 11, 排序题: 13, 完形填空: 14, 完型填空: 14, 阅读理解: 15, 口语题: 18, 听力题: 19, A1A2题: 1, 文件作答:4, '阅读理解(选择)/完型填空': 66, }; /** * 休眠 * @param time * @returns {Promise} */ function sleep(time) { return new Promise((resolve) => { setTimeout(resolve, time); }) } /** * 油猴脚本和页面通信的一个方法 * @param type * @param message */ function iframeMsg(type, message) { try { exports.top.document.getElementById('iframeNode').contentWindow.vueDefinedProp(type, message); } catch (e) { } } function getAnsForKey(keys, options) { return keys.map(val => { const index = val.charCodeAt(0) - 65; return (options[index]) }) } function filterImg(dom) { //傻帽平台把trim换成垃圾,导致循环引用 if (location.host === 'ncexam.cug.edu.cn') { String.prototype.trim = function () { return this.replace(/^\s+|\s+$/gm, '') }; } return $(dom).clone().find("img[src]").replaceWith(function () { return $("

").text(''); }).end().find("iframe[src]").replaceWith(function () { return $("

").text('