// ==UserScript==
// @name 全网内容屏蔽
// @name:zh 网络内容过滤器
// @namespace Violentmonkey Scripts
// @match *://*.weibo.com/*
// @match *://*.weibo.cn/*
// @match *://weibo.com/*
// @match *://m.hupu.com/*
// @match *://tieba.baidu.com/*
// @match *://www.zhihu.com/*
// @match *://www.zhihu.com
// @match *://*.bilibili.com/*
// @exclude *://weibo.com/tv*
// @grant GM.getValue
// @grant GM.setValue
// @version 4.0.1
// @author no one
// @description 屏蔽特定用户的帖子和评论
// @description:zh 屏蔽特定用户的帖子和评论
// @run-at document-start
// @require https://update.gf.qytechs.cn/scripts/472943/1320613/Itsnotlupus%27%20MiddleMan.js
// ==/UserScript==
(() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
// src/utils/store.ts
var DomainStore = class _DomainStore {
static NgListKey = "NgList";
static domainKeyPrefix;
static listener(user) {
const store = new _DomainStore();
store.addUser(user);
}
static {
const domain = document.location.host;
let segs = domain.split(".");
if (segs.length > 2) segs = segs.slice(1);
this.domainKeyPrefix = `${segs.join(".")}:${this.NgListKey}`;
}
static async init() {
let blockedUsers = [];
const value = await GM.getValue(_DomainStore.blockUsersKey());
if (value === void 0) {
const list = await this.loadBlackList();
blockedUsers = list.map((name) => {
if (this.domainKeyPrefix.includes("zhihu")) {
return {
id: name,
name: "",
blockedDate: /* @__PURE__ */ new Date()
};
} else {
return {
name,
id: "",
blockedDate: /* @__PURE__ */ new Date()
};
}
});
const value2 = JSON.stringify(blockedUsers);
await GM.setValue(_DomainStore.blockUsersKey(), value2);
} else {
blockedUsers = JSON.parse(value);
blockedUsers.forEach((user) => {
user.name = user.name.trim();
});
}
const val = await GM.getValue(_DomainStore.patternKey());
const patterns = JSON.parse(val || "[]");
return new _DomainStore(blockedUsers, patterns);
}
nameMap = /* @__PURE__ */ new Map();
// private idMap: Map<string | number, BlockedUser> = new Map();
excludePatterns = [];
get userList() {
return this.nameMap.keys();
}
get patternList() {
return structuredClone(this.excludePatterns);
}
matchPattern(text) {
text = text.trim();
return this.excludePatterns.some((pattern) => {
return text.toLocaleLowerCase().includes(pattern.toLocaleLowerCase());
});
}
addPattern(text) {
const s = new Set(this.excludePatterns).add(text.trim());
this.excludePatterns = [...s];
this.flush();
}
removePattern(text) {
text = text.trim();
this.excludePatterns = this.excludePatterns.filter((pattern) => {
return pattern !== text;
});
this.flush();
}
hasUser({ name, id }) {
if (!name) {
return false;
}
return this.nameMap.has(name.trim());
}
addUser({ name, id }) {
name = name.trim();
const user = { name, id, blockedDate: /* @__PURE__ */ new Date() };
if (user.name) this.nameMap.set(name, user);
this.flush();
}
removeUser({ name, id }) {
if (name) this.nameMap.delete(name.trim());
this.flush();
}
static blockUsersKey() {
return `${_DomainStore.domainKeyPrefix}:blockedusers`;
}
static patternKey() {
return `${_DomainStore.domainKeyPrefix}:patterns`;
}
async flush() {
const blockedUsers = [...this.nameMap.values()];
const val = JSON.stringify(blockedUsers);
await GM.setValue(_DomainStore.blockUsersKey(), val);
const pv = JSON.stringify(this.excludePatterns);
await GM.setValue(_DomainStore.patternKey(), pv);
}
static singleton;
constructor(users, patterns) {
if (_DomainStore.singleton) {
return _DomainStore.singleton;
}
for (const user of users) {
this.nameMap.set(user.name, user);
}
this.excludePatterns = patterns;
_DomainStore.singleton = this;
}
// 获取屏蔽词列表
static async loadBlackList() {
const value = await GM.getValue(_DomainStore.domainKeyPrefix);
if (!value) return [];
const ret = JSON.parse(value.toString());
if (!Array.isArray(ret)) return [];
console.log(`gm value: ${ret}`);
return ret;
}
};
// src/utils/css.ts
var BlockButtonClass = "block-button";
var HoverButtonClass = "hover-button";
var cssByCls = (cls) => `.${cls}`;
var ButtonCSSText = `
${cssByCls(BlockButtonClass)} {
cursor: pointer;
height: 12px;
width: 12px;
margin-left: 1px;
float: inherit;
background: white;
border-width: 0;
padding: 0;
line-height:0px;
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: bottom;
}
${cssByCls(BlockButtonClass)}:hover {
transform: translateY(0) scale(1.5);
}`;
var css = `
#add_ngList_btn {
position: fixed;
bottom: 2rem;
left: 1rem;
width: 2rem;
height: 2rem;
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.5);
background: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer !important;
z-index: 100;
}
#add_ngList_btn::before {
content: '';
position: absolute;
width: 16px;
height: 2px;
background: rgba(0, 0, 0, 0.5);
top: calc(50% - 1px);
left: calc(50% - 8px);
}
#add_ngList_btn::after {
content: '';
position: absolute;
height: 16px;
width: 2px;
background: rgba(0, 0, 0, 0.5);
top: calc(50% - 8px);
left: calc(50% - 1px);
}
.my-dialog__wrapper {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
margin: 0;
z-index: 10000;
background: rgba(0, 0, 0, 0.3);
display: none;
}
.my-dialog {
position: relative;
background: #FFFFFF;
border-radius: 2px;
box-shadow: 0 1px 3px rgb(0 0 0 / 30%);
box-sizing: border-box;
width: 50%;
transform: none;
left: 0;
margin: 0 auto;
}
.my-dialog .my-dialog__header {
border-bottom: 1px solid #e4e4e4;
padding: 14px 16px 10px 16px;
}
.my-dialog__title {
line-height: 24px;
font-size: 18px;
color: #303133;
}
.my-dialog__headerbtn {
position: absolute;
top: 20px;
right: 20px;
padding: 0;
background: transparent;
border: none;
outline: none;
cursor: pointer;
font-size: 16px;
width: 12px;
height: 12px;
transform: rotateZ(45deg);
}
.my-dialog .my-dialog__header .my-dialog__headerbtn {
right: 16px;
top: 16px;
}
.my-dialog__headerbtn .my-dialog__close::before {
content: '';
position: absolute;
width: 12px;
height: 1.5px;
background: #909399;
top: calc(50% - 0.75px);
left: calc(50% - 6px);
border-radius: 2px;
}
.my-dialog__headerbtn:hover .my-dialog__close::before {
background: #1890ff;
}
.my-dialog__headerbtn .my-dialog__close::after {
content: '';
position: absolute;
height: 12px;
width: 1.5px;
background: #909399;
top: calc(50% - 6px);
left: calc(50% - 0.75px);
border-radius: 2px;
}
.my-dialog__headerbtn:hover .my-dialog__close::after {
background: #1890ff;
}
.my-dialog__body {
padding: 30px 20px;
color: #606266;
font-size: 14px;
word-break: break-all;
}
.my-dialog__footer {
padding: 20px;
padding-top: 10px;
text-align: right;
box-sizing: border-box;
}
.my-dialog .my-dialog__footer {
padding: 0px 16px 24px 16px;
margin-top: 40px;
}
#ngList {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
max-height: 480px;
overflow-y: scroll;
}
${ButtonCSSText}
.close-icon {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
position: relative;
transform: rotateZ(45deg);
margin-left: 8px;
cursor: pointer;
}
.close-icon:hover {
background: #409eff;
}
.close-icon::before {
content: '';
position: absolute;
width: 8px;
height: 2px;
background: #409eff;
top: calc(50% - 1px);
left: calc(50% - 4px);
border-radius: 2px;
}
.close-icon:hover::before {
background: #fff;
}
.close-icon::after {
content: '';
position: absolute;
height: 8px;
width: 2px;
background: #409eff;
top: calc(50% - 4px);
left: calc(50% - 1px);
border-radius: 2px;
}
.close-icon:hover::after {
background: #fff;
}
.ng_item {
background-color: #ecf5ff;
display: inline-flex;
align-items: center;
padding: 0 10px;
font-size: 12px;
color: #409eff;
border: 1px solid #d9ecff;
border-radius: 4px;
box-sizing: border-box;
white-space: nowrap;
height: 28px;
line-height: 26px;
margin-left: 12px;
margin-top: 8px;
}
.ng_pattern {
background-color: #ff704d;
display: inline-flex;
align-items: center;
padding: 0 10px;
font-size: 12px;
color: #000000;
text-decoration: line-through;
border: 1px solid #d9ecff;
border-radius: 4px;
box-sizing: border-box;
white-space: nowrap;
height: 28px;
line-height: 26px;
margin-left: 12px;
margin-top: 8px;
}
.input_container {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.el-input {
position: relative;
font-size: 14px;
display: inline-block;
width: 100%;
}
.el-input__inner {
-webkit-appearance: none;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
width: 100%;
cursor: pointer;
font-family: inherit;
}
.el-button {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.el-button:focus,
.el-button:hover {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
.el-button:active {
color: #3a8ee6;
border-color: #3a8ee6;
outline: none;
}
.input_container .el-input {
margin-right: 12px;
}
.tips {
margin-top: 24px;
font-size: 12px;
color: #F56C6C;
}
.${HoverButtonClass}:hover {
filter: opacity(1);
transition: filter 0.1s linear 0.1s;
}
.${HoverButtonClass} {
filter: opacity(0);
z-index: 10;
position: absolute;
top: 8px;
left: 8px;
transition: filter 0.1s linear 0s;
}
`;
var svgIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10" />
<line x1="4" y1="4" x2="20" y2="20" />
</svg>
`;
function createBlockButton({
name,
id,
subclass,
listeners,
css: css2
}) {
name = name.trim().replace(/^@/, "").replace("\uFF1A", "");
const wrapper = document.createElement("div");
wrapper.innerHTML = svgIcon;
wrapper.className = BlockButtonClass;
if (subclass) wrapper.classList.add(subclass);
wrapper.setAttribute("user-name", name);
wrapper.setAttribute("user-id", id);
if (css2) {
const style = document.createElement("style");
style.textContent = css2;
wrapper.appendChild(style);
}
wrapper.addEventListener("click", (ev) => {
ev.preventDefault();
ev.stopPropagation();
if (typeof listeners === "function") {
listeners({ name, id });
} else {
listeners.forEach((listener) => {
listener({ name, id });
});
}
});
return wrapper;
}
function addStyle(cssStyle) {
if (!cssStyle) return;
const head = document.querySelector("head");
const style = document.createElement("style");
style.type = "text/css";
style.innerHTML = cssStyle;
head?.appendChild(style);
}
// src/filters/base.ts
var defaultNameFn = (elem) => {
const href = elem.getAttribute("href");
const id = href?.split("/").at(-1);
return {
name: elem?.textContent || elem?.getAttribute("aria-label"),
id
};
};
var defaultContentFn = (elem) => {
return elem ? elem.textContent : "";
};
function newListAndUser(list, user, content) {
return {
listSelector: list,
userSelector: user,
contentSelector: content ? content : ""
};
}
function RegisterSubclass(target) {
WebsiteFilter.registerClass(target);
}
var WebsiteFilter = class _WebsiteFilter {
static subclasses;
static registerClass(FilterClass) {
if (!_WebsiteFilter.subclasses) {
_WebsiteFilter.subclasses = [];
}
_WebsiteFilter.subclasses.push(FilterClass);
}
static fromHost() {
const host = document.location.host;
for (const cls of _WebsiteFilter.subclasses) {
if (host.includes(cls.host)) {
return new cls();
}
}
}
renderers = [];
proxyOpt = {
requestRouters: [],
responseRouters: []
};
registered = false;
removeElements(selectors, root = document, nameFn = defaultNameFn, contentFn = defaultContentFn) {
if (selectors.length < 1) {
return;
}
const selector = selectors[0];
const list = root.querySelectorAll(selector.listSelector);
list.forEach((element) => {
const user = element.querySelector(selector.userSelector);
if (!user) {
return;
}
let content;
if (selector.contentSelector) {
const contentElement = element.querySelector(selector.contentSelector);
content = contentFn(contentElement);
} else {
content = "";
}
const poster = nameFn(user);
if (this.inBlackList(poster, content)) {
element?.parentNode?.removeChild(element);
} else {
this.removeElements(selectors.slice(1), element, nameFn, contentFn);
}
});
}
inBlackList(name, content = "") {
const store = new DomainStore();
return store.hasUser(name) || store.matchPattern(content);
}
registerHooks() {
if (!this.registered) {
const opt = this.proxyOpt;
opt.requestRouters.forEach((router) => {
middleMan.addHook(router.hookMeta.pattern, this.requestHandler(router));
});
opt.responseRouters.forEach((router) => {
middleMan.addHook(
router.hookMeta.pattern,
this.responseHandler(router)
);
});
this.registered = true;
}
}
constructor() {
this.addHooks(
...Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter((name) => Object.getPrototypeOf(this)[name].hookMeta).reduce((hooks, name) => {
const pd = Object.getOwnPropertyDescriptor(
Object.getPrototypeOf(this),
name
);
const fn = pd.value.bind(this);
fn.hookMeta = pd.value.hookMeta;
hooks.push(fn);
return hooks;
}, [])
);
this.renderers = Object.getOwnPropertyNames(
Object.getPrototypeOf(this)
).reduce((fns, name) => {
const method = Object.getOwnPropertyDescriptor(
Object.getPrototypeOf(this),
name
).value;
if (method.filterMeta) {
const fn = method.bind(this);
fn.filterMeta = method.filterMeta;
fns.push(fn);
}
return fns;
}, []);
this.registerHooks();
}
addHooks(...hooks) {
hooks.forEach((hook) => {
switch (hook.hookMeta.type) {
case "request":
this.proxyOpt.requestRouters.push(hook);
break;
case "response":
this.proxyOpt.responseRouters.push(hook);
break;
}
});
}
requestHandler(hook) {
return {
async requestHandler(request) {
const h = hook;
return h(request);
}
};
}
responseHandler(hook) {
return {
async responseHandler(request, response, error) {
if (error) {
throw error;
}
const res = await response.json();
const url = request.url;
const h = hook;
h(url, res);
return Response.json(res);
}
};
}
injectButton({
listSelector,
userSelector,
elementButtonFunc,
doc = document,
subListSelector,
subUserSelector,
nameFn = defaultNameFn
}) {
const list = doc.querySelectorAll(listSelector);
list.forEach((element) => {
let user = element.querySelector(userSelector);
if (!user) {
return;
}
const { name, id } = nameFn(user);
if (elementButtonFunc)
elementButtonFunc(element, { name, id });
if (element.querySelector(`${cssByCls(BlockButtonClass)}`)) {
return;
}
const btn = createBlockButton({
name,
id,
listeners: [DomainStore.listener, this.render.bind(this)]
});
while (user && user.parentNode !== element) {
if (user.parentNode.childElementCount > 1) {
user.parentNode.appendChild(btn);
break;
}
user = user.parentNode;
}
if (user && user.parentNode === element) {
user.parentNode.appendChild(btn);
}
});
list.forEach((element) => {
if (subListSelector && subUserSelector) {
this.injectButton({
listSelector: subListSelector,
userSelector: subUserSelector,
doc: element,
nameFn
});
}
});
}
render() {
this.renderers.forEach((f) => {
if (typeof f.filterMeta === "boolean") {
f();
} else {
const href = document.location.href;
if (href.match(f.filterMeta.pattern)) {
f();
}
}
});
}
};
function filterFunc(target, name, descriptor) {
const fn = descriptor.value;
fn.filterMeta = true;
}
function patternFilterFunc(pattern) {
return (target, name, descriptor) => {
descriptor.value.filterMeta = { pattern };
};
}
function HookDecorator(type) {
return (pattern) => {
return (target, name, descriptor) => {
descriptor.value.hookMeta = {
type,
pattern
};
};
};
}
var reqHook = HookDecorator("request");
var respHook = HookDecorator("response");
// src/filters/zhihu.ts
var userFunc = (element) => {
const href = element.getAttribute("href");
return {
id: href.split("/").at(-1),
name: element.textContent
};
};
var FeedUserFunc = (e) => {
const metaText = e.dataset.zaExtraModule;
let id = "";
if (metaText) {
const meta = JSON.parse(metaText);
id = meta?.card?.content?.author_member_hash_id;
}
const zop = e.dataset.zop;
const name = JSON.parse(zop).authorName;
return { id, name };
};
var ZhihuFilter = class extends WebsiteFilter {
interceptAnalytics() {
return Response.json({}, { status: 200 });
}
interceptTouch() {
return Response.json({ success: true }, { status: 201 });
}
async filterComments() {
const selector = {
comments: "div.css-18ld3w0 > div[data-id]",
commentUser: "div.css-jp43l4 a.css-10u695f",
commentContent: "div.css-jp43l4 div.CommentContent.css-1jpzztt",
replies: "div[data-id]",
replyUser: "a.css-10u695f",
replyContent: "div.CommentContent.css-1jpzztt"
};
this.removeElements(
[
newListAndUser(
selector.comments,
selector.commentUser,
selector.commentContent
),
newListAndUser(
selector.replies,
selector.replyUser,
selector.replyContent
)
],
document,
userFunc,
ZhihuFilter.contentFunc
);
this.injectButton({
listSelector: selector.comments,
userSelector: selector.commentUser,
subListSelector: selector.replies,
subUserSelector: selector.replyUser,
nameFn: userFunc
});
}
static contentFunc(element) {
return element ? element.textContent + element.querySelector("img")?.getAttribute("alt") : "";
}
async filterAnswerComments() {
const selector = {
comments: "div.css-16zdamy div[data-id]",
commentUser: "div.css-1tww9qq a.css-10u695f",
commentContent: "div.CommentContent.css-1jpzztt"
};
this.removeElements(
[
newListAndUser(
selector.comments,
selector.commentUser,
selector.commentContent
)
],
document,
userFunc,
ZhihuFilter.contentFunc
);
this.injectButton({
listSelector: selector.comments,
userSelector: selector.commentUser,
nameFn: userFunc
});
}
async filterAnswers() {
const cardSelector = {
card: "div.Card.AnswerCard.css-0",
user: "div.ContentItem.AnswerItem"
};
this.removeElements(
[newListAndUser(cardSelector.card, cardSelector.user)],
document,
FeedUserFunc
);
this.injectButton({
listSelector: cardSelector.card,
userSelector: cardSelector.user,
nameFn: FeedUserFunc
});
const selector = {
answers: "div.List-item",
answerUser: "div.ContentItem.AnswerItem"
};
this.removeElements(
[newListAndUser(selector.answers, selector.answerUser)],
document,
FeedUserFunc
);
this.injectButton({
listSelector: selector.answers,
userSelector: selector.answerUser,
nameFn: FeedUserFunc
});
}
async filterRecommends() {
const selector = {
listSelector: "div.Card.TopstoryItem.TopstoryItem-isRecommend",
userSelector: "div.ContentItem.AnswerItem"
};
this.removeElements(
[newListAndUser(selector.listSelector, selector.userSelector)],
document,
FeedUserFunc
);
this.injectButton({
listSelector: selector.listSelector,
userSelector: selector.userSelector,
nameFn: FeedUserFunc
});
}
async filterQuestions() {
}
hookComments(url, res) {
const comments = res.data;
res.data = comments.filter((comment) => {
const id = comment.author.id;
const name = comment.author.name;
const content = comment.content;
return !this.inBlackList({ id, name }, content);
});
res.data.forEach((comment) => {
comment.childComments = comment.childComments?.filter((childComment) => {
const { id, name } = childComment.author;
const content = childComment.content;
return !this.inBlackList({ id, name }, content);
});
});
}
hookAnswers(url, res) {
const answers = res.data;
res.data = answers.filter((answer) => {
const id = answer.target?.author?.id;
const name = answer.target.author.name;
const content = answer.target?.content;
return !this.inBlackList({ name, id }, content);
});
}
interceptTrends(url, res) {
res.preset_words.words = [];
}
interceptHotList(url, res) {
res.data = [];
res.display_num = 0;
res.display_first = false;
}
interceptRecommends(url, res) {
res.data = [];
}
};
__publicField(ZhihuFilter, "host", "zhihu.com");
__decorateClass([
reqHook(/zhihu-web-analytics|datahub|apm/)
], ZhihuFilter.prototype, "interceptAnalytics", 1);
__decorateClass([
reqHook(/lastread\/touch/)
], ZhihuFilter.prototype, "interceptTouch", 1);
__decorateClass([
filterFunc
], ZhihuFilter.prototype, "filterComments", 1);
__decorateClass([
filterFunc
], ZhihuFilter.prototype, "filterAnswerComments", 1);
__decorateClass([
filterFunc
], ZhihuFilter.prototype, "filterAnswers", 1);
__decorateClass([
filterFunc
], ZhihuFilter.prototype, "filterRecommends", 1);
__decorateClass([
filterFunc
], ZhihuFilter.prototype, "filterQuestions", 1);
__decorateClass([
respHook(/\/root_comment|\/child_comment/)
], ZhihuFilter.prototype, "hookComments", 1);
__decorateClass([
respHook(/questions\/\d+\/feeds/)
], ZhihuFilter.prototype, "hookAnswers", 1);
__decorateClass([
respHook(/search\/preset_words/)
], ZhihuFilter.prototype, "interceptTrends", 1);
__decorateClass([
respHook(/feed\/topstory\/hot-lists/)
], ZhihuFilter.prototype, "interceptHotList", 1);
__decorateClass([
respHook(/recommend_follow_people/)
], ZhihuFilter.prototype, "interceptRecommends", 1);
ZhihuFilter = __decorateClass([
RegisterSubclass
], ZhihuFilter);
// src/filters/weibo.ts
var WeiboFilter = class extends WebsiteFilter {
apiBlackList = ["/female_version.mp3", "/intake/v2/rum/events"];
mockRequests() {
return Response.json({}, { status: 200 });
}
interceptRead() {
const data = {
data: [
{
act: "PC_real_read",
duration: 1902,
read_duration: 1902,
itemid: "5067162012353224",
type: "adMblog",
rid: "0_0_1_5135480043505157444_0_0_0",
page: "",
root_id: "5058972623834652",
uicode: 20000390,
groupid: 20000390,
fid: 232150,
analysis_extra: "",
__date: 1723590632,
ext: "module:02",
PC_real_read: 1
}
],
ok: 1
};
return Response.json(data);
}
constructor() {
super();
this.hideTrends();
}
async filterSearchResults() {
const selector = {
cards: "div.card-wrap",
cardUser: "div.info a.name",
cardContent: "div.feed_list_content",
retweetedCards: "div.card-wrap div.card-comment",
retweetedCardUser: "div.con a.name",
comments: "div.card-review",
commentUser: "div.content a.name",
commentContent: "div.content div.txt"
};
this.injectButton({
listSelector: selector.cards,
userSelector: selector.cardUser,
elementButtonFunc: this.createCommentButton.bind(this)
});
this.injectButton({
listSelector: selector.retweetedCards,
userSelector: selector.retweetedCardUser
});
this.removeElements([
newListAndUser(selector.cards, selector.cardUser, selector.cardContent),
newListAndUser(
selector.comments,
selector.commentUser,
selector.commentContent
)
]);
this.removeElements([
newListAndUser(selector.cards, selector.retweetedCardUser)
]);
}
async filterFeeds() {
const selector = {
cardListSelector: "div.vue-recycle-scroller__item-view",
cardUserSelector: "div.Feed_body_3R0rO a.ALink_default_2ibt1",
commentListSelector: "div.wbpro-list",
commentUserSelector: "div.con1.woo-box-item-flex div.text a.ALink_default_2ibt1",
replyListSelector: "div.item2",
replyUserSelector: "div.con2 a.ALink_default_2ibt1"
};
this.removeElements([
newListAndUser(selector.cardListSelector, selector.cardUserSelector),
newListAndUser(
selector.commentListSelector,
selector.commentUserSelector
),
newListAndUser(selector.replyListSelector, selector.replyUserSelector)
]);
this.injectButton({
listSelector: selector.cardListSelector,
userSelector: selector.cardUserSelector
});
const feedWrappers = document.querySelectorAll(selector.cardListSelector);
feedWrappers.forEach((feed) => {
this.injectButton({
listSelector: selector.commentListSelector,
userSelector: selector.commentUserSelector,
doc: feed,
subListSelector: selector.replyListSelector,
subUserSelector: selector.replyUserSelector
});
});
}
async filterReplies() {
const reply = document.querySelector("div.ReplyModal_scroll3_2kADQ");
if (!reply) {
return;
}
const selector = {
commentListSelector: "div.wbpro-list",
commentUserSelector: "div.con1.woo-box-item-flex a.ALink_default_2ibt1",
root: reply,
replyListSelector: "div.vue-recycle-scroller__item-view",
replyUserSelector: "div.con2 a.ALink_default_2ibt1"
};
this.removeElements(
[
newListAndUser(
selector.commentListSelector,
selector.commentUserSelector
),
newListAndUser(selector.replyListSelector, selector.replyUserSelector)
],
reply
);
this.injectButton({
listSelector: selector.commentListSelector,
userSelector: selector.commentUserSelector,
doc: reply,
subListSelector: selector.replyListSelector,
subUserSelector: selector.replyUserSelector
});
}
createCommentButton(card, user) {
this.injectButton({
listSelector: "div.card-together div.list div.card-review",
userSelector: "a.name",
doc: card
});
}
async filterDetailComments() {
const selector = {
commentListSelector: "div.vue-recycle-scroller__item-view",
commentUserSelector: "div.con1.woo-box-item-flex div.text a.ALink_default_2ibt1",
replyListSelector: "div.item2",
replyUserSelector: "div.con2 a.ALink_default_2ibt1"
};
this.removeElements([
newListAndUser(
selector.commentListSelector,
selector.commentUserSelector
),
newListAndUser(selector.replyListSelector, selector.replyUserSelector)
]);
this.injectButton({
listSelector: selector.commentListSelector,
userSelector: selector.commentUserSelector,
subListSelector: selector.replyListSelector,
subUserSelector: selector.replyUserSelector
});
}
async hideTrends() {
let trend = document.querySelector("div.main-side");
if (trend) trend.style.display = "none";
if (trend = document.querySelector("div.Main_side_i7Vti"))
trend.style.display = "none";
}
async createRetweetButton() {
this.removeElements([
newListAndUser(
"div.vue-recycle-scroller__item-view",
"div.retweet.Feed_retweet_JqZJb a.ALink_default_2ibt1"
)
]);
this.injectButton({
listSelector: "div.retweet.Feed_retweet_JqZJb",
userSelector: "a.ALink_default_2ibt1"
});
}
filterComments(comments) {
return comments.reduce((filtered, comment) => {
const myText = comment.text || "";
const ngWordInMyText = this.inBlackList(
{ name: comment.user?.screen_name },
myText
);
if (!ngWordInMyText) {
filtered.push(comment);
}
return filtered;
}, []);
}
filterStatuses(statuses) {
return statuses.reduce((acc, cur) => {
if (cur.user.following) {
const myText = cur.text || "";
const ngWordInMyText = this.inBlackList(
{ name: cur.user?.screen_name },
myText
);
if (!ngWordInMyText) {
if (cur.retweeted_status) {
const oriText = cur.retweeted_status.text || "";
const ngWordInOriText = this.inBlackList(
{ name: cur.retweeted_status?.user?.screen_name },
oriText
);
if (ngWordInOriText) return acc;
}
acc.push(cur);
}
}
return acc;
}, []);
}
filterSearchBand(searchBands) {
return searchBands.reduce((acc, cur) => {
if (!this.inBlackList({ name: "" }, cur.word)) {
acc.push(cur);
}
return acc;
}, []);
}
onFriendTimeline(url, res) {
if (url.includes("m.weibo.cn")) {
res = res;
res.data.statuses = this.filterStatuses(res.data.statuses);
} else {
res = res;
res.statuses = this.filterStatuses(res.statuses);
console.log(
`filtered url: ${url}, users: ${res.statuses.reduce((pre, cur) => {
pre.push(cur.user.screen_name);
return pre;
}, [])}`
);
}
}
onSearchBand(url, res) {
res.data.realtime = this.filterSearchBand(res.data.realtime);
}
onTrendsBand(url, res) {
res.data.list = [];
}
hook_buildComments(url, res) {
res.data = this.filterComments(res.data);
}
};
__publicField(WeiboFilter, "host", "weibo.com");
__decorateClass([
reqHook(/female_version|rum\/events/)
], WeiboFilter.prototype, "mockRequests", 1);
__decorateClass([
reqHook(/log\/read/)
], WeiboFilter.prototype, "interceptRead", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "filterSearchResults", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "filterFeeds", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "filterReplies", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "filterDetailComments", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "hideTrends", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "createRetweetButton", 1);
__decorateClass([
respHook(/friendstimeline/)
], WeiboFilter.prototype, "onFriendTimeline", 1);
__decorateClass([
respHook(/\/searchBand/)
], WeiboFilter.prototype, "onSearchBand", 1);
__decorateClass([
respHook(/getIndexBand/)
], WeiboFilter.prototype, "onTrendsBand", 1);
__decorateClass([
respHook(/\/buildComments/)
], WeiboFilter.prototype, "hook_buildComments", 1);
WeiboFilter = __decorateClass([
RegisterSubclass
], WeiboFilter);
// src/filters/hupu.ts
var HupuFilter = class extends WebsiteFilter {
async filterHupuComments() {
const selector = {
commentsSelector: "div.index_discuss-card__Nd4MK.hp-m-discuss-card.post-card",
userSelector: "p.discuss-card__user span.discuss-card__username",
repliesSelector: "div.index_discuss-card__Nd4MK.hp-m-discuss-card.discuss-card",
quotesSelector: "div.discuss-card__quote-container-quote",
quoteUserSelector: "div.discuss-card__quote-container-quote span.discuss-card__quote-container-discusser"
};
this.removeElements([
newListAndUser(selector.commentsSelector, selector.userSelector)
]);
this.injectButton({
listSelector: selector.commentsSelector,
userSelector: selector.userSelector
});
this.removeElements([
newListAndUser(selector.commentsSelector, selector.quoteUserSelector)
]);
this.injectButton({
listSelector: selector.quotesSelector,
userSelector: selector.quoteUserSelector
});
this.removeElements([
newListAndUser(selector.repliesSelector, selector.userSelector)
]);
this.injectButton({
listSelector: selector.repliesSelector,
userSelector: selector.userSelector
});
}
hupuRouter(url, res) {
function filterHupuReplies(replies) {
return replies.reduce((filtered, reply) => {
const user = reply.user.username;
if (!this.inBlackList({ name: user })) {
filtered.push(reply);
}
return filtered;
}, []);
}
res.data.replies = filterHupuReplies(res.data.replies);
}
};
__publicField(HupuFilter, "host", "hupu.com");
__decorateClass([
filterFunc
], HupuFilter.prototype, "filterHupuComments", 1);
__decorateClass([
respHook(/\/bbs-reply-detail/)
], HupuFilter.prototype, "hupuRouter", 1);
HupuFilter = __decorateClass([
RegisterSubclass
], HupuFilter);
// src/utils/time.ts
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// src/filters/tieba.ts
var TiebaFilter = class extends WebsiteFilter {
constructor() {
super();
this.hideLoginPopup();
}
async hideLoginPopup() {
let login = null;
while (!login) {
login = document.querySelector("div.tieba-custom-pass-login");
if (login) {
const ob = new MutationObserver((mutations) => {
const popup = document.querySelector("div.tieba-custom-pass-login");
const closeButton = document.querySelector("span.close-btn");
if (closeButton) {
closeButton.click();
} else {
popup.style.display = "none";
}
});
ob.observe(login, {
attributeFilter: ["style"],
subtree: true
});
break;
}
await sleep(10);
}
}
async filterTiebaThreadListComments() {
const selector = {
threadsSelector: "li.j_thread_list.clearfix.thread_item_box",
threadUserSelector: "span.tb_icon_author",
content: "div.col2_right.j_threadlist_li_right"
};
const contentFn = (element) => {
const title = element.querySelector(
"div.threadlist_abs.threadlist_abs_onlyline"
);
const preview = element.querySelector(
"div.threadlist_title.pull_left.j_th_tit"
);
return title?.textContent + preview?.textContent;
};
const fn = (user) => {
const field = user.dataset.field;
const id = JSON.parse(field)?.user_id;
return {
name: user.getAttribute("title")?.replace("\u4E3B\u9898\u4F5C\u8005: ", ""),
id
};
};
this.removeElements(
[
newListAndUser(
selector.threadsSelector,
selector.threadUserSelector,
selector.content
)
],
document,
fn,
contentFn
);
this.injectButton({
listSelector: selector.threadsSelector,
userSelector: selector.threadUserSelector,
nameFn: fn
});
}
async filterTiebaThreadComments() {
const selector = {
commentsSelector: "div.l_post.l_post_bright.j_l_post.clearfix",
commentUserSelector: "div.d_author li.d_name a.p_author_name.j_user_card",
commentContent: "div.p_content div.d_post_content.j_d_post_content",
repliesSelector: "div.j_lzl_c_b_a.core_reply_content li.lzl_single_post.j_lzl_s_p",
replyUserSelector: "div.lzl_cnt a.at.j_user_card",
replyContent: "div.lzl_cnt span.lzl_content_main"
};
this.removeElements([
newListAndUser(
selector.commentsSelector,
selector.commentUserSelector,
selector.commentContent
),
newListAndUser(
selector.repliesSelector,
selector.replyUserSelector,
selector.replyContent
)
]);
this.injectButton({
listSelector: selector.commentsSelector,
userSelector: selector.commentUserSelector,
subListSelector: selector.repliesSelector,
subUserSelector: selector.replyUserSelector
});
}
async hideRightBar() {
const rightBar = document.querySelector("div.right_section.right_bright");
if (!rightBar) {
return;
}
rightBar.parentNode.removeChild(rightBar);
}
filterTiebaReplies(data) {
const userMap = /* @__PURE__ */ new Map();
for (const user of Object.values(data.user_list)) {
userMap.set(user.user_nickname_v2, true);
}
const comments = data.comment_list;
data.comment_list = Object.entries(comments).reduce(
(filtered, [postId, comment]) => {
let replies = comment.comment_info;
replies = replies.filter(
(reply) => !this.inBlackList({ name: reply.show_nickname }, reply.content)
);
comment.comment_list_num = replies.length;
comment.comment_info = replies;
if (comment.comment_list_num > 0) {
filtered = {
...filtered,
[postId]: comment
};
}
return filtered;
},
{}
);
return data;
}
hookReplies(url, res) {
res.data = this.filterTiebaReplies(res.data);
}
hookTopicList(url, res) {
res.data.user_his_topic.topic_list = [];
res.data.sug_topic.topic_list = [];
res.data.bang_topic.topic_list = [];
res.data.manual_topic.topic_list = [];
}
hookSuggestion(url, res) {
res.hottopic_list.search_data = [];
res.query_tips.search_data = [];
}
};
__publicField(TiebaFilter, "host", "tieba.baidu.com");
__decorateClass([
filterFunc
], TiebaFilter.prototype, "hideLoginPopup", 1);
__decorateClass([
filterFunc
], TiebaFilter.prototype, "filterTiebaThreadListComments", 1);
__decorateClass([
filterFunc
], TiebaFilter.prototype, "filterTiebaThreadComments", 1);
__decorateClass([
filterFunc
], TiebaFilter.prototype, "hideRightBar", 1);
__decorateClass([
respHook(/\/p\/totalComment/)
], TiebaFilter.prototype, "hookReplies", 1);
__decorateClass([
respHook(/\/topicList/)
], TiebaFilter.prototype, "hookTopicList", 1);
__decorateClass([
respHook(/\/suggestion/)
], TiebaFilter.prototype, "hookSuggestion", 1);
TiebaFilter = __decorateClass([
RegisterSubclass
], TiebaFilter);
// src/filters/bilibili.ts
var BilibiliFilter = class extends WebsiteFilter {
render() {
super.render();
}
commentsButton(name, id) {
return createBlockButton({
name,
id,
css: ButtonCSSText,
listeners: [DomainStore.listener, this.render.bind(this)]
});
}
hoverButtonFunc(selector) {
return (element, user) => {
const wrapper = element.querySelector(selector);
if (element.querySelector(cssByCls(BlockButtonClass))) {
return;
}
const hoverButton = createBlockButton({
name: user.name,
id: user.id,
subclass: HoverButtonClass,
listeners: [DomainStore.listener, this.render.bind(this)]
});
wrapper.appendChild(hoverButton);
};
}
filterReplies(e) {
let replies = e.shadowRoot?.querySelector("div#replies")?.querySelector("bili-comment-replies-renderer")?.shadowRoot;
let replyRenderers = replies?.querySelectorAll(
"bili-comment-reply-renderer"
);
replyRenderers?.forEach((replyShadowRoot) => {
let reply = replyShadowRoot?.shadowRoot;
let replyUser = reply?.querySelector("bili-comment-user-info")?.shadowRoot?.querySelector("#user-name");
let name = replyUser?.textContent || "";
let id = replyUser?.getAttribute("data-user-profile-id") || "";
if (this.inBlackList({ name, id })) {
replyShadowRoot.parentElement?.removeChild(replyShadowRoot);
} else {
if (replyUser.parentNode.querySelector(cssByCls(BlockButtonClass))) {
return;
}
const button = this.commentsButton(name, id);
replyUser.parentNode.appendChild(button);
}
});
}
filterComments() {
const srw = document.querySelector(
"#comment > div > bili-comments"
)?.shadowRoot;
if (!srw) {
return;
}
const comments = srw.querySelectorAll(
"#feed > bili-comment-thread-renderer"
);
comments?.forEach((e) => {
this.filterReplies(e);
const comment = e.shadowRoot?.querySelector(
"bili-comment-renderer"
)?.shadowRoot;
let commentUser = comment?.querySelector(
"#header > bili-comment-user-info"
)?.shadowRoot;
const userInfo = commentUser.querySelector("#user-name");
const buttonWrapper = commentUser.querySelector("div#info");
let userName = userInfo?.textContent;
let userId = userInfo?.getAttribute("data-user-profile-id") || "";
if (this.inBlackList({ name: userName, id: userId })) {
e.parentNode.removeChild(e);
} else {
if (buttonWrapper.querySelector(cssByCls(BlockButtonClass))) {
return;
}
const button = this.commentsButton(userName, userId);
buttonWrapper.appendChild(button);
}
});
}
filterVideoList() {
const selector = {
videos: ".feed-card",
author: ".bili-video-card__info--owner",
title: ".bili-video-card__info--tit"
};
const nameFn = (element) => {
const author = element.querySelector(".bili-video-card__info--author");
const href = element.getAttribute("href");
return { name: author.textContent, id: href.split("/").at(-1) };
};
this.removeElements(
[newListAndUser(selector.videos, selector.author, selector.title)],
document,
nameFn
);
this.injectButton({
listSelector: selector.videos,
userSelector: selector.author,
elementButtonFunc: this.hoverButtonFunc(".bili-video-card__image--wrap"),
nameFn
});
}
filterVideoPlaylist() {
const selector = {
videos: ".video-page-card-small",
videoAuthor: ".upname a",
title: "div.info a p.title"
};
const nameFn = (element) => {
return {
name: element.querySelector("span.name").textContent,
id: element.getAttribute("href").split("/").at(-2)
};
};
this.removeElements(
[newListAndUser(selector.videos, selector.videoAuthor, selector.title)],
document,
nameFn
);
this.injectButton({
listSelector: selector.videos,
userSelector: selector.videoAuthor,
nameFn,
elementButtonFunc: this.hoverButtonFunc(".pic-box")
});
}
hookMain(url, res) {
return this.hookComments(url, res);
}
hookReplies(url, res) {
return this.hookComments(url, res);
}
hookComments(url, res) {
const filterReplyFunc = (reply) => {
const id = reply.mid_str;
const name = reply.member.uname;
const content = reply.content.message;
return !this.inBlackList({ name, id }, content);
};
let { replies } = res.data;
replies = replies.filter(filterReplyFunc);
replies.forEach((reply) => {
const subReplies = reply.replies;
reply.replies = subReplies.filter(filterReplyFunc);
});
res.data.replies = replies;
}
hookSearchVideo(url, res) {
res.data.result = res.data.result.filter((item) => {
const name = item.author;
const id = item.mid;
const desc = item.description;
return !this.inBlackList({ name, id }, desc);
});
}
hookSearchTrends(url, res) {
res.data.trending.list = [
{
keyword: "fsd",
show_name: "FSD",
icon: "http://i0.hdslb.com/bfs/activity-plat/static/20221213/eaf2dd702d7cc14d8d9511190245d057/lrx9rnKo24.png",
uri: "",
goto: ""
}
];
}
};
__publicField(BilibiliFilter, "host", "bilibili.com");
__decorateClass([
filterFunc
], BilibiliFilter.prototype, "filterComments", 1);
__decorateClass([
patternFilterFunc(/search\.bilibili\.com|bilibili\.com\/\?/)
], BilibiliFilter.prototype, "filterVideoList", 1);
__decorateClass([
patternFilterFunc(/com\/video\/\w+/)
], BilibiliFilter.prototype, "filterVideoPlaylist", 1);
__decorateClass([
respHook(/reply\/wbi\/main/)
], BilibiliFilter.prototype, "hookMain", 1);
__decorateClass([
respHook(/\/reply\/reply/)
], BilibiliFilter.prototype, "hookReplies", 1);
__decorateClass([
respHook(/search\/type/)
], BilibiliFilter.prototype, "hookSearchVideo", 1);
__decorateClass([
respHook(/search\/square/)
], BilibiliFilter.prototype, "hookSearchTrends", 1);
BilibiliFilter = __decorateClass([
RegisterSubclass
], BilibiliFilter);
// src/views/panel.ts
var MainView = class _MainView {
store;
filter;
static instance;
constructor() {
if (_MainView.instance) {
return _MainView.instance;
}
this.filter = WebsiteFilter.fromHost();
this.store = new DomainStore();
addStyle(css);
window.addEventListener("load", () => {
appObserverInit();
});
_MainView.instance = this;
}
static DialogSelector = ".my-dialog__wrapper";
dialogElement() {
return document.querySelector(_MainView.DialogSelector);
}
freshPage() {
this.filter.render();
}
render() {
setInterval(() => {
this.renderSettingButton();
this.renderSettingPanel();
this.filter.render();
}, 1e3);
}
/* 生成添加屏蔽关键词的按钮 */
async renderSettingButton() {
if (!document.body) {
return;
}
if (document.body.querySelector("#add_ngList_btn")) {
return;
}
const btn = document.createElement("div");
btn.title = "\u6DFB\u52A0\u5C4F\u853D\u5173\u952E\u8BCD";
const span = document.createElement("span");
span.innerText = "";
btn.appendChild(span);
btn.id = "add_ngList_btn";
document.body.appendChild(btn);
btn.addEventListener("click", () => {
this.renderBlockedUsers();
this.showDialog();
});
}
async renderSettingPanel() {
const dialogTemplate = `
<div class="my-dialog" style="margin-top: 15vh; width: 40%;">
<div class="my-dialog__header">
<span class="my-dialog__title">\u5C4F\u853D\u8BCD\u5217\u8868</span>
<button type="button" aria-label="Close" class="my-dialog__headerbtn">
<i class="my-dialog__close"></i>
</button>
</div>
<div class="my-dialog__body">
<div class="input_container">
<div class="el-input">
<input id="ngWord_input" class="el-input__inner" type="text" />
</div>
<button type="button" class="el-button" id="add_btn">
<span>\u6DFB\u52A0</span>
</button>
</div>
<div id="ngList"></div>
<p class="tips">\u6CE8\uFF1A1. \u53EF\u8FC7\u6EE4\u5305\u542B\u5C4F\u853D\u8BCD\u7684\u7528\u6237\u3001\u5FAE\u535A\u3001\u8BC4\u8BBA\u3001\u70ED\u641C\u3002 2. \u5173\u952E\u8BCD\u4FDD\u5B58\u5728\u672C\u5730\u7684local storage\u4E2D\u3002 3. \u66F4\u6539\u5173\u952E\u8BCD\u540E\u5237\u65B0\u9875\u9762\u751F\u6548\uFF08\u4E0D\u5237\u65B0\u9875\u9762\u7684\u60C5\u51B5\u4E0B\uFF0C\u53EA\u6709\u4E4B\u540E\u52A0\u8F7D\u7684\u5FAE\u535A\u624D\u4F1A\u751F\u6548\uFF09\u3002</p>
</div>
<div class="my-dialog__footer"></div>
</div>
`;
if (!document.body) {
return;
}
if (document.body.querySelector(".my-dialog__wrapper")) {
return;
}
const wrapper = document.createElement("div");
wrapper.classList.add("my-dialog__wrapper");
wrapper.innerHTML = dialogTemplate;
document.body.appendChild(wrapper);
document.querySelector(".my-dialog__headerbtn").addEventListener("click", () => {
this.hideDialog();
});
document.querySelector("#add_btn").addEventListener("click", () => {
const ngWord_input = document.querySelector(
"#ngWord_input"
);
if (ngWord_input && ngWord_input.value) {
this.store.addPattern(ngWord_input.value);
ngWord_input.value = "";
this.renderBlockedUsers();
}
});
}
showDialog() {
this.dialogElement().style.display = "initial";
}
hideDialog() {
this.dialogElement().style.display = "none";
}
renderBlockedUsers() {
let blockedUsersHTML = "";
const users = [...this.store.userList];
for (const [i, pattern] of this.store.patternList.reverse().entries()) {
blockedUsersHTML += `<span class="ng_pattern" data-type="pattern">${pattern}<i class="close-icon" data-index=${i}></i></span>`;
}
for (const [i, item] of users.reverse().entries()) {
blockedUsersHTML += `<span class="ng_item" data-type="user">${item}<i class="close-icon" data-index=${i}></i></span>`;
}
const ngListNode = document.querySelector("#ngList");
if (ngListNode) {
ngListNode.innerHTML = blockedUsersHTML;
const buttons = ngListNode.querySelectorAll(".close-icon");
for (const button of buttons) {
button.addEventListener("click", () => {
const name = button.parentNode.textContent;
const type = button.parentElement.dataset.type;
switch (type) {
case "user":
this.store.removeUser({ name, id: name });
break;
case "pattern":
this.store.removePattern(name);
break;
}
this.renderBlockedUsers();
});
}
}
}
};
function appObserverInit() {
const targetNode = document.getElementById("app");
if (!targetNode) {
return;
}
const config = {
childList: true,
subtree: true
};
const callback = function() {
const audioList = document.querySelectorAll(".AfterPatch_bg_34rqc");
for (const audio of audioList) {
audio.remove();
console.log("\u79FB\u9664\u4E86\u5F31\u667A\u4E09\u8FDE");
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
}
// src/main.ts
async function main() {
await DomainStore.init();
const controller = new MainView();
controller.render();
}
main();
})();