// ==UserScript== // @name BUCT cource helper // @namespace http://tampermonkey.net/ // @version 2025-03-12 // @description 北化在线助手 // @author Bluemangoo // @match https://course.buct.edu.cn/meol/jpk/course/layout/newpage/index.jsp?* // @icon https://www.google.com/s2/favicons?sz=64&domain=buct.edu.cn // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // ==/UserScript== (function () { "use strict"; const HOST = "https://local.bluemangoo.net:3443"; let stat = { question: { id: "" }, autoMode: false }; class Poll { polling = true; constructor() { this.poll(); } async poll() { if (!this.polling) { return; } let res; try { res = await fetch(`${HOST}/polling?env=course`, { method: "GET", headers: { "Content-Type": "application/json" } }); } catch { await new Promise((resolve) => setTimeout(resolve, 1000)); return this.poll(); } this.poll(); try { const data = await res.json(); if (data.status !== "nothing") { const { questionID, answer } = data.data; console.log("回答", questionID, "\n", answer); answerQuestion(questionID, answer); } } catch (e) { console.error(e); } } } function getAnswerElement() { const doc = document .getElementById("mainFrame") .contentDocument.getElementById("questionshow").contentDocument; return doc.getElementsByClassName("extable")[0]; } function getContent() { const doc = document .getElementById("mainFrame") .contentDocument.getElementById("questionshow").contentDocument; const question = doc .getElementsByTagName("iframe")[0] .contentDocument.getElementById("body").innerText; const answer = doc.getElementsByClassName("extable")[0].innerText.replaceAll("\t", "- "); return question + answer; } function copyToClipboard() { navigator.clipboard.writeText(getContent()); } async function answerQuestion(id, answer) { if (id !== stat.question.id) { return; } aiButton.value = "?"; let answered = false; const answers = answer.split("\n"); const children = getAnswerElement().children[0].children; for (const child of children) { if (child.classList[0] !== "optionContent") { continue; } if (answers.includes(child.innerText.replaceAll("\t", ""))) { child.children[0].children[0].click(); answered = true; } } if (answered && stat.autoMode) { const submitButton = getAnswerElement().nextElementSibling.children[1]; submitButton.click(); await new Promise((resolve) => setTimeout(resolve, 500)); if (!allDone()) { aiButton.click(); } } } async function ask() { const q = getContent(); const req = await fetch(`${HOST}/question`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ question: q }) }); const data = await req.json(); if (data.data.questionId) { stat.question.id = data.data.questionId; } aiButton.value = "Zzz"; } function getAutoText() { return stat.autoMode ? "A*" : "A"; } function toggleAutoMode() { stat.autoMode = !stat.autoMode; autoButton.value = getAutoText(); } function allDone() { const element = document .getElementById("mainFrame") .contentDocument.getElementsByClassName("infotable")[1]; return !element.innerText.toString().includes("未作答"); } const flag = { copyButton: false, aiButton: false }; let aiButton; let autoButton; let poll; function newButton(document, value, onclick) { const button = document.createElement("input"); button.value = value; button.style = "margin-left: 10px;"; button.type = "button"; if (onclick) { button.onclick = onclick; } return button; } function createButton(addAiButton = false) { const base = document.getElementById("mainFrame"); const win = base.contentWindow; const doc = base.contentDocument; win.getContent = getContent; win.getAnswerElement = getAnswerElement; win.answerQuestion = answerQuestion; win.copyToClipboard = copyToClipboard; if (!flag.copyButton) { const button = newButton(doc, "复制", copyToClipboard); doc.getElementsByClassName("navigation")[0].childNodes[1].appendChild(button); flag.copyButton = true; } if (addAiButton && !flag.aiButton) { aiButton = newButton(doc, "?", ask); doc.getElementsByClassName("navigation")[0].childNodes[1].appendChild(aiButton); autoButton = newButton(doc, getAutoText(), toggleAutoMode); doc.getElementsByClassName("navigation")[0].childNodes[1].appendChild(autoButton); flag.aiButton = true; } } function initAiBridge() { createButton(true); if (poll) { poll.polling = false; } poll = new Poll(); } function stopPolling() { if (poll) { poll.polling = false; flag.copyButton = false; flag.aiButton = false; } } GM_registerMenuCommand("添加复制按钮", createButton); GM_registerMenuCommand("初始化ai桥", initAiBridge); GM_registerMenuCommand("停止轮询", stopPolling); // window.stat = stat; // window.getContent = getContent; // window.getAnswerElement = getAnswerElement; // window.answerQuestion = answerQuestion; // window.copyToClipboard = copyToClipboard; // window.ask = ask; // window.toggleAutoMode = toggleAutoMode; // window.allDone = allDone; // window.flag = flag; // window.initAiBridge = initAiBridge; // window.stopPolling = stopPolling; // window.aiButton = aiButton; // window.autoButton = autoButton; // window.newButton = newButton; // window.getAutoText = getAutoText; // window.createButton = createButton; // window.initAiBridge = initAiBridge; // window.stopPolling = stopPolling; })();