针对2023暑期教师研修更新,16倍速,自动答题,自动切换列表中的视频,后台播放,学时不更新的解决方法看下面
// ==UserScript==// @name 国家中小学智慧教育##刷课脚本(16倍速,自动答题,自动切换列表中的视频,后台播放,学时不更新的解决方法看下面)// @namespace http://tampermonkey.net/// @version 3.3.3// @license CC BY-NC-SA// @description 针对2023暑期教师研修更新,16倍速,自动答题,自动切换列表中的视频,后台播放,学时不更新的解决方法看下面// @author HGGshiwo// @match https://*.zxx.edu.cn/teacherTraining/courseDetail*// @match https://basic.smartedu.cn/teacherTraining/courseDetail*// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==// @grant none// ==/UserScript==(function () {("use strict");const courses = [{ course_id: '08e005b6-442f-40d0-bf5d-ac3ed35feaeb', resNo: 1, groupNo: 2 },{ course_id: '1a11eeee-8d43-4d3b-8818-1b842a0ee966', resNo: 1, groupNo: 1 },{ course_id: '47678428-4c27-4526-a8cf-15fb65138617', resNo: 1, groupNo: 1 }]// functionconst changInputValue = (inputDom, newText) => {if (!inputDom) {return;}let lastValue = inputDom.value;inputDom.value = newText;let event = new Event("input", { bubbles: true });event.simulated = true;let tracker = inputDom._valueTracker;if (tracker) {tracker.setValue(lastValue);}inputDom.dispatchEvent(event);};function findLastIndex(array, predicate) {// 先将数组反转const reversedArray = array.slice().reverse();// 使用findIndex找到满足条件的元素的索引const index = reversedArray.findIndex(predicate);if (index === -1) {return -1; // 若未找到,则直接返回-1}// 计算满足条件的元素在原数组中的索引const originalIndex = array.length - 1 - index;return originalIndex;}const State = {LoadPage: "loadPage",GetActive: "getActive",SwitchSource: "switchSource",PlayVideo: "playVideo",HandlePlayRes: "handlePlayRes",WaitPlay: "waitPlay",SwitchActive: "switchActive",SwitchFirst: "switchFirst",TaskEnd: "taskEnd",}var state = State.LoadPage;var groups = undefined;var groupNo = undefined;var resItems = undefined;var resNo = undefined;var videoErr = undefined;var interval = undefined;const func_table = {loadPage: () => {var video = document.querySelector("video");var resItems = document.querySelector(".resource-item");if (!!video && !!resItems) {return State.GetActive}else {console.log(666, "等待视频加载")return State.LoadPage}},getActive: () => {groups = document.querySelector(".fish-collapse.fish-collapse-icon-position-right.tcourse-catalog.undefined").childNodes//适配chrome版本低于97, firefox版本低于108的用户groupNo = findLastIndex([...groups], group => {resItems = [...group.querySelectorAll(".resource-item")]resNo = resItems.findIndex(resItem => resItem.className.includes("active"))return resNo !== -1})return State.SwitchSource},switchSource: () => {//视频修改为标清 zxj663建议添加let sped = document.querySelector("div.vjs-menu-button.vjs-menu-button-popup.vjs-control.vjs-button.vjs-resolution-button > span");if(!sped) {return State.SwitchSource}if (sped.innerText != "标清") {document.querySelector("div.vjs-menu-button.vjs-menu-button-popup.vjs-control.vjs-button.vjs-resolution-button > div > ul > li:nth-child(3) > span.vjs-menu-item-text").click();}return State.PlayVideo},playVideo: () => {let icons = resItems[resNo].getElementsByClassName("iconfont");if (icons[0] && icons[0].className.includes("icon_checkbox_fill")) {console.log(666, `第${groupNo + 1}组, 第${resNo + 1}个视频已经观看`);return State.SwitchActive}console.log(666, `开始观看: 第${resNo + 1}个视频,第${groupNo + 1}组`);var video = document.querySelector("video");if (!!video) {video.muted = true;video.play().then(() => {videoErr = false}).catch((err) => {console.log(666, err);videoErr = true});renderMenu()video.playbackRate = rateMenu[active].value;video.addEventListener("pause", () => state = State.PlayVideo, false)video.addEventListener("ended", () => state = State.SwitchActive, false)return State.HandlePlayRes}else {//是pdf,直接跳下一个return State.SwitchActive}},handlePlayRes: () => {//处理播放的结果return videoErr === undefined ? State.HandlePlayRes : videoErr ? State.PlayVideo : State.WaitPlay},waitPlay: () => { return state },switchActive: () => {//从列表中查找当前的课程const index = courses.findIndex(course => window.location.href.includes(course.course_id))if (index !== -1 && (courses[index].groupNo < groupNo || (courses[index].groupNo == groupNo && courses[index].resNo <= resNo))) {if (index + 1 < courses.length) {console.log(666, "进入下一个学习页面");window.open(`https://basic.smartedu.cn/teacherTraining/courseDetail?courseId=${courses[index + 1].course_id}`, "_self");}else {return State.TaskEnd}}//如果没看完当前组,则观看当前组的下一个视频if (resNo + 1 != resItems.length) {resNo += 1resItems[resNo].click();console.log(666, `点击当前组的下一个视频`);return State.SwitchSource;}//如果看完了当前组,没看完当前页面,则看下一个页面if (groupNo + 1 != groups.length) {console.log(666, `点击下一组的第一个视频`);groupNo += 1let header = groups[groupNo].querySelector(".fish-collapse-header")if (!!header) {header.click()}return State.SwitchFirst}//如果都看完了return State.TaskEnd},switchFirst: () => {resItems = groups[groupNo].getElementsByClassName("resource-item");resNo = 0resItems[resNo].click();return State.SwitchSource},taskEnd: () => {if(!!interval) {clearInterval(interval)}window.alert("都看完了")return State.TaskEnd;}}const setVideoHandler = () => {interval = setInterval(() => {try {var popup = false;[".nqti-option", ".index-module_footer_wewZ2 .fish-btn", ".fish-modal-confirm-btns .fish-btn"].forEach(selector => {let dom = document.querySelector(selector)if (!!dom) {popup = truedom.click()}})//增加填空题支持var inputForm = document.querySelector(".index-module_box_blt8G");if (!!inputForm) {popup = truechangInputValue(inputForm.getElementsByTagName("input")[1], " ");}if (!popup) {state = func_table[state]()console.log(666, `${state}已经完成!`)}else {console.log(666, "处理弹窗")}}catch (err) {console.log(666, `${state}: ${err}`)}}, 1000)}//修改播放速度const changeRate = (rate, index) => {localStorage.setItem("_active", `${index}`)active = indexdocument.querySelector(".vjs-playback-rate-value").innerHTML = rateMenu[index].titledocument.getElementsByTagName("video")[0].playbackRate = ratereturn false}//修改速度菜单const renderMenu = () => {document.querySelector(".vjs-playback-rate .vjs-menu-content").innerHTML =rateMenu.map((rate, index) =>`<li class="vjs-menu-item" tabindex="-1" role="menuitemradio" aria-disabled="false" aria-checked="${index == active}"><span class="vjs-menu-item-text">${rate.title}</span><span class="vjs-control-text" aria-live="polite"></span></li>`).join(" ")const doms = document.querySelectorAll(".vjs-playback-rate .vjs-menu-content .vjs-menu-item")rateMenu.forEach((rate, index) => {doms[index].addEventListener("click", () => changeRate(rate.value, index), false)})//显示速度控制菜单const rateButtons = document.getElementsByClassName("vjs-playback-rate vjs-menu-button vjs-menu-button-popup vjs-control vjs-button vjs-hidden")if (rateButtons.length > 0) {rateButtons[0].classList.remove("vjs-hidden")document.querySelector(".vjs-playback-rate-value").innerHTML = rateMenu[active].title}}//获取速度let activeStr = localStorage.getItem("_active")const rateMenu = [{ title: "1x", value: 1 }, { title: "1.5x", value: 1.5 }, { title: "2x", value: 2 }, { title: "2.5x", value: 2.5 }, { title: "3x", value: 3 }]let active = activeStr === null ? 0 : parseInt(activeStr)//下面开始运行脚本console.log(666, "开始执行脚本")setVideoHandler();})();