Greasy Fork

Greasy Fork is available in English.

<video>辅助

我本人在阿b看视频的辅助js,只测试过火狐.内置多个功能,可以设置倍速,音量,全屏等.本脚本永久开源,永久免费。本脚本仅供合法使用,不得被用于任何的非法用途。

当前为 2023-03-14 提交的版本,查看 最新版本

// ==UserScript==
// @name         <video>辅助
// @namespace    http://tampermonkey.net/
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/bangumi/play/*
// @match        https://www.le.com/ptv/vplay/*
// @icon         http://bilibili.com/favicon.ico
// @noframes
// @description  我本人在阿b看视频的辅助js,只测试过火狐.内置多个功能,可以设置倍速,音量,全屏等.本脚本永久开源,永久免费。本脚本仅供合法使用,不得被用于任何的非法用途。
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @compatible   firefox
// @license      MIT
// @version 0.0.1.20230314090153
// ==/UserScript==
/*
缺点:全屏后较为单调.且火狐必须先配置浏览器.功能少.
优点:强解耦
*/
/*添加元素,仅执行一次*/
(function addEles(){
    const sv=GM_setValue,gv=GM_getValue,as=GM_addStyle,s=document.createElement('script');
    let vedio;
    s.src="http://greasyfork.icu/scripts/435697-myutils/code/myUtils.js?version=1074160";
    document.head.append(s);
    s.onload=()=>{
        as(`#mbvt_root{
            position: fixed;
            top: 30% !important;
            right: 0 !important;
            z-index: 9999999;
        }/*video{
            width: 100%;height: 100%;position: fixed;z-index: 1659548286991;left: 0;top: 0;background: black;
        }*/`);
        const root=my.append(`div`,my.zone,'',`id`,'mbvt_root'),//总div
              rateData = {
                  select倍速:1, '0.5x':0.5,'1.0x':1,'1.25x':1.25,'1.5x':1.5,'2.0x':2.0
              },
              rateDataLen = rateData.length,
              rateSelector = my.append(`select`,null),
              volumeData = {
                  select音量:1,'0%':0,'10%':0.1,'100%':1
              },
              volumeSelector = my.append(`select`,null),
              fullscreenBtn=my.append(`button`,null,'fullscreen'),
              playBtn=my.append(`button`,null,'play'),
              isFs=my.append('input',null,'','type',"checkbox"),
              isAutoPlay=my.append('input',null,'','type',"checkbox");

        isFs.checked=parseInt(gv('autoFs',0));
        isAutoPlay.checked=parseInt(gv('autoPlay',0));
        fullscreenBtn.onclick=()=>{
            vedio.requestFullscreen();
        };
        playBtn.onmouseover=()=>{
            vedio.pause();
            vedio.play();
        };

        for (const key in rateData) my.append(`option`,rateSelector,key,`value`,rateData[key]);
        for (const key in volumeData) my.append(`option`,volumeSelector,key,`value`,volumeData[key]);
        rateSelector.onchange=e=>{
            const t=e.target,
                  i=t.selectedIndex,
                  rate=t.options[i].value;
            if(i.selectedIndex===0) return;
            vedio.playbackRate=rate;
            sv('rateIndex',i);
            t.children[0].selected = true;
        }
        volumeSelector.onchange=e=>{
            const t=e.target,
                  i=t.selectedIndex,
                  volume=t.options[i].value;
            if(i.selectedIndex===0) return;
            vedio.volume=volume;
            sv('volumeIndex',i);
            t.children[0].selected = true;
        }
        isFs.onchange=e=>{
            sv('autoFs',e.target.checked&1);
        }
        isAutoPlay.onchange=e=>{
            sv('autoPlay',e.target.checked&1);
        }
        appendDivWithEle(root,rateSelector,volumeSelector,playBtn,fullscreenBtn);
        my.after(isFs,fullscreenBtn,'');
        my.after(isAutoPlay,playBtn,'');

        return init()
        /*初始化倍速,音量,全屏*/
        function init(){
            // console.log('触发init')
            const v=document.querySelector('video');//作为网页加载好的flag
            if(!v){
                console.log("video not found, retry after 1000ms...");
                return setTimeout(init,1000);
            }else{//已加载好.对第一次视频的初始化
                // console.log(v)
                observeVideo(vedio=v,init);
                let playFlag=1;
                v.onplay=()=>{
                    if(isFs.checked &!document.fullScreen) fullscreenBtn.click();
                    return (playFlag<2)&&(playFlag++)&&(()=>{
                        v.volume=volumeSelector.children[gv('volumeIndex',0)].value;
                        v.playbackRate=rateSelector.children[gv('rateIndex',0)].value;
                    })()
                }
                // v.focus();
                if(isAutoPlay.checked) v.play();
                if(isFs.checked&!document.fullScreen)fullscreenBtn.click();
            }
        }
    }
})()
/*div套子div,子div套实质ele*/
function appendDivWithEle(dad,...elements){
    elements.forEach(e=>{
        my.append(e,my.append(`div`,dad));
    })
}
/*观察video*/
function observeVideo(video,init){
    const targetNode = video,
          config = {
              attributes: true,
              attributeFilter: ["src"],
              childList: false,
              subtree: false
          },
          // 当观察到变动时执行的回调函数
          callback = function(mutations, observer) {
              for(let mutation of mutations) {
                  if (mutation.type == 'attributes') {
                      // 触发换源:清晰度改变/下一个视频/网络波动
                      //换源前半:video标签丢失,mutation.target.src由实变为''
                      //换源后半:video标签不丢失,mutation.target.src由''变为实
                      if(mutation.target.src){
                          // console.log('触发换源后半')
                          observer.disconnect();
                          //重新初始化
                          init();
                      }
                  }
              }
          },
          // 创建一个观察器实例并传入回调函数
          observer = new MutationObserver(callback);
    observer.observe(targetNode, config);
}