Greasy Fork is available in English.

Bilibili - 在未登录的情况下自动并无限试用最高画质

在未登录的情况下自动并无限试用最高画质 | V1.4 新增对播放列表页面的支持

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         Bilibili - 在未登录的情况下自动并无限试用最高画质
// @namespace    https://bilibili.com/
// @version      1.4
// @description  在未登录的情况下自动并无限试用最高画质 | V1.4 新增对播放列表页面的支持
// @license      GPL-3.0
// @author       DD1969
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/list/*
// @match        https://www.bilibili.com/festival/*
// @icon         https://www.bilibili.com/favicon.ico
// @grant        unsafeWindow
// @grant        GM_getValue
// @grant        GM_setValue
// @run-at       document-start
// ==/UserScript==

(async function() {
  'use strict';

  // 如果希望以其他分辨率来观看视频,请将下一行等号右边的数字 1080 改为 720 或者 480,然后保存
  const preferQuality = 1080;

  // 如果希望避免看到切换高画质时的音画不同步现象,请将下一行等号右边的 false 改为 true,然后保存
  const isWaitUntilHighQualityLoaded = false;

  // apply configs from scriptStorage to localStorage
  const bilibili_player_codec_prefer_type = GM_getValue('bilibili_player_codec_prefer_type');
  const b_miniplayer = GM_getValue('b_miniplayer');
  const recommend_auto_play = GM_getValue('recommend_auto_play');
  const bpx_player_profile = GM_getValue('bpx_player_profile');
  if (bilibili_player_codec_prefer_type && b_miniplayer && recommend_auto_play && bpx_player_profile) {
    window.localStorage.setItem('bilibili_player_codec_prefer_type', bilibili_player_codec_prefer_type);
    window.localStorage.setItem('b_miniplayer', b_miniplayer);
    window.localStorage.setItem('recommend_auto_play', recommend_auto_play);
    window.localStorage.setItem('bpx_player_profile', bpx_player_profile);
  }

  // override 'setItem'
  const originSetItem = Storage.prototype.setItem;
  Storage.prototype.setItem = function(key, value) {
    // fix TypeError: Cannot read properties of null (reading 'offLoudness') at turnOffLoudnessNormalization
    if (key === 'bpx_player_profile') {
      const profile = JSON.parse(value);
      if (!profile.audioEffect) profile.audioEffect = {};
      value = JSON.stringify(profile);
    }
    originSetItem.call(this, key, value);

    // save configs into scriptStorage
    if (key === 'bilibili_player_codec_prefer_type' || key === 'b_miniplayer' || key === 'recommend_auto_play' || key === 'bpx_player_profile') {
      setTimeout(() => {
        GM_setValue('bilibili_player_codec_prefer_type', window.localStorage.getItem('bilibili_player_codec_prefer_type') || '0');
        GM_setValue('b_miniplayer', window.localStorage.getItem('b_miniplayer') || '1');
        GM_setValue('recommend_auto_play', window.localStorage.getItem('recommend_auto_play') || 'open');
        GM_setValue('bpx_player_profile', window.localStorage.getItem('bpx_player_profile') || `{ lastView: ${Date.now() - 864e5}, lastUid: 0 }`);
      }, 100);
    }
  }

  // no need to continue this script if user has logged in
  if (document.cookie.includes('DedeUserID')) return;

  // enable trial every time a new video loaded
  const originDefineProperty = Object.defineProperty;
  Object.defineProperty = function(obj, prop, descriptor) {
    if (prop === 'isViewToday' || prop === 'isVideoAble') {
      descriptor = {
        get: () => true,
        enumerable: !1,
        configurable: !0
      }
    }
    return originDefineProperty.call(this, obj, prop, descriptor);
  }

  // extend trial time by overriding "setTimeout"
  const originSetTimeout = unsafeWindow.setTimeout;
  unsafeWindow.setTimeout = function(func, delay) {
    if (delay === 3e4) delay = 3e8;
    return originSetTimeout.call(this, func, delay);
  }

  // click the trial button automatically
  setInterval(async () => {
    const trialBtn = document.querySelector('.bpx-player-toast-confirm-login');
    if (!trialBtn) return;

    // start trialling
    await new Promise(resolve => setTimeout(resolve, 1000));
    trialBtn.click();

    // avoid audio and video out of sync
    if (isWaitUntilHighQualityLoaded) {
      // stop playing first
      const isPlaying = !unsafeWindow.player.mediaElement().paused;
      if (isPlaying) unsafeWindow.player.mediaElement().pause();

      // search for end signal
      const timer4Toast = setInterval(() => {
        const toasts = Array.from(document.querySelectorAll('.bpx-player-toast-text'));
        if (toasts.some(toast => toast.textContent.endsWith('试用中'))) {
          if (isPlaying) unsafeWindow.player.mediaElement().play();;
          clearInterval(timer4Toast);
        }
      }, 100);
    }

    // switch to preferred video quality
    const preferQualityNum = ({ 1080: 80, 720: 64, 480: 32 })[preferQuality] || 80;
    setTimeout(() => {
      if (unsafeWindow.player.getQuality().nowQ <= preferQualityNum) return;
      unsafeWindow.player.requestQuality(preferQualityNum)
    }, 5000);
  }, 1500);

})();