// ==UserScript== // @name 广开大学英语B // @namespace https://course.ougd.cn/ // @version 1.0 // @description 1234 // @author Assistant // @match *://course.ougd.cn/* // @icon none // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // ========== 1. 答案库配置(根据cmid或标题精确对应) ========== // 第一次大作业(判断题使用文本 True/False) const QUIZ1_ANSWERS = { "1": "My pleasure", "2": "Pleased to meet you", "3": "Oh thanks. I got it yesterday", "4": "I'm fine. Thank you.", "5": "a happy journey", "6": "True", "7": "True", "8": "True", "9": "False", "10": "False", "11": "The Statue of Liberty", "12": "something that you can see", "13": "in France", "14": "go to the top", "15": "Bartholdi", "16": "sight", "17": "hardly", "18": "occurred", "19": "due", "20": "decisions", "21": "At", "22": "idea", "23": "varying", "24": "when", "25": "going to" }; // 第二次大作业(保持原有格式:前2题文本,3-5填空字母,6-10判断题字母A/B,11-15文本,16-20文本,21-25字母) const QUIZ2_ANSWERS = { "1": "By taking a course.", "2": "That's terrific!", "3": "B", "4": "C", "5": "D", "6": "A", "7": "A", "8": "B", "9": "A", "10": "B", "11": "D", "12": "C", "13": "A", "14": "B", "15": "B", "16": "B", "17": "C", "18": "B", "19": "A", "20": "A", "21": "B", "22": "A", "23": "D", "24": "C", "25": "E" }; // 第三次大作业(全部文本,判断题使用 True/False) const QUIZ3_ANSWERS = { "1": "d", "2": "c", "3": "c", "4": "c", "5": "c", "6": "A", "7": "B", "8": "B", "9": "A", "10": "A", "11": "D", "12": "D", "13": "A", "14": "C", "15": "B", "16": "C", "17": "A", "18": "B", "19": "C", "20": "C", "21": "B", "22": "A", "23": "C", "24": "E", "25": "D" }; // 第四次大作业(全部文本,判断题使用 True/False) const QUIZ4_ANSWERS = { "1": "What does your father do?", "2": "Yes,here you are.", "3": "Cheer up.", "4": "Nothing serious.", "5": "So do I.", "6": "True", "7": "True", "8": "True", "9": "False", "10": "False", "11": "issued", "12": "call the booking office", "13": "You will be informed by phone and e-mail.", "14": "a fee of $150 to $ 200", "15": "You can use part of the ticket price for future travel.", "16": "unless", "17": "depends", "18": "will have finished", "19": "available", "20": "that", "21": "most", "22": "for", "23": "own", "24": "written", "25": "services" }; // 根据cmid精确识别(用户URL中应有cmid参数) function detectQuizByCmid() { const url = window.location.href; const match = url.match(/[?&]cmid=(\d+)/); if (match) { const cmid = match[1]; if (cmid === '63140') return QUIZ1_ANSWERS; if (cmid === '63141') return QUIZ2_ANSWERS; if (cmid === '63142') return QUIZ3_ANSWERS; if (cmid === '63143') return QUIZ4_ANSWERS; } // 兜底:根据标题 const title = document.title; if (title.includes('第一次大作业')) return QUIZ1_ANSWERS; if (title.includes('第二次大作业')) return QUIZ2_ANSWERS; if (title.includes('第三次大作业')) return QUIZ3_ANSWERS; if (title.includes('第四次大作业')) return QUIZ4_ANSWERS; // 默认第二次 console.warn('[AutoQuiz] 无法识别测验,默认使用第二次大作业答案'); return QUIZ2_ANSWERS; } let CURRENT_ANSWERS = null; function log(msg) { console.log(`[AutoQuiz] ${msg}`); } function getAnswer(qno) { return CURRENT_ANSWERS ? CURRENT_ANSWERS[qno] : null; } // 模糊标准化:移除标点、空格、大小写,仅保留字母数字和中文 function fuzzyNormalize(text) { if (!text) return ''; // 转为小写,移除标点符号(保留字母、数字、中文字符、空格) let normalized = text.toLowerCase() .replace(/[^\p{L}\p{N}\s]/gu, '') // 移除标点,保留字母数字和中文 .replace(/\s+/g, ' ') // 多个空格合并为一个 .trim(); return normalized; } // 提取选项的纯文本(去除前缀字母和点) function getOptionPureText(optionElement) { // 优先取 flex-fill 里的内容 let contentDiv = optionElement.querySelector('.flex-fill'); if (contentDiv) return contentDiv.innerText.trim(); let fullText = optionElement.innerText.trim(); // 去除 "a. " 或 "A. " 等前缀 let match = fullText.match(/^[A-Za-z]\.\s*(.*)$/); if (match) return match[1].trim(); return fullText; } // 模糊匹配查找 radio/checkbox function findOptionInputByFuzzyText(questionDiv, targetText) { const targetNorm = fuzzyNormalize(targetText); const options = questionDiv.querySelectorAll('.answer .d-flex, .answer .r0, .answer .r1'); for (let opt of options) { let pure = getOptionPureText(opt); if (fuzzyNormalize(pure) === targetNorm) { let input = opt.querySelector('input'); if (input) return input; } } // 备选:label const labels = questionDiv.querySelectorAll('label'); for (let label of labels) { let pure = label.innerText.trim(); let match = pure.match(/^[A-Za-z]\.\s*(.*)$/); if (match) pure = match[1].trim(); if (fuzzyNormalize(pure) === targetNorm) { let input = label.querySelector('input'); if (input) return input; } } return null; } // 填充选择题(radio/checkbox) function fillRadioOrCheckbox(questionDiv, qno, answer) { // 先按模糊文本匹配 let targetInput = findOptionInputByFuzzyText(questionDiv, answer); if (targetInput && !targetInput.checked) { targetInput.checked = true; targetInput.dispatchEvent(new Event('change', { bubbles: true })); targetInput.dispatchEvent(new Event('click', { bubbles: true })); log(`✅ 题${qno} 选中: "${answer}"`); return true; } // 如果答案是单个字母(用于第二次大作业的判断题A/B),尝试按字母值匹配 if (answer.length === 1 && answer.match(/[A-Ea-e]/)) { let letterInput = questionDiv.querySelector(`input[value="${answer.toUpperCase()}"]`); if (letterInput && !letterInput.checked) { letterInput.checked = true; letterInput.dispatchEvent(new Event('change', { bubbles: true })); log(`✅ 题${qno} 按字母value选中 ${answer}`); return true; } // 尝试按选项前缀(如 "B.") let options = questionDiv.querySelectorAll('.answer .d-flex, .answer .r0, .answer .r1'); for (let opt of options) { let text = opt.innerText.trim(); if (text.match(new RegExp(`^${answer}\\.`, 'i'))) { let input = opt.querySelector('input'); if (input && !input.checked) { input.checked = true; input.dispatchEvent(new Event('change', { bubbles: true })); log(`✅ 题${qno} 按前缀字母选中 ${answer}`); return true; } } } } log(`❌ 题${qno} 未找到匹配选项: "${answer}"`); return false; } // 填充文本框(填空题) function fillTextInput(questionDiv, qno, fillText) { const textInput = questionDiv.querySelector('input[type="text"], textarea'); if (!textInput || textInput.disabled) return false; // 直接填入,不做标准化比较(因为输入框可能为空或已有值) if (textInput.value !== fillText) { textInput.value = fillText; textInput.dispatchEvent(new Event('input', { bubbles: true })); textInput.dispatchEvent(new Event('change', { bubbles: true })); log(`✅ 题${qno} 填入: ${fillText}`); return true; } return false; } function processQuestion(questionDiv, qno) { const answer = getAnswer(qno); if (!answer) { log(`⏭️ 题${qno} 无预置答案`); return false; } const hasRadio = questionDiv.querySelector('input[type="radio"], input[type="checkbox"]'); const hasTextInput = questionDiv.querySelector('input[type="text"], textarea'); if (hasRadio && !hasTextInput) { return fillRadioOrCheckbox(questionDiv, qno, answer); } else if (hasTextInput) { return fillTextInput(questionDiv, qno, answer); } return false; } // ========== 3. 自动下一页 ========== function autoNextOrSubmit() { let finishBtn = document.querySelector('input[name="finishattempt"][type="submit"], button[name="finishattempt"]'); if (finishBtn && finishBtn.offsetParent !== null) { log('提交所有并结束'); finishBtn.click(); return true; } let nextInput = document.querySelector('input[type="submit"][name="next"], input[type="submit"][value="下一页"], .mod_quiz-next-nav'); if (nextInput && nextInput.offsetParent !== null) { log('点击“下一页”按钮'); setTimeout(() => nextInput.click(), 500); return true; } let allLinks = document.querySelectorAll('a'); for (let a of allLinks) { let text = (a.innerText || '').toLowerCase(); if (text.includes('上一页') || text.includes('previous')) continue; if (text.includes('下一页') || text.includes('next') || a.classList.contains('mod_quiz-next-nav')) { log(`跳转链接: ${a.href}`); setTimeout(() => { window.location.href = a.href; }, 500); return true; } } log('未找到任何翻页/提交按钮'); return false; } function autoFillAndSubmit() { const questions = document.querySelectorAll('.que'); if (!questions.length) { log('未找到题目'); return; } log(`共 ${questions.length} 题,开始填充`); let filled = 0; for (let i = 0; i < questions.length; i++) { let q = questions[i]; let qnoElem = q.querySelector('.qno'); let qno = qnoElem ? qnoElem.innerText.trim() : (i+1).toString(); qno = qno.replace(/\D/g, ''); if (!qno) qno = (i+1).toString(); if (processQuestion(q, qno)) filled++; } log(`成功填充 ${filled} 题`); setTimeout(autoNextOrSubmit, 1500); } function init() { const url = window.location.href; if (url.includes('/mod/quiz/attempt.php')) { CURRENT_ANSWERS = detectQuizByCmid(); log(`使用答案集: cmid=${url.match(/[?&]cmid=(\d+)/) ? url.match(/[?&]cmid=(\d+)/)[1] : '未知'}`); setTimeout(autoFillAndSubmit, 1000); } else if (url.includes('/mod/quiz/review.php')) { const div = document.createElement('div'); div.innerText = '✅ 自动答题脚本(稳定版)已加载,请打开 attempt 页面使用。'; div.style.cssText = 'position:fixed; bottom:10px; right:10px; background:#4caf50; color:white; padding:6px 12px; border-radius:6px; z-index:10000; font-size:12px;'; document.body.appendChild(div); setTimeout(() => div.remove(), 5000); } } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); else init(); })();