在浙学自动刷课

可以快速地自动看完在浙学上一门科目的所有视频和文档。

目前為 2022-07-24 提交的版本,檢視 最新版本

// ==UserScript==
// @name         在浙学自动刷课
// @namespace    Vikrant
// @version      1.0.0
// @description  可以快速地自动看完在浙学上一门科目的所有视频和文档。
// @author       Vikrant4096
// @match        https://www.zjooc.cn/ucenter/student/course/study/*/plan/detail/*
// @grant        unsafeWindow
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @license      GNU GPLv3
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';
    let videoRate = 16                          //倍速播放视频的倍数,最大为16倍,默认为16倍,网速慢的话可以调小一些
    let delay = 2000                            //某些环节等待加载的延迟,如果网络卡顿可以调大一些(单位:ms)

    let win = unsafeWindow
    let winDoc = unsafeWindow.document

    let labelList = []
    let dirList = []

    let labelNow = null
    let dirNow = null

    let dirIndex = 0
    let labelIndex = 0

    if (videoRate < 0 || videoRate > 16) {                      //防小天才
        videoRate = 16
        console.log('视频倍速不得大于16倍或小于0!')
    }
    if (delay < 0) {
        delay = 2000
        console.log('delay不得小于0!')
    }

    let nullFunction = function () { }                          //空函数
    let find = {                                                //查找类函数的集合
        _dir: "#pane-Chapter>div>ul>li.el-submenu>ul>li>span",
        dir: function () {                                      //获取每一个小章节存入数组
            let list = winDoc.querySelectorAll(
                "#pane-Chapter>div>ul>li.el-submenu>ul>li>span"
            )
            return list
        },

        _videoLabel: "div>span.label>i.icon-shipin:not(.complete)+span",
        videoLabel: function () {                               //获取每一个小章节里上方内容是视频(未看)的标签存入数组
            let list = winDoc.querySelectorAll(
                "div>span.label>i.icon-shipin:not(.complete)+span"
            )
            return list
        },

        _button: "div>div>div.contain-bottom>button",
        button: function () {                   //获取小章节里每一个文档的“完成学习”按钮存入数组
            let list = winDoc.querySelectorAll(
                "div>div>div.contain-bottom>button"
            )
            return list
        }
    }

    function doAfterLoad(selector, event, interval = 1000) { //当元素加载后执行特定函数
        let scan = setInterval(() => {
            let load = winDoc.querySelector(selector)
            if (load) {
                stop(scan)
                event()
            }
        }, interval)
        function stop(obj) {                              //函数内定义的stop(),方便在setInterval内部停止自身
            clearInterval(obj)
        }
    }

    function nextDir() {                                  //跳转至下一个小章节
        if (++dirIndex > dirList.length - 1) {
            end()
        } else {
            dirList[dirIndex].click()
            dirNow = dirList[dirIndex]
            setTimeout(() => {
                labelList = find.videoLabel()             //初始化labelList相关的值
                labelIndex = 0
                labelNow = labelList[0]
                if (labelList.length == 0) {
                    nextDir()
                } else {
                    labelNow.click()
                    setTimeout(() => {
                        videoPlay(nextLabel)
                        docPass()
                    }, delay)
                }
            }, delay)
        }
    }

    function nextLabel() {                                //点击下一个未观看的视频标签
        if (++labelIndex > labelList.length - 1) {
            nextDir()
        } else {
            labelList[labelIndex].click()
            labelNow = labelList[labelIndex]
            setTimeout(() => {
                videoPlay(nextLabel)
            }, delay)
        }
    }

    function videoPlay(afterEvent = nullFunction) {       //播放当前页面的视频并指定播放完之后执行的函数
        doAfterLoad("video", () => {
            let video = winDoc.querySelector("video")
            video.muted = true                            //静音
            video.playbackRate = videoRate                //调倍速
            video.play()                                  //开始播放视频
            video.addEventListener('ended', () => {       //监听视频是否播放完毕
                afterEvent()
            })
        })
    }

    function docPass() {                                   //自动点击所有“完成学习”按钮
        doAfterLoad(find._button, () => {
            let button = find.button()
            for (let i = 0; i < button.length; i++) {
                button[i].click()
            }
        })
    }

    function end() {                                        //结束函数
        winDoc.querySelector("#passButton").innerHTML = "完成!"
        GM_addStyle(`
                #passButton{
                    background-color:#e67e22
                }
            `)
    }

    function main() {                                       //主函数
        setTimeout(() => {
            dirList = find.dir()                            //初始化dirList和labelList以及相关的值
            labelList = find.videoLabel()
            dirIndex = 0
            labelIndex = 0
            dirNow = dirList[0]
            labelNow = labelList[0]
            dirList[0].click()
            setTimeout(() => {
                if (labelList.length == 0) {
                    nextDir()
                } else {
                    labelList[0].click()
                    videoPlay(nextLabel)
                }
            }, delay);
        }, delay);
    }

    let passButton = winDoc.createElement('button')            //创建按钮
    passButton.id = 'passButton'
    passButton.innerHTML = '开始刷课'
    win.onload = () => {                                       //在页面加载时添加按钮
        let header = winDoc.querySelector("#app>div>section>section>header")
        header.appendChild(passButton)
        passButton.onclick = () => {                           //指定按钮点击事件
            main()
            passButton.innerHTML = '刷课中…'
            GM_addStyle(`
                #passButton{
                    background-color:#53555e
                }
            `)
            passButton.onclick = nullFunction              //按钮点击后移除点击事件
        }
    }                                                      //定义按钮样式
    GM_addStyle(`                                          
        #passButton{
            background-color: #1192ff;
            color: white;
            text-align: center;
            padding: 0px 32px;
            text-decoration: none;
            display: inline-block;
            font-size: 14px;
        }
    `)
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址