Greasy Fork

Greasy Fork is available in English.

哔哩哔哩网页版展示 IP 属地

我不喜欢 IP 属地,但是你手机都显示了,为什么电脑不显示呢?目前仅视频、动态评论区

目前为 2023-09-23 提交的版本。查看 最新版本

// ==UserScript==
// @name         哔哩哔哩网页版展示 IP 属地
// @namespace    http://zhangmaimai.com
// @version      1.5.2
// @author       MaxChang3
// @description  我不喜欢 IP 属地,但是你手机都显示了,为什么电脑不显示呢?目前仅视频、动态评论区
// @license      MIT
// @icon         https://www.bilibili.com/favicon.ico
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/list/*
// @match        https://www.bilibili.com/bangumi/play/*
// @match        https://t.bilibili.com/*
// @match        https://www.bilibili.com/opus/*
// @match        https://space.bilibili.com/*
// @match        https://www.bilibili.com/v/topic/detail/*
// @match        https://www.bilibili.com/cheese/play/*
// @grant        unsafeWindow
// @run-at       document-body
// ==/UserScript==

(function () {
  'use strict';

  const isElementLoaded = async (selector, root = document) => {
    const getElement = () => root.querySelector(selector);
    return new Promise((resolve) => {
      const element = getElement();
      if (element)
        return resolve(element);
      const observer = new MutationObserver((_) => {
        const element2 = getElement();
        if (!element2)
          return;
        resolve(element2);
        observer.disconnect();
      });
      observer.observe(root === document ? root.body : root, {
        childList: true,
        subtree: true
      });
    });
  };
  const startsWithAny = (str, prefixes) => prefixes.some((prefix) => str.startsWith(prefix));
  const getLocationString = (replyItem) => {
    var _a;
    const locationString = (_a = replyItem == null ? void 0 : replyItem.reply_control) == null ? void 0 : _a.location;
    return locationString ?? "IP属地:未知";
  };
  const getLocationFromElement = (replyItemEl) => {
    var _a, _b, _c;
    const locationElement = replyItemEl.className.startsWith("sub") ? replyItemEl.querySelector(".reply-content") : replyItemEl;
    const locationString = getLocationString((_c = (_b = (_a = locationElement == null ? void 0 : locationElement.__vnode) == null ? void 0 : _a.ctx) == null ? void 0 : _b.props) == null ? void 0 : _c.reply);
    return `  ${locationString}`;
  };
  const insertLocation = (replyItemEl) => {
    const replyInfo = replyItemEl.className.startsWith("sub") ? replyItemEl.querySelector(".sub-reply-info") : replyItemEl.querySelector(".reply-info");
    if (!replyInfo)
      throw Error("Can not detect reply info");
    replyInfo.children[0].innerHTML += getLocationFromElement(replyItemEl);
  };
  const isReplyItem = (el) => el instanceof HTMLDivElement && ["reply-item", "sub-reply-item"].includes(el.className);
  const observeAndInjectComments = async (root) => {
    const targetNode = await isElementLoaded(".reply-list", root);
    const observer = new MutationObserver((mutationsList) => {
      for (let mutation of mutationsList) {
        if (mutation.type !== "childList")
          continue;
        mutation.addedNodes.forEach((node) => {
          if (!isReplyItem(node))
            return;
          insertLocation(node);
          if (node.className.startsWith("sub"))
            return;
          const subReplyListEl = node.querySelector(".sub-reply-list");
          if (!subReplyListEl)
            return;
          const subReplyList = Array.from(subReplyListEl.children);
          subReplyList.pop();
          subReplyList.map(insertLocation);
        });
      }
    });
    observer.observe(targetNode, { childList: true, subtree: true });
  };
  var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  const hookCommentXHR = () => {
    const originalXHR = _unsafeWindow.XMLHttpRequest;
    class newXHR extends originalXHR {
      constructor() {
        super();
      }
      open(method, url) {
        if (url.startsWith("https://api.bilibili.com/x/v2/reply/wbi/main")) {
          this.withCredentials = true;
        }
        super.open(method, url);
      }
    }
    _unsafeWindow.XMLHttpRequest = newXHR;
    console.log("hooked", originalXHR, _unsafeWindow.XMLHttpRequest);
  };
  const pageType = {
    "dynamic": Symbol("dynamic"),
    "bangumi": Symbol("bangumi")
  };
  const hookBbComment = async (type) => {
    hookCommentXHR();
    if (type === pageType.dynamic) {
      const dynBtn = await isElementLoaded(".bili-dyn-action.comment");
      if (dynBtn)
        dynBtn.click();
      await isElementLoaded(".bb-comment");
      dynBtn.click();
    } else if (type === pageType.bangumi) {
      await isElementLoaded(".bb-comment");
    }
    const bbComment = _unsafeWindow.bbComment;
    if (!bbComment)
      throw Error("Can not detect bbComment");
    const createListCon = bbComment.prototype._createListCon;
    const createSubReplyItem = bbComment.prototype._createSubReplyItem;
    const applyHandler = (target, thisArg, args) => {
      const [item] = args;
      const result = Reflect.apply(target, thisArg, args);
      const replyTimeRegex = /<span class="reply-time">(.*?)<\/span>/;
      return result.replace(replyTimeRegex, `<span class="reply-time">$1&nbsp;&nbsp;${getLocationString(item)}</span>`);
    };
    bbComment.prototype._createListCon = new Proxy(createListCon, { apply: applyHandler });
    bbComment.prototype._createSubReplyItem = new Proxy(createSubReplyItem, { apply: applyHandler });
  };
  const matchPrefix = async (url) => {
    var _a;
    if (startsWithAny(url, [
      "https://www.bilibili.com/video/",
      // 视频
      "https://www.bilibili.com/list/",
      // 新列表
      "https://www.bilibili.com/opus/",
      // 新版单独动态页
      "https://www.bilibili.com/cheese/play/"
      // 课程页
    ])) {
      observeAndInjectComments();
    } else if (url.startsWith("https://www.bilibili.com/bangumi/play/")) {
      const isNewBangumi = !!document.querySelector("meta[name=next-head-count]");
      if (isNewBangumi) {
        observeAndInjectComments();
      } else {
        hookBbComment(pageType.bangumi);
      }
    } else if (url.startsWith("https://space.bilibili.com/") && url.endsWith("dynamic") || // 个人空间动态页
    url.startsWith("https://www.bilibili.com/v/topic/detail/")) {
      hookBbComment(pageType.dynamic);
    } else if (url.startsWith("https://space.bilibili.com/")) {
      const dynamicTab = await isElementLoaded(".n-dynamic");
      dynamicTab.addEventListener("click", () => {
        hookBbComment(pageType.dynamic);
      }, { once: true });
    } else if (url.startsWith("https://t.bilibili.com/") && location.pathname === "/") {
      const dynHome = await isElementLoaded(".bili-dyn-home--member");
      const isNewDyn = (_a = dynHome.querySelector(".bili-dyn-sidebar__btn")) == null ? void 0 : _a.innerText.startsWith("新版反馈");
      if (isNewDyn) {
        const dynList = await isElementLoaded(".bili-dyn-list", dynHome);
        let lastObserved;
        const observer = new MutationObserver((mutationsList) => {
          for (let mutation of mutationsList) {
            if (mutation.type !== "childList" || !(mutation.target instanceof HTMLElement) || !mutation.target.classList.contains("bili-comment-container") || mutation.target === lastObserved)
              continue;
            observeAndInjectComments(mutation.target);
            lastObserved = mutation.target;
          }
        });
        observer.observe(dynList, { childList: true, subtree: true });
      } else {
        hookBbComment(pageType.dynamic);
      }
    } else if (url.startsWith("https://t.bilibili.com/")) {
      const dynItem = await isElementLoaded(".bili-dyn-item");
      const isNewDyn = !!dynItem.querySelector(".bili-comment-container");
      if (isNewDyn) {
        const commentContainer = await isElementLoaded(".bili-comment-container", dynItem);
        observeAndInjectComments(commentContainer);
      } else {
        hookBbComment(pageType.dynamic);
      }
    }
  };
  matchPrefix(location.href);

})();