超星学习通+ChatGPT自动答题脚本(支持考试,作业,章节测试,支持新版学习通)

超星学习通+ChatGPT自动答题脚本(支持考试和作业和章节测试,支持新版学习通)。直接获取到答案,可以复制答案到剪切板。

// ==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");
    });
  });

})();