// ==UserScript== // @name B站硬核会员答题辅助 // @namespace http://tampermonkey.net/ // @description 硬核会员答题辅助 // @version 1.0 // @match https://www.bilibili.com/h5/senior-newbie/qa // @match *://chat.deepseek.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addValueChangeListener // @run-at document-end // @downloadURL https://update.greasyfork.icu/scripts/574348/B%E7%AB%99%E7%A1%AC%E6%A0%B8%E4%BC%9A%E5%91%98%E7%AD%94%E9%A2%98%E8%BE%85%E5%8A%A9.user.js // @updateURL https://update.greasyfork.icu/scripts/574348/B%E7%AB%99%E7%A1%AC%E6%A0%B8%E4%BC%9A%E5%91%98%E7%AD%94%E9%A2%98%E8%BE%85%E5%8A%A9.meta.js // ==/UserScript== (function () { 'use strict'; const IS_A = location.host.includes("bilibili.com"); const IS_B = location.host.includes("deepseek.com"); /*********************** * 工具 ***********************/ const log = (tag, msg, data) => { console.log(`[${tag}] ${msg}`, data || ""); }; const sleep = (ms) => new Promise(r => setTimeout(r, ms)); const makeKey = (t) => t.replace(/\s+/g, "").slice(0, 120); /*********************** * A 页面 ***********************/ if (IS_A) { let lastKey = ""; let lock = false; let pendingAnswer = null; const getBlock = () => { const blocks = document.querySelectorAll(".senior-question"); return blocks[blocks.length - 1]; }; const extract = () => { const b = getBlock(); if (!b) return null; const q = b.querySelector(".senior-question__qs"); const a = b.querySelectorAll(".senior-question__answer"); if (!q || !a.length) return null; let text = q.innerText.trim() + " "; a.forEach(i => text += i.innerText.trim() + " "); return text; }; const clickAnswer = (letter) => { const b = getBlock(); const items = b.querySelectorAll(".senior-question__answer"); for (let el of items) { if (el.innerText.trim().startsWith(letter)) { el.click(); log("A6", "点击完成", letter); return true; } } return false; }; /*********************** * S5:接收答案 ***********************/ GM_addValueChangeListener("answer", async (n, o, v, remote) => { if (!remote || !v) return; log("A5", "收到B答案", v); pendingAnswer = v; await sleep(100); if (!lock) { log("A5", "锁状态异常,跳过点击"); return; } const ok = clickAnswer(pendingAnswer); if (ok) { pendingAnswer = null; log("A6", "点击成功,等待下一题"); await sleep(500); lock = false; } else { log("A6", "点击失败,未找到选项"); } }); /*********************** * S1-S2:发送题目 ***********************/ const sendTask = (q) => { const key = makeKey(q); if (key === lastKey) return; lastKey = key; lock = true; log("A1", "抓取题目", q); log("A2", "发送题目", key); GM_setValue("task", { id: Date.now(), key, text: q }); }; const observer = new MutationObserver(() => { const q = extract(); if (!q) return; const key = makeKey(q); if (key !== lastKey && !lock) { sendTask(q); } }); observer.observe(document.body, { childList: true, subtree: true, characterData: true }); } /*********************** * B 页面 ***********************/ if (IS_B) { let lastTask = 0; const setVal = (el, val) => { const setter = Object.getOwnPropertyDescriptor( HTMLTextAreaElement.prototype, "value" ).set; setter.call(el, val); el.dispatchEvent(new Event("input", { bubbles: true })); }; const sendEnter = (el) => { el.dispatchEvent(new KeyboardEvent("keydown", { bubbles: true, key: "Enter", code: "Enter", keyCode: 13, which: 13 })); }; /*********************** * S3:接收题目 ***********************/ GM_addValueChangeListener("task", (n, o, task, remote) => { if (!remote || !task) return; if (task.id === lastTask) return; lastTask = task.id; log("B3", "收到题目", task.key); setTimeout(() => { const input = document.querySelector("textarea"); if (!input) { log("B3", "输入框不存在"); return; } log("B4", "开始输入"); setVal(input, task.text + " 只回答A/B/C/D"); setTimeout(() => { log("B4", "发送到AI"); sendEnter(input); }, 500); }, 800); }); /*********************** * S4:监听AI输出 ***********************/ setInterval(() => { const msgs = document.querySelectorAll(".ds-markdown-paragraph"); if (!msgs.length) return; const last = msgs[msgs.length - 1].innerText.trim(); const m = last.match(/\b([A-D])\b/); if (m) { log("B4", "AI输出答案", m[1]); GM_setValue("answer", m[1]); } }, 400); } })();