// ==UserScript==
// @name 联大学堂 全自动刷课+答题
// @namespace http://tampermonkey.net/
// @version 2.0 修复稳定版
// @description 视频页面跳过时间限制
// @match *://*.jxjypt.cn/*
// @require https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1.min.js
// @require https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js
// @grant GM_xmlhttpRequest
// @run-at document-end
// ==/UserScript==
(function () {
'use strict';
let hasVideo = !!document.querySelector('video');
const hasExam = !!document.querySelector('.m-question');
// ==============================================
// 功能1:视频刷课 + OCR答题(新版多选适配版)
// ==============================================
function initVideoModule() {
// 强制解除时长限制
function unlockLimit() {
try {
if (typeof g_watchPercentage !== 'undefined') g_watchPercentage = 0;
if (typeof g_totalAnwserTime !== 'undefined') g_totalAnwserTime = 0;
if (typeof g_totalVideoDuration !== 'undefined' && g_totalVideoDuration > 0) {
g_totalAnwserTime = Math.floor(g_totalVideoDuration * 0);
}
console.log("✅ 时长限制已强制解除");
} catch (e) {}
}
// OCR识别 统一大写 适配多选
async function recognizeImage(file) {
const { data } = await Tesseract.recognize(file, 'chi_sim+eng');
let text = data.text;
if (text.includes('如')) {
text += 'AB';
}
text = text.replace(/4/g, 'A');
text = text.replace(/©/g, 'C');
text = text.replace(/×/g, '');
text = text.replace(/条/g, '释');
text = text.replace(/可/g, '释');
text = text.replace(/了/g, 'B');
text = text.toUpperCase();
return text;
}
// 悬浮面板
function createPanel() {
let panel = document.createElement('div');
panel.id = 'autoStudyPanel';
panel.style.cssText = `
position:fixed;top:140px;right:20px;z-index:999999;
background:#fff;padding:12px;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,0.2);
width:220px;max-height:80vh;overflow-y:auto;box-sizing:border-box;
`;
panel.innerHTML = `
🎯 全自动连刷
计时:00:00
总长:00:00
进度:0%
状态:等待启动
OCR状态:未获取
`;
document.body.appendChild(panel);
}
let isRunning = false;
let timer = 0;
let total = 0;
let interval = null;
let jumped = false;
let aiAlreadyCalled = false;
function fmt(s) {
let m = Math.floor(s / 60);
let sec = Math.floor(s % 60);
return `${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
}
function closePopups() {
try {
$("button:contains('确定'),button:contains('关闭'),.close,.layui-layer-close").click();
$(".layui-layer,.modal,.popup").hide();
} catch (e) {}
}
function loadDurationNow() {
let checkVideo = setInterval(() => {
let video = document.querySelector('video');
if (video && video.duration > 0) {
total = video.duration;
updateInfo();
clearInterval(checkVideo);
}
}, 100);
}
function updateInfo() {
let percent = total > 0 ? (timer / total) * 100 : 0;
$('#videoInfo').html(`计时:${fmt(timer)}
总长:${fmt(total)}
进度:${percent.toFixed(1)}%`);
}
function loop() {
if (!isRunning || jumped) return;
closePopups();
let video = document.querySelector('video');
if (!video) return;
if (video.paused) video.play().catch(() => {});
if (!video.paused && !video.ended && video.readyState >= 4) {
timer++;
}
updateInfo();
}
// 下一课跳转
function goNext() {
aiAlreadyCalled = false;
$('#questionDisplay').text('');
$('#answerStatus').text('OCR状态:未获取');
let cur = $('dd.z-color.z-class-icon').first();
if (!cur.length) return;
let next = cur.next('dd');
if (next.length) next.click();
else {
let nextChap = cur.closest('.course-list-txt').next().find('dd').first();
if (nextChap.length) nextChap.click();
}
setTimeout(() => {
timer = 0;
total = 0;
jumped = false;
loadDurationNow();
unlockLimit();
$('#status').text('状态:下一节加载中');
setTimeout(showQuestions, 1200);
setTimeout(() => {
if (isRunning && !aiAlreadyCalled) getAnswerOnce();
}, 2500);
}, 4000);
}
function start() {
isRunning = true;
$('#status').text('状态:运行中(单选+多选已适配)');
clearInterval(interval);
interval = setInterval(loop, 1000);
setTimeout(() => {
if (isRunning && !aiAlreadyCalled) getAnswerOnce();
}, 1500);
}
function stop() {
isRunning = false;
clearInterval(interval);
$('#status').text('状态:已暂停');
let video = document.querySelector('video');
if (video) video.pause();
}
function getExamQuestions() {
const result = [];
document.querySelectorAll('.m-question').forEach(el => {
const q = {};
q.title = el.querySelector('.sub-dotitle pre')?.innerText.trim() || '无题目';
q.options = {};
el.querySelectorAll('.m-question-option').forEach(opt => {
const k = opt.getAttribute('data-value');
const v = opt.innerText.trim().replace(/^[A-Z]\./, '').trim();
if (k && v && !v.includes('null')) q.options[k] = v;
});
result.push(q);
});
return result;
}
function showQuestions() {
const qs = getExamQuestions();
let txt = '';
if (!qs.length) txt = '未检测到题目';
else qs.forEach((q, i) => {
txt += `第${i+1}题:${q.title}\n`;
Object.entries(q.options).forEach(([k, v]) => txt += `${k}. ${v}\n`);
txt += `——————————\n`;
});
$('#questionDisplay').text(txt);
}
// 读取答案图片 + 提取全部ABCD
async function getImageAnswer() {
try {
$('.zkjx').click();
const img = document.querySelector('.solution img');
if (!img) {
$('#answerStatus').text('OCR:未找到答案图');
return null;
}
const response = await fetch(img.src);
const blob = await response.blob();
const text = await recognizeImage(blob);
let oldText = $('#questionDisplay').text();
$('#questionDisplay').text(oldText + `\n✅ 识别答案:${text}\n`);
const matchAll = text.match(/[A-D]/g);
if (matchAll && matchAll.length > 0) {
return [...new Set(matchAll)];
}
} catch (e) {
$('#answerStatus').text('OCR:识别失败');
}
return null;
}
// 提交答案
function realSubmit() {
setTimeout(() => {
let submitBtn = document.getElementById('submitSelfBtn');
if (submitBtn) {
$('#status').text('✅ 答案已提交,跳转下一课');
submitBtn.click();
}
setTimeout(() => { jumped = true; goNext(); }, 1500);
}, 1200);
}
// 核心:多选强制点击修复版
async function getAnswerOnce() {
if (aiAlreadyCalled) return;
aiAlreadyCalled = true;
$('#answerStatus').text('OCR状态:识别中...');
const ans = await getImageAnswer();
if (ans && Array.isArray(ans)) {
$('#answerStatus').text(`OCR状态:${ans.join("、")}`);
// 逐个强制触发鼠标事件,百分百勾选
for (let key of ans) {
let opt = document.querySelector(`.m-question-option[data-value="${key}"]`);
if (opt) {
opt.dispatchEvent(new MouseEvent('mousedown', {bubbles: true}));
opt.dispatchEvent(new MouseEvent('mouseup', {bubbles: true}));
opt.click();
opt.classList.add('active');
}
}
} else {
$('#answerStatus').text('OCR:无有效答案');
}
realSubmit();
}
// 初始化绑定
$(function () {
createPanel();
unlockLimit();
loadDurationNow();
setTimeout(showQuestions, 800);
$('#startBtn').click(start);
$('#stopBtn').click(stop);
$('#showQBtn').click(showQuestions);
$('#getAnswerBtn').click(getAnswerOnce);
$('#unlockBtn').click(unlockLimit);
});
}
// ==============================================
// 功能2:试卷全自动答题(完全没动,保留原版)
// ==============================================
function initExamModule() {
window.confirm = () => true;
window.alert = () => {};
window.prompt = () => null;
function createPanel() {
if (document.getElementById('autoStudyPanel')) return;
let panel = $('');
panel.css({
position: 'fixed', top: '100px', right: '20px', zIndex: '999999',
background: '#fff', padding: '12px', borderRadius: '10px', boxShadow: '0 0 12px rgba(0,0,0,0.25)',
width: '260px', maxHeight: '80vh', overflowY: 'auto', fontSize: '14px'
});
panel.html(`
🎯 联大学堂自动答题
状态:加载完成,就绪
`);
$('body').append(panel);
}
function closePopups() {
try {
$("button:contains('确定'),button:contains('关闭'),.close,.layui-layer-close,.modal-close").click();
$(".layui-layer,.modal,.popup").hide();
} catch (e) {}
}
function expandAllAnswers() {
$('.zkjx').click();
$('.solution').show();
}
function getAllAnswers() {
expandAllAnswers();
const result = [];
$('.m-question').each((i, el) => {
const q = {};
q.title = $(el).find('.sub-dotitle pre').text().trim() || $(el).find('.sub-dotitle').text().trim();
q.answer = $(el).find('.da-list:first .wenzi').text().trim();
q.element = el;
if ($(el).find('.sub-answer-double').length > 0) {
q.type = "多选题";
} else if ($(el).find('dd[data-value]').length > 0) {
q.type = "单选题";
} else if ($(el).find('textarea').length > 0) {
q.type = "简答题";
} else {
q.type = "其他题型";
}
result.push(q);
});
return result;
}
function showAllAnswers() {
const list = getAllAnswers();
let txt = '';
list.forEach((q, i) => {
txt += `【第${i+1}题】(${q.type})\n答案:${q.answer || '无'}\n---\n`;
});
$('#answerDisplay').text(txt);
$('#status').text(`状态:已显示 ${list.length} 题完整答案`);
}
function autoAnswerOne(questionEl, answer) {
if (!answer || answer === '') return;
const $el = $(questionEl);
let ans = answer.trim();
if (ans === "对" || ans === "正确") ans = "A";
if (ans === "错" || ans === "错误") ans = "B";
for (let c of ans) {
if (c >= 'A' && c <= 'Z') {
const opt = $el.find(`dd[data-value="${c}"]`);
if (opt.length) {
opt.click().css({ background: '#e6f7ff', border: '1px solid #1890ff' });
}
const optText = (c === 'A') ? "正确" : "错误";
const opt2 = $el.find(`dd[data-value="${optText}"]`);
if (opt2.length) {
opt2.click().css({ background: '#e6f7ff', border: '1px solid #1890ff' });
}
}
}
const textarea = $el.find('textarea.e__textarea, textarea');
if (textarea.length) {
textarea.val(answer).trigger('input').trigger('change').css({
background: '#e6f7ff', border: '1px solid #1890ff'
});
}
}
function autoAnswerAll() {
closePopups();
const list = getAllAnswers();
if (list.length === 0) {
$('#status').text('❌ 未找到题目,请确认页面已加载完成');
return;
}
let count = 0;
list.forEach((q, i) => {
setTimeout(() => {
autoAnswerOne(q.element, q.answer);
count++;
$('#status').text(`状态:答题中 ${count}/${list.length} 题`);
}, i * 300);
});
setTimeout(() => {
$('#status').text(`✅ 全部答题完成!共 ${list.length} 题`);
}, list.length * 300 + 600);
}
function submitPaper() {
closePopups();
setTimeout(() => {
const btn = $('#btn_submit')[0] || $("button:contains('交卷')")[0] || $("a:contains('交卷')")[0];
if (btn) {
btn.click();
$('#status').text('✅ 已触发交卷');
} else {
$('#status').text('❌ 未找到交卷按钮');
}
}, 1000);
}
$(function () {
createPanel();
$('#autoAllBtn').click(autoAnswerAll);
$('#showAnswerBtn').click(showAllAnswers);
$('#submitBtn').click(submitPaper);
$('#status').text('✅ 脚本加载成功!支持单选+多选+简答+判断');
});
}
// ==============================================
// 自动监听视频
// ==============================================
function waitForVideo() {
const check = setInterval(() => {
const video = document.querySelector('video');
if (video) {
clearInterval(check);
hasVideo = true;
initVideoModule();
}
}, 500);
}
// ==============================================
// 自动加载
// ==============================================
window.addEventListener('load', () => {
if (hasExam) {
initExamModule();
} else {
waitForVideo();
}
});
})();