Greasy Fork

Greasy Fork is available in English.

myBilibiliVideoTools-解耦版

我本人在哔哩哔哩看视频的专用工具,尽测试过火狐,内置多个功能,可以设置倍速,音量,全屏等.本脚本永久开源,永久免费。本脚本不得被用于任何的非法用途,仅能被合法的学习和使用。如果您安装了本脚本,产生的一切后果均由您承担,本人概不负责。本脚本的后续更新与否只取决于本人的心情。

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

// ==UserScript==
// @name         myBilibiliVideoTools-解耦版
// @简称         mbvt
// @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
// @run-at       document-idle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @compatible     firefox
// @description 我本人在哔哩哔哩看视频的专用工具,尽测试过火狐,内置多个功能,可以设置倍速,音量,全屏等.本脚本永久开源,永久免费。本脚本不得被用于任何的非法用途,仅能被合法的学习和使用。如果您安装了本脚本,产生的一切后果均由您承担,本人概不负责。本脚本的后续更新与否只取决于本人的心情。
// @license MIT
// @version 0.0.1.20230103174800
// ==/UserScript==
let myRateSelector,myVolumeSelector,myFullscreenBtn,vedio,playFlag;
const sv=GM_setValue,gv=GM_getValue,as=GM_addStyle;
/*
缺点:全屏后较为单调.且火狐必须先配置浏览器.功能少.
优点:强解耦
*/
/*添加元素,仅执行一次*/
(function addEles(){
    const s=document.createElement('script');
    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.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').on('click',()=>{
                  vedio.requestFullscreen();
              }),
              playBtn=my.append(`button`,null,'play','style','color: white;background: black').on('mouseover',()=>{
                  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;
        }
        divAppendDivWithEle(root,rateSelector,volumeSelector,playBtn,fullscreenBtn);

        myRateSelector=rateSelector;
        myVolumeSelector=volumeSelector;
        myFullscreenBtn=fullscreenBtn;

        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);
        playFlag=1;
        v.onplay=()=>{
            // alert(1)
            myFullscreenBtn.click()
            return (playFlag<2)&&(playFlag++)&&(()=>{
                v.volume=myVolumeSelector.children[gv('volumeIndex',0)].value;
                v.playbackRate=myRateSelector.children[gv('rateIndex',0)].value;
            })()
        }
        myFullscreenBtn.click()
        v.focus();
    }
}
/*div套子div,子div套实质ele*/
function divAppendDivWithEle(dad,...elements){
    elements.forEach(e=>{
        my.append(e,my.append(`div`,dad));
    })
}
/*观察video*/
function observeVideo(video){
    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);
}