// ==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 // @downloadURL none // ==/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>/; return result.replace(replyTimeRegex, `$1  ${getLocationString(item)}`); }; 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); })();