// ==UserScript== // @name 哔哩哔哩网页版展示 IP 属地 // @namespace http://zhangmaimai.com // @version 1.4.8 // @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/* // @require https://unpkg.com/@elliotdong/ajax-interceptor@0.1.2/dist/index.umd.cjs // @grant unsafeWindow // @run-at document-body // @downloadURL none // ==/UserScript== (function (ajaxInterceptor) { 'use strict'; const isElementLoaded = async (selector, root = document, timeout = 1e4) => { const start = Date.now(); while (root.querySelector(selector) === null) { if (Date.now() - start > timeout) throw new Error(`Timeout: ${timeout}ms exceeded`); await new Promise((resolve) => requestAnimationFrame(resolve)); } return root.querySelector(selector); }; const startsWithAny = (str, prefixes) => prefixes.some((prefix) => str.startsWith(prefix)); const getIPAddress = (replyItemEl) => { var _a, _b, _c, _d, _e, _f; const IPString = (_f = (_e = (_d = (_c = (_b = (_a = replyItemEl.className.startsWith("sub") ? replyItemEl.querySelector(".reply-content") : replyItemEl) == null ? void 0 : _a.__vnode) == null ? void 0 : _b.ctx) == null ? void 0 : _c.props) == null ? void 0 : _d.reply) == null ? void 0 : _e.reply_control) == null ? void 0 : _f.location; return `  ${IPString ?? "IP属地:未知"}`; }; const insertPAddressEl = (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 += getIPAddress(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; insertPAddressEl(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(insertPAddressEl); }); } }); observer.observe(targetNode, { childList: true, subtree: true }); }; var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); const hookCommentFetch = () => { ajaxInterceptor.intercept(_unsafeWindow); ajaxInterceptor.addBeforeRequestInterceptor(async (requestInit) => { var _a; if ((_a = requestInit.url) == null ? void 0 : _a.startsWith("https://api.bilibili.com/x/v2/reply/wbi/main")) { requestInit.credentials = "include"; } return ajaxInterceptor.defineRequestInit(requestInit); }); }; const pageType = { "dynamic": Symbol("dynamic"), "bangumi": Symbol("bangumi") }; const hookBbComment = async (type) => { hookCommentFetch(); 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  ${item.reply_control.location ?? "IP属地:未知"}`); }; 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/")) { 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); })(interceptor);