Greasy Fork

Greasy Fork is available in English.

哔哩免登录看评论+1080p视频+免弹窗

通过拦截一些特定 Bilibili 接口请求或响应,让你的体验能够像登录用户一样丝滑

当前为 2025-04-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         哔哩免登录看评论+1080p视频+免弹窗
// @namespace    vruses
// @version      1.0
// @description  通过拦截一些特定 Bilibili 接口请求或响应,让你的体验能够像登录用户一样丝滑
// @author       layenh
// @match        *://*.bilibili.com/*
// @license      Mit
// @grant        none
// @require      https://update.greasyfork.icu/scripts/533087/1572495/WbiSign.js
// @run-at       document-start
// @icon         data:image/jpeg;base64,AAAAHGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZgAAAOptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABwaWN0AAAAAAAAAAAAAAAAAAAAAA5waXRtAAAAAAABAAAAImlsb2MAAAAAREAAAQABAAAAAAEOAAEAAAAAAAAF6wAAACNpaW5mAAAAAAABAAAAFWluZmUCAAAAAAEAAGF2MDEAAAAAamlwcnAAAABLaXBjbwAAABNjb2xybmNseAABAA0ABoAAAAAMYXYxQ4EADAAAAAAUaXNwZQAAAAAAAADwAAAA8AAAABBwaXhpAAAAAAMICAgAAAAXaXBtYQAAAAAAAAABAAEEAYIDBAAABfNtZGF0EgAKChgd+/vYICGg0IAy2gtEgACiiihQtIDqrkvPF1l+b90DLzEPNo7jbm8MUMGGUuKslo1owZD1WKBRgQ/2f406AlN00FgeyTrTTgl2N3L2WtrdDuFrTP1h/Nj/y8vB30i3CyIM1dTrmSCUOgVaFhBiXR2FxcZJOI9yBw/GBIZZ5KdPQafrWOAFWYuhbVmQSBwGnqsRBA76x+yeYrO4V2yLQ6OnFqpyZ9mIuhOlS/TePUfELDQ55lN1pmnFx58An5dtTY6L9N7ew5/j4LZnle2loske4Sld/QT6tT09zRcfCjsLSgX6J17LA4EpWo7Fd8ZA7+4FTZ5kICFXPMkitgbgMmPX9FksaV4I3oRT0gc5P/OQAwTb80beqnROrknzLfvadRXOc3jL5XXFt9xrGs5SyYmSqsvJJhGYhn+DeFM2qs1eh5iryQJVkIxmgRBn5HL/3CQfVPjCEw8x9jIduTsWlhUXXGOZFxIN6dFW1x+gLex+dFcUxA62vGuVLSqynO5qUrRIWlDowhE0CvocZsAm6m+bESQ9lx2myX665hAXO8FQtYXXVjUtmFyR5cB56kzFS50iigWSMzYFpqQUDI0ubvn891dbuwf0Env9w7tMiWbT7rBdkLNb/X/l6Q/zMzOlpTSyKn0GklbBr5yismlx5IWFn/p5+idowJyI7yk14X/Q3sq9ypkVrkTerhgjYf7gIAcdSsmJOHvwquxc222exmrpl5CubUT+tVh3S+j3XptKG+gdgXXGeTiwcpqq3aydRD3IEz1Fer514wFvs1iu2s4A1Bjb9vNBf3p/zvsyoAQGhwWunOZGJcEV2BgOZXb9HQsqUP/S0UV4yeWxZOLmO8OExFk+QTe1ieKha5J9+G9xX1uX3k5GgLchVEKjSVR9KVYftuY4ipGHFxlTtwN9igRt/kNJnmXUBXSC/zONSU18J2o8cVBETIGNpzwzetj9XG0Y0sXhjmUz95zo1h6Gqm91lIyYau6f8zEBRucpsiY4rESvn8QtCGUuzd2MmqVpSjI6vmS6DBqp8Te6lwdT40tTJiYI7AVcdZIMuAMW60/UqXwnwv490LrLg1lrrgK0LSkMjlTCEIVr3dO14WtF1aUEKFKklL7PPVouB+IGsMRE958I4TITUbZ4s2CYKn9C+JDog+MszzWF9NZ0ZYIjFgML2a1ma8IlGPXEWOGbEbWt/DU6NOwVQZ3GFXQs8zvF2QE+2+mZEuB6XFvg5STbTRaWSNkZDZAK79Hk5UH/t2/9BhJr3q2IuYFqDw6To2Clf0rA3dSg4ebYAi4JKnJrz/NTJ/eWI35B+Z312mZuGr+EwS7pvQyJiIa2rWdmfeFoSKcxtLe/eHH2ZBq6Ye/+3/dDhsBEMg1JZrwEGvTs3hf0qNZKdaaLpEdRx2gmyPgtnesn4BfNXD0oko7NbxtjsRtk6nQAKCl/Np5DPLz2FHs52M+JlBPd12AES58muiDS6lWRNq4f9nnvFL2ShZQCc9HooGBfCpOFcpugDer0/kyHJJTfja8rOJobIu/BTUd17QOqEnnULMa2GZlo/KYjzPAvVtle9AZC3DCU4Z1JHIXIR8TWrTe9a7HA8tccL+0V1oFZQUHbygW2oVqLnVGxJOoROhQJ8/OMD/R/j8gOceE+M29bxFRFhYMwsPUrm79cj/sOQ6hhVCEClGfK+Of3ILxjlwfwN2O5UF28QIYG4DDFIpaH2jvSv4EDgQnbCvV8Fi9DTk5BW47JBaZv40VBrBoGEoZnJA0VokU2hnT6cuGhW8PuDc+AWNocs29yOBfvxmP/BVx35a85olXPGeQWzAgPub5F2OPrv5FNP4nbeuDC/rMdhtRDL+5q7EPBy6mHCLeqq7huUV9QIwmELMLKLo2btWstDirvPzfxSCPhacfJjTi4aXc8/e5sR//+KJusEYHymIEhSKEiPqT+WnBTgB1m747UE1HuldvkPt8ap87oSEALbQhf1wiaLRYDSxxXFt/bh/Ozu02nZN2Sk3eJ20LA9w3cUZpk
// ==/UserScript==

// Prevent the player from retrieving the correct playback information
Object.defineProperty(window, "__playinfo__", {
  get: function () {
    return null;
  },
});
const mockUserInfo = {
  code: 0,
  message: "0",
  ttl: 1,
  data: {
    isLogin: true,
    email_verified: 1,
    face: "https://i0.hdslb.com/bfs/face/0c84b9f4ad546d3f20324809d45fc439a2a8ddab.jpg",
    face_nft: 0,
    face_nft_type: 0,
    level_info: {
      current_level: 6,
      current_min: 28800,
      current_exp: 29050,
      next_exp: "--",
    },
    mid: 3493281916783362,
    mobile_verified: 1,
    money: 10000000000000,
    moral: 70,
    official: {
      role: 0,
      title: "",
      desc: "",
      type: -1,
    },
    officialVerify: {
      type: -1,
      desc: "",
    },
    pendant: {
      pid: 0,
      name: "",
      image: "",
      expire: 0,
      image_enhance: "",
      image_enhance_frame: "",
      n_pid: 0,
    },
    scores: 0,
    uname: "bilibili",
    vipDueDate: 1674748800000,
    vipStatus: 0,
    vipType: 1,
    vip_pay_type: 0,
    vip_theme_type: 0,
    vip_label: {
      path: "",
      text: "",
      label_theme: "",
      text_color: "",
      bg_style: 0,
      bg_color: "",
      border_color: "",
      use_img_label: true,
      img_label_uri_hans: "",
      img_label_uri_hant: "",
      img_label_uri_hans_static:
        "https://i0.hdslb.com/bfs/vip/d7b702ef65a976b20ed854cbd04cb9e27341bb79.png",
      img_label_uri_hant_static:
        "https://i0.hdslb.com/bfs/activity-plat/static/20220614/e369244d0b14644f5e1a06431e22a4d5/KJunwh19T5.png",
    },
    vip_avatar_subscript: 0,
    vip_nickname_color: "",
    vip: {
      type: 1,
      status: 0,
      due_date: 1674748800000,
      vip_pay_type: 0,
      theme_type: 0,
      label: {
        path: "",
        text: "",
        label_theme: "",
        text_color: "",
        bg_style: 0,
        bg_color: "",
        border_color: "",
        use_img_label: true,
        img_label_uri_hans: "",
        img_label_uri_hant: "",
        img_label_uri_hans_static:
          "https://i0.hdslb.com/bfs/vip/d7b702ef65a976b20ed854cbd04cb9e27341bb79.png",
        img_label_uri_hant_static:
          "https://i0.hdslb.com/bfs/activity-plat/static/20220614/e369244d0b14644f5e1a06431e22a4d5/KJunwh19T5.png",
      },
      avatar_subscript: 0,
      nickname_color: "",
      role: 0,
      avatar_subscript_url: "",
      tv_vip_status: 0,
      tv_vip_pay_type: 0,
      tv_due_date: 0,
      avatar_icon: {
        icon_resource: {},
      },
    },
    wallet: {
      mid: 700756870,
      bcoin_balance: 0,
      coupon_balance: 0,
      coupon_due_time: 0,
    },
    has_shop: false,
    shop_url: "",
    answer_status: 0,
    is_senior_member: 1,
    wbi_img: {
      img_url:
        "https://i0.hdslb.com/bfs/wbi/7cd084941338484aae1ad9425b84077c.png",
      sub_url:
        "https://i0.hdslb.com/bfs/wbi/4932caff0ff746eab6f01bf08b70ac45.png",
    },
    is_jury: false,
    name_render: null,
  },
};
// Normally, getting data from localStorage is sufficient,
// I doubt anyone clears localStorage manually.
// GenWebTicket will be automatically triggered,
// but the more async requests, the less overall speed.
const web_key_urls = {
  img_key_url: localStorage.getItem("wbi_img_url") || "",
  sub_key_url: localStorage.getItem("wbi_sub_url") || "",
};
/**
 * @param {string}
 * */
const getWebKey = function (str) {
  return str.slice(str.lastIndexOf("/") + 1, str.lastIndexOf("."));
};
const img_key = getWebKey(web_key_urls.img_key_url);
const sub_key = getWebKey(web_key_urls.sub_key_url);
(function () {
  "use strict";
  const originalOpen = XMLHttpRequest.prototype.open;
  const originalSend = XMLHttpRequest.prototype.send;

  XMLHttpRequest.prototype.open = function (...args) {
    this._interceptUrl = args[1];
    // inject custom qsParams to fetch higher-quality CDN video
    if (this._interceptUrl.includes("api.bilibili.com/x/player/wbi/playurl")) {
      // Remove w_rid & wts, set try_look=1 and qn=80, then re-WbiSign
      const qsParams = Object.fromEntries(
        new URLSearchParams(args[1].split(/\?|&w_rid/)[1]).entries()
      );
      Reflect.set(qsParams, "qn", 80); //qualityNumber->1080p
      Reflect.set(qsParams, "try_look", 1);
      const query = new WbiSign().encWbi(qsParams, img_key, sub_key);
      args[1] = "//api.bilibili.com/x/player/wbi/playurl?" + query;
    }
    return originalOpen.apply(this, args);
  };

  XMLHttpRequest.prototype.send = function (body) {
    const xhr = this;

    const customOnReadyStateChange = function () {
      if (xhr.readyState === 4) {
        if (
          xhr._interceptUrl.includes("api.bilibili.com/x/web-interface/nav")
        ) {
          const resJson = JSON.parse(xhr.responseText);
          const wbi_img = resJson.data.wbi_img;
          Object.defineProperty(xhr, "responseText", {
            get: function () {
              if (resJson?.data?.isLogin === false) {
                // replace true wbi_key
                mockUserInfo.data.wbi_img = wbi_img;
                return JSON.stringify(mockUserInfo);
              }
              return JSON.stringify(resJson);
            },
          });
        } else if (
          xhr._interceptUrl.includes("api.bilibili.com/x/player/wbi/v2")
        ) {
          const resJson = JSON.parse(xhr.responseText);
          resJson.data.login_mid = Math.floor(Math.random() * 100000);
          Object.defineProperty(xhr, "responseText", {
            get: function () {
              return JSON.stringify(resJson);
            },
          });
        } else if (
          xhr._interceptUrl.includes("api.bilibili.com/x/player/wbi/playurl")
        ) {
          // request 1080p
          setTimeout(() => {
            const defaultQuality =
              JSON.parse(localStorage.bpx_player_profile).media.quality || 80;
            window.player && window.player.requestQuality(defaultQuality, null);
          }, 1000);
        }
      }

      if (xhr._originalOnReadyStateChange) {
        xhr._originalOnReadyStateChange.apply(this, arguments);
      }
    };

    if (!xhr._isHooked) {
      xhr._originalOnReadyStateChange = xhr.onreadystatechange;
      xhr.onreadystatechange = customOnReadyStateChange;
      xhr._isHooked = true;
    }

    return originalSend.apply(this, arguments);
  };
})();
//解除未登录用户查看评论数量限制
(function () {
  "use strict";
  const originalFetch = window.fetch;

  window.fetch = function (input, init = {}) {
    let url = "";

    // 处理 input 可能是字符串或 Request 对象
    if (typeof input === "string") {
      url = input;
    } else if (input instanceof Request) {
      url = input.url;
    }

    // 拦截获取视频评论、评论的评论列表请求
    if (
      url.includes("x/v2/reply/wbi/main") ||
      url.includes("x/v2/reply/reply")
    ) {
      init = Object.assign({}, init, { credentials: "omit" });
    }

    return originalFetch.call(this, input, init);
  };
})();