// ==UserScript==
// @name 超星学习通+ChatGPT自动答题脚本(支持考试,作业,章节测试,支持新版学习通)
// @namespace http://tampermonkey.net/
// @version 0.4
// @description 超星学习通+ChatGPT自动答题脚本(支持考试和作业和章节测试,支持新版学习通)。直接获取到答案,可以复制答案到剪切板。
// @author Cwyu
// @license MIT
// @supportURL 1441577495@qq.com
// @contributionURL https://afdian.net/a/cwyuu
// @match *://mooc1.chaoxing.com/exam-ans/mooc2/exam/preview?*
// @match *://mooc1.chaoxing.com/mooc2/work/dowork?*
// @match *://mooc1.chaoxing.com/mycourse/studentstudy?*
// @match *://mooc1.chaoxing.com/mycourse/studentstudy*
// @match *://mooc1.chaoxing.com/mooc-ans/mooc2/work/dowork*
// @icon https://www.google.com/s2/favicons?sz=64&domain=chaoxing.com
// @grant unsafeWindow
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-end
// ==/UserScript==
(function () {
"use strict";
// 添加CSS样式
GM_addStyle(`
#my-window {
position: fixed;
top: 10px;
left: 10px;
width: 491px;
height: 308px;
background-color: rgba(173, 255, 47, 0.7);
border: 1px solid #000;
border-radius: 5px;
z-index: 9999;
overflow: hidden;
}
#my-window .header {
background-color: #000;
color: #fff;
padding: 5px;
font-size: 16px;
font-weight: bold;
border-radius: 5px 5px 0 0;
cursor: move;
}
#my-window .resizer {
position: absolute;
bottom: 0;
right: 0;
width: 20px;
height: 20px;
background-color: #000;
cursor: se-resize;
border-radius: 0 0 5px 0;
z-index: 1;
}
#hide-btn {
float: right;
}
#floating-button {
position: fixed;
top: 20px;
left: -45px;
width: 50px;
height: 50px;
background-color: #333;
color: #fff;
border-radius: 50%;
text-align: center;
line-height: 50px;
cursor: pointer;
transition: all 0.3s ease;
z-index: 9999;
}
#floating-button:hover {
left: 0;
}
#floating-button:active {
top: 30px;
}
.buttons {
position: absolute;
bottom: 10px;
left: 10px;
display: flex;
justify-content: flex-end;
}
.buttons button {
display: block;
margin-bottom: 5px;
margin-right: 5px;
}
.buttons input {
display: block;
margin-bottom: 5px;
margin-right: 5px;
}
.buttons p {
display: block;
margin-bottom: 5px;
margin-right: 5px;
}
.editing {
color: red!important;
}
`);
// 创建窗口元素
const myWindow = document.createElement("div");
myWindow.id = "my-window";
myWindow.innerHTML = `
<div class="header">窗口标题
<button id="hide-btn">隐藏</button>
</div>
<div class="resizer"></div>
<div class="row">
<div class="col">题目</div>
<div class="col" id="question"></div>
<div class="col-separator"></div>
<div class="col">答案</div>
<div class="col"></div>
</div>
<div class="buttons">
<button id="prev-btn">上一题</button>
<button id="next-btn">下一题</button>
<button id="refresh-btn">重新获取</button>
<button id="copy-btn">复制答案</button>
<input type="text" name="key" placeholder="请输入订阅链接">
<button id="save-btn">保存订阅</button>
<p id="card_status"></p>
</div>
`;
// 创建悬浮球元素
const floatingButton = document.createElement("div");
floatingButton.id = "floating-button";
// 获取页面body元素
const body = document.getElementsByTagName("body")[0];
// 添加窗口和悬浮球到页面
body.appendChild(myWindow);
body.appendChild(floatingButton);
// 隐藏窗口函数
function hideWindow() {
myWindow.style.display = "none";
floatingButton.style.display = "block";
}
// 显示窗口函数
function showWindow() {
myWindow.style.display = "block";
floatingButton.style.display = "none";
}
// 绑定隐藏窗口按钮的click事件
const hideBtn = document.getElementById("hide-btn");
hideBtn.addEventListener("click", hideWindow);
// 绑定悬浮球的click事件
floatingButton.addEventListener("click", showWindow);
// 初始化隐藏悬浮球
floatingButton.style.display = "none";
// 获取头部元素
const header = myWindow.querySelector('.header');
// 获取调整大小元素
const resizer = myWindow.querySelector('.resizer');
// 处理调整大小事件
resizer.addEventListener('mousedown', function (e) {
e.preventDefault();
const { left, top, width, height } = myWindow.getBoundingClientRect();
const startX = e.clientX;
const startY = e.clientY;
function onMouseMove(e) {
const newWidth = Math.max(200, width + (e.clientX - startX));
const newHeight = Math.max(100, height + (e.clientY - startY));
myWindow.style.width = newWidth + 'px';
myWindow.style.height = newHeight + 'px';
}
function onMouseUp() {
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onMouseUp);
}
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('mouseup', onMouseUp);
});
// 处理移动事件
let isDragging = false;
let mouseX = 0;
let mouseY = 0;
header.addEventListener('mousedown', function (e) {
e.preventDefault();
isDragging = true;
mouseX = e.clientX;
mouseY = e.clientY;
});
document.addEventListener('mousemove', function (e) {
if (isDragging) {
const deltaX = e.clientX - mouseX;
const deltaY = e.clientY - mouseY;
const newLeft = myWindow.offsetLeft + deltaX;
const newTop = myWindow.offsetTop + deltaY;
myWindow.style.left = newLeft + 'px';
myWindow.style.top = newTop + 'px';
mouseX = e.clientX;
mouseY = e.clientY;
}
});
document.addEventListener('mouseup', function (e) {
isDragging = false;
});
const answerCol = document.querySelector('.row .col:nth-child(5)');
let timu = ["正在获取题目"];
async function decrypt(str){
const data = {
b64_code: str,
text: timu
};
const response = await fetch("https://service-75fbid0g-1316165338.gz.apigw.tencentcs.com:443/release/decrypt", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
const result = await response.json();
timu = result;
showText(0);
}
if (document.title == "作业作答") {
const divs = document.querySelectorAll('.padBom50.questionLi:not(script)');
const texts = [];
divs.forEach(div => {
const text = div.textContent.trim().replace(/\s+/g, ' ');
texts.push(text);
});
timu = texts.map((text) =>
text.replace(/var\s+wordNum\s*=.*$/gm, "").trim()
);
}
if (document.title == "整卷预览") {
const elements = document.querySelectorAll('div.questionLi:not(script)');
const texts = [];
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
const text = element.textContent.trim().replace(/\s+/g, ' ');
texts.push(text);
}
timu = texts.map((text) =>
text.replace(/window\.UEDITOR_CONFIG\.initialFrameWidth.*保存/g, "").trim()
);
}
async function main() {
if (document.title === "学生学习页面") {
await queryElements();
}
}
main();
async function queryElements(){
const timeoutPromise = new Promise((resolve) => {
// 获取 iframe 对象
const iframe = document.getElementById('iframe');
if (!iframe) {
setTimeout(queryElements, 3000); // 等待1秒后重试
} else {
const iframeDoc = iframe.contentDocument || iframe.contentWindow && iframe.contentWindow.document;
const second = iframeDoc.querySelector('iframe');
if (!second) {
setTimeout(queryElements, 3000); // 等待1秒后重试
} else {
const secondDoc = second.contentDocument || second.contentWindow && second.contentWindow.document;
const third = secondDoc.getElementById('frame_content');
if (!third) {
setTimeout(queryElements, 3000); // 等待1秒后重试
} else {
const thirdDoc = third.contentDocument || third.contentWindow && third.contentWindow.document;
const elements = thirdDoc.querySelectorAll('div.TiMu:not(script)');
if (elements.length > 0) {
const texts = [];
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
const text = element.textContent.trim().replace(/\s+/g, ' ');
texts.push(text);
}
const style = $("style[type='text/css']", thirdDoc);
const fontData = style.text().match(/'(data:application\/font-ttf;.*?)'/)[1];
timu = texts.map((text) =>
text
.replace(/var\s+wordNum\s*=.*$/gm, "")
.replace(/点击上传x[^}]*}/gm, "")
.replace(/填写答案[^x]*x/gm, "")
.trim()
);
decrypt(fontData.split(",")[1]);
} else {
setTimeout(queryElements, 3000); // 等待1秒后重试
}
}
}
}
});
// 等待 Promise 对象执行完成
await timeoutPromise;
};
let currentIndex = 0;
const col1 = document.querySelector('.row .col:nth-child(2)');
function showText(index) {
col1.textContent = timu[index];
}
function showNext() {
if (currentIndex < timu.length - 1) {
currentIndex++;
showText(currentIndex);
answerCol.textContent = "";
}
}
function showPrev() {
if (currentIndex > 0) {
currentIndex--;
showText(currentIndex);
answerCol.textContent = "";
}
}
// 绑定按钮点击事件
document.getElementById('prev-btn').addEventListener('click', showPrev);
document.getElementById('next-btn').addEventListener('click', showNext);
// 显示第一个文本
showText(currentIndex);
const refreshBtn = document.getElementById("refresh-btn");
refreshBtn.addEventListener("click", async function () {
// 获取输入框元素
var inputElement = document.querySelector('input[name="key"]');
answerCol.textContent = "请等待......";
const data = {
"cardNum": inputElement.value,
"question": timu[currentIndex]
};
const response = await fetch('https://service-75fbid0g-1316165338.gz.apigw.tencentcs.com/release/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'charset': 'utf-8'
},
body: JSON.stringify(data)
});
const json = await response.json();
if (json.data == null) {
const content = json.msg;
answerCol.textContent = content;
} else {
const content = json.data.answer;
answerCol.textContent = content;
}
});
const copyBtn = document.querySelector('#copy-btn');
copyBtn.addEventListener('click', function () {
const answerText = answerCol.textContent;
navigator.clipboard.writeText(answerText)
.then(() => {
console.log('Text copied to clipboard');
})
.catch(err => {
console.error('Could not copy text: ', err);
});
});
// 获取输入框元素
var inputElement = document.querySelector('input[name="key"]');
// 获取存储的数据
var storedValue = GM_getValue('key');
// 如果存储的数据存在,则将其设置为输入框的值
if (storedValue) {
inputElement.value = storedValue;
}
// 获取按钮元素
var buttonElement = document.querySelector('#save-btn');
// 获取<p>元素
var pElement = document.getElementById('card_status');
// 当按钮被点击时执行的函数
buttonElement.addEventListener('click', async function () {
// 获取输入框的值
var inputValue = inputElement.value;
// 存储数据
GM_setValue('key', inputValue);
// 发送POST请求
var data = {
"cardNum": inputValue
};
var response = await fetch('https://service-75fbid0g-1316165338.gz.apigw.tencentcs.com/release/getcard', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
// 从响应中获取msg字段的值
var json = await response.json();
var msg = json.msg;
pElement.textContent = "可用的token余额:" + msg
});
// 获取题目元素
const questionElement = document.querySelector("#question");
// 添加双击事件监听器
questionElement.addEventListener("dblclick", function (event) {
// 阻止默认行为
event.preventDefault();
// 创建可编辑的 div 元素
const editableDiv = document.createElement("div");
editableDiv.setAttribute("contenteditable", true);
editableDiv.textContent = questionElement.textContent;
// 用可编辑的 div 元素替换题目元素
questionElement.replaceWith(editableDiv);
// 让可编辑的 div 元素获取焦点
editableDiv.focus();
// 给题目元素添加样式类,改变元素文本颜色
editableDiv.classList.add("editing");
// 添加失去焦点事件监听器,保存编辑内容并恢复题目元素
editableDiv.addEventListener("blur", function () {
// 保存编辑后的文本内容到 timu 数组
timu[currentIndex] = editableDiv.textContent;
// 用编辑后的内容替换可编辑的 div 元素
questionElement.textContent = editableDiv.textContent;
editableDiv.replaceWith(questionElement);
// 移除题目元素样式类,恢复元素文本颜色
editableDiv.classList.remove("editing");
});
});
})();