// ==UserScript==
// @name 专注学习通、国开、智慧树、U校园助手-免费高分题库
// @version 1.0
// @authon wangyiyi
// @description 想要学习通关更轻松?试试这款“零干扰”的学习通助手!它不仅能自动搞定视频、作业和考试,更采用先进的后台任务技术,完全不占用您的网络宽带。无论是刷剧还是打游戏,它都在后台默默为您“打工”。配合免费的高分题库和看得见的实时进度条,让每一次学习都高效又省心。QQ在线客服1:3319450748 在线客服2:3885512520
// @match *://*.chaoxing.com/*
// @match *://*.edu.cn/*
// @match *://*.nbdlib.cn/*
// @connect azkou.cn
// @connect localhost
// @connect 127.0.0.1
// @grant GM_getTab
// @grant GM_saveTab
// @run-at document-end
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_info
// @grant GM_getResourceText
// @grant GM_openInTab
// @grant GM_deleteValue
// @grant GM_notification
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @icon http://pan-yz.chaoxing.com/favicon.ico
// @original-script https://scriptcat.org/zh-CN/script-show-page/6033
// @require https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js
// @require https://cdn.bootcdn.net/ajax/libs/limonte-sweetalert2/11.1.0/sweetalert2.all.min.js
// @require https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.19.0/js/md5.min.js
// @license MIT
// @run-at document-start
// @antifeature payment 可使用web付费脚本平台进行播放、考试、题库
// ==/UserScript==
const floatingWindow = document.createElement('div');
floatingWindow.id = 'baidu-floating-window';
floatingWindow.style.cssText = `
position: fixed;
z-index: 9999;
background-color: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
width: 300px;
height: 500px;
left: 20px;
top: 20px;
font-family: 'Microsoft YaHei', sans-serif;
overflow: hidden;
display: flex;
flex-direction: column;
`;
const titleBar = document.createElement('div');
titleBar.style.cssText = `
padding: 12px 15px;
background-color: #f5f5f5;
border-bottom: 1px solid #e0e0e0;
cursor: move;
display: flex;
justify-content: space-between;
align-items: center;
user-select: none;
flex-shrink: 0;
`;
const titleBar12 = document.createElement('div');
titleBar12.style.cssText = `
padding: 12px 15px;
background-color: #f5f5f5;
border-bottom: 1px solid #e0e0e0;
cursor: move;
display: flex;
justify-content: space-between;
align-items: center;
user-select: none;
flex-shrink: 0;
`;
const title = document.createElement('h3');
title.textContent = '青禾院-轻量版V 2.0';
title.style.cssText = `
margin: 0;
font-size: 15px;
color: #333;
font-weight: normal;
`;
const closeBtn = document.createElement('span');
closeBtn.textContent = '×';
closeBtn.style.cssText = `
font-size: 20px;
cursor: pointer;
color: #999;
line-height: 1;
padding: 0 5px;
`;
//
const navBar = document.createElement('div');
navBar.style.cssText = `
display: flex;
border-bottom: 1px solid #f0f0f0;
background-color: #fafafa;
flex-shrink: 0;
`;
//
const navBar22 = document.createElement('div');
navBar22.style.cssText = `
display: flex;
border-bottom: 1px solid #f0f0f0;
background-color: #fafafa;
flex-shrink: 0;
`;
//
const createNavButton = (text, onClick) => {
const btn = document.createElement('button');
btn.textContent = text;
btn.style.cssText = `
flex: 1;
padding: 12px 0;
background: none;
border: none;
cursor: pointer;
font-size: 14px;
color: #666;
transition: all 0.3s;
position: relative;
`;
btn.addEventListener('click', onClick);
return btn;
};
const homeBtn = createNavButton('首页', () => {
homeContent.style.display = 'block';
settingsContent.style.display = 'none';
questionBankContent.style.display = 'none';
myContent.style.display = 'none';
description.style.display = 'block';
playButton.style.display = 'none';
});
const settingsBtn = createNavButton('设置', () => {
homeContent.style.display = 'none';
settingsContent.style.display = 'block';
questionBankContent.style.display = 'none';
myContent.style.display = 'none';
description.style.display = 'block';
playButton.style.display = 'none';
});
const questionBankBtn = createNavButton('题库', () => {
homeContent.style.display = 'none';
settingsContent.style.display = 'none';
questionBankContent.style.display = 'block';
myContent.style.display = 'none';
description.style.display = 'block';
playButton.style.display = 'block';
});
//
const availableCourses = [
"学习通",
"智慧树",
"U校园",
"U校园AI",
"MOOC",
"学习强国",
"知到",
"乐跑",
"继续教育",
"智慧职教",
"优学院"
];
const myBtn = createNavButton('', () => {
homeContent.style.display = 'none';
settingsContent.style.display = 'none';
questionBankContent.style.display = 'none';
myContent.style.display = 'block';
description.style.display = 'none';
playButton.style.display = 'none';
});
var setting = {
showBox: 1,
maskImg: 1,
task: 0,
video: 1,
audio: 1,
rate: 1,
review: 0,
work: 1,
time: 5000,
sub: 0,
force: 0,
decrypt: 1,
examTurn: 0,
examTurnTime: 1,
goodStudent: 0,
alterTitle: 1,
autoLogin: 0,
phone: '',
password: '',
videoMode: 'simulate',
reportInterval: 60,
showProgressBar: 1
}
var _w = unsafeWindow,
_l = location,
_d = _w.document,
$ = _w.jQuery || top.jQuery,
UE = _w.UE,
md5 = window.md5 || $.md5;
var TyprInstance = null;
try {
if (typeof unsafeWindow !== 'undefined' && unsafeWindow.Typr) {
TyprInstance = unsafeWindow.Typr;
} else if (typeof window !== 'undefined' && window.Typr) {
TyprInstance = window.Typr;
} else if (typeof Typr !== 'undefined') {
TyprInstance = Typr;
} else if (typeof unsafeWindow !== 'undefined' && unsafeWindow.TyprMd5) {
TyprInstance = unsafeWindow.TyprMd5;
} else if (typeof TyprMd5 !== 'undefined') {
TyprInstance = TyprMd5;
}
} catch(e) {}
function getCookie(name) {
return ('; ' + document.cookie).split('; ' + name + '=').pop().split(';')[0];
}
function formatDuration(seconds) {
if (!seconds || seconds < 0) return '00:00';
var total = Math.max(0, Math.floor(Number(seconds) || 0));
var h = Math.floor(total / 3600);
var m = Math.floor((total % 3600) / 60);
var s = total % 60;
var pad = function(n) { return String(n).padStart(2, '0'); };
if (h > 0) {
return pad(h) + ':' + pad(m) + ':' + pad(s);
}
return pad(m) + ':' + pad(s);
}
function tidyStr(s) {
if (!s) return null;
return s.replace(/<(?!img).*?>/g, "").replace(/^【.*?】\s*/, '').replace(/\s*(\d+\.\d+分)$/, '').trim().replace(/ /g, '');
}
function tidyQuestion(s) {
if (!s) return null;
return s.replace(/<(?!img).*?>/g, "").replace(/^【.*?】\s*/, '').replace(/\s*(\d+\.\d+分)$/, '').replace(/^\d+[.、]/, '').trim();
}
function splitAnswer(answer) {
if (!answer) return [];
var parts = answer.split(/[#]+/).map(a => a.trim()).filter(a => a !== '');
if (parts.length === 0 && answer.trim() !== '') {
return [answer.trim()];
}
return parts;
}
function getStr(str, start, end) {
let res = str.match(new RegExp(start + '(.*?)' + end));
return res ? res[1] : null;
}
function isTaskCompleted(task) {
if (!task) return false;
if (task.isPassed === true) return true;
if (task.status === 'completed' || task.status === 'finished') return true;
if (task.finished === true) return true;
return false;
}
var logQueue = [];
var logTimer = null;
function getTopLogContainer() {
try {
var topDoc = top.document;
var container = topDoc.getElementById('ne-21log');
if (container) return $(container);
container = document.getElementById('ne-21log');
if (container) return $(container);
return null;
} catch(e) {
return null;
}
}
function flushLogs() {
if (logQueue.length === 0) return;
var container = getTopLogContainer();
if (container && container.length) {
var logsToShow = logQueue.slice();
logQueue = [];
for (var i = logsToShow.length - 1; i >= 0; i--) {
container.prepend(logsToShow[i]);
}
container.scrollTop(0);
}
if (logTimer) {
clearTimeout(logTimer);
logTimer = null;
}
}
function scheduleFlushLogs() {
if (logTimer) return;
logTimer = setTimeout(flushLogs, 100);
}
function log(str, color) {
var time = new Date().toLocaleTimeString();
var logHtml = '
[' + time + '] ' + str + '
';
logQueue.push(logHtml);
scheduleFlushLogs();
console.log('[刷课小助手欢迎使用][' + time + ']', str);
}
var API_SERVERS = [
{ url: "123", name: "参数" },
{ url: "456", name: "参数2" },
{ url: "h4444", name: "参数3" }
];
var CURRENT_SERVER_INDEX = 0;
function getCurrentApiUrl() {
return API_SERVERS[CURRENT_SERVER_INDEX].url;
}
function getApiKey() {
var key = GM_getValue('api_key', '');
return key;
}
function hasApiKey() {
var key = getApiKey();
return key && key.trim() !== '';
}
function getQuotaInfo() {
return {
remaining: GM_getValue('quota_remaining', 0),
free_remaining: GM_getValue('quota_free_remaining', 0),
recharge_balance: GM_getValue('quota_recharge_balance', 0),
today_free_usage: GM_getValue('quota_today_free_usage', 0)
};
}
var quotaInfo = getQuotaInfo();
function saveQuotaInfo() {
GM_setValue('quota_remaining', quotaInfo.remaining);
GM_setValue('quota_free_remaining', quotaInfo.free_remaining);
GM_setValue('quota_recharge_balance', quotaInfo.recharge_balance);
GM_setValue('quota_today_free_usage', quotaInfo.today_free_usage);
}
function updateQuotaInfo(newQuotaInfo) {
if (newQuotaInfo) {
quotaInfo.remaining = newQuotaInfo.remaining !== undefined ? newQuotaInfo.remaining : quotaInfo.remaining;
quotaInfo.free_remaining = newQuotaInfo.free_remaining !== undefined ? newQuotaInfo.free_remaining : quotaInfo.free_remaining;
quotaInfo.recharge_balance = newQuotaInfo.recharge_balance !== undefined ? newQuotaInfo.recharge_balance : quotaInfo.recharge_balance;
quotaInfo.today_free_usage = newQuotaInfo.today_free_usage !== undefined ? newQuotaInfo.today_free_usage : quotaInfo.today_free_usage;
saveQuotaInfo();
updateQuotaDisplay();
}
}
function updateQuotaDisplay() {
try {
var targetDoc = top.document;
if (!targetDoc.querySelector('#quotaInfo')) targetDoc = document;
var $quotaInfo = $('#quotaInfo', targetDoc);
if ($quotaInfo.length) {
var remaining = quotaInfo.remaining;
var hasKey = hasApiKey();
if (remaining > 0) {
$quotaInfo.html('还有次数: ' + remaining + ' | 当前免费: ' + quotaInfo.free_remaining);
} else if (remaining === 0 && hasKey) {
$quotaInfo.html('次数已用完 | 点击充值');
} else if (!hasKey) {
$quotaInfo.html('需要答题请联系站长获取key进行保存答题');
} else {
$quotaInfo.html('是否已购买,加载~');
}
}
} catch(e) {}
}
function checkApiKeyBeforeAction(actionName) {
var apiKey = getApiKey();
if (!apiKey || apiKey.trim() === '') {
log('❌ 无法执行' + actionName + ':请先在设置中配置API密钥', 'red');
return false;
}
quotaInfo = getQuotaInfo();
if (quotaInfo.remaining <= 0 && quotaInfo.free_remaining <= 0) {
log('❌ 无法执行' + actionName + ':API次数已用完,请充值', 'red');
return false;
}
return true;
}
function testApi(key, serverIndex) {
return new Promise((resolve, reject) => {
var testQuestion = "test";
var testType = "单选题";
var testOptions = ["选项A", "选项B"];
var apiUrl = API_SERVERS[serverIndex || 0].url;
var formData = 'question=' + encodeURIComponent(testQuestion) + '&key=' + encodeURIComponent(key) + '&type=' + encodeURIComponent(testType) + '&options=' + encodeURIComponent(JSON.stringify(testOptions));
var timeoutId = setTimeout(() => {
reject('请求超时');
}, 10000);
GM_xmlhttpRequest({
method: 'POST',
url: apiUrl,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: formData,
timeout: 10000,
onload: function(xhr) {
clearTimeout(timeoutId);
try {
var res = JSON.parse(xhr.responseText);
if (res.code == 1 || res.code == 400) {
if (res.quota_info) {
updateQuotaInfo(res.quota_info);
}
resolve(res);
} else {
reject(res.msg || '密钥无效');
}
} catch(e) {
reject('解析响应失败');
}
},
onerror: function() {
clearTimeout(timeoutId);
reject('网络请求失败');
},
ontimeout: function() {
clearTimeout(timeoutId);
reject('请求超时');
}
});
});
}
function generateEncLocal(classId, uid, jobId, objectId, playTime, duration) {
var str = '[' + classId + '][' + uid + '][' + jobId + '][' + objectId + '][' + (playTime * 1000) + '][d_yHJ!$pdA~5][' + (duration * 1000) + '][0_' + duration + ']';
return md5(str);
}
function waitForElement(selector, timeout = 30000) {
return new Promise((resolve, reject) => {
var start = Date.now();
var timer = setInterval(() => {
if ($(selector).length) {
clearInterval(timer);
resolve();
} else if (Date.now() - start > timeout) {
clearInterval(timer);
reject();
}
}, 500);
});
}
function getElement(parent, selector) {
return new Promise((resolve) => {
var iframe = parent.querySelector(selector);
if (iframe) resolve(iframe);
var observer = new MutationObserver((mutations) => {
var iframe = parent.querySelector(selector);
if (iframe) {
observer.disconnect();
resolve(iframe);
}
});
observer.observe(parent, { childList: true, subtree: true });
setTimeout(() => {
observer.disconnect();
resolve(null);
}, 10000);
});
}
function getBlankInputCount($question) {
var count = 0;
var $inputs = $question.find('.blankList2 input, input[type="text"][name*="answer"]');
if ($inputs.length) {
var uniqueIdentifiers = new Set();
$inputs.each(function() {
var name = $(this).attr('name');
var id = $(this).attr('id');
if (name) {
uniqueIdentifiers.add(name);
} else if (id) {
uniqueIdentifiers.add(id);
} else {
uniqueIdentifiers.add($(this).index());
}
});
count = uniqueIdentifiers.size;
if (count > 0) return count;
}
var $editorBlocks = $question.find('[data-editorindex]');
if ($editorBlocks.length) {
var uniqueIndices = new Set();
$editorBlocks.each(function() {
var idx = $(this).attr('data-editorindex');
if (idx !== undefined && idx !== null && idx !== '') {
uniqueIndices.add(idx);
}
});
count = uniqueIndices.size;
if (count > 0) return count;
}
return count === 0 ? 1 : count;
}
function fillBlankAnswer($question, answers, isPhoneMode, contextWindow) {
var answerList = splitAnswer(answers);
log('答案: ' + answerList.join(' | '), 'blue');
if (isPhoneMode) {
var $allInputs = $question.find('.blankList2 input, input[type="text"][name*="answer"]');
if ($allInputs.length) {
var uniqueInputs = [];
var seen = new Set();
$allInputs.each(function() {
var name = $(this).attr('name');
var id = $(this).attr('id');
var key = name || id || $(this).index();
if (!seen.has(key)) {
seen.add(key);
uniqueInputs.push(this);
}
});
$(uniqueInputs).each(function(i) {
setTimeout(() => {
var answerValue = answerList[i] !== undefined ? answerList[i] : (answerList[0] || '');
$(this).val(answerValue);
$(this).trigger('input').trigger('change');
log('填空题' + (i+1) + '填写: ' + answerValue, 'green');
}, i * 200);
});
return true;
}
return false;
}
var $pcInputs = $question.find('.Zy_ulTk .XztiHover1 textarea, .stem_answer .Answer .divText .textDIV textarea, .subEditor textarea');
if ($pcInputs.length) {
var uniquePCInputs = [];
var seenPC = new Set();
$pcInputs.each(function() {
var id = $(this).attr('id');
var name = $(this).attr('name');
var key = id || name || $(this).index();
if (!seenPC.has(key)) {
seenPC.add(key);
uniquePCInputs.push(this);
}
});
$(uniquePCInputs).each(function(i) {
setTimeout(() => {
var $this = $(this);
var answerValue = answerList[i] !== undefined ? answerList[i] : (answerList[0] || '');
if (UE && UE.getEditor && UE.getEditor($this.attr('id'))) {
UE.getEditor($this.attr('id')).setContent(answerValue);
} else {
$this.val(answerValue);
$this.trigger('input').trigger('change');
}
log('填空题' + (i+1) + ': ' + answerValue, 'green');
}, i * 200);
});
return true;
}
return false;
}
function fillShortAnswer($question, answer, isPhoneMode, contextWindow) {
log('📝 简答题答案: ' + answer.substring(0, 100) + '...', 'blue');
if (isPhoneMode) {
var $textarea = $question.find('textarea[name^="answer"], .answerTxt textarea');
if ($textarea.length) {
$textarea.val(answer);
$textarea.trigger('input').trigger('change');
return true;
}
return false;
}
var $ueTextarea = $question.find('textarea[name^="answerEditor"], .eidtDiv textarea, .divText textarea');
if ($ueTextarea.length) {
var id = $ueTextarea.first().attr('id');
if (id && UE && UE.getEditor && UE.getEditor(id)) {
try {
UE.getEditor(id).setContent(answer);
return true;
} catch(e) {}
}
$ueTextarea.val(answer);
$ueTextarea.trigger('input').trigger('change');
return true;
}
return false;
}
var reportWorker = null;
var activeVideoJob = null;
function createReportWorker(videoInfo, taskObj) {
var name = videoInfo.name;
var duration = videoInfo.duration;
var dtoken = videoInfo.dtoken;
var objectId = videoInfo.objectId;
var jobId = taskObj.jobid;
var rt = videoInfo.rt;
var otherInfo = videoInfo.otherInfo;
var reportUrl = _defaults.reportUrl;
var classId = _defaults.clazzId;
var uid = getCookie('_uid') || getCookie('UID');
var startTime = videoInfo.playedTime || 0;
var rate = setting.rate;
var reportInterval = setting.reportInterval;
var workerCode = `
var timer = null;
var currentTime = ${startTime};
var duration = ${duration};
var rate = ${rate};
var reportInterval = ${reportInterval};
var lastReportTime = ${startTime};
var isRunning = true;
var startTime = Date.now() - (${startTime} * 1000 / ${rate});
var reportCount = 0;
function sendReport(playTime, isComplete) {
self.postMessage({
type: 'doReport',
playTime: playTime,
isComplete: isComplete
});
}
function updateLoop() {
if (!isRunning) return;
var now = Date.now();
var elapsed = (now - startTime) / 1000;
var newTime = Math.min(elapsed * rate, duration);
if (newTime > currentTime) {
currentTime = newTime;
var timeSinceLastReport = currentTime - lastReportTime;
var shouldReport = timeSinceLastReport >= reportInterval || currentTime >= duration;
if (shouldReport) {
sendReport(Math.ceil(currentTime), currentTime >= duration);
lastReportTime = currentTime;
}
self.postMessage({
type: 'progress',
currentTime: currentTime,
duration: duration
});
}
if (currentTime >= duration) {
isRunning = false;
if (timer) clearInterval(timer);
self.postMessage({ type: 'completed' });
} else {
timer = setTimeout(updateLoop, 200);
}
}
updateLoop();
self.onmessage = function(e) {
var data = e.data;
switch(data.type) {
case 'updateRate':
rate = data.rate;
break;
case 'stop':
isRunning = false;
if (timer) clearTimeout(timer);
self.postMessage({ type: 'stopped' });
break;
}
};
`;
var blob = new Blob([workerCode], { type: 'application/javascript' });
var worker = new Worker(URL.createObjectURL(blob));
worker.videoContext = {
name: name,
duration: duration,
dtoken: dtoken,
objectId: objectId,
jobId: jobId,
rt: rt,
otherInfo: otherInfo,
reportUrl: reportUrl,
classId: classId,
uid: uid
};
worker.onmessage = function(e) {
var data = e.data;
switch(data.type) {
case 'progress':
if (setting.showProgressBar) {
updateProgressBar(data.currentTime, data.duration);
}
break;
case 'doReport':
var ctx = worker.videoContext;
var enc = generateEncLocal(ctx.classId, ctx.uid, ctx.jobId, ctx.objectId, data.playTime, ctx.duration);
var isdrag = data.isComplete ? '4' : '0';
var reportsUrl = ctx.reportUrl + '/' + ctx.dtoken +
'?clazzId=' + ctx.classId +
'&playingTime=' + data.playTime +
'&duration=' + ctx.duration +
'&clipTime=0_' + ctx.duration +
'&objectId=' + ctx.objectId +
'&otherInfo=' + ctx.otherInfo +
'&jobid=' + ctx.jobId +
'&userid=' + ctx.uid +
'&isdrag=' + isdrag +
'&view=pc' +
'&enc=' + enc +
'&rt=' + ctx.rt +
'&dtype=Video' +
'&_t=' + Date.now();
log('上报: ' + formatDuration(data.playTime) + '/' + formatDuration(ctx.duration), 'blue');
GM_xmlhttpRequest({
method: "GET",
url: reportsUrl,
headers: {
'Host': _l.host,
'Referer': _l.protocol + '//' + _l.host + '/ananas/modules/video/index.html'
},
onload: function(res) {
try {
var result = JSON.parse(res.responseText);
if (result.isPassed && !worker.isCompleted) {
worker.isCompleted = true;
log('已完成: ' + ctx.name, 'green');
if (worker.completeCallback) worker.completeCallback();
}
} catch(e) {}
},
onerror: function() {
log('将继续尝试', 'orange');
}
});
break;
case 'completed':
log('等待服务器确认...', 'green');
setTimeout(function() {
if (worker.completeCallback) worker.completeCallback();
}, 5000);
break;
case 'stopped':
log('📡 Worker已停止', 'blue');
break;
}
};
return worker;
}
var currentVideoInterval = null;
var currentProgressBar = null;
var currentVideoWorker = null;
var currentVideoTaskId = null;
var videoTaskCounter = 0;
var _mlist, _defaults, _domList, $subBtn, $saveBtn, $frame_c, $okBtn;
var isProcessing = false;
var isBoxHidden = false;
var pikaqiuAdded = false;
var pendingMissionCount = 0;
var completedMissionCount = 0;
var isJumping = false;
var hasTriggeredNoTaskJump = false;
var isVideoTaskActive = false;
var currentVideoName = null;
function forceCleanupAll() {
var taskId = videoTaskCounter;
log('...', 'orange');
if (currentVideoWorker) {
try {
currentVideoWorker.postMessage({ type: 'stop' });
setTimeout(function() {
try {
if (currentVideoWorker) currentVideoWorker.terminate();
} catch(e) {}
}, 100);
currentVideoWorker = null;
log('止视频上报', 'green');
} catch(e) {
log('终止Worker失败: ' + e.message, 'orange');
}
}
if (currentVideoInterval) {
clearInterval(currentVideoInterval);
currentVideoInterval = null;
log('定时器', 'green');
}
if (reportWorker) {
try {
reportWorker.terminate();
} catch(e) {}
reportWorker = null;
}
removeProgressBar();
isVideoTaskActive = false;
currentVideoName = null;
activeVideoJob = null;
currentVideoTaskId = null;
log('清理完成', 'green');
}
function removeProgressBar() {
if (currentProgressBar) {
try {
$(currentProgressBar).remove();
currentProgressBar = null;
log('悬浮窗', 'green');
} catch(e) {
log('进度条失败: ' + e.message, 'orange');
}
}
try {
var targetDoc = top.document;
var existingBar = targetDoc.querySelector('#video-progress-bar');
if (existingBar) {
$(existingBar).remove();
log('悬浮窗', 'green');
}
} catch(e) {}
}
function createProgressBar(videoName, duration) {
// 先彻底移除旧的
removeProgressBar();
currentVideoName = videoName;
var taskId = ++videoTaskCounter;
currentVideoTaskId = taskId;
var targetDoc = top.document;
var barHtml = `
当前播放视频:${videoName}
0%
00:00
进度条: --:--
${formatDuration(duration)}
进行中
⚡ ${setting.rate}x
`;
try {
$(targetDoc.body).append(barHtml);
currentProgressBar = targetDoc.querySelector('#video-progress-bar');
} catch(e) {
$(document.body).append(barHtml);
currentProgressBar = document.querySelector('#video-progress-bar');
}
log('进行中', 'blue');
}
function updateProgressBar(playTime, duration) {
if (!currentProgressBar) return;
var taskId = currentProgressBar.getAttribute('data-task-id');
if (taskId && currentVideoTaskId && parseInt(taskId) !== currentVideoTaskId) {
return;
}
var percent = Math.min(100, Math.round((playTime / duration) * 100));
var remaining = Math.max(0, duration - playTime);
var fillBar = currentProgressBar.querySelector('#progress-bar-fill');
var percentSpan = currentProgressBar.querySelector('#progress-percent');
var currentSpan = currentProgressBar.querySelector('#progress-current');
var remainingSpan = currentProgressBar.querySelector('#progress-remaining');
if (fillBar) fillBar.style.width = percent + '%';
if (percentSpan) percentSpan.textContent = percent + '%';
if (currentSpan) currentSpan.textContent = formatDuration(playTime);
if (remainingSpan) remainingSpan.textContent = '剩余: ' + formatDuration(remaining);
}
function completeCurrentTask() {
forceCleanupAll();
if (_mlist && _mlist.length > 0) {
var completedTask = _mlist[0];
var taskName = completedTask.property ? (completedTask.property.name || completedTask.property.title || '未知') : '未知';
log('完成任务: ' + taskName, 'green');
_mlist.splice(0, 1);
completedMissionCount++;
log(': ' + completedMissionCount + '/' + pendingMissionCount + ' | 剩余: ' + _mlist.length, 'blue');
}
if (_domList && _domList.length > 0) {
_domList.splice(0, 1);
}
isProcessing = false;
if (_mlist && _mlist.length > 0) {
log(' ' + _mlist.length + ' 继续...', 'green');
setTimeout(function() {
missionStart();
}, 1000);
} else {
log('处理完毕', 'green');
toNext();
}
}
function toNext() {
if (isJumping) return;
isJumping = true;
log('检查章节...', 'blue');
var nextBtn = null;
try {
nextBtn = top.document.querySelector('#mainid > .prev_next.next:not(.disabled)') ||
top.document.querySelector('#prevNextFocusNext:not(.disabled)') ||
top.document.querySelector('.prev_next.next:not(.disabled)') ||
$('.prev_next.next:not(.disabled)')[0];
if (nextBtn && !nextBtn.disabled && !nextBtn.classList.contains('disabled')) {
log('下一节按钮等待跳转', 'green');
setTimeout(() => {
nextBtn.click();
log('📖 已点击跳转按钮', 'green');
isJumping = false;
}, 3000);
return true;
} else {
log('已全部完成', 'green');
}
} catch(e) {
log('❌ 跳转失败: ' + e.message, 'red');
}
isJumping = false;
return false;
}
function getVideoStatus(item, callback) {
var objectId = item.property.objectid;
var statusUrl = _l.protocol + '//' + _l.host + '/ananas/status/' + objectId +
'?k=' + (getCookie('fid') || '') + '&flag=normal&_dc=' + Date.now();
GM_xmlhttpRequest({
method: "GET",
url: statusUrl,
headers: {
'Host': _l.host,
'Referer': _l.protocol + '//' + _l.host + '/ananas/modules/video/index.html'
},
onload: function(res) {
try {
var videoInfo = JSON.parse(res.responseText);
callback({
success: true,
duration: videoInfo.duration,
dtoken: videoInfo.dtoken,
objectId: objectId,
rt: item.property.rt || '0.9',
otherInfo: item.otherInfo || '',
jobid: item.jobid,
playedTime: videoInfo.playingTime || 0,
isPassed: videoInfo.isPassed || false,
name: item.property.name
});
} catch(e) {
callback({ success: false, error: e.message });
}
},
onerror: function(err) {
callback({ success: false, error: err.error });
}
});
}
function simulateVideoReport(videoInfo, taskObj) {
var name = videoInfo.name || taskObj.property.name;
var duration = videoInfo.duration;
var isAlreadyPassed = videoInfo.isPassed || false;
if (isAlreadyPassed && !setting.review) {
log('已完成: ' + name + ',跳过', 'green');
completeCurrentTask();
return;
}
log('' + name + ',总时长: ' + formatDuration(duration), 'purple');
log('', 'blue');
if (setting.showProgressBar) {
createProgressBar(name, duration);
updateProgressBar(videoInfo.playedTime || 0, duration);
}
isVideoTaskActive = true;
currentVideoName = name;
currentVideoWorker = createReportWorker(videoInfo, taskObj);
reportWorker = currentVideoWorker;
var workerTaskId = videoTaskCounter;
// 设置完成回调
currentVideoWorker.completeCallback = function() {
if (workerTaskId === currentVideoTaskId && isVideoTaskActive) {
forceCleanupAll();
completeCurrentTask();
}
};
}
function normalVideoPlay(dom, obj) {
var name = obj.property.name;
var target = dom.length > 0 ? dom[0] : null;
if (!target) {
log('3秒后重试', 'orange');
isProcessing = false;
setTimeout(function() {
normalVideoPlay(dom, obj);
}, 3000);
return;
}
log('处理视频:' + name, 'purple');
isVideoTaskActive = true;
currentVideoName = name;
var executed = false;
var doc = target.contentDocument || target.contentWindow.document;
if (currentVideoInterval) {
clearInterval(currentVideoInterval);
}
currentVideoInterval = setInterval(function() {
var media = doc.querySelector('video') || doc.querySelector('audio');
if (media && !executed) {
executed = true;
log('✅ ' + name + ' 开始播放', 'green');
media.pause();
media.muted = true;
media.playbackRate = setting.rate > 1 ? Math.min(setting.rate, 16) : 1;
media.play();
var resumePlay = function() {
if (media.paused && !media.ended) {
media.play();
}
};
media.addEventListener('pause', resumePlay);
var onVideoEnd = function() {
log('✅ ' + name + ' 播放完成', 'green');
media.removeEventListener('pause', resumePlay);
media.removeEventListener('ended', onVideoEnd);
clearInterval(currentVideoInterval);
currentVideoInterval = null;
forceCleanupAll();
completeCurrentTask();
};
media.addEventListener('ended', onVideoEnd);
if (media.ended) {
onVideoEnd();
}
}
}, 1500);
}
function missionVideo(dom, obj) {
if (!setting.video) {
log('视频任务', 'orange');
completeCurrentTask();
return;
}
var isPassed = obj.isPassed;
var name = obj.property.name;
if (!setting.review && isPassed === true) {
log('视频:' + name + ' 已完成,跳过', 'green');
completeCurrentTask();
return;
}
if (setting.videoMode === 'simulate') {
log('处理视频: ' + name, 'purple');
getVideoStatus(obj, function(result) {
if (result.success) {
simulateVideoReport(result, obj);
} else {
log('失败: ' + result.error + ',降级到正常播放', 'red');
normalVideoPlay(dom, obj);
}
});
return;
}
normalVideoPlay(dom, obj);
}
function missionAudio(dom, obj) {
if (!setting.audio) {
log('音频任务', 'orange');
completeCurrentTask();
return;
}
var isPassed = obj.isPassed;
var name = obj.property.name;
if (!setting.review && isPassed === true) {
log('✅ 音频:' + name + ' 已完成,跳过', 'green');
completeCurrentTask();
return;
}
log('🎵 处理音频:' + name + ',等待5秒后完成', 'purple');
setTimeout(function() {
completeCurrentTask();
}, 5000);
}
function missionBook(dom, obj) {
var jobId = obj.property.jobid;
var name = obj.property.bookname;
var jtoken = obj.jtoken;
var knowledgeId = _defaults.knowledgeid;
var courseId = _defaults.courseid;
var clazzId = _defaults.clazzId;
if (isTaskCompleted(obj)) {
log('✅ 读书:' + name + ' 已完成,跳过', 'green');
completeCurrentTask();
return;
}
$.ajax({
url: _l.protocol + "//" + _l.host + '/ananas/job?jobid=' + jobId + '&knowledgeid=' + knowledgeId + '&courseid=' + courseId + '&clazzid=' + clazzId + '&jtoken=' + jtoken + '&_dc=' + Date.now(),
method: 'GET',
success: function(res) {
log('📚 读书:' + name + (res.msg || '完成'), 'green');
completeCurrentTask();
},
error: function() {
log('❌ 读书:' + name + ' 处理失败,3秒后重试', 'red');
isProcessing = false;
setTimeout(function() {
missionBook(dom, obj);
}, 3000);
}
});
}
function missionDoucument(dom, obj) {
var jobId = obj.property.jobid;
var name = obj.property.name;
var jtoken = obj.jtoken;
var knowledgeId = _defaults.knowledgeid;
var courseId = _defaults.courseid;
var clazzId = _defaults.clazzId;
if (isTaskCompleted(obj)) {
log('✅ 文档:' + name + ' 已完成,跳过', 'green');
completeCurrentTask();
return;
}
$.ajax({
url: _l.protocol + "//" + _l.host + '/ananas/job/document?jobid=' + jobId + '&knowledgeid=' + knowledgeId + '&courseid=' + courseId + '&clazzid=' + clazzId + '&jtoken=' + jtoken + '&_dc=' + Date.now(),
method: 'GET',
success: function(res) {
log('文档:' + name + (res.msg || '完成'), 'green');
completeCurrentTask();
},
error: function() {
log('文档:' + name + ' 处理失败,3秒后重试', 'red');
isProcessing = false;
setTimeout(function() {
missionDoucument(dom, obj);
}, 3000);
}
});
}
function missionRead(dom, obj) {
var jobId = obj.property.jobid;
var name = obj.property.title;
var jtoken = obj.jtoken;
var knowledgeId = _defaults.knowledgeid;
var courseId = _defaults.courseid;
var clazzId = _defaults.clazzId;
if (isTaskCompleted(obj)) {
log('阅读:' + name + ' 已完成,跳过', 'green');
completeCurrentTask();
return;
}
$.ajax({
url: _l.protocol + '//' + _l.host + '/ananas/job/readv2?jobid=' + jobId + '&knowledgeid=' + knowledgeId + '&courseid=' + courseId + '&clazzid=' + clazzId + '&jtoken=' + jtoken + '&_dc=' + Date.now(),
method: 'GET',
success: function(res) {
log('阅读:' + name + (res.msg || '完成'), 'green');
completeCurrentTask();
},
error: function() {
log(' 阅读:' + name + ' 处理失败,3秒后重试', 'red');
isProcessing = false;
setTimeout(function() {
missionRead(dom, obj);
}, 3000);
}
});
}
function missionStart() {
if (isProcessing) {
log('处理中,跳过', 'orange');
return;
}
if (!_mlist || _mlist.length <= 0) {
log('处理完毕', 'green');
isProcessing = false;
toNext();
return;
}
forceCleanupAll();
isProcessing = true;
var _type = _mlist[0].type;
var _dom = _domList[0];
var _task = _mlist[0];
if (_type == undefined) {
_type = _mlist[0].property.module;
}
var taskName = _task.property ? (_task.property.name || _task.property.title || '未知') : '未知';
log('处理任务: ' + taskName + ' (类型: ' + _type + ')', 'blue');
var handlers = {
'video': () => missionVideo(_dom, _task),
'audio': () => missionAudio(_dom, _task),
'workid': () => missionWork(_dom, _task),
'document': () => missionDoucument(_dom, _task),
'read': () => missionRead(_dom, _task),
'insertbook': () => missionBook(_dom, _task)
};
if (handlers[_type]) {
handlers[_type]();
} else if (['insertimage'].includes(_type)) {
log('无需处理任务,跳过', 'orange');
completeCurrentTask();
} else {
log('处理此类型:' + _type + ',跳过', 'red');
completeCurrentTask();
}
}
function getAnswer(type, questionText, optionsData, retryCount) {
retryCount = retryCount || 0;
var startServerIndex = retryCount;
return new Promise((resolve, reject) => {
var apiKey = getApiKey();
if (!apiKey || apiKey.trim() === '') {
log('次数已用完', 'red');
reject('NO_API_KEY');
return;
}
quotaInfo = getQuotaInfo();
if (quotaInfo.remaining <= 0 && quotaInfo.free_remaining <= 0) {
log('次数已用完', 'red');
reject('QUOTA_EXHAUSTED');
return;
}
var typeMap = {0:'单选题',1:'多选题',2:'填空题',3:'判断题',4:'简答题'};
var typeText = typeMap[type] || '单选题';
function tryServer(index) {
if (index >= API_SERVERS.length) {
log('次数已用完', 'red');
reject('所有接口均失败');
return;
}
var apiUrl = API_SERVERS[index].url;
var formData = 'question=' + encodeURIComponent(questionText) + '&key=' + encodeURIComponent(apiKey) + '&type=' + encodeURIComponent(typeText);
if (optionsData && optionsData.length) {
formData += '&options=' + encodeURIComponent(JSON.stringify(optionsData));
}
if (index === startServerIndex) {
log('请求答案 - 题型:' + typeText + ' 题目:' + questionText.substring(0, 40) + '...', 'blue');
}
var timeoutId = setTimeout(() => {
tryServer(index + 1);
}, 15000);
GM_xmlhttpRequest({
method: 'POST',
url: apiUrl,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: formData,
timeout: 15000,
onload: function(xhr) {
clearTimeout(timeoutId);
try {
var res = JSON.parse(xhr.responseText);
if (res.code == 1 && res.data) {
if (res.quota_info) {
updateQuotaInfo(res.quota_info);
}
CURRENT_SERVER_INDEX = index;
GM_setValue('current_server_index', index);
log('✅ 答案: ' + res.data.substring(0, 100) + '...', 'purple');
resolve(res.data);
} else if (res.code == 400) {
log('❌ ' + (res.msg || 'API密钥无效'), 'red');
reject('API_KEY_INVALID');
} else {
tryServer(index + 1);
}
} catch(e) {
tryServer(index + 1);
}
},
onerror: function() {
clearTimeout(timeoutId);
tryServer(index + 1);
},
ontimeout: function() {
clearTimeout(timeoutId);
tryServer(index + 1);
}
});
}
tryServer(startServerIndex);
});
}
function missionWork(dom, obj) {
if (!setting.work) {
log('处理测验', 'orange');
completeCurrentTask();
return;
}
if (!checkApiKeyBeforeAction('自动答题')) {
completeCurrentTask();
return;
}
var isDo = true;
if (setting.task && obj.jobid == undefined) {
isDo = false;
}
if (isDo) {
if (obj.jobid !== undefined) {
var phoneWeb = _l.protocol + '//' + _l.host + '/work/phone/work?workId=' + obj.jobid.replace('work-', '') + '&courseId=' + _defaults.courseid + '&clazzId=' + _defaults.clazzId + '&knowledgeId=' + _defaults.knowledgeid + '&jobId=' + obj.jobid + '&enc=' + obj.enc;
log('📝 准备处理测验', 'purple');
setTimeout(function() {
startDoPhoneCyWork(0, [dom], phoneWeb, obj);
}, 3000);
} else {
setTimeout(function() {
startDoCyWork(0, [dom], obj);
}, 3000);
}
} else {
log('ℹ️ 用户设置只处理属于任务点的任务', 'orange');
completeCurrentTask();
}
}
function startDoPhoneCyWork(index, doms, phoneWeb, taskObj) {
if (index == doms.length) {
log('处理完毕', 'green');
completeCurrentTask();
return;
}
getElement($(doms[index]).contents()[0], 'iframe').then(function(iframe) {
if (!iframe) {
setTimeout(function() {
startDoPhoneCyWork(index, doms, phoneWeb, taskObj);
}, 5000);
return;
}
var workIframe = $(iframe);
var workStatus = workIframe.contents().find('.newTestCon .newTestTitle .testTit_status').text().trim();
if (!workStatus) {
_domList.splice(0, 1);
isProcessing = false;
setTimeout(switchMission, 2000);
return;
}
if (workStatus.indexOf("待做") != -1 || workStatus.indexOf("待完成") != -1 || workStatus.indexOf("未达到及格线") != -1) {
workIframe.attr('src', phoneWeb);
getElement($(doms[index]).contents()[0], 'iframe[src="' + phoneWeb + '"]').then(function() {
setTimeout(function() {
doPhoneWork(workIframe.contents(), taskObj);
}, 3000);
});
} else if (workStatus.indexOf('待批阅') != -1) {
_mlist.splice(0, 1);
_domList.splice(0, 1);
log('跳过', 'red');
completeCurrentTask();
} else if (workStatus.indexOf('已完成') != -1 || workStatus.indexOf('已交') != -1) {
log('跳过', 'green');
completeCurrentTask();
} else {
_mlist.splice(0, 1);
_domList.splice(0, 1);
log('状态,跳过', 'red');
completeCurrentTask();
}
});
}
function doPhoneWork($dom, taskObj) {
var $cy = $dom.find('.Wrappadding form');
$subBtn = $cy.find('.zquestions .zsubmit .btn-ok-bottom');
$okBtn = $dom.find('#okBtn');
$saveBtn = $cy.find('.zquestions .zsubmit .btn-save');
var TimuList = $cy.find('.zquestions .Py-mian1');
startDoPhoneTimu(0, TimuList, taskObj);
}
function isQuestionAnswered($timu, _type) {
if (_type == 0 || _type == 1) {
var $opts = _type == 0 ? $timu.find('.answerList.singleChoice li') : $timu.find('.answerList.multiChoice li');
for (var i = 0; i < $opts.length; i++) {
if ($($opts[i]).attr('aria-label')) return true;
}
} else if (_type == 2) {
var $inputs = $timu.find('.blankList2 input');
if ($inputs.length && $inputs.first().val() && $inputs.first().val().trim() !== '') return true;
} else if (_type == 3) {
var $pd = $timu.find('.answerList.panduan li');
for (var i = 0; i < $pd.length; i++) {
if ($($pd[i]).attr('aria-label')) return true;
}
} else if (_type == 4) {
var $ta = $timu.find('textarea[name^="answer"]');
if ($ta.length && $ta.first().val() && $ta.first().val().trim() !== '') return true;
}
return false;
}
function getQuestionType($timu, typeName) {
var typeMap = {
'单选题': 0,
'多选题': 1,
'填空题': 2,
'判断题': 3,
'简答题': 4
};
var _type = typeMap[typeName];
if (_type === undefined) {
if ($timu.find('.answerList.singleChoice li').length) _type = 0;
else if ($timu.find('.answerList.multiChoice li').length) _type = 1;
else if ($timu.find('.blankList2 input').length) _type = 2;
else if ($timu.find('.answerList.panduan li').length) _type = 3;
else if ($timu.find('textarea').length) _type = 4;
}
return _type;
}
function handlePhoneJudge($timu, answer) {
var trueKeywords = '正确|是|对|√|T|ri';
var $pd = $timu.find('.answerList.panduan li');
if (trueKeywords.indexOf(answer) != -1 || trueKeywords.toLowerCase().indexOf(answer.toLowerCase()) != -1) {
$pd.each(function(i, t) {
if ($(t).attr('val-param') == 'true') {
$(t).click();
log('正确 (接口返回: ' + answer + ')', 'green');
}
});
} else {
$pd.each(function(i, t) {
if ($(t).attr('val-param') == 'false') {
$(t).click();
log(' 错误 (接口返回: ' + answer + ')', 'green');
}
});
}
}
function startDoPhoneTimu(index, TimuList, taskObj) {
if (index == TimuList.length) {
finishQuiz();
return;
}
var contextWindow = TimuList[index] ? (TimuList[index].ownerDocument.defaultView || unsafeWindow) : unsafeWindow;
var $timu = $(TimuList[index]);
var questionFull = $timu.find('.Py-m1-title').html();
var _question = tidyQuestion(questionFull).replace(/.*?\[.*?题\]\s*\n\s*/, '').trim();
var typeName = questionFull.match(/.*?\[(.*?)]|$/)[1];
var _type = getQuestionType($timu, typeName);
if (isQuestionAnswered($timu, _type)) {
log(' 第' + (index + 1) + '题已作答', 'green');
setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), 30);
return;
}
var $opts = [];
var optsText = [];
var optionsData = [];
var pureQuestion = _question;
if (_type == 0 || _type == 1) {
$opts = _type == 0 ? $timu.find('.answerList.singleChoice li') : $timu.find('.answerList.multiChoice li');
$opts.each(function() {
optsText.push(tidyStr($(this).html()).replace(/^[A-Z]\s*\n\s*/, '').trim());
});
optionsData = optsText;
} else if (_type == 2) {
var blankCount = getBlankInputCount($timu);
optionsData = [blankCount.toString()];
} else if (_type == 3) {
optionsData = ["对", "错"];
} else if (_type == 4) {
optionsData = ["1"];
}
getAnswer(_type, pureQuestion, optionsData).then((agrs) => {
if (agrs == '无答案' || !agrs) {
log('跳过此题', 'red');
setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), setting.time);
return;
}
if (setting.alterTitle) {
$timu.find('.Py-m1-title').html($timu.find('.Py-m1-title').html() + '📖 ' + agrs + '
');
}
if (_type == 0) {
var idx = optsText.findIndex(t => t == agrs);
if (idx != -1) $timu.find('.answerList.singleChoice li').eq(idx).click();
else log('未找到匹配选项: ' + agrs, 'orange');
} else if (_type == 1) {
var ansArr = splitAnswer(agrs);
$opts.each((i, t) => {
if (ansArr.includes(optsText[i])) {
setTimeout(() => $(t).click(), 300);
}
});
} else if (_type == 2) {
fillBlankAnswer($timu, agrs, true, contextWindow);
} else if (_type == 3) {
handlePhoneJudge($timu, agrs);
} else if (_type == 4) {
fillShortAnswer($timu, agrs, true, contextWindow);
}
log('第' + (index + 1) + '答题成功', 'green');
setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), setting.time);
}).catch(() => {
log('第' + (index + 1) + '答案失败,跳过', 'orange');
setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), setting.time);
});
}
function startDoCyWork(index, doms, taskObj) {
if (index == doms.length) {
log('处理完毕', 'green');
completeCurrentTask();
return;
}
getElement($(doms[index]).contents()[0], 'iframe').then(function(iframe) {
if (!iframe) {
setTimeout(function() {
startDoCyWork(index, doms, taskObj);
}, 5000);
return;
}
var workIframe = $(iframe);
var workStatus = workIframe.contents().find(".newTestCon .newTestTitle .testTit_status").text().trim();
if (!workStatus) {
_domList.splice(0, 1);
isProcessing = false;
setTimeout(switchMission, 2000);
return;
}
if (workStatus.indexOf("待做") != -1 || workStatus.indexOf("待完成") != -1) {
log('处理测验', 'purple');
setTimeout(function() {
doWork(index, doms, iframe, taskObj);
}, 5000);
} else if (workStatus.indexOf('待批阅') != -1) {
_mlist.splice(0, 1);
_domList.splice(0, 1);
log('跳过', 'red');
completeCurrentTask();
} else if (workStatus.indexOf('已完成') != -1 || workStatus.indexOf('已交') != -1) {
log('跳过', 'green');
completeCurrentTask();
} else {
_mlist.splice(0, 1);
_domList.splice(0, 1);
log('跳过', 'red');
completeCurrentTask();
}
});
}
function doWork(index, doms, dom, taskObj) {
$frame_c = $(dom).contents();
var $CyHtml = $frame_c.find('.CeYan');
var TiMuList = $CyHtml.find('.TiMu');
$subBtn = $frame_c.find(".ZY_sub").find(".btnSubmit");
$saveBtn = $frame_c.find(".ZY_sub").find(".btnSave");
startDoWork(0, TiMuList);
}
function handlePCJudge($timu, answer) {
var trueKeywords = '正确|是|对|√|T|ri';
var $pdContainer = $timu.find('.Zy_ulTop li');
if ($pdContainer.length === 0) {
$pdContainer = $timu.find('.stem_answer .answer_p').parent();
}
if (trueKeywords.indexOf(answer) != -1 || trueKeywords.toLowerCase().indexOf(answer.toLowerCase()) != -1) {
var clicked = false;
$pdContainer.each(function(i, t) {
var $opt = $(t).find('a, .answer_p');
if ($opt.length === 0) $opt = $(t);
var valAttr = $(t).find('span').attr('val-param') || $(t).attr('val-param');
if (valAttr == 'true') {
$(t).click();
clicked = true;
log(' 正确 (接口返回: ' + answer + ')', 'green');
}
});
if (!clicked && $pdContainer.length > 0) {
$($pdContainer[0]).click();
log('正确(默认第一个) (接口返回: ' + answer + ')', 'green');
}
} else {
var clicked = false;
$pdContainer.each(function(i, t) {
var valAttr = $(t).find('span').attr('val-param') || $(t).attr('val-param');
if (valAttr == 'false') {
$(t).click();
clicked = true;
log('错误 (接口返回: ' + answer + ')', 'green');
}
});
if (!clicked && $pdContainer.length > 1) {
$($pdContainer[1]).click();
log(' 错误(默认第二个) (接口返回: ' + answer + ')', 'green');
} else if (!clicked && $pdContainer.length === 1) {
$($pdContainer[0]).click();
log('错误(唯一选项) (接口返回: ' + answer + ')', 'green');
}
}
}
function finishQuiz() {
if (setting.sub) {
log('准备自动提交', 'green');
setTimeout(() => {
if ($subBtn && $subBtn.length) $subBtn.click();
setTimeout(() => {
if ($okBtn && $okBtn.length) $okBtn.click();
log('成功', 'green');
completeCurrentTask();
}, 3000);
}, 5000);
} else if (setting.force) {
log('强制提交', 'red');
setTimeout(() => {
if ($subBtn && $subBtn.length) $subBtn.click();
setTimeout(() => {
if ($okBtn && $okBtn.length) $okBtn.click();
log('成功', 'green');
completeCurrentTask();
}, 3000);
}, 5000);
} else {
log('自动保存', 'green');
setTimeout(() => {
if ($saveBtn && $saveBtn.length) $saveBtn.click();
log('成功', 'green');
completeCurrentTask();
}, 5000);
}
}
function startDoWork(c, TiMuList) {
if (c == TiMuList.length) {
finishQuiz();
return;
}
var $timu = $(TiMuList[c]);
var questionFull = $timu.find('.Zy_TItle.clearfix > div').html();
var _question = tidyQuestion(questionFull);
var typeName = questionFull.match(/^【(.*?)】|$/)[1];
var _TimuType = getQuestionType($timu, typeName);
var $opts = [];
var optsText = [];
var optionsData = [];
var pureQuestion = _question;
if (_TimuType == 0 || _TimuType == 1) {
$opts = $timu.find('.Zy_ulTop li a');
$opts.each(function() {
optsText.push(tidyStr($(this).html()));
});
optionsData = optsText;
} else if (_TimuType == 2) {
var blankCount = getBlankInputCount($timu);
optionsData = [blankCount.toString()];
} else if (_TimuType == 3) {
optionsData = ["对", "错"];
} else if (_TimuType == 4) {
optionsData = ["1"];
}
getAnswer(_TimuType, pureQuestion, optionsData).then((agrs) => {
if (agrs == '暂无答案' || !agrs) {
log('⚠️ PC第' + (c + 1) + '题无法获取答案,跳过', 'orange');
setTimeout(() => startDoWork(c + 1, TiMuList), setting.time);
return;
}
if (setting.alterTitle) {
$timu.find('.Zy_TItle.clearfix > div').html($timu.find('.Zy_TItle.clearfix > div').html() + '📖 ' + agrs + '
');
}
if (_TimuType == 0) {
var idx = optsText.findIndex(t => t == agrs);
if (idx != -1) $($opts[idx]).parent().click();
} else if (_TimuType == 1) {
var ansArr = splitAnswer(agrs);
$opts.each((i, t) => {
if (ansArr.includes(optsText[i])) $($opts[i]).parent().click();
});
} else if (_TimuType == 2) {
fillBlankAnswer($timu, agrs, false, null);
} else if (_TimuType == 3) {
handlePCJudge($timu, agrs);
} else if (_TimuType == 4) {
fillShortAnswer($timu, agrs, false, null);
}
log('✅ PC第' + (c + 1) + '题自动答题成功', 'green');
setTimeout(() => startDoWork(c + 1, TiMuList), setting.time);
}).catch(() => {
log('⚠️ PC第' + (c + 1) + '题获取答案失败,跳过', 'orange');
setTimeout(() => startDoWork(c + 1, TiMuList), setting.time);
});
}
function switchMission() {
isProcessing = false;
missionStart();
}
function toNextExam() {
if (setting.examTurn) {
var $nextbtn = $('.mark_table .whiteDiv .nextDiv a.jb_btn');
var delay = setting.examTurnTime ? 2000 + (Math.floor(Math.random() * 5 + 1) * 1000) : 2000;
setTimeout(() => $nextbtn.click(), delay);
log('⏭️ ' + (delay/1000) + '秒后自动跳转下一题', 'blue');
}
}
function base64ToUint8Array(base64) {
var data = window.atob(base64);
var buf = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) buf[i] = data.charCodeAt(i);
return buf;
}
function decryptFont() {
if (setting.decrypt !== 1) return;
try {
if (!TyprInstance || !TyprInstance.U || !TyprInstance.parse) {
try {
if (typeof unsafeWindow !== 'undefined' && unsafeWindow.Typr) {
TyprInstance = unsafeWindow.Typr;
} else if (typeof window !== 'undefined' && window.Typr) {
TyprInstance = window.Typr;
} else if (typeof Typr !== 'undefined') {
TyprInstance = Typr;
} else if (typeof unsafeWindow !== 'undefined' && unsafeWindow.TyprMd5) {
TyprInstance = unsafeWindow.TyprMd5;
} else if (typeof TyprMd5 !== 'undefined') {
TyprInstance = TyprMd5;
}
} catch(e) {}
if (!TyprInstance || !TyprInstance.U) {
log('进行中,加急中,请稍等~~~', 'blue');
setTimeout(decryptFont, 1000);
return;
}
}
var $tip = $('style:contains(font-cxsecret)');
if (!$tip.length) {
return;
}
var styleText = $tip.text();
var fontBase64 = null;
var match1 = styleText.match(/base64,([\w\W]+?)'/);
if (match1 && match1[1]) fontBase64 = match1[1];
if (!fontBase64) {
var match2 = styleText.match(/url\("data:application\/font-woff;charset=utf-8;base64,([\w\W]+?)"\)/);
if (match2 && match2[1]) fontBase64 = match2[1];
}
if (!fontBase64) {
var match3 = styleText.match(/url\('data:application\/font-woff;charset=utf-8;base64,([\w\W]+?)'\)/);
if (match3 && match3[1]) fontBase64 = match3[1];
}
if (!fontBase64) return;
var fontUint8Array = base64ToUint8Array(fontBase64);
var parsedFont = TyprInstance.parse(fontUint8Array);
if (!parsedFont || parsedFont.length === 0) return;
var font = parsedFont[0];
var tableJson = GM_getResourceText('Table');
if (!tableJson) return;
var table;
try {
table = JSON.parse(tableJson);
} catch(e) {
return;
}
var match = {};
var matchCount = 0;
for (var i = 19968; i < 40870; i++) {
var glyph = TyprInstance.U.codeToGlyph(font, i);
if (!glyph) continue;
var path = TyprInstance.U.glyphToPath(font, glyph);
if (!path) continue;
var pathStr = JSON.stringify(path);
var hash = md5(pathStr);
if (!hash) continue;
var hashKey = hash.slice(24);
var realChar = table[hashKey];
if (realChar !== undefined && realChar !== null && realChar !== 0) {
match[i] = realChar;
matchCount++;
}
}
if (matchCount === 0) return;
var $elements = $('.font-cxsecret');
if ($elements.length === 0) return;
$elements.each(function() {
var $el = $(this);
var html = $el.html();
if (!html) return;
for (var code in match) {
var encryptedChar = String.fromCharCode(parseInt(code));
var realChar = String.fromCharCode(match[code]);
var escapedChar = encryptedChar.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
var regex = new RegExp(escapedChar, 'g');
html = html.replace(regex, realChar);
}
if ($el.html() !== html) {
$el.html(html);
$el.removeClass('font-cxsecret');
}
});
log('✅ 字体解密完成!已还原 ' + matchCount + ' 个字符', 'green');
} catch(e) {
log('❌ 字体解密失败: ' + e.message, 'red');
}
}
function showPikaqiu() {
if (!setting.maskImg) return;
if (pikaqiuAdded) return;
try {
var targetDoc = top.document;
if (targetDoc.querySelector('#pikaqiu-img')) return;
var imgHtml = '
';
$(targetDoc.body).append(imgHtml);
pikaqiuAdded = true;
$('#pikaqiu-img', targetDoc).click(function() {
var $box = $('#ne-21box', targetDoc);
if ($box.length) {
if ($box.css('display') === 'none') {
$box.css('display', 'block');
isBoxHidden = false;
} else {
$box.css('display', 'none');
isBoxHidden = true;
}
}
});
} catch(e) {}
}
function showBox() {
if (!setting.showBox) return;
try {
var targetDoc = top.document;
if (targetDoc.querySelector('#ne-21box')) {
flushLogs();
quotaInfo = getQuotaInfo();
updateQuotaDisplay();
return;
}
} catch(e) {}
var boxHtml = `
`;
try {
$(top.document.body).append(boxHtml);
} catch(e) {
$(document.body).append(boxHtml);
}
setTimeout(function() {
try {
var targetDoc = top.document;
if (!targetDoc.querySelector('#ne-21close')) {
targetDoc = document;
}
$('#ne-21close', targetDoc).click(function() {
$('#ne-21box', targetDoc).hide();
isBoxHidden = true;
});
var moreBtn = targetDoc.getElementById('moreSettingsBtn');
var moreSet = targetDoc.getElementById('moreSettings');
var visible = false;
if (moreBtn) {
moreBtn.onclick = function() {
moreSet.style.display = visible ? 'none' : 'block';
moreBtn.textContent = visible ? '设置' : '关闭设置';
visible = !visible;
};
}
$('input[name="videoMode"]', targetDoc).change(function() {
setting.videoMode = this.value;
GM_setValue('videoMode', setting.videoMode);
log('切换: ' + (setting.videoMode === 'simulate' ? '上报' : '播放'), 'green');
});
$('#videoRateSlider', targetDoc).on('input', function() {
$('#rateValue', targetDoc).text(parseFloat(this.value).toFixed(2));
}).on('change', function() {
var newRate = parseFloat(this.value);
setting.rate = newRate;
GM_setValue('videoRate', newRate);
if (currentVideoWorker && isVideoTaskActive) {
currentVideoWorker.postMessage({ type: 'updateRate', rate: newRate });
}
log('倍速: ' + newRate.toFixed(2) + 'x', 'green');
});
$('#showProgressBarCheck', targetDoc).change(function() {
setting.showProgressBar = this.checked ? 1 : 0;
GM_setValue('showProgressBar', setting.showProgressBar);
});
$('#goToTkBtn', targetDoc).click(function() {
GM_openInTab('', { active: true });
});
$('#saveApiKeyBtn', targetDoc).click(function() {
var key = $('#apiKeyInput', targetDoc).val();
if (key && key.trim()) {
var $testResult = $('#testResult', targetDoc);
$testResult.html('⏳ 测试中...').css('color', '#666');
testApi(key.trim(), 0).then(function(res) {
GM_setValue('api_key', key.trim());
log('验证有效', 'green');
if (res.quota_info) {
updateQuotaInfo(res.quota_info);
var remaining = res.quota_info.remaining || 0;
var freeRemaining = res.quota_info.free_remaining || 0;
$testResult.html('剩余次数: ' + remaining + ' | 免费: ' + freeRemaining).css('color', 'green');
} else {
$testResult.html('密钥有效').css('color', 'green');
}
$('#apiKeyInput', targetDoc).val('');
$('#apiKeyInput', targetDoc).attr('placeholder', '已设置');
updateQuotaDisplay();
setTimeout(function() {
$testResult.html('');
}, 5000);
}).catch(function(err) {
$testResult.html('无效: ' + err).css('color', 'red');
log('无效请联系站长: ' + err, 'red');
setTimeout(function() {
$testResult.html('');
}, 5000);
});
} else {
var existingKey = getApiKey();
if (existingKey) {
var $testResult = $('#testResult', targetDoc);
$testResult.html(' 密钥...').css('color', '#666');
testApi(existingKey, 0).then(function(res) {
if (res.quota_info) {
updateQuotaInfo(res.quota_info);
var remaining = res.quota_info.remaining || 0;
var freeRemaining = res.quota_info.free_remaining || 0;
$testResult.html(' 剩余次数: ' + remaining + ' | 免费: ' + freeRemaining).css('color', 'green');
} else {
$testResult.html(' 有效').css('color', 'green');
}
updateQuotaDisplay();
setTimeout(function() {
$testResult.html('');
}, 5000);
}).catch(function(err) {
GM_setValue('api_key', '');
quotaInfo = { remaining: 0, free_remaining: 0, recharge_balance: 0, today_free_usage: 0 };
saveQuotaInfo();
updateQuotaDisplay();
$testResult.html(' 请重新输入').css('color', 'red');
log('请重新设置', 'orange');
setTimeout(function() {
$testResult.html('');
}, 5000);
});
} else {
log(' 密钥', 'red');
$('#testResult', targetDoc).html(' 密钥').css('color', 'red');
setTimeout(function() {
$('#testResult', targetDoc).html('');
}, 3000);
}
}
});
var timeIntervalInput = targetDoc.getElementById('timeInterval');
if (timeIntervalInput) {
timeIntervalInput.addEventListener('change', function(e) {
var newTime = parseInt(e.target.value);
if (newTime >= 1000 && newTime <= 10000) {
setting.time = newTime;
localStorage.setItem('GPTJsSetting.time', newTime);
log('⚙️ 答题间隔: ' + newTime + 'ms', 'blue');
} else {
e.target.value = setting.time;
}
});
}
var settingsList = ['sub', 'force', 'examTurn', 'goodStudent', 'alterTitle', 'review'];
settingsList.forEach(function(id) {
var cb = targetDoc.getElementById('GPTJsSetting.' + id);
if (cb) {
var newCb = cb.cloneNode(true);
cb.parentNode.replaceChild(newCb, cb);
var savedValue = localStorage.getItem('GPTJsSetting.' + id);
newCb.checked = savedValue !== null ? savedValue === 'true' : setting[id];
newCb.addEventListener('change', function(e) {
var checked = e.target.checked;
var settingKey = e.target.id.replace('GPTJsSetting.', '');
setting[settingKey] = checked;
localStorage.setItem(e.target.id, checked);
log('⚙️ ' + settingKey + ' = ' + checked, 'blue');
});
}
});
var savedTime = localStorage.getItem('GPTJsSetting.time');
if (savedTime) {
setting.time = parseInt(savedTime);
if (timeIntervalInput) timeIntervalInput.value = setting.time;
}
var savedKey = getApiKey();
if (savedKey) {
$('#apiKeyInput', targetDoc).attr('placeholder', '已设置');
testApi(savedKey, 0).then(function(res) {
if (res.quota_info) {
updateQuotaInfo(res.quota_info);
}
log(' 有效', 'green');
}).catch(function(err) {
GM_setValue('api_key', '');
quotaInfo = { remaining: 0, free_remaining: 0, recharge_balance: 0, today_free_usage: 0 };
saveQuotaInfo();
updateQuotaDisplay();
log(' 重新设置', 'orange');
});
} else {
updateQuotaDisplay();
}
$('#ne-21notice', targetDoc).html('一、售后-在线客服1:3319450748(QQ) ;在线客服2:3885512520 (QQ)如遇到无法打开请联系站长
二、如果需要同时进行多门课程,请联系站长合作,一对一辅导课程,机构老师合作可优惠刷
三、支持课程:青书学堂 / 智慧职教 / U校园 / 毕业论文 / 国家开放大学 / 画课堂 / 学起 / 雨课堂/学堂云等等
');
flushLogs();
showPikaqiu();
} catch(e) {
console.error('失败:', e);
}
}, 100);
}
$(document).keydown(function(e) {
if (e.keyCode == 120) {
var $box = $('#ne-21box');
if ($box.length === 0) return;
if (isBoxHidden) {
$box.show();
isBoxHidden = false;
log(' 显示', 'green');
} else {
$box.hide();
isBoxHidden = true;
log(' 隐藏 ', 'blue');
}
}
});
function getTaskParams() {
try {
var scripts = _d.scripts;
for (let i = 0; i < scripts.length; i++) {
if (scripts[i].innerHTML.indexOf('mArg = "";') != -1 && scripts[i].innerHTML.indexOf('==UserScript==') == -1) {
return getStr(scripts[i].innerHTML.replace(/\s/g, ""), 'try{mArg=', ';}catch');
}
}
return null;
} catch(e) {
return null;
}
}
$(function() {
var savedServerIndex = GM_getValue('current_server_index', 0);
if (savedServerIndex >= 0 && savedServerIndex < API_SERVERS.length) {
CURRENT_SERVER_INDEX = savedServerIndex;
}
setting.videoMode = GM_getValue('videoMode', 'simulate');
setting.rate = GM_getValue('videoRate', 1);
setting.showProgressBar = GM_getValue('showProgressBar', 1);
var settingsMap = {
'sub': 'sub',
'force': 'force',
'examTurn': 'examTurn',
'goodStudent': 'goodStudent',
'alterTitle': 'alterTitle',
'review': 'review',
'time': 'time'
};
for (var key in settingsMap) {
var val = localStorage.getItem('GPTJsSetting.' + key);
if (val !== null) {
if (key === 'time') {
setting[settingsMap[key]] = parseInt(val);
} else {
setting[settingsMap[key]] = val === 'true';
}
}
}
_w.confirm = function() { return true; };
if (setting.decrypt) {
setTimeout(decryptFont, 2000);
setTimeout(function() {
if ($('.font-cxsecret').length > 0) {
decryptFont();
}
}, 5000);
setTimeout(function() {
if ($('.font-cxsecret').length > 0) {
decryptFont();
}
}, 10000);
}
if (_l.pathname == '/login' && setting.autoLogin) {
showBox();
waitForElement('#phone').then(() => {
$('#phone').val(setting.phone);
$('#pwd').val(setting.password);
$('#loginBtn').click();
});
} else if (_l.pathname.includes('/mycourse/studentstudy')) {
showBox();
log(' 视频模式: ' + (setting.videoMode === 'simulate' ? '模拟上报' : '正常播放') + ' | 倍速: ' + setting.rate.toFixed(2) + 'x', 'green');
} else if (_l.pathname.includes('/knowledge/cards')) {
showBox();
var params = getTaskParams();
if (!params || params == '$mArg') {
log('处理', 'red');
if (!hasTriggeredNoTaskJump) {
hasTriggeredNoTaskJump = true;
setTimeout(() => {
toNext();
}, 2000);
}
return;
}
try {
var allTasks = $.parseJSON(params).attachments;
if (!allTasks || allTasks.length <= 0) {
log(' 可处理', 'red');
if (!hasTriggeredNoTaskJump) {
hasTriggeredNoTaskJump = true;
setTimeout(() => {
toNext();
}, 2000);
}
return;
}
} catch(e) {
log(' 参数失败', 'red');
return;
}
waitForElement('.wrap .ans-cc .ans-attach-ct').then(() => {
if (top.checkJob) top.checkJob = function() { return false; };
var allTasks = $.parseJSON(params).attachments;
_defaults = $.parseJSON(params).defaults;
var pendingTasks = [];
for (var i = 0; i < allTasks.length; i++) {
var task = allTasks[i];
if (!isTaskCompleted(task)) {
pendingTasks.push(task);
} else {
var taskName = task.property?.name || task.property?.title || '任务点' + (i+1);
log('任务点 ' + taskName + ' 已完成,跳过', 'green');
}
}
pendingMissionCount = pendingTasks.length;
completedMissionCount = 0;
if (pendingMissionCount === 0) {
log(' 已完成', 'green');
setTimeout(() => {
toNext();
}, 2000);
return;
}
log('发现 ' + allTasks.length + ' 其中 ' + pendingMissionCount + ' 个待处理', 'green');
_mlist = [];
_domList = [];
$('.wrap .ans-cc .ans-attach-ct').each((i, t) => {
if (i < allTasks.length && !isTaskCompleted(allTasks[i])) {
_mlist.push(allTasks[i]);
_domList.push($(t).find('iframe'));
}
});
if (_mlist.length > 0) {
log('开始处理 ' + _mlist.length + ' 个待完成任务', 'green');
missionStart();
} else {
log('已完成', 'green');
setTimeout(() => {
toNext();
}, 2000);
}
}).catch(() => {
log('❌ 等待元素超时', 'red');
if (!hasTriggeredNoTaskJump) {
hasTriggeredNoTaskJump = true;
setTimeout(() => {
toNext();
}, 2000);
}
});
} else if (_l.pathname.includes('/exam/test/reVersionTestStartNew')) {
showBox();
waitForElement('.mark_table .whiteDiv').then(() => missonExam());
} else if (_l.pathname.includes('/mooc2/work/dowork')) {
showBox();
waitForElement('.mark_table form').then(() => missonHomeWork());
} else if (_l.pathname.includes('/work/phone/doHomeWork')) {
var _oldal = _w.alert;
_w.alert = function(msg) {
if (msg == '保存成功') return;
return _oldal(msg);
};
var _oldcf = _w.confirm;
_w.confirm = function(msg) {
if (msg.includes('确认提交') || msg.includes('未做完')) return true;
return _oldcf(msg);
};
}
});
function reinitTaskList() {
if (isProcessing) {
log(' 重新初始化', 'orange');
setTimeout(reinitTaskList, 3000);
return;
}
forceCleanupAll();
var params = getTaskParams();
if (!params || params == '$mArg') {
log(' 参数', 'red');
return;
}
try {
var allTasks = $.parseJSON(params).attachments;
if (!allTasks || allTasks.length <= 0) {
log(' 无任务点', 'red');
return;
}
_defaults = $.parseJSON(params).defaults;
var pendingTasks = [];
for (var i = 0; i < allTasks.length; i++) {
var task = allTasks[i];
if (!isTaskCompleted(task)) {
pendingTasks.push(task);
}
}
pendingMissionCount = pendingTasks.length;
if (pendingMissionCount === 0) {
log(' 已完成', 'green');
return;
}
log(' 发现 ' + pendingMissionCount + ' 个待处理任务', 'green');
_mlist = [];
_domList = [];
$('.wrap .ans-cc .ans-attach-ct').each((i, t) => {
if (i < allTasks.length && !isTaskCompleted(allTasks[i])) {
_mlist.push(allTasks[i]);
_domList.push($(t).find('iframe'));
}
});
if (_mlist.length > 0 && !isProcessing) {
log(' 剩余任务', 'green');
missionStart();
}
} catch(e) {
log(' 失败: ' + e.message, 'red');
}
}
var lastChapterUrl = _l.href;
setInterval(function() {
if (_l.href !== lastChapterUrl) {
lastChapterUrl = _l.href;
forceCleanupAll();
setTimeout(function() {
if (_l.pathname.includes('/knowledge/cards')) {
reinitTaskList();
}
}, 3000);
}
}, 2000);
window.addEventListener('beforeunload', function() {
forceCleanupAll();
});