Bilibili - 自动切换直播画质至最高画质

自动切换Bilibili直播画质至最高画质 | V0.5 修复无法在未登录的情况下切换画质的问题

目前为 2023-10-30 提交的版本。查看 最新版本

// ==UserScript==
// @name         Bilibili - 自动切换直播画质至最高画质
// @namespace    https://bilibili.com/
// @version      0.5
// @description  自动切换Bilibili直播画质至最高画质 | V0.5 修复无法在未登录的情况下切换画质的问题
// @license      GPL-3.0
// @author       DD1969
// @match        https://live.bilibili.com/*
// @icon         https://www.bilibili.com/favicon.ico
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @noframes
// ==/UserScript==

(async function() {
  'use strict';

  // jump to actual room if live streaming is nested
  setInterval(() => {
    const nestedPage = document.querySelector('iframe[src*=blanc]');
    if (nestedPage) unsafeWindow.location.href = nestedPage.src;
  }, 200);

  // set target quality to 1080p
  const targetQualityNumber = "10000";

  // hide the loading gif
  const styleElement = document.createElement('style');
  styleElement.textContent = `.web-player-loading { opacity: 0; }`;
  document.head.appendChild(styleElement);

  // wait until cookie and livePlayer loaded
  await new Promise(resolve => {
    const timer = setInterval(() => {
      if (document.cookie && unsafeWindow.livePlayer && unsafeWindow.livePlayer.getPlayerInfo && unsafeWindow.livePlayer.switchQuality) {
        clearInterval(timer);
        resolve();
      }
    }, 200);
  });

  // get room ID
  const roomID = await fetch(`https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=${location.pathname.split('/').pop()}`)
    .then(res => res.json())
    .then(json => json.data.room_info.room_id);

  // get data from API
  const roomPlayInfo = await new Promise(resolve => {
    GM_xmlhttpRequest({
      method: 'GET',
      url: `https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?room_id=${roomID}&protocol=0,1&format=0,1,2&codec=0,1,2&qn=${targetQualityNumber}&platform=web&ptype=8&dolby=5&panorama=1`,
      headers: { 'Cookie': '\n' },
      responseType: 'json',
      onload: res => resolve(res.response)
    });
  });

  // get target codec
  const targetCodec = roomPlayInfo
    .data
    .playurl_info
    .playurl
    .stream
    .find(stream => stream.protocol_name === 'http_hls')
    .format
    .find(format => format.format_name === 'fmp4')
    .codec
    .find(codec => codec.codec_name === 'avc');

  // override 'find' method of Array to change the processing codec config
  const originFind = Array.prototype.find;
  Array.prototype.find = function(func) {
    if (this.some(item => item.codec_name === 'avc')) {
      return originFind.call([targetCodec], func);
    }
    return originFind.call(this, func);
  }

  // override 'split' method of String to change the processing cookie string
  const originSplit = String.prototype.split;
  String.prototype.split = function (spliter) {
    let str = this;
    if (spliter === ';' && str.length > 0) str += '; DedeUserID=123456';
    return originSplit.call(str, spliter);
  }

  // switch quality
  const { quality } = unsafeWindow.livePlayer.getPlayerInfo();
  if (quality !== targetQualityNumber) {
    unsafeWindow.livePlayer.switchQuality(targetQualityNumber);
    setTimeout(() => unsafeWindow.livePlayer.reload(), 2000);
  }

})();