`;
top.document.getElementsByTagName("body")[0].appendChild(zhihuishuSaveTip);
}
};
function showPanel() {
let html = `
`;
addModal2(html);
checkVersion();
}
function dragModel(modal) {
// 获取拖动句柄
const headerElem = modal.querySelector("#hcsearche-modal-links");
if (headerElem) {
headerElem.style.cursor = "move";
}
// 设置初始位置
const pos = GM_getValue("pos");
if (pos) {
const [left, top] = pos.split(",");
modal.style.left = left;
modal.style.top = top;
} else {
modal.style.left = "30px";
modal.style.top = "30px";
}
// 确保模态框可见并置顶
modal.style.position = "fixed";
modal.style.zIndex = "999999999";
modal.style.overflow = "visible";
// 简单的鼠标事件变量
let isDragging = false;
let offsetX = 0;
let offsetY = 0;
// 鼠标按下事件 - 开始拖动
if (headerElem) {
headerElem.addEventListener("mousedown", function(e) {
e.preventDefault();
// 计算鼠标位置与模态框位置之间的偏移量
offsetX = e.clientX - parseInt(modal.style.left);
offsetY = e.clientY - parseInt(modal.style.top);
isDragging = true;
// 临时增加z-index在拖动过程中
const oldZIndex = modal.style.zIndex;
modal.style.zIndex = "9999999999";
// 添加临时鼠标移动和鼠标松开处理程序
function moveHandler(e) {
if (!isDragging) return;
// 计算新位置
let newLeft = e.clientX - offsetX;
let newTop = e.clientY - offsetY;
// 获取窗口尺寸和模态框尺寸
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const modalWidth = modal.offsetWidth;
const modalHeight = modal.offsetHeight;
// 防止拖出屏幕 - 左侧和上侧边界
newLeft = Math.max(0, newLeft);
newTop = Math.max(0, newTop);
// 防止拖出屏幕 - 右侧和下侧边界
// 保留至少50px在屏幕内,确保用户能够访问到模态框
newLeft = Math.min(newLeft, windowWidth - Math.min(modalWidth, 100));
newTop = Math.min(newTop, windowHeight - Math.min(modalHeight, 80));
// 应用新位置
modal.style.left = newLeft + "px";
modal.style.top = newTop + "px";
// 保存位置
GM_setValue("pos", newLeft + "px," + newTop + "px");
}
function upHandler() {
isDragging = false;
modal.style.zIndex = oldZIndex;
// 移除临时事件监听器
document.removeEventListener("mousemove", moveHandler);
document.removeEventListener("mouseup", upHandler);
}
// 添加临时事件监听器
document.addEventListener("mousemove", moveHandler);
document.addEventListener("mouseup", upHandler);
});
}
// 添加快捷键控制显示/隐藏
document.addEventListener("keydown", function(e) {
if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
modal.style.display = "none";
GM_setValue("hide", true);
vm.hideTip();
} else if (e.key === "ArrowDown" || e.key === "ArrowRight") {
modal.style.display = "block";
GM_setValue("hide", false);
}
});
// 如果之前设置为隐藏,则隐藏模态框
if (GM_getValue("hide")) {
modal.style.display = "none";
vm.hideTip();
}
// 初始检查 - 确保弹窗在可视范围内
setTimeout(function() {
// 获取当前位置
let currentLeft = parseInt(modal.style.left || "0");
let currentTop = parseInt(modal.style.top || "0");
// 获取窗口尺寸和模态框尺寸
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const modalWidth = modal.offsetWidth;
const modalHeight = modal.offsetHeight;
// 检查是否在可视范围内
let needsAdjustment = false;
// 左侧和上侧边界检查
if (currentLeft < 0) {
currentLeft = 0;
needsAdjustment = true;
}
if (currentTop < 0) {
currentTop = 0;
needsAdjustment = true;
}
// 右侧和下侧边界检查
if (currentLeft > windowWidth - Math.min(modalWidth, 100)) {
currentLeft = windowWidth - Math.min(modalWidth, 100);
needsAdjustment = true;
}
if (currentTop > windowHeight - Math.min(modalHeight, 80)) {
currentTop = windowHeight - Math.min(modalHeight, 80);
needsAdjustment = true;
}
// 如果需要调整,应用新位置
if (needsAdjustment) {
modal.style.left = currentLeft + "px";
modal.style.top = currentTop + "px";
GM_setValue("pos", currentLeft + "px," + currentTop + "px");
}
}, 500);
}
function createContainer(className, childElements) {
let container = top.document.createElement("div");
container.className = className;
// Ensure container doesn't clip its contents
container.style.overflow = "visible";
container.style.maxHeight = "none";
container.style.maxWidth = "none";
if (Array.isArray(childElements)) {
childElements.forEach(child => {
container.appendChild(child);
});
} else if (childElements) {
container.appendChild(childElements);
}
return container;
}
function render(tagName, elemId, childElem, isFixed, newPos) {
let doc = top.document;
let elem = doc.getElementById(elemId);
if (elem) {
elem.innerHTML = "";
} else {
elem = doc.createElement(tagName);
elem.id = elemId;
// Make sure styles are applied before adding to DOM
elem.style.position = "fixed";
elem.style.zIndex = "999999999";
elem.style.overflow = "visible";
elem.style.left = "30px";
elem.style.top = "30px";
doc.body.appendChild(elem);
}
// Create content container
let contentNode = doc.createElement("div");
contentNode.className = tagName + "-container";
contentNode.style.overflow = "visible";
// Add child elements
if (Array.isArray(childElem)) {
childElem.forEach(child => contentNode.appendChild(child));
} else if (childElem) {
contentNode.appendChild(childElem);
}
elem.appendChild(contentNode);
elem.classList.add(elemId);
// Apply animation class with slight delay
setTimeout(function() {
elem.classList.add(elemId + "-show");
}, 10);
return elem;
}
function renderModal(childElem, newPos) {
// Generate random ID for the element
const randomTag = String.fromCharCode(rand(65, 90), rand(65, 90), rand(65, 90)) + rand(1, 100).toString();
// Create the modal element
const modal = render(randomTag, modelId, childElem);
// Apply drag behavior
dragModel(modal);
// Apply visibility based on GM_getValue
if (GM_getValue("hide")) {
$("#" + modelId).hide();
vm.hideTip();
}
return modal;
}
function addModal2(html, newPos, footerChildNode = false) {
// 创建干净的拖动标题栏(使用成功提示框的颜色)
let headerNode = document.createElement("div");
headerNode.id = "hcsearche-modal-links";
headerNode.style.cssText = `
background-color: #f0f9eb;
padding: 10px;
text-align: center;
cursor: move;
font-weight: bold;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
user-select: none;
overflow: visible;
width: 360px;
`;
// 添加标题文本
let titleNode = document.createElement("div");
titleNode.textContent = "学习通小助手-考试端";
titleNode.style.cssText = `
font-size: 16px;
color: #333;
`;
headerNode.appendChild(titleNode);
// 创建iframe容器
let iframeNode = document.createElement("iframe");
iframeNode.id = "iframeNode";
iframeNode.width = "100%";
iframeNode.height = GLOBAL.length + "px";
iframeNode.style.height = GLOBAL.length + "px";
iframeNode.frameBorder = "0";
iframeNode.srcdoc = html;
// 创建内容容器
let contentContainer = document.createElement("div");
contentContainer.className = "content-modal";
contentContainer.style.cssText = `
position: relative;
border-left: 5px solid #f0f9eb;
border-right: 5px solid #f0f9eb;
border-bottom: 5px solid #f0f9eb;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
background-color: white;
overflow: visible;
width: 360px;
`;
// 添加元素到容器
contentContainer.appendChild(headerNode);
contentContainer.appendChild(iframeNode);
// 创建并返回模态框
let modal = renderModal(contentContainer, newPos);
// 确保模态框可见并可拖动
if (modal) {
modal.style.borderRadius = "6px";
modal.style.overflow = "visible";
modal.style.boxShadow = "0 2px 8px rgba(0,0,0,0.1)";
modal.style.width = "370px";
}
return modal;
}
const init$1 = async ($TiMu, select, wrap) => {
let question = formatString(filterImg($TiMu.find(select.elements.question)));
if (select.elements.type && select.elements.type.includes("input[name^=type]:eq")) {
select.elements.type = "input[name^=type]:eq(" + GLOBAL.i + ")";
}
let data = {
$item: $TiMu,
question_text: $TiMu.find(select.elements.question).text(),
question: question.length === 0 ? $TiMu.find(select.elements.question) : question.replace(/^\d+、/, "").replace(/[((](\d+\s?(\.\d+)?分)[))]$/, "").replace(/^((\d+.(\s+)?)?)[\[((【](.*?)[】))\]]/, "").trim(),
$options: select.elements.$options ? $TiMu.find(select.elements.$options) : undefined,
options: select.elements.options ? jQuery.map($TiMu.find(select.elements.options), function(val) {
return formatString(filterImg(val)).replace(/^[A-Ga-g][.、]/, "").trim();
}) : undefined
};
if (select.elements.type) {
const getType = getQuestionType($TiMu.find(select.elements.type).text());
const val = $TiMu.find(select.elements.type).val();
data.type = isNaN(getType) ? isNaN(val) ? val : parseInt(val) : getType;
} else {
data.type = defaultWorkTypeResolver(data.$options);
}
if (select.elements.answer) {
data.answer = getAnswer(filterImg($TiMu.find(select.elements.answer)) || $TiMu.find(select.elements.answer).val(), data.options, data.type);
}
if (data && data.type === 3 && data.options.length === 0) {
data.options = [ "正确", "错误" ];
}
try {
const r = await wrap(data);
if (typeof r === "boolean") return undefined;
return data;
} catch (error) {
console.error("Error in init$1:", error);
return data;
}
};
async function WorkerJSPlus(options) {
if (GLOBAL.isMatch) return;
if (isEmbeddedInLearningShell()) {
return;
}
const match = options.match ? typeof options.match === "boolean" ? options.match : options.match() : false;
if (!match) return;
GLOBAL.isMatch = true;
if (options.hook && typeof options.hook === "function") {
if (options.hook()) return;
}
const defaultFunc = () => {};
const main = () => {
setTimeout(() => {
showPanel();
if (options.init && typeof options.init === "function") {
if (options.init()) return;
}
const select = {
root: options.root,
elements: options.elements,
ignore_click: options.ignore_click
};
new WorkerJS(select, options.wrap ? options.wrap : defaultFunc, options.fill ? options.fill : defaultFunc, options.finished ? options.finished : defaultFunc, options.fillFinish ? options.fillFinish : defaultFunc).fillAnswer();
}, GLOBAL.delay);
};
if (options.intv) {
setIntervalFunc(options.intv, main);
} else {
main();
}
}
var WorkerJS = function(select, searchHander, fillHander, onFinish = function(need_jump) {}, fillFinish = function() {}) {
GLOBAL.index = 0;
this.init = init$1;
this.fillAnswer = async () => {
let arr = jQuery(select.root);
console.log("=== 答题调试信息 ===");
console.log("题目选择器:", select.root);
console.log("找到题目数量:", arr.length);
console.log("当前页面URL:", location.href);
console.log("当前页面路径:", location.pathname);
if (arr.length > 0) {
console.log("第一个题目元素:", arr[0]);
console.log("第一个题目内容:", jQuery(arr[0]).find(select.elements.question).text());
}
while (true) {
if (arr.length === 0) {
console.log("没有找到题目,退出答题流程");
return;
}
await sleep((isNaN(parseInt(GM_getValue("search_delay"))) ? 2 : GM_getValue("search_delay")) * 1e3);
if (GLOBAL.stop) {
continue;
}
if (GLOBAL.index >= arr.length) {
let auto_jump = GM_getValue("auto_jump") === undefined || GM_getValue("auto_jump");
const next = await onFinish(auto_jump);
if (next) {
GLOBAL.index = 0;
setTimeout(this.fillAnswer, 300);
}
if (auto_jump) {
iframeMsg("tip", {
tip: "自动答题已完成,即将切换下一题"
});
next || setTimeout(() => {
iframeMsg("tip", {
type: "hidden",
tip: "自动答题已完成,请检查提交"
});
}, Math.max(GM_getValue("search_delay") || 2, 5) * 1e3);
} else {
iframeMsg("tip", {
tip: "自动答题已完成" + (arr.length === 1 ? ",请手动切换" : "请检查提交")
});
}
return true;
}
try {
console.log("正在处理第", GLOBAL.index + 1, "题");
let data = await this.init(jQuery(arr[GLOBAL.index++]), select, searchHander);
if (!data) {
console.log("题目数据为空,跳过");
GLOBAL.index--;
continue;
}
console.log("题目数据:", data);
console.log("题目内容:", data.question);
console.log("题目选项:", data.options);
iframeMsg("tip", {
tip: "准备答第" + GLOBAL.index + "题"
});
const formatResult = await formatSearchAnswer(data);
console.log("搜索结果:", formatResult);
const hookAnswer = data.answer && data.answer.length > 0 && GM_getValue("start_pay");
const formatAns = hookAnswer ? {
success: true,
num: formatResult.num,
list: [ data.answer ]
} : formatResult;
console.log("最终答案:", formatAns);
if (formatResult.answers || formatAns.success) {
iframeMsg("tip", {
tip: "准备填充答案,当前使用免费题库"
});
const func = !hookAnswer && formatResult.answers ? defaultFillAnswer : defaultQuestionResolve;
let r = await func(hookAnswer ? formatAns.list : formatAns.answers ? formatResult.answers : formatAns.list, data, fillHander, select.ignore_click ? select.ignore_click : () => {
return false;
});
iframeMsg("push", {
index: GLOBAL.index,
question: r.question,
answer: r.ans,
style: r.style
});
GM_getValue("start_pay") && String(GM_getValue("token")).length === 10 && catchAnswer(r);
await fillFinish(r);
} else {
console.log("搜索失败:", formatAns.msg);
GLOBAL.index--;
iframeMsg("tip", {
tip: formatAns.msg
});
}
} catch (e) {
GLOBAL.index--;
console.table(e);
}
}
};
};
// @thanks 特别感谢 qxin i 借鉴 网页限制解除(改) 开源地址 https://greasyfork.org/zh-CN/scripts/28497
function init() {
rule = rwl_userData.rules.rule_def;
hook_eventNames = rule.hook_eventNames.split("|");
unhook_eventNames = rule.unhook_eventNames.split("|");
eventNames = hook_eventNames.concat(unhook_eventNames);
if (rule.dom0) {
setInterval(clearLoop, 10 * 1e3);
setTimeout(clearLoop, 1500);
window.addEventListener("load", clearLoop, true);
clearLoop();
}
if (rule.hook_addEventListener) {
EventTarget.prototype.addEventListener = addEventListener;
document.addEventListener = addEventListener;
if (hasFrame) {
for (let i = 0; i < hasFrame.length; i++) {
hasFrame[i].contentWindow.document.addEventListener = addEventListener;
}
}
}
if (rule.hook_preventDefault) {
Event.prototype.preventDefault = function() {
if (hook_eventNames.indexOf(this.type) < 0) {
Event_preventDefault.apply(this, arguments);
}
};
if (hasFrame) {
for (let i = 0; i < hasFrame.length; i++) {
hasFrame[i].contentWindow.Event.prototype.preventDefault = function() {
if (hook_eventNames.indexOf(this.type) < 0) {
Event_preventDefault.apply(this, arguments);
}
};
}
}
}
if (rule.hook_set_returnValue) {
Event.prototype.__defineSetter__("returnValue", function() {
if (this.returnValue !== true && hook_eventNames.indexOf(this.type) >= 0) {
this.returnValue = true;
}
});
}
}
function addEventListener(type, func, useCapture) {
var _addEventListener = this === document ? document_addEventListener : EventTarget_addEventListener;
if (hook_eventNames.indexOf(type) >= 0) {
_addEventListener.apply(this, [ type, returnTrue, useCapture ]);
} else if (unhook_eventNames.indexOf(type) >= 0) {
var funcsName = storageName + type + (useCapture ? "t" : "f");
if (this[funcsName] === undefined) {
this[funcsName] = [];
_addEventListener.apply(this, [ type, useCapture ? unhook_t : unhook_f, useCapture ]);
}
this[funcsName].push(func);
} else {
_addEventListener.apply(this, arguments);
}
}
function clearLoop() {
rule = clear();
var elements = getElements();
for (var i in elements) {
for (var j in eventNames) {
var name = "on" + eventNames[j];
if (Object.prototype.toString.call(elements[i]) == "[object String]") {
continue;
}
if (elements[i][name] !== null && elements[i][name] !== onxxx) {
if (unhook_eventNames.indexOf(eventNames[j]) >= 0) {
elements[i][storageName + name] = elements[i][name];
elements[i][name] = onxxx;
} else {
elements[i][name] = null;
}
}
}
}
document.onmousedown = function() {
return true;
};
}
function returnTrue(e) {
return true;
}
function unhook_t(e) {
return unhook(e, this, storageName + e.type + "t");
}
function unhook_f(e) {
return unhook(e, this, storageName + e.type + "f");
}
function unhook(e, self, funcsName) {
var list = self[funcsName];
for (var i in list) {
list[i](e);
}
e.returnValue = true;
return true;
}
function onxxx(e) {
var name = storageName + "on" + e.type;
this[name](e);
e.returnValue = true;
return true;
}
function getElements() {
var elements = Array.prototype.slice.call(document.getElementsByTagName("*"));
elements.push(document);
var frames = document.querySelectorAll("frame");
if (frames) {
hasFrame = frames;
var frames_element;
for (let i = 0; i < frames.length; i++) {
frames_element = Array.prototype.slice.call(frames[i].contentWindow.document.querySelectorAll("*"));
elements.push(frames[i].contentWindow.document);
elements = elements.concat(frames_element);
}
}
return elements;
}
var settingData = {
status: 1,
version: .1,
message: "",
positionTop: "0",
positionLeft: "0",
positionRight: "auto",
addBtn: false,
connectToTheServer: false,
waitUpload: [],
currentURL: "null",
shortcut: 3,
rules: {},
data: []
};
var rwl_userData = null;
var rule = null;
var hasFrame = false;
var storageName = "storageName";
var hook_eventNames, unhook_eventNames, eventNames;
var EventTarget_addEventListener = EventTarget.prototype.addEventListener;
var document_addEventListener = document.addEventListener;
var Event_preventDefault = Event.prototype.preventDefault;
rwl_userData = GM_getValue("rwl_userData");
if (!rwl_userData) {
rwl_userData = settingData;
}
for (let value in settingData) {
if (!rwl_userData.hasOwnProperty(value)) {
rwl_userData[value] = settingData[value];
GM_setValue("rwl_userData", rwl_userData);
}
}
// @thanks 特别感谢 wyn大佬 提供的 字典匹配表 原作者 wyn665817@163.com 开源地址 https://scriptcat.org/script-show-page/432/code
function removeF() {
var $tip = $("style:contains(font-cxsecret)");
if (!$tip.length) return;
var font = $tip.text().match(/base64,([\w\W]+?)'/)[1];
font = Typr.parse(base64ToUint8Array(font))[0];
var table = JSON.parse(GM_getResourceText("Table"));
var match = {};
for (var i = 19968; i < 40870; i++) {
$tip = Typr.U.codeToGlyph(font, i);
if (!$tip) continue;
$tip = Typr.U.glyphToPath(font, $tip);
$tip = MD5(JSON.stringify($tip)).slice(24);
match[i] = table[$tip];
}
$(".font-cxsecret").html(function(index, html) {
$.each(match, function(key, value) {
key = String.fromCharCode(key);
key = new RegExp(key, "g");
value = String.fromCharCode(value);
html = html.replace(key, value);
});
return html;
}).removeClass("font-cxsecret");
function base64ToUint8Array(base64) {
var data = window.atob(base64);
var buffer = new Uint8Array(data.length);
for (var i = 0; i < data.length; ++i) {
buffer[i] = data.charCodeAt(i);
}
return buffer;
}
}
function start() {
try {
removeF();
} catch (e) {}
try {
init();
} catch (e) {}
}
WorkerJSPlus({
name: "学习通新版作业",
match: location.pathname === "/mooc2/work/dowork" || location.pathname === "/mooc-ans/mooc2/work/dowork",
root: ".questionLi",
elements: {
question: "h3",
options: ".stem_answer .answerBg .answer_p, .textDIV, .eidtDiv",
$options: ".stem_answer .answerBg, .textDIV, .eidtDiv",
type: "input[type^=hidden]:eq(0)"
},
wrap: obj => {
obj.question = obj.question.replace(obj.$item.find(".colorShallow").text(), "").replace(/^(\d+\.\s)/, "");
},
ignore_click: $item => {
return Boolean($item.find(".check_answer,.check_answer_dx").length);
},
fill: (type, answer, $option) => {
if (type === 4 || type === 2 || type === 5) {
UE$1.getEditor($option.find("textarea").attr("name")).setContent(answer);
}
}
});
WorkerJSPlus({
name: "超星旧版考试",
match: (location.pathname === "/exam/test/reVersionTestStartNew" || location.pathname === "/exam-ans/exam/test/reVersionTestStartNew") && !location.href.includes("newMooc=true"),
root: ".TiMu",
elements: {
question: ".Cy_TItle .clearfix",
options: ".Cy_ulTop .clearfix",
$options: ":radio, :checkbox, .Cy_ulTk textarea",
type: "[name^=type]:not([id])"
},
ignore_click: $item => {
return $item.get(0).checked;
},
fill: (type, answer, $option) => {
if (type === 4 || type === 2 || type === 5) {
UE$1.getEditor($option.attr("name")).setContent(answer);
}
},
finished: auto_jump => {
auto_jump && setInterval(function() {
const btn = $(".saveYl:contains(下一题)").offset();
var mouse = document.createEvent("MouseEvents"), arr = [ btn.left + Math.ceil(Math.random() * 80), btn.top + Math.ceil(Math.random() * 26) ];
mouse.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, arr[0], arr[1], false, false, false, false, 0, null);
_self.event = $.extend(true, {}, mouse);
delete _self.event.isTrusted;
_self.getTheNextQuestion(1);
}, Math.ceil(GLOBAL.fillAnswerDelay * Math.random()) * 2);
}
});
WorkerJSPlus({
name: "超星旧版作业",
match: location.pathname === "/work/doHomeWorkNew" || location.pathname === "/mooc-ans/work/doHomeWorkNew",
init: start,
root: ".clearfix .TiMu",
elements: {
question: ".Zy_TItle .clearfix",
options: "ul:eq(0) li .after",
$options: "ul:eq(0) li :radio,:checkbox,textarea,.num_option_dx,.num_option",
type: "input[name^=answertype]"
},
ignore_click: $item => {
if ($item.is("input")) {
return $item.get(0).checked;
}
return $item.attr("class").includes("check_answer");
},
fill: async (type, answer, $option) => {
if (type === 4 || type === 2 || type === 5) {
UE$1.getEditor($option.attr("name")).setContent(answer);
}
}
});
WorkerJSPlus({
name: "超星新版考试",
match: () => {
const cxSinglePage = (location.pathname === "/exam/test/reVersionTestStartNew" || location.pathname === "/exam-ans/exam/test/reVersionTestStartNew" || location.pathname === "/mooc-ans/exam/test/reVersionTestStartNew") && location.href.includes("newMooc=true");
const cxAll = location.pathname === "/mooc2/exam/preview" || location.pathname === "/exam-ans/mooc2/exam/preview" || location.pathname === "/mooc-ans/mooc2/exam/preview";
return cxSinglePage || cxAll;
},
root: ".questionLi",
elements: {
question: "h3 div",
options: ".answerBg .answer_p, .textDIV, .eidtDiv",
$options: ".answerBg, .textDIV, .eidtDiv",
type: "input[name^=type]:eq(" + GLOBAL.i + ")"
},
ignore_click: $item => {
return Boolean($item.find(".check_answer,.check_answer_dx").length);
},
hook: () => {
GLOBAL.i = Number((location.pathname === "/exam/test/reVersionTestStartNew" || location.pathname === "/exam-ans/exam/test/reVersionTestStartNew" || location.pathname === "/mooc-ans/exam/test/reVersionTestStartNew") && location.href.includes("newMooc=true"));
},
wrap: obj => {
if (obj.type === 6) {
obj.type = 4;
}
},
fill: (type, answer, $option) => {
if (type === 4 || type === 2 || type === 5) {
const name = $option.find("textarea").attr("name");
UE$1.getEditor(name).setContent(answer);
if (GLOBAL.i === 0) {
console.log("#" + name.replace("answerEditor", "save_"));
$("#" + name.replace("answerEditor", "save_")).click();
}
}
},
finished: a => {
a && $('.nextDiv .jb_btn:contains("下一题")').click();
}
});
WorkerJSPlus({
name: "超星随堂测验",
match: location.pathname.includes("/page/quiz/stu/answerQuestion"),
root: ".question-item",
elements: {
question: ".topic-txt",
options: ".topic-option-list",
$options: ".topic-option-list input",
type: "input[class^=que-type]"
},
ignore_click: $item => {
return Boolean($item.find(".check_answer,.check_answer_dx").length);
},
wrap: obj => {
if (obj.type === 16) {
obj.type = 3;
}
},
fill: (type, answer, $option) => {
if (type === 4 || type === 2) {
$option.val(answer);
}
}
});
function JSONParseHook(func) {
const parse = JSON.parse;
JSON.parse = function(...args) {
const o = parse.call(this, ...args);
func(o);
return o;
};
}
function hookZhiHuiShuWork(o, arr) {
function format(item) {
let options = [];
let options_id;
if (item.questionOptions && item.questionOptions.length) {
options = item.questionOptions.map(o => {
return formatString(o.content);
});
options_id = item.questionOptions.map(o => {
return o.id;
});
}
return {
qid: item.id,
question: formatString(item.name),
type: getQuestionType(item.questionType.name),
options_id: options_id,
options: options
};
}
if (o.rt && o.rt.examBase && o.rt.examBase.workExamParts.length > 0) {
GLOBAL.content = o.rt;
GLOBAL.json = o.rt.examBase.workExamParts.map(part => {
return part.questionDtos.map(item => {
if ("阅读理解(选择)/完型填空" === item.questionType.name || "听力训练" === item.questionType.name || !(item.questionType.name.includes("填空") || item.questionType.name.includes("问答")) && item.questionChildrens && item.questionChildrens.length > 0) {
return item.questionChildrens.map(i => {
console.log(format(i));
return format(i);
}).flat();
} else {
return format(item);
}
});
}).flat();
} else if (o.rt && Object.keys(o.rt).length > 0 && !isNaN(Object.keys(o.rt)[0])) {
GLOBAL.img = o.rt;
}
}
WorkerJSPlus({
match: location.href.includes("checkHomework") && location.host.includes("zhihuishu"),
hook: () => {
JSONParseHook(hookZhiHuiShuWork);
},
init: () => {
R({
type: 2,
content: GLOBAL.content,
img: GLOBAL.img
});
}
});
GLOBAL.timeout = 10 * 1e3;
function uploadAnswer(data) {
const arr2 = division(data, 100);
for (let arr2Element of arr2) {
gmRequest({
method: "POST",
url: "https://lyck6.cn/pcService/api/uploadAnswer",
headers: {
"Content-Type": "application/json;charset=utf-8"
},
data: JSON.stringify(arr2Element),
timeout: GLOBAL.timeout
});
}
}
function uploadAnswerToPlat(data, plat) {
const arr2 = division(data, 100);
for (let arr2Element of arr2) {
gmRequest({
method: "POST",
url: "https://lyck6.cn/collect-service/v1/uploadAnswerToPlat?plat=" + plat,
headers: {
"Content-Type": "application/json;charset=utf-8"
},
data: JSON.stringify(arr2Element),
timeout: GLOBAL.timeout
});
}
}
function parseIcve(questions) {
return questions.map(item => {
const options = item.Selects.map(opt => {
return formatString(opt);
});
const type = getQuestionType(item.ACHType.QuestionTypeName);
const answer = item.Answers.map(key => {
if (type === 0 || type === 1) {
return options[key.charCodeAt() - 65];
} else if (type === 3) {
return key === "1" ? "正确" : "错误";
}
});
const answerKey = type === 0 || type === 1 ? item.Answers : answer;
return {
id: item.Id,
question: item.ContentText,
answerKey: answerKey,
options: type === 3 ? [ "正确", "错误" ] : options,
answer: answer,
type: type
};
});
}
WorkerJSPlus({
name: "资源库 WWW开头",
match: location.pathname === "/study/works/works.html" || location.pathname === "/study/exam/exam.html",
root: ".questions",
elements: {
question: ".preview_stem",
options: "li .preview_cont",
$options: "li input",
type: "input:hidden"
},
hook: () => {
JSONParseHook(o => {
if (location.pathname === "/study/works/works.html") {
if (o.paper) {
GLOBAL.json = parseIcve(o.paper.PaperQuestions);
uploadAnswer(GLOBAL.json);
}
} else if (location.pathname === "/study/exam/exam.html") {
if (o.array) {
GLOBAL.json = parseIcve(o.array.map(item => {
return item.Questions;
}).flat());
uploadAnswer(GLOBAL.json);
}
}
});
},
ignore_click: $item => {
return $item.prop("checked");
},
wrap: obj => {
function get_element(id) {
for (let jsonElement of GLOBAL.json) {
if (jsonElement.id === id) {
return jsonElement;
}
}
}
const ele = get_element(obj.$item.find("input:hidden").val());
obj.question = ele.question;
obj.answer = ele.answerKey ? ele.answerKey : ele.answer;
obj.type = ele.type;
obj.options = ele.options;
console.log(obj);
},
fill: (type, answer, $option) => {
if (type === 4 || type === 2) {
UE$1.getEditor($option.attr("name")).setContent(answer);
}
}
});
function parseYkt(problems) {
return problems.map(item => {
const question = formatString(item.Body);
const type = getQuestionType(item.TypeText);
const options = [];
const answer = [];
if (type <= 1) {
options.push(...item.Options.sort((a, b) => {
return a.key.charCodeAt(0) - b.key.charCodeAt(0);
}).map(item => {
return formatString(item.value);
}));
if (item.Answer) {
if (Array.isArray(item.Answer)) {
answer.push(...item.Answer);
} else {
answer.push(...item.Answer.split(""));
}
}
} else if (type === 3 && item.Answer && item.Answer.length === 1) {
answer.push(item.Answer[0].replace("true", "正确").replace("false", "错误"));
}
return {
answer: answer,
options: options,
type: type,
qid: item.problem_id,
question: question
};
});
}
function parsehnzkwText(problems) {
return problems.map(item => {
const type = item.flag === 1 ? 2 : item.flag === 0 ? 0 : item.flag === 4 ? 1 : item.flag === 3 ? 3 : undefined;
let answer = [];
let options = [];
if (type === 2) {
answer.push(item.answer);
return {
question: formatString(item.content),
options: options,
type: type,
answer: answer
};
} else if (type === 0) {
for (let subjectOption of item.optionss) {
const opt = formatString(subjectOption);
options.push(opt);
}
if (type === 1) {
item.answer.split("|").map(i => {
answer.push(options[i.toUpperCase().charCodeAt(0) - 65]);
});
} else {
answer.push(options[item.answer.toUpperCase().charCodeAt(0) - 65]);
}
return {
question: formatString(item.content),
options: options,
type: type,
answer: answer
};
} else if (type === 3) {
for (let subjectOption of item.selectOption) {
const opt = formatString(subjectOption);
options.push(opt);
}
answer.push(item.answer);
return {
question: formatString(item.content),
options: options,
type: type,
answer: answer
};
}
});
}
function parseDanWei(pro) {
return pro.map(i => {
const type = getQuestionType(i.ttop010);
const question = i.ttop011;
const options = [];
const answer = [];
if (type === 0 || type === 1 || type === 3) {
options.push(...i.ttop018.length > 0 ? i.ttop018.split("$$") : [ "正确", "错误" ]);
answer.push(...i.ttop022.split("").map(item => {
return options[item.charCodeAt(0) - 65];
}));
} else if (type === 2 || type === 4) {
answer.push(...i.ttop021.split("$$"));
}
return {
question: question,
type: type,
answer: answer,
options: options
};
}).filter(i => i);
}
function parseYxbyunExam(problems) {
return problems.map(item => {
const type = getQuestionType(item.bigName);
return item.smallContent.map(item => {
let answer = [];
let options = [];
if (type === 2) {
answer.push(item.answer);
return {
question: formatString(item.content),
options: options,
type: type,
answer: answer
};
} else if (type === 0 || type === 3 || type === 1) {
let answer = [];
let options = [];
for (let subjectOption of item.question.optionList) {
const opt = formatString(subjectOption.questionContent);
options.push(opt);
}
if (type === 1) {
item.question.questionAnswer.split(",").map(i => {
answer.push(options[i.toUpperCase().charCodeAt(0) - 65]);
});
} else {
answer.push(options[item.question.questionAnswer.toUpperCase().charCodeAt(0) - 65]);
}
return {
question: formatString(item.question.questionTitle),
options: options,
type: type,
answer: answer
};
}
});
});
}
WorkerJSPlus({
name: "exam2_euibe_com_exam",
match: location.hostname === "exam2.euibe.com" && location.pathname === "/KaoShi/ShiTiYe.aspx",
root: ".question",
elements: {
question: ".wenti",
options: "li label span",
$options: "li label"
},
wrap: obj => {
obj.type = getQuestionType($(".question_head").text());
},
finished: need_jump => {
$(".paginationjs-next").click();
return true;
}
});
WorkerJSPlus({
name: "lzwyedu_jijiaool_com_exam",
match: () => {
const pathMatch = location.pathname.includes("/learnspace/course/test/") || location.pathname.includes("/Student/ExamManage/CourseOnlineExamination");
const matchHostArr = [ "lzwyedu.jijiaool.com", "cgjx.jsnu.edu.cn", "learn-cs.icve.com.cn", "nwnu.jijiaool.com", "lut.jijiaool.com", "learn.courshare.cn", "cj1027-kfkc.webtrn.cn" ];
return pathMatch && matchHostArr.includes(location.host);
},
root: ".test_item",
elements: {
question: ".test_item_tit",
options: ".test_item_theme label .zdh_op_con",
$options: "label input"
},
wrap: obj => {
obj.question = obj.question.replace(/该题未做$/, "").replace(/^\d+\./, "").replace(/^\d+、/, "").replace(/[((](\d+\s?(\.\d+)?分)[))]$/, "").replace(/^((\d+.(\s+)?)?)[\[((【](.*?)[】))\]]/, "").trim();
obj.type = getQuestionType(obj.$item.prevAll(".test_item_type:first").text());
if (obj.type === 3) {
obj.options = [ "对", "错" ];
}
}
});
WorkerJSPlus({
name: "zzx_ouchn_edu_cn_exam",
match: location.hostname === "zzx.ouchn.edu.cn" && location.pathname.includes("/edu/public/student/"),
root: ".subject",
elements: {
question: ".question span",
options: ".answer>span>p:first-child",
$options: ".answer>span>p:first-child"
},
wrap: obj => {
if (obj.$options.length > 1) {
obj.type = 0;
}
}
});
WorkerJSPlus({
name: "zzx_ouchn_edu_cn_exam",
match: location.hostname === "zzx.ouchn.edu.cn" && location.pathname.includes("/edu/public/student/"),
root: ".subject",
elements: {
question: ".question span",
options: ".answer>span>p:first-child",
$options: ".answer>span>p:first-child"
},
wrap: obj => {
if (obj.$options.length > 1) {
obj.type = 0;
}
}
});
WorkerJSPlus({
name: "havust_hnscen_cn_exam",
match: location.hostname === "havust.hnscen.cn" && location.pathname.includes("/stuExam/examing/"),
root: ".main .mt_2 > div",
elements: {
question: ".flex_row+div",
options: ".flex_row+div+div .el-radio__label,.el-checkbox__label",
$options: ".flex_row+div+div .el-radio__label,.el-checkbox__label",
type: ".flex_row .mr_2"
}
});
WorkerJSPlus({
name: "www_zygbxxpt_com_exam",
match: location.hostname === "www.zygbxxpt.com" && location.pathname.includes("/exam"),
root: ".Body",
elements: {
question: ".QName",
options: ".QuestinXuanXiang p:parent",
$options: ".QuestinXuanXiang p:parent",
type: ".QName span"
},
wrap: obj => {
obj.question = obj.question.replace(/\([^\)]*\)/g, "").replace(/\【.*?\】/g, "");
obj.options = obj.options.map(item => {
return item.split(">").pop().trim();
});
}
});
WorkerJSPlus({
name: "xuexi_jsou_cn_work",
match: location.hostname === "xuexi.jsou.cn" && location.pathname.includes("/jxpt-web/student/newHomework/showHomeworkByStatus"),
root: ".insert",
elements: {
question: ".window-title",
options: ".questionId-option .option-title div[style^=display]",
$options: ".questionId-option .option-title .numberCover"
},
wrap: obj => {
obj.type = {
1: 0,
2: 1,
7: 3
}[obj.$item.find(".question-type").val()];
if (obj.options.length == 2) {
obj.type = 3;
}
}
});
WorkerJSPlus({
name: "czvtc_cjEdu_com_exam",
match: () => {
const pathMatch = location.pathname.includes("/ExamInfo") || location.pathname.includes("/Examination");
const matchHostArr = [ "czvtc.cj-edu.com", "hbkjxy.cj-edu.com", "bhlgxy.cj-edu.com", "hbsi.cj-edu.com", "czys.cj-edu.com", "hbjd.cj-edu.com", "xttc.cj-edu.com", "bvtc.cj-edu.com", "caztc.cj-edu.com" ];
return pathMatch && matchHostArr.includes(location.host);
},
intv: () => {
return $(".el-container .all_subject>.el-row").length;
},
root: ".el-container .all_subject>.el-row",
elements: {
question: ".stem div:last-child",
options: ".el-radio-group .el-radio__label,.el-checkbox-group .el-checkbox__label",
$options: ".el-radio-group .el-radio__original,.el-checkbox-group .el-checkbox__original"
},
wrap: obj => {
if (obj.$options.length < 3 && obj.$options.eq(0).attr("type") === "radio") {
obj.type = 3;
} else if (obj.$options.length > 2 && obj.$options.eq(0).attr("type") === "radio") {
obj.type = 0;
} else if (obj.$options.length > 2 && obj.$options.eq(0).attr("type") === "checkbox") {
obj.type = 1;
}
}
});
WorkerJSPlus({
name: "learning_mhtall_com_exam",
match: location.host.includes("learning.mhtall.com") && location.pathname.includes("/rest/course/exercise/item"),
root: "#div_item",
elements: {
question: ".item_title",
options: ".opt div label",
$options: ".opt div input:not(.button_short)",
type: "h4"
},
ignore_click: $item => {
return $item.prop("checked");
},
wrap: obj => {
if (obj.type === 0 || obj.type === 3) {
obj.answer = $(".div_answer").text().match(/[a-zA-Z]/).map(i => {
return obj.options[i.charCodeAt(0) - 65];
});
} else if (obj.type === 2) {
obj.answer = $(".div_answer").text().replace("参考答案:", "").split(",");
}
},
fill: (type, answer, $option) => {
if (type === 2 || type === 4) {
$option.val(answer);
$(".DIV_TYPE_BLANK .button_short").click();
}
},
fillFinish: () => {
if ($(".opt+div+div input:eq(1)").val() === "下一题") {
$(".opt+div+div input:eq(1)").click();
} else {
$(".button_short:eq(2)").click();
}
}
});
})();
// =============考试端结束==============
(() => {
// 配置变量
const token = GM_getValue('tikutoken');
let jumpType = GM_getValue('jumpType', 1); // 0:智能模式,1:遍历模式,2:不跳转
let disableMonitor = GM_getValue('disableMonitor', 0); // 0:无操作,1:解除多端学习监控
let randomDo = GM_getValue('unrivalrandomdo', 0);
const backGround = 0;
let videoQuestionEnabled = GM_getValue('videoQuestionEnabled', true);
// 视频播放模式:'real' 真实播放(默认),'simulate' 接口模拟上报
let videoPlayMode = GM_getValue('videoPlayMode', 'real');
// 真实播放模式下是否自动静音
let autoMuteVideo = GM_getValue('autoMuteVideo', true);
// gmRequest 见脚本顶部共享缓冲层
// ========== 资源治理(仅清理脚本自身创建的定时器与 iframe) ==========
// 模块级定时器单例,供 cleanupBeforeTask 统一回收
let workInfoLoop = null;
let simVideoLoop = null;
let realVideoProgressMonitor = null;
let workCheckcross = null;
let workDoneInterval = null;
// 定时器注册表(studentstudy 目录/跳转类 interval)
const xxtTimerRegistry = [];
function xxtSetInterval(fn, ms, label) {
const entry = { id: setInterval(fn, ms), label: label || '' };
xxtTimerRegistry.push(entry);
return entry.id;
}
function xxtClearInterval(id) {
const idx = xxtTimerRegistry.findIndex(function (e) { return e.id === id; });
if (idx >= 0) xxtTimerRegistry.splice(idx, 1);
try { clearInterval(id); } catch (_) { }
}
function xxtClearTimersByPrefix(prefix) {
for (let i = xxtTimerRegistry.length - 1; i >= 0; i--) {
if (!prefix || xxtTimerRegistry[i].label.indexOf(prefix) === 0) {
try { clearInterval(xxtTimerRegistry[i].id); } catch (_) { }
xxtTimerRegistry.splice(i, 1);
}
}
}
function xxtV6ResourceSnapshot() {
let iframeCount = 'N/A';
try { iframeCount = top.document.querySelectorAll('iframe').length; } catch (e) { iframeCount = '跨域'; }
let memInfo = 'N/A';
if (typeof performance !== 'undefined' && performance.memory) {
memInfo = (performance.memory.usedJSHeapSize / 1024 / 1024).toFixed(1) + 'MB';
}
return {
iframeCount: iframeCount,
memInfo: memInfo,
timers: {
simVideoLoop: !!simVideoLoop,
realVideoProgressMonitor: !!realVideoProgressMonitor,
workInfoLoop: !!workInfoLoop,
workCheckcross: !!workCheckcross,
workDoneInterval: !!workDoneInterval
},
registryCount: xxtTimerRegistry.length
};
}
// 诊断菜单:仅 top 注册一次(避免 studentstudy / cards / video iframe 各注册导致点一次打三条)
try {
if (typeof GM_registerMenuCommand === 'function' && window.top === window) {
GM_registerMenuCommand('资源诊断(iframe/内存/定时器)', () => {
try {
const snap = xxtV6ResourceSnapshot();
const timerFlags = [snap.timers.simVideoLoop, snap.timers.realVideoProgressMonitor,
snap.timers.workInfoLoop, snap.timers.workCheckcross, snap.timers.workDoneInterval]
.map(v => v ? 1 : 0).join('/');
console.log('[资源诊断] gmRequest queue=' + gmQueue.length +
' active=' + gmActive +
' | 定时器(sim/real/work/check/done)=' + timerFlags +
' | 注册表=' + snap.registryCount +
' | 顶层 iframe=' + snap.iframeCount +
' | JS堆=' + snap.memInfo +
' | ' + new Date().toLocaleTimeString());
try {
if (typeof logs !== 'undefined' && logs && logs.addLog) {
logs.addLog('📊 资源诊断:iframe ' + snap.iframeCount + ',堆 ' + snap.memInfo, 'blue');
}
} catch (_) { }
} catch (e) {
console.log('[资源诊断] 异常:', e);
}
});
}
} catch (e) { /* 菜单注册失败不阻塞脚本 */ }
// ========== 资源治理 end ==========
// 自动登录配置
let autoLogin = 1;
let phoneNumber = GM_getValue('phoneNumber', '');
let password = GM_getValue('password', '');
// 基础配置
const host = 'http://14.29.190.187:54223/';
const REAL_RATE_MIN = 0.75;
const REAL_RATE_MAX = 3;
const REAL_RATE_STEP = 0.25;
const normalizeRealVideoRate = (raw) => {
let r = parseFloat(raw);
if (!isFinite(r)) r = 1;
r = Math.max(REAL_RATE_MIN, Math.min(REAL_RATE_MAX, r));
r = Math.round(r / REAL_RATE_STEP) * REAL_RATE_STEP;
return Math.round(r * 100) / 100;
};
const parseSimulateVideoRate = (raw) => {
let r = parseFloat(raw);
if (!isFinite(r)) return 1;
if (r === parseInt(r, 10)) return parseInt(r, 10);
return r;
};
(function migrateSplitVideoRateKeys() {
const flag = 'unrival_v558_split_rate';
if (GM_getValue(flag, false)) return;
const legacy = GM_getValue('unrivalrate', null);
if (legacy !== null && legacy !== undefined && legacy !== '') {
if (GM_getValue('unrivalrate_simulate', null) === null) {
GM_setValue('unrivalrate_simulate', legacy);
}
if (GM_getValue('unrivalrate_real', null) === null) {
GM_setValue('unrivalrate_real', normalizeRealVideoRate(legacy));
}
}
GM_setValue(flag, true);
})();
let rateSimulate = parseSimulateVideoRate(GM_getValue('unrivalrate_simulate', GM_getValue('unrivalrate', 1)));
let rateReal = normalizeRealVideoRate(GM_getValue('unrivalrate_real', GM_getValue('unrivalrate', 1)));
const accuracy = GM_getValue('accuracy', 80);
let reportInterval = Math.max(10, parseInt(GM_getValue('reportInterval', 90), 10) || 90);
// 升级时一次性清理已废弃的 GM 键(旧版视频优化开关)
(function cleanupRemovedVideoOptimizationKeys() {
const V4_CLEANUP_FLAG = 'unrival_v4_video_opt_cleaned';
if (GM_getValue(V4_CLEANUP_FLAG, false)) return;
['smartSpeedControl', 'durationCompensation', 'behaviorSimulation', 'detectionEvasion', 'riskWarning'].forEach(function (k) {
try {
if (typeof GM_deleteValue === 'function') GM_deleteValue(k);
else GM_setValue(k, undefined);
} catch (e) { }
});
GM_setValue(V4_CLEANUP_FLAG, true);
})();
const ctUrl = 'https://cx.icodef.com/wyn-nb?v=4';
const getQueryVariable = (variable) => {
let q = _l.search.substring(1),
v = q.split("&"),
r = false;
for (let i = 0, l = v.length; i < l; i++) {
let p = v[i].split("=");
p[0] == variable && (r = p[1]);
}
return r;
};
// 工具函数
const getCookie = name => `; ${document.cookie}`.split(`; ${name}=`).pop().split(';').shift();
// 环境变量
const isCat = GM_info.scriptHandler == 'ScriptCat';
const _w = unsafeWindow;
const _d = _w.document;
const _l = _w.location;
const _p = _l.protocol;
const _h = _l.host;
const isFf = _w.navigator.userAgent.includes("Firefox");
const isMobile = _w.navigator.userAgent.includes("Android");
let stop = false;
// 检测 studentstudy 页是否存在「下一节」按钮(兼容新旧 DOM)
function xxtIsMooc2StudyPage() {
try {
return /[?&]mooc2=1(?:&|$)/.test(top.location.search);
} catch (_) {
return getQueryVariable('mooc2') == '1';
}
}
function xxtNextChapterBtnUsable(btn, isMooc2) {
if (!btn) return false;
if (btn.disabled || btn.classList.contains('gray') || btn.classList.contains('disabled')) return false;
try {
const st = top.getComputedStyle(btn);
if (st.display === 'none' || st.visibility === 'hidden') return false;
} catch (_) { }
if (!isMooc2 && btn.classList.contains('orientationright')) {
const oc = btn.getAttribute('onclick');
if (!oc || !String(oc).trim()) return false;
}
return true;
}
function xxtGetNextChapterBtn(doc) {
doc = doc || top.document;
const isMooc2 = xxtIsMooc2StudyPage();
if (isMooc2) {
const mooc2Selectors = [
'#prevNextFocusNext',
'#mainid .prev_next.next',
'.prev_next.next'
];
for (let i = 0; i < mooc2Selectors.length; i++) {
const btn = doc.querySelector(mooc2Selectors[i]);
if (xxtNextChapterBtnUsable(btn, isMooc2)) return btn;
}
return null;
}
// 旧版每 card 各有一对 orientationleft/right,首个 .orientationright 常为隐藏项(如 #right1)
const oldBtns = doc.querySelectorAll('.orientationright, #right1, #right2');
for (let j = 0; j < oldBtns.length; j++) {
if (xxtNextChapterBtnUsable(oldBtns[j], isMooc2)) return oldBtns[j];
}
return null;
}
function xxtHasNextChapter() {
try {
return !!xxtGetNextChapterBtn(top.document);
} catch (_) {
return false;
}
}
let xxtChapterEndLogged = false;
let xxtChapterStopLogged = false;
function xxtNotifyChapterEnd(msg) {
msg = msg || '已是最后一章,无下一节可跳转,脚本已停止';
console.log('[章节跳转] ' + msg);
try {
if (typeof top._xxtStudyAddLog === 'function') {
if (!xxtChapterEndLogged) {
xxtChapterEndLogged = true;
top._xxtStudyAddLog(msg, 'green');
if (msg.indexOf('脚本已停止') >= 0) {
xxtChapterStopLogged = true;
}
} else if (msg.indexOf('脚本已停止') >= 0 && !xxtChapterStopLogged) {
xxtChapterStopLogged = true;
top._xxtStudyAddLog('脚本已停止', 'green');
}
return;
}
} catch (_) { }
try {
const logEl = top.document.getElementById('log');
if (logEl) {
const now = new Date();
const pad = (n) => (Array(2).join(0) + n).slice(-2);
const t = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
logEl.innerHTML += '
';
logEl.scrollTop = logEl.scrollHeight;
}
} catch (_) { }
}
try {
top.xxtHasNextChapter = xxtHasNextChapter;
top.xxtGetNextChapterBtn = xxtGetNextChapterBtn;
} catch (_) { }
const handleImgs = (s) => {
imgEs = s.match(/(
]*)>)/);
if (imgEs) {
for (let j = 0, k = imgEs.length; j < k; j++) {
let urls = imgEs[j].match(
/http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+/),
url;
if (urls) {
url = urls[0].replace(/http[s]?:\/\//, '');
s = s.replaceAll(imgEs[j], url);
}
}
}
return s;
};
const trim = (s) => {
return handleImgs(s).replaceAll('javascript:void(0);', '').replaceAll(" ", '').replaceAll(",", ',').replaceAll(
"。", '.').replaceAll(":", ':').replaceAll(";",
';').replaceAll("?", '?').replaceAll("(", '(').replaceAll(")", ')').replaceAll("“", '"')
.replaceAll("”", '"').replaceAll("!", '!').replaceAll("-", ' ').replace(/(<([^>]+)>)/ig, '')
.replace(/^\s+/ig, '').replace(/\s+$/ig, '');
};
let cVersion = 999;
let classId = getQueryVariable('clazzid') || getQueryVariable('clazzId') || getQueryVariable('classid') ||
getQueryVariable('classId');
const courseId = getQueryVariable('courseid') || getQueryVariable('courseId');
let UID = getCookie('_uid') || getCookie('UID');
let FID = getCookie('fid');
const jq = _w.top.$ || _w.top.jQuery;
// 劫持confirm函数
_w.confirm = () => true;
// 安全增强版 confirm 劫持
function safeConfirmHook() {
const oldConfirm = window.confirm;
const handler = (msg) => {
if (getQueryVariable('mooc2') == '1') {
return true;
}
if (document.activeElement && document.activeElement.closest('#xxt-helper-window')) {
return oldConfirm(msg);
}
return true;
};
try {
window.confirm = handler;
if (typeof top !== 'undefined') {
top.confirm = handler;
}
if (typeof unsafeWindow !== 'undefined') {
unsafeWindow.confirm = handler;
}
if (window.frames && window.frames.length) {
for (let i = 0; i < window.frames.length; i++) {
try {
window.frames[i].confirm = handler;
} catch (e) {}
}
}
} catch (e) {
console.log('confirm劫持失败:', e);
}
}
safeConfirmHook();
rateSimulate = parseSimulateVideoRate(rateSimulate);
rateReal = normalizeRealVideoRate(rateReal);
try {
_w.top.unrivalReviewMode = GM_getValue('unrivalreview', '0') || '0';
_w.top.unrivalDoWork = GM_getValue('unrivaldowork', '1') || '1';
_w.top.unrivalAutoSubmit = GM_getValue('unrivalautosubmit', '1') || '1';
_w.top.unrivalAutoSave = GM_getValue('unrivalautosave', '1') || '1';
_w.top.unrivalRandomDo = GM_getValue('unrivalrandomdo', 0);
} catch (e) { }
if (_l.href.indexOf("knowledge/cards") > 0) {
let allowBackground = false,
spans = _d.getElementsByTagName('span');
for (let i = 0, l = spans.length; i < l; i++) {
if (spans[i].innerHTML.indexOf('章节未开放') != -1) {
if (_l.href.indexOf("ut=s") != -1) {
_l.href = _l.href.replace("ut=s", "ut=t").replace(/&cpi=[0-9]{1,10}/, '');
} else if (_l.href.indexOf("ut=t") != -1) {
spans[i].innerHTML = '此课程为闯关模式,请回到上一章节完成学习任务!'
return;
}
break;
}
}
_w.top.unrivalPageRd = String(Math.random());
try { _w.top.xxtNoTaskJumpAttempted = false; } catch (_) { }
if (!isFf) {
try {
cVersion = parseInt(navigator.userAgent.match(/Chrome\/[0-9]{2,3}./)[0].replace('Chrome/', '')
.replace('.', ''));
} catch (e) { }
}
var busyThread = 0,
getStr = (str, start, end) => {
let res = str.substring(str.indexOf(start), str.indexOf(end)).replace(start, '');
return res;
},
scripts = _d.getElementsByTagName('script'),
param = null;
for (let i = 0, l = scripts.length; i < l; i++) {
if (scripts[i].innerHTML.indexOf('mArg = "";') != -1 && scripts[i].innerHTML.indexOf(
'==UserScript==') == -1) {
param = getStr(scripts[i].innerHTML, 'try{\n mArg = ', ';\n}catch(e){');
}
}
if (param == null) {
return;
}
try {
vrefer = _d.getElementsByClassName('ans-attach-online ans-insertvideo-online')[0].src;
} catch (e) {
vrefer = _p + '//' + _h + '/ananas/modules/video/index.html?v=2022-1118-1729';
}
GM_setValue('vrefer', vrefer);
GM_setValue('host', _h);
var base222 = `data:image/jpeg;base64,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`
// 检查是否已存在悬浮窗,避免重复创建
let existingFloatWin = top.document.getElementById("xxt-helper-window");
if (existingFloatWin) {
existingFloatWin.remove();
}
// 创建悬浮窗 - 确保创建在顶级文档中
const floatWin = top.document.createElement("div");
floatWin.id = "xxt-helper-window";
// 全局状态变量
let isMax = false;
// 最小化状态在同一 top window 内共享(内存变量,不写 GM)
// 同 tab SPA 切章保留;F5/关浏览器自然丢失,避免历史白屏问题(不写 GM)
let isMinimized = (function () {
try { return top.__xxtFloatMinimized === true; } catch (e) { return false; }
})();
let dragCurX = 370, dragCurY = 75; // 拖拽当前偏移,提升为模块级供最大化恢复使用
// 悬浮窗状态持久化(位置写 GM;最小化仅同 top 内存共享,不写 GM,避免休眠后白屏)
const FLOAT_POS_KEY = 'unrival_float_pos_v2';
function loadFloatPos() {
try {
const s = GM_getValue(FLOAT_POS_KEY, null);
if (s && typeof s.x === 'number' && typeof s.y === 'number') {
// 坐标合法性校验:超出屏幕范围则重置,防止悬浮窗跑出屏幕外
const maxX = (window.innerWidth || 1200) - 100;
const maxY = (window.innerHeight || 800) - 40;
const safeX = (s.x >= 0 && s.x <= maxX) ? s.x : 370;
const safeY = (s.y >= 0 && s.y <= maxY) ? s.y : 75;
return { x: safeX, y: safeY };
}
} catch (e) {}
return null;
}
function saveFloatPos(x, y) {
try {
GM_setValue(FLOAT_POS_KEY, { x, y });
} catch (e) {}
}
floatWin.innerHTML = `
投喂渠道
"劝君莫惜金缕衣,劝君惜取少年时"
赞赏助我拿下瑞幸生椰拿铁☕(少冰不另外加糖)真心好喝,早日拿下瑞幸黑金🦌
—如果帮你省下了少年时,就莫要惜金缕衣喽,感谢您的打赏。我会非常🦀🦀你的慷慨和鼓励q(≧▽≦q) ➡️学长也还有学业在身,如果加微信未能及时回复,请多多包涵哈哈哈,欢迎大家加微信咨询: Why15236444193 (遇问题下滑看运行日志⏬) 还有我在考虑要不要建个群聊,大家可以把意愿反馈给我📩———如果觉得悬浮窗不舒服,可以用旧版——点击跳转
运行日志
[00:00:00]如果此提示不消失,说明页面出现了错误,请联系作者
任务配置
如果显示视频已观看完毕,但视频任务未完成,可尝试开启复习模式或适当降低倍速后重刷
视频倍速:
章节测试:
章节测试正确率(百分比):
视频上报间隔(秒):
题库配置
关注微信公众号:一之哥哥,发送 "token" 领取你的token,可以提高答题并发数量。
领取到token后,填入输入框中,点击保存即可。还有undefined是没有设定,而不是有效token
题库Token:
保存
自动登录配置
⚠️ 风险提示:超星官方禁止自动登录脚本,使用时可能触发账号风控。建议不要自动登录,当心风控。
作者的话
"劝君莫惜金缕衣,劝君惜取少年时"
我闭了昏黄的台灯,此时窗外正好飘来一片月光,泼洒在电脑屏幕上,红色的报错,洁白的就像一个还未睁开眸子看着世界的孩子的心。
📁 每一次优化都是学长透支身体的结果,熬穿了不知道多少个夜晚,您的赞赏会是刺破黑暗苍穹的亮光照亮我前行的路
因为淋过雨,所以想替学弟撑把伞。学长已经把路铺好了。学长快点不起拼好饭了,赞赏助力学长全款拿下拼好饭。
✨ 有的学弟很调皮啊,给我的赞赏备注个学长CPDD,哎,说来惭愧,学长现在还没牵过女孩子的手,所以可以赞赏安慰一下学长吗?
学长也还有学业在身,如果加微信未能及时回复,请多多包涵哈!学长目前准备优化:1. 添加更多免费题库 2. 兼容多平台 3. 优化脚本体验(持续优化中)4. 制作超简化版本
学长是galgame最长的河流,如果有galgame问题也欢迎大家加微信咨询:Why15236444193 | 还有我在考虑要不要建个群聊,大家可以把意愿反馈给我📩
—— 若觉得悬浮窗不舒服,可点击跳转:旧版 ——点击跳转(功能所见及所得,详情重点请观看使用须知)
`;
// 在插入DOM之前就设好位置,避免刷新后先显示默认位置再跳动
(function() {
const _pos = loadFloatPos();
if (_pos) {
dragCurX = _pos.x;
dragCurY = _pos.y;
floatWin.style.transform = `translate(${_pos.x}px, ${_pos.y}px)`;
}
// 首帧前应用折叠状态,避免切章后先展开再缩回
if (isMinimized) {
const contentEl = floatWin.querySelector('#xxt-helper-content');
if (contentEl) contentEl.style.display = 'none';
floatWin.style.height = 'auto';
floatWin.style.minHeight = 'auto';
const minProgressEl = floatWin.querySelector('#xxt-min-progress');
if (minProgressEl) minProgressEl.style.display = 'inline';
const minBtnEl = floatWin.querySelector('#xxt-min');
if (minBtnEl) { minBtnEl.textContent = '▢'; minBtnEl.title = '恢复'; }
}
})();
top.document.body.appendChild(floatWin);
// 最小化状态在 appendChild 前已应用;initFloatingWindow 内仍保留兜底(绑事件与二次确认)
// 悬浮窗样式
const style = document.createElement("style");
style.innerHTML = `
#xxt-helper-window {
position: fixed;
top: 0;
left: 0;
width: 720px; /* 原来900px,缩小为原来的80% */
height: 560px; /* 原来700px,缩小为原来的80% */
background: #fff;
border: 2px solid #444;
border-radius: 8px;
box-shadow: 0 6px 20px rgba(0,0,0,0.25);
z-index: 2147483647 !important; /* 使用最大可能的z-index值 */
display: flex;
flex-direction: column;
overflow: visible !important; /* 允许内容溢出 */
min-width: 240px; /* 原来300px,缩小为原来的80% */
min-height: 160px; /* 原来200px,缩小为原来的80% */
transform: translate(370px, 75px); /* 初始位置用 transform,拖动全程不触发 reflow */
will-change: transform; /* 提示浏览器提前创建合成层 */
max-width: 720px !important; /* 限制最大宽度与原始宽度一致 */
max-height: 560px !important; /* 限制最大高度与原始高度一致 */
contain: none !important; /* 防止被CSS containment限制 */
clip: auto !important; /* 防止被裁剪 */
pointer-events: auto !important; /* 确保鼠标事件正常工作 */
visibility: visible !important; /* 确保可见性 */
opacity: 1 !important; /* 确保不透明 */
box-sizing: content-box !important; /* 确保边框不会增加元素实际大小 */
padding: 0 !important; /* 移除内边距 */
margin: 0 !important; /* 移除外边距 */
font-size: 14px !important; /* 适当缩小字体 */
}
#xxt-helper-header {
background: #444;
color: #fff;
padding: 8px 12px;
cursor: move;
display: flex;
align-items: center;
flex-shrink: 0; /* 防止头部被压缩 */
}
#xxt-helper-header button {
background: transparent;
color: #fff;
border: none;
margin-left: 8px;
cursor: pointer;
font-size: 14px;
padding: 4px 8px;
border-radius: 3px;
transition: background-color 0.2s;
}
#xxt-helper-header button:hover {
background: rgba(255,255,255,0.2);
}
#xxt-helper-content {
flex: 1;
overflow: auto; /* 改为auto显示滚动条 */
padding: 15px;
display: flex;
flex-direction: column;
z-index: 999999; /* 增加层级保证显示 */
}
/* 配置标签样式 */
#config-tabs {
display: flex;
gap: 5px;
margin-bottom: 15px;
border-bottom: 2px solid #eee;
flex-shrink: 0;
}
.config-tab {
background: #f5f5f5;
border: 1px solid #ddd;
border-bottom: none;
padding: 8px 16px;
cursor: pointer;
border-radius: 4px 4px 0 0;
font-size: 14px;
transition: all 0.2s;
white-space: nowrap;
}
.config-tab:hover {
background: #e9e9e9;
}
.config-tab.active {
background: #fff;
border-color: #007bff;
color: #007bff;
font-weight: bold;
}
/* 配置面板样式 */
.config-panel {
display: none;
flex: 1;
overflow-y: auto;
padding: 10px 0;
}
.config-panel.active {
display: block;
}
/* Bootstrap面板样式优化 */
.panel {
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.panel-heading {
background: #f5f5f5;
border-bottom: 1px solid #ddd;
padding: 10px 15px;
font-weight: bold;
border-radius: 4px 4px 0 0;
}
.panel-body {
padding: 15px;
}
.panel-info {
border-color: #bce8f1;
}
.panel-info > .panel-heading {
background: #d9edf7;
border-color: #bce8f1;
color: #31708f;
}
/* 按钮样式优化 */
.btn {
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.42857143;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
text-decoration: none;
transition: all 0.2s;
}
.btn-default {
color: #333;
background-color: #fff;
border-color: #ccc;
}
.btn-default:hover {
color: #333;
background-color: #e6e6e6;
border-color: #adadad;
}
.btn-success {
color: #fff;
background-color: #5cb85c;
border-color: #4cae4c;
}
.btn-success:hover {
color: #fff;
background-color: #449d44;
border-color: #398439;
}
/* 输入框样式 */
input[type="text"], input[type="number"], input[type="password"] {
display: inline-block;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
}
input[type="text"]:focus, input[type="number"]:focus, input[type="password"]:focus {
border-color: #66afe9;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102,175,233,.6);
}
/* 响应式设计 */
@media (max-width: 1200px) {
#xxt-helper-window {
width: 640px; /* 原来800px,缩小为原来的80% */
height: 480px; /* 原来600px,缩小为原来的80% */
}
}
@media (max-width: 1000px) {
#xxt-helper-window {
width: 90vw; /* 改用视窗单位 */
height: 90vh;
left: 5vw;
top: 5vh;
}
.config-tab {
padding: 6px 12px;
font-size: 12px;
}
}
/* 视频倍速输入框显示上下箭头按钮 */
#unrivalRate {
/* 确保显示spinner */
-webkit-appearance: textfield !important;
-moz-appearance: textfield !important;
}
/* 强制显示Webkit浏览器的spinner */
#unrivalRate::-webkit-outer-spin-button,
#unrivalRate::-webkit-inner-spin-button {
-webkit-appearance: inner-spin-button !important;
opacity: 1 !important;
height: 100% !important;
width: 20px !important;
cursor: pointer !important;
display: block !important;
}
/* Firefox浏览器spinner样式 */
#unrivalRate[type="number"] {
-moz-appearance: textfield !important;
}
#unrivalRate[type="number"]::-moz-number-spin-box {
opacity: 1 !important;
display: block !important;
}
.progress-panel {
width: 100%;
min-width: 300px;
max-width: 450px;
padding: 12px 15px;
border-radius: 8px;
background: #ffffff;
box-shadow: 0 4px 12px rgba(23, 162, 184, 0.15);
height: 120px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 4px;
}
.progress-label {
font-size: 11px;
color: #6c757d;
margin-bottom: 2px;
}
.progress-task-name {
font-size: 14px;
font-weight: 600;
color: #212529;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 200px;
}
.progress-percent {
font-size: 20px;
font-weight: 700;
color: #17a2b8;
white-space: nowrap;
}
.progress-meta {
margin: 4px 0 6px;
font-size: 11px;
color: #6c757d;
}
.progress-bar {
width: 100%;
height: 14px;
border-radius: 999px;
background: #e9ecef;
overflow: hidden;
position: relative;
}
.progress-bar-fill {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 0%;
border-radius: 999px;
background: linear-gradient(90deg, #0dcaf0, #0b7fab);
transition: width 0.3s ease;
}
.progress-detail {
margin-top: 6px;
font-size: 11px;
color: #495057;
line-height: 1.4;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`;
// 将样式添加到顶级窗口
try {
const topWindow = window.top || window;
topWindow.document.head.appendChild(style);
} catch (e) {
// 如果出现跨域问题,退回到当前document
document.head.appendChild(style);
}
// 标签切换功能
function initTabSwitching() {
const tabs = top.document.querySelectorAll('.config-tab');
const panels = top.document.querySelectorAll('.config-panel');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
// 移除所有活动状态
tabs.forEach(t => t.classList.remove('active'));
panels.forEach(p => p.classList.remove('active'));
// 添加当前活动状态
tab.classList.add('active');
const targetPanel = top.document.getElementById(tab.dataset.tab);
if (targetPanel) {
targetPanel.classList.add('active');
}
});
});
}
// 初始化标签切换
setTimeout(initTabSwitching, 100);
// 拖动逻辑
// 拖动逻辑
function setupDragging() {
const header = top.document.getElementById("xxt-helper-header");
let isDown = false, startMouseX, startMouseY;
header.addEventListener("pointerdown", e => {
if (e.target.tagName === 'BUTTON') return;
isDown = true;
startMouseX = e.clientX;
startMouseY = e.clientY;
header.setPointerCapture(e.pointerId);
floatWin.style.userSelect = 'none';
e.preventDefault();
});
header.addEventListener("pointermove", e => {
if (!isDown) return;
const rawX = dragCurX + (e.clientX - startMouseX);
const rawY = dragCurY + (e.clientY - startMouseY);
// 边界限制:只保证标题栏不超出浏览器,内容区允许超出
const headerW = header.offsetWidth || 200;
const headerH = header.offsetHeight || 40;
const maxX = (window.top.innerWidth || window.innerWidth) - headerW;
const maxY = (window.top.innerHeight || window.innerHeight) - headerH;
const x = Math.max(0, Math.min(maxX, rawX));
const y = Math.max(0, Math.min(maxY, rawY));
floatWin.style.transform = `translate(${x}px, ${y}px)`;
}, { passive: true });
header.addEventListener("pointerup", e => {
if (!isDown) return;
isDown = false;
const rawX = dragCurX + (e.clientX - startMouseX);
const rawY = dragCurY + (e.clientY - startMouseY);
const headerW = header.offsetWidth || 200;
const headerH = header.offsetHeight || 40;
const maxX = (window.top.innerWidth || window.innerWidth) - headerW;
const maxY = (window.top.innerHeight || window.innerHeight) - headerH;
dragCurX = Math.max(0, Math.min(maxX, rawX));
dragCurY = Math.max(0, Math.min(maxY, rawY));
header.releasePointerCapture(e.pointerId);
floatWin.style.userSelect = '';
if (!isMax) saveFloatPos(dragCurX, dragCurY);
});
header.addEventListener("selectstart", e => {
e.preventDefault();
});
}
// 初始化拖拽功能
setTimeout(setupDragging, 100);
// 按钮逻辑 - 立即设置,不等待其他条件
// 悬浮窗初始化函数
// 悬浮窗初始化函数
function initFloatingWindow() {
const minBtn = top.document.getElementById("xxt-min");
const closeBtn = top.document.getElementById("xxt-close");
if (minBtn) {
minBtn.onclick = () => {
if (!isMinimized) {
// 最小化:只显示标题栏,按钮变为恢复图标
top.document.getElementById("xxt-helper-content").style.display = "none";
top.document.getElementById("xxt-helper-window").style.height = "auto";
top.document.getElementById("xxt-helper-window").style.minHeight = "auto";
// 显示标题栏进度
const minProgress = top.document.getElementById("xxt-min-progress");
if (minProgress) minProgress.style.display = "inline";
isMinimized = true;
try { top.__xxtFloatMinimized = true; } catch (e) { }
minBtn.textContent = '▢';
minBtn.title = '恢复';
} else {
// 恢复:显示完整内容,按钮变回最小化图标
top.document.getElementById("xxt-helper-content").style.display = "flex";
top.document.getElementById("xxt-helper-window").style.height = "560px";
top.document.getElementById("xxt-helper-window").style.minHeight = "160px";
// 隐藏标题栏进度
const minProgress = top.document.getElementById("xxt-min-progress");
if (minProgress) minProgress.style.display = "none";
isMinimized = false;
try { top.__xxtFloatMinimized = false; } catch (e) { }
minBtn.textContent = '─';
minBtn.title = '最小化';
}
};
}
if (closeBtn) {
closeBtn.onclick = () => {
floatWin.style.display = "none";
};
}
// 同页切章后若曾最小化,直接恢复折叠(不模拟 click,避免误切换)
if (isMinimized && minBtn) {
try {
top.document.getElementById("xxt-helper-content").style.display = "none";
top.document.getElementById("xxt-helper-window").style.height = "auto";
top.document.getElementById("xxt-helper-window").style.minHeight = "auto";
const minProgress = top.document.getElementById("xxt-min-progress");
if (minProgress) minProgress.style.display = "inline";
minBtn.textContent = '▢';
minBtn.title = '恢复';
} catch (e) { console.log('[悬浮窗] 恢复最小化状态失败:', e); }
}
// 初始化时更新标题栏版本号显示
const versionSpan = top.document.getElementById('xxt-version');
if (versionSpan && GM_info && GM_info.script && GM_info.script.version) {
versionSpan.textContent = 'v' + GM_info.script.version;
}
}
// 设置按钮事件处理
setTimeout(initFloatingWindow, 200);
var logs = {
"logArry": [],
"addLog": function (str, color = "black") {
if (this.logArry.length >= 50) {
this.logArry.splice(0, 1);
}
var nowTime = new Date();
var nowHour = (Array(2).join(0) + nowTime.getHours()).slice(-2);
var nowMin = (Array(2).join(0) + nowTime.getMinutes()).slice(-2);
var nowSec = (Array(2).join(0) + nowTime.getSeconds()).slice(-2);
this.logArry.push("
[" + nowHour + ":" + nowMin + ":" +
nowSec + "] " + str + "");
let logStr = "";
for (let logI = 0, logLen = this.logArry.length; logI < logLen; logI++) {
logStr += this.logArry[logI] + "
";
}
try {
top.document.getElementById('log').innerHTML = logStr;
var logElement = top.document.getElementById('log');
logElement.scrollTop = logElement.scrollHeight;
} catch (e) {
console.error("日志更新失败:", e);
}
},
"getLogs": function () {
return this.logArry.map(log => {
// 移除HTML标签和时间戳,只返回纯文本内容
return log.replace(/<[^>]*>/g, '').replace(/\[\d{2}:\d{2}:\d{2}\]\s*/, '');
});
}
},
xxtRequestJump = (reason, logMsg) => {
if (jumpType == 2) {
return false;
}
if (!xxtHasNextChapter()) {
stop = true;
xxtNotifyChapterEnd();
return false;
}
try { _w.top.jump = true; } catch (_) { }
logs.addLog(logMsg || '准备跳转下一节…', logMsg && logMsg.indexOf('🎉') >= 0 ? 'green' : 'blue');
console.log('[章节跳转] jump reason=' + reason);
return true;
},
xxtTryNoTaskJump = (logMsg) => {
try {
if (_w.top.xxtNoTaskJumpAttempted) {
return false;
}
_w.top.xxtNoTaskJumpAttempted = true;
} catch (_) { }
return xxtRequestJump('noTasks', logMsg);
},
// 任务切换前清理 cards 侧定时器与测验 iframe(阅读助手模块不在此清理)
cleanupBeforeTask = (reason) => {
let cleared = [];
if (simVideoLoop) {
try { clearInterval(simVideoLoop); } catch (_) { }
simVideoLoop = null;
cleared.push('simVideo');
}
if (realVideoProgressMonitor) {
try { clearInterval(realVideoProgressMonitor); } catch (_) { }
realVideoProgressMonitor = null;
cleared.push('realVideo');
}
if (workInfoLoop) {
try { clearInterval(workInfoLoop); } catch (_) { }
workInfoLoop = null;
cleared.push('workInfo');
}
if (workCheckcross) {
try { clearInterval(workCheckcross); } catch (_) { }
workCheckcross = null;
cleared.push('checkcross');
}
if (workDoneInterval) {
try { clearInterval(workDoneInterval); } catch (_) { }
workDoneInterval = null;
cleared.push('workDone');
}
try {
let fc = top.document.getElementById('frame_content');
if (fc && fc.src && fc.src !== 'about:blank' && fc.src !== '' && fc.src.indexOf('work/phone') >= 0) {
fc.src = 'about:blank';
cleared.push('workIframe');
}
} catch (_) { }
if (cleared.length > 0) {
logs.addLog('🧹 任务切换:已清理脚本定时器与测验 iframe', 'blue');
console.log('[资源清理]' + (reason ? ' ' + reason : '') + ' cleared:', cleared.join(','));
}
},
clampPercent = (value) => {
if (typeof value !== 'number' || isNaN(value)) return 0;
return Math.max(0, Math.min(100, Math.round(value)));
},
progressTracker = {
state: {
taskName: '暂无任务',
percent: 0,
type: '-',
detail: '等待任务开始'
},
elements: {
name: null,
percent: null,
bar: null,
detail: null,
type: null
},
init: function () {
if (!this.elements.name) {
this.elements = {
name: top.document.getElementById('progressTaskName'),
percent: top.document.getElementById('progressTaskPercent'),
bar: top.document.getElementById('progressBarFill'),
detail: top.document.getElementById('progressTaskDetail'),
type: top.document.getElementById('progressTaskType')
};
}
return this.elements.name && this.elements.percent && this.elements.bar && this.elements.detail && this.elements.type;
},
render: function () {
if (!this.init()) return;
// 使用 requestAnimationFrame 优化渲染
if (!this.updateScheduled) {
this.updateScheduled = true;
requestAnimationFrame(() => {
this.updateScheduled = false;
this.elements.name.textContent = this.state.taskName;
this.elements.percent.textContent = this.state.percent + '%';
this.elements.bar.style.width = this.state.percent + '%';
this.elements.bar.setAttribute('aria-valuenow', this.state.percent);
this.elements.detail.textContent = this.state.detail;
this.elements.type.textContent = '类型:' + this.state.type;
// 更新标题栏简化进度显示
const minProgress = top.document.getElementById('xxt-min-progress');
if (minProgress) {
if (this.state.taskName && this.state.taskName !== '暂无任务') {
minProgress.textContent = this.state.taskName + ' ' + this.state.percent + '%';
} else {
minProgress.textContent = '暂无任务';
}
}
});
}
},
update: function (patch = {}) {
this.state = Object.assign({}, this.state, patch);
if (typeof this.state.percent !== 'number') {
this.state.percent = 0;
}
this.state.percent = clampPercent(this.state.percent);
this.render();
},
reset: function (message = '等待任务开始') {
this.update({
taskName: '暂无任务',
percent: 0,
type: '-',
detail: message
});
}
},
getTaskName = (item) => {
if (!item) return '未命名任务';
if (item['name']) return item['name'];
if (item['property']) {
if (item['property']['name']) return item['property']['name'];
if (item['property']['title']) return item['property']['title'];
}
return '未命名任务';
},
buildTaskTitle = (typeLabel, item) => {
return '[' + typeLabel + '] ' + getTaskName(item);
},
reportProgress = (typeLabel, item, percent, detail) => {
progressTracker.update({
taskName: buildTaskTitle(typeLabel, item),
type: typeLabel,
percent: percent,
detail: detail
});
},
formatDuration = (seconds = 0) => {
const total = Math.max(0, Math.floor(Number(seconds) || 0));
const h = Math.floor(total / 3600);
const m = Math.floor((total % 3600) / 60);
const s = total % 60;
const pad = (n) => String(n).padStart(2, '0');
if (h > 0) {
return `${pad(h)}:${pad(m)}:${pad(s)}`;
}
return `${pad(m)}:${pad(s)}`;
},
htmlHook = setInterval(function () {
if (top.document.getElementById('unrivalRate') && top.document.getElementById('updateRateButton') && top.document
.getElementById('reviewModeButton') && top.document.getElementById('autoDoWorkButton') && top.document
.getElementById('autoSubmitButton') && top.document.getElementById('autoSaveButton') && top.document
.getElementById('randomDoButton')) {
if (!backGround) {
top.document.getElementById('fuckMeModeButton').style.display = "none";
}
allowBackground = Math.round(new Date() / 1000) - parseInt(GM_getValue(
'unrivalBackgroundVideoEnable',
'6')) < 15;
if (allowBackground) {
top.document.getElementById('fuckMeModeButton').setAttribute('href', 'unrivalxxtbackground/');
}
clearInterval(htmlHook);
progressTracker.render();
if (cVersion < 86) {
logs.addLog(
'\u60a8\u7684\u6d4f\u89c8\u5668\u5185\u6838\u8fc7\u8001\uff0c\u8bf7\u66f4\u65b0\u7248\u672c\u6216\u4f7f\u7528\u4e3b\u6d41\u6d4f\u89c8\u5668\uff0c\u63a8\u8350\u003c\u0061\u0020\u0068\u0072\u0065\u0066\u003d\u0022\u0068\u0074\u0074\u0070\u0073\u003a\u002f\u002f\u0077\u0077\u0077\u002e\u006d\u0069\u0063\u0072\u006f\u0073\u006f\u0066\u0074\u002e\u0063\u006f\u006d\u002f\u007a\u0068\u002d\u0063\u006e\u002f\u0065\u0064\u0067\u0065\u0022\u0020\u0074\u0061\u0072\u0067\u0065\u0074\u003d\u0022\u0076\u0069\u0065\u0077\u005f\u0077\u0069\u006e\u0064\u006f\u0077\u0022\u003e\u0065\u0064\u0067\u0065\u6d4f\u89c8\u5668\u003c\u002f\u0061\u003e',
'red');
stop = true;
return;
}
if (isMobile) {
logs.addLog('手机浏览器不保证能正常运行此脚本', 'orange');
}
_d.addEventListener('visibilitychange', function () {
let isH = _d.hidden;
if (!isH) {
logs.addLog('挂机功能不稳定,不建议长时间最小化窗口', 'orange');
}
});
top.document.getElementById('unrivalRate').value = rateSimulate;
const rateSelectInit = top.document.getElementById('unrivalRateSelect');
if (rateSelectInit) rateSelectInit.value = String(rateReal);
// 添加上下箭头按钮 - 美化版原生spinner样式
const rateInput = top.document.getElementById('unrivalRate');
if (rateInput && !rateInput.parentNode.querySelector('.rate-controls')) {
const controls = top.document.createElement('div');
controls.className = 'rate-controls';
controls.style.cssText = `
display: inline-block;
vertical-align: top;
margin-left: -1px;
width: 18px;
height: 44px;
border: 1px solid #ccc;
border-left: none;
background: #fff;
position: relative;
border-radius: 0 4px 4px 0;
box-sizing: border-box;
`;
const upBtn = top.document.createElement('div');
upBtn.innerHTML = '▲';
upBtn.style.cssText = `
position: absolute;
top: 0;
left: 0;
right: 0;
height: 22px;
border-bottom: 1px solid #e0e0e0;
background: linear-gradient(to bottom, #fafafa, #f0f0f0);
cursor: pointer;
font-size: 7px;
line-height: 22px;
text-align: center;
color: #555;
user-select: none;
transition: all 0.1s ease;
`;
upBtn.onclick = () => {
const current = parseFloat(rateInput.value) || 1;
rateInput.value = current + 1;
};
const downBtn = top.document.createElement('div');
downBtn.innerHTML = '▼';
downBtn.style.cssText = `
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 22px;
background: linear-gradient(to bottom, #f0f0f0, #fafafa);
cursor: pointer;
font-size: 7px;
line-height: 22px;
text-align: center;
color: #555;
user-select: none;
transition: all 0.1s ease;
`;
downBtn.onclick = () => {
const current = parseFloat(rateInput.value) || 1;
rateInput.value = Math.max(current - 1, 1);
};
// 添加悬停和点击效果
upBtn.onmouseover = () => {
upBtn.style.background = 'linear-gradient(to bottom, #e8f4fd, #d1ecf1)';
upBtn.style.color = '#007bff';
};
upBtn.onmouseout = () => {
upBtn.style.background = 'linear-gradient(to bottom, #fafafa, #f0f0f0)';
upBtn.style.color = '#555';
};
upBtn.onmousedown = () => {
upBtn.style.background = 'linear-gradient(to bottom, #d1ecf1, #bee5eb)';
};
upBtn.onmouseup = () => {
upBtn.style.background = 'linear-gradient(to bottom, #e8f4fd, #d1ecf1)';
};
downBtn.onmouseover = () => {
downBtn.style.background = 'linear-gradient(to bottom, #d1ecf1, #e8f4fd)';
downBtn.style.color = '#007bff';
};
downBtn.onmouseout = () => {
downBtn.style.background = 'linear-gradient(to bottom, #f0f0f0, #fafafa)';
downBtn.style.color = '#555';
};
downBtn.onmousedown = () => {
downBtn.style.background = 'linear-gradient(to bottom, #bee5eb, #d1ecf1)';
};
downBtn.onmouseup = () => {
downBtn.style.background = 'linear-gradient(to bottom, #d1ecf1, #e8f4fd)';
};
controls.appendChild(upBtn);
controls.appendChild(downBtn);
rateInput.parentNode.insertBefore(controls, rateInput.nextSibling);
}
// rate-controls 创建后同步播放模式 UI(真实模式隐藏数字输入框)
try {
if (typeof top.__xxtApplyVideoPlayModeUI === 'function') {
top.__xxtApplyVideoPlayModeUI(videoPlayMode);
}
} catch (e) { }
top.document.getElementById('updateToken').onclick = function () {
var token = top.document.getElementById('token').value;
logs.addLog('题库token已更新为' +token, 'green');
GM_setValue('tikutoken', token);
}
top.document.getElementById('accuracy').value=accuracy;
top.document.getElementById('updateaccuracy').onclick = function () {
var uaccuracy = top.document.getElementById('accuracy').value;
if (parseFloat(uaccuracy) == parseInt(uaccuracy)) {
uaccuracy = parseInt(uaccuracy);
} else {
uaccuracy = parseFloat(uaccuracy);
}
GM_setValue('accuracy', uaccuracy);
accuracy = uaccuracy;
if (uaccuracy >= 0 && uaccuracy<=100) {
logs.addLog('章节测试正确率已更新为'+uaccuracy+'%,将在3秒内生效', 'green');
} else {
logs.addLog('奇怪正确率', 'orange');
}
}
top.document.getElementById('updateRateButton').onclick = function () {
let urate;
if (videoPlayMode === 'real') {
const sel = top.document.getElementById('unrivalRateSelect');
urate = normalizeRealVideoRate(sel ? sel.value : rateReal);
rateReal = urate;
GM_setValue('unrivalrate_real', urate);
if (sel) sel.value = String(urate);
if (urate > 0) {
logs.addLog('真实播放倍速已保存为 ' + urate + ' 倍,下一节视频或刷新页面后生效', 'green');
if (urate > 2) {
logs.addLog('⚠️ 倍速较高,存在被检测风险,请谨慎使用', 'orange');
}
} else {
logs.addLog('奇怪的真实播放倍速,请重新选择', 'orange');
}
} else {
urate = top.document.getElementById('unrivalRate').value;
if (parseFloat(urate) == parseInt(urate, 10)) {
urate = parseInt(urate, 10);
} else {
urate = parseFloat(urate);
}
if (!isFinite(urate)) urate = 1;
rateSimulate = urate;
GM_setValue('unrivalrate_simulate', urate);
top.document.getElementById('unrivalRate').value = urate;
if (urate > 0) {
logs.addLog('模拟倍速已保存为 ' + urate + ' 倍,将在下一节模拟视频生效', 'green');
if (urate > 3) {
logs.addLog('⚠️ 倍速较高,存在被检测风险,请谨慎使用', 'orange');
}
} else {
logs.addLog('奇怪的倍速,将会自动跳过视频任务', 'orange');
}
}
}
top.document.getElementById('reportInterval').value = reportInterval;
top.document.getElementById('updateReportInterval').onclick = function () {
let intervalValue = parseInt(top.document.getElementById('reportInterval').value, 10);
if (isNaN(intervalValue) || intervalValue < 10) {
intervalValue = 90;
logs.addLog('上报间隔设置无效,已恢复为默认 90 秒', 'orange');
}
reportInterval = intervalValue;
GM_setValue('reportInterval', reportInterval);
top.document.getElementById('reportInterval').value = reportInterval;
logs.addLog('视频上报间隔已更新为 ' + reportInterval + ' 秒,将在下次上报时生效', 'green');
}
top.document.getElementById('backGround').onclick = function () {
let backGroundButton = top.document.getElementById('backGround');
if (backGroundButton.getAttribute('class') == 'btn btn-default') {
// 开启挂机:切换为 btn-success(绿色样式)
backGroundButton.setAttribute('class', 'btn btn-success');
logs.addLog('挂机已激活...', 'green'); // 日志文字也同步为绿色,呼应按钮颜色
_w.top.backNow = 1;
GM_setValue('unrivalbackground', '1'); // 保存激活状态
} else {
// 关闭挂机:恢复为 btn-default(默认白色样式)
backGroundButton.setAttribute('class', 'btn btn-default');
logs.addLog('挂机已关闭...', 'green');
_w.top.backNow = 0;
GM_setValue('unrivalbackground', '0'); // 保存取消激活状态
}
}
top.document.getElementById('reviewModeButton').onclick = function () {
let reviewButton = top.document.getElementById('reviewModeButton');
if (reviewButton.getAttribute('class') == 'btn btn-default') {
// 开启复习模式:切换为 btn-success(绿色样式)
reviewButton.setAttribute('class', 'btn btn-success');
logs.addLog('复习模式已开启...', 'green'); // 日志文字也同步为绿色,呼应按钮颜色
GM_setValue('unrivalreview', '1');
_w.top.unrivalReviewMode = '1';
} else {
// 关闭复习模式:恢复为 btn-default(默认白色样式)
reviewButton.setAttribute('class', 'btn btn-default');
logs.addLog('复习模式已关闭...', 'green');
GM_setValue('unrivalreview', '0');
_w.top.unrivalReviewMode = '0';
}
}
top.document.getElementById('autoDoWorkButton').onclick = function () {
let autoDoWorkButton = top.document.getElementById('autoDoWorkButton');
if (autoDoWorkButton.getAttribute('class') == 'btn btn-default') {
// 开启自动答题:切换为 btn-success(绿色样式)
autoDoWorkButton.setAttribute('class', 'btn btn-success');
logs.addLog('自动答题已开启...', 'green'); // 日志文字也同步为绿色,呼应按钮颜色
GM_setValue('unrivaldowork', '1');
_w.top.unrivalDoWork = '1';
} else {
// 关闭自动答题:恢复为 btn-default(默认白色样式)
autoDoWorkButton.setAttribute('class', 'btn btn-default');
logs.addLog('自动答题已关闭...', 'green');
GM_setValue('unrivaldowork', '0');
_w.top.unrivalDoWork = '0';
}
}
top.document.getElementById('autoSubmitButton').onclick = function () {
let autoSubmitButton = top.document.getElementById('autoSubmitButton');
if (autoSubmitButton.getAttribute('class') == 'btn btn-default') {
// 开启自动提交:切换为 btn-success(绿色样式)
autoSubmitButton.setAttribute('class', 'btn btn-success');
logs.addLog('自动提交已开启...', 'green'); // 日志文字也同步为绿色,呼应按钮颜色
GM_setValue('unrivalautosubmit', '1');
_w.top.unrivalAutoSubmit = '1';
} else {
// 关闭自动提交:恢复为 btn-default(默认白色样式)
autoSubmitButton.setAttribute('class', 'btn btn-default');
logs.addLog('自动提交已关闭...', 'green');
GM_setValue('unrivalautosubmit', '0');
_w.top.unrivalAutoSubmit = '0';
}
}
top.document.getElementById('autoSaveButton').onclick = function () {
let autoSaveButton = top.document.getElementById('autoSaveButton');
if (autoSaveButton.getAttribute('class') == 'btn btn-default') {
// 开启自动保存:切换为 btn-success(绿色样式)
autoSaveButton.setAttribute('class', 'btn btn-success');
logs.addLog('自动保存已开启...', 'green'); // 日志文字也同步为绿色,呼应按钮颜色
GM_setValue('unrivalautosave', '1');
_w.top.unrivalAutoSave = '1';
} else {
// 关闭自动保存:恢复为 btn-default(默认白色样式)
autoSaveButton.setAttribute('class', 'btn btn-default');
logs.addLog('自动保存已关闭...', 'green');
GM_setValue('unrivalautosave', '0');
_w.top.unrivalAutoSave = '0';
}
}
top.document.getElementById('randomDoButton').onclick = function () {
let randomDoButton = top.document.getElementById('randomDoButton');
if (randomDoButton.getAttribute('class') == 'btn btn-default') {
// 开启随机答题:切换为 btn-success(绿色样式)
randomDoButton.setAttribute('class', 'btn btn-success');
randomDoButton.innerHTML = '随机答题: 开启';
logs.addLog('随机答题已开启,找不到答案的单选、多选、判断会自动选【C、ABCD、错】', 'green');
GM_setValue('unrivalrandomdo', 1);
_w.top.unrivalRandomDo = 1;
randomDo = 1;
} else {
// 关闭随机答题:恢复为 btn-default(默认白色样式)
randomDoButton.setAttribute('class', 'btn btn-default');
randomDoButton.innerHTML = '随机答题: 关闭';
logs.addLog('随机答题已关闭...', 'green');
GM_setValue('unrivalrandomdo', 0);
_w.top.unrivalRandomDo = 0;
randomDo = 0;
}
}
top.document.getElementById('videoTimeButton').onclick = function () {
top.document.getElementById('videoTime').style.display = 'block';
top.document.getElementById('videoTimeContent').src = _p +
'//stat2-ans.chaoxing.com/task/s/index?courseid=' + courseId + '&clazzid=' +
classId;
}
// 初始设置按钮状态和颜色
top.document.getElementById('jumpTypeButton').textContent = '模式: ' + (jumpType === 0 ? '智能' : jumpType === 1 ? '遍历' : '不跳转');
top.document.getElementById('disableMonitorButton').textContent = '多端学习: ' + (disableMonitor === 1 ? '解除' : '启用');
top.document.getElementById('autoLoginButton').textContent = '自动登录: ' + (autoLogin === 1 ? '开启' : '关闭');
top.document.getElementById('videoQuestionButton').textContent = '视频题目: ' + (videoQuestionEnabled ? '开启' : '关闭');
top.document.getElementById('autoStartButton').textContent = '自动阅读: ' + (GM_getValue('autoStart', true) ? '开启' : '关闭');
top.document.getElementById('phoneNumber').value = GM_getValue('phoneNumber', '');
top.document.getElementById('password').value = GM_getValue('password', '');
// 设置初始按钮颜色
if (disableMonitor === 1) {
top.document.getElementById('disableMonitorButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('disableMonitorButton').setAttribute('class', 'btn btn-default');
}
if (autoLogin === 1) {
top.document.getElementById('autoLoginButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('autoLoginButton').setAttribute('class', 'btn btn-default');
}
if (videoQuestionEnabled) {
top.document.getElementById('videoQuestionButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('videoQuestionButton').setAttribute('class', 'btn btn-default');
}
// 视频播放模式、自动静音与倍速控件初始化
(function initVideoPlayModeUI() {
const radioReal = top.document.getElementById('videoModeReal');
const radioSim = top.document.getElementById('videoModeSimulate');
const muteCb = top.document.getElementById('autoMuteVideoCheckbox');
const muteLabel = top.document.getElementById('autoMuteVideoLabel');
const rateInput = top.document.getElementById('unrivalRate');
const rateSelect = top.document.getElementById('unrivalRateSelect');
// 1) radio 初始选中
if (videoPlayMode === 'real') {
if (radioReal) radioReal.checked = true;
} else {
if (radioSim) radioSim.checked = true;
}
// 2) checkbox 初始选中
if (muteCb) muteCb.checked = !!autoMuteVideo;
// 3) 双倍速控件:根据模式切显示 + 自动静音是否生效的视觉提示
const applyModeUI = (mode) => {
if (rateInput && rateSelect) {
if (mode === 'real') {
rateInput.style.display = 'none';
rateSelect.style.display = 'inline-block';
// input 自带的上下箭头容器也一起隐藏
const ctrls = rateInput.parentNode && rateInput.parentNode.querySelector('.rate-controls');
if (ctrls) ctrls.style.display = 'none';
} else {
rateInput.style.display = 'inline-block';
rateSelect.style.display = 'none';
const ctrls = rateInput.parentNode && rateInput.parentNode.querySelector('.rate-controls');
if (ctrls) ctrls.style.display = 'inline-block';
}
}
if (muteLabel) muteLabel.style.opacity = (mode === 'real') ? '1' : '0.5';
};
applyModeUI(videoPlayMode);
// 4) select 同步真实播放倍速(0.75~3,步进 0.25)
if (rateSelect) {
rateSelect.value = String(rateReal);
}
if (rateInput) {
rateInput.value = rateSimulate;
}
// 暴露给后续事件用
top.__xxtApplyVideoPlayModeUI = applyModeUI;
})();
// 自动阅读按钮颜色初始化
if (GM_getValue('autoStart', true)) {
top.document.getElementById('autoStartButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('autoStartButton').setAttribute('class', 'btn btn-default');
}
randomDo = GM_getValue('unrivalrandomdo', 0);
try { _w.top.unrivalRandomDo = randomDo; } catch (_) { }
if (randomDo == 1) {
top.document.getElementById('randomDoButton').setAttribute('class', 'btn btn-success');
top.document.getElementById('randomDoButton').innerHTML = '随机答题: 开启';
} else {
top.document.getElementById('randomDoButton').setAttribute('class', 'btn btn-default');
top.document.getElementById('randomDoButton').innerHTML = '随机答题: 关闭';
}
// jumpType切换事件
top.document.getElementById('jumpTypeButton').onclick = function () {
jumpType = (jumpType + 1) % 3;
let modeText = ['智能', '遍历', '不跳转'][jumpType];
this.textContent = '模式: ' + modeText;
GM_setValue('jumpType', jumpType);
logs.addLog('已切换到' + modeText + '模式', 'green');
};
// disableMonitor切换事件
top.document.getElementById('disableMonitorButton').onclick = function () {
disableMonitor = (disableMonitor === 1) ? 0 : 1;
let statusText = (disableMonitor === 1) ? '解除' : '启用';
this.textContent = '多端学习: ' + statusText;
GM_setValue('disableMonitor', disableMonitor);
if (disableMonitor === 1) {
this.setAttribute('class', 'btn btn-success');
logs.addLog('多端学习已开启', 'green');
// 立即劫持appendChild,防止监控脚本注入
_w.appendChild = _w.Element.prototype.appendChild;
_w.Element.prototype.appendChild = function () {
try {
if (arguments[0].src && arguments[0].src.indexOf('detect.chaoxing.com') > 0) {
return;
}
} catch (e) { }
_w.appendChild.apply(this, arguments);
};
} else {
this.setAttribute('class', 'btn btn-default');
logs.addLog('多端学习已关闭', 'green');
// 立即恢复原生appendChild
if (_w.appendChild) {
_w.Element.prototype.appendChild = _w.appendChild;
}
}
};
// autoLogin切换事件
top.document.getElementById('autoLoginButton').onclick = function () {
autoLogin = (autoLogin === 1) ? 0 : 1;
this.textContent = '自动登录: ' + (autoLogin === 1 ? '开启' : '关闭');
GM_setValue('autoLogin', autoLogin);
if (autoLogin === 1) {
this.setAttribute('class', 'btn btn-success');
logs.addLog('自动登录功能已开启', 'green');
} else {
this.setAttribute('class', 'btn btn-default');
logs.addLog('自动登录功能已关闭', 'green');
}
};
// videoQuestion切换事件
top.document.getElementById('videoQuestionButton').onclick = function () {
videoQuestionEnabled = !videoQuestionEnabled;
this.textContent = '视频题目: ' + (videoQuestionEnabled ? '开启' : '关闭');
GM_setValue('videoQuestionEnabled', videoQuestionEnabled);
if (videoQuestionEnabled) {
this.setAttribute('class', 'btn btn-success');
logs.addLog('视频题目自动处理功能已开启', 'green');
} else {
this.setAttribute('class', 'btn btn-default');
logs.addLog('视频题目自动处理功能已关闭', 'green');
}
};
// 视频播放模式切换事件
(function bindVideoPlayModeEvents() {
const radios = top.document.querySelectorAll('input[name="videoPlayMode"]');
const rateInput = top.document.getElementById('unrivalRate');
const rateSelect = top.document.getElementById('unrivalRateSelect');
const muteCb = top.document.getElementById('autoMuteVideoCheckbox');
const onModeChange = (newMode) => {
videoPlayMode = newMode;
GM_setValue('videoPlayMode', videoPlayMode);
if (typeof top.__xxtApplyVideoPlayModeUI === 'function') {
top.__xxtApplyVideoPlayModeUI(newMode);
}
if (newMode === 'real') {
if (rateSelect) rateSelect.value = String(rateReal);
logs.addLog('已切换为真实播放模式(实际播放视频,由学习通自身上报进度),倍速:' + rateReal + 'x', 'green');
} else {
if (rateInput) rateInput.value = rateSimulate;
logs.addLog('已切换为模拟模式(不实际播放,由脚本上报进度),倍速:' + rateSimulate + 'x', 'blue');
}
};
radios.forEach(r => {
r.addEventListener('change', function () {
if (this.checked) onModeChange(this.value);
});
});
if (muteCb) {
muteCb.addEventListener('change', function () {
autoMuteVideo = !!this.checked;
GM_setValue('autoMuteVideo', autoMuteVideo);
logs.addLog(autoMuteVideo ?
'真实播放模式下将自动静音' :
'真实播放模式下不再自动静音',
autoMuteVideo ? 'green' : 'blue');
});
}
})();
// 自动阅读按钮切换事件
top.document.getElementById('autoStartButton').onclick = function () {
const currentAutoStart = GM_getValue('autoStart', true);
const newAutoStart = !currentAutoStart;
GM_setValue('autoStart', newAutoStart);
this.textContent = '自动阅读: ' + (newAutoStart ? '开启' : '关闭');
if (newAutoStart) {
this.setAttribute('class', 'btn btn-success');
logs.addLog('自动阅读功能已开启', 'green');
} else {
this.setAttribute('class', 'btn btn-default');
logs.addLog('自动阅读功能已关闭', 'green');
}
};
// 保存登录信息事件
top.document.getElementById('saveLoginInfo').onclick = function () {
let newPhone = top.document.getElementById('phoneNumber').value;
let newPassword = top.document.getElementById('password').value;
if (newPhone && !/^1[3-9]\d{9}$/.test(newPhone)) {
logs.addLog('手机号格式错误,请重新输入', 'red');
return;
}
GM_setValue('phoneNumber', newPhone);
GM_setValue('password', newPassword);
phoneNumber = newPhone;
password = newPassword;
logs.addLog('登录信息已保存', 'green');
};
}
}, 100),
loopjob = () => {
if (_w.top.unrivalScriptList.length > 1) {
logs.addLog('您同时开启了多个刷课脚本,建议关闭其他脚本,否则会有挂科风险!', 'red');
}
if (cVersion < 8.6 * 10) {
logs.addLog(
'\u60a8\u7684\u6d4f\u89c8\u5668\u5185\u6838\u8fc7\u8001\uff0c\u8bf7\u66f4\u65b0\u7248\u672c\u6216\u4f7f\u7528\u4e3b\u6d41\u6d4f\u89c8\u5668\uff0c\u63a8\u8350\u003c\u0061\u0020\u0068\u0072\u0065\u0066\u003d\u0022\u0068\u0074\u0074\u0070\u0073\u003a\u002f\u002f\u0077\u0077\u0077\u002e\u006d\u0069\u0063\u0072\u006f\u0073\u006f\u0066\u0074\u002e\u0063\u006f\u006d\u002f\u007a\u0068\u002d\u0063\u006e\u002f\u0065\u0064\u0067\u0065\u0022\u0020\u0074\u0061\u0072\u0067\u0065\u0074\u003d\u0022\u0076\u0069\u0065\u0077\u005f\u0077\u0069\u006e\u0064\u006f\u0077\u0022\u003e\u0065\u0064\u0067\u0065\u6d4f\u89c8\u5668\u003c\u002f\u0061\u003e',
'red');
stop = true;
return;
}
if (stop) {
return;
}
try {
if (top.__xxtNativeWorkResuming && missionList['m' + top.__xxtNativeWorkResuming]) {
setTimeout(loopjob, 800);
return;
}
if (top.__xxtNativeWorkResume && top.__xxtNativeWorkResume.jobid && missionList['m' + top.__xxtNativeWorkResume.jobid]) {
setTimeout(loopjob, 800);
return;
}
} catch (_) { }
let missionli = missionList;
if (missionli == []) {
setTimeout(loopjob, 500);
return;
}
for (let itemName in missionli) {
if (missionli[itemName]['running']) {
setTimeout(loopjob, 500);
return;
}
}
for (let itemName in missionli) {
if (!missionli[itemName]['done']) {
cleanupBeforeTask('loopjob');
switch (missionli[itemName]['type']) {
case 'video':
doVideo(missionli[itemName]).catch(e => {
logs.addLog('视频任务执行出错: ' + e.message, 'red');
});
break;
case 'document':
doDocument(missionli[itemName]);
break;
case 'work':
doWork(missionli[itemName]);
break;
}
setTimeout(loopjob, 500);
return;
}
}
if (busyThread <= 0) {
if (jumpType != 2) {
xxtRequestJump('allDone', '🎉 所有任务处理完毕,准备跳转下一节');
} else {
logs.addLog('所有任务处理完毕,用户设置为不跳转,脚本已结束运行,如需自动跳转,请到任务配置界面改变模式为遍历', 'green');
}
clearInterval(loopjob);
} else {
setTimeout(loopjob, 500);
}
},
readyCheck = () => {
setTimeout(function () {
try {
if (!xxtHasNextChapter() && !xxtChapterEndLogged) {
xxtChapterEndLogged = true;
logs.addLog('已是最后一章,无下一节可跳转,本页任务完成后脚本将停止', 'green');
}
if (!isCat) {
logs.addLog(
'推荐使用
脚本猫运行此脚本,使用其他脚本管理器不保证能正常运行',
'orange');
}
if (_w.top.unrivalReviewMode == '1') {
logs.addLog('复习模式已开启,遇到已完成的视频任务不会跳过', 'green');
top.document.getElementById('reviewModeButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('reviewModeButton').setAttribute('class', 'btn btn-default');
}
var backGroundStatus = GM_getValue('unrivalbackground', '0');
if (backGroundStatus === '1') {
_w.top.backNow = 1;
top.document.getElementById('backGround').setAttribute('class', 'btn btn-success'); // 设置按钮为绿色
} else {
top.document.getElementById('backGround').setAttribute('class', 'btn btn-default'); // 设置按钮为白色
}
if (_w.top.unrivalDoWork == '1') {
logs.addLog('自动做章节测试已开启,将会自动做章节测试', 'green');
top.document.getElementById('autoDoWorkButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('autoDoWorkButton').setAttribute('class', 'btn btn-default');
}
if (_w.top.unrivalAutoSubmit == '1') {
top.document.getElementById('autoSubmitButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('autoSubmitButton').setAttribute('class', 'btn btn-default');
}
if (_w.top.unrivalAutoSave == '1') {
top.document.getElementById('autoSaveButton').setAttribute('class', 'btn btn-success');
} else {
top.document.getElementById('autoSaveButton').setAttribute('class', 'btn btn-default');
}
if (_w.top.unrivalRandomDo == 1) {
top.document.getElementById('randomDoButton').setAttribute('class', 'btn btn-success');
top.document.getElementById('randomDoButton').innerHTML = '随机答题: 开启';
} else {
top.document.getElementById('randomDoButton').setAttribute('class', 'btn btn-default');
top.document.getElementById('randomDoButton').innerHTML = '随机答题: 关闭';
}
} catch (e) {
console.log(e);
readyCheck();
return;
}
}, 500);
}
readyCheck();
try {
var pageData = JSON.parse(param);
} catch (e) {
if (jumpType != 2) {
xxtTryNoTaskJump('ℹ️ 此页无任务,准备跳转下一节');
} else {
logs.addLog('此页无任务,用户设置为不跳转,脚本已结束运行,如需自动跳转,请到任务配置界面改变模式为遍历', 'green');
}
return;
}
let data = pageData['defaults'],
jobList = [],
classId = data['clazzId'],
chapterId = data['knowledgeid'],
reportUrl = data['reportUrl'],
ktoken = data['ktoken'];
UID = UID || data['userid'];
FID = FID || data['fid'];
for (let i = 0, l = pageData['attachments'].length; i < l; i++) {
let item = pageData['attachments'][i];
if (item['job'] != true || item['isPassed'] == true) {
if (_w.top.unrivalReviewMode == '1' && item['type'] == 'video') {
jobList.push(item);
}
continue;
} else {
jobList.push(item);
}
}
// 从 mArg 读取已学进度(毫秒转秒)
getTaskPlayedTimeSec = (attachmentItem) => {
if (attachmentItem['headOffset'] > 0) {
return Math.floor(attachmentItem['headOffset'] / 1000);
}
if (attachmentItem['playTime'] > 0) {
return Math.floor(attachmentItem['playTime'] / 1000);
}
return 0;
},
// 从页面 video 元素读取当前播放位置(用于续播)
getIframePlayedTimeSec = (objectId) => {
if (!objectId) {
return 0;
}
const mediaIframes = _d.querySelectorAll(
'iframe.ans-insertvideo-online, iframe[src*="/ananas/modules/video/"], iframe[src*="/ananas/modules/audio/"]'
);
for (let i = 0, l = mediaIframes.length; i < l; i++) {
try {
const dataAttr = mediaIframes[i].getAttribute('data');
if (!dataAttr) {
continue;
}
const data = JSON.parse(dataAttr);
if (!data || data.objectid !== objectId) {
continue;
}
const iframeDoc = mediaIframes[i].contentDocument ||
(mediaIframes[i].contentWindow && mediaIframes[i].contentWindow.document);
if (!iframeDoc) {
continue;
}
const media = iframeDoc.querySelector('video') || iframeDoc.querySelector('audio');
if (media && media.currentTime > 0) {
return Math.floor(media.currentTime);
}
} catch (e) { }
}
return 0;
},
video_getReady = (item) => {
let taskPlayedTimeSec = getTaskPlayedTimeSec(item),
statusUrl = _p + '//' + _h + '/ananas/status/' + item['property']['objectid'] + '?k=' +
FID + '&flag=normal&_dc=' + String(Math.round(new Date())),
doubleSpeed = item['property']['doublespeed'];
busyThread += 1;
gmRequest({
method: "get",
headers: {
'Host': _h,
'Referer': vrefer,
'Sec-Fetch-Site': 'same-origin'
},
url: statusUrl,
onload: function (res) {
try {
busyThread -= 1;
let videoInfo = JSON.parse(res.responseText),
duration = videoInfo['duration'],
dtoken = videoInfo['dtoken'];
if (duration == undefined) {
top.document.getElementById('joblist').innerHTML += `
` + '[无效视频]' + item['property']['name'] + `
`
return;
}
missionList['m' + item['jobid']] = {
'module': item['property']['module'],
'type': 'video',
'dtoken': dtoken,
'duration': duration,
'objectId': item['property']['objectid'],
'property': item['property'],
'rt': item['property']['rt'] || '0.9',
'otherInfo': item['otherInfo'],
'doublespeed': doubleSpeed,
'jobid': item['jobid'],
'name': item['property']['name'],
'taskPlayedTimeSec': taskPlayedTimeSec,
'isPassed': item['isPassed'] == true,
'done': false,
'running': false
};
top.document.getElementById('joblist').innerHTML += `
` + '[视频]' + item['property']['name'] + `
`
} catch (e) { }
},
onerror: function (err) {
console.log(err);
if (err.error.indexOf('@connect list') >= 0) {
logs.addLog('请添加安全网址,将 【 //@connect ' + _h +
' 】方括号里的内容(不包括方括号)添加到脚本代码内指定位置,否则脚本无法正常运行,如图所示:', 'red');
logs.addLog(
'

'
);
stop = true;
} else {
logs.addLog('获取任务详情失败', 'red');
logs.addLog('错误原因:' + err.error, 'red');
}
}
});
},
// 视频题目处理相关函数
parseVideoCpi = (item) => {
const fromQuery = getQueryVariable('cpi');
if (fromQuery) return fromQuery;
const other = (item && item['otherInfo']) || '';
const om = other.match(/cpi_(\d+)/);
if (om) return om[1];
if (reportUrl) {
const rm = String(reportUrl).match(/\/a\/(\d+)/);
if (rm) return rm[1];
}
return UID;
},
requestVideoQuestionInit = (url) => {
return new Promise((resolve, reject) => {
gmRequest({
method: "get",
url: url,
headers: {
'Host': _h,
'Referer': vrefer,
'Sec-Fetch-Site': 'same-origin',
'User-Agent': navigator.userAgent,
'X-Requested-With': 'XMLHttpRequest'
},
timeout: 10000,
onload: function(res) {
try {
if (res.status === 200) {
resolve(JSON.parse(res.responseText));
} else {
reject(new Error('HTTP ' + res.status));
}
} catch (e) {
reject(e);
}
},
onerror: function(err) {
reject(err);
},
ontimeout: function() {
reject(new Error('Request timeout'));
}
});
});
},
initVideoQuestions = async (mid, cpi, classid, courseid) => {
const dc = new Date().valueOf();
const midEnc = encodeURIComponent(mid);
const videoCourseId = courseid || (data && data['courseid']) || courseId || '';
const candidates = [];
const seen = {};
const pushCandidate = (url) => {
if (!url || seen[url]) return;
seen[url] = true;
candidates.push(url);
};
const v2Query = 'mid=' + midEnc + '&cpi=' + cpi + '&classid=' + classid +
(videoCourseId ? '&courseid=' + videoCourseId : '') + '&_dc=' + dc;
pushCandidate(_p + '//' + _h + '/mooc-ans/richvideo/initdatawithviewerV2?' + v2Query);
const initdataUrl = data && data['initdataUrl'];
if (initdataUrl) {
const v2FromInit = initdataUrl.replace(/initdatawithviewer$/i, 'initdatawithviewerV2');
if (v2FromInit !== initdataUrl) {
pushCandidate(v2FromInit + '?' + v2Query);
}
pushCandidate(initdataUrl + '?start=undefined&mid=' + midEnc + '&_dc=' + dc);
pushCandidate(initdataUrl + '?mid=' + midEnc + '&cpi=' + cpi + '&classid=' + classid + '&_dc=' + dc);
}
pushCandidate(_p + '//' + _h + '/richvideo/initdatawithviewer?start=undefined&mid=' + midEnc + '&_dc=' + dc);
pushCandidate(_p + '//' + _h + '/ananas/initdatawithviewer?mid=' + midEnc + '&cpi=' + cpi + '&classid=' + classid + '&_dc=' + dc);
let lastErr = null;
let lastEmpty = null;
for (let i = 0; i < candidates.length; i++) {
try {
const result = await requestVideoQuestionInit(candidates[i]);
const count = Array.isArray(result) ? result.length : 0;
if (count > 0) {
return result;
}
lastEmpty = result;
} catch (e) {
lastErr = e;
}
}
if (lastEmpty !== null) {
return lastEmpty;
}
throw lastErr || new Error('initVideoQuestions failed');
},
flattenVideoQuestionItems = (res) => {
const out = [];
const seen = new WeakSet();
const walk = (node, depth) => {
if (!node || depth > 6) return;
if (Array.isArray(node)) {
node.forEach(n => walk(n, depth + 1));
return;
}
if (typeof node !== 'object') return;
if (seen.has(node)) return;
const options = node.options;
const hasOptions = Array.isArray(options) && options.length > 0;
const resourceId = node.resourceId || node.eventid || node.eventId;
if (hasOptions && (resourceId || node.description || node.title)) {
seen.add(node);
out.push(node);
return;
}
if (Array.isArray(node.datas)) {
node.datas.forEach(d => walk(d, depth + 1));
return;
}
if (node.datas && typeof node.datas === 'object') {
walk(node.datas, depth + 1);
return;
}
Object.keys(node).forEach(k => {
if (k !== 'options') walk(node[k], depth + 1);
});
};
walk(res, 0);
return out;
},
pickVideoQuestionAnswer = (item1) => {
const options = item1.options;
if (!options || !options.length) return '';
const right = options.filter(o => o.isRight === true || o.isRight === 1 ||
o.isRight === '1' || o.isRight === 'true');
if (right.length) {
return right.map(o => (o.name || o.content || '').trim()).filter(Boolean).join('');
}
const fromField = item1.rightAnswer || item1.answer || item1.correctAnswer ||
item1.rightOption || item1.standardAnswer;
if (fromField) {
return String(fromField).replace(/[^A-Ga-g]/g, '').toUpperCase();
}
return '';
},
normalizeVideoQuizText = (text) => {
return String(text || '').replace(/<[^>]+>/g, '').replace(/\s+/g, '')
.replace(/[(())]/g, '').toLowerCase();
},
matchVideoQuestionFromCache = (cache, domText) => {
if (!cache || !cache.length) return null;
const normDom = normalizeVideoQuizText(domText);
if (normDom) {
for (let i = 0; i < cache.length; i++) {
const normQ = normalizeVideoQuizText(cache[i].description);
if (!normQ) continue;
if (normDom.indexOf(normQ) >= 0 || normQ.indexOf(normDom) >= 0) {
return cache[i];
}
}
}
return cache.length === 1 ? cache[0] : null;
},
clickVideoQuizOptionByAnswer = (optionLabels, answerLetter) => {
if (!answerLetter || !optionLabels || !optionLabels.length) return false;
const letter = String(answerLetter).trim().charAt(0).toUpperCase();
for (let i = 0; i < optionLabels.length; i++) {
const label = optionLabels[i];
const text = (label.textContent || '').trim();
if (text.startsWith(letter) || text.startsWith(letter + '.') ||
text.startsWith(letter + '、') || text.startsWith(letter + '.')) {
label.click();
return true;
}
const input = label.querySelector('input');
if (input && String(input.value || '').toUpperCase() === letter) {
label.click();
return true;
}
}
const idx = letter.charCodeAt(0) - 65;
if (idx >= 0 && idx < optionLabels.length) {
optionLabels[idx].click();
return true;
}
return false;
},
buildVideoQuestionCache = async (item) => {
const videoMid = (item['property'] && item['property']['mid']) || item['videoMid'] || '';
if (!videoMid) return [];
const videoCpi = parseVideoCpi(item);
const res = await initVideoQuestions(videoMid, videoCpi, classId, data && data['courseid']);
if (!res || !res.length) return [];
const questionList = flattenVideoQuestionItems(res);
if (!questionList.length) return [];
const cache = [];
for (let i = 0; i < questionList.length; i++) {
const q = questionList[i];
let answer = pickVideoQuestionAnswer(q);
if (!answer) {
const resourceId = q.resourceId || q.eventid || q.eventId;
if (resourceId) {
const submitResult = await trySubmitVideoQuestion(item, q, videoCpi, '');
if (submitResult) answer = submitResult.answer;
}
}
if (!answer) continue;
cache.push({
description: q.description || q.title || '',
answer: answer
});
}
return cache;
},
trySubmitVideoQuestion = async (item, item1, videoCpi, presetAnswer) => {
const objectId = item['objectId'];
const resourceId = item1.resourceId || item1.eventid || item1.eventId;
const memberinfo = item1.memberinfo || item1.memberInfo || '';
const description = item1.description || item1.title || '视频内题目';
const answerList = [];
const addAnswer = (v) => {
const ans = (v || '').trim();
if (ans && !answerList.includes(ans)) answerList.push(ans);
};
addAnswer(presetAnswer);
(item1.options || []).forEach(o => addAnswer(o.name || o.content));
for (let i = 0; i < answerList.length; i++) {
try {
const res1 = await submitVideoAnswer(classId, videoCpi, objectId, resourceId, memberinfo, answerList[i]);
if (res1 && res1.status) {
return { answer: answerList[i], res1: res1, description: description };
}
} catch (e) { }
}
return null;
},
submitVideoAnswer = async (classid, cpi, objectid, eventid, memberinfo, answer) => {
return new Promise((resolve, reject) => {
let url = `${_p}//${_h}/question/quiz-validation?classid=${classid}&cpi=${cpi}&objectid=${objectid}&_dc=${new Date().valueOf()}&eventid=${eventid}&memberinfo=${memberinfo}&answerContent=${answer}`;
gmRequest({
method: "get",
url: url,
headers: {
'Host': _h,
'Referer': vrefer,
'Sec-Fetch-Site': 'same-origin',
'User-Agent': navigator.userAgent
},
timeout: 10000,
onload: function(res) {
try {
if (res.status === 200) {
let data = JSON.parse(res.responseText);
resolve(data);
} else {
reject(new Error(`HTTP ${res.status}`));
}
} catch (e) {
reject(e);
}
},
onerror: function(err) {
if (err.error && err.error.includes("connect list")) {
const domain = err.error.match(/:\/\/(.[^/]+)/)[1];
const notice = `由于connect未添加导致无权限请求
请复制以下代码至脚本中的第19行位置
// @connect ${domain}`;
logs.addLog(notice, 'red');
} else {
logs.addLog(`请求报错[${url} - GET][${err.statusText || 'timeout'}]`, 'red');
}
reject(err);
},
ontimeout: function() {
logs.addLog(`请求报错[${url} - GET][timeout]`, 'red');
reject(new Error('Request timeout'));
}
});
});
},
// 分析视频任务失败原因
analyzeVideoTaskFailure = (item, playTime, duration, isdrag, ispass) => {
let reasons = [];
let suggestions = [];
// 1. 检查视频题目处理状态
if (videoQuestionEnabled) {
reasons.push("视频题目:已启用自动处理 ✅");
// 检查是否有题目处理记录
let questionLogs = logs.getLogs().filter(log =>
log.includes('正在完成视频中的题目') ||
log.includes('视频内无提问') ||
log.includes('视频题目已完毕')
);
if (questionLogs.length > 0) {
reasons.push("题目处理:有处理记录 ✅");
} else {
reasons.push("题目处理:无处理记录 ⚠️");
suggestions.push("检查视频是否真的有题目");
}
} else {
reasons.push("视频题目:未启用自动处理 ⚠️");
suggestions.push("建议开启视频题目自动处理功能");
}
// 2. 检查学习时长
let durationPercent = (playTime / duration * 100).toFixed(1);
if (playTime >= duration) {
reasons.push(`学习时长:${playTime}秒 (要求:${duration}秒) ${durationPercent}% ✅`);
} else {
reasons.push(`学习时长:${playTime}秒 (要求:${duration}秒) ${durationPercent}% ❌`);
suggestions.push("增加播放时长");
}
// 3. 检查倍速设置
const activeRate = videoPlayMode === 'real' ? rateReal : rateSimulate;
if (activeRate > 3) {
reasons.push(`播放倍速:${activeRate}倍 (高风险) ⚠️⚠️`);
suggestions.push("降低倍速到1-2倍");
} else if (activeRate > 2) {
reasons.push(`播放倍速:${activeRate}倍 (可能被检测) ⚠️`);
suggestions.push("建议降低倍速到1-2倍");
} else {
reasons.push(`播放倍速:${activeRate}倍 ✅`);
}
// 4. 检查服务器响应状态
if (isdrag === '4') {
reasons.push("服务器状态:isdrag=4 (时长足够但未确认完成)");
suggestions.push("开启复习模式重新播放");
}
// 5. 检查任务通过状态
if (ispass) {
if (ispass.isPassed === true) {
reasons.push("任务状态:已通过验证 ✅");
} else {
reasons.push("任务状态:未通过验证 ❌");
suggestions.push("检查是否有遗漏的交互要求");
}
} else {
reasons.push("任务状态:未知状态 ⚠️");
}
// 6. 检查复习模式
if (_w.top.unrivalReviewMode === '1') {
reasons.push("当前模式:复习模式 ✅");
} else {
reasons.push("当前模式:普通模式");
suggestions.push("尝试开启复习模式");
}
// 7. 检查网络状态
reasons.push("网络状态:正常 ✅");
// 8. 添加通用建议
if (suggestions.length === 0) {
suggestions.push("1. 开启复习模式");
suggestions.push("2. 使用1倍速重新播放");
suggestions.push("3. 如果仍不通过,手动点击视频确认完成");
}
return {
reasons: reasons,
suggestions: suggestions
};
},
finishVideoQuestions = async (item) => {
try {
logs.addLog(`[${item['name']}]获取视频中的题目`, 'info');
if (!item) {
logs.addLog('视频对象为空', 'error');
return false;
}
const videoMid = (item['property'] && item['property']['mid']) || item['videoMid'] || '';
if (!videoMid) {
if (!item['property']) {
logs.addLog(`[${item['name']}]缺少视频 property(任务数据未传入,无法拉题)`, 'orange');
} else {
logs.addLog(`[${item['name']}]缺少视频 mid,无法拉取题目`, 'orange');
logs.addLog(`property结构: ${JSON.stringify(item['property'], null, 2)}`, 'info');
}
logs.addLog(`[${item['name']}]已跳过视频内题目`, 'info');
return true;
}
// 获取视频题目(cpi 来自 URL / otherInfo,不是 UID)
const videoCpi = parseVideoCpi(item);
let res = await initVideoQuestions(videoMid, videoCpi, classId, data && data['courseid']);
if (!res || res.length === 0) {
logs.addLog(`[${item['name']}]视频题目已完毕`, 'green');
return true;
}
const questionList = flattenVideoQuestionItems(res);
if (!questionList.length) {
logs.addLog(`[${item['name']}]视频题目解析失败(接口返回 ${res.length} 条,未找到可答题目)`, 'orange');
return true;
}
logs.addLog(`[${item['name']}]解析到 ${questionList.length} 道视频题`, 'info');
for (const item1 of questionList) {
try {
const resourceId = item1.resourceId || item1.eventid || item1.eventId;
if (!item1.options || !item1.options.length) {
logs.addLog('题目缺少选项,已跳过', 'orange');
continue;
}
if (!resourceId) {
logs.addLog('题目缺少 resourceId/eventid,已跳过', 'orange');
continue;
}
const memberinfo = item1.memberinfo || item1.memberInfo || '';
const description = item1.description || item1.title || '视频内题目';
let answer = pickVideoQuestionAnswer(item1);
let submitResult = null;
if (answer) {
const res1 = await submitVideoAnswer(classId, videoCpi, item['objectId'], resourceId, memberinfo, answer);
if (res1 && res1.status) {
submitResult = { answer: answer, res1: res1, description: description };
}
}
if (!submitResult) {
submitResult = await trySubmitVideoQuestion(item, item1, videoCpi, answer);
}
if (submitResult) {
const ansLabel = submitResult.res1.isRight ? '正确答案' : '尝试答案';
logs.addLog(`[正在完成视频中的题目]:${submitResult.description}
${ansLabel}: ${submitResult.answer}`, submitResult.res1.isRight ? 'green' : 'orange');
} else {
logs.addLog(`[${description}]视频题目提交失败(已尝试全部选项)`, 'error');
}
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (e) {
logs.addLog('处理视频题目异常: ' + (e.message || e), 'error');
}
}
logs.addLog(`[${item['name']}]视频题目已完毕`, 'green');
return true;
} catch (e) {
logs.addLog(`[${item['name']}]处理视频题目时出错: ${e.message}`, 'red');
logs.addLog(`视频对象: ${JSON.stringify(item, null, 2)}`, 'info');
return false;
}
},
// 真实播放:按 objectid 匹配 video/audio iframe
// 返回 true 表示本函数已接管并完成;false 表示未命中,由调用方跳过(不切换到模拟模式)
realPlayVideo = async (item) => {
logs.addLog('🎥 真实播放模式:' + item['name'], 'blue');
const targetObjectId = item['objectId'] ||
(item['property'] && item['property']['objectid']) || '';
if (!targetObjectId) {
logs.addLog('⚠️ 视频任务缺少 objectId,已跳过:' + item['name'], 'orange');
return false;
}
// 在 knowledge/cards 文档中按 objectid 匹配 iframe
let targetIframe = null;
let matchAttempts = 0;
const maxMatchAttempts = 10;
while (!targetIframe && matchAttempts < maxMatchAttempts) {
const mediaIframes = document.querySelectorAll(
'iframe.ans-insertvideo-online, iframe[src*="/ananas/modules/video/"], iframe[src*="/ananas/modules/audio/"]'
);
for (const f of mediaIframes) {
try {
const dataAttr = f.getAttribute('data');
if (!dataAttr) continue;
const data = JSON.parse(dataAttr);
if (data && data.objectid === targetObjectId) {
targetIframe = f;
break;
}
} catch (e) {
// JSON.parse 失败,跳过该 iframe
}
}
if (!targetIframe) {
await new Promise(r => setTimeout(r, 500));
matchAttempts++;
}
}
if (!targetIframe) {
logs.addLog('⚠️ 未找到 objectid=' + targetObjectId.slice(0, 8) +
'... 对应的视频 iframe,已跳过:' + item['name'], 'orange');
return false;
}
// 进入目标 iframe,等待 video 元素出现
let videoElement = null;
let iframeDocument = null;
let videoAttempts = 0;
const maxVideoAttempts = 20;
while (!videoElement && videoAttempts < maxVideoAttempts) {
try {
iframeDocument = targetIframe.contentDocument ||
(targetIframe.contentWindow && targetIframe.contentWindow.document);
if (iframeDocument) {
videoElement = iframeDocument.querySelector('video');
}
} catch (e) {
// 跨域,理论上 knowledge/cards 内同域应可访问
}
if (!videoElement) {
await new Promise(r => setTimeout(r, 500));
videoAttempts++;
}
}
if (!videoElement) {
logs.addLog('⚠️ 视频 iframe 内未找到 video 元素,已跳过:' + item['name'], 'orange');
return false;
}
logs.addLog('✅ 命中视频 objectid=' + targetObjectId.slice(0, 8) +
'...,开始真实播放', 'green');
// 真实模式:V2 拉题并缓存正确答案,弹窗时再 DOM 点选
let videoQuestionCache = [];
if (videoQuestionEnabled) {
try {
videoQuestionCache = await buildVideoQuestionCache(item);
if (videoQuestionCache.length) {
logs.addLog(`[${item['name']}]解析到 ${videoQuestionCache.length} 道视频题`, 'green');
} else {
logs.addLog('未缓存到视频题答案,弹窗出现时将无法自动点选', 'orange');
}
} catch (e) {
logs.addLog('视频题目缓存失败:' + e.message, 'orange');
}
}
// 倍速:真实播放从独立配置读取(0.75~3,步进 0.25),开始播放后再应用
const applyRealPlaybackRate = (doc, videoEl, targetRate) => {
const applied = normalizeRealVideoRate(targetRate);
try { videoEl.playbackRate = applied; } catch (e) { }
try {
const vjsRoot = doc.getElementById('video');
const win = doc.defaultView || window;
let player = vjsRoot && vjsRoot.player;
if (!player && win.videojs && typeof win.videojs.getPlayer === 'function') {
player = win.videojs.getPlayer('video');
}
if (player && typeof player.playbackRate === 'function') {
player.playbackRate(applied);
}
} catch (e) { }
return applied;
};
// 自动静音
if (autoMuteVideo) {
try {
videoElement.muted = true;
videoElement.volume = 0;
} catch (e) { }
}
// 视频内题目检测频率(毫秒)· 与 doVideo 内日志 "已启用(每5秒)" 保持一致
const QUESTION_CHECK_INTERVAL = 5000;
// 视频内题目弹窗自动作答(progressMonitor 按 QUESTION_CHECK_INTERVAL 调用;busy 防并发重入)
let videoQuestionBusy = false;
const handleVideoQuestions = async () => {
if (!videoQuestionEnabled || !iframeDocument || videoQuestionBusy) return;
try {
const submitBtn = iframeDocument.querySelector('#videoquiz-submit');
if (!submitBtn) return;
const optionLabels = Array.from(
iframeDocument.querySelectorAll('.ans-videoquiz-opt label')
);
if (optionLabels.length === 0) return;
videoQuestionBusy = true;
let optionClicked = false;
let matched = null;
if (videoQuestionCache.length) {
const stemEl = iframeDocument.querySelector('.tkTopic, .ans-videoquiz-tit, .videoquiz-title, .ans-videoquiz .title, .ans-videoquiz');
const stemText = stemEl ? stemEl.textContent : '';
matched = matchVideoQuestionFromCache(videoQuestionCache, stemText);
if (matched && matched.answer) {
optionClicked = clickVideoQuizOptionByAnswer(optionLabels, matched.answer);
}
}
if (!optionClicked) {
logs.addLog('视频内题目:未能匹配正确答案,请手动作答', 'orange');
videoQuestionBusy = false;
return;
}
await new Promise(r => setTimeout(r, 500));
submitBtn.click();
await new Promise(r => setTimeout(r, 1000));
const container = iframeDocument.querySelector('#video .ans-videoquiz');
if (container) container.remove();
// 学习通题目弹窗会留下 .x-component-default 遮罩,统一隐藏以恢复播放
Array.from(iframeDocument.querySelectorAll('.x-component-default'))
.forEach(com => { com.style.display = 'none'; });
const qDesc = (matched && matched.description) ? matched.description : '视频内题目';
const qAns = (matched && matched.answer) ? matched.answer : '';
logs.addLog(`[正在完成视频中的题目]:${qDesc}
正确答案: ${qAns}`, 'green');
} catch (e) {
console.log('处理视频内题目失败:', e);
} finally {
videoQuestionBusy = false;
}
};
// 尝试播放(自动播放被禁用时点 vjs 播放按钮兜底)
const tryPlay = async () => {
try {
await videoElement.play();
return true;
} catch (e) {
const playBtns = [];
try {
playBtns.push(iframeDocument.querySelector('.vjs-big-play-button'));
playBtns.push(iframeDocument.querySelector('.vjs-play-control'));
} catch (err) { }
for (const btn of playBtns) {
if (btn) {
btn.click();
await new Promise(r => setTimeout(r, 500));
if (!videoElement.paused) return true;
}
}
return false;
}
};
const playSuccess = await tryPlay();
if (!playSuccess) {
logs.addLog('⚠️ 视频无法自动播放,已跳过:' + item['name'], 'orange');
return false;
}
logs.addLog('✅ 视频开始播放', 'green');
rateReal = normalizeRealVideoRate(GM_getValue('unrivalrate_real', rateReal));
const appliedRate = applyRealPlaybackRate(iframeDocument, videoElement, rateReal);
logs.addLog('真实播放倍速:' + appliedRate + 'x', 'blue');
// 进度监听 + 视频内题目轮询
// 注意:真实播放模式下,任务点进度由学习通视频播放器自身上报,脚本不再调用 getEnc/reportUrl
if (realVideoProgressMonitor) {
try { clearInterval(realVideoProgressMonitor); } catch (_) { }
realVideoProgressMonitor = null;
}
let lastReportTime = 0;
let lastQuestionCheckTime = 0;
realVideoProgressMonitor = setInterval(async () => {
try {
const now = Date.now();
if (!videoQuestionBusy && now - lastQuestionCheckTime >= QUESTION_CHECK_INTERVAL) {
lastQuestionCheckTime = now;
await handleVideoQuestions();
}
if (videoElement.paused && !videoElement.ended) {
videoElement.play().catch(e => {
logs.addLog('恢复播放失败:' + e.message, 'orange');
});
}
const currentTime = Math.floor(videoElement.currentTime);
const duration = Math.floor(videoElement.duration);
if (currentTime - lastReportTime >= reportInterval || videoElement.ended) {
const percent = duration > 0 ? (currentTime / duration) * 100 : 0;
const watchedMinutes = (currentTime / 60).toFixed(1);
const remainingMinutes = ((duration - currentTime) / 60).toFixed(1);
const progressText = '真实播放中 (' + formatDuration(currentTime) +
' / ' + formatDuration(duration) + ')';
reportProgress('视频', item, percent, progressText);
lastReportTime = currentTime;
logs.addLog(item['name'] + '已观看' + watchedMinutes +
'分钟,剩余大约' + remainingMinutes + '分钟,完成' +
percent.toFixed(1) + '%', 'blue');
}
if (videoElement.ended || (duration > 0 && currentTime >= duration - 1)) {
clearInterval(realVideoProgressMonitor);
realVideoProgressMonitor = null;
reportProgress('视频', item, 100, '视频任务已完成');
logs.addLog('✅ 视频播放完成(任务点由学习通自身上报)', 'green');
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
}
} catch (e) {
clearInterval(realVideoProgressMonitor);
realVideoProgressMonitor = null;
logs.addLog('真实播放监听异常,已跳过:' + e.message, 'red');
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
}
}, 1000);
return true;
},
doVideo = async (item) => {
const missionKey = 'm' + item['jobid'];
if (!missionList[missionKey]) return;
if (missionList[missionKey]['running'] || missionList[missionKey]['done']) return;
missionList[missionKey]['running'] = true;
if (allowBackground && backGround) {
if (_w.top.document.getElementsByClassName('catalog_points_sa').length > 0 || _w.top.document
.getElementsByClassName('lock').length > 0) {
logs.addLog('您已安装超星挂机小助手,但此课程可能为闯关模式,不支持后台挂机,将为您在线完成', 'blue');
} else {
item['userid'] = UID;
item['classId'] = classId;
item['review'] = [false, true][_w.top.unrivalReviewMode];
item['reportUrl'] = reportUrl;
item['rt'] = missionList['m' + item['jobid']]['rt'];
GM_setValue('unrivalBackgroundVideo', item);
_d.cookie = "videojs_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
logs.addLog(
'您已安装超星挂机小助手,已添加至后台任务,
点我查看后台',
'green');
setTimeout(function () {
missionList[missionKey]['running'] = false;
missionList[missionKey]['done'] = true;
}, 5000);
return;
}
}
let videojs_id = String(parseInt(Math.random() * 9999999));
_d.cookie = 'videojs_id=' + videojs_id + ';path=/'
// 初始化进度条
reportProgress('视频', item, 0, item['duration'] ? ('准备开始 (00:00 / ' + formatDuration(item['duration']) + ')') : '准备开始...');
// 真实/模拟模式分流:real 走 realPlayVideo;simulate 走下方接口上报
// real 未命中则跳过该任务,不自动降级为模拟
if (videoPlayMode === 'real') {
logs.addLog('当前模式:真实播放模式', 'blue');
if (videoQuestionEnabled) {
logs.addLog('视频内题目:已启用(接口缓存答案,每5秒)', 'green');
} else {
logs.addLog('视频内题目:已关闭', 'info');
}
const realPlaySuccess = await realPlayVideo(item);
if (realPlaySuccess) {
return;
}
// 未命中 iframe 则跳过该任务
logs.addLog('真实播放模式未命中视频元素,本任务跳过;如需脚本完成该任务点请切换为「模拟模式」后再试。', 'orange');
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
return;
}
// 模拟模式:接口上报进度
logs.addLog('当前模式:模拟模式(不实际播放视频)', 'blue');
rateSimulate = parseSimulateVideoRate(GM_getValue('unrivalrate_simulate', rateSimulate));
if (rateSimulate <= 0) {
logs.addLog('⚠️ 奇怪的倍速,视频已自动跳过', 'orange');
setTimeout(function () {
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
}, 5000);
return;
}
if (videoQuestionEnabled) {
logs.addLog('开始处理视频题目(接口模式):' + item['name'], 'blue');
try {
await finishVideoQuestions(item);
} catch (e) {
logs.addLog('处理视频题目时出错,继续播放视频:' + e.message, 'orange');
}
} else {
logs.addLog('视频题目自动处理功能已关闭,跳过题目处理', 'info');
}
// 合并 mArg 与 iframe 进度,取较大值作为模拟上报起点
let taskPlayedTimeSec = item['taskPlayedTimeSec'] || 0,
iframePlayedTimeSec = getIframePlayedTimeSec(item['objectId']),
initialSec = Math.max(taskPlayedTimeSec, iframePlayedTimeSec);
if (_w.top.unrivalReviewMode == '1' && item['isPassed']) {
initialSec = 0;
logs.addLog('复习模式:已完成任务从头重刷(模拟模式)', 'green');
} else if (item['duration']) {
initialSec = Math.min(initialSec, item['duration']);
}
const formatPlayedSource = (sec) => sec > 0 ? formatDuration(sec) : '无';
if (initialSec > 0) {
logs.addLog('从 ' + formatDuration(initialSec) + ' 续刷(模拟模式;任务数据 ' +
formatPlayedSource(taskPlayedTimeSec) + ',页面视频 ' +
formatPlayedSource(iframePlayedTimeSec) + ')', 'green');
}
const initialPercent = item['duration'] ? (initialSec / item['duration']) * 100 : 0;
const initialProgressDetail = item['duration']
? ('进度 ' + formatDuration(initialSec) + ' / ' + formatDuration(item['duration']))
: ('已观看 ' + formatDuration(initialSec));
reportProgress('视频', item, initialPercent, initialSec > 0 ? initialProgressDetail : (
item['duration'] ? ('准备开始 (00:00 / ' + formatDuration(item['duration']) + ')') : '准备开始...'
));
logs.addLog('🎬 开始刷视频:' + item['name'] + ',倍速:' + String(rateSimulate) + '倍', 'blue');
logs.addLog('视频观看信息每' + reportInterval + '秒上报一次,请耐心等待', 'green');
logs.addLog('如遇脚本使用异常情况,请检查脚本版本是否为最新版,
点我(脚本猫)或
点我(greasyfork)检查', 'orange');
if (disableMonitor) {
logs.addLog('解除多端学习监控有清除进度风险,请谨慎使用', 'orange');
}
let dtype = 'Video';
if (item['module'].includes('audio')) {
dtype = 'Audio';
rt = '';
}
// 墙钟计时:切标签/最小化后按真实经过时间补算进度
const simWallOffsetSec = initialSec > 0 ? Math.max(0, initialSec - rateSimulate) : -rateSimulate,
simWallStartMs = Date.now() - (simWallOffsetSec * 1000 / rateSimulate);
let playTime = initialSec,
isdrag = initialSec > 0 ? '0' : '3',
times = 0,
encUrl = '',
first = true;
if (simVideoLoop) {
try { clearInterval(simVideoLoop); } catch (_) { }
simVideoLoop = null;
}
simVideoLoop = setInterval(function () {
// 同步异常兜底:清除 loop 并标记任务完成,避免 loopjob 卡死
try {
rateSimulate = parseSimulateVideoRate(GM_getValue('unrivalrate_simulate', rateSimulate));
if (rateSimulate <= 0) {
clearInterval(simVideoLoop);
simVideoLoop = null;
logs.addLog('⚠️ 奇怪的倍速,视频已自动跳过', 'orange');
setTimeout(function () {
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
}, 5000);
return;
} else if (item['doublespeed'] == 0 && rateSimulate > 1 && _w.top.unrivalReviewMode == '0') {
//rateSimulate = 1;
//logs.addLog('该视频不允许倍速播放,已恢复至一倍速,高倍速会被清空进度挂科,勿存侥幸', 'red');
}
rt = missionList['m' + item['jobid']]['rt'];
const simElapsedSec = (Date.now() - simWallStartMs) / 1000;
playTime = Math.ceil(simElapsedSec * rateSimulate);
if (item['duration']) {
playTime = Math.min(playTime, item['duration']);
}
// 更新进度条
const cappedTime = item['duration'] ? Math.min(playTime, item['duration']) : playTime;
const percent = item['duration'] ? (cappedTime / item['duration']) * 100 : 0;
reportProgress('视频', item, percent, item['duration'] ? ('进度 ' + formatDuration(cappedTime) + ' / ' + formatDuration(item['duration'])) : ('已观看 ' + formatDuration(cappedTime)));
if (times == 0 || times % reportInterval == 0 || playTime >= item['duration']) {
if (playTime >= item['duration']) {
clearInterval(simVideoLoop);
simVideoLoop = null;
playTime = item['duration'];
isdrag = '4';
reportProgress('视频', item, 100, '视频任务已完成');
} else if (playTime > 0) {
isdrag = '0';
}
encUrl = host + 'chaoXing/v3/getEnc.php?classid=' + classId +
'&playtime=' + playTime + '&duration=' + item['duration'] + '&objectid=' + item[
'objectId'] + '&jobid=' + item['jobid'] + '&uid=' + UID;
busyThread += 1;
var _bold_playTime = playTime;
function ecOnload(res) {
let enc = '';
if (res && res.status == 200) {
enc = res.responseText;
if (enc.includes('--#')) {
let warnInfo = enc.match(new RegExp('--#(.*?)--#', "ig"))[0]
.replace(/--#/ig, '');
logs.addLog(warnInfo, 'red');
enc = enc.replace(/--#(.*?)--#/ig, '');
}
if (enc.indexOf('.stop') >= 0) {
clearInterval(simVideoLoop);
simVideoLoop = null;
stop = true;
return;
}
} else {
strEc = `[${classId}][${UID}][${item['jobid']}][${item['objectId']}][${playTime * 1000}][d_yHJ!$pdA~5][${item['duration'] * 1000}][0_${item['duration']}]`,
enc = jq.md5(strEc);
}
if (enc.length != 32) {
clearInterval(simVideoLoop);
simVideoLoop = null;
stop = true;
return;
}
let reportsUrl = reportUrl + '/' + item['dtoken'] +
'?clazzId=' + classId + '&playingTime=' + playTime +
'&duration=' + item['duration'] + '&clipTime=0_' + item[
'duration'] + '&objectId=' + item['objectId'] +
'&otherInfo=' + item['otherInfo'] + '&jobid=' + item[
'jobid'] + '&userid=' + UID + '&isdrag=' + isdrag +
'&view=pc&enc=' + enc + '&rt=' + rt + '&dtype=' + dtype +
'&_t=' + String(Math.round(new Date()));
gmRequest({
method: "get",
headers: {
'Host': _h,
'Referer': vrefer,
'Sec-Fetch-Site': 'same-origin',
'Content-Type': 'application/json'
},
url: reportsUrl,
onload: function (res) {
try {
let today = new Date(),
todayStr = today.getFullYear() +
'd' + today.getMonth() + 'd' + today
.getDate(),
timelong = GM_getValue(
'unrivaltimelong', {});
if (timelong[UID] == undefined ||
timelong[UID]['today'] != todayStr
) {
timelong[UID] = {
'time': 0,
'today': todayStr
};
} else {
timelong[UID]['time']++;
}
GM_setValue('unrivaltimelong',
timelong);
busyThread -= 1;
if (timelong[UID]['time'] / 60 > 22 &&
item['doublespeed'] == 0 && _w.top
.unrivalReviewMode == '0') {
clearInterval(simVideoLoop);
simVideoLoop = null;
logs.addLog(
'今日学习时间过长,继续学习会导致清空进度,请明天再来',
'red');
setTimeout(function () {
missionList['m' + item[
'jobid']][
'running'
] = false;
missionList['m' + item[
'jobid']][
'done'
] = true;
}, 5000);
return;
}
let ispass = JSON.parse(res
.responseText);
first = false;
if (ispass['isPassed'] && _w.top
.unrivalReviewMode == '0') {
logs.addLog('✅ 视频任务已完成', 'green');
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
clearInterval(simVideoLoop);
simVideoLoop = null;
return;
} else if (isdrag == '4') {
if (_w.top.unrivalReviewMode ==
'1') {
logs.addLog('✅ 视频已观看完毕', 'green');
} else {
// 分析任务失败原因
let analysis = analyzeVideoTaskFailure(item, playTime, item['duration'], isdrag, ispass);
// 生成详细的原因说明
let mainReason = '';
if (analysis.reasons.some(r => r.includes('视频题目'))) {
mainReason = ' - 可能原因:视频内提问未完成或学习通服务器未通过';
} else if (analysis.reasons.some(r => r.includes('观看时长'))) {
mainReason = ' - 可能原因:观看时长不足或倍速过高';
} else if (analysis.reasons.some(r => r.includes('服务器'))) {
mainReason = ' - 可能原因:学习通服务器未通过或网络问题';
} else {
mainReason = ' - 可能原因:学习通服务器未通过';
}
logs.addLog(`[${item['name']}]视频已观看完毕,但视频任务未完成${mainReason}`, 'red');
// 只显示关键原因,避免重复
let keyReasons = analysis.reasons.filter(r =>
r.includes('❌') || r.includes('⚠️⚠️') || r.includes('未通过')
);
if (keyReasons.length > 0) {
logs.addLog('🔍 关键问题:', 'orange');
keyReasons.forEach(reason => {
logs.addLog(`├─ ${reason}`, 'orange');
});
}
// 只显示最重要的建议
if (analysis.suggestions.length > 0) {
logs.addLog('💡 建议操作:', 'blue');
analysis.suggestions.slice(0, 3).forEach((suggestion, index) => {
logs.addLog(`${index + 1}. ${suggestion}`, 'blue');
});
}
}
missionList['m' + item['jobid']][
'running'
] = false;
missionList['m' + item['jobid']][
'done'
] = true;
try {
clearInterval(simVideoLoop);
simVideoLoop = null;
} catch (e) {
}
} else {
const totalDuration = item['duration'] || 0;
const watchedMinutes = (_bold_playTime / 60).toFixed(1);
const remainingSeconds = Math.max(totalDuration - _bold_playTime, 0);
const remainingMinutes = (remainingSeconds / 60).toFixed(1);
const progress = totalDuration > 0
? ((_bold_playTime / totalDuration) * 100).toFixed(1)
: '0.0';
logs.addLog(item['name'] + '已观看' +
watchedMinutes + '分钟,剩余大约' +
remainingMinutes + '分钟,完成' + progress + '%');
}
} catch (e) {
console.log(e);
if (res.responseText.indexOf('验证码') >=
0) {
logs.addLog('已被超星风控,请
点我处理,60秒后自动刷新页面',
'red');
missionList['m' + item['jobid']][
'running'
] = false;
clearInterval(simVideoLoop);
simVideoLoop = null;
stop = true;
setTimeout(function () {
_l.reload();
}, 60000);
return;
}
logs.addLog('超星返回错误信息,十秒后重试,请重新登录或重新打开浏览器', 'red');
times = -10;
return;
}
},
onerror: function (err) {
console.log(err);
if (err.error.indexOf('@connect list') >=
0) {
logs.addLog(
'请添加安全网址,将 【 //@connect ' +
_h +
' 】方括号里的内容(不包括方括号)添加到脚本代码内指定位置,否则脚本无法正常运行,如图所示:',
'red');
logs.addLog(
'

'
);
stop = true;
} else {
logs.addLog('观看视频失败', 'red');
logs.addLog('错误原因:' + err.error, 'red');
}
missionList['m' + item['jobid']][
'running'
] = false;
clearInterval(simVideoLoop);
simVideoLoop = null;
}
});
};
gmRequest({
method: "get",
url: encUrl,
timeout: 2000,
onload: ecOnload,
onerror: function (err) {
console.log(err);
ecOnload(false);
},
ontimeout: function (err) {
console.log(err);
ecOnload(false);
}
});
}
times += 1;
} catch (e) {
// 同步异常兜底:清除 loop 并标记任务完成
console.log('[模拟视频] loop 同步异常兜底:', e);
try { clearInterval(simVideoLoop);
simVideoLoop = null; } catch (_) { }
try {
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
} catch (_) { }
}
}, 1000);
},
doDocument = (item) => {
missionList['m' + item['jobid']]['running'] = true;
logs.addLog('开始刷文档:' + item['name']);
setTimeout(function () {
busyThread += 1;
gmRequest({
method: "get",
url: _p + '//' + _h + '/ananas/job/document?jobid=' + item['jobid'] +
'&knowledgeid=' + chapterId + '&courseid=' + courseId + '&clazzid=' +
classId + '&jtoken=' + item['jtoken'],
onload: function (res) {
try {
busyThread -= 1;
let ispass = JSON.parse(res.responseText);
if (ispass['status']) {
logs.addLog('文档任务已完成', 'green');
} else {
logs.addLog('文档已阅读完成,但任务点未完成', 'red');
}
} catch (err) {
console.log(err);
console.log(res.responseText);
logs.addLog('解析文档内容失败', 'red');
}
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
},
onerror: function (err) {
console.log(err);
if (err.error.indexOf('@connect list') >= 0) {
logs.addLog('请添加安全网址,将 【 //@connect ' + _h +
' 】方括号里的内容(不包括方括号)添加到脚本代码内指定位置,否则脚本无法正常运行,如图所示:', 'red');
logs.addLog(
'

'
);
stop = true;
} else {
logs.addLog('阅读文档失败', 'red');
logs.addLog('错误原因:' + err.error, 'red');
}
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
}
});
}, parseInt(Math.random() * 2000 + 9000, 10))
},
xxtSleep = (ms) => new Promise(function (resolve) { setTimeout(resolve, ms); }),
xxtSerializeWorkItem = (item) => ({
jobid: item['jobid'],
enc: item['enc'],
name: item['name'],
workid: item['workid'],
type: item['type']
}),
xxtIsWorkTabActive = () => {
try {
const tab = top.document.querySelector('#dct2');
if (!tab) return true;
const cls = tab.className || '';
return cls.indexOf('active') >= 0 || cls.indexOf('currents') >= 0 || cls.indexOf('current') >= 0;
} catch (e) {
return false;
}
},
xxtSwitchToWorkTab = () => {
try {
const tab = top.document.querySelector('#dct2');
if (tab) tab.click();
} catch (e) { }
},
xxtGetWorkSearchRoot = () => {
try {
if (_d && (_l.href.indexOf('knowledge/cards') >= 0 || _d.querySelector('.wrap .ans-cc') || _d.querySelector('.ans-attach-ct'))) {
return _d;
}
} catch (e) { }
try {
const outer = top.document.getElementById('iframe');
if (outer && outer.contentDocument) return outer.contentDocument;
} catch (e) { }
return _d;
},
xxtFindWorkAttachIframe = () => {
const root = xxtGetWorkSearchRoot();
if (!root) return null;
const selectors = [
'.wrap .ans-cc .ans-attach-ct iframe[src*="modules/work"]',
'.wrap .ans-cc .ans-attach-ct iframe',
'.ans-attach-ct iframe[src*="modules/work"]',
'.ans-insertwork-online iframe',
'iframe.ans-insertwork-online',
'iframe[src*="modules/work/index"]',
'iframe[src*="modules/work"]',
'.ans-attach-ct iframe'
];
for (let i = 0; i < selectors.length; i++) {
const el = root.querySelector(selectors[i]);
if (el) return el;
}
return null;
},
xxtIsWorkAnswerViewOnly = (doc) => {
if (!doc) return false;
try {
const href = String(doc.location && doc.location.href ? doc.location.href : '');
if (/selectWorkQuestionYiPiYue|YiPiYue/i.test(href)) return true;
} catch (e) { }
return false;
},
xxtFindAnswerDocInShell = async (shellDoc, shellWin) => {
if (!shellDoc) return null;
if (shellDoc.querySelectorAll('.Py-mian1').length && !xxtIsWorkAnswerViewOnly(shellDoc)) {
return { mode: 'phone', answerDoc: shellDoc, answerWin: shellWin };
}
if (shellDoc.querySelectorAll('.TiMu').length && !xxtIsWorkAnswerViewOnly(shellDoc)) {
return { mode: 'pc', answerDoc: shellDoc, answerWin: shellWin };
}
let sawViewOnly = false;
const iframes = shellDoc.querySelectorAll('iframe');
for (let i = 0; i < iframes.length; i++) {
const nested = iframes[i];
await xxtWaitForIframeReady(nested, 6000);
let nDoc = null, nWin = null;
try {
nDoc = nested.contentDocument;
nWin = nested.contentWindow;
} catch (e) { continue; }
if (!nDoc) continue;
if (xxtIsWorkAnswerViewOnly(nDoc)) {
sawViewOnly = true;
continue;
}
if (nDoc.querySelectorAll('.Py-mian1').length) {
return { mode: 'phone', answerDoc: nDoc, answerWin: nWin };
}
if (nDoc.querySelectorAll('.TiMu').length) {
return { mode: 'pc', answerDoc: nDoc, answerWin: nWin };
}
}
if (sawViewOnly) {
return { skip: true, status: '待批阅', reason: '待批阅' };
}
return null;
},
xxtWaitForIframeReady = async (iframe, timeoutMs) => {
const start = Date.now();
while (Date.now() - start < timeoutMs) {
try {
const doc = iframe.contentDocument;
if (doc && (doc.readyState === 'complete' || doc.body)) return doc;
} catch (e) { }
await xxtSleep(200);
}
try { return iframe.contentDocument; } catch (e) { return null; }
},
xxtGetWorkShellStatus = (shellDoc) => {
const el = shellDoc.querySelector('.newTestCon .newTestTitle .testTit_status, .newTestCon .testTit_status, .testTit_status');
return el ? String(el.textContent || '').trim() : '';
},
xxtTryClickWorkStart = (doc) => {
const quick = ['.newTestCon a.newTestBtn', '.newTestCon .newTestStart', '.newTestCon a', '.startBtn', '.toStart'];
for (let i = 0; i < quick.length; i++) {
const el = doc.querySelector(quick[i]);
if (el) { try { el.click(); return true; } catch (_) { } }
}
const nodes = doc.querySelectorAll('.newTestCon a, .newTestCon button, .newTestCon span');
for (let j = 0; j < nodes.length; j++) {
const t = (nodes[j].textContent || '').trim();
if (/开始|进入|答题|继续/.test(t) && t.length < 24) {
try { nodes[j].click(); return true; } catch (_) { }
}
}
return false;
},
xxtResolveNativeAnswerContext = async (maxWaitMs) => {
const start = Date.now();
while (Date.now() - start < maxWaitMs) {
const attachIframe = xxtFindWorkAttachIframe();
if (!attachIframe) {
await xxtSleep(500);
continue;
}
await xxtWaitForIframeReady(attachIframe, 8000);
let shellDoc = null, shellWin = null;
try {
shellDoc = attachIframe.contentDocument;
shellWin = attachIframe.contentWindow;
} catch (e) { }
if (!shellDoc) {
await xxtSleep(500);
continue;
}
const status = xxtGetWorkShellStatus(shellDoc);
if (/已完成|已交/.test(status)) {
return { skip: true, status: status, reason: '已完成' };
}
if (/待批阅/.test(status)) {
return { skip: true, status: status, reason: '待批阅' };
}
const found = await xxtFindAnswerDocInShell(shellDoc, shellWin);
if (found) {
if (found.skip) {
return { skip: true, status: found.status, reason: found.reason };
}
return {
mode: found.mode,
answerDoc: found.answerDoc,
answerWin: found.answerWin,
shellDoc: shellDoc,
status: status,
attachIframe: attachIframe
};
}
if (/待做|待完成|未达到及格线/.test(status)) {
xxtTryClickWorkStart(shellDoc);
}
await xxtSleep(1000);
}
return null;
},
xxtGetWidFromDoc = (doc) => {
const el = doc.getElementById('workLibraryId') || doc.getElementById('oldWorkId');
if (el && el.value) return el.value;
const hid = doc.querySelector('input[name="workLibraryId"], input[name="oldWorkId"]');
return hid && hid.value ? hid.value : '';
},
xxtParsePhoneQuestionsNative = (doc) => {
const questionList = [];
const questionsElement = doc.getElementsByClassName('Py-mian1');
for (let i = 0, questionNum = questionsElement.length; i < questionNum; i++) {
const questionElement = questionsElement[i];
const idElements = questionElement.getElementsByTagName('input');
let questionId = '0';
let question = questionElement.getElementsByClassName('Py-m1-title fs16')[0].innerHTML;
question = handleImgs(question).replace(/(<([^>]+)>)/ig, '').replace(/[0-9]{1,3}.\[(.*?)\]/ig, '').replaceAll('\n', '')
.replace(/^\s+/ig, '').replace(/\s+$/ig, '');
for (let z = 0, k = idElements.length; z < k; z++) {
try {
if (idElements[z].getAttribute('name').indexOf('answer') >= 0) {
questionId = idElements[z].getAttribute('name').replace('type', '');
break;
}
} catch (e) { continue; }
}
if (questionId == '0' || question == '') continue;
const typeE = questionElement.getElementsByTagName('input');
let typeN = 'fuckme';
for (let g = 0, h = typeE.length; g < h; g++) {
if (typeE[g].id == 'answertype' + questionId.replace('answer', '').replace('check', '')) {
typeN = typeE[g].value;
break;
}
}
if (['0', '1', '3'].indexOf(typeN) < 0) continue;
const type = { '0': '单选题', '1': '多选题', '3': '判断题' }[typeN];
const optionList = { length: 0 };
if (['单选题', '多选题'].indexOf(type) >= 0) {
const answersElements = questionElement.getElementsByClassName('answerList')[0].getElementsByTagName('li');
for (let x = 0, j = answersElements.length; x < j; x++) {
const optionE = answersElements[x];
const optionTextE = trim(optionE.innerHTML.replace(/(^\s*)|(\s*$)/g, ''));
const optionText = optionTextE.slice(1).replace(/(^\s*)|(\s*$)/g, '');
const optionValue = optionTextE.slice(0, 1);
if (optionText == '') break;
optionList[optionText] = { id: optionE.getAttribute('id-param'), value: optionValue };
optionList.length++;
}
if (answersElements.length != optionList.length) continue;
}
questionList.push({ question: question, displayQuestion: question, type: type, questionid: questionId, options: optionList });
}
return questionList;
},
xxtCleanQuestionStem = (text, typeName) => {
let q = handleImgs(String(text || '')).replace(/(<([^>]+)>)/ig, '').replace(/^\s+/ig, '').replace(/\s+$/ig, '');
q = q.replace(/^\d+[、.\s]*/, '').replace(/^【.*?】\s*/, '').replace(/^\[.*?\]\s*/, '');
if (typeName && q.indexOf(typeName) === 0) q = q.slice(typeName.length).trim();
return q.replace(/^\s*[、..]\s*/, '');
},
xxtHasWorkAnswerText = (result) => !!(result && String(result).trim()),
xxtWorkFetchMeta = (res) => {
const raw = String(res.answer || '').trim();
const msg = String(res.msg || '').trim();
const code = res.code;
const placeholder = !raw || /\(未搜索到答案\)|未搜索到答案|未找到答案,可点击/.test(raw);
const noAnswer = !!res.serverError || code === -1 || placeholder;
let hint = msg;
if (!hint && noAnswer && raw) hint = raw;
const ans = noAnswer ? '' : raw;
return { hint: hint, ans: ans };
},
xxtFormatWorkQuestionDisplay = (qu, ans, idx, tot, answered, oldAns, selectedOption, hintLine) => {
const header = '
【第' + idx + '/' + tot + '题 - ' + qu['type'] + '】';
const questionLine = '📋 ' + (qu['displayQuestion'] || qu['question']);
let answerLine = '';
let answerColor = 'red';
if (answered && oldAns) {
answerLine = '✅ 已作答:' + oldAns + '(跳过)';
answerColor = 'blue';
} else if (ans && /^未找到,自动/.test(String(ans))) {
answerLine = selectedOption ? ('❗ 自动选答:' + ans + ' 选' + selectedOption) : ('❗ 自动选答:' + ans);
answerColor = '#a16207';
} else if (ans) {
answerLine = selectedOption ? ('✅ 答案:' + ans + ' 选' + selectedOption) : ('✅ 答案:' + ans);
answerColor = 'green';
} else {
answerLine = '❌ 未找到答案';
answerColor = 'red';
}
let html = header + '
' + questionLine;
if (hintLine) html += '
' + hintLine;
html += '
' + answerLine + '';
return html;
},
xxtParsePCQuestionsNative = (doc) => {
const list = [];
doc.querySelectorAll('.CeYan .TiMu, .TiMu').forEach(function (el) {
const titleDiv = el.querySelector('.Zy_TItle.clearfix > div, .Zy_Title.clearfix > div, .Zy_TItle > div');
if (!titleDiv) return;
const questionFull = titleDiv.innerHTML || '';
const typeMatch = questionFull.match(/【(.*?)】/);
let typeName = typeMatch ? typeMatch[1] : '';
if (!typeName && el.querySelector('.Zy_ulTop li input[type="checkbox"]')) typeName = '多选题';
else if (!typeName && el.querySelector('.Zy_ulTop li')) typeName = '单选题';
if (['单选题', '多选题', '判断题'].indexOf(typeName) < 0) return;
const question = trim(questionFull).replace(/^\d+\.?\s*/, '');
const displayQuestion = xxtCleanQuestionStem(questionFull, typeName);
list.push({ element: el, question: question, displayQuestion: displayQuestion, type: typeName, mode: 'pc' });
});
return list;
},
xxtNativeWorkLog = (msg, color) => {
logs.addLog(msg, color || 'green');
},
xxtConfirmNativeSubmit = (ctx) => {
const docs = [ctx.answerDoc, ctx.shellDoc, top.document];
for (let i = 0; i < docs.length; i++) {
const d = docs[i];
if (!d) continue;
const btn = d.querySelector('#confirmSubWin > div > div > a.bluebtn, #confirmSubWin a.bluebtn, #popok');
if (btn) { try { btn.click(); return true; } catch (_) { } }
}
return false;
},
xxtFinishNativeWork = (item, ctx, totalQuestionNum, questionNum) => {
const rate = totalQuestionNum > 0 ? Math.floor(((totalQuestionNum - questionNum) / totalQuestionNum) * 100) : 0;
return new Promise(function (resolve) {
const done = function () {
setTimeout(resolve, 3000);
};
if (rate >= accuracy && _w.top.unrivalAutoSubmit == '1') {
xxtNativeWorkLog('正确率符合标准,已提交答案', 'green');
setTimeout(function () {
if (ctx.mode === 'phone' && ctx.answerWin) {
try {
if (typeof ctx.answerWin.submitCheckTimes === 'function') ctx.answerWin.submitCheckTimes();
if (typeof ctx.answerWin.escapeBlank === 'function') ctx.answerWin.escapeBlank();
if (typeof ctx.answerWin.submitAction === 'function') ctx.answerWin.submitAction();
} catch (e) { console.log(e); }
} else {
const subBtn = ctx.answerDoc.querySelector('.ZY_sub .btnSubmit, .btnSubmit');
if (subBtn) subBtn.click();
}
setTimeout(function () {
xxtConfirmNativeSubmit(ctx);
done();
}, 2500);
}, parseInt(Math.random() * 2000 + 3000, 10));
} else if (_w.top.unrivalAutoSave == 1) {
xxtNativeWorkLog('正确率不符合标准或未设置自动提交,已自动保存答案', 'blue');
setTimeout(function () {
if (ctx.mode === 'phone' && ctx.answerWin && typeof ctx.answerWin.noSubmit === 'function') {
try { ctx.answerWin.noSubmit(); } catch (e) { console.log(e); }
} else {
const saveBtn = ctx.answerDoc.querySelector('.ZY_sub .btnSave, .btnSave');
if (saveBtn) saveBtn.click();
}
done();
}, 2000);
} else {
xxtNativeWorkLog('用户设置为不自动保存答案,请手动提交或保存作业', 'orange');
done();
}
});
},
xxtAnswerPhoneQuestionNative = (doc, quu, result) => {
const choiceEs = doc.getElementsByTagName('li');
const qid = quu.questionid.replace('answer', '');
const pickSelected = (li) => {
const emEl = li.getElementsByTagName('em')[0];
return emEl ? (emEl.getAttribute('id-param') || emEl.textContent || '') : '';
};
if (quu.type === '判断题') {
if (!xxtHasWorkAnswerText(result)) {
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let u = 0, k = choiceEs.length; u < k; u++) {
if (choiceEs[u].getAttribute('val-param') == 'false' && choiceEs[u].getAttribute('id-param') == qid) {
choiceEs[u].click();
return { ok: true, selected: pickSelected(choiceEs[u]), answerText: '未找到,自动选【错】' };
}
}
}
return { ok: false, selected: '', answerText: '' };
}
let answer = 'abaabaaba';
if ('正确是对√Tri'.indexOf(result) >= 0) answer = 'true';
else if ('错误否错×Fwr'.indexOf(result) >= 0) answer = 'false';
for (let u = 0, k = choiceEs.length; u < k; u++) {
if (choiceEs[u].getAttribute('val-param') == answer && choiceEs[u].getAttribute('id-param') == qid) {
choiceEs[u].click();
return { ok: true, selected: pickSelected(choiceEs[u]), answerText: result };
}
}
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let u = 0, k = choiceEs.length; u < k; u++) {
if (choiceEs[u].getAttribute('val-param') == 'false' && choiceEs[u].getAttribute('id-param') == qid) {
choiceEs[u].click();
return { ok: true, selected: pickSelected(choiceEs[u]), answerText: '未找到,自动选【错】' };
}
}
}
} else if (quu.type === '单选题') {
if (!xxtHasWorkAnswerText(result)) {
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let y = 0, j = choiceEs.length; y < j; y++) {
if (choiceEs[y].getElementsByTagName('em').length < 1) continue;
if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == 'C' && choiceEs[y].getAttribute('id-param') == qid) {
if (!String(choiceEs[y].getAttribute('class') || '').includes('cur')) choiceEs[y].click();
return { ok: true, selected: pickSelected(choiceEs[y]), answerText: '未找到,自动选【C】' };
}
}
}
} else {
for (let option in quu.options) {
const optNorm = trim(option).replace(/\s/ig, '');
const ansNorm = trim(result).replace(/\s/ig, '');
if (optNorm == ansNorm || optNorm.includes(ansNorm) || ansNorm.includes(optNorm)) {
for (let y = 0, j = choiceEs.length; y < j; y++) {
if (choiceEs[y].getElementsByTagName('em').length < 1) continue;
if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == quu.options[option].value && choiceEs[y].getAttribute('id-param') == qid) {
if (!String(choiceEs[y].getAttribute('class') || '').includes('cur')) choiceEs[y].click();
return { ok: true, selected: pickSelected(choiceEs[y]), answerText: result };
}
}
}
}
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let y = 0, j = choiceEs.length; y < j; y++) {
if (choiceEs[y].getElementsByTagName('em').length < 1) continue;
if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == 'C' && choiceEs[y].getAttribute('id-param') == qid) {
if (!String(choiceEs[y].getAttribute('class') || '').includes('cur')) choiceEs[y].click();
return { ok: true, selected: pickSelected(choiceEs[y]), answerText: '未找到,自动选【C】' };
}
}
}
}
} else if (quu.type === '多选题') {
let matched = false;
const selectedOptions = [];
if (xxtHasWorkAnswerText(result)) {
const answerData = trim(result).replace(/\s/ig, '');
for (let option in quu.options) {
const optNorm = trim(option).replace(/\s/ig, '');
if (optNorm && answerData.includes(optNorm)) {
for (let y = 0, j = choiceEs.length; y < j; y++) {
if (choiceEs[y].getElementsByTagName('em').length < 1) continue;
if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == quu.options[option].value && choiceEs[y].getAttribute('id-param') == qid) {
if (!String(choiceEs[y].getAttribute('class') || '').includes('cur')) choiceEs[y].click();
matched = true;
const opt = pickSelected(choiceEs[y]);
if (opt) selectedOptions.push(opt);
break;
}
}
}
}
if (matched) {
return { ok: true, selected: selectedOptions.join(''), answerText: result };
}
}
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let y = 0, j = choiceEs.length; y < j; y++) {
if (choiceEs[y].getAttribute('id-param') == qid) {
if (!String(choiceEs[y].getAttribute('class') || '').includes('cur')) choiceEs[y].click();
const opt = pickSelected(choiceEs[y]);
if (opt) selectedOptions.push(opt);
}
}
return { ok: true, selected: selectedOptions.length ? selectedOptions.join('') : '全选', answerText: '未找到,自动全选' };
}
}
return { ok: false, selected: '', answerText: result || '' };
},
xxtPcOptionLetterAt = (idx) => String.fromCharCode(65 + idx),
xxtPcUpdateHiddenAnswer = (timuEl, isSingle) => {
if (!timuEl) return;
const allLis = timuEl.querySelectorAll('.Zy_ulTop li.on, .Zy_ulTop li.cur');
let answerVal = '';
allLis.forEach(function (li, i) {
const idx = Array.prototype.indexOf.call(timuEl.querySelectorAll('.Zy_ulTop li'), li);
const letter = xxtPcOptionLetterAt(idx >= 0 ? idx : i);
answerVal += (i > 0 ? ',' : '') + letter;
});
const ansInput = timuEl.querySelector('.Zy_ulBottom input[name^="answer"]');
if (ansInput) {
ansInput.value = answerVal;
try { ansInput.dispatchEvent(new Event('change', { bubbles: true })); } catch (_) { }
}
const ansTa = timuEl.querySelector('.Zy_ulBottom textarea[name^="answer"]');
if (ansTa) {
ansTa.value = answerVal;
try { ansTa.dispatchEvent(new Event('change', { bubbles: true })); } catch (_) { }
}
},
xxtPcClickOptionLi = (liEl, isSingle) => {
if (!liEl) return;
const timuEl = liEl.closest('.TiMu');
if (liEl.classList.contains('on') || liEl.classList.contains('cur')) {
xxtPcUpdateHiddenAnswer(timuEl, isSingle);
return;
}
if (isSingle !== false) {
const parent = liEl.parentElement;
if (parent) {
parent.querySelectorAll('li').forEach(function (s) {
s.classList.remove('on', 'cur');
});
}
}
liEl.classList.add('on');
liEl.querySelectorAll('input[type="radio"], input[type="checkbox"]').forEach(function (inp) {
inp.checked = true;
try { inp.dispatchEvent(new Event('change', { bubbles: true })); } catch (_) { }
});
const aEl = liEl.querySelector('a');
if (aEl) { try { aEl.click(); } catch (_) { } }
try { liEl.click(); } catch (_) { }
xxtPcUpdateHiddenAnswer(timuEl, isSingle);
},
xxtPcClickOptionAt = (quEl, idx, isSingle) => {
const optLis = quEl.querySelectorAll('.Zy_ulTop li');
const opts = quEl.querySelectorAll('.Zy_ulTop li a');
if (optLis[idx]) {
xxtPcClickOptionLi(optLis[idx], isSingle);
return;
}
if (opts[idx]) {
const li = opts[idx].closest('li');
if (li) xxtPcClickOptionLi(li, isSingle);
else { try { opts[idx].click(); } catch (_) { } }
}
},
xxtPcIsMooc2NativeWork = () => {
try {
if (xxtIsMooc2StudyPage()) return true;
} catch (_) { }
try {
if (/[?&]mooc2=1(?:&|$)/.test(_l.search || '')) return true;
} catch (_) { }
return false;
},
xxtPcIsOptionSelected = (quEl, idx, isSingle) => {
const optLis = quEl.querySelectorAll('.Zy_ulTop li');
const li = optLis[idx];
if (!li) return false;
if (li.classList.contains('on') || li.classList.contains('cur')) return true;
const inp = li.querySelector('input[type="radio"], input[type="checkbox"]');
if (inp && inp.checked) return true;
const ansInput = quEl.querySelector('.Zy_ulBottom input[name^="answer"], .Zy_ulBottom textarea[name^="answer"]');
if (ansInput && String(ansInput.value || '').trim()) {
const letter = xxtPcOptionLetterAt(idx);
const val = String(ansInput.value).replace(/\s+/g, '').toUpperCase();
return val.indexOf(letter) >= 0;
}
return false;
},
xxtPcIsJudgeSelected = (quEl, target) => {
if (!target) return false;
if (target.classList.contains('on') || target.classList.contains('cur')) return true;
const inp = target.querySelector('input[type="radio"], input[type="checkbox"]');
if (inp && inp.checked) return true;
const ansInput = quEl.querySelector('.Zy_ulBottom input[name^="answer"], .Zy_ulBottom textarea[name^="answer"]');
return !!(ansInput && String(ansInput.value || '').trim());
},
xxtPcMooc2SimpleClick = (quEl, idx) => {
const optLis = quEl.querySelectorAll('.Zy_ulTop li');
const opts = quEl.querySelectorAll('.Zy_ulTop li a');
const ps = quEl.querySelectorAll('.Zy_ulTop li p');
if (opts[idx]) { try { opts[idx].click(); return; } catch (_) { } }
if (ps[idx]) { try { ps[idx].click(); return; } catch (_) { } }
if (optLis[idx]) { try { optLis[idx].click(); } catch (_) { } }
},
xxtPcApplyOptionClick = (quEl, idx, isSingle) => {
if (xxtPcIsMooc2NativeWork()) {
xxtPcMooc2SimpleClick(quEl, idx);
if (xxtPcIsOptionSelected(quEl, idx, isSingle)) return true;
}
xxtPcClickOptionAt(quEl, idx, isSingle);
return xxtPcIsOptionSelected(quEl, idx, isSingle);
},
xxtPcApplyJudgeClick = (quEl, target) => {
if (!target) return false;
if (xxtPcIsMooc2NativeWork()) {
try { target.click(); } catch (_) { }
if (xxtPcIsJudgeSelected(quEl, target)) return true;
}
xxtPcClickOptionLi(target, true);
return xxtPcIsJudgeSelected(quEl, target);
},
xxtPcCollectOptionMeta = (el) => {
const optLis = el.querySelectorAll('.Zy_ulTop li');
const opts = el.querySelectorAll('.Zy_ulTop li a');
const optsText = [];
if (opts.length) {
opts.forEach(function (a) {
optsText.push(trim(a.innerHTML).replace(/^[A-Za-z]\s*/, '').trim());
});
return { optLis: optLis, opts: opts, optsText: optsText };
}
const ul = el.querySelector('ul');
if (ul) {
ul.querySelectorAll('li').forEach(function (li) {
const after = li.querySelector('.after');
const raw = after ? after.textContent : li.textContent;
optsText.push(trim(String(raw || '').replace(/^[A-Za-z][.、\s]*/, '')));
});
}
return { optLis: el.querySelectorAll('ul li'), opts: [], optsText: optsText };
},
xxtAnswerPCQuestionNative = (qu, result) => {
const el = qu.element;
const meta = xxtPcCollectOptionMeta(el);
const optLis = meta.optLis;
const opts = meta.opts;
const optsText = meta.optsText;
const letterAt = xxtPcOptionLetterAt;
if (qu.type === '判断题') {
if (!xxtHasWorkAnswerText(result)) {
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100 && optLis[1]) {
const applied = xxtPcApplyJudgeClick(el, optLis[1]);
return { ok: applied, selected: applied ? 'B' : '', answerText: applied ? '未找到,自动选【错】' : '' };
}
return { ok: false, selected: '', answerText: '' };
}
const trueList = ['正确', '是', '对', '√', 'T', 'true'];
const isTrue = trueList.some(function (k) { return String(result).indexOf(k) >= 0; });
const target = isTrue ? optLis[0] : (optLis[1] || optLis[0]);
if (target) {
const applied = xxtPcApplyJudgeClick(el, target);
const idx = Array.prototype.indexOf.call(optLis, target);
return { ok: applied, selected: applied ? (idx >= 0 ? letterAt(idx) : 'B') : '', answerText: result };
}
return { ok: false, selected: '', answerText: result || '' };
}
if (qu.type === '单选题') {
const pickRandomC = () => {
if (!((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100)) return null;
let cIdx = -1;
for (let i = 0; i < optsText.length; i++) {
if (letterAt(i) === 'C') { cIdx = i; break; }
}
if (cIdx < 0 && optsText.length > 2) cIdx = 2;
if (cIdx >= 0) {
const applied = xxtPcApplyOptionClick(el, cIdx, true);
return { ok: applied, selected: applied ? letterAt(cIdx) : '', answerText: applied ? '未找到,自动选【C】' : '' };
}
return null;
};
if (!xxtHasWorkAnswerText(result)) {
const randomRes = pickRandomC();
if (randomRes) return randomRes;
return { ok: false, selected: '', answerText: '' };
}
const ansNorm = String(result).replace(/\s+/g, '').trim();
let idx = optsText.findIndex(function (t) { return t == result || t.replace(/\s+/g, '').trim() == ansNorm; });
if (idx == -1) idx = optsText.findIndex(function (t) {
return ansNorm && (t.indexOf(result) != -1 || String(result).indexOf(t) != -1);
});
if (idx >= 0) {
const applied = xxtPcApplyOptionClick(el, idx, true);
return { ok: applied, selected: applied ? letterAt(idx) : '', answerText: result };
}
const randomRes = pickRandomC();
if (randomRes) return randomRes;
} else if (qu.type === '多选题') {
let matched = false;
const selectedOptions = [];
if (xxtHasWorkAnswerText(result)) {
const ansArr = String(result).split(/[,,;;\s]+/).filter(function (s) { return s && String(s).trim(); });
optsText.forEach(function (t, i) {
const tNorm = t.replace(/\s+/g, '').trim();
for (let ai = 0; ai < ansArr.length; ai++) {
const aNorm = ansArr[ai].replace(/\s+/g, '').trim();
if (!aNorm) continue;
if (t == ansArr[ai] || tNorm == aNorm || t.indexOf(ansArr[ai]) != -1) {
if (xxtPcApplyOptionClick(el, i, false)) {
matched = true;
selectedOptions.push(letterAt(i));
}
}
}
});
if (matched) {
return { ok: true, selected: selectedOptions.join(''), answerText: result };
}
}
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
const allSel = [];
for (let i = 0; i < optsText.length; i++) {
if (xxtPcApplyOptionClick(el, i, false)) allSel.push(letterAt(i));
}
if (allSel.length) {
return { ok: true, selected: allSel.join(''), answerText: '未找到,自动全选' };
}
}
}
return { ok: false, selected: '', answerText: result || '' };
},
xxtFetchWorkAnswerOnce = (qu, wid, typeCode, useGet) => {
return new Promise(function (resolve) {
const cleanQ = qu.question.replace(/(^\s*)|(\s*$)/g, '');
if (useGet) {
gmRequest({
method: 'GET',
headers: { 'Authorization': token },
timeout: 6000,
url: host + 'chaoXing/v3/getAnswer.php?tm=' + encodeURIComponent(cleanQ) + '&type=' + typeCode + '&wid=' + wid + '&courseid=' + courseId,
onload: function (res) {
let answer = '', msg = '';
try {
const ctResult = JSON.parse(res.responseText);
answer = ctResult.data || '';
msg = ctResult.msg || '';
} catch (e) {
if (res.finalUrl && res.finalUrl.includes('getAnswer.php')) {
resolve({ answer: '', msg: '', serverError: true });
return;
}
}
resolve({ answer: answer, msg: msg, serverError: false, code: typeof ctResult.code !== 'undefined' ? ctResult.code : (answer ? 0 : -1) });
},
onerror: function () { resolve({ answer: '', msg: '', serverError: true }); },
ontimeout: function () { resolve({ answer: '', msg: '', serverError: true }); }
});
return;
}
let param = 'question=' + encodeURIComponent(cleanQ);
if (ctUrl.includes('icodef')) param += '&type=' + typeCode + '&id=' + wid;
gmRequest({
method: 'POST',
headers: { 'Content-type': 'application/x-www-form-urlencoded', 'Authorization': token },
url: ctUrl,
timeout: 6000,
data: param,
onload: function (res) {
let ctResult = { code: -1, data: '', msg: '' };
try { ctResult = JSON.parse(res.responseText); } catch (e) { }
resolve({
answer: ctResult.data || '',
msg: ctResult.msg || '',
serverError: false,
code: ctResult.code
});
},
onerror: function () { resolve({ answer: '', msg: '', serverError: true }); },
ontimeout: function () { resolve({ answer: '', msg: '', serverError: true }); }
});
});
},
xxtFetchWorkAnswer = async (qu, wid, typeCode) => {
let r = await xxtFetchWorkAnswerOnce(qu, wid, typeCode, false);
if (!r.answer && r.code === -1) {
r = await xxtFetchWorkAnswerOnce(qu, wid, typeCode, true);
}
return r;
},
xxtRunNativeChapterWork = async (item) => {
const ctx = await xxtResolveNativeAnswerContext(90000);
if (!ctx) {
throw new Error('未找到章节测验答题区域,请确认已切换到「章节测验」标签');
}
if (ctx.skip) {
xxtNativeWorkLog('章节测验状态:' + ctx.reason + ',已跳过', ctx.reason === '待批阅' ? 'orange' : 'green');
return;
}
const wid = xxtGetWidFromDoc(ctx.answerDoc) || String(item['workid'] || '').replace('work-', '') || String(item['jobid']).replace('work-', '');
let questionList = [];
let questionNum = 0;
let totalQuestionNum = 0;
if (ctx.mode === 'phone') {
questionList = xxtParsePhoneQuestionsNative(ctx.answerDoc);
} else {
questionList = xxtParsePCQuestionsNative(ctx.answerDoc);
}
totalQuestionNum = questionList.length;
questionNum = totalQuestionNum;
if (totalQuestionNum <= 0) {
throw new Error('未解析到可作答题目(仅支持单选/多选/判断)');
}
const typeMap = { '单选题': '0', '多选题': '1', '判断题': '3' };
for (let i = 0; i < questionList.length; i++) {
const qu = questionList[i];
await xxtSleep(parseInt(Math.random() * 2000 + 1500, 10));
let fetchRes = await xxtFetchWorkAnswer(qu, wid, typeMap[qu.type]);
let fetchMeta = xxtWorkFetchMeta(fetchRes);
if (!fetchMeta.ans && fetchRes.serverError) {
logs.addLog('查题错误,服务器连接失败(使用高峰期),等待一段时间', 'orange');
await xxtSleep(3000);
fetchRes = await xxtFetchWorkAnswer(qu, wid, typeMap[qu.type]);
fetchMeta = xxtWorkFetchMeta(fetchRes);
if (!fetchMeta.ans && fetchRes.serverError) {
logs.addLog('查题错误,服务器连接失败(使用高峰期),等待一段时间', 'orange');
}
}
const ans = fetchMeta.ans;
const hintLine = fetchMeta.hint;
const applyRes = ctx.mode === 'phone'
? xxtAnswerPhoneQuestionNative(ctx.answerDoc, qu, ans)
: xxtAnswerPCQuestionNative(qu, ans);
if (applyRes.ok) {
questionNum -= 1;
logs.addLog(xxtFormatWorkQuestionDisplay(qu, applyRes.answerText || ans, i + 1, totalQuestionNum, false, '', applyRes.selected, hintLine));
} else {
logs.addLog(xxtFormatWorkQuestionDisplay(qu, ans, i + 1, totalQuestionNum, false, '', '', hintLine));
}
}
await xxtFinishNativeWork(item, ctx, totalQuestionNum, questionNum);
},
doWork = (item) => {
try {
if (top.__xxtNativeWorkResuming === item['jobid']) top.__xxtNativeWorkResuming = null;
} catch (_) { }
missionList['m' + item['jobid']]['running'] = true;
logs.addLog('开始刷章节测试:' + item['name']);
logs.addLog('您设置的答题正确率为:' + String(accuracy) + '%,只有在高于此正确率时才会提交测试', 'blue');
try {
const wp = top.document.getElementById('workPanel');
if (wp) wp.style.display = 'none';
} catch (_) { }
if (!xxtIsWorkTabActive() || !xxtFindWorkAttachIframe()) {
try {
top.__xxtNativeWorkResume = xxtSerializeWorkItem(item);
top.__xxtNativeWorkResuming = item['jobid'];
} catch (_) { }
logs.addLog('正在切换到章节测验标签页…', 'blue');
xxtSwitchToWorkTab();
return;
}
xxtRunNativeChapterWork(item).then(function () {
missionList['m' + item['jobid']]['running'] = false;
missionList['m' + item['jobid']]['done'] = true;
}).catch(function (e) {
logs.addLog('章节测验处理失败:' + (e && e.message ? e.message : String(e)), 'red');
missionList['m' + item['jobid']]['running'] = false;
});
},
missionList = [];
try {
top._xxtStudyAddLog = (msg, color) => logs.addLog(msg, color || 'green');
} catch (_) { }
if (jobList.length <= 0) {
if (jumpType != 2) {
xxtTryNoTaskJump('ℹ️ 此页无任务,准备跳转下一节');
} else {
logs.addLog('此页无任务,用户设置为不跳转,脚本已结束运行,如需自动跳转,请到任务配置界面改变模式为遍历', 'green');
}
return;
}
for (let i = 0, l = jobList.length; i < l; i++) {
let item = jobList[i];
if (item['type'] == 'video') {
video_getReady(item);
} else if (item['type'] == 'document') {
missionList['m' + item['jobid']] = {
'type': 'document',
'jtoken': item['jtoken'],
'jobid': item['jobid'],
'name': item['property']['name'],
'done': false,
'running': false
};
top.document.getElementById('joblist').innerHTML += `
` + '[文档]' + item['property']['name'] + `
`
} else if (item['type'] == 'workid' && _w.top.unrivalDoWork == '1') {
missionList['m' + item['jobid']] = {
'type': 'work',
'workid': item['property']['workid'],
'jobid': item['jobid'],
'name': item['property']['title'],
'enc': item['enc'],
'done': false,
'running': false
};
top.document.getElementById('joblist').innerHTML += `
` + '[章节测试]' + item['property']['title'] + `
`
} else {
try {
let jobName = item['property']['name'];
if (jobName == undefined) {
jobName = item['property']['title'];
}
top.document.getElementById('joblist').innerHTML += `
`
} catch (e) { }
}
}
try {
if (top.__xxtNativeWorkResume && top.__xxtNativeWorkResume.jobid) {
const rw = top.__xxtNativeWorkResume;
top.__xxtNativeWorkResume = null;
try { top.__xxtNativeWorkResuming = rw.jobid; } catch (_) { }
setTimeout(function () {
const mi = missionList['m' + rw.jobid];
if (mi && !mi.done) {
doWork(mi);
}
}, 3500);
}
} catch (_) { }
loopjob();
} else if (_l.href.includes("mycourse/studentstudy")) {
xxtClearTimersByPrefix('study');
var audiofile =
'data:audio/ogg;base64,T2dnUwACAAAAAAAAAABwRPFFAAAAAGFtEqwBHgF2b3JiaXMAAAAAAUAfAAAAAAAAUHgAAAAAAACZAU9nZ1MAAAAAAAAAAAAAcETxRQEAAAA7J4IBDP8F////////////tQN2b3JiaXMvAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAxNDAxMjIgKFR1cnBha8OkcsOkamlpbikGAAAAJQAAAEVOQ09ERVI9U291bmQgU3R1ZGlvLCBsaWJWb3JiaXMgMS4zLjEbAAAAQUxCVU0gQVJUSVNUPUFkdmVudHVyZSBMYW5kFAAAAEFMQlVNPUFkdmVudHVyZSBMYW5kIQAAAEVOQ09ESU5HIEFQUExJQ0FUSU9OPVNvdW5kIFN0dWRpbxUAAABBUlRJU1Q9QWR2ZW50dXJlIExhbmQjAAAAVElUTEU9RW1wdHkgTG9vcCBGb3IgSlMgUGVyZm9ybWFuY2UBBXZvcmJpcxJCQ1YBAAABAAxSFCElGVNKYwiVUlIpBR1jUFtHHWPUOUYhZBBTiEkZpXtPKpVYSsgRUlgpRR1TTFNJlVKWKUUdYxRTSCFT1jFloXMUS4ZJCSVsTa50FkvomWOWMUYdY85aSp1j1jFFHWNSUkmhcxg6ZiVkFDpGxehifDA6laJCKL7H3lLpLYWKW4q91xpT6y2EGEtpwQhhc+211dxKasUYY4wxxsXiUyiC0JBVAAABAABABAFCQ1YBAAoAAMJQDEVRgNCQVQBABgCAABRFcRTHcRxHkiTLAkJDVgEAQAAAAgAAKI7hKJIjSZJkWZZlWZameZaouaov+64u667t6roOhIasBADIAAAYhiGH3knMkFOQSSYpVcw5CKH1DjnlFGTSUsaYYoxRzpBTDDEFMYbQKYUQ1E45pQwiCENInWTOIEs96OBi5zgQGrIiAIgCAACMQYwhxpBzDEoGIXKOScggRM45KZ2UTEoorbSWSQktldYi55yUTkompbQWUsuklNZCKwUAAAQ4AAAEWAiFhqwIAKIAABCDkFJIKcSUYk4xh5RSjinHkFLMOcWYcowx6CBUzDHIHIRIKcUYc0455iBkDCrmHIQMMgEAAAEOAAABFkKhISsCgDgBAIMkaZqlaaJoaZooeqaoqqIoqqrleabpmaaqeqKpqqaquq6pqq5seZ5peqaoqp4pqqqpqq5rqqrriqpqy6ar2rbpqrbsyrJuu7Ks256qyrapurJuqq5tu7Js664s27rkearqmabreqbpuqrr2rLqurLtmabriqor26bryrLryratyrKua6bpuqKr2q6purLtyq5tu7Ks+6br6rbqyrquyrLu27au+7KtC7vourauyq6uq7Ks67It67Zs20LJ81TVM03X9UzTdVXXtW3VdW1bM03XNV1XlkXVdWXVlXVddWVb90zTdU1XlWXTVWVZlWXddmVXl0XXtW1Vln1ddWVfl23d92VZ133TdXVblWXbV2VZ92Vd94VZt33dU1VbN11X103X1X1b131htm3fF11X11XZ1oVVlnXf1n1lmHWdMLqurqu27OuqLOu+ruvGMOu6MKy6bfyurQvDq+vGseu+rty+j2rbvvDqtjG8um4cu7Abv+37xrGpqm2brqvrpivrumzrvm/runGMrqvrqiz7uurKvm/ruvDrvi8Mo+vquirLurDasq/Lui4Mu64bw2rbwu7aunDMsi4Mt+8rx68LQ9W2heHVdaOr28ZvC8PSN3a+AACAAQcAgAATykChISsCgDgBAAYhCBVjECrGIIQQUgohpFQxBiFjDkrGHJQQSkkhlNIqxiBkjknIHJMQSmiplNBKKKWlUEpLoZTWUmotptRaDKG0FEpprZTSWmopttRSbBVjEDLnpGSOSSiltFZKaSlzTErGoKQOQiqlpNJKSa1lzknJoKPSOUippNJSSam1UEproZTWSkqxpdJKba3FGkppLaTSWkmptdRSba21WiPGIGSMQcmck1JKSamU0lrmnJQOOiqZg5JKKamVklKsmJPSQSglg4xKSaW1kkoroZTWSkqxhVJaa63VmFJLNZSSWkmpxVBKa621GlMrNYVQUgultBZKaa21VmtqLbZQQmuhpBZLKjG1FmNtrcUYSmmtpBJbKanFFluNrbVYU0s1lpJibK3V2EotOdZaa0ot1tJSjK21mFtMucVYaw0ltBZKaa2U0lpKrcXWWq2hlNZKKrGVklpsrdXYWow1lNJiKSm1kEpsrbVYW2w1ppZibLHVWFKLMcZYc0u11ZRai621WEsrNcYYa2415VIAAMCAAwBAgAlloNCQlQBAFAAAYAxjjEFoFHLMOSmNUs45JyVzDkIIKWXOQQghpc45CKW01DkHoZSUQikppRRbKCWl1losAACgwAEAIMAGTYnFAQoNWQkARAEAIMYoxRiExiClGIPQGKMUYxAqpRhzDkKlFGPOQcgYc85BKRljzkEnJYQQQimlhBBCKKWUAgAAChwAAAJs0JRYHKDQkBUBQBQAAGAMYgwxhiB0UjopEYRMSielkRJaCylllkqKJcbMWomtxNhICa2F1jJrJcbSYkatxFhiKgAA7MABAOzAQig0ZCUAkAcAQBijFGPOOWcQYsw5CCE0CDHmHIQQKsaccw5CCBVjzjkHIYTOOecghBBC55xzEEIIoYMQQgillNJBCCGEUkrpIIQQQimldBBCCKGUUgoAACpwAAAIsFFkc4KRoEJDVgIAeQAAgDFKOSclpUYpxiCkFFujFGMQUmqtYgxCSq3FWDEGIaXWYuwgpNRajLV2EFJqLcZaQ0qtxVhrziGl1mKsNdfUWoy15tx7ai3GWnPOuQAA3AUHALADG0U2JxgJKjRkJQCQBwBAIKQUY4w5h5RijDHnnENKMcaYc84pxhhzzjnnFGOMOeecc4wx55xzzjnGmHPOOeecc84556CDkDnnnHPQQeicc845CCF0zjnnHIQQCgAAKnAAAAiwUWRzgpGgQkNWAgDhAACAMZRSSimllFJKqKOUUkoppZRSAiGllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimVUkoppZRSSimllFJKKaUAIN8KBwD/BxtnWEk6KxwNLjRkJQAQDgAAGMMYhIw5JyWlhjEIpXROSkklNYxBKKVzElJKKYPQWmqlpNJSShmElGILIZWUWgqltFZrKam1lFIoKcUaS0qppdYy5ySkklpLrbaYOQelpNZaaq3FEEJKsbXWUmuxdVJSSa211lptLaSUWmstxtZibCWlllprqcXWWkyptRZbSy3G1mJLrcXYYosxxhoLAOBucACASLBxhpWks8LR4EJDVgIAIQEABDJKOeecgxBCCCFSijHnoIMQQgghREox5pyDEEIIIYSMMecghBBCCKGUkDHmHIQQQgghhFI65yCEUEoJpZRSSucchBBCCKWUUkoJIYQQQiillFJKKSGEEEoppZRSSiklhBBCKKWUUkoppYQQQiillFJKKaWUEEIopZRSSimllBJC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',
audioPlayer = new Audio(audiofile);
_w.top.backNow = 0;
audioPlayer.loop = true;
_w.audioPlayer = audioPlayer;
xxtSetInterval(function () {
try {
_w.jQuery.fn.viewer.Constructor.prototype.show = () => { };
} catch (e) {
}
}, 1000, 'study.loop.viewerPatch');
try {
_w.unrivalScriptList.push('Fuck me please');
} catch (e) {
_w.unrivalScriptList = ['Fuck me please'];
}
function checkOffline() {
let dleft = _d.getElementsByClassName('left');
if (dleft.length == 1) {
let img = dleft[0].getElementsByTagName('img');
if (img.length == 1) {
if (img[0].src.indexOf('loading.gif') != -1) {
return true;
}
}
}
return false;
}
xxtSetInterval(function () {
if (checkOffline()) {
setTimeout(function () {
if (checkOffline()) {
_l.reload();
}
}, 10000)
}
}, 3000, 'study.loop.offlineCheck');
_d.addEventListener('visibilitychange', function () {
var c = 0;
if (_w.top.backNow == 0) {
_d.title = '⚠️请先激活挂机';
return
} else {
_d.title = '学生学习页面';
}
if (_d.hidden) {
audioPlayer.play();
var timer = xxtSetInterval(function () {
if (c) {
_d.title = '挂机中';
c = 0;
} else {
_d.title = '挂机中';
c = 1;
}
if (!_d.hidden) {
xxtClearInterval(timer);
_d.title = '学生学习页面';
}
}, 1300, 'study.ephemeral.titleBlink');
} else {
audioPlayer.pause();
}
});
_w.unrivalgetTeacherAjax = _w.getTeacherAjax;
_w.getTeacherAjax = (courseid, classid, cid) => {
if (cid == getQueryVariable('chapterId')) {
return;
}
xxtClearTimersByPrefix('study.ephemeral');
_w.top.unrivalPageRd = '';
_w.unrivalgetTeacherAjax(courseid, classid, cid);
}
if (disableMonitor == 1) {
_w.appendChild = _w.Element.prototype.appendChild;
_w.Element.prototype.appendChild = function () {
try {
if (arguments[0].src.indexOf('detect.chaoxing.com') > 0) {
return;
}
} catch (e) { }
_w.appendChild.apply(this, arguments);
};
}
_w.jump = false;
xxtSetInterval(function () {
if (getQueryVariable('mooc2') == '1') {
let tabs = _d.getElementsByClassName('posCatalog_select');
for (let i = 0, l = tabs.length; i < l; i++) {
let tabId = tabs[i].getAttribute('id');
if (tabId && tabId.indexOf('cur') >= 0 && tabs[i].getAttribute('class') == 'posCatalog_select') {
tabs[i].setAttribute('onclick', "getTeacherAjax('" + courseId + "','" + classId +
"','" + tabId.replace('cur', '') + "');");
}
}
} else {
let h4s = _d.getElementsByTagName('h4'),
h5s = _d.getElementsByTagName('h5');
for (let i = 0, l = h4s.length; i < l; i++) {
const h4Id = h4s[i].getAttribute('id');
if (h4Id && h4Id.indexOf('cur') >= 0) {
h4s[i].setAttribute('onclick', "getTeacherAjax('" + courseId + "','" + classId +
"','" + h4Id.replace('cur', '') + "');");
}
}
for (let i = 0, l = h5s.length; i < l; i++) {
const h5Id = h5s[i].getAttribute('id');
if (h5Id && h5Id.indexOf('cur') >= 0) {
h5s[i].setAttribute('onclick', "getTeacherAjax('" + courseId + "','" + classId +
"','" + h5Id.replace('cur', '') + "');");
}
}
}
}, 1000, 'study.loop.onclickPatch');
xxtSetInterval(function () {
if (_w.jump) {
_w.jump = false;
if (!xxtHasNextChapter()) {
stop = true;
xxtNotifyChapterEnd();
return;
}
_w.top.unrivalDoneWorkId = '';
_w.jjump = (rd) => {
if (rd != _w.top.unrivalPageRd) {
return;
}
try {
setTimeout(function () {
if (jumpType == 1) {
let nextBtn = xxtGetNextChapterBtn(_d);
if (!nextBtn) {
stop = true;
xxtNotifyChapterEnd();
return;
}
try {
setTimeout(function () {
if (rd != _w.top.unrivalPageRd) {
return;
}
// 新版学习通:点击前先检查并处理弹窗
if (getQueryVariable('mooc2') == '1') {
// 检查是否有未完成任务提示弹窗
const warn = document.querySelector('.popDiv.wid440.popMove .jobLimitTip');
if (warn && /当前章节还有任务点未完成,是否去完成/.test(warn.innerText)) {
console.log('[学习通助手] 检测到未完成任务提示,自动点击下一节');
// 直接点击弹窗中的下一节按钮
const nextBtnPop = document.querySelector('.popDiv.wid440.popMove .nextChapter');
if (nextBtnPop) {
nextBtnPop.click();
return;
}
}
}
nextBtn = xxtGetNextChapterBtn(_d);
if (nextBtn) {
nextBtn.click();
}
// 旧版学习通:点击后检查弹窗是否出现
if (getQueryVariable('mooc2') != '1') {
setTimeout(function () {
const tip = document.getElementById('jobFinishTip');
if (tip && tip.style.display !== 'none') {
const nextBtnTip = tip.querySelector('.nextChapter');
if (nextBtnTip) nextBtnTip.click();
}
}, 500);
}
}, 2000);
} catch (e) { }
return;
}
if (getQueryVariable('mooc2') == '1') {
let ul = _d.getElementsByClassName('prev_ul')[0],
lis = ul.getElementsByTagName('li');
for (let i = 0, l = lis.length; i < l; i++) {
if (lis[i].getAttribute('class') == 'active') {
if (i + 1 >= l) {
break;
} else {
try {
lis[i + 1].click();
} catch (e) { }
return;
}
}
}
let tabs = _d.getElementsByClassName('posCatalog_select');
for (let i = 0, l = tabs.length; i < l; i++) {
if (tabs[i].getAttribute('class') ==
'posCatalog_select posCatalog_active') {
while (i + 1 < tabs.length) {
let nextTab = tabs[i + 1];
if ((nextTab.innerHTML.includes(
'icon_Completed prevTips') && _w.top
.unrivalReviewMode == '0') || nextTab
.innerHTML.includes(
'catalog_points_er prevTips')) {
i++;
continue;
}
if (!nextTab.id || nextTab.id.indexOf('cur') < 0) {
i++;
continue;
}
let clickF = xxtSetInterval(function () {
if (rd != _w.top.unrivalPageRd) {
xxtClearInterval(clickF);
return;
}
// 新版学习通:点击前先检查并处理弹窗
const warn = document.querySelector('.popDiv.wid440.popMove .jobLimitTip');
if (warn && /当前章节还有任务点未完成,是否去完成/.test(warn.innerText)) {
console.log('[学习通助手] 检测到未完成任务提示,自动点击下一节');
// 直接点击弹窗中的下一节按钮
const nextBtn = document.querySelector('.popDiv.wid440.popMove .nextChapter');
if (nextBtn) {
nextBtn.click();
xxtClearInterval(clickF);
return;
}
}
nextTab.click();
}, 2000, 'study.ephemeral.clickF');
break;
}
break;
}
}
} else {
let div = _d.getElementsByClassName('tabtags')[0],
spans = div.getElementsByTagName('span');
for (let i = 0, l = spans.length; i < l; i++) {
const spanClass = spans[i].getAttribute('class');
if (spanClass && spanClass.indexOf('currents') >= 0) {
if (i + 1 == l) {
break;
} else {
try {
spans[i + 1].click();
// 旧版学习通:点击后检查弹窗是否出现
setTimeout(function () {
const tip = document.getElementById('jobFinishTip');
if (tip && tip.style.display !== 'none') {
const nextBtn = tip.querySelector('.nextChapter');
if (nextBtn) nextBtn.click();
}
}, 500);
} catch (e) { }
return;
}
}
}
let tabs = _d.getElementsByTagName('span'),
newTabs = [];
for (let i = 0, l = tabs.length; i < l; i++) {
if (tabs[i].getAttribute('style') != null && tabs[i]
.getAttribute('style').indexOf(
'cursor:pointer;height:18px;') >= 0) {
newTabs.push(tabs[i]);
}
}
tabs = newTabs;
for (let i = 0, l = tabs.length; i < l; i++) {
const parentClass = tabs[i].parentNode.getAttribute('class');
if (parentClass == 'currents') {
while (i + 1 < tabs.length) {
let nextTab = tabs[i + 1].parentNode;
if ((nextTab.innerHTML.includes(
'roundpoint blue') && _w.top
.unrivalReviewMode == '0') || nextTab
.innerHTML.includes('roundpointStudent lock')
) {
i++;
continue;
}
if (!nextTab.id || nextTab.id.indexOf('cur') < 0) {
i++;
continue;
}
let clickF = xxtSetInterval(function () {
if (rd != _w.top.unrivalPageRd) {
xxtClearInterval(clickF);
return;
}
nextTab.click();
// 旧版学习通:点击后检查弹窗是否出现
setTimeout(function () {
const tip = document.getElementById('jobFinishTip');
if (tip && tip.style.display !== 'none') {
const nextBtn = tip.querySelector('.nextChapter');
if (nextBtn) {
nextBtn.click();
xxtClearInterval(clickF);
}
}
}, 500);
}, 2000, 'study.ephemeral.clickF');
break;
}
break;
}
}
}
}, 2000);
} catch (e) { }
}
_w.onReadComplete1();
setTimeout('jjump("' + _w.top.unrivalPageRd + '")', 2856);
}
}, 200, 'study.loop.jumpLoop');
} else if (_l.href.indexOf("work/phone/doHomeWork") > 0) {
var wIdE = _d.getElementById('workLibraryId') || _d.getElementById('oldWorkId'),
wid = wIdE.value;
_w.top.unrivalWorkDone = false;
_w.aalert = _w.alert;
_w.alert = (msg) => {
if (msg == '保存成功') {
_w.top.unrivalDoneWorkId = getQueryVariable('workId');
return;
}
aalert(msg);
}
if (_w.top.unrivalDoneWorkId == getQueryVariable('workId')) {
_w.top.unrivalWorkDone = true;
return;
}
_w.confirm = (msg) => {
return true;
}
var questionList = [],
questionsElement = _d.getElementsByClassName('Py-mian1'),
questionNum = questionsElement.length,
totalQuestionNum = questionNum;
for (let i = 0; i < questionNum; i++) {
let questionElement = questionsElement[i],
idElements = questionElement.getElementsByTagName('input'),
questionId = '0',
question = questionElement.getElementsByClassName('Py-m1-title fs16')[0].innerHTML;
question = handleImgs(question).replace(/(<([^>]+)>)/ig, '').replace(/[0-9]{1,3}.\[(.*?)\]/ig, '').replaceAll('\n',
'').replace(/^\s+/ig, '').replace(/\s+$/ig, '');
for (let z = 0, k = idElements.length; z < k; z++) {
try {
if (idElements[z].getAttribute('name').indexOf('answer') >= 0) {
questionId = idElements[z].getAttribute('name').replace('type', '');
break;
}
} catch (e) {
console.log(e);
continue;
}
}
if (questionId == '0' || question == '') {
continue;
}
typeE = questionElement.getElementsByTagName('input');
if (typeE == null || typeE == []) {
continue;
}
let typeN = 'fuckme';
for (let g = 0, h = typeE.length; g < h; g++) {
if (typeE[g].id == 'answertype' + questionId.replace('answer', '').replace('check', '')) {
typeN = typeE[g].value;
break;
}
}
if (['0', '1', '3'].indexOf(typeN) < 0) {
continue;
}
type = {
'0': '单选题',
'1': '多选题',
'3': '判断题'
}[typeN];
let optionList = {
length: 0
};
if (['单选题', '多选题'].indexOf(type) >= 0) {
let answersElements = questionElement.getElementsByClassName('answerList')[0].getElementsByTagName(
'li');
for (let x = 0, j = answersElements.length; x < j; x++) {
let optionE = answersElements[x],
optionTextE = trim(optionE.innerHTML.replace(/(^\s*)|(\s*$)/g, "")),
optionText = optionTextE.slice(1).replace(/(^\s*)|(\s*$)/g, ""),
optionValue = optionTextE.slice(0, 1),
optionId = optionE.getAttribute('id-param');
if (optionText == '') {
break;
}
optionList[optionText] = {
'id': optionId,
'value': optionValue
}
optionList.length++;
}
if (answersElements.length != optionList.length) {
continue;
}
}
questionList.push({
'question': question,
'type': type,
'questionid': questionId,
'options': optionList
});
}
var qu = null,
nowTime = -4000,
busyThread = questionList.length,
ctOnload = function (res, quu, index, total) {
busyThread -= 1;
// 检查题目是否已完成(已选择答案)
let isAlreadyAnswered = false;
let existingAnswer = '';
try {
const allLi = _d.getElementsByTagName('li');
for (let li of allLi) {
if (li.getAttribute('id-param') == quu['questionid'].replace('answer', '')) {
if (li.getAttribute('class') && li.getAttribute('class').includes('cur')) {
isAlreadyAnswered = true;
const emEl = li.getElementsByTagName('em')[0];
if (emEl) {
existingAnswer = emEl.getAttribute('id-param') || '';
}
break;
}
}
}
} catch (e) { }
// 题目格式化显示函数
const formatQuestionDisplay = function(qu, ans, idx, tot, answered, oldAns, selectedOption) {
const header = '【第' + idx + '/' + tot + '题 - ' + qu['type'] + '】';
const questionLine = '📋 ' + qu['question'];
let answerLine = '';
if (answered && oldAns) {
answerLine = '✅ 已作答:' + oldAns + '(跳过)';
} else if (ans) {
if (selectedOption) {
answerLine = '✅ 答案:' + ans + ' 选' + selectedOption;
} else {
answerLine = '✅ 答案:' + ans;
}
} else {
answerLine = '❌ 未找到答案';
}
return header + '
' + questionLine + '
' + answerLine;
};
var ctResult = {
'code': -1,
'finalUrl': '',
'data': '未找到答案,可点击蓝色复制题目按钮后手动自行搜索处理'
};
if (res) {
try {
var responseText = res.responseText,
ctResult = JSON.parse(responseText);
} catch (e) {
console.log(e);
if (res.finalUrl && res.finalUrl.includes('getAnswer.php')) {
_w.top.unrivalWorkInfo = '查题错误,服务器连接失败(使用高峰期),等待一段时间';
return;
}
}
}
try {
let choiceEs = _d.getElementsByTagName('li');
if (ctResult['code'] == -1 ) {
try {
if (ctResult['msg'] !== undefined) {
_w.top.unrivalWorkInfo = ctResult['msg'] ;
}
} catch (e) { }
busyThread += 1;
gmRequest({
method: "GET",
headers: {
'Authorization': token,
},
timeout: 6000,
url: host + 'chaoXing/v3/getAnswer.php?tm=' + encodeURIComponent(quu['question']
.replace(/(^\s*)|(\s*$)/g, '')) + '&type=' + {
'单选题': '0',
'多选题': '1',
'判断题': '3'
}[quu['type']] + '&wid=' + wid + '&courseid=' + courseId,
onload: function (res) {
ctOnload(res, quu, index, total);
},
onerror: function (err) {
_w.top.unrivalWorkInfo = '查题错误,服务器连接失败(使用高峰期),等待一段时间';
console.log(err);
busyThread -= 1;
},
ontimeout: function (err) {
_w.top.unrivalWorkInfo = '查题错误,服务器连接失败(使用高峰期),等待一段时间';
console.log(err);
busyThread -= 1;
}
});
return;
}
try {
var result = ctResult['data'];
} catch (e) {
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, '', index, total, isAlreadyAnswered, existingAnswer, '');
return;
}
// 如果题目已作答,显示跳过信息
if (isAlreadyAnswered) {
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, result, index, total, true, existingAnswer, '');
return;
}
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, result, index, total, false, '', '');
switch (quu['type']) {
case '判断题':
(function () {
let answer = 'abaabaaba';
if ('正确是对√Tri'.indexOf(result) >= 0) {
answer = 'true';
} else if ('错误否错×Fwr'.indexOf(result) >= 0) {
answer = 'false';
}
for (let u = 0, k = choiceEs.length; u < k; u++) {
if (choiceEs[u].getAttribute('val-param') ==
answer && choiceEs[u].getAttribute(
'id-param') == quu['questionid'].replace(
'answer', '')) {
choiceEs[u].click();
questionNum -= 1;
// 更新显示,添加选中选项字母
const emEl = choiceEs[u].getElementsByTagName('em')[0];
let selectedOption = '';
if (emEl) {
selectedOption = emEl.getAttribute('id-param') || emEl.textContent || '';
}
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, result, index, total, false, '', selectedOption);
return;
}
}
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let u = 0, k = choiceEs.length; u <
k; u++) {
if (choiceEs[u].getElementsByTagName('em')
.length < 1) {
continue;
}
if (choiceEs[u].getAttribute('val-param') ==
'false' && choiceEs[u].getAttribute(
'id-param') == quu['questionid']
.replace('answer', '')) {
choiceEs[u].click();
// 更新显示,添加选中选项字母
const emEl = choiceEs[u].getElementsByTagName('em')[0];
let selectedOption = '';
if (emEl) {
selectedOption = emEl.getAttribute('id-param') || emEl.textContent || '';
}
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, '未找到,自动选【错】', index, total, false, '', selectedOption);
return;
}
}
}
})();
break;
case '单选题':
(function () {
let answerData = result;
for (let option in quu['options']) {
if (trim(option).replace(/\s/ig, '') == trim(answerData).replace(/\s/ig, '') || trim(
option).replace(/\s/ig, '').includes(trim(answerData).replace(/\s/ig, '')) ||
trim(answerData).replace(/\s/ig, '').includes(trim(option).replace(/\s/ig, ''))) {
for (let y = 0, j = choiceEs.length; y <
j; y++) {
if (choiceEs[y].getElementsByTagName(
'em').length < 1) {
continue;
}
if (choiceEs[y].getElementsByTagName(
'em')[0].getAttribute(
'id-param') == quu['options'][
option
]['value'] && choiceEs[y]
.getAttribute('id-param') == quu[
'questionid'].replace('answer',
'')) {
if (!choiceEs[y].getAttribute(
'class').includes('cur')) {
choiceEs[y].click();
}
questionNum -= 1;
// 更新显示,添加选中选项
const emEl = choiceEs[y].getElementsByTagName('em')[0];
let selectedOption = '';
if (emEl) {
selectedOption = emEl.getAttribute('id-param') || emEl.textContent || '';
}
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, result, index, total, false, '', selectedOption);
return;
}
}
}
}
if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
for (let y = 0, j = choiceEs.length; y <
j; y++) {
if (choiceEs[y].getElementsByTagName('em')
.length < 1) {
continue;
}
if (choiceEs[y].getElementsByTagName('em')[
0].getAttribute('id-param') ==
'C' && choiceEs[y].getAttribute(
'id-param') == quu['questionid']
.replace('answer', '')) {
if (!choiceEs[y].getAttribute('class')
.includes('cur')) {
choiceEs[y].click();
}
// 更新显示,添加选中选项字母
const emEl = choiceEs[y].getElementsByTagName('em')[0];
let selectedOption = '';
if (emEl) {
selectedOption = emEl.getAttribute('id-param') || emEl.textContent || '';
}
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, '未找到,自动选【C】', index, total, false, '', selectedOption);
return;
}
}
}
})();
break;
case '多选题':
(function () {
let answerData = trim(result).replace(/\s/ig, ''),
selectedOptions = [];
for (let option in quu['options']) {
if (answerData.includes(trim(option).replace(/\s/ig, ''))) {
for (let y = 0, j = choiceEs.length; y <
j; y++) {
if (choiceEs[y].getElementsByTagName(
'em').length < 1) {
continue;
}
if (choiceEs[y].getElementsByTagName(
'em')[0].getAttribute(
'id-param') == quu['options'][
option
]['value'] && choiceEs[y]
.getAttribute('id-param') == quu[
'questionid'].replace('answer',
'')) {
if (!choiceEs[y].getAttribute(
'class').includes('cur')) {
choiceEs[y].click();
}
// 收集选中的选项字母
const emEl = choiceEs[y].getElementsByTagName('em')[0];
let opt = '';
if (emEl) {
opt = emEl.getAttribute('id-param') || emEl.textContent || '';
}
if (opt) selectedOptions.push(opt);
break;
}
}
}
}
if (selectedOptions.length > 0) {
questionNum -= 1;
// 更新显示,添加选中的选项字母
const selectedStr = selectedOptions.join('');
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, result, index, total, false, '', selectedStr);
} else if ((randomDo == 1 || _w.top.unrivalRandomDo == 1) && accuracy < 100) {
let selectedOptions = [];
for (let y = 0, j = choiceEs.length; y <
j; y++) {
if (choiceEs[y].getElementsByTagName('em')
.length < 1) {
continue;
}
if (choiceEs[y].getAttribute('id-param') ==
quu['questionid'].replace('answer', '')
) {
if (!choiceEs[y].getAttribute('class')
.includes('cur')) {
choiceEs[y].click();
const emEl = choiceEs[y].getElementsByTagName('em')[0];
let opt = '';
if (emEl) {
opt = emEl.getAttribute('id-param') || emEl.textContent || '';
}
if (opt) selectedOptions.push(opt);
}
}
}
// 更新显示,添加选中的选项字母
const selectedStr = selectedOptions.length > 0 ? selectedOptions.join('') : '全选';
_w.top.unrivalWorkInfo = formatQuestionDisplay(quu, '未找到,自动全选', index, total, false, '', selectedStr);
}
})();
break;
}
} catch (e) {
console.log(e);
}
}
for (let i = 0, l = questionList.length; i < l; i++) {
nowTime += parseInt(Math.random() * 2000 + 2500, 10);
setTimeout(function () {
qu = questionList[i];
let param = 'question=' + encodeURIComponent(
qu['question']);
if (ctUrl.includes('icodef')) {
param += '&type=' + {
'单选题': '0',
'多选题': '1',
'判断题': '3'
}[qu['type']] + '&id=' + wid;
}
gmRequest({
method: "POST",
headers: {
'Content-type': 'application/x-www-form-urlencoded',
'Authorization': token,
},
url: ctUrl,
timeout: 2000,
data: param,
onload: function (res) {
ctOnload(res, qu, i + 1, l);
},
onerror: function () {
ctOnload(false, qu, i + 1, l);
},
ontimeout: function () {
ctOnload(false, qu, i + 1, l);
}
});
}, nowTime);
}
var workInterval = setInterval(function () {
if (busyThread != 0) {
return;
}
clearInterval(workInterval);
if (Math.floor((totalQuestionNum - questionNum) / totalQuestionNum) * 100 >= accuracy && _w.top
.unrivalAutoSubmit == '1') {
_w.top.unrivalDoneWorkId = getQueryVariable('workId');
_w.top.unrivalWorkInfo = '正确率符合标准,已提交答案';
setTimeout(function () {
submitCheckTimes();
escapeBlank()
submitAction()
// setTimeout(function() {
// document.querySelector(".cx_alert-blue").click()
// }, parseInt(1000));
}, parseInt(Math.random() * 2000 + 3000, 10));
} else if (_w.top.unrivalAutoSave == 1) {
_w.top.unrivalWorkInfo = '正确率不符合标准或未设置自动提交,已自动保存答案';
if (Math.floor((totalQuestionNum - questionNum) / totalQuestionNum) >= 0) {
setTimeout(function () {
_w.top.unrivalDoneWorkId = getQueryVariable('workId');
_w.noSubmit();
}, 2000);
}
} else {
_w.top.unrivalWorkInfo = '用户设置为不自动保存答案,请手动提交或保存作业';
}
}, 1000);
} else if (_l.href.includes('work/phone/selectWorkQuestionYiPiYue')) {
_w.top.unrivalWorkDone = true;
_w.top.unrivalDoneWorkId = getQueryVariable('workId');
} else if (_l.href.includes('stat2-ans.chaoxing.com/task/s/index')) {
if (_w.top == _w) {
return;
}
_d.getElementsByClassName('page-container studentStatistic')[0].setAttribute('class', 'studentStatistic');
_d.getElementsByClassName('page-item item-task-list minHeight390')[0].remove();
_d.getElementsByClassName('subNav clearfix')[0].remove();
setInterval(function () {
_l.reload();
}, 90000);
} else if (_l.href.includes('passport2.') && _l.href.includes('login?refer=http') && autoLogin == 1) {
if (!(/^1[3456789]\d{9}$/.test(phoneNumber))) {
alert('自动登录的手机号填写错误,无法登陆')
return;
}
if (password == '') {
alert('未填写登录密码,无法登陆')
return;
}
gmRequest({
method: "get",
url: 'https://passport2-api.chaoxing.com/v11/loginregister?cx_xxt_passport=json&uname=' +
phoneNumber + '&code=' + encodeURIComponent(password),
onload: function (res) {
try {
let ispass = JSON.parse(res.responseText);
if (ispass['status']) {
_l.href = decodeURIComponent(getQueryVariable('refer'));
} else {
alert(ispass['mes']);
}
} catch (err) {
console.log(res.responseText);
alert('登陆失败');
}
},
onerror: function (err) {
alert('登陆错误');
}
});
} else if (_l.href.includes('unrivalxxtbackground')) {
_d.getElementsByTagName("html")[0].innerHTML = `
学习通挂机小助手
`;
var logs = {
"logArry": [],
"addLog": function (str, color = "black") {
if (this.logArry.length >= 50) {
this.logArry.splice(0, 1);
}
var nowTime = new Date(),
nowHour = (Array(2).join(0) + nowTime.getHours()).slice(-2),
nowMin = (Array(2).join(0) + nowTime.getMinutes()).slice(-2),
nowSec = (Array(2).join(0) + nowTime.getSeconds()).slice(-2),
logElement = _d.getElementById('log'),
logStr = "";
this.logArry.push("
[" + nowHour + ":" + nowMin + ":" +
nowSec + "] " + str + "");
for (let logI = 0, logLen = this.logArry.length; logI < logLen; logI++) {
logStr += this.logArry[logI] + "
";
}
_d.getElementById('log').innerHTML = logStr;
logElement.scrollTop = logElement.scrollHeight;
}
};
logs.addLog('此页面不必保持在最前端,后台会自动进行任务', 'green');
setInterval(function () {
logs.addLog('此页面不必保持在最前端,后台会自动进行任务', 'green');
logs.addLog('如想禁用后台刷视频功能,请关闭脚本并重启浏览器', 'blue');
}, 120000)
GM_addValueChangeListener('unrivalxxtbackgroundinfo', function (name, old_value, new_value, remote) {
if (old_value != new_value) {
logs.addLog(new_value);
}
});
setInterval(function () {
if (Math.round(new Date() / 1000) - parseInt(GM_getValue('unrivalBackgroundVideoEnable', '6')) >
15) {
logs.addLog('超星挂机小助手可能运行异常,如页面无反应,请尝试重启脚本或重启浏览器(脚本版本有此问题)');
}
}, 10000);
var loopShow = () => {
let jobList = GM_getValue('unrivalBackgroundList', '1');
if (jobList == '1') {
top.document.getElementById('joblist').innerHTML = '请将"超星挂机小助手"升级到最新版并重启浏览器';
} else {
try {
let jobHtml = '';
for (let i = 0, l = jobList.length; i < l; i++) {
let status = '';
if (jobList[i]['done']) {
status = '已完成';
} else if (parseInt(jobList[i]['playTime']) > 0) {
status = '进行中';
} else {
status = '等待中';
}
if (jobList[i]['review']) {
status += ':复习模式';
}
jobHtml += `
` + '[' + status + ']' + jobList[i]['name'] + `
`
}
top.document.getElementById('joblist').innerHTML = jobHtml;
} catch (e) {
top.document.getElementById('joblist').innerHTML = '请将"超星挂机小助手"升级到最新版并重启浏览器!';
}
}
}
loopShow();
setInterval(loopShow, 10000);
}
// 初始化完成日志g('脚本已加载 v' + GM_info.script.version);
// 使用须知弹窗功能
function showUsageGuide() {
// 检查是否为课程列表页面(只在课程列表页面显示弹窗,不在单个课程的章节目录页面显示)
const isCatalogPage = () => {
const href = _l.href;
const pathname = _l.pathname;
// 排除学习页面和单个课程的章节目录页面
if (href.includes('studentstudy') || href.includes('knowledge/cards')) {
return false;
}
// 排除单个课程的章节目录页面(如:/mooc-ans/course/233047813.html)
if (/\/mooc-ans\/course\/\d+/.test(pathname) || /\/mooc2-ans\/course\/\d+/.test(pathname)) {
return false;
}
// 只匹配真正的课程列表页面URL
const isMatch = href.includes('mycourse/studentcourse') ||
href.includes('mycourse/stu');
return isMatch;
};
if (!isCatalogPage()) {
return;
}
// 检查今日是否已禁用
const getTodayDateString = () => {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const dismissedDate = GM_getValue('usage_guide_dismissed_date', '');
const todayDate = getTodayDateString();
if (dismissedDate === todayDate) {
return;
}
// 创建遮罩层 - 半透明,z-index最高
const overlay = document.createElement('div');
overlay.id = 'usage-guide-overlay';
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
z-index: 2147483646;
display: flex;
align-items: center;
justify-content: center;
`;
// 创建弹窗
const modal = document.createElement('div');
modal.id = 'usage-guide-modal';
modal.style.cssText = `
position: relative;
width: 640px;
max-width: 92vw;
background: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
z-index: 2147483647;
font-family: 'Microsoft YaHei', Arial, sans-serif;
border: 1px solid #e0e0e0;
`;
modal.innerHTML = `
弹窗来自 yyy404 : 超星学习通刷课脚本 v` + GM_info.script.version + `
刷课脚本使用说明
使用方法
●
视频播放:
「任务配置」
里可选两种模式。
真实播放
(默认)
会实际播放视频,由学习通自身上报进度,倍速可选
0.75x~3.0x(步进0.25)
(课程允许时生效)
;
模拟模式
不实际播放,由脚本模拟上报进度,倍速可自由设置。
●
进入
课程章节目录
页面后,脚本自动开始工作。进度与状态请下滑查看
「运行日志」
。
开启倍速不能保证一次性通过。
●
章节测验:脚本会自动切换到章节页的
「章节测验」
标签,在
学习通页面原生答题区
实时勾选填答(
已弃用悬浮窗 workPanel
),过程与结果请查看
「运行日志」
。开启
自动提交
后,仅当答题正确率
高于设定值
才会自动提交,否则需手动提交。开启
随机答题
后,找不到答案的单选、多选、判断会自动选
【C、ABCD、错】
,只在规定正确率
不为 100%
时才生效。
重要提醒
●
遇到问题请先查看
运行日志
,通常能找到解决方案。
开启倍速不能保证一次性通过。
●
如不自动跳转,请检查
「任务配置」
中的跳转模式(
智能 / 遍历 / 不跳转
)。真实播放若未命中视频或遇网络问题,可切换
「模拟模式」
重试。
别熬夜太晚啦 , 注意身体,早点睡,天天开心~~~~~~yyy404
觉得脚本好用的话,可以
赞赏支持
或者给脚本一个
客观评价
哦!
`;
overlay.appendChild(modal);
document.body.appendChild(overlay);
// 绑定事件
setTimeout(() => {
const closeBtn = document.getElementById('usage-guide-close');
const dismissBtn = document.getElementById('usage-guide-dismiss');
if (closeBtn) {
closeBtn.onclick = () => {
overlay.remove();
};
}
if (dismissBtn) {
dismissBtn.onclick = () => {
GM_setValue('usage_guide_dismissed_date', todayDate);
overlay.remove();
};
}
// ESC键关闭
const handleEsc = (e) => {
if (e.key === 'Escape') {
overlay.remove();
document.removeEventListener('keydown', handleEsc);
}
};
document.addEventListener('keydown', handleEsc);
}, 100);
}
setTimeout(showUsageGuide, 500);
})();
// ==================== 阅读助手功能开始 ====================
(function() {
'use strict';
// 全局状态管理(跨页面保持)
window.readingAssistantGlobalState = window.readingAssistantGlobalState || {
isRunning: false,
isPaused: false,
scrollPosition: 0,
manuallyPaused: false,
startTime: 0,
chapterElapsed: 0,
timerInterval: null
};
// 防重复跳转锁
let hasAutoJump = false;
// 配置
const CONFIG = {
scrollSpeed: parseFloat(GM_getValue('scrollSpeed', 1.0)),
scrollMode: GM_getValue('scrollMode', 'pixel'), // paragraph, page, pixel
scrollPixel: parseInt(GM_getValue('scrollPixel', 300)),
autoStart: GM_getValue('autoStart', true),
showTips: GM_getValue('showTips', true),
highlightMode: GM_getValue('highlightMode', false),
loopMode: GM_getValue('loopMode', true), // 循环阅读模式
targetMinutes: parseInt(GM_getValue('readingTargetMinutes', 0), 10) || 0,
showChapterTimer: GM_getValue('readingShowChapterTimer', true) !== false
};
const TASK_ELAPSED_PREFIX = 'readingTaskSec_';
const GOAL_NOTIFIED_PREFIX = 'readingGoalDone_';
const SESSION_TASK_KEY = 'readingAssistantTabTaskKey';
let resolvedReadingTaskKey = null;
// 状态
const STATE = {
get isRunning() { return window.readingAssistantGlobalState.isRunning; },
set isRunning(value) { window.readingAssistantGlobalState.isRunning = value; },
get isPaused() { return window.readingAssistantGlobalState.isPaused; },
set isPaused(value) { window.readingAssistantGlobalState.isPaused = value; },
get currentScrollTop() { return window.readingAssistantGlobalState.scrollPosition; },
set currentScrollTop(value) { window.readingAssistantGlobalState.scrollPosition = value; },
get manuallyPaused() { return window.readingAssistantGlobalState.manuallyPaused; },
set manuallyPaused(value) { window.readingAssistantGlobalState.manuallyPaused = value; },
contentElements: [],
currentIndex: 0,
scrollTimer: null
};
// 日志
function log(msg) {
console.log(`[学习通阅读助手] ${msg}`);
}
// 格式化时间(秒 → 00:00:00)
function formatTime(seconds) {
const h = String(Math.floor(seconds / 3600)).padStart(2, '0');
const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0');
const s = String(seconds % 60).padStart(2, '0');
return `${h}:${m}:${s}`;
}
// 解析 URL 参数(键名小写)
function parseUrlParams(url) {
try {
const u = new URL(url, location.origin);
const p = {};
u.searchParams.forEach(function (v, k) { p[k.toLowerCase()] = v; });
return p;
} catch (e) {
return {};
}
}
function sanitizeTaskKeyPart(s) {
return String(s || '').replace(/[^\w.-]/g, '_').slice(0, 64);
}
function readTabTaskKeyHint() {
try {
return sessionStorage.getItem(SESSION_TASK_KEY) || '';
} catch (e) {
return '';
}
}
function writeTabTaskKeyHint(key) {
try {
if (key) sessionStorage.setItem(SESSION_TASK_KEY, key);
} catch (e) {}
}
// 阅读任务目录页 → 任务键(含 query,区分同课多任务)
function computeCatalogTaskKey(url) {
url = url || location.href;
let path;
try {
path = new URL(url, location.origin).pathname;
} catch (e) {
path = location.pathname;
}
const m = path.match(/\/course\/(\d+)\.html/i);
const params = parseUrlParams(url);
if (m) {
const qIdx = url.indexOf('?');
const q = qIdx >= 0 ? url.slice(qIdx + 1, qIdx + 81) : '';
return 'rd_c' + m[1] + (q ? '_' + sanitizeTaskKeyPart(q) : '');
}
if (path.indexOf('/zt/portal') !== -1) {
return 'rd_p' + sanitizeTaskKeyPart(params.id || params.courseid || params.jobid || path.replace(/\W/g, '_'));
}
const qIdx = url.indexOf('?');
const qs = qIdx >= 0 ? url.slice(qIdx + 1, qIdx + 81) : 'x';
return 'rd_' + sanitizeTaskKeyPart(path.replace(/\W/g, '_')) + '_' + sanitizeTaskKeyPart(qs);
}
function isReadingChapterFlip() {
const ref = document.referrer || '';
return ref.indexOf('/ztnodedetailcontroller/visitnodedetail') !== -1;
}
// 阅读正文页 → 从 URL 算任务键(仅 cardid/cfid,不含章节级参数)
function computeReadingPageTaskKey(url) {
url = url || location.href;
const p = parseUrlParams(url);
const cid = p.courseid || p.coursid || p.clazzid || '';
const taskPart = p.cardid || p.cfid || '';
if (cid && taskPart) {
return 'rd_' + sanitizeTaskKeyPart(cid) + '_' + sanitizeTaskKeyPart(taskPart);
}
if (taskPart) {
return 'rd_t_' + sanitizeTaskKeyPart(taskPart);
}
return '';
}
function computeReadingPageWeakKey(url) {
url = url || location.href;
const qIdx = url.indexOf('?');
const qs = qIdx >= 0 ? url.slice(qIdx + 1) : '';
if (qs) {
return 'rd_q_' + sanitizeTaskKeyPart(qs.slice(0, 120));
}
try {
return 'rd_path_' + sanitizeTaskKeyPart(new URL(url, location.origin).pathname.replace(/\W/g, '_'));
} catch (e) {
return '';
}
}
function resolveReadingPageTaskKey() {
const tabHint = readTabTaskKeyHint();
// 同任务内翻章:沿用本标签已确定的任务键,避免章节 URL 变化导致计时归零
if (tabHint && isReadingChapterFlip()) {
return tabHint;
}
const fromUrl = computeReadingPageTaskKey(location.href);
if (fromUrl) return fromUrl;
if (tabHint) return tabHint;
const ref = document.referrer || '';
if (ref && (ref.indexOf('/mooc-ans/course/') !== -1 || ref.indexOf('/zt/portal') !== -1)) {
return computeCatalogTaskKey(ref);
}
const weak = computeReadingPageWeakKey(location.href);
if (weak) return weak;
return 'rd_unknown_' + sanitizeTaskKeyPart(location.href.slice(-120));
}
// 当前阅读任务键(按任务隔离;阅读页仅用本页 URL / 本标签 sessionStorage)
function getReadingTaskKey() {
if (resolvedReadingTaskKey) return resolvedReadingTaskKey;
if (isReadingTaskPage()) {
resolvedReadingTaskKey = computeCatalogTaskKey(location.href);
writeTabTaskKeyHint(resolvedReadingTaskKey);
return resolvedReadingTaskKey;
}
if (isReadingPage()) {
resolvedReadingTaskKey = resolveReadingPageTaskKey();
writeTabTaskKeyHint(resolvedReadingTaskKey);
return resolvedReadingTaskKey;
}
resolvedReadingTaskKey = 'rd_unknown';
return resolvedReadingTaskKey;
}
function getTaskSavedElapsed() {
return GM_getValue(TASK_ELAPSED_PREFIX + getReadingTaskKey(), 0);
}
function saveTaskSavedElapsed(seconds) {
GM_setValue(TASK_ELAPSED_PREFIX + getReadingTaskKey(), Math.max(0, Math.floor(seconds)));
}
function getTaskDisplayElapsed() {
return getTaskSavedElapsed() + (window.readingAssistantGlobalState.chapterElapsed || 0);
}
function formatTarget(minutes) {
if (!minutes || minutes <= 0) return '无';
return formatTime(minutes * 60);
}
function getGoalStatus() {
const targetMin = CONFIG.targetMinutes;
if (!targetMin || targetMin <= 0) return 'none';
return getTaskDisplayElapsed() >= targetMin * 60 ? 'done' : 'pending';
}
function renderGoalBadge() {
const status = getGoalStatus();
if (status === 'none') return '';
if (status === 'done') {
return '
✓ 已达标';
}
const pct = Math.min(100, Math.floor(getTaskDisplayElapsed() / (CONFIG.targetMinutes * 60) * 100));
return '
✗ 未达标 ' + pct + '%';
}
function ensureReadingTipsStyle() {
if (document.getElementById('reading-tips-style')) return;
const s = document.createElement('style');
s.id = 'reading-tips-style';
s.textContent = [
'.reading-goal-badge{display:inline-block;margin-left:6px;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;vertical-align:middle;}',
'.reading-goal-pending{background:rgba(244,67,54,0.22);color:#ffb4ab;}',
'.reading-goal-ok{background:rgba(76,175,80,0.28);color:#b9f6ca;}',
'.reading-goal-pop{animation:readingGoalPop 0.55s ease;}',
'@keyframes readingGoalPop{0%{transform:scale(1)}45%{transform:scale(1.12)}100%{transform:scale(1)}}'
].join('');
document.head.appendChild(s);
}
function showReadingToast(msg, durationMs) {
durationMs = durationMs || 5000;
let el = document.getElementById('reading-toast');
if (el) el.remove();
el = document.createElement('div');
el.id = 'reading-toast';
el.textContent = msg;
el.style.cssText = 'position:fixed;top:20px;left:50%;transform:translateX(-50%);' +
'background:rgba(40,40,40,0.92);color:#fff;padding:12px 20px;border-radius:8px;' +
'font-size:14px;z-index:10000;max-width:90%;text-align:center;line-height:1.5;';
document.body.appendChild(el);
setTimeout(function () { if (el.parentNode) el.remove(); }, durationMs);
}
function checkReadingGoal() {
if (getGoalStatus() !== 'done') return;
const notifyKey = GOAL_NOTIFIED_PREFIX + getReadingTaskKey();
if (GM_getValue(notifyKey, false)) return;
GM_setValue(notifyKey, true);
log('本任务已达目标时长 ' + CONFIG.targetMinutes + ' 分钟');
const badge = document.getElementById('reading-goal-badge');
if (badge) badge.classList.add('reading-goal-pop');
}
// 本章时长累加到本任务
function flushChapterToTask() {
const ch = window.readingAssistantGlobalState.chapterElapsed || 0;
if (ch > 0) {
saveTaskSavedElapsed(getTaskSavedElapsed() + ch);
window.readingAssistantGlobalState.chapterElapsed = 0;
window.readingAssistantGlobalState.startTime = 0;
}
}
// 启动计时(当前章)
function startTimer() {
if (window.readingAssistantGlobalState.timerInterval) return;
window.readingAssistantGlobalState.startTime = Date.now() - window.readingAssistantGlobalState.chapterElapsed * 1000;
window.readingAssistantGlobalState.timerInterval = setInterval(function () {
window.readingAssistantGlobalState.chapterElapsed = Math.floor((Date.now() - window.readingAssistantGlobalState.startTime) / 1000);
updateTips();
}, 1000);
}
// 停止计时
function stopTimer() {
if (window.readingAssistantGlobalState.timerInterval) {
clearInterval(window.readingAssistantGlobalState.timerInterval);
window.readingAssistantGlobalState.timerInterval = null;
}
}
// 重置当前章时长
function resetChapterTimer() {
stopTimer();
window.readingAssistantGlobalState.chapterElapsed = 0;
window.readingAssistantGlobalState.startTime = 0;
}
// R 键:重置当前阅读任务计时
function resetTaskTimer() {
const taskKey = getReadingTaskKey();
saveTaskSavedElapsed(0);
GM_setValue(GOAL_NOTIFIED_PREFIX + taskKey, false);
resetChapterTimer();
updateTips();
log('本任务阅读时长已重置');
showReadingToast('本任务阅读时长已重置');
}
// 更新提示栏(本任务 + 目标 + 本章)
function updateTips() {
const tips = document.getElementById('reading-tips');
if (!tips) return;
const taskSec = getTaskDisplayElapsed();
const chapter = window.readingAssistantGlobalState.chapterElapsed;
let line2 = '本任务 ' + formatTime(taskSec) + ' / ' + formatTarget(CONFIG.targetMinutes);
if (CONFIG.showChapterTimer) {
line2 += ' · 本章 ' + formatTime(chapter);
}
line2 += renderGoalBadge();
tips.innerHTML = 'K: 开始 | Z: 暂停 | S: 设置 | R: 重置本任务
' + line2;
checkReadingGoal();
}
// 页面检测(兼容新旧目录页)
function isReadingTaskPage() {
return (location.href.includes('/mooc-ans/course/') && location.href.includes('.html')) //感谢用户:ᦸᐝSᴗhi꧂的反馈
|| location.href.includes('/mooc-ans/zt/portal/');
}
function isReadingPage() {
return location.href.includes('/ztnodedetailcontroller/visitnodedetail');
}
// 自动跳转到阅读页面
function autoJumpToReading() {
if (hasAutoJump) return;
if (!isReadingTaskPage()) return;
getReadingTaskKey();
log('检测到阅读任务目录页面,准备跳转');
const observer = new MutationObserver(() => {
const readingLink = document.querySelector(
'a[href*="/ztnodedetailcontroller/visitnodedetail"],.catalog_detail a,.chapter_item a,.nodeItem a,.posCatalog_name a'
); //感谢用户:ᦸᐝSᴗhi꧂的反馈
if (readingLink) {
log('找到阅读章节,正在跳转');
readingLink.click();
hasAutoJump = true;
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// 收集内容元素
function collectContent() {
const selectors = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img', 'video'];
STATE.contentElements = [];
selectors.forEach(selector => {
document.querySelectorAll(selector).forEach(el => {
if (el.offsetHeight > 20 && el.offsetWidth > 20) {
STATE.contentElements.push(el);
}
});
});
STATE.contentElements.sort((a, b) =>
a.getBoundingClientRect().top - b.getBoundingClientRect().top
);
log(`找到 ${STATE.contentElements.length} 个内容元素`);
}
// 清除高亮
function clearHighlight() {
document.querySelectorAll('.reading-highlight').forEach(el => {
el.classList.remove('reading-highlight');
el.style.outline = '';
});
}
// 段落阅读
function scrollToNext() {
if (STATE.isPaused || STATE.currentIndex >= STATE.contentElements.length) {
completeReading();
return;
}
const element = STATE.contentElements[STATE.currentIndex];
if (CONFIG.highlightMode) {
clearHighlight();
element.classList.add('reading-highlight');
element.style.outline = '4px solid #00FF00';
element.style.transition = 'outline 0.3s ease';
}
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
STATE.currentIndex++;
const randomSpeed = CONFIG.scrollSpeed * (0.9 + Math.random() * 0.3);
STATE.scrollTimer = setTimeout(scrollToNext, randomSpeed * 1000);
}
// 整页阅读
function pageScroll() {
const totalHeight = document.documentElement.scrollHeight - window.innerHeight - 50;
const scrollStep = totalHeight / (CONFIG.scrollSpeed * 10);
if (!STATE.currentScrollTop) {
STATE.currentScrollTop = 0;
}
const scroll = () => {
if (STATE.isPaused) return;
STATE.currentScrollTop += scrollStep;
if (STATE.currentScrollTop >= totalHeight) {
completeReading();
} else {
window.scrollTo({ top: STATE.currentScrollTop, behavior: 'smooth' });
STATE.scrollTimer = setTimeout(scroll, 100);
}
};
scroll();
}
// 像素滚动
function pixelScroll() {
const totalHeight = document.documentElement.scrollHeight - window.innerHeight - 50;
if (!STATE.currentScrollTop) {
STATE.currentScrollTop = window.pageYOffset || document.documentElement.scrollTop;
}
const scroll = () => {
if (STATE.isPaused) return;
STATE.currentScrollTop += CONFIG.scrollPixel;
if (STATE.currentScrollTop >= totalHeight) {
completeReading();
} else {
window.scrollTo({ top: STATE.currentScrollTop, behavior: 'smooth' });
STATE.scrollTimer = setTimeout(scroll, CONFIG.scrollSpeed * 1000);
}
};
scroll();
}
// 完成阅读
function completeReading() {
STATE.isRunning = false;
STATE.isPaused = false;
clearHighlight();
clearTimeout(STATE.scrollTimer);
flushChapterToTask();
resetChapterTimer();
log('阅读完成');
setTimeout(() => {
const nextBtn = document.querySelector('.nodeItem.r i') ||
document.querySelector('a[title="下一章"]') ||
document.querySelector('.next_btn') ||
document.querySelector('.nextBtn') ||
Array.from(document.querySelectorAll('*')).find(el =>
el.textContent && (el.textContent.includes('下一章') || el.textContent.includes('下一节'))
);
if (nextBtn) {
log('找到下一章按钮,正在跳转');
nextBtn.click();
} else if (CONFIG.loopMode) {
log('未找到下一章按钮,循环模式开启,准备跳转到第一章');
setTimeout(() => {
jumpToFirstChapter();
}, 1000);
} else {
log('未找到下一章按钮,阅读结束');
}
}, 2000);
}
// 跳转到第一章
function jumpToFirstChapter() {
log('开始寻找第一章...');
const firstChapterSelectors = [
'.posCatalog_select:first-child a',
'.posCatalog_name:first-child a',
'.catalog_points_yi:first-child a',
'.catalog_title:first-child a',
'.nodeItem:first-child a',
'.catalogDetail:first-child a',
'.catalog_sectionLevel1:first-child a',
'a[href*="/ztnodedetailcontroller/visitnodedetail"]'
];
let firstChapterLink = null;
for (const selector of firstChapterSelectors) {
const links = document.querySelectorAll(selector);
if (links.length > 0) {
firstChapterLink = links[0];
log(`通过选择器 ${selector} 找到第一章链接`);
break;
}
}
if (firstChapterLink) {
log('找到第一章链接,正在跳转...');
firstChapterLink.click();
return;
}
log('尝试返回上级页面...');
if (window.history.length > 1) {
window.history.back();
} else {
const currentUrl = location.href;
const urlParts = currentUrl.split('/');
if (urlParts.length > 3) {
const rootUrl = urlParts.slice(0, 4).join('/');
log(`跳转到根目录: ${rootUrl}`);
location.href = rootUrl;
}
}
}
// 开始阅读
function startReading() {
if (STATE.scrollTimer) clearTimeout(STATE.scrollTimer);
if (STATE.isRunning) return;
startTimer();
STATE.isRunning = true;
STATE.isPaused = false;
STATE.currentIndex = 0;
log(`开始${CONFIG.scrollMode}阅读`);
switch(CONFIG.scrollMode) {
case 'paragraph':
collectContent();
if (STATE.contentElements.length > 0) {
scrollToNext();
} else {
log('未找到段落内容,切换整页模式');
pageScroll();
}
break;
case 'page':
pageScroll();
break;
case 'pixel':
pixelScroll();
break;
}
}
// 暂停阅读
function pauseReading() {
if (STATE.isRunning) {
stopTimer();
STATE.isPaused = true;
STATE.manuallyPaused = true;
GM_setValue('manuallyPaused', true);
clearTimeout(STATE.scrollTimer);
log('阅读已暂停');
}
}
// 继续阅读
function resumeReading() {
if (!STATE.isRunning) {
STATE.manuallyPaused = false;
GM_setValue('manuallyPaused', false);
startTimer();
startReading();
} else {
STATE.isPaused = false;
STATE.manuallyPaused = false;
GM_setValue('manuallyPaused', false);
startTimer();
log('继续阅读');
switch(CONFIG.scrollMode) {
case 'paragraph':
scrollToNext();
break;
case 'page':
pageScroll();
break;
case 'pixel':
pixelScroll();
break;
}
}
}
// 停止阅读
function stopReading() {
STATE.isRunning = false;
STATE.isPaused = false;
STATE.manuallyPaused = false;
clearTimeout(STATE.scrollTimer);
clearHighlight();
flushChapterToTask();
resetChapterTimer();
log('阅读已停止');
}
// 显示阅读器设置面板
function showSettings() {
const existingModal = document.getElementById('reading-settings-modal');
if (existingModal) {
existingModal.remove();
return;
}
const modal = document.createElement('div');
modal.id = 'reading-settings-modal';
modal.style.cssText = `
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: white; padding: 20px; border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3); z-index: 9999;
font-family: Arial, sans-serif; min-width: 320px;
border: 1px solid #ddd;
`;
modal.innerHTML = `
阅读器设置
0 = 不提醒
小猫 or 小狗
计时按墙钟统计;最小化一般仍继续,自动滚动可能变慢;与学习通平台记录可能不一致
`;
document.body.appendChild(modal);
document.getElementById('mode').onchange = function() {
const pixelSetting = document.getElementById('pixelSetting');
pixelSetting.style.display = this.value === 'pixel' ? 'block' : 'none';
};
document.getElementById('save').onclick = () => {
CONFIG.scrollSpeed = parseFloat(document.getElementById('speed').value);
CONFIG.scrollMode = document.getElementById('mode').value;
CONFIG.scrollPixel = parseInt(document.getElementById('pixel').value);
CONFIG.autoStart = document.getElementById('autoStart').checked;
CONFIG.showTips = document.getElementById('showTips').checked;
CONFIG.highlightMode = document.getElementById('highlightMode').checked;
CONFIG.loopMode = document.getElementById('loopMode').checked;
CONFIG.targetMinutes = Math.max(0, parseInt(document.getElementById('targetMinutes').value, 10) || 0);
CONFIG.showChapterTimer = document.getElementById('showChapterTimer').checked;
GM_setValue('scrollSpeed', CONFIG.scrollSpeed);
GM_setValue('scrollMode', CONFIG.scrollMode);
GM_setValue('scrollPixel', CONFIG.scrollPixel);
GM_setValue('autoStart', CONFIG.autoStart);
GM_setValue('showTips', CONFIG.showTips);
GM_setValue('highlightMode', CONFIG.highlightMode);
GM_setValue('loopMode', CONFIG.loopMode);
GM_setValue('readingTargetMinutes', CONFIG.targetMinutes);
GM_setValue('readingShowChapterTimer', CONFIG.showChapterTimer);
if (CONFIG.targetMinutes > 0) {
GM_setValue(GOAL_NOTIFIED_PREFIX + getReadingTaskKey(), false);
}
modal.remove();
log('设置已保存');
if (isReadingPage()) {
const oldTips = document.getElementById('reading-tips');
if (oldTips) oldTips.remove();
showTips();
}
};
document.getElementById('close').onclick = () => {
modal.remove();
};
}
// 显示快捷键提示
function showTips() {
if (!CONFIG.showTips || !isReadingPage()) return;
ensureReadingTipsStyle();
const existingTips = document.getElementById('reading-tips');
if (existingTips) existingTips.remove();
const tips = document.createElement('div');
tips.id = 'reading-tips';
tips.style.cssText = `
position: fixed; bottom: 10px; right: 10px;
background: rgba(0,0,0,0.7); color: white; padding: 10px;
border-radius: 6px; font-size: 12px; z-index: 9998;
font-family: Arial, sans-serif;
`;
document.body.appendChild(tips);
updateTips();
}
// 键盘事件
function bindKeys() {
if (window.readingAssistantKeysbound) return;
document.addEventListener('keydown', (e) => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
switch(e.key.toLowerCase()) {
case 'k':
e.preventDefault();
resumeReading();
break;
case 'z':
e.preventDefault();
pauseReading();
break;
case 's':
e.preventDefault();
showSettings();
break;
case 'r':
e.preventDefault();
resetTaskTimer();
break;
}
});
window.readingAssistantKeysbound = true;
}
// 初始化
function init() {
bindKeys();
if (isReadingTaskPage()) {
autoJumpToReading();
} else if (isReadingPage()) {
getReadingTaskKey();
if (CONFIG.scrollMode === 'pixel' && window.readingAssistantInitialized) {
showTips();
return;
}
showTips();
const wasManuallyPaused = GM_getValue('manuallyPaused', false);
if (CONFIG.autoStart && !wasManuallyPaused) {
setTimeout(startReading, 2000);
} else if (wasManuallyPaused) {
log('检测到手动暂停状态,不自动开始阅读');
}
window.readingAssistantInitialized = true;
}
}
// 启动
init();
window.__xxtStopReading = stopReading;
})();
// ==================== 阅读助手功能结束 ====================
// ==================== 由衷感谢iPycc ====================
(function() {
'use strict';
// 安全解析 Table 资源,支持回退到 SourceTable
const safeParseTable = () => {
const tryRead = (key) => {
try {
const text = GM_getResourceText && GM_getResourceText(key);
if (text) return JSON.parse(text);
} catch (e) {
console.warn(`加载${key}资源失败`, e);
}
return null;
};
return tryRead('Table') || tryRead('SourceTable');
};
const ChaoxingHelper = {
// 复制 (字体解密及替换)
copyEnabler: {
decrypt(retryCount = 0) {
// 检查 Typr 和 md5 是否加载
if (typeof Typr === 'undefined' || typeof md5 === 'undefined') {
if (retryCount < 5) {
setTimeout(() => this.decrypt(retryCount + 1), 500);
return;
}
console.warn('[Chaoxing Helper] Typr 或 md5 未加载,放弃解密');
return;
}
const styleElement = this.findStyleContaining('font-cxsecret');
if (!styleElement) {
if (retryCount < 5) {
setTimeout(() => this.decrypt(retryCount + 1), 500);
return;
}
return;
}
// 支持单引号和双引号
const fontMatch = styleElement.textContent.match(/base64,([\w\W]+?)["']/);
if (!fontMatch) return;
try {
const fontData = Typr.parse(this.base64ToUint8Array(fontMatch[1]))?.[0];
const table = safeParseTable();
if (!fontData || !table) {
if (retryCount < 3) {
setTimeout(() => this.decrypt(retryCount + 1), 500);
return;
}
return;
}
const charMap = this.createCharMap(fontData, table);
this.replaceEncryptedText(charMap);
console.log(`[Chaoxing Helper] Decryption completed ${Object.keys(charMap).length} characters`);
} catch (e) {
console.warn('[Chaoxing Helper] 解密过程出错:', e);
}
},
watch() {
// 监听样式和字体类的出现,出现后尝试解密
const tryOnce = () => this.decrypt();
const styleObserver = new MutationObserver(() => tryOnce());
const bodyObserver = new MutationObserver(() => tryOnce());
try {
styleObserver.observe(document.head || document.documentElement, { childList: true, subtree: true });
bodyObserver.observe(document.body || document.documentElement, { childList: true, subtree: true });
} catch (e) {
// ignore
}
// 首次尝试
tryOnce();
},
findStyleContaining(text) {
const styles = document.querySelectorAll('style');
return Array.from(styles).find(style =>
style.textContent.includes(text)
);
},
base64ToUint8Array(base64) {
const data = window.atob(base64);
return new Uint8Array([...data].map(char => char.charCodeAt(0)));
},
createCharMap(font, table) {
const charMap = {};
for (let i = 19968; i < 40870; i++) {
const glyph = Typr.U.codeToGlyph(font, i);
if (!glyph) continue;
const path = Typr.U.glyphToPath(font, glyph);
const pathHash = md5(JSON.stringify(path)).slice(24);
if (table[pathHash]) {
charMap[String.fromCharCode(i)] = String.fromCharCode(table[pathHash]);
}
}
return charMap;
},
replaceEncryptedText(charMap) {
const elements = document.querySelectorAll('.font-cxsecret');
elements.forEach(element => {
let html = element.innerHTML;
Object.entries(charMap).forEach(([encrypted, decrypted]) => {
html = html.replace(new RegExp(encrypted, 'g'), decrypted);
});
element.innerHTML = html;
element.classList.remove('font-cxsecret');
});
}
},
// 粘贴 (强制启用粘贴功能)
pasteEnabler: {
init() {
this.removeGlobalRestrictions();
this.injectGlobalStyles();
this.enableExistingElements();
this.startMutationObserver();
this.monitorUEditor();
},
removeGlobalRestrictions() {
['paste', 'contextmenu', 'selectstart', 'dragstart', 'copy', 'cut', 'keydown']
.forEach(event => document[`on${event}`] = null);
this.removeElementRestrictions(document.body);
},
injectGlobalStyles() {
const style = document.createElement('style');
style.textContent = `
* {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
}
input, textarea, [contenteditable] {
user-select: text !important;
pointer-events: auto !important;
}
`;
document.head.appendChild(style);
},
removeElementRestrictions(element) {
if (!element) return;
// 移除事件监听器和属性
['paste', 'contextmenu', 'keydown', 'selectstart', 'dragstart', 'copy', 'cut']
.forEach(event => {
element[`on${event}`] = null;
element.removeAttribute(`on${event}`);
});
element.removeAttribute('readonly');
element.removeAttribute('disabled');
// 恢复样式
Object.assign(element.style, {
userSelect: 'text',
webkitUserSelect: 'text',
mozUserSelect: 'text',
msUserSelect: 'text',
pointerEvents: 'auto'
});
},
enableExistingElements() {
document.querySelectorAll('input, textarea, [contenteditable]')
.forEach(el => this.removeElementRestrictions(el));
},
startMutationObserver() {
new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType !== 1) return;
if (node.matches?.('input, textarea, [contenteditable]')) {
this.removeElementRestrictions(node);
}
if (node.tagName === 'IFRAME') {
setTimeout(() => {
try {
node.contentDocument?.querySelectorAll('input, textarea, [contenteditable]')
.forEach(el => this.removeElementRestrictions(el));
} catch (e) {
// 跨域iframe,静默处理
}
}, 500);
}
node.querySelectorAll?.('input, textarea, [contenteditable]')
.forEach(el => this.removeElementRestrictions(el));
});
});
}).observe(document.body, { childList: true, subtree: true });
},
handlePaste(e) {
e.preventDefault();
e.stopPropagation();
const doc = e.target.ownerDocument || document;
const clipboardData = e.clipboardData || window.clipboardData;
// 处理图片粘贴
const imageItem = Array.from(clipboardData?.items || [])
.find(item => item.type?.startsWith('image/'));
if (imageItem) {
const imageFile = imageItem.getAsFile();
const reader = new FileReader();
reader.onload = () => this.insertImage(doc, reader.result);
reader.readAsDataURL(imageFile);
return;
}
// 处理文本粘贴
const text = clipboardData?.getData?.('text/plain') ||
window.clipboardData?.getData?.('Text') || '';
if (text) {
this.insertText(doc, text);
}
},
insertImage(doc, dataUrl) {
const img = doc.createElement('img');
img.src = dataUrl;
img.alt = '粘贴图片';
const selection = doc.getSelection();
if (selection?.rangeCount > 0) {
const range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(img);
range.setStartAfter(img);
selection.removeAllRanges();
selection.addRange(range);
} else {
doc.body?.appendChild(img);
}
},
insertText(doc, text) {
if (doc.execCommand?.('insertText', false, text)) return true;
const selection = doc.getSelection();
if (selection?.rangeCount > 0) {
const range = selection.getRangeAt(0);
range.deleteContents();
const textNode = doc.createTextNode(text);
range.insertNode(textNode);
range.setStartAfter(textNode);
selection.removeAllRanges();
selection.addRange(range);
return true;
}
doc.body?.appendChild(doc.createTextNode(text));
return false;
},
monitorUEditor() {
let attempts = 0;
const maxAttempts = 20;
const checkUEditor = () => {
attempts++;
// 处理主窗口UEditor实例
if (typeof UE !== 'undefined' && UE.instants) {
Object.values(UE.instants).forEach(instance => {
this.processUEditorInstance(instance);
});
}
// 处理iframe中的UEditor实例
document.querySelectorAll('iframe').forEach(iframe => {
try {
const iframeWindow = iframe.contentWindow;
if (iframeWindow?.UE?.instants) {
Object.values(iframeWindow.UE.instants).forEach(instance => {
this.processUEditorInstance(instance);
});
}
} catch (error) {
// 跨域iframe,静默处理
}
});
if (attempts < maxAttempts) setTimeout(checkUEditor, 500);
};
checkUEditor();
},
processUEditorInstance(instance) {
if (!instance || typeof instance !== 'object') return;
// 启用编辑器
if (instance.options) {
instance.options.pasteplain = true;
instance.options.readonly = false;
instance.options.disabled = false;
}
if (instance.setEnabled && instance.body) {
instance.setEnabled(true);
}
// 处理编辑器主体
if (instance.body && !instance.body.__cxPasteEnabled) {
this.removeElementRestrictions(instance.body);
instance.body.addEventListener('paste', (e) => this.handlePaste(e), true);
instance.body.__cxPasteEnabled = true;
}
// 处理iframe文档
const iframeDoc = instance.iframe?.contentDocument;
if (iframeDoc && !iframeDoc.__cxPasteEnabled) {
this.removeElementRestrictions(iframeDoc.body);
iframeDoc.addEventListener('paste', (e) => this.handlePaste(e), true);
iframeDoc.__cxPasteEnabled = true;
}
}
},
// 一键复制所有题目
copyAllQuestion: {
MESSAGE: { REQUEST: 'CX_GET_TITLES', RESPONSE: 'CX_TITLES_RESPONSE' },
init() {
// 跨页面消息监听(子 iframe 也会加载本脚本)
this.setupMessageHandler();
// 顶层页面插入复制按钮
this.insertCopyButton();
// 注入模态框
this.injectModal();
},
// 注入模态框的HTML和CSS
injectModal() {
const modalHtml = `
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
// 获取模态框元素
const modalOverlay = document.getElementById('cx-copy-modal-overlay');
const textarea = document.getElementById('cx-copy-modal-textarea');
const cancelButton = document.getElementById('cx-copy-modal-cancel');
const copyButton = document.getElementById('cx-copy-modal-copy');
// 取消按钮事件
cancelButton.addEventListener('click', () => {
modalOverlay.style.display = 'none';
});
// 复制按钮事件
copyButton.addEventListener('click', async () => {
try {
await this.copyToClipboard(textarea.value);
this.toast('已复制题目内容');
modalOverlay.style.display = 'none';
} catch (e) {
this.toast('复制失败,请重试');
}
});
// 点击遮罩层关闭模态框
modalOverlay.addEventListener('click', (e) => {
if (e.target === modalOverlay) {
modalOverlay.style.display = 'none';
}
});
},
// 显示模态框并填充内容
showModal(content) {
const modalOverlay = document.getElementById('cx-copy-modal-overlay');
const textarea = document.getElementById('cx-copy-modal-textarea');
if (modalOverlay && textarea) {
textarea.value = content;
modalOverlay.style.display = 'flex';
}
},
setupMessageHandler() {
window.addEventListener('message', (event) => {
try {
const data = event.data || {};
if (data?.type !== this.MESSAGE.REQUEST || !data.id) return;
// 只响应超星域名消息
const host = new URL(event.origin).hostname || '';
if (!/chaoxing\.com$/.test(host)) return;
const titles = this.extractTitlesFromDocument(document); // 兼容旧协议
const questions = this.extractQuestionsFromDocument(document);
const header = this.findHeaderTitle(document) || document.title || '';
event.source?.postMessage({
type: this.MESSAGE.RESPONSE,
id: data.id,
titles, // 兼容旧协议
questions,
header
}, event.origin);
} catch (err) {
// 忽略跨域或解析错误
}
}, false);
},
insertCopyButton() {
const h2s = Array.from(document.querySelectorAll('h2'));
const anchor = h2s.find(h => h.textContent?.trim()?.includes('章节详情'));
if (!anchor) return;
if (document.getElementById('__cx_copy_all_btn')) return;
const btn = document.createElement('button');
btn.id = '__cx_copy_all_btn';
btn.textContent = '点击复制所有题目';
btn.setAttribute('type', 'button');
btn.style.cssText = [
'position: sticky',
'top: 8px',
'margin: 8px 0',
'padding: 6px 12px',
'background: #1677ff',
'color: #fff',
'border: none',
'border-radius: 4px',
'font-size: 14px',
'cursor: pointer',
'z-index: 9999'
].join(';');
btn.addEventListener('click', async () => {
try {
const content = await this.collectAllTitles();
this.showModal(content); // 显示模态框而不是直接复制
} catch (e) {
this.toast('收集题目失败,请重试');
}
});
anchor.insertAdjacentElement('afterend', btn);
},
// 汇总顶层及所有 iframe 的题目
async collectAllTitles() {
const sections = await this.collectTitlesFromDocument(document);
const lines = [];
sections.forEach(({ header, questions }) => {
if (questions?.length) {
if (header) {
lines.push(`# ${header}`);
lines.push('');
}
questions.forEach((q, idx) => {
const titleLine = `${idx + 1}. ${q.title}`;
lines.push(titleLine);
if (Array.isArray(q.options) && q.options.length) {
q.options.forEach(opt => lines.push(opt));
}
lines.push('');
});
}
});
return lines.join('\n');
},
// 递归采集指定文档内所有题目(含嵌套 iframe)
async collectTitlesFromDocument(doc) {
const sections = [];
const header = this.findHeaderTitle(doc) || doc.title || '';
const questions = this.extractQuestionsFromDocument(doc);
if (questions.length) sections.push({ header, questions });
const frames = Array.from(doc.querySelectorAll('iframe'));
for (const frame of frames) {
try {
const fdoc = frame.contentDocument;
if (fdoc) {
const childSections = await this.collectTitlesFromDocument(fdoc);
sections.push(...childSections);
} else {
const res = await this.collectFromFrame(frame);
if (res?.questions?.length) sections.push(res);
}
} catch (_) {
const res = await this.collectFromFrame(frame);
if (res?.questions?.length) sections.push(res);
}
}
return sections;
},
collectFromFrame(frame) {
// 优先同源直接采集
try {
const doc = frame.contentDocument;
if (doc) {
const questions = this.extractQuestionsFromDocument(doc);
const header = this.findHeaderTitle(doc) || doc.title || '';
return Promise.resolve({ header, questions });
}
} catch (_) {
// frame
}
// 跨域使用 postMessage 请求
const id = Math.random().toString(36).slice(2);
return new Promise((resolve) => {
const onMessage = (event) => {
const data = event.data || {};
if (data?.type === this.MESSAGE.RESPONSE && data.id === id) {
window.removeEventListener('message', onMessage);
const questions = Array.isArray(data.questions) ? data.questions : (data.titles || []).map(t => ({ title: t, options: [], type: 'other' }));
resolve({ header: data.header || '', questions });
}
};
window.addEventListener('message', onMessage);
// 超时保护
const timer = setTimeout(() => {
window.removeEventListener('message', onMessage);
resolve({ header: '', titles: [] });
}, 3000);
try {
frame.contentWindow?.postMessage({ type: this.MESSAGE.REQUEST, id }, '*');
} catch (e) {
clearTimeout(timer);
window.removeEventListener('message', onMessage);
resolve({ header: '', titles: [] });
}
});
},
extractTitlesFromDocument(doc) {
// 覆盖更多页面结构(老版/新版、题目容器、TiMu 包裹等)
const primarySelectors = [
'.Zy_TItle .fontLabel',
'.Zy_Title .fontLabel',
'.newZy_TItle .fontLabel',
'.newZy_Title .fontLabel',
'.TiMu .Zy_TItle .fontLabel',
'.TiMu .Zy_Title .fontLabel',
'[class*="Zy_"][class*="TItle"] .fontLabel',
'[class*="Zy_"][class*="Title"] .fontLabel'
];
const fallbackSelectors = [
'.Zy_TItle',
'.Zy_Title',
'.newZy_TItle',
'.newZy_Title',
'.TiMu .Zy_TItle',
'.TiMu .Zy_Title'
];
const set = new Set();
// 先从 fontLabel(解密字体)中提取
primarySelectors.forEach(sel => {
doc.querySelectorAll(sel).forEach(n => {
const text = (n.textContent || '').replace(/\s+/g, ' ').trim();
if (text) set.add(text);
});
});
// 若未命中,则退回到题目容器本身文本
if (set.size === 0) {
fallbackSelectors.forEach(sel => {
doc.querySelectorAll(sel).forEach(n => {
const text = (n.textContent || '').replace(/\s+/g, ' ').trim();
if (text) set.add(text);
});
});
}
return Array.from(set);
},
// 提取选择题与简答题为结构化数据
extractQuestionsFromDocument(doc) {
const questions = [];
const containers = Array.from(doc.querySelectorAll('.TiMu'));
const getTitleFrom = (root) => {
const titleNode = root.querySelector('.Zy_TItle .fontLabel, .Zy_Title .fontLabel, .newZy_TItle .fontLabel, .newZy_Title .fontLabel')
|| root.querySelector('.Zy_TItle, .Zy_Title, .newZy_TItle, .newZy_Title');
return (titleNode?.textContent || '').replace(/\s+/g, ' ').trim();
};
if (containers.length > 0) {
containers.forEach(box => {
const title = getTitleFrom(box);
if (!title) return;
const ul = box.querySelector('ul.Zy_ulTop.w-top.fl');
const lis = ul ? Array.from(ul.querySelectorAll(':scope > li')) : [];
const options = lis.map((li, idx) => {
const p = li.querySelector('p') || li.querySelector('a') || li;
const text = (p?.textContent || '').replace(/\s+/g, ' ').trim();
const letter = String.fromCharCode(65 + idx); // A,B,C...
return `${letter}. ${text}`;
}).filter(Boolean);
let type = 'other';
if (options.length === 4) type = 'single';
else if (options.length >= 5) type = 'multi';
questions.push({ title, options, type });
});
}
// 若无 TiMu 容器,退回到标题列表作为简答题/其他题
if (questions.length === 0) {
const titles = this.extractTitlesFromDocument(doc);
titles.forEach(t => questions.push({ title: t, options: [], type: 'other' }));
}
return questions;
},
findHeaderTitle(doc) {
// 子页面:作业标题常在 .ceyan_name h3 或 .newTestTitle
const h3 = doc.querySelector('.ceyan_name h3');
if (h3?.textContent) return h3.textContent.trim();
const testName = doc.querySelector('.newTestTitle .TestTitle_name');
if (testName?.textContent) return testName.textContent.trim();
// 顶层列表页面:寻找"章节详情"
const h2 = Array.from(doc.querySelectorAll('h2')).find(h => h.textContent?.includes('章节详情'));
if (h2?.textContent) return h2.textContent.trim();
return '';
},
async copyToClipboard(text) {
try {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(text);
return true;
}
} catch (_) {
//copy not success
}
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.top = '-9999px';
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); } catch (_) {
// copy
}
document.body.removeChild(ta);
return true;
},
toast(msg) {
try {
const el = document.createElement('div');
el.textContent = msg;
el.style.cssText = [
'position: fixed',
'left: 50%','top: 24px','transform: translateX(-50%)',
'background: rgba(0,0,0,0.75)',
'color: #fff','padding: 8px 12px','border-radius: 4px',
'font-size: 13px','z-index: 10000'
].join(';');
document.body.appendChild(el);
setTimeout(() => el.remove(), 1500);
} catch (_) {
// msg
}
}
},
// 主初始化
init() {
try {
this.pasteEnabler.init();
} catch (e) {
console.error('[Chaoxing Helper] pasteEnabler 初始化失败:', e);
}
try {
this.copyEnabler.watch();
} catch (e) {
console.error('[Chaoxing Helper] copyEnabler 初始化失败:', e);
}
try {
this.copyAllQuestion.init();
} catch (e) {
console.error('[Chaoxing Helper] copyAllQuestion 初始化失败:', e);
}
console.log('[Chaoxing Helper] Done');
}
};
// 启动 - 确保在 DOM 加载后执行
const start = () => {
if (!document || document.__cxHelperStarted) return;
document.__cxHelperStarted = true;
ChaoxingHelper.init();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
// 如果 DOM 已经加载完成,延迟一点执行以确保所有资源都已加载
setTimeout(start, 100);
}
})();
// ==================== 由衷感谢iPycc ====================