Greasy Fork

Greasy Fork is available in English.

青书学堂视频挂机

青书学堂视频自动静音播放,解放双手。支持自动播放视频、作业答案自动填入

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         青书学堂视频挂机
// @namespace    https://github.com/lanomw
// @version      1.2.3
// @description  青书学堂视频自动静音播放,解放双手。支持自动播放视频、作业答案自动填入
// @author       lanomw
// @match        *://*.qingshuxuetang.com/*
// @icon         https://degree.qingshuxuetang.com/resources/default/images/favicon.ico
// @require      https://unpkg.com/[email protected]/dist/web/pxmu.min.js
// @require      https://lib.baomitu.com/lodash.js/latest/lodash.min.js
// @run-at       document-body
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict'

    // 考试页面解除复制
    if (location.href.indexOf('ExamPaper') !== -1) {
        $('*').unbind('copy')
        return
    }

    // 做作业
    if (location.href.indexOf('ExercisePaper') !== -1) {
        listenSource([
            {
                fn: () => $('.question-detail-options .question-detail-option').length,
                callback: autoFillAnswer
            },
        ]);
        return
    }

    // 看网课
    if (location.href.indexOf('CourseShow') !== -1) {
        listenSource([
            {
                fn: () => _.has(window, 'CoursewarePlayer.videoPlayer.player'),
                callback: autoPlayVideo
            },
            {
                fn: () => _.has(window, 'CoursewareNodesManager'),
                callback: proxyRenderMenu
            }
        ]);
    }
})();

// url参数转换为对象
function UrlSearch() {
    const search = location.search.replace('?', '')
    const params = {}
    const arr = search.split('&')
    arr.forEach(item => {
        const pArr = item.split('=')
        params[pArr[0]] = pArr[1]
    })

    return params
}

/**
 * 监听资源是否执行完成
 * @param listen - 资源监听
 * [{
 *     fn: 返回值为真时,执行callback并移除任务
 *     callback: 回调
 * }]
 */
function listenSource(listen = []) {

    function setup() {
        listen.forEach((item, index) => {
            const {fn, callback} = item;

            if (fn()) {
                callback();
                listen.splice(index, 1);
            }
        })

        if (listen.length) {
            requestAnimationFrame(setup);
        }
    }

    if (listen.length) {
        requestAnimationFrame(setup);
    }
}

window.Manager = {
    search: UrlSearch(), // url参数
    menus: [], // 菜单渲染节点
}

// tree 菜单抹平为一级菜单。用于执行课程切换的数据在叶子节点,其余为无用的导航菜单
function buildMenus(nodes) {
    const menus = [];

    function recursiveNodes(nodes) {
        nodes.forEach(function (node) {
            if (node.nodes) {
                recursiveNodes(node.nodes)
            } else {
                menus.push(node)
            }
        })
    }

    recursiveNodes(nodes)

    return menus
}

// 自动播放视频
function autoPlayVideo() {
    // 静音、倍速
    CoursewarePlayer.videoPlayer.player.muted(true)
    CoursewarePlayer.videoPlayer.player.playbackRate(2)
    CoursewarePlayer.videoPlayer.player.currentTime(0)

    // 自动播放视频、播放结束跳转下一课程
    CoursewarePlayer.addListener('ended', function () {
        const nextNodeId = getNextLesson()

        if (nextNodeId) {
            CoursewareNodesManager.onMenuClick(nextNodeId)
        } else {
            pxmu.diaglog({
                congif: {
                    btncount: true,
                },
                content: {
                    text: '本课程已播放完成,请手动检查成绩',
                }
            }).then(function (res) {
                pxmu.closediaglog();
            });
        }
    })

    // 播放视频
    CoursewarePlayer.play()
}

// 菜单渲染拦截
function proxyRenderMenu() {
    const _renderMenu = CoursewareNodesManager.renderMenu

    CoursewareNodesManager.renderMenu = function (menuContainerId, coursewareNodes, onMenuClick) {
        _renderMenu(menuContainerId, coursewareNodes, onMenuClick)

        Manager.menus = buildMenus(coursewareNodes)

    }
}

// 解析 url nodeId,从菜单获取下一课程的 nodeId
function getNextLesson() {
    const menus = Manager.menus

    for (let i = 0; i < menus.length; i++) {
        if (menus[i].id === Manager.search.nodeId) {
            return (menus[i + 1] || {}).id
        }
    }
}

// 答案自动填入
function autoFillAnswer() {
    var urlSearch = UrlSearch()

    fetch(`https://degree.qingshuxuetang.com/xnsy/Student/DetailData?_t=${new Date().getMilliseconds()}&quizId=${urlSearch.quizId}`, {
        method: 'GET', headers: {
            Host: 'degree.qingshuxuetang.com',
            Cookie: Object.entries(Cookies.get()).map(([key, value]) => `${key}=${value}`).join('; '),
            Referer: `https://degree.qingshuxuetang.com/xnsy/Student/ExercisePaper?courseId=${urlSearch.courseId}&quizId=${urlSearch.quizId}&teachPlanId=${urlSearch.teachPlanId}&periodId=${urlSearch.periodId}`,
            'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': 'macOS',
            'Sec-Fetch-Dest': 'empty',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Site': 'same-origin',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
            'X-Requested-With': 'XMLHttpRequest',
        },
    }).then(res => res.json()).then(res => {
        var questions = res.data.paperDetail.questions

        Object.values(questions).forEach(item => {
            // 处理单选/多选 答案填入
            for (let i = 0; i < item.solution.length; i++) {
                $(`#${item.questionId}_${item.solution.charAt(i)}`).click()
            }
        })

        pxmu.success({
            msg: '答案已自动填入', bg: '#4CC443',
        })
    }).catch(err => {
        pxmu.fail({
            msg: '答案已填入失败。请手动填入答案', bg: 'red',
        })

        setTimeout(() => {
            // 异常则直接打开答案查看页面。窗口可能会被浏览器拦截。需要允许
            window.open(location.href.replace('ExercisePaper', 'ViewQuiz'), '_blank')
        }, 1500)

        console.error(err)
    });
}