Greasy Fork is available in English.
我不喜欢 IP 属地,但是你手机都显示了,为什么电脑不显示呢?目前仅视频、动态评论区
当前为
// ==UserScript==
// @name 哔哩哔哩网页版展示 IP 属地
// @namespace http://zhangmaimai.com
// @version 1.4.6
// @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/*
// @grant unsafeWindow
// @run-at document-body
// ==/UserScript==
(function () {
'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 pageType = {
"dynamic": Symbol("dynamic"),
"bangumi": Symbol("bangumi")
};
const hookBbComment = async (type) => {
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 ${item.reply_control.location ?? "IP属地:未知"}</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/",
// video
"https://www.bilibili.com/list/",
// new media list (favlist)
"https://www.bilibili.com/opus/"
// new single dynamic page
])) {
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 === "https://t.bilibili.com/") {
const dynHome = await isElementLoaded(".bili-dyn-home--member");
const isNewDyn = (_a = dynHome.querySelector(".bili-dyn-sidebar__btn") || void 0) == 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);
})();