NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==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() }) } })();