U校园刷时长-强化版

改编了《U校园刷时长》这个脚本(原作者貌似停止维护)

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         U校园刷时长-强化版
// @namespace    https://blog.1think2program.cn/
// @version      0.7
// @description  改编了《U校园刷时长》这个脚本(原作者貌似停止维护)
// @author       DaXue(原作者) - 盧瞳
// @
// @match        https://ucontent.unipus.cn/_pc_default/pc.html?cid=*
// @grant        none
// @license      GPL-3.0
// ==/UserScript==

var minTime = [8, 30]; //最短停留时间,默认是3分30秒
var maxTime = [15, 30]; //最大停留时间,默认为5分30秒
var unitInterval = [1, 5]; //循环的单元区间,默认为1-5单元
var maxTestTime = [10, 30]; //单元测试最短停留时间,默认是8分30秒
var minTestTime = [15, 30]; //单元测试最大停留时间,默认为10分30秒
var autojump = 1; //是否开启自动跳过非必修章节功能,0为关闭,1为开启
var feibixiuWaitTime = 15000; //跳过非必修等待的时间,单位毫秒
var jumpTimeOut = 0; //是否开启自动跳过已过截止时间的必修章节
var unitTestStay = 0; //是否单独设置单元测试的时间

var feibixiu = document.getElementsByClassName(
  "taskTipStyle--disrequired-1ZUIG"
);
var bixiu = document.getElementsByClassName("taskTipStyle--required-23n0J");

let waitTime = realTime(minTime[0], minTime[1], maxTime[0], maxTime[1]); // 本次停留时间
let currentUnit = 0; // 当前单元

const timer = creatPanel();

function switch_next(selector, classFlag) {
  let flag = false;
  for (let [index, unit] of document.querySelectorAll(selector).entries()) {
    if (flag) {
      unit.click();
      //防止必修弹窗失效,跳转便刷新页面,1000表示跳转1秒后刷新页面
      setTimeout(() => {
        location.reload();
      }, 1000);
      flag = false;
      break;
    }
    if (unit.classList.contains(classFlag)) {
      flag = true;
    }
  }
}

const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));

function jumpToNextSection() {
  switch_next(".layoutHeaderStyle--circleTabsBox-jQdMo a", "selected");
  switch_next("#header .TabsBox li", "active");
  switch_next("#sidemenu li.group", "active");
}

// 跳转到开头的第一单元
function jumpToFirstSection() {
  console.log("jumpToFirstSection,跳转到第一个单元");
  let items = document.querySelectorAll("#sidemenu li.group");
  for (let item of items) {
    if (getUnitNum(item.textContent) == unitInterval[0]) {
      item.click();
      break;
    }
  }
}

if (autojump == 1) {
  setTimeout(async () => {
    if (feibixiu[0].innerText == "非必修") {
      // debugger;
      // 三十秒后切换,防止检测异常
      waitTime = feibixiuWaitTime;
      await sleep(feibixiuWaitTime);
      jumpToNextSection();
    } else if (bixiu[0].innerText == "必修") {
      return 0;
    }
  }, 3000);
}

// 自动跳过已过截止时间的必修章节
setTimeout(() => {
  try {
    var isTestTimeOut = document.getElementsByClassName(
      "taskTipStyle--warningheadertext-1ch9A"
    );
    if (
      isTestTimeOut[0].innerText ==
        "学习截止时间已过,你可以继续学习,但本次提交得分不计入学习成绩" &&
      jumpTimeOut == 1
    ) {
      jumpToNextSection();
    }
  } catch (a) {
    return 0;
  }
}, 3000);

//计算实际停留时间,防止每个页面停留时间相同
function realTime(minMinutes, minSeconds, maxMinutes, maxSeconds) {
  let rate = Math.random();
  return (
    (minMinutes * 60 +
      minSeconds +
      ((maxMinutes - minMinutes) * 60 + maxSeconds - minSeconds) * rate) *
    1000
  );
}

//自动点击必修弹窗和麦克风弹窗 3000表示延迟3秒,因为弹窗有延迟,主要看反应速度。
setTimeout(() => {
  var x = document.getElementsByClassName("dialog-header-pc--close-yD7oN");
  x[0].click();
  document
    .querySelector("div.dialog-header-pc--dialog-header-2qsXD")
    .parentElement.querySelector("button")
    .click();
}, 3000);

// 如果不是在单元区间内,跳转到第一个单元
setTimeout(() => {
  // 如果不是在单元区间内,跳转到第一个单元
  let unitStr = document.querySelectorAll("#sidemenu li.group.active")[0]
    .textContent;

  currentUnit = getUnitNum(unitStr);

  if (currentUnit < unitInterval[0] || currentUnit > unitInterval[1]) {
    // 不在单元区间内,跳转到第一个单元
    console.log("跳转到第一个单元");
    let items = document.querySelectorAll("#sidemenu li.group");
    for (let item of items) {
      if (getUnitNum(item.textContent) == unitInterval[0]) {
        console.log("找到第一个单元");
        item.click();
        break;
      }
    }
  }
}, 3000);

setTimeout(() => {
  try {
    // 单独设置单元测试的时间
    var unitTest = document.getElementsByClassName(
      "utButtonStyle--toDoButton-1S89L"
    );
    if (unitTestStay == 1 && unitTest[0].innerText == "开始做题") {
      setTimeout(() => {
        jumpToNextSection();
      }, realTime(minTestTime[0], minTestTime[1], maxTestTime[0], maxTestTime[1]));
    }
  } catch (e) {
    setTimeout(() => {
      jumpToNextSection();
    }, realTime(minTime[0], minTime[1], maxTime[0], maxTime[1]));
  }

  setInterval(() => {
    waitTime -= 1000;
    updatePanel();
  }, 1000);

  setTimeout(() => {
    jumpToNextSection();
  }, waitTime);
}, 4000);

function creatPanel() {
  let timerPanel = document.createElement("div");
  timerPanel.id = "timerPanel";
  timerPanel.innerHTML = `
    <div id="timerPanelHeader">章节跳转倒计时</div>
    <div id="timer">准备开始</div>
    <div id="unit">当前单元: </div>
`;
  document.body.appendChild(timerPanel);

  let style = document.createElement("style");
  style.innerHTML = `
    #timerPanel {
        position: fixed;
        top: 0;
        right: 0;
        width: 200px;
        height: 100px;
        background-color: #f1f1f1;
        border: 1px solid #d3d3d3;
        z-index: 9999;
        text-align: center;
    }
    #timerPanelHeader {
        padding: 2px;
        cursor: move;
        background-color: #2196F3;
        color: #fff;
        font-size: 15px;
        text-align: center;
        height: 40px;
    }
    #timer {
        color: #f00;
        line-height: 60px;
        font-size: 25px;
    }
`;
  document.head.appendChild(style);

  let timerPanelHeader = document.getElementById("timerPanelHeader");
  let timer = document.getElementById("timer");
  let pos1 = 0,
    pos2 = 0,
    pos3 = 0,
    pos4 = 0;

  timerPanelHeader.onmousedown = dragMouseDown;

  function dragMouseDown(e) {
    e = e || window.event;
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    timerPanel.style.top = timerPanel.offsetTop - pos2 + "px";
    timerPanel.style.left = timerPanel.offsetLeft - pos1 + "px";
  }

  // 在 dragMouseDown 函数中,当鼠标松开时,将面板的位置存储到 localStorage
  function closeDragElement() {
    document.onmouseup = null;
    document.onmousemove = null;
    localStorage.setItem("timerPanelTop", timerPanel.style.top);
    localStorage.setItem("timerPanelLeft", timerPanel.style.left);
  }

  // 在页面加载时,从 localStorage 中读取面板的位置
  window.onload = function () {
    let top = localStorage.getItem("timerPanelTop");
    let left = localStorage.getItem("timerPanelLeft");
    if (top && left) {
      timerPanel.style.top = top;
      timerPanel.style.left = left;
    }
  };

  return timer;
}

function getUnitNum(unitStr) {
  //   let unitStr = document.querySelectorAll("#sidemenu li.group.active")[0]
  //     .textContent;
  let parts = unitStr.split(" ");
  let fullNumber = parts[0]; // 获取 "1-1"
  let firstNumber = fullNumber.split("-")[0]; // 获取 "1"
  firstNumber = parseInt(firstNumber);
  return parseInt(firstNumber);
}

function updatePanel() {
  // 更新倒计时
  let milliseconds = waitTime;
  let totalSeconds = Math.floor(milliseconds / 1000);
  let minutes = Math.floor(totalSeconds / 60);
  let remainingSeconds = totalSeconds % 60;
  if (remainingSeconds < 10) {
    remainingSeconds = "0" + remainingSeconds; // 在一位数前面添加一个 '0'
  }
  timer.textContent = minutes.toString() + ":" + remainingSeconds.toString();
  // 更新单元
  document.getElementById("unit").textContent =
    "当前单元: " + currentUnit.toString() + "单元";
}