// ==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 question = { id: "" }; 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()); } function answerQuestion(id, answer) { if (id !== question.id) { return; } aiButton.value = "?"; 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(); } } } 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) { question.id = data.data.questionId; } aiButton.value = "Zzz"; } const flag = { copyButton: false, aiButton: false }; let aiButton; let poll; 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 = doc.createElement("input"); button.value = "复制"; button.style = "margin-left: 10px;"; button.type = "button"; button.onclick = copyToClipboard; doc.getElementsByClassName("navigation")[0].childNodes[1].appendChild(button); flag.copyButton = true; } if (addAiButton && !flag.aiButton) { const button = doc.createElement("input"); aiButton = button; button.value = "?"; button.style = "margin-left: 10px;"; button.type = "button"; button.onclick = ask; doc.getElementsByClassName("navigation")[0].childNodes[1].appendChild(button); flag.aiButton = true; } } function initAiBridge() { createButton(true); if (poll) { poll.polling = false; } poll = new Poll(); } function stopPolling() { if (poll) { poll.polling = false; } } GM_registerMenuCommand("添加复制按钮", createButton); GM_registerMenuCommand("初始化ai桥", initAiBridge); GM_registerMenuCommand("停止轮询", stopPolling); })();