百度网盘视频倍速播放-滑动条版

视频内外部添加可拖动的调节视频倍速的滑动条(初始化倍速:max:2.0,min:0.5,step:0.05,val:1.0)。视频音量条设置为竖直方向(初始化音量:vol:20%)。 //\\//\\ 脚本412-416行,用户可进行对倍速(max,min,step,val)、音量(vol)的初始化设置。 //\\//\\ 支持各种快捷键调节视频,脚本299-349行可进行快捷键键位修改。 //\\//\\ 在当前网页切换视频时,保持用户设置的音量和倍速。

// ==UserScript==
// @name         百度网盘视频倍速播放-滑动条版
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  视频内外部添加可拖动的调节视频倍速的滑动条(初始化倍速:max:2.0,min:0.5,step:0.05,val:1.0)。视频音量条设置为竖直方向(初始化音量:vol:20%)。  //\\//\\  脚本412-416行,用户可进行对倍速(max,min,step,val)、音量(vol)的初始化设置。  //\\//\\  支持各种快捷键调节视频,脚本299-349行可进行快捷键键位修改。 //\\//\\  在当前网页切换视频时,保持用户设置的音量和倍速。
// @author       fajiao
// @match        *://pan.baidu.com/play/video*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    var DocUtil = {
        insertAfter: function (targetElm, newElm) {
            if (targetElm && newElm) {
                let parent = targetElm.parentNode;
                if (parent.lastChild == targetElm) {
                    parent.appendChild(newElm);
                } else {
                    parent.insertBefore(newElm, targetElm.nextSibling)
                }
            }
        },
        addEventListener: function (obj, event, func) {
            if (obj && (typeof obj == "object") && (typeof event == "string") && (typeof func == "function")) {
                obj.addEventListener(event, func);
            }
        },
        removeEventListener: function (obj, event, func) {
            if (obj && (typeof obj == "object") && (typeof event == "string") && (typeof func == "function")) {
                obj.removeEventListener(event, func);
            }
        },
        addStyleRule(style, rule, index) {
            if (style) {
                let sheet = style.sheet || style.styleSheet || {};
                index = index || sheet.cssRules.length || 0;
                if (sheet.insertRule) {
                    sheet.insertRule(rule, index);
                } else if (sheet.addRule) {
                    // sheet.addRule(selectorText, cssText, index);
                }
            }
        },
        addStyleRules(style, rules) {
            if (style && typeof style == "object" && "innerText" in style) {
                style.innerText += rules;
            }
        },
        log() {
            console.log(arguments);
        }
    };

    function SpeedComponentUtil(config) {
        var _config = {};
        var _component = {};
        var _style = {};

        init(config);

        function init(config) {
            initConfig(config);
            initOuterComponent();
            initInnerComponent();
        }

        function initConfig(config) {
            config = config || {};
            _config.max = config.max || 2.0;
            _config.min = config.min || 0.5;
            _config.step = config.step || 0.05;
            _config.val = config.val || 1.0;
            _config.vol = config.vol || 0.2;
        }

        function initOuterComponent() {
            let outerSpeedDiv = document.createElement("div");
            let outerLayerDiv = document.createElement("div");
            let outerSpeedSlider = document.createElement("input");
            let outerSpeedTip = document.createElement("span");

            outerSpeedDiv.id = "outerSpeedDiv";
            outerLayerDiv.id = "outerLayerDiv";

            outerSpeedSlider.type = "range";
            outerSpeedSlider.max = _config.max;
            outerSpeedSlider.min = _config.min;
            outerSpeedSlider.step = _config.step;
            outerSpeedSlider.value = _config.val;
            outerSpeedTip.innerText = `×${_config.val.toFixed(2)}`;

            outerSpeedDiv.appendChild(outerLayerDiv);
            outerLayerDiv.appendChild(outerSpeedSlider);
            outerLayerDiv.appendChild(outerSpeedTip);

            _component.outerSpeedDiv = outerSpeedDiv;
            _component.outerLayerDiv = outerLayerDiv;
            _component.outerSpeedSlider = outerSpeedSlider;
            _component.outerSpeedTip = outerSpeedTip;
            initOuterComponentStyle();
        }

        function initInnerComponent() {
            let innerSpeedDiv = document.createElement("div");
            let innerLayerSliderDiv = document.createElement("div");
            let innerSpeedSlider = document.createElement("input");
            let innerLayerTipDiv = document.createElement("div");
            let innerSpeedTip = document.createElement("span");

            innerSpeedDiv.id = "innerSpeedDiv";
            innerLayerTipDiv.id = "innerLayerTipDiv";
            innerLayerSliderDiv.id = "innerLayerSliderDiv";

            innerSpeedSlider.type = "range";
            innerSpeedSlider.max = _config.max;
            innerSpeedSlider.min = _config.min;
            innerSpeedSlider.step = _config.step;
            innerSpeedSlider.value = _config.val;
            innerSpeedTip.innerText = `×${_config.val.toFixed(2)}`;

            innerSpeedDiv.appendChild(innerLayerTipDiv);
            innerLayerTipDiv.appendChild(innerSpeedTip);
            innerSpeedDiv.appendChild(innerLayerSliderDiv);
            innerLayerSliderDiv.appendChild(innerSpeedSlider);

            _component.innerSpeedDiv = innerSpeedDiv;
            _component.innerLayerSliderDiv = innerLayerSliderDiv;
            _component.innerSpeedSlider = innerSpeedSlider;
            _component.innerLayerTipDiv = innerLayerTipDiv;
            _component.innerSpeedTip = innerSpeedTip;
            initInnerComponentStyle();
        }

        function initOuterComponentStyle() {
            let style = _style.outerSpeedComponentStyle || document.getElementById("outerSpeedComponentStyle") || (function () {
                let style = document.createElement('style');
                style.type = 'text/css';
                style.id = "outerSpeedComponentStyle";
                _component.outerSpeedDiv.appendChild(style);
                _style.outerSpeedComponentStyle = style;
                return style;
            })();

            DocUtil.addStyleRules(style, `
            #outerSpeedDiv{width:155px;height:auto;margin:0 0 0 30px;display:inline-block}
            #outerLayerDiv{width:140px;height:35px;text-align:left;display:table-cell;vertical-align:middle;padding-left:10px;padding-right:10px}
            #outerLayerDiv span{font-size:16px;font-weight:bold;color:black}
            #outerLayerDiv input[type=range]{-webkit-appearance:none;width:100px;height:10px;background:transparent;transform:translateY(-2px);outline:0}
            #outerLayerDiv input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:#fafbf2;border:2.5px solid black;margin-top:-6px;cursor:pointer}
            #outerLayerDiv input[type=range]::-webkit-slider-runnable-track{width:100%;height:5px;border-radius:5px;background:#48abee;cursor:pointer}
            #outerLayerDiv input[type=range]::-moz-range-thumb{width:15px;height:15px;border-radius:50%;background:#fafbf2;border:2.5px solid black;cursor:pointer}
            #outerLayerDiv input[type=range]::-moz-range-track{width:100%;height:5px;border-radius:5px;background:#2497e3;cursor:pointer}
            #outerSpeedDiv .noWork{background:#c5c4c9;pointer-events:none}
            `);
        }

        function initInnerComponentStyle() {
            let style = _style.innerSpeedComponentStyle || document.getElementById("innerSpeedComponentStyle") || (function () {
                let style = document.createElement('style');
                style.type = 'text/css';
                style.id = "innerSpeedComponentStyle";
                _component.innerSpeedDiv.appendChild(style);
                _style.innerSpeedComponentStyle = style;
                return style;
            })();

            DocUtil.addStyleRules(style, `
            #innerSpeedDiv{width:50px;height:auto}
            #innerLayerTipDiv{width:100%;height:36px;background:transparent}
            #innerLayerTipDiv span{width:100%;height:100%;font-size:16px;font-weight:bold;color:white;text-align:center;display:inline-block;line-height:36px}
            #innerLayerSliderDiv{width:auto;height:50px;background:rgba(43,51,63,.7);display:table-cell;vertical-align:middle;transform-origin:left top;transform:translateY(-36px) rotate(-90deg)}
            #innerLayerSliderDiv input[type=range]{-webkit-appearance:none;width:100px;height:10px;background:transparent;outline:0}
            #innerLayerSliderDiv input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:#fafbf2;transform:translateY(-6px);border:2.5px solid black;cursor:pointer}
            #innerLayerSliderDiv input[type=range]::-webkit-slider-runnable-track{width:100%;height:5px;border-radius:5px;background:#48abee;cursor:pointer}
            #innerLayerSliderDiv input[type=range]::-moz-range-thumb{width:15px;height:15px;border-radius:50%;background:#fafbf2;border:2.5px solid black;cursor:pointer}
            #innerLayerSliderDiv input[type=range]::-moz-range-track{width:100%;height:5px;border-radius:5px;background:#2497e3;cursor:pointer}
            #innerSpeedDiv .noWork{display:none}
            `);
        }

        this.getComponent = function (componentStr) {
            return componentStr ? _component[componentStr] : _component;
        }
    }

    function SpeedUtil(config) {
        var _config = {};
        var _scUtil = null;
        var _cmpnt = null;
        var _state = null;
        var _priorId = null;
        var _h5player = null;

        init(config);

        function init(config) {
            initConfig(config);
            initParameter();
            initOuterComponentPosition();
            startLoadState();
            findH5player((_priorId = new Date().getTime()), 1);
            initListener();
        }

        function initConfig(config) {
            config = config || {};
            _config.max = config.max || 2.0;
            _config.min = config.min || 0.5;
            _config.step = config.step || 0.05;
            _config.val = config.val || 1.0;
            _config.vol = config.vol || 0.2;
        }

        function initParameter() {
            _scUtil = new SpeedComponentUtil(_config);
            _cmpnt = _scUtil.getComponent();
        }

        function initOuterComponentPosition() {
            let toolbar = document.querySelector(".video-toolbar-buttonbox");
            DocUtil.insertAfter(toolbar.lastChild, _cmpnt.outerSpeedDiv);
        }

        function initInnerComponentPosition(volbtn) {
            DocUtil.insertAfter(volbtn, _cmpnt.innerSpeedDiv);
        }

        function findH5player(curId, num) {
            if (curId != _priorId) {
                // console.log("abort", curId, num, new Date().getTime());
                return;
            }
            if (num >= 45) {
                // console.log("timeout", curId, num, new Date().getTime());
                return;
            }
            let player = getH5player();
            if (player) {
                // console.log("success", curId, num, new Date().getTime());
                stopLoadState(player);
            } else {
                // console.log("failure", curId, num, new Date().getTime());
                setTimeout(function () {
                    findH5player(curId, ++num);
                }, 1000);
            }
        }

        function initListener() {
            DocUtil.addEventListener(_cmpnt.outerSpeedSlider, "input", function () {
                // console.log("outer", "input", _cmpnt.outerSpeedSlider.value);
                let player = _h5player || getH5player();
                if (player) {
                    player.tech_.setPlaybackRate(_cmpnt.outerSpeedSlider.value);
                }
            });

            DocUtil.addEventListener(_cmpnt.innerSpeedSlider, "input", function () {
                // console.log("inner", "input", _cmpnt.innerSpeedSlider.value);
                let player = _h5player || getH5player();
                if (player) {
                    player.tech_.setPlaybackRate(_cmpnt.innerSpeedSlider.value);
                }
            });

            DocUtil.addEventListener(_cmpnt.innerLayerTipDiv, "mouseover", function () {
                _cmpnt.innerLayerSliderDiv.classList.remove("noWork");
            });
            DocUtil.addEventListener(_cmpnt.innerLayerTipDiv, "mouseout", function () {
                _cmpnt.innerLayerSliderDiv.classList.add("noWork");
            });
            DocUtil.addEventListener(_cmpnt.innerLayerSliderDiv, "mouseover", function () {
                _cmpnt.innerLayerSliderDiv.classList.remove("noWork");
            });
            DocUtil.addEventListener(_cmpnt.innerLayerSliderDiv, "mouseout", function () {
                _cmpnt.innerLayerSliderDiv.classList.add("noWork");
            });

            DocUtil.addEventListener(window, "popstate", function () {
                let curId = new Date().getTime();
                _priorId = curId;
                startLoadState();
                setTimeout(function () {
                    findH5player(curId, 1)
                }, 3000);
            });

            DocUtil.addEventListener(document, "keypress", function (e) {
                let player = _h5player || getH5player();
                let curPlayElm = document.querySelector(".currentplay") || {};
                if (_state == "stopLoad") {
                    if (player) {
                        let speed = _config.val;
                        let step = _config.step;
                        let max = _config.max;
                        let min = _config.min;
                        switch (e.key) {
                            case "c":
                                //加速
                                player.tech_.setPlaybackRate((((speed + step)) < max ? (speed + step) : max));
                                break;
                            case "x":
                                //还原
                                player.tech_.setPlaybackRate(1);
                                break;
                            case "z":
                                //减速
                                player.tech_.setPlaybackRate((((speed - step) > min) ? (speed - step) : min));
                                break;
                            case "f":
                                //全屏
                                player.controlBar.fullscreenToggle.el_.click();
                                break;
                            case "m":
                                //画中画
                                if (document.pictureInPictureEnabled) {
                                    if (!document.pictureInPictureElement) {
                                        player.tech_.el_.requestPictureInPicture();
                                    } else {
                                        document.exitPictureInPicture();
                                    }
                                }
                                break;
                        }
                    }
                }
                switch (e.key) {
                    case "d":
                        //开关灯
                        document.querySelector(".video-functions-last").click();
                        break;
                    case "b":
                        //前一个视频
                        if (curPlayElm.previousSibling) {
                            curPlayElm.previousSibling.firstChild.click();
                        }
                        break;
                    case "n":
                        //后一个视频
                        if (curPlayElm.nextSibling) {
                            curPlayElm.nextSibling.firstChild.click();
                        }
                        break;
                    case "h":
                        window.alert("快捷键提醒:\nz:减速,x:还原,c:加速\nd:开关灯,f:全屏\nb:前一个视频,n:后一个视频,m:画中画\nh:帮助\n脚本299-349行可进行快捷键键位修改");
                        break;
                }
            });
        }

        function startLoadState() {
            _state = "startLoad";
            // console.log("load start",new Date().getTime());
            _cmpnt.outerLayerDiv.classList.add("noWork");
            _cmpnt.innerLayerSliderDiv.classList.add("noWork");
            _h5player = null;
        }

        function stopLoadState(player) {
            _state = "stopLoad";
            // console.log("load stop",new Date().getTime());

            let bar = player.controlBar;
            bar.removeChild("volumeMenuButton");
            let volbtn = (bar.addChild("volumeMenuButton", {
                inline: false
            }, 1)).el_;
            initInnerComponentPosition(volbtn);

            _cmpnt.outerLayerDiv.classList.remove("noWork");
            _h5player = player;

            DocUtil.addEventListener(player.tech_.el_, "ratechange", function () {
                let player = _h5player || getH5player();
                if (player) {
                    let speedStr = player.tech_.playbackRate().toFixed(2);
                    let speedNum = parseFloat(speedStr);
                    // console.log("ratechange", speed, new Date().getTime());
                    _config.val = speedNum;
                    _cmpnt.outerSpeedSlider.value = speedNum;
                    _cmpnt.outerSpeedTip.innerText = `×${speedStr}`;
                    _cmpnt.innerSpeedSlider.value = speedNum;
                    _cmpnt.innerSpeedTip.innerText = `×${speedStr}`;
                }
            });
            DocUtil.addEventListener(player.tech_.el_, "volumechange", function () {
                let player = _h5player || getH5player();
                if (player) {
                    let vol = parseFloat(player.tech_.volume().toFixed(2));
                    // console.log("volumechange", vol, new Date().getTime());
                    _config.vol = vol;
                }
            });
            player.tech_.el_.oncanplay = function () {
                let speed = parseFloat(_config.val.toFixed(2));
                let vol = _config.vol;
                player.tech_.setPlaybackRate(speed);
                player.tech_.setVolume(vol);
                player.tech_.el_.oncanplay = null;
            }
        }

        function getH5player() {
            return window.videojs ? window.videojs.getPlayers().html5player : null;
        }
    }

    DocUtil.addEventListener(window, "load", function () {
        new SpeedUtil({
            max: 2.0, //最大倍速值
            min: 0.5, //最小倍速值
            step: 0.05, //步进值
            val: 1.0, //初始倍速值
            vol: 0.23, //初始音量值
        });
    });
})();