wsxy_Learn

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

Version vom 05.02.2020. Aktuellste Version

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greatest.deepsurf.us/scripts/396002/770268/wsxy_Learn.js

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

// 自动报名高学分课程。2020年初,高于1学分的有且仅有20门3学分课程。
const autoSignupMaxCredit = async () => {
  // 需要 iframe 提升才会执行
  if (window.top === window.self) {
    let courses = document.querySelectorAll('#requiredCourseTable .course');
    for await (let c of courses) {
      let coursePk = c.getElementsByClassName('coursePk')[0].textContent;
      let title = c.getElementsByClassName('title')[0].getAttribute('title');
      let jdjs = c.getElementsByClassName('jdjs')[0].textContent; // 进度
      let csInfo = await getCourseInfo(coursePk);
      let csCredit = csInfo.courseCredit;
      if (jdjs === '未报名') {
        // 自动报名高学分课程
        if (csCredit > 1) {
          console.log(`${csCredit}学分:${title}`);
          c.click();
          console.log('Click:' + title);
          const info = document.getElementsByClassName('layui-layer-btn0');
          if (info.length === 1) {
            document.getElementsByClassName('layui-layer-btn0')[0].click();
            console.log('报名:' + title);
          }
        }
      }
    }
  }
};

// 自动报名高学时课程
const autoSignupMaxTime = async () => {
  // 需要 iframe 提升才会执行
  if (window.top === window.self) {
    // 数组存储所有未报名课程故的课时数据
    let timesArray = [];
    // 获取所有未报名课程的子节点。若直接使用所有必修课程,可能出现课程数字相同而对已报名课程二次点击。
    let unCoursesJdpoint = document.querySelectorAll(
      '#requiredCourseTable .course > .jdpoint[style]'
    );
    for await (let u of unCoursesJdpoint) {
      // 由子节点获取父节点从而获取课程编号
      let coursePk = u.parentNode.getElementsByClassName('coursePk')[0].textContent;
      let csInfo = await getCourseInfo(coursePk);
      let csTime = csInfo.courseTime;
      timesArray.push(csTime);
    }
    let longest = Math.max(...timesArray);
    console.log(longest);
    let indexMax = timesArray.indexOf(longest);
    // 出现过该错误 indexMax === -Infinity 导致:
    // TypeError: unCoursesJdpoint[timesArray.indexOf(...)] is undefined
    if (unCoursesJdpoint[indexMax]) {
      unCoursesJdpoint[indexMax].parentNode.click();
    } else {
      location.reload(true);
    }
    const notice = document.getElementsByClassName('layui-layer-btn0');
    if (notice.length === 1) {
      document.getElementsByClassName('layui-layer-btn0')[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')); //用户已获得的总学分
    // 全部未完成必修课程。为同时解决学时学分问题,只关注必修课。
    const courses = document.querySelectorAll('#requiredCourseTable .course');
    // 初始化预期学时/学分为已得值
    let pendingCredit = user_required_credit;
    let pendingTime = user_total_hour;
    // 向预期学时/学分添加已报名课程数据
    for await (let c of courses) {
      let coursePk = c.getElementsByClassName('coursePk')[0].textContent;
      let applyPk = c.getElementsByClassName('applyPk')[0].textContent;
      let jdjs = c.getElementsByClassName('jdjs')[0].textContent; // 完成进度定性
      if (jdjs === '完成进度') {
        let csInfo = await getCourseInfo(coursePk);
        let csCredit = csInfo.courseCredit;
        let csTime = csInfo.courseTime;
        checkVideoPlayerType(applyPk, (isNewPlayer, applyPk) => {
          if (isNewPlayer) {
            console.log(`跳过 applyPk: ${applyPk}`);
          } else {
            pendingCredit += csCredit;
            pendingTime += csTime;
          }
        });
      }
    }
    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 {
      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;
              }
            }
          }
        }
      }
    }
  }
};