理论上所有选择题考试都可以用,需要加QQ获取token,但是只是为了防止滥用,不会收费,也不会发广告,请看下方的详细说明。
当前为
// ==UserScript==
// @name 易班考试
// @namespace http://tampermonkey.net/
// @license Common
// @version 1.4.7
// @description 理论上所有选择题考试都可以用,需要加QQ获取token,但是只是为了防止滥用,不会收费,也不会发广告,请看下方的详细说明。
// @author 木木
// @match *.yooc.me/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=yooc.me
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
let has_init = false;
let tk;
let id;
let button_init = false;
let user_data;
//=========替换特殊字符防止匹配不上=======================
window.my_replace = function my_replace(text) {
text = text.replace(new RegExp(/ | |\\t|\\r|\\n|<br>|<br\/>| |\s/g), "");
return text;
}
const localStorage = window.localStorage;
function set_value(key, value) {
localStorage.setItem(key, value);
}
function get_value(key) {
return localStorage.getItem(key);
}
// localStorage.removeItem('examAnswersAtom');
// localStorage.removeItem('examTakePosAtom');
// =========试卷的一些信息存储,包括易班id,cookie,考试名称===============
user_data = JSON.parse(get_value('data') != null ? get_value('data') : '{}');
function update_data(key, value) {
user_data[key] = value;
set_value('data', JSON.stringify(user_data));
}
// ==========获取token=============================
let token = get_value("token");
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
if (key.startsWith('exam-paper')) {
let value = localStorage[key];
localStorage.removeItem(key);
set_value('back-' + key, value);
}
}
function get_token() {
let t = prompt("请输入token(进群691977572免费获取)", token === null ? '' : token);
if (t.length !== 16) {
alert("长度不对");
get_token();
} else {
token = t;
set_value("token", token);
}
}
// ============判断当前页面链接,如果是电脑版则跳转到手机版=====================
let u = window.location.href;
if (u === ('https://www.yooc.me/')) {
window.location.replace('https://www.yooc.me/mobile/yooc')
}
if (u.startsWith('https://www.yooc.me/group/') && u.endsWith('topics')) {
window.location.replace(u.replace('www', 'group').replace('topics', 'index'));
}
// =================劫持fetch方法========================================
// =================监听并获取一些数据,以便服务器实现解密等功能================
// =================修改返回值以达到查卷,禁止乱序等功能======================
window.au_fetch = window.fetch;
window.fetch = function (url) {
if (url.indexOf('api') === -1) {
return au_fetch(url);
}
if (url.indexOf("yibanId") !== -1) {
id = url.slice(url.indexOf("yibanId=") + 8);
update_data('yibanId', id);
}
return window.au_fetch.apply(window, arguments).then((response) => {
const reader = response.body.getReader();
const stream = new ReadableStream({
start(controller) {
function push() {
// "done"是一个布尔型,"value"是一个Unit8Array
reader.read().then((e) => {
let {done, value} = e;
// 判断是否还有可读的数据?
let text = new TextDecoder("utf-8").decode(value);
if (done) {
// 告诉浏览器已经结束数据发送
controller.close();
return;
}
if (url.indexOf('api/exam/detail/get?userId') !== -1) {
let res_json = JSON.parse(text);
update_data('examId', res_json['data']['examId']);
update_data('examuserId', res_json['data']['examuserId']);
update_data('exam_name', res_json['data']['name']);
}
text = text.replace('"isHidePaper":1', '"isHidePaper":0');
text = text.replace('"isHideAnswer":1', '"isHideAnswer":0');
text = text.replace('"isShowRank":0', '"isShowRank":1');
text = text.replace('"isChoiceShuffle":1', '"isChoiceShuffle":0');
text = text.replace('"isSubjectShuffle":1', '"isSubjectShuffle":0');
controller.enqueue(new TextEncoder().encode(text));
push();
});
}
push();
}
});
return new Response(stream, {headers: {"Content-Type": "text/html"}});
});
};
function do_exam() {
if (token === null) {
get_token();
return;
}
let ul = document.getElementsByTagName("ul");
if (ul.length === 0) {
alert('未找到页面资源,请稍后再试');
}
let bottom = ul[1];
let last = bottom.getElementsByTagName("li")[0].children[0];
let next = bottom.getElementsByTagName("li")[3].children[0];
let main = document.getElementsByTagName("main")[0];
let h3 = main.getElementsByTagName("h3")[0];
let res;
// ===============在网页存储找到试卷并发送到服务器解密================
for (let i = 0; i < localStorage.length; i++) {
if (localStorage.key(i).startsWith("exam-paper")) {
let res_str = localStorage.getItem(localStorage.key(i));
res = JSON.parse(my_replace(res_str));
break;
}
}
if (res === undefined) {
alert("找不到试卷,请刷新重试,或者检查是否开启缓存");
return;
}
res['token'] = token;
res['id'] = id;
res['data'] = user_data;
const httpRequest = new XMLHttpRequest();
httpRequest.open('POST', 'https://124.222.110.105:5721', true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.send(JSON.stringify(res));
httpRequest.onreadystatechange = function () {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
let result = JSON.parse(httpRequest.responseText);
if (result['msg'] !== '成功请求') {
if (result['msg'] === 'token不存在') {
get_token();
} else if (result['msg'] === '次数耗尽,请明天再试') {
alert('次数耗尽,请明天再试,或者输入新的token');
get_token();
} else {
alert(result['msg']);
}
return;
}
tk = result['result'];
window.tk = tk;
// console.log(result);
let span = bottom.getElementsByTagName("span");
let count_text = span[0].innerText;
let count_list = count_text.split("/");//目前题目位置1/50,分割之后为["1","50"]
for (let i = 0; i < count_list[0]; i++) {
//点回第一题
last.click();
}
for (let i = 0; i < parseInt(count_list[1]); i++) {
let title_obj = h3.getElementsByTagName("div")[0];
let title = my_replace(title_obj.innerHTML);
let body = h3.parentElement.children[1].children[0];
// =========如果body是空则不是选择题=====================
if (body === undefined) {
title = title.replace(new RegExp(/<input.*?>/g), "{input}").replace(new RegExp(/<.*?>/g), "");
let inputs = title_obj.getElementsByTagName('input');
const ans = tk[title];
for (let j = 0; j < inputs.length; j++) {
let answer = ans[j];
let ev = new Event('input', {bubbles: true});
ev.simulated = true;
inputs[j].value = (Array.isArray(answer) ? answer[0] : answer);
inputs[j].dispatchEvent(ev);
}
next.click();
continue;
}
//=====如果是填空题在上面的if已经continue了,所以下面的是选择题的代码====
const ans = tk[title];
let ans_l = body.getElementsByTagName("li");
//不是未初始化,说明返回的数据中有这个题目
if (ans !== undefined) {
//单选题,答案是哪个就点哪个就可以了
if (body.className.indexOf('jsx-2160564469') !== -1) {
for (let j = 0; j < ans_l.length; j++) {
let an_str = my_replace(ans_l[j].children[1].innerHTML.slice(2));
if (ans.indexOf(an_str) !== -1) {
ans_l[j].click();
}
}
} else if (body.className.indexOf('jsx-2550022912') !== -1) {//多选题需要判断有没有选对,没选对的取消勾选,对的没选的就选上
for (let j = 0; j < ans_l.length; j++) {
let an_str = my_replace(ans_l[j].children[1].innerHTML.slice(2));
if (ans.indexOf(an_str) !== -1 && ans_l[j].children[0].children[0].childElementCount === 2) {
ans_l[j].click();
} else if (ans.indexOf(an_str) === -1 && ans_l[j].children[0].children[0].childElementCount === 1) {
ans_l[j].click();
}
}
}
}
next.click();
}
alert('答题成功请检查后等待一段时间再交卷以免因为时长问题被发现');
} else if (httpRequest.readyState === 4) {
if (httpRequest.status === 0) {
alert('在解密过程中,向服务器发送原始试卷失败,可能是被浏览器拦截或者服务器故障,如果你是苹果设备请更换设备后再试。');
} else {
alert('发生错误,请进群691977572联系作者。服务器数据:' + httpRequest.responseText);
}
}
}
}
if (!has_init) {
if (u.indexOf('yooc.me') !== -1) {
const httpRequest = new XMLHttpRequest();
httpRequest.open('GET', 'https://124.222.110.105:5721/', true);
httpRequest.send();
httpRequest.onreadystatechange = function () {
if (httpRequest.readyState === 4 && httpRequest.status === 0) {
has_init = true;
alert('无法连接服务器,可能被拦截或者服务器down了,如果是苹果请更换安卓或Windows设备,如果是电脑端请访问https://124.222.110.105:5721/,在拦截界面点击高级,点击继续访问。然后回到此页面刷新。');
}
}
}
}
// =============在进入考试之前判断是否能够连接服务器,连不上就提示用户========
if (u.endsWith('exams')) {
const httpRequest = new XMLHttpRequest();
httpRequest.open('GET', 'https://124.222.110.105:5721/times/' + token, true);
httpRequest.send();
httpRequest.onreadystatechange = function () {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
const times_json = JSON.parse(httpRequest.responseText);
if (!times_json['ok']) {
if (confirm('未输入token或者token不存在,如果你没有token,请加群获取:691977572。点确定输入token,点取消继续考试(脚本不会工作)')) get_token();
} else if (times_json['times'] <= 0) {
alert('token使用次数已用尽,');
} else {
alert('服务器连接成功,剩余次数' + times_json['times']);
}
} else if (httpRequest.readyState === 4) {
alert('查询剩余次数失败,可能是服务器G了,可能脚本不会正常工作');
}
}
}
function create_float_menu(button_data_list) {
let dragging = false;
let box = document.createElement('div');
box.className = 'floating-btn';
for (const button_data of button_data_list) {
console.log(button_data);
let button = document.createElement('div');
button.innerText = button_data.text;
button.className = 'div-btn';
button.onclick = function () {
if (dragging) {
return;
}
button_data.onclick();
}
box.appendChild(button);
}
box.onmousedown = function (ev) {
let disX = ev.pageX - box.offsetLeft;
let disY = ev.pageY - box.offsetTop;
document.onmousemove = function (e) {
dragging = true;
box.style.left = e.clientX - disX + 'px';
box.style.top = e.clientY - disY + 'px';
};
};
document.onmouseup = function () {
setTimeout(function () {
dragging = false;
}, 100)
document.onmousemove = null;
box.onmouseup = null;
};
return box;
}
// 插入悬浮窗=======================================================
window.insert_float=function insert_float() {
let menu_data = [{text: '做题', onclick: function () {
if (confirm('你要消耗一次次数并开始考试吗?')) do_exam();
}}, {text: '输入token', onclick: get_token},]
let box = create_float_menu(menu_data);
document.body.appendChild(box);
}
window.onload = function () {
let style = document.createElement('style');
style.innerHTML = '.notice{}.div-btn{margin:5px;border-width:1px;border-style:solid;border-radius:2px;background:deepskyblue;text-align-all:center}.floating-btn{z-index:1;background:aquamarine;position:fixed;top:20px;left:20px}';
document.body.appendChild(style);
insert_float();
}
})();