tutu / 以训兴业

// ==UserScript==
// @namespace    https://openuserjs.org/user/tutu
// @name         以训兴业
// @version      1.3.6
// @description   以训兴业视频播放小助手
// @author       tutu
// @license       MIT
// @copyright     2021, tutu (https://openuserjs.org/users/tutu)
// @icon         https://zpimg.cn/a/img/logo/bj_wap.png
// @include      *://www.bjjnts.cn/*
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
// @updateURL https://openuserjs.org/meta/tutu/以训兴业.meta.js
// @downloadURL https://openuserjs.org/install/tutu/以训兴业.user.js
// @grant        GM_notification
// @grant        window.focus
// @grant window.onurlchange
// @note 1.2.1 简化视频播放逻辑
// @note 1.2.2 fix定时检测视频是否播放完成bug
// @note 1.3.0 播放视频中需要输入验证码或人脸识别发送chrome通知
// @note 1.3.1 加入urlchange判断逻辑
// @note 1.3.2 chrome notifcation bugfix
// @note 1.3.3 refactor refreshVideoRouteLogic
// @note 1.3.4 增加通过考试的控制台输出逻辑
// @note 1.3.5 更新icon图标
// @note 1.3.6 修改include及刷新视频逻辑
// @noframes
// ==/UserScript==

(function () {
  'use strict';

  refreshVideoRouteLogic()
  // 单页应用路由变化判断
  if (window.onurlchange === null) {
    window.addEventListener('urlchange', () => {
      refreshVideoRouteLogic()
    });
  }

  function delayExecFn(fn, delay = 2e3) {
    const seed = setTimeout(function () {
      clearTimeout(seed)
      fn();
    }, delay)
  }

  function notify(text = '需要人工介入了哦!') {
    let handled = false
    return function () {
      if (handled) return
      handled = true
      GM_notification({
        title: '京训钉',
        text,
        timeout: 3 * 60 * 1000, // 3分钟
        image: "https://zpimg.cn/a/img/logo/bj_wap.png",
        ondone: function(){
                delayExecFn(function () {
            handled = false
          }, 60e3)
        },
        onclick: function () {
          window.focus()
          delayExecFn(function () {
            handled = false
          }, 60e3)
        }
      })

    }
  }

  const normalNotifyFn = notify()
  const FINISH_NOTIFY_MSG = '播放完了, 可以去考试啦!'
  const finishedNotifyFn = notify(FINISH_NOTIFY_MSG)

  // 视频播放界面刷新逻辑
  function refreshVideoRouteLogic() {
    const {
      pathname,
      search
    } = location
    const currLoc = pathname + search;

    if (pathname !== '/study/video') return

    /*
     * 获取未完成的课程列表里
     */
    function getUnFinishedFirstClassInfo() {
      const unFinishedClasses = $('div[class^="progress_get_on"],div[class^="not_start"]')
      if (unFinishedClasses.length) {
        const unFinishedFirstClass = unFinishedClasses.eq(0).closest('a')
        const href = unFinishedFirstClass.attr('href')
        const title = unFinishedFirstClass.find('span[class^="units_title"]').text()
        const duration = unFinishedFirstClass.find('span[class^="time_box"]').text().slice(1, -1)
        return {
          href,
          title,
          duration
        }
      }
      return {};
    }

    /*
     * 播放第一个未完成的课程
     */
    function playFirstUnFinishedClass() {
      const {
        href,
        title,
        duration
      } = getUnFinishedFirstClassInfo()
      // 没有未完成的课程,即所有课程都已播放完毕
      if (!href) {
        console.log(FINISH_NOTIFY_MSG)
        return
      }
      // 当有未完成播放的课程时,优先播放未完成的课程
      else if (href !== currLoc) {
        console.log(`自动未完成的课程. \n课程题目:${title}, 总时长:${duration}`)
        delayExecFn(function () {
          location.replace(href)
        }, 3e3)
      }
    }

    /*
     * 播放DOM中的视频
     */
    function playVideo() {
      const videoDom = document.querySelector('video')
      if (videoDom) {
        videoDom.autoplay = true
        videoDom.muted = true;
        videoDom.playbackRate = 1.1;
        videoDom.setAttribute('controls', 'controls')
        videoDom.play()
      }
    }

    /*
     * 定时检测视频播放进度
     */
    function intervalDetctVideoPlayProgress() {
      const interSeed = setInterval(function () {
        // 检测是否有验证码或者人脸识别弹框
        const isNotifiy = !!$('div.ant-modal').length;
        if (isNotifiy) {
          normalNotifyFn()
        }
        
        const isPassedTest = !!$('div[class^="test_wrap"] span.anticon-check-circle').length
        if(isPassedTest) {
            clearInterval(interSeed)
            console.log('已经通过考试,可以去学习新的课程啦!')
        }

        // 总时长
        const duration = $('.duration').text()
        // 当前播放时间
        const currTime = $('.current-time').text()
        // 完成当前视频播放
        if (currTime === duration) {
          clearInterval(interSeed)
          const {
            href
          } = getUnFinishedFirstClassInfo()
          href ? location.replace(href) : finishedNotifyFn()
        }
      }, 2e3)
    }

    delayExecFn(function () {
      playFirstUnFinishedClass()
      playVideo()
      intervalDetctVideoPlayProgress()

    })
  }

})();