Greasy Fork

Greasy Fork is available in English.

国家开放大学课程视频后台播放

提升学习效率

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         国家开放大学课程视频后台播放
// @namespace    http://tampermonkey.net/
// @version      2.4
// @description  提升学习效率
// @author       TurbMZ
// @license      MIT
// @match        https://moodle.syxy.ouchn.cn/mod/*/view.php*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ouchn.cn
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    let cache_status = localStorage.getItem('_my_tamermonkey_status_');
    let cache_loop_status = localStorage.getItem('_my_tamermonkey_loop_status_');
    console.log('后台播放缓存状态',cache_status);
    console.log('后台循环缓存状态',cache_loop_status);
    if(cache_status === null) {
       cache_status= 0;
    } else {
       cache_status = JSON.parse(cache_status);
    }
    if(cache_loop_status === null){
       cache_loop_status = 0;
    } else {
       cache_loop_status = JSON.parse(cache_loop_status);
    }
    let loop_status = cache_loop_status || 0;
    let status = cache_status || 0;
    localStorage.setItem('_my_tamermonkey_status_', status);
    localStorage.setItem('_my_tamermonkey_loop_status_',loop_status);

    let _my_tamermonkey_speed_ = 1;
    const speedMap = [ 1, 1.5, 2, 4 ];
    const container = document.getElementById('page-content');
    const navDom = document.querySelector('.mobile_course');
    const cursess = navDom.querySelectorAll('.activity');
    const list = Array.from(cursess).filter(item=>{
        return Array.from(item.classList).includes('page') ||
               Array.from(item.classList).includes('url');
    })
    let videoDom = document.getElementsByTagName('VIDEO')[0];
    let tryTimes = 0; // 已重试次数
    const maxReTryTimes = 10; // 最大重试次数 200ms 重试一次
    // 播放下一个视频
    const nextPageVideo = function() {
        console.log('课程列表',list)
        let currentIndex = Array.from(list).findIndex((item,index)=>{
            return Array.from(item.classList).includes('current')
        });
        console.log('播放下一个视频',currentIndex)
        if(currentIndex>-1 && currentIndex != list.length-1){ // 有且 当前不是最后一个
            const nextLi = list[currentIndex+1]
            const alink = nextLi.querySelector('.aalink')
            alink&&alink.click()
        }
    }

    const init = function() {
        console.log("初始化插件功能", status, typeof status);
        container.style.position = 'relative';
        let btnText = status?'停用后台播放':'启用后台播放';
        let controlBox = document.createElement('DIV');
        let controlBtn = document.createElement('SPAN');
        let speedBtn = document.createElement('SPAN');
        let jopeToEndBtn = document.createElement('SPAN');
        let loopPlayBtn = document.createElement('SPAN');
        // 开关循环播放视频
        const loopHandler = function(e){
            loop_status = loop_status ? 0 : 1;
            localStorage.setItem('_my_tamermonkey_loop_status_',loop_status);
            e.target.innerText = loop_status?'关闭循环播放':'开启循环播放';
        };
        // 控制开关
        const controlHandler = function(e) {
            status = status ? 0: 1;
            localStorage.setItem('_my_tamermonkey_status_',status);
            let btnText = status?'停用后台播放':'启用后台播放';
            e.target.innerText = btnText;
        }
        // 调速
        const speedHandler = function(e) {
            let currentSpeedIndex = speedMap.findIndex(v=>_my_tamermonkey_speed_===v);
            if(currentSpeedIndex===speedMap.length-1){
                currentSpeedIndex = 0;
            }else{
                ++currentSpeedIndex;
            }
            _my_tamermonkey_speed_ = speedMap[currentSpeedIndex];
            videoDom.playbackRate = _my_tamermonkey_speed_;
            e.target.innerText = `快进>>${_my_tamermonkey_speed_}倍速`;
        }
        // 快进到最后
        const toEndHandler = function(e) {
            console.log('快进到最后');
            let duration = videoDom.duration;
            let toEndTime = Math.floor(duration-1);
            videoDom.currentTime = toEndTime;
            console.log(videoDom.currentTime);
        }
        //容器设置样式和id
        controlBox.id = 'myTampermonkeyControl';
        controlBox.style.cssText = 'position:absolute;right:0px;bottom:0px;display:flex;align-items:center;font-size:12px;';
        //控制按钮设置样式和id
        controlBtn.id = 'controlBtn';
        controlBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;margin-right:10px;cursor:pointer;background:#999;color:#fff;';
        controlBtn.innerText = btnText;
        speedBtn.id = 'speedBtn';
        speedBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;cursor:pointer;background:#999;color:#fff;margin-right:10px;';
        speedBtn.innerText = `快进>>${_my_tamermonkey_speed_}倍速`;
        jopeToEndBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;cursor:pointer;background:#999;color:#fff;';
        jopeToEndBtn.innerText = '跳到最后';
        loopPlayBtn.innerText = loop_status?'关闭循环播放':'开启循环播放';
        loopPlayBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;margin-right:10px;cursor:pointer;background:#999;color:#fff;';
        // 按钮添加事件
        loopPlayBtn.onclick = loopHandler;
        controlBtn.onclick= controlHandler;
        speedBtn.onclick = speedHandler;
        jopeToEndBtn.onclick = toEndHandler;
        controlBox.appendChild(loopPlayBtn);
        controlBox.appendChild(controlBtn);
        controlBox.appendChild(speedBtn);
        controlBox.appendChild(jopeToEndBtn);
        container.appendChild(controlBox);
        videoDom.addEventListener('ended', function () { //结束
            console.log("播放结束");
            console.log('是否循环播放',loop_status);
            if(loop_status) nextPageVideo()
            //controlBtn.click()
        }, false);
        document.addEventListener('visibilitychange', function() {
            if(!videoDom){
                videoDom = document.getElementsByTagName('VIDEO')[0];
            }
            var isHidden = document.hidden;
            console.log(document.visibilityState,isHidden,status); // window._my_tamermonkey_status_
            if (isHidden && status) {
                console.log(status);
                setTimeout(()=>{
                    videoDom.play();
                },200)
            }else if(isHidden){
                videoDom.pause();
            }
        });
        // 如开启后台播放,自动静音播放视频
        if(status) {
            videoDom.muted = 'muted';
            setTimeout(()=> {
                const playPromise = videoDom.play();
                if (playPromise !== undefined) {
                    playPromise.then(res => {
                        // Automatic playback started!
                        // Show playing UI.
                    }).catch(error => {
                        // Auto-play was prevented
                        // Show paused UI.
                    });
                }
            },100)
        }
    }
    if(videoDom){ // 有视频
        console.log('有视频');
        init();
    }else{ // 视频未加载,重试
        console.log('视频未加载');
        let timer = null;
            timer = setInterval(()=>{
                console.log('轮询');
                if(tryTimes >= maxReTryTimes){ // 重试最后都没有找到视频
                    clearInterval(timer);
                    timer = null;
                    if(loop_status){ // 如果是循环播放,则说明是文本课程,直接跳转下一个课程
                        console.log('文本课程,直接跳转下一个课程')
                        setTimeout(()=>{
                            nextPageVideo()
                        },2000)
                    }
                    return;
                }
                videoDom = document.getElementsByTagName('VIDEO')[0];
                if(videoDom){
                    try{
                        init();
                        clearInterval(timer);
                        timer = null;
                        return;
                    }catch(err){
                        clearInterval(timer);
                        timer = null;
                        console.log(err);
                    }
                }
                tryTimes++
            },200)
    }

    // Your code here...
})();