中检网自动学习

中国检察教育培训网络学院全自动学习课程,点击学习中心,最后进入班级即可。

当前为 2024-08-23 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         中检网自动学习
// @namespace    https://github.com/chiupam
// @version      1.4
// @description  中国检察教育培训网络学院全自动学习课程,点击学习中心,最后进入班级即可。
// @author       chiupam
// @match        https://www.sppet.cn/portal/play.do*
// @match        https://www.sppet.cn/examine/index.html*
// @icon         https://www.sppet.cn/examine/data/imgs/favicon.ico
// @grant        none
// @license      GNU GPLv3
// ==/UserScript==

(async function () {
  'use strict';

  // 动态插入日志容器到页面
  function createLogContainer() {
    const logContainer = document.createElement('div');
    logContainer.id = 'log-container';
    logContainer.style.padding = '10px'; // 设置容器内部的边距为 10px
    logContainer.style.backgroundColor = '#333'; // 设置背景颜色为深灰色
    logContainer.style.color = '#fff'; // 设置文本颜色为白色
    logContainer.style.border = '1px solid #ddd'; // 设置边框为 1px 的浅灰色实线,以区分容器和背景
    logContainer.style.maxHeight = `${window.innerHeight / 3}px`; // 设置容器的最大高度为 200px
    logContainer.style.maxWidth = '400px'; // 设置容器的最大宽度为 400px
    logContainer.style.overflowY = 'auto'; // 当内容超过容器高度时,自动显示垂直滚动条
    logContainer.style.position = 'fixed'; // 固定位置,始终显示在页面上
    logContainer.style.top = `${window.innerHeight / 3}px`; // 设置容器顶部距离页面顶部三分之一窗口高度的位置
    logContainer.style.right = '10px'; // 距离页面右侧10px
    logContainer.style.zIndex = '1000'; // 确保在页面上层显示

    document.body.appendChild(logContainer); // 将日志容器添加到页面中

    return logContainer;
  }

  // 添加日志到日志容器
  function logPage(logContainer, message) {
    console.log(message); // 同时在控制台输出日志

    const logEntry = document.createElement('div');
    logEntry.textContent = message; // 设置日志内容
    logEntry.style.whiteSpace = 'nowrap'; // 禁止换行
    logEntry.style.overflow = 'hidden'; // 超出部分隐藏
    logEntry.style.textOverflow = 'ellipsis'; // 超出部分显示省略号
    logContainer.appendChild(logEntry); // 将日志内容添加到日志容器中
    logContainer.scrollTop = logContainer.scrollHeight; // 自动滚动到容器底部
  }

  // 格式化日期
  function formatDate() {
    // 获取 UTC 时间的毫秒数,并加上 8 小时的毫秒数 (8 * 60 * 60 * 1000)
    const offsetMilliseconds = 8 * 60 * 60 * 1000;
    const beijingTime = new Date(new Date().getTime() + offsetMilliseconds);

    // 格式化为 YYYY-MM-DD HH:MM:SS
    return beijingTime.toISOString().replace('T', ' ').split('.')[0];
  }

  // 获取课程列表
  function setupStudyControls(logContainer, course, progress, courseName) {
    let count = 0; // 用于计数已完成课程的数量
    progress.forEach(element => {if (parseFloat(element.textContent.trim()) === 100) count++}); // 如果课程进度为100,计数加1

    if (count < progress.length) { // 如果有未完成的课程
      const division = `${count}/${progress.length}` // 计算已完成课程的数量和总课程数量
      const percentage = `${count / progress.length * 100}%` // 计算已完成课程的百分比
      logPage(logContainer, `总课程完成进度: ${division} (${percentage})`);

      // 遍历所有课程,找到未完成的课程并点击继续学习按钮
      for (let i = 0; i < progress.length; i++) {
        logPage(logContainer, `${courseName[i].textContent.trim()}`); // 输出课程名称

        let progressFloat = parseFloat(progress[i].textContent.trim()); // 课程进度
        if (progressFloat < 100) {
          logPage(logContainer, `上述课程进度: ${progressFloat}%,${progressFloat === 0 ? '开始' : '继续'}学习`);
          logPage(logContainer, `若未弹出新窗口, 请检查是否被浏览器拦截`); // 新窗口有可能被拦截, 提示一下用户
          course[i].click(); // 点击继续学习按钮
          break; // 找到并点击按钮后,停止遍历
        } else {
          logPage(logContainer, `上述课程已学完, 跳过`);
        }
      }
    } else {
      logPage(logContainer, '所有课程已完成');
    }
  }

  // 针对视频元素进行特殊处理
  function setupVideoControls(video) {
    // video.play().catch(); // 播放视频(注释掉是因为只要点击 "开始学习" 或 "继续学习" 按钮就行, 无需程序干预)
    video.muted = true; // 静音视频(必须保留的原因是, 不先行静音就无法使事件监听器正常运行)
    video.addEventListener('pause', () => {video.play().catch()}); // 事件监听器:视频暂停时自动恢复播放
    video.addEventListener('volumechange', () => {video.muted = true}); // 事件监听器:视频音量变化时强制静音

    const intervalChoise = setInterval(function() {
      const choise = document.querySelector('.user_choise'); // 获取选项元素
      if (choise) {
        choise.click(); // 点击 "开始学习" 或 "继续学习" 按钮
        clearInterval(intervalChoise); // 停止轮询
      }
    }, 100); // 每隔0.1秒检查一次
  }

  // 在播放页面执行以下操作
  if (window.location.href.includes('play.do')) {
    const logContainer = createLogContainer(); // 创建日志容器
    logPage(logContainer, `程序执行时间: ${formatDate()}`);

    let video; // 声明视频变量
    const intervalVideo = setInterval(function() {
      if (!video) {
        video = document.querySelector('video'); // 获取第一个视频元素
        if (video) {
          logPage(logContainer, '找到视频, 开始监控学习进度');
          logPage(logContainer, '开始播放视频, 开启静音');
          setupVideoControls(video); // 设置视频控制
          clearInterval(intervalVideo); // 停止轮询
        } else {
          logPage(logContainer, '未找到视频, 等待加载...');
        }
      }
    }, 1500); // 每1.5秒一次URL
  } else {
    const logContainer = createLogContainer(); // 创建日志容器
    logPage(logContainer, `程序执行时间: ${formatDate()}`);

    let hasLoggedMessage = false; // 初始化一个变量控制日志框体输出
    const checkLogin = setInterval(function() {
      const login = document.querySelector('.login_btn'); // 获取登录元素
      if (login.textContent.trim() === "登录") {
        if (!hasLoggedMessage) {
          logPage(logContainer, `请先登录, 再进行后续的操作`); // 提示用户下一步的操作
          hasLoggedMessage = true; // 修改变量, 不让上述提示继续输出到日志框体中
        }
      } else {
        logPage(logContainer, `请点击学习中心, 进入需要学习的班级`); // 进一步提示用户下一步的操作
        clearInterval(checkLogin); // 停止轮询
      }
    }, 1000); // 每隔1秒检查登录状态

    const checkInterval = setInterval(function() {
      // console.log(`${formatDate()} 请点击学习中心, 进入需要学习的班级`)
      if (window.location.href.includes('stady_detail')) {
        const intervalId = setInterval(function() {
          const course = document.querySelectorAll('.btn'); // 获取所有继续学习的按钮元素
          const progress = document.querySelectorAll('.el-progress__text'); // 获取所有进度条的元素
          const courseName = document.querySelectorAll('.text_title.oneEllipsis'); // 获取所有课程的名称

          if (progress.length === 0) location.reload(); // 如果 progress.length 等于0, 刷新页面
          setupStudyControls(logContainer, course, progress, courseName);

          clearInterval(intervalId); // 停止轮询
        }, 3000); // 每隔3秒轮询一次

        clearInterval(checkInterval); // 停止检查
      }
    }, 1000); // 每隔1秒检查一次URL
  }
})();

// 在第一个页面中,添加以下脚本用于检测 localStorage 变化并执行刷新
if (window.location.href.includes('stady_detail')) {
  window.addEventListener('storage', function(event) {
    if (event.key === 'refresh' && event.newValue === 'true') {
      localStorage.removeItem('refresh');
      location.reload();
    }
  });
}