// ==UserScript== // @name Dongying Continuing Education // @namespace http://tampermonkey.net/ // @version 1.2 // @description from ai build // @author xuefeng // @match *://*.yxlearning.com/* // @grant none // @license // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 确保页面完全加载后再执行脚本 window.onload = function () { // 确保页面完全加载后再执行脚本,在这使用的是延时的办法 setTimeout(function () { // 获取当前页所有章节的元素的ID function getAllUnitID() { // 声明一个存储当前课程的每章节id的数组 var allUnitID = []; // 获取所有 class 为 "pt5" 的 ul 元素 var ulElements = document.querySelectorAll('ul.pt5'); // 遍历每个 ul 元素 ulElements.forEach(function (ul) { // 获取 ul 元素下的所有 li 元素 var liElements = ul.querySelectorAll('li'); // 遍历每个 li 元素并获取其 id liElements.forEach(function (li) { allUnitID.push(li.id); }); }); console.log("已经获取所有的章节ID", allUnitID); return allUnitID; } // 找到当前章节的管视频播放的那个video标签,也即当前页面真实的视频标签 // nowUnitVideoElement 当前章节真实的视频元素标签 function nowUnitTrueVideo() { var nowUnitTrueVideoElement = document.querySelectorAll("video"); for (var i = 0; i < nowUnitTrueVideoElement.length; i++) { if (nowUnitTrueVideoElement[i].duration) { // 判断当前页面是否有视频标签 duration是看所拿到的视频标签是否有播放时长的属性,如果有那就是真实的视频元素 return nowUnitTrueVideoElement[i];//拿到真实的视频元素就返回给调用该函数的变量 } } } // 点击这个视频所在的章节(即点击nowUnitID,即点击这个对应标题进入视频播放页),并确保完全进入该章节后改变promise状态 // inNowUnitID 进入当前的章节,以便于播放该小标题下的视频 // nowUnitID 当前小标题的ID(即当前章节的ID) const inNowUnitID = (nowUnitID) => { return new Promise((resolve) => { // promise 一旦建立就立即执行,但是状态的改变需要resolve() document.querySelectorAll('li[id="' + nowUnitID + '"]')[0].click(); setTimeout(() => { resolve("等待时间到,应该已完全进入该章节") }, 40000) //往往是刚通过上句.click()点击该视频之后,改小标题下的视频还没有出来,如果此时接着点击播放视频,就会失败,所以添加了一个延时点击。 }) } // 进入当前章节后找到真正的视频元素,并且保持持续播放,直到100% // getNowUnitTrueVideoElement_AND_keepVideoPlay 获得当前小章节的真实视频元素 并 保证持续播放 // nowUnitID:当前小章节的ID const getNowUnitTrueVideoElement_AND_keepVideoPlay = (nowUnitID) => { //传入nowUnitID,也就是传入当前的小章节ID,然后在本函数内嵌套有chekckVideoPlay函数,会用到 return new Promise((resolve) => { const nowUnitTrueVideoElement = () => { //定义一个函数,用于获取当前小章节的视频元素 var nowUnitTrueVideoElement = document.querySelectorAll("video"); //获取当前页面的所有video标签 for (var i = 0; i < nowUnitTrueVideoElement.length; i++) { //遍历所有video标签 if (nowUnitTrueVideoElement[i].duration) { //判断当前video标签是否为真实视频(即有duration属性) return nowUnitTrueVideoElement[i]; //返回真实视频 } } } if (nowUnitTrueVideoElement().paused) { // 如果视频暂停 nowUnitTrueVideoElement().muted = true; // 静音 nowUnitTrueVideoElement().play(); // 就点击播放 console.log("自动点击本页视频播放"); } const checkVideo_IS_Done = setInterval(() => { // 检测视频是否播放完毕,只有播放完毕之后才允许该promise resolve() console.log("当前章节视频完成了" + document.querySelector('[id="' + nowUnitID + '-badge"]').textContent); if (document.querySelector('[id="' + nowUnitID + '-badge"]').textContent == '100%') { //当播放已经达到100% clearInterval(checkVideo_IS_Done); //清除定时检查功能 resolve("本节播放完成") } }, 1000) }) } // 视频播放特殊处理,检测弹出的答题框 function autoClickSkipButton() { // 选择需要观察变动的节点 var targetNode = document.body; // 配置观察选项 var config = { childList: true, subtree: true }; const changecallback = function (mutations) { mutations.forEach(function (mutation) { if (document.querySelector('div.ccQuestion')) { // 找到并点击 "跳过" 按钮 var skipButton = document.querySelector('input[value="跳过"]'); if (skipButton) { skipButton.click(); // 重新启动观察者,以便处理后续的变化 observer.disconnect(); observer.observe(document.body, config); } } }); }; // 创建一个观察者实例 var observer = new MutationObserver(changecallback); // 开始观察 observer.observe(targetNode, config); console.log("已开启自动跳过答题框"); } //-------------------------事件顺序------------------------------- // 获取本课程所有的章节ID(也即allUnitID) const allUnitID = getAllUnitID(); // 开始播放课程所有章节 const start = async (allUnitID) => { console.log("Type of allUnitID:", typeof allUnitID); for (const nowUnitID of allUnitID) { const res1 = await inNowUnitID(nowUnitID) console.log(res1) const res2 = await getNowUnitTrueVideoElement_AND_keepVideoPlay(nowUnitID) console.log(res2) } } // 开始 start(allUnitID); // 调用观察者确保跳过答题框 autoClickSkipButton(); // 不需要传入参数 }, 20000); // 延迟10秒执行 }; })();