Greasy Fork is available in English.

bv辅助

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

// ==UserScript==
// @name         bv辅助
// @namespace    https://greasyfork.org/users/718683
// @author       runwithfaith
// @match        https://www.bilibili.com/video/*
// @match        https://www.le.com/ptv/vplay/*
// @match        https://www.ixigua.com/*
// @match        https://haokan.baidu.com/*
// @match        https://tv.cctv.com/*
// @icon         http://bilibili.com/favicon.ico
// @description  我本人在阿b看视频的辅助js,只测试过火狐.内置多个功能,可以设置倍速,音量,全屏等.本脚本永久开源,永久免费。本脚本仅供合法使用,不得被用于任何的非法用途。
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @compatible   firefox
// @require https://greasyfork.org/scripts/435697-myutils/code/myUtils.js?version=1236344
// @license      MIT
// @noframes
// @version 0.0.1.20231120041830
// ==/UserScript==
/*
缺点:全屏后较为单调.且火狐必须先配置浏览器.功能少.
优点:强解耦
*/
/*添加元素,仅执行一次*/
;(function addEles(){
    const sv=GM_setValue,gv=GM_getValue,as=GM_addStyle,uw=unsafeWindow;
    let vedio;
    as(`#mbvt{
            position: fixed;
            top: 30% !important;
            right: 0 !important;
            z-index: 9999999;
            width: 50px;
        }/*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'),//总div
          fsBtn=my.append(`button`,null,'全屏'),
          play=my.append(`button`,null,'play'),
          pause=my.append(`button`,null,'pause'),
          replay=my.append(`button`,null,'起点'),
          isFs=my.append('input',null,'','type',"checkbox"),
          isAutoPlay=my.append('input',null,'','type',"checkbox"),
          back5s=my.append('button',null,'back'),
          vcover=my.append('button',null,'封面'),
          rate=my.append('input',null,'倍速'),
          volume=my.append('input',null,'音量');
    isFs.checked=parseInt(gv('autoFs',0));
    isAutoPlay.checked=parseInt(gv('autoPlay',0));
    fsBtn.onclick=()=>{vedio.requestFullscreen();};
    replay.onclick=()=>{vedio.currentTime=0;vedio.play()};
    vcover.onclick=()=>{open(uw.vd.pic)};
    play.onmouseover=()=>{vedio.pause();vedio.play()};
    pause.onmouseover=()=>{vedio.pause()};
    back5s.onmouseover=()=>{vedio.currentTime-= 5;};
    rate.onclick=e=>{
        const r= Number(prompt('设置倍速0-4:',rate.value));
        if(r>-1){
            vedio.playbackRate=r;
            sv('pbRate',r);
            e.target.value=r;
        }
    };
    volume.onclick=e=>{
        const v= Number(prompt('设置音量0-1:',volume.value));
        if(v>-1){
            vedio.volume=v;
            sv('volume',v);
            e.target.value=v;
        }
    };
    isFs.onchange=e=>{sv('autoFs',e.target.checked&1)}
    isAutoPlay.onchange=e=>{sv('autoPlay',e.target.checked&1)}
    appendDivWithEle(root,fsBtn,back5s,play,pause,replay,vcover,rate,volume);
    my.after(isFs,fsBtn,'');
    my.after(isAutoPlay,play,'');

    return init()
    function init(){/*初始化倍速,音量,全屏*/
        const v=document.querySelector('video');//作为网页加载好的flag
        if(!v){
            // console.log("video not found, retry after 1000ms...");
            return setTimeout(init,1000);
        }else{//首次初始化
            observeVideo(vedio=v,init);
            v.addEventListener('play',()=>{
                let flag=1;
                if(isFs.checked &!document.fullScreen) fsBtn.click();
                return (flag<2)&&(flag++)&&(()=>{
                    const vo=parseFloat(gv('volume',1)),r=gv('pbRate',1);
                    v.playbackRate=rate.value=r;
                    v.volume=volume.value=vo;
                })()
            })
            if(isAutoPlay.checked) v.play();
            if(isFs.checked&!document.fullScreen)fsBtn.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);
}