course-helper/script/buct-cource-helper.js
2025-05-24 16:28:12 +08:00

227 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==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 done = allDone();
const submitButton = getAnswerElement().nextElementSibling.children[1];
submitButton.click();
await new Promise((resolve) => setTimeout(resolve, 500));
if (!done) {
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;
})();