// ==UserScript== // @name 『不知名』学习通自动学习助手-免费题库-高分题库 // @version 3.0.5 // @namespace bzm // @description 学习通助手,支持视频,作业、考试自动答题,免费高分题库填入key高速服务。 // @match *://*.chaoxing.com/* // @run-at document-end // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_info // @grant GM_getResourceText // @grant GM_openInTab // @icon http://pan-yz.chaoxing.com/favicon.ico // @original-script https://scriptcat.org/zh-CN/script-show-page/5717 // @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 // @connect tk.swk.tw // @connect so.swk.tw // @connect tk.n1t.cn //@tag 无言题库 //@tag 搜题助手 //@tag 免费搜题 //@tag 可选付费 // @antifeature payment 脚本存在第三方答题接口付费功能 //@ 如果脚本提示添加安全网址,请将脚本提示内容填写到下方区域,一行一个,如果不会,请加群询问 //@ 安全网址请填写在上方空白区域 // ==/UserScript== /*********************************自定义配置区******************************************************** */ var setting = { showBox: 1, // 显示脚本浮窗 maskImg: 1, // 显示皮卡丘 task: 0, // 只处理任务点任务 video: 1, // 处理视频 audio: 1, // 处理音频 rate: 1, // 视频/音频倍速 review: 1, // 复习模式 work: 1, // 测验自动处理 time: 5000, // 答题时间间隔(ms) sub: 0, // 测验自动提交 force: 0, // 测验强制提交 decrypt: 1, // 字体解密 examTurn: 1, // 考试自动跳转 examTurnTime: 0, // 考试自动跳转随机间隔 goodStudent: 0, // 好学生模式 alterTitle: 1, // 答案插入题目 autoLogin: 0, // 自动登录 phone: '', // 登录手机号 password: '' // 登录密码 } /**************************************************************************************************/ var _w = unsafeWindow, _l = location, _d = _w.document, $ = _w.jQuery || top.jQuery, UE = _w.UE, md5 = window.md5, Typr = window.Typr; // API配置 - 支持多个备用接口 var API_SERVERS = [ { url: "https://tk.swk.tw/api/search.php", name: "主接口" }, { url: "https://so.swk.tw/api/search.php", name: "备用接口1" }, { url: "https://tk.n1t.cn/api/search.php", name: "备用接口2" } ]; var CURRENT_SERVER_INDEX = 0; // 获取当前API URL function getCurrentApiUrl() { return API_SERVERS[CURRENT_SERVER_INDEX].url; } // 切换到下一个备用接口(不输出日志) function switchToNextApiServer() { CURRENT_SERVER_INDEX = (CURRENT_SERVER_INDEX + 1) % API_SERVERS.length; return getCurrentApiUrl(); } // 获取API密钥的函数 function getApiKey() { var key = GM_getValue('api_key', ''); return key; } // 检查是否有API密钥 function hasApiKey() { var key = getApiKey(); return key && key.trim() !== ''; } // 配额信息 - 从GM存储读取 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(); var _mlist, _defaults, _domList, $subBtn, $saveBtn, $frame_c, $okBtn; var reportUrlChange = 0; var isProcessing = false; var isBoxHidden = false; var pikaqiuAdded = false; var pendingMissionCount = 0; // 待处理任务点计数 var completedMissionCount = 0; // 已完成任务点计数 var isJumping = false; // 是否正在跳转 var currentProcessingTask = null; // 当前正在处理的任务 var totalMissionCount = 0; // 总任务点数量 // 日志队列 var logQueue = []; var logTimer = null; // 答案分割函数 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; } // 保存配额信息到GM存储 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('⚠️ 请先设置API密钥'); } else { $quotaInfo.html('📊 剩余次数: 加载中...'); } } } catch(e) {} } 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); } // 显示皮卡丘 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) {} } $(document).keydown(function(e) { if (e.keyCode == 120) { var $box = $('#ne-21box'); if ($box.length === 0) return; if (isBoxHidden) { $box.css('display', 'block'); $box.css('opacity', '1'); isBoxHidden = false; log('📌 面板已显示', 'green'); } else { $box.css('display', 'none'); isBoxHidden = true; log('📌 面板已隐藏,按F9键恢复显示', 'blue'); } } }); // 测试API密钥(支持多接口) 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 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; } // ========== getAnswer 函数(支持多接口备用,静默切换) ========== 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('❌ 请先设置API密钥才能使用自动答题功能', 'red'); reject('NO_API_KEY'); return; } quotaInfo = getQuotaInfo(); if (quotaInfo.remaining <= 0 && quotaInfo.free_remaining <= 0) { log('❌ API次数已用完,无法获取答案', '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 serverName = API_SERVERS[index].name; 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) { // API密钥无效,不需要切换接口 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 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 { var parentHtml = $(this).parent().html() || ''; uniqueIdentifiers.add($(this).index() + '_' + parentHtml.substring(0, 50)); } }); 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; } } var $pcInputs = $question.find('.Zy_ulTk .XztiHover1 textarea, .stem_answer .Answer .divText .textDIV textarea, .subEditor textarea'); if ($pcInputs.length) { var uniquePCInputs = new Set(); $pcInputs.each(function() { var id = $(this).attr('id'); var name = $(this).attr('name'); if (id) { uniquePCInputs.add(id); } else if (name) { uniquePCInputs.add(name); } else { uniquePCInputs.add($(this).index()); } }); count = uniquePCInputs.size; if (count > 0) { return count; } } if (count === 0) { return 1; } return 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); } }); log(`📝 找到 ${uniqueInputs.length} 个填空输入框,准备填写`, 'blue'); $(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; } var $editorBlocks = $question.find('[data-editorindex]'); if ($editorBlocks.length) { var uniqueEditors = []; var seenIndices = new Set(); $editorBlocks.each(function() { var idx = $(this).attr('data-editorindex'); if (idx && !seenIndices.has(idx)) { seenIndices.add(idx); uniqueEditors.push(this); } }); log(`📝 找到 ${uniqueEditors.length} 个编辑器,准备填写`, 'blue'); uniqueEditors.forEach(function(editor, i) { var editorIndex = $(editor).attr('data-editorindex'); var itemId = $(editor).attr('data-itemid'); setTimeout(() => { try { var ueditor = null; if (contextWindow && contextWindow.editors && contextWindow.editors[editorIndex]) { ueditor = contextWindow.editors[editorIndex].ueditor; } if (!ueditor && contextWindow && contextWindow.UE && contextWindow.UE.instants) { var instantKey = 'ueditorInstant' + editorIndex; ueditor = contextWindow.UE.instants[instantKey]; } if (!ueditor && itemId && contextWindow && contextWindow.UE && contextWindow.UE.getEditor) { ueditor = contextWindow.UE.getEditor('ananas-editor-answer' + itemId); } if (ueditor) { var answerValue = answerList[i] !== undefined ? answerList[i] : (answerList[0] || ''); ueditor.setContent(answerValue); log(`✅ 填空题第${i+1}空已填写: ${answerValue}`, 'green'); } if (itemId) { var answerValue = answerList[i] !== undefined ? answerList[i] : (answerList[0] || ''); $('#answer' + itemId).val(answerValue).trigger('change'); } } catch(e) {} }, i * 300); }); 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); } }); log(`📝 找到 ${uniquePCInputs.length} 个填空输入框 (PC),准备填写`, 'blue'); $(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 $editorBlocks = $question.find('[data-editorindex]'); if ($editorBlocks.length) { $editorBlocks.each(function(i) { var editorIndex = $(this).attr('data-editorindex'); var itemId = $(this).attr('data-itemid'); setTimeout(() => { try { var ueditor = null; if (contextWindow && contextWindow.editors && contextWindow.editors[editorIndex]) { ueditor = contextWindow.editors[editorIndex].ueditor; } if (!ueditor && contextWindow && contextWindow.UE && contextWindow.UE.instants) { var instantKey = 'ueditorInstant' + editorIndex; ueditor = contextWindow.UE.instants[instantKey]; } if (!ueditor && itemId && contextWindow && contextWindow.UE && contextWindow.UE.getEditor) { ueditor = contextWindow.UE.getEditor('ananas-editor-answer' + itemId); } if (ueditor) { ueditor.setContent(answer); log('✅ 简答题答案已填写', 'green'); } if (itemId) { $('#answer' + itemId).val(answer).trigger('change'); } } catch(e) {} }, 300); }); return true; } 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; } 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 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 getStr(str, start, end) { let res = str.match(new RegExp(`${start}(.*?)${end}`)); return res ? res[1] : null; } function parseUrlParams() { let query = window.location.search.substring(1); let vars = query.split("&"); let _p = {}; for (let i = 0; i < vars.length; i++) { let pair = vars[i].split("="); _p[pair[0]] = pair[1]; } return _p; } function getElement(parent, selector, timeout = 10000) { return new Promise(resolve => { var result = parent.querySelector(selector); if (result) return resolve(result); var timer; var observer = new MutationObserver(mutations => { for (var mutation of mutations) { for (var node of mutation.addedNodes) { if (node instanceof Element) { result = node.matches(selector) ? node : node.querySelector(selector); if (result) { observer.disconnect(); timer && clearTimeout(timer); return resolve(result); } } } } }); observer.observe(parent, { childList: true, subtree: true }); timer = setTimeout(() => { observer.disconnect(); resolve(null); }, timeout); }); } function getTaskParams() { try { var _iframeScripts = _d.scripts; for (let i = 0; i < _iframeScripts.length; i++) { if (_iframeScripts[i].innerHTML.indexOf('mArg = "";') != -1 && _iframeScripts[i].innerHTML.indexOf('==UserScript==') == -1) { var _p = getStr(_iframeScripts[i].innerHTML.replace(/\s/g, ""), 'try{mArg=', ';}catch'); return _p; } } return null; } catch (e) { return null; } } // 检查任务点是否真正完成 function isTaskCompleted(task) { if (!task) return false; // 如果有 isPassed 字段且为 true,表示已完成 if (task.isPassed === true) return true; // 如果有 status 字段 if (task.status === 'completed' || task.status === 'finished') return true; // 如果有 finished 字段 if (task.finished === true) return true; return false; } // 跳转到下一个任务点,确保当前任务点真正完成后再跳转 function toNext() { if (isJumping) return; isJumping = true; // 更新已完成计数 completedMissionCount++; log(`📊 任务进度: ${completedMissionCount}/${pendingMissionCount}`, 'blue'); // 检查是否所有任务点都已完成 if (completedMissionCount >= pendingMissionCount && pendingMissionCount > 0) { log('✅ 所有任务点已完成!准备跳转到下一章节', 'green'); // 查找下一章节按钮 var nextBtn = null; try { nextBtn = top.document.querySelector('#mainid > .prev_next.next') || top.document.querySelector('#prevNextFocusNext') || $('.prev_next.next')[0]; if (nextBtn && !nextBtn.disabled) { log('✅ 找到下一节按钮,3秒后跳转', 'green'); setTimeout(() => { nextBtn.click(); log('📖 已点击跳转按钮', 'green'); }, 3000); } else { log('📚 课程已全部完成,无更多任务点', 'green'); } } catch(e) { log('❌ 跳转失败: ' + e.message, 'red'); } isProcessing = false; isJumping = false; return; } // 还有任务未完成,继续处理下一个 if (completedMissionCount < pendingMissionCount) { log(`🔄 还有 ${pendingMissionCount - completedMissionCount} 个任务待处理,继续...`, 'blue'); isProcessing = false; isJumping = false; setTimeout(switchMission, 3000); } else { isProcessing = false; isJumping = false; } } function switchMission() { if (_mlist.length <= 0) { log('✅ 此页面任务处理完毕', 'green'); isProcessing = false; // 检查是否还有待处理任务 if (completedMissionCount < pendingMissionCount) { //log(`⚠️ 警告:还有 ${pendingMissionCount - completedMissionCount} 个任务未完成,但任务列表为空`, 'orange'); } // 任务列表为空,说明所有任务都已处理,触发跳转 toNext(); return; } isProcessing = false; setTimeout(missionStart, 3000); } // ========== 任务处理 ========== function missionStart() { if (isProcessing) return; if (_mlist.length <= 0) { log('✅ 此页面任务处理完毕', 'green'); isProcessing = false; toNext(); return; } isProcessing = true; var _type = _mlist[0]['type']; var _dom = _domList[0]; var _task = _mlist[0]; currentProcessingTask = _task; if (_type == undefined) { _type = _mlist[0]['property']["module"]; } 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'); switchMission(); } else { log(`⚠️ 暂不支持处理此类型:${_type},跳过。`, 'red'); switchMission(); } } function missionVideo(dom, obj) { if (!setting.video) { log('ℹ️ 用户设置不处理视频任务', 'orange'); isProcessing = false; return setTimeout(switchMission, 3000); } var { isPassed, property } = obj; var { name } = property; // 检查任务是否已完成 if (isTaskCompleted(obj)) { log(`✅ 视频:${name} 已完成,跳过`, 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; return setTimeout(switchMission, 1000); } var target = dom.length > 0 ? dom[0] : null; if (!target) { log('⚠️ 未找到视频iframe,3秒后重试', 'orange'); isProcessing = false; return setTimeout(() => missionVideo(dom, obj), 3000); } log(`🎬 处理视频:${name}`, 'purple'); var executed = false; var doc = target.contentDocument || target.contentWindow.document; var intervalId = setInterval(() => { 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 resume = () => { if (media.paused) media.play(); }; media.addEventListener('pause', resume); if (media.parentElement) media.parentElement.addEventListener('mouseleave', resume); media.addEventListener('ended', () => { log(`✅ ${name} 播放完成`, 'green'); media.removeEventListener('pause', resume); clearInterval(intervalId); // 标记任务完成并移除 _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(switchMission, 1000); }); } }, 2500); } function missionAudio(dom, obj) { if (!setting.audio) { log('ℹ️ 用户设置不处理音频任务', 'orange'); isProcessing = false; return setTimeout(switchMission, 3000); } var { isPassed, property } = obj; var { name } = property; if (isTaskCompleted(obj)) { log(`✅ 音频:${name} 已完成,跳过`, 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; return setTimeout(switchMission, 1000); } log(`🎵 处理音频:${name},等待3秒后完成`, 'purple'); // 模拟完成,移除任务 setTimeout(() => { _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(switchMission, 1000); }, 3000); } 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'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; return setTimeout(switchMission, 1000); } $.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'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; switchMission(); }, error: function() { log(`❌ 读书:${name} 处理失败,3秒后重试`, 'red'); isProcessing = false; setTimeout(() => 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'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; return setTimeout(switchMission, 1000); } $.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'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; switchMission(); }, error: function() { log(`❌ 文档:${name} 处理失败,3秒后重试`, 'red'); isProcessing = false; setTimeout(() => 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'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; return setTimeout(switchMission, 1000); } $.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'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; switchMission(); }, error: function() { log(`❌ 阅读:${name} 处理失败,3秒后重试`, 'red'); isProcessing = false; setTimeout(() => missionRead(dom, obj), 3000); } }); } function missionWork(dom, obj) { if (!setting.work) { log('ℹ️ 用户设置不自动处理测验', 'orange'); isProcessing = false; return switchMission(); } if (!checkApiKeyBeforeAction('自动答题')) { isProcessing = false; return switchMission(); } 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(() => { startDoPhoneCyWork(0, dom, phoneWeb, obj); }, 3000); } else { setTimeout(() => { startDoCyWork(0, dom, obj); }, 3000); } } else { log('ℹ️ 用户设置只处理属于任务点的任务', 'orange'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; switchMission(); } } function startDoPhoneCyWork(index, doms, phoneWeb, taskObj) { if (index == doms.length) { log('✅ 此页面全部测验已处理完毕', 'green'); // 测验完成后移除任务 _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(switchMission, 5000); return; } getElement($(doms[index]).contents()[0], 'iframe').then(iframe => { if (!iframe) { setTimeout(() => 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(() => { setTimeout(() => doPhoneWork(workIframe.contents(), taskObj), 3000); }); } else if (workStatus.indexOf('待批阅') != -1) { _mlist.splice(0, 1); _domList.splice(0, 1); log('⚠️ 测验待批阅,跳过', 'red'); isProcessing = false; setTimeout(() => startDoPhoneCyWork(index + 1, doms, phoneWeb, taskObj), 5000); } else if (workStatus.indexOf('已完成') != -1 || workStatus.indexOf('已交') != -1) { log('✅ 测验已完成,跳过', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => startDoPhoneCyWork(index + 1, doms, phoneWeb, taskObj), 5000); } else { _mlist.splice(0, 1); _domList.splice(0, 1); log('⚠️ 未知状态,跳过', 'red'); isProcessing = false; setTimeout(() => startDoPhoneCyWork(index + 1, doms, phoneWeb, taskObj), 5000); } }); } 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 startDoPhoneTimu(index, TimuList, taskObj) { if (index == TimuList.length) { if (setting.sub) { log('✅ 测验处理完成,准备自动提交。', 'green'); setTimeout(() => { $subBtn.click(); setTimeout(() => { $okBtn.click(); log('✅ 提交成功', 'green'); // 提交成功后移除任务 _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => switchMission(), 3000); }, 3000); }, 5000); } else if (setting.force) { log('⚠️ 存在无答案题目,强制提交', 'red'); setTimeout(() => { $subBtn.click(); setTimeout(() => { $okBtn.click(); log('✅ 提交成功', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => switchMission(), 3000); }, 3000); }, 5000); } else { log('💾 测验处理完成,自动保存', 'green'); setTimeout(() => { $saveBtn.click(); setTimeout(() => { log('✅ 保存成功', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => switchMission(), 3000); }, 3000); }, 5000); } return; } var contextWindow = TimuList[index] ? (TimuList[index].ownerDocument.defaultView || unsafeWindow) : unsafeWindow; var questionFull = $(TimuList[index]).find('.Py-m1-title').html(); var _question = tidyQuestion(questionFull).replace(/.*?\[.*?题\]\s*\n\s*/, '').trim(); var typeName = questionFull.match(/.*?\[(.*?)]|$/)[1]; var typeMap = { '单选题': 0, '多选题': 1, '填空题': 2, '判断题': 3, '简答题': 4 }; var _type = typeMap[typeName]; if (_type === undefined) { if ($(TimuList[index]).find('.answerList.singleChoice li').length) _type = 0; else if ($(TimuList[index]).find('.answerList.multiChoice li').length) _type = 1; else if ($(TimuList[index]).find('.blankList2 input').length) _type = 2; else if ($(TimuList[index]).find('.answerList.panduan li').length) _type = 3; else if ($(TimuList[index]).find('textarea').length) _type = 4; } var checkAnswered = function() { if (_type == 0 || _type == 1) { var $opts = _type == 0 ? $(TimuList[index]).find('.answerList.singleChoice li') : $(TimuList[index]).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 = $(TimuList[index]).find('.blankList2 input'); if ($inputs.length && $inputs.first().val() && $inputs.first().val().trim() !== '') return true; var $editorBlocks = $(TimuList[index]).find('[data-editorindex]'); if ($editorBlocks.length) { var hasContent = false; $editorBlocks.each(function() { var itemId = $(this).attr('data-itemid'); if (itemId && $('#answer' + itemId).val() && $('#answer' + itemId).val().trim() !== '') { hasContent = true; } }); if (hasContent) return true; } } else if (_type == 3) { var $pd = $(TimuList[index]).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 = $(TimuList[index]).find('textarea[name^="answer"]'); if ($ta.length && $ta.first().val() && $ta.first().val().trim() !== '') return true; var $editorBlocks = $(TimuList[index]).find('[data-editorindex]'); if ($editorBlocks.length) { var hasContent = false; $editorBlocks.each(function() { var itemId = $(this).attr('data-itemid'); if (itemId && $('#answer' + itemId).val() && $('#answer' + itemId).val().trim() !== '') { hasContent = true; } }); if (hasContent) return true; } } return false; }; if (checkAnswered()) { 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 ? $(TimuList[index]).find('.answerList.singleChoice li') : $(TimuList[index]).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($(TimuList[index])); optionsData = [blankCount.toString()]; log(`📝 填空题传入空数量: ${blankCount}`, 'blue'); } else if (_type == 3) { optionsData = ["对", "错"]; log(`📝 判断题传入固定选项: ["对","错"]`, 'blue'); } else if (_type == 4) { optionsData = ["1"]; log(`📝 简答题传入固定参数: ["1"]`, 'blue'); } getAnswer(_type, pureQuestion, optionsData).then((agrs) => { if (agrs == '暂无答案') { log('⚠️ 无法匹配正确答案,跳过此题', 'red'); setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), setting.time); return; } if (setting.alterTitle) { $(TimuList[index]).find('.Py-m1-title').html($(TimuList[index]).find('.Py-m1-title').html() + `

📖 ${agrs}

`); } if (_type == 0) { var idx = optsText.findIndex(t => t == agrs); if (idx != -1) $(TimuList[index]).find('.answerList.singleChoice li').eq(idx).click(); } 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($(TimuList[index]), agrs, true, contextWindow); } else if (_type == 3) { var isTrue = ['正确','是','对','√','T','ri'].some(k => agrs.includes(k)); var $pd = $(TimuList[index]).find('.answerList.panduan li'); $pd.each((i, t) => { if ((isTrue && $(t).attr('val-param') == 'true') || (!isTrue && $(t).attr('val-param') == 'false')) { $(t).click(); } }); } else if (_type == 4) { fillShortAnswer($(TimuList[index]), agrs, true, contextWindow); } log(`✅ 第${index + 1}题自动答题成功`, 'green'); setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), setting.time); }).catch(() => { setTimeout(() => startDoPhoneTimu(index + 1, TimuList, taskObj), setting.time); }); } function startDoCyWork(index, doms, taskObj) { if (index == doms.length) { log('✅ 此页面全部测验已处理完毕', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(switchMission, 5000); return; } getElement($(doms[index]).contents()[0], 'iframe').then(iframe => { if (!iframe) { setTimeout(() => 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(() => doWork(index, doms, iframe, taskObj), 5000); } else if (workStatus.indexOf('待批阅') != -1) { _mlist.splice(0, 1); _domList.splice(0, 1); log('⚠️ 测验待批阅,跳过', 'red'); isProcessing = false; setTimeout(() => startDoCyWork(index + 1, doms, taskObj), 5000); } else if (workStatus.indexOf('已完成') != -1 || workStatus.indexOf('已交') != -1) { log('✅ 测验已完成,跳过', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => startDoCyWork(index + 1, doms, taskObj), 5000); } else { _mlist.splice(0, 1); _domList.splice(0, 1); log('⚠️ 未知状态,跳过', 'red'); isProcessing = false; setTimeout(() => startDoCyWork(index + 1, doms, taskObj), 5000); } }); } 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(index, doms, 0, TiMuList, taskObj); } function startDoWork(index, doms, c, TiMuList, taskObj) { if (c == TiMuList.length) { if (setting.sub) { log('✅ 测验处理完成,准备自动提交。', 'green'); setTimeout(() => { $subBtn.click(); setTimeout(() => { $frame_c.find('#confirmSubWin > div > div > a.bluebtn').click(); log('✅ 提交成功', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => startDoCyWork(index + 1, doms, taskObj), 3000); }, 3000); }, 5000); } else if (setting.force) { log('⚠️ 存在无答案题目,强制提交', 'red'); setTimeout(() => { $subBtn.click(); setTimeout(() => { $frame_c.find('#confirmSubWin > div > div > a.bluebtn').click(); log('✅ 提交成功', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => startDoCyWork(index + 1, doms, taskObj), 3000); }, 3000); }, 5000); } else { log('💾 测验处理完成,自动保存', 'green'); setTimeout(() => { $saveBtn.click(); setTimeout(() => { log('✅ 保存成功', 'green'); _mlist.splice(0, 1); _domList.splice(0, 1); isProcessing = false; setTimeout(() => startDoCyWork(index + 1, doms, taskObj), 3000); }, 3000); }, 5000); } return; } var questionFull = $(TiMuList[c]).find('.Zy_TItle.clearfix > div').html(); var _question = tidyQuestion(questionFull); var typeName = questionFull.match(/^【(.*?)】|$/)[1]; var typeMap = { '单选题': 0, '多选题': 1, '填空题': 2, '判断题': 3, '简答题': 4 }; var _TimuType = typeMap[typeName]; if (_TimuType === undefined) { if ($(TiMuList[c]).find('.Zy_ulTop li').length) { _TimuType = $(TiMuList[c]).find('input[type="checkbox"]').length ? 1 : 0; } else if ($(TiMuList[c]).find('.Zy_ulTk .XztiHover1').length) { _TimuType = 2; } else { _TimuType = 4; } } var $opts = []; var optsText = []; var optionsData = []; var pureQuestion = _question; if (_TimuType == 0 || _TimuType == 1) { $opts = $(TiMuList[c]).find('.Zy_ulTop li a'); $opts.each(function() { optsText.push(tidyStr($(this).html())); }); optionsData = optsText; } else if (_TimuType == 2) { var blankCount = getBlankInputCount($(TiMuList[c])); optionsData = [blankCount.toString()]; log(`📝 填空题传入空数量: ${blankCount}`, 'blue'); } else if (_TimuType == 3) { optionsData = ["对", "错"]; log(`📝 判断题传入固定选项: ["对","错"]`, 'blue'); } else if (_TimuType == 4) { optionsData = ["1"]; log(`📝 简答题传入固定参数: ["1"]`, 'blue'); } getAnswer(_TimuType, pureQuestion, optionsData).then((agrs) => { if (setting.alterTitle) { $(TiMuList[c]).find('.Zy_TItle.clearfix > div').html($(TiMuList[c]).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($(TiMuList[c]), agrs, false, null); } else if (_TimuType == 3) { var isTrue = ['正确','是','对','√','T','ri'].some(k => agrs.includes(k)); $opts.each((i, t) => { var txt = tidyStr($(t).html()); if ((isTrue && (txt == '对' || txt == '√' || txt == '正确')) || (!isTrue && (txt == '错' || txt == '×' || txt == '错误'))) { $($opts[i]).parent().click(); } }); } else if (_TimuType == 4) { fillShortAnswer($(TiMuList[c]), agrs, false, null); } setTimeout(() => startDoWork(index, doms, c + 1, TiMuList, taskObj), setting.time); }).catch(() => { setTimeout(() => startDoWork(index, doms, c + 1, TiMuList, taskObj), setting.time); }); } // ========== 作业处理 ========== function missonHomeWork() { log('📝 开始处理作业', 'green'); if (!checkApiKeyBeforeAction('作业自动答题')) return; var $_homeworktable = $('.mark_table').find('form'); var TimuList = $_homeworktable.find('.questionLi'); doHomeWork(0, TimuList); } function doHomeWork(index, TiMuList) { if (index == TiMuList.length) { log('✅ 作业题目已全部完成', 'green'); return; } var typeName = $(TiMuList[index]).attr('typename'); var typeMap = { '单选题': 0, '多选题': 1, '填空题': 2, '判断题': 3, '简答题': 4 }; var _type = typeMap[typeName]; var _questionFull = $(TiMuList[index]).find('.mark_name').html(); var _question = tidyQuestion(_questionFull).replace(/^[(].*?[)]/, '').trim(); if (_type === undefined) { var _answerTmpArr = $(TiMuList[index]).find('.stem_answer').find('.answer_p'); if (_answerTmpArr && _answerTmpArr.length > 0) { _type = $(TiMuList[index]).find('input[type="checkbox"]').length ? 1 : 0; } else if ($(TiMuList[index]).find('.stem_answer').find('.divText textarea').length) { _type = 4; } } var checkAnswered = function() { if (_type == 0 || _type == 1) { var $opts = $(TiMuList[index]).find('.stem_answer .answer_p'); for (var i = 0; i < $opts.length; i++) { if ($($opts[i]).parent().find('span').attr('class') && $($opts[i]).parent().find('span').attr('class').indexOf('check_answer') != -1) { return true; } } } else if (_type == 2) { var $inputs = $(TiMuList[index]).find('.stem_answer .Answer .divText .textDIV textarea'); if ($inputs.length && $inputs.val() && $inputs.val().trim() !== '') return true; } else if (_type == 3) { var $opts = $(TiMuList[index]).find('.stem_answer .answer_p'); for (var i = 0; i < $opts.length; i++) { if ($($opts[i]).parent().find('span').attr('class') && $($opts[i]).parent().find('span').attr('class').indexOf('check_answer') != -1) { return true; } } } else if (_type == 4) { var $ta = $(TiMuList[index]).find('.stem_answer .eidtDiv textarea'); if ($ta.length && $ta.val() && $ta.val().trim() !== '') return true; } return false; }; if (checkAnswered()) { log(`📌 第${index + 1}题已作答,跳过`, 'green'); setTimeout(() => doHomeWork(index + 1, TiMuList), 30); return; } var $opts = []; var optsText = []; var optionsData = []; var pureQuestion = _question; if (_type == 0 || _type == 1) { $opts = $(TiMuList[index]).find('.stem_answer .answer_p'); $opts.each(function() { optsText.push(tidyStr($(this).html())); }); optionsData = optsText; } else if (_type == 2) { var blankCount = getBlankInputCount($(TiMuList[index])); optionsData = [blankCount.toString()]; log(`📝 填空题传入空数量: ${blankCount}`, 'blue'); } else if (_type == 3) { optionsData = ["对", "错"]; log(`📝 判断题传入固定选项: ["对","错"]`, 'blue'); } else if (_type == 4) { optionsData = ["1"]; log(`📝 简答题传入固定参数: ["1"]`, 'blue'); } getAnswer(_type, pureQuestion, optionsData).then((agrs) => { if (setting.alterTitle) { $(TiMuList[index]).find('.mark_name').html($(TiMuList[index]).find('.mark_name').html() + `

📖 ${agrs}

`); } if (_type == 0) { var idx = optsText.findIndex(t => t == agrs); if (idx != -1) $($opts[idx]).parent().click(); } else if (_type == 1) { var ansArr = splitAnswer(agrs); $opts.each((i, t) => { if (ansArr.includes(optsText[i])) { setTimeout(() => $($opts[i]).parent().click(), 300); } }); } else if (_type == 2) { fillBlankAnswer($(TiMuList[index]), agrs, false, null); } else if (_type == 3) { var isTrue = ['正确','是','对','√','T','ri'].some(k => agrs.includes(k)); $opts.each((i, t) => { var txt = tidyStr($(t).html()); if ((isTrue && (txt == '对' || txt == '√' || txt == '正确')) || (!isTrue && (txt == '错' || txt == '×' || txt == '错误'))) { $($opts[i]).parent().click(); } }); } else if (_type == 4) { fillShortAnswer($(TiMuList[index]), agrs, false, null); } log(`✅ 第${index + 1}题自动答题成功`, 'green'); setTimeout(() => doHomeWork(index + 1, TiMuList), setting.time); }).catch(() => { setTimeout(() => doHomeWork(index + 1, TiMuList), setting.time); }); } // ========== 考试处理 ========== function missonExam() { if (!checkApiKeyBeforeAction('考试自动答题')) return; var $_examtable = $('.mark_table').find('.whiteDiv'); var _questionFull = tidyStr($_examtable.find('h3.mark_name').html().trim()); var typeName = _questionFull.match(/[(](.*?),.*?分[)]|$/)[1]; var typeMap = { '单选题': 0, '多选题': 1, '填空题': 2, '判断题': 3, '简答题': 4 }; var _qType = typeMap[typeName]; var _question = tidyQuestion(_questionFull.replace(/[(].*?分[)]/, '').replace(/^\s*/, '')); var $_ansdom = $_examtable.find('#submitTest').find('.stem_answer'); if (_qType === undefined) { var $opts = $_ansdom.find('.clearfix.answerBg .fl.answer_p'); if ($opts.length) { _qType = $_ansdom.find('input[type="checkbox"]').length ? 1 : 0; } else if ($_ansdom.find('.Answer .divText .subEditor textarea').length) { _qType = 4; } } var checkAnswered = function() { if (_qType == 0 || _qType == 1) { var $opts = $_ansdom.find('.clearfix.answerBg .fl.answer_p'); for (var i = 0; i < $opts.length; i++) { if ($($opts[i]).parent().find('span').attr('class') && $($opts[i]).parent().find('span').attr('class').indexOf('check_answer') != -1) { return true; } } } else if (_qType == 2) { var $inputs = $_ansdom.find('.Answer .divText .subEditor textarea'); if ($inputs.length && $inputs.val() && $inputs.val().trim() !== '') return true; } else if (_qType == 4) { var $ta = $_ansdom.find('.subEditor textarea'); if ($ta.length && $ta.val() && $ta.val().trim() !== '') return true; } return false; }; if (checkAnswered()) { log('📌 此题已作答,跳过', 'green'); toNextExam(); return; } var $opts = []; var optsText = []; var optionsData = []; var pureQuestion = _question; if (_qType == 0 || _qType == 1) { $opts = $_ansdom.find('.clearfix.answerBg .fl.answer_p'); $opts.each(function() { optsText.push(tidyStr($(this).html())); }); optionsData = optsText; } else if (_qType == 2) { var blankCount = getBlankInputCount($_ansdom); optionsData = [blankCount.toString()]; log(`📝 填空题传入空数量: ${blankCount}`, 'blue'); } else if (_qType == 4) { optionsData = ["1"]; log(`📝 简答题传入固定参数: ["1"]`, 'blue'); } getAnswer(_qType, pureQuestion, optionsData).then((agrs) => { if (setting.alterTitle) { $_examtable.find('h3.mark_name').html($_examtable.find('h3.mark_name').html() + `📖 ${agrs}`); } if (_qType == 0) { var idx = optsText.findIndex(t => t == agrs); if (idx != -1) { var $target = $($opts[idx]).parent(); if (setting.goodStudent) { $target.find('span').css('font-weight', 'bold'); log('📝 好学生模式:答案已加粗,未自动选择', 'blue'); } else { $target.click(); } } setTimeout(() => toNextExam(), setting.time); } else if (_qType == 1) { var ansArr = splitAnswer(agrs); $opts.each((i, t) => { if (ansArr.includes(optsText[i])) { if (setting.goodStudent) { $($opts[i]).parent().find('span').css('font-weight', 'bold'); } else { setTimeout(() => $($opts[i]).parent().click(), 300); } } }); setTimeout(() => toNextExam(), setting.time); } else if (_qType == 2) { fillBlankAnswer($_ansdom, agrs, false, null); setTimeout(() => toNextExam(), setting.time); } else if (_qType == 4) { fillShortAnswer($_ansdom, agrs, false, null); setTimeout(() => toNextExam(), setting.time); } log('✅ 自动答题成功', 'green'); }).catch(() => { setTimeout(() => toNextExam(), setting.time); }); } 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 decryptFont() { if (typeof Typr === 'undefined') return; 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++) { var glyph = Typr.U.codeToGlyph(font, i); if (!glyph) continue; var path = Typr.U.glyphToPath(font, glyph); var hash = md5(JSON.stringify(path)).slice(24); match[i] = table[hash]; } $('.font-cxsecret').html(function(idx, html) { $.each(match, function(key, value) { html = html.replace(new RegExp(String.fromCharCode(key), 'g'), String.fromCharCode(value)); }); return html; }).removeClass('font-cxsecret'); } 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 showBox() { if (!setting.showBox) return; try { var topDoc = top.document; if (topDoc.querySelector('#ne-21box')) { flushLogs(); quotaInfo = getQuotaInfo(); updateQuotaDisplay(); return; } } catch(e) {} var boxHtml = `

📚 学习通助手 ₙ₁ᵗ

[F9隐藏]
🔑 API配置
📊 剩余次数: 加载中...
`; 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() { var $box = $('#ne-21box', targetDoc); $box.css('display', 'none'); 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; }; } var goToTkBtn = targetDoc.getElementById('goToTkBtn'); if (goToTkBtn) { goToTkBtn.onclick = function() { GM_openInTab('https://tk.swk.tw', { 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(`✅ API密钥已保存`, 'green'); if (res.quota_info) { updateQuotaInfo(res.quota_info); } $testResult.html('✅ 密钥有效').css('color', 'green'); $('#apiKeyInput', targetDoc).val(''); $('#apiKeyInput', targetDoc).attr('placeholder', '已设置'); setTimeout(function() { $testResult.html(''); }, 3000); }).catch(function(err) { $testResult.html('❌ 密钥无效').css('color', 'red'); log(`❌ API密钥无效`, 'red'); setTimeout(function() { $testResult.html(''); }, 3000); }); } else { log('❌ 请输入API密钥', 'red'); } }); 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']; 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('✅ API密钥有效', 'green'); }).catch(function(err) { GM_setValue('api_key', ''); quotaInfo = { remaining: 0, free_remaining: 0, recharge_balance: 0, today_free_usage: 0 }; saveQuotaInfo(); updateQuotaDisplay(); log('⚠️ API密钥已失效,请重新设置', 'orange'); }); } else { updateQuotaDisplay(); } $('#ne-21notice', targetDoc).html(`
💡 脚本已加载 | F9隐藏/显示 | 答题间隔${setting.time/1000}秒
`); flushLogs(); showPikaqiu(); } catch(e) { console.error('绑定事件失败:', e); } }, 100); } // 页面初始化 $(function() { // 恢复上次使用的接口索引 var savedServerIndex = GM_getValue('current_server_index', 0); if (savedServerIndex >= 0 && savedServerIndex < API_SERVERS.length) { CURRENT_SERVER_INDEX = savedServerIndex; } var settingsMap = { 'sub': 'sub', 'force': 'force', 'examTurn': 'examTurn', 'goodStudent': 'goodStudent', 'alterTitle': 'alterTitle', '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'; } } } $('.navshow').find('a:contains(体验新版)')[0] && $('.navshow').find('a:contains(体验新版)')[0].click(); setting.decrypt && decryptFont(); 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('✅ 初始化完毕!', 'green'); // 注意:这里不再自动跳转,让用户手动进入课程 // 用户需要点击进入课程页面,脚本会在课程页面自动处理任务 } else if (_l.pathname.includes('/knowledge/cards')) { showBox(); var params = getTaskParams(); if (!params || params == '$mArg' || $.parseJSON(params)['attachments'].length <= 0) { log('⚠️ 无任务点可处理', 'red'); } else { waitForElement('.wrap .ans-cc .ans-attach-ct').then(() => { top.checkJob ? top.checkJob = () => false : true; var allTasks = $.parseJSON(params)['attachments']; _defaults = $.parseJSON(params)['defaults']; _domList = []; // 统计待处理任务点数量(排除已完成的) 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'); } } totalMissionCount = allTasks.length; pendingMissionCount = pendingTasks.length; completedMissionCount = 0; log(`📋 发现 ${totalMissionCount} 个任务点,其中 ${pendingMissionCount} 个待处理`, 'green'); // 重新构建待处理列表 _mlist = []; var newDomList = []; var domIndex = 0; $('.wrap .ans-cc .ans-attach-ct').each((i, t) => { if (i < allTasks.length && !isTaskCompleted(allTasks[i])) { _mlist.push(allTasks[i]); newDomList.push($(t).find('iframe')); } domIndex++; }); _domList = newDomList; if (_mlist.length > 0) { log(`🚀 开始处理 ${_mlist.length} 个待完成任务点`, 'green'); missionStart(); } else { log('✅ 所有任务点已完成', 'green'); // 所有任务已完成,触发跳转 setTimeout(() => { var nextBtn = top.document.querySelector('#mainid > .prev_next.next') || top.document.querySelector('#prevNextFocusNext') || $('.prev_next.next')[0]; if (nextBtn && !nextBtn.disabled) { log('🔄 所有任务已完成,准备跳转到下一章节', 'green'); setTimeout(() => { nextBtn.click(); }, 2000); } }, 2000); } }).catch(() => log('❌ 等待元素超时', 'red')); } } 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); }; } });