哔哩哔哩(bilibili)播放器辅助设置

B站播放器增强设置,自动宽屏,默认最高画质,默认关闭弹幕等

// ==UserScript==
// @name         哔哩哔哩(bilibili)播放器辅助设置
// @namespace    bilibili
// @version      1.0.1
// @description  B站播放器增强设置,自动宽屏,默认最高画质,默认关闭弹幕等
// @author       darkless
// @match        https://www.bilibili.com/video/*
// @grant        none
// ==/UserScript==

'use strict';

(async function () {
  console.group('哔哩哔哩(bilibili)播放器初始化开始');
  const config = {
    closeBarrage: true, // true表示关闭弹幕,false表示开启弹幕
    autoWidescreen: true, // true表示开启自动宽屏,false表示关闭自动宽屏
    autoPlayList: [], // 开启自动连播白名单,目前仅支持BV号,如 ['BV123445']
    redundantElements: [
      '#bannerAd', 
      '#activity_vote', /*  */
      '.ad-report', /*  */
      '.video-page-special-card', 
      'reportFirst1',
      'reportFirst2',
      'reportFirst3',
    ],
  };

  const document = this.document;

  const handleSettingLoaded = (e) => {
    console.log('加载播放器设置');
    const videoControl = e.detail.videoControl;
    const videoSendBar = e.detail.videoSendBar;

    // 切换弹幕开关
    switchBarrage(config.closeBarrage, videoSendBar);

    // 最高画质
    hightQuality(videoControl);

    // 自动宽屏
    autoWidescreen(config.autoWidescreen, videoControl);

    // 自动播放列表
    autoPlayList(config.autoPlayList, this);

    // 展开简介
    expandDescription(document);

    // 删除部分元素
    removeElements(config.redundantElements, document);

    console.log('初始化结束');
    console.groupEnd();
  };

  const handlePlayerLoaded = (e) => {
    const { data } = e;
    if (data.type === 'PlayerLoaded' || data.type === 'VideoLoaded') {
      console.log(data)
      getRoots(document);
    }
  };

  document.addEventListener('SettingLoaded', handleSettingLoaded);
  this.addEventListener('message', handlePlayerLoaded);

  observePlayerStatus(this);
}.bind(window)());

function removeElements(selectors, document) {

  selectors.forEach((selector) => {
    let elements;
    if (selector.indexOf('.') === 0) {
      elements = document.querySelectorAll(selector);
    } else {
      elements = document.querySelector(selector);
    }

    if (elements && Array.isArray(elements)) {
      elements.forEach((element) => {
        if (typeof element.remove === 'function') {
          element.remove();
        }
      });
    } else {
      if (typeof elements.remove === 'function') {
        elements.remove();
      }
    }
  });
  console.log('部分推广元素已删除');
}

function expandDescription(document) {
  const element = document.getElementsByClassName('desc-info')[0];
  if (!/open/.test(element.className)) {
    document.getElementsByClassName('toggle-btn')[0].click();
  }
  console.log('简介已展开');
}

function autoPlayList(videos, window) {
  const button = window.document.getElementsByClassName('switch-button').item(0);
  const bv = window.location.pathname.split('/')[2];
  const isAutoPlayVideo = videos.includes(bv);
  let timer;

  let isOpen = button.className === 'switch-button on';
  let needOpen = !isOpen && isAutoPlayVideo;
  let needClose = isOpen && !isAutoPlayVideo;

  const observer = new window.MutationObserver((_, observer) => {
    clearTimeout(timer);
    isOpen = button.className === 'switch-button on';
    needOpen = needOpen = !isOpen && isAutoPlayVideo;
    needClose = isOpen && !isAutoPlayVideo;

    if (!needOpen && !needClose) {
      observer.disconnect();
      console.log('自动连P已切换');
      return;
    }

    if (needOpen || needClose) {
      timer = setTimeout(() => {
        button.click();
      }, 3000);
      return;
    }
  });

  observer.observe(button, {
    attributes: true,
    attributeFilter: ['class'],
    attributeOldValue: true,
  });

  if (needOpen || needClose) {
    timer = setTimeout(() => button.click(), 0);
  }
}

function autoWidescreen(autoWidescreen, element) {
  const widescreenElement = element.getElementsByClassName('bilibili-player-video-btn-widescreen').item(0);
  if (autoWidescreen && !/closed/.test(widescreenElement.className)) {
    widescreenElement.click();
    console.log('已开启宽屏');
  }
}

function hightQuality(element) {
  const isVip = document.querySelector('.profile-info .vip') !== null;
  const isLogin = document.getElementById('bilibiliPlayer').getAttribute('data-login') === 'true';

  const list = element.querySelectorAll('.bilibili-player-video-btn-quality .bui-select-list .bui-select-item');
  const newList = Array.prototype.slice.call(list);
  newList.some((item) => {
    let result = true;

    const children = item.children;
    if (children.length >= 3) {
      const className = children.item(2).className;
      switch (className) {
        case 'bilibili-player-bigvip':
          result = isVip;
          break;
        case 'bilibili-player-needlogin':
          result = isLogin;
          break;
        default:
          result = true;
          break;
      }
    }

    if (result) {
      console.log('画质已切换至最高');
      item.click();
    }
    return result;
  });
}

function switchBarrage(close, root) {
  const element = root.getElementsByClassName('bui-switch-input').item(0);

  if (close === element.checked) {
    element.click();
  }
  console.log('弹幕开关已切换');
}

function getRoots(document) {
  const videoControls = document.getElementsByClassName('bilibili-player-video-control');
  const videoSendBars = document.getElementsByClassName('bilibili-player-video-sendbar');

  if (videoControls.length > 0 && videoSendBars.length > 0) {
    document.dispatchEvent(new CustomEvent('SettingLoaded', {
      detail: {
        videoControl: videoControls[0],
        videoSendBar: videoSendBars[0],
      },
    }));
  } else {
    setTimeout(() => {
      getRoots(document);
    }, 500);
  }
}

function observePlayerStatus(window) {
  const rootElement = window.document.getElementById('bilibiliPlayer');
  const videoElement = rootElement.getElementsByClassName('bilibili-player-video')[0].children[0];

  const rootObserver = new window.MutationObserver((_, observer) => {
    window.postMessage({
      type: 'PlayerLoaded',
      timestamp: Date.now(),
    }, '*');
    observer.disconnect();
  });

  rootObserver.observe(rootElement, {
    attributes: true,
    attributeFilter: ['data-login'],
    childList: true,
  });

  const videoObserver = new window.MutationObserver(() => {
    setTimeout(() => {
      window.postMessage({
        type: 'VideoLoaded',
        timestamp: Date.now(),
      }, '*');
    }, 3000);
  });

  videoObserver.observe(videoElement, {
    attributes: true,
    attributeFilter: ['src'],
  });
}