Greasy Fork

wsxy_Learn

网上学院函数库:自动报名、听课、考试等

目前为 2020-02-05 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/396002/770310/wsxy_Learn.js

// ==UserScript==
// @name          wsxy_Learn
// @namespace     Vionlentmonkey
// @version       0.8.1
// @description   网上学院函数库:自动报名、听课、考试等
// ==/UserScript==

// 自动报名高学分课程。2020 年初,高于 1 学分的有且仅有 20 门 3 学分课程。
const autoSignupMaxCredit = async () => {
  // 需要 iframe 提升才会执行
  if (window.top === window.self) {
    let courses = document.querySelectorAll('#requiredCourseTable .course');
    const waitCourseInfo = JSON.parse(localStorage.getItem('waitCourseInfo'));
    for (let w of waitCourseInfo) {
      // 学分高且未报名。
      // 取消报名的也有 apply_pk,但没有进度点数 jdpoint 。
      if (w.courseCredit > 1 && !w.jdpoint) {
        console.log(w.course_name);
        for (let c of courses) {
          let coursePk = Number(c.getElementsByClassName('coursePk')[0].textContent);
          // 不能作为判断依据。
          if (coursePk === w.course_pk) {
            c.click();
            const btn = document.getElementsByClassName('layui-layer-btn0');
            if (btn.length === 1) {
              btn[0].click();
            }
          }
        }
      }
    }
  }
};

// 自动报名高学时课程
const autoSignupMaxTime = async () => {
  // 需要 iframe 提升才会执行
  if (window.top === window.self) {
    // 存储所有未报名课程的课时和对应编号
    let timesMap = new Map();
    const waitCourseInfo = JSON.parse(localStorage.getItem('waitCourseInfo'));
    for (let w of waitCourseInfo) {
      // 报名后等于零,undefined 代表未报名
      if (w.jdpoint === undefined) {
        timesMap.set(w.course_pk, w.courseTime);
      }
    }
    let timesArray = [...timesMap.values()];
    let longest = Math.max(...timesArray);
    console.log(longest);
    let maxTimeCourse_pk = 0;
    for (let m of timesMap) {
      if (m[1] === longest) {
        maxTimeCourse_pk = m[0];
      }
    }
    //console.log(maxTimeCourse_pk);
    let courses = document.querySelectorAll('#requiredCourseTable .course');
    for (let c of courses) {
      let coursePk = Number(c.getElementsByClassName('coursePk')[0].textContent);
      // 不能作为判断依据。
      if (coursePk === maxTimeCourse_pk) {
        c.click();
        const btn = document.getElementsByClassName('layui-layer-btn0');
        if (btn.length === 1) {
          btn[0].click();
        }
      }
    }
  }
};

const autoOpenExam = async exams => {
  for await (let exam of exams) {
    const examURL = location.origin + '/sfxzwsxy/' + exam.getAttribute('onclick').split("'")[1];
    // 魔法打开的考卷确认交卷后不能自动关闭,只得如此暴力处理,1分钟后强行关闭。
    let autoExam = GM_openInTab(examURL, true);
    setTimeout(autoExam.close, 60000);
  }
};

const autoOpenTrain = async (isNewPlayer, applyPk) => {
  if (isNewPlayer) {
    console.log(`跳过 applyPk: ${applyPk}`);
  } else {
    const trainURL =
      location.origin +
      '/sfxzwsxy/jypxks/modules/train/ware/course_ware_view.jsp?applyPk=' +
      applyPk +
      '&courseType=1';
    const openClose = GM_openInTab(trainURL, true);
    // 25分钟自动关闭
    setTimeout(openClose.close, 1500000);
  }
};

const autoLearn = async exams => {
  if (window.top === window.self) {
    // 30 分钟刷新一次
    setInterval(() => {
      location.reload(true);
    }, 1800000);
    const total_hour = Number(localStorage.getItem('total_hour')); //规定需达到的总学时
    const required_hour = Number(localStorage.getItem('required_hour')); //规定需达到的必修学时
    const required_credit = Number(localStorage.getItem('required_credit')); //规定需达到的总学分
    const user_total_hour = Number(localStorage.getItem('user_total_hour')); //用户已获得的总学时
    const user_required_hour = Number(localStorage.getItem('user_required_hour')); //用户已获得的必修学时
    const user_required_credit = Number(localStorage.getItem('user_required_credit')); //用户已获得的总学分

    console.log(`已获得:必修学时:${user_required_hour},学分:${user_required_credit}`);
    // 判断是否已完成。首次在新标签页打开本页显然是未完成,但刷新后可能进入已完成状态。
    if (
      user_total_hour >= total_hour &&
      user_required_hour >= required_hour &&
      user_required_credit >= required_credit
    ) {
      console.log(`本学年任务已经完成`);
      return;
    } else {
      // 全部未完成必修课程。为同时解决学时学分问题,只关注必修课。
      const waitCourseInfo = JSON.parse(localStorage.getItem('waitCourseInfo'));
      //console.log(waitCourseInfo);
      const courses = document.querySelectorAll('#requiredCourseTable .course');
      // 初始化预期学时/学分为已得值
      let pendingCredit = user_required_credit;
      let pendingTime = user_total_hour;
      // 向预期学时/学分添加已报名课程数据
      for (w of waitCourseInfo) {
        // jdpoint 保证已报名,否则无法处理取消报名的问题
        if (w.player === 'old' && w.jdpoint >= 0) {
          pendingCredit += w.courseCredit;
          pendingTime += w.courseTime;
        }
      }
      if (user_required_credit < required_credit && exams.length > 0) {
        console.log('学分未满,有待考试课程');
        await autoOpenExam(exams);
        // 1分钟后考完关闭,2分钟后刷新
        setTimeout(() => {
          location.reload(true);
        }, 120000);
      } else if (pendingTime < total_hour) {
        console.log(
          `已报名:必修学时:${pendingTime.toFixed(1)},学分:${pendingCredit},继续报名。`
        );
        autoSignupMaxTime();
      } else if (pendingTime >= total_hour && pendingCredit < required_credit) {
        // 因为全部学习必修课,出现本状况可能很小,暂不处理
        console.log(
          `已报名:必修学时:${pendingTime.toFixed(1)},学分:${pendingCredit},有待处理。`
        );
      } else if (pendingTime >= total_hour && pendingCredit >= required_credit) {
        console.log(
          `已报名:必修学时:${pendingTime.toFixed(1)},学分:${pendingCredit},已达预期。`
        );
        if (user_required_hour < total_hour) {
          console.log('学时未满,自动打开已报名课程,将定时关闭。');
          let i = 0;
          for await (let c of courses) {
            let applyPk = c.getElementsByClassName('applyPk')[0].textContent;
            let jdjs = c.getElementsByClassName('jdjs')[0].textContent; // 完成进度定性
            // 未报名课程 applyPk === '',取消报名的课程却能直接获取 applyPk,可能不适合使用 for length++ 循环
            if (jdjs === '完成进度') {
              if (i < GM_config.get('batch')) {
                // 部分少见的新型播放器会弹出 confirm,避开为宜
                checkVideoPlayerType(applyPk, autoOpenTrain);
                i++;
              } else {
                // 跳过的课程一样会计数,可能不准
                console.log(`已尝试批量打开${i}个课程`);
                return;
              }
            }
          }
        }
      }
    }
  }
};