// ==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.16
// @author no one
// @description 屏蔽特定用户的帖子和评论
// @description:zh 屏蔽特定用户的帖子和评论
// @require https://update.greasyfork.org/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;
storeKey = "name";
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(key = "name") {
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, key);
}
nameMap = /* @__PURE__ */ new Map();
idMap = /* @__PURE__ */ 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 (this.storeKey === "name") {
return this.nameMap.has(name.trim());
} else if (this.storeKey === "id") {
return this.idMap.has(id.toString().trim());
}
}
addUser({ name, id }) {
name = name.trim();
const user = { name, id, blockedDate: /* @__PURE__ */ new Date() };
if (this.storeKey === "name") this.nameMap.set(name, user);
if (this.storeKey === "id") this.idMap.set(id, user);
this.flush();
}
removeUser({ name, id }) {
if (this.storeKey === "name") this.nameMap.delete(name.trim());
if (this.storeKey === "id") this.idMap.delete(id.toString().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, key = "name") {
if (_DomainStore.singleton) {
return _DomainStore.singleton;
}
for (const user of users) {
switch (key) {
case "id":
this.idMap.set(user.id, user);
break;
case "name":
this.nameMap.set(user.name, user);
break;
}
}
this.storeKey = key;
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 [];
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: inherit;
#color: transparent;
mix-blend-mode: difference;
border-width: 0;
padding: 0;
display: inline-block;
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(50);
transition: filter 0.1s linear 0.1s;
}
.${HoverButtonClass} {
background-color: #fff;
background-color: rgba(255,255,255,0.2);
height: 16px;
width: 16px;
filter: opacity(5);
z-index: 10;
position: absolute;
top: 12px;
left: 12px;
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,
eid
}) {
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);
wrapper.setAttribute("button-id", eid);
if (css2) {
const style = document.createElement("style");
style.textContent = css2;
wrapper.appendChild(style);
}
wrapper.addEventListener("click", (ev) => {
ev.preventDefault();
ev.stopPropagation();
const element = ev.currentTarget;
const user = {
name: element.getAttribute("user-name"),
id: element.getAttribute("user-id")
};
if (typeof listeners === "function") {
listeners(user);
} else {
listeners.forEach((listener) => {
listener(user);
});
}
});
return wrapper;
}
function addStyle(cssStyle) {
if (!cssStyle) return;
const head = document.querySelector("head");
const style = document.createElement("style");
const ttwindow = window;
if (ttwindow.trustedTypes) {
const policy = ttwindow.trustedTypes.createPolicy("default", {
createHTML: (html) => html.replace(/</g, "<")
});
style.innerHTML = policy.createHTML(cssStyle).toString();
} else {
style.innerHTML = cssStyle;
}
head?.appendChild(style);
}
// src/views/panel.ts
var MainView = class _MainView {
store;
filter;
static instance;
constructor(filter) {
if (_MainView.instance) {
return _MainView.instance;
}
this.filter = filter;
this.store = new DomainStore();
addStyle(css);
window.addEventListener("load", () => {
appObserverInit();
});
_MainView.instance = this;
}
static DialogSelector = ".my-dialog__wrapper";
dialogElement() {
return document.querySelector(_MainView.DialogSelector);
}
render() {
this.filter.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">
<textarea id="ngWord_input" style="line-height: 14px" placeholder="\u6279\u91CF\u8F93\u5165\uFF0C\u6BCF\u884C\u4E00\u4E2A" class="el-input__inner"></textarea>
</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) {
const values = ngWord_input.value.trim().split("\n");
for (const v of values) {
this.store.addPattern(v);
}
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();
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
}
// src/utils/encoding.ts
function md5cycle(x, k) {
let a = x[0];
let b = x[1];
let c = x[2];
let d = x[3];
a = ff(a, b, c, d, k[0], 7, -680876936);
d = ff(d, a, b, c, k[1], 12, -389564586);
c = ff(c, d, a, b, k[2], 17, 606105819);
b = ff(b, c, d, a, k[3], 22, -1044525330);
a = ff(a, b, c, d, k[4], 7, -176418897);
d = ff(d, a, b, c, k[5], 12, 1200080426);
c = ff(c, d, a, b, k[6], 17, -1473231341);
b = ff(b, c, d, a, k[7], 22, -45705983);
a = ff(a, b, c, d, k[8], 7, 1770035416);
d = ff(d, a, b, c, k[9], 12, -1958414417);
c = ff(c, d, a, b, k[10], 17, -42063);
b = ff(b, c, d, a, k[11], 22, -1990404162);
a = ff(a, b, c, d, k[12], 7, 1804603682);
d = ff(d, a, b, c, k[13], 12, -40341101);
c = ff(c, d, a, b, k[14], 17, -1502002290);
b = ff(b, c, d, a, k[15], 22, 1236535329);
a = gg(a, b, c, d, k[1], 5, -165796510);
d = gg(d, a, b, c, k[6], 9, -1069501632);
c = gg(c, d, a, b, k[11], 14, 643717713);
b = gg(b, c, d, a, k[0], 20, -373897302);
a = gg(a, b, c, d, k[5], 5, -701558691);
d = gg(d, a, b, c, k[10], 9, 38016083);
c = gg(c, d, a, b, k[15], 14, -660478335);
b = gg(b, c, d, a, k[4], 20, -405537848);
a = gg(a, b, c, d, k[9], 5, 568446438);
d = gg(d, a, b, c, k[14], 9, -1019803690);
c = gg(c, d, a, b, k[3], 14, -187363961);
b = gg(b, c, d, a, k[8], 20, 1163531501);
a = gg(a, b, c, d, k[13], 5, -1444681467);
d = gg(d, a, b, c, k[2], 9, -51403784);
c = gg(c, d, a, b, k[7], 14, 1735328473);
b = gg(b, c, d, a, k[12], 20, -1926607734);
a = hh(a, b, c, d, k[5], 4, -378558);
d = hh(d, a, b, c, k[8], 11, -2022574463);
c = hh(c, d, a, b, k[11], 16, 1839030562);
b = hh(b, c, d, a, k[14], 23, -35309556);
a = hh(a, b, c, d, k[1], 4, -1530992060);
d = hh(d, a, b, c, k[4], 11, 1272893353);
c = hh(c, d, a, b, k[7], 16, -155497632);
b = hh(b, c, d, a, k[10], 23, -1094730640);
a = hh(a, b, c, d, k[13], 4, 681279174);
d = hh(d, a, b, c, k[0], 11, -358537222);
c = hh(c, d, a, b, k[3], 16, -722521979);
b = hh(b, c, d, a, k[6], 23, 76029189);
a = hh(a, b, c, d, k[9], 4, -640364487);
d = hh(d, a, b, c, k[12], 11, -421815835);
c = hh(c, d, a, b, k[15], 16, 530742520);
b = hh(b, c, d, a, k[2], 23, -995338651);
a = ii(a, b, c, d, k[0], 6, -198630844);
d = ii(d, a, b, c, k[7], 10, 1126891415);
c = ii(c, d, a, b, k[14], 15, -1416354905);
b = ii(b, c, d, a, k[5], 21, -57434055);
a = ii(a, b, c, d, k[12], 6, 1700485571);
d = ii(d, a, b, c, k[3], 10, -1894986606);
c = ii(c, d, a, b, k[10], 15, -1051523);
b = ii(b, c, d, a, k[1], 21, -2054922799);
a = ii(a, b, c, d, k[8], 6, 1873313359);
d = ii(d, a, b, c, k[15], 10, -30611744);
c = ii(c, d, a, b, k[6], 15, -1560198380);
b = ii(b, c, d, a, k[13], 21, 1309151649);
a = ii(a, b, c, d, k[4], 6, -145523070);
d = ii(d, a, b, c, k[11], 10, -1120210379);
c = ii(c, d, a, b, k[2], 15, 718787259);
b = ii(b, c, d, a, k[9], 21, -343485551);
x[0] = add32(a, x[0]);
x[1] = add32(b, x[1]);
x[2] = add32(c, x[2]);
x[3] = add32(d, x[3]);
}
function cmn(q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32(a << s | a >>> 32 - s, b);
}
function ff(a, b, c, d, x, s, t) {
return cmn(b & c | ~b & d, a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t) {
return cmn(b & d | c & ~d, a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t) {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t) {
return cmn(c ^ (b | ~d), a, b, x, s, t);
}
function md51(s) {
let txt = "";
let n = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i;
for (i = 64; i <= s.length; i += 64) {
md5cycle(state, md5blk(s.substring(i - 64, i)));
}
s = s.substring(i - 64);
let tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < s.length; i++)
tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
tail[i >> 2] |= 128 << (i % 4 << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i++) tail[i] = 0;
}
tail[14] = n * 8;
md5cycle(state, tail);
return state;
}
function md5blk(s) {
let md5blks = [], i;
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
}
return md5blks;
}
var hex_chr = "0123456789abcdef".split("");
function rhex(n) {
let s = "", j = 0;
for (; j < 4; j++)
s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
return s;
}
function hex(x) {
for (let i = 0; i < x.length; i++) x[i] = rhex(x[i]);
return x.join("");
}
function add32(a, b) {
return a + b & 4294967295;
}
function md5(s) {
return hex(md51(s));
}
// src/utils/middleman.ts
var middleman_default = middleMan;
// src/filters/base.ts
var defaultWrapperFunc = (userNode, root) => {
while (userNode && userNode.parentNode !== root) {
if (userNode.parentNode.childElementCount > 1) {
return userNode.parentNode;
}
userNode = userNode.parentNode;
}
return userNode.parentNode;
};
var defaultNameFn = (elem) => {
const href = elem.getAttribute("href");
const id = href?.split("/").at(-1);
let name = elem?.textContent || elem?.getAttribute("aria-label");
name = name.trim().replace(/^@/, "").replace("\uFF1A", "").trim();
return {
name,
id
};
};
var defaultContentFn = (elem) => {
return elem ? elem.textContent : "";
};
function locator(list, user, content, wrapper) {
return {
l: list,
u: user,
c: content ? content : "",
w: wrapper
};
}
function RegisterSubclass(target) {
WebsiteFilter.registerClass(target);
}
var WebsiteFilter = class _WebsiteFilter {
static filterKey = "name";
hardDelete = false;
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 cls;
}
}
}
renderers = [];
proxyOpt = {
requestRouters: [],
responseRouters: []
};
registered = false;
modifyDom({
locators,
elementButtonFunc,
doc = document,
nameFn = defaultNameFn,
contentFn = defaultContentFn
}) {
this.injectButton({
locators,
elementButtonFunc,
doc,
nameFn
});
this.removeElements(locators, doc, nameFn, contentFn);
}
injectButton({
locators,
elementButtonFunc,
doc = document,
nameFn = defaultNameFn
}) {
if (locators.length < 1) {
return;
}
const l = locators[0];
const list = doc.querySelectorAll(l.l);
const buttonID = md5(l.l + l.u).slice(0, 8);
list.forEach((element) => {
(() => {
let ue = element.querySelector(l.u);
if (!ue) {
return;
}
const user = nameFn(ue);
if (!elementButtonFunc)
elementButtonFunc = this.defaultButtonFunc.bind(this);
const btn = elementButtonFunc({ element, user, eid: buttonID });
if (btn === void 0) {
return;
}
let buttonWrapper = l.w;
if (!buttonWrapper) {
buttonWrapper = defaultWrapperFunc;
}
let wrapper;
if (typeof buttonWrapper === "function") {
wrapper = buttonWrapper(ue, element);
} else {
wrapper = element.querySelector(buttonWrapper);
}
wrapper.appendChild(btn);
})();
this.injectButton({
locators: locators.slice(1),
elementButtonFunc,
doc: element,
nameFn
});
});
}
removeElements(selectors, root = document, nameFn = defaultNameFn, contentFn = defaultContentFn) {
if (selectors.length < 1) {
return;
}
const selector = selectors[0];
const list = root.querySelectorAll(selector.l);
list.forEach((element) => {
if (element.style.display === "none") {
return;
}
const user = element.querySelector(selector.u);
if (!user) {
return;
}
let content;
if (selector.c) {
const contentElement = element.querySelector(selector.c);
content = contentFn(contentElement);
} else {
content = "";
}
if (nameFn === void 0) nameFn = defaultNameFn;
const poster = nameFn(user);
if (this.inBlackList(poster, content)) {
if (this.hardDelete) {
element?.parentNode?.removeChild(element);
} else {
element.style.display = "none";
}
} else {
this.removeElements(selectors.slice(1), element, nameFn, contentFn);
}
});
}
inBlackList(name, content = "") {
const store = new DomainStore();
const blocked = store.hasUser(name) || store.matchPattern(content);
if (blocked) {
}
return blocked;
}
registerHooks() {
if (!this.registered) {
const opt = this.proxyOpt;
opt.requestRouters.forEach((router) => {
middleman_default.addHook(router.hookMeta.pattern, this.requestHandler(router));
});
opt.responseRouters.forEach((router) => {
middleman_default.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);
}
};
}
defaultButtonFunc({ element, user, eid }) {
if (element.querySelector(`${cssByCls(BlockButtonClass)}[button-id="${eid}"]`)) {
return;
}
const { name, id } = user;
return createBlockButton({
name,
id,
listeners: [DomainStore.listener, this.render.bind(this)],
eid
});
}
render() {
this.renderers.forEach((f) => {
if (typeof f.filterMeta === "boolean") {
f();
} else {
const href = document.location.href;
if (f.filterMeta.pattern.exec(href)) {
f();
}
}
});
}
};
function filterFunc(target, name, descriptor) {
const fn = descriptor.value;
fn.filterMeta = true;
}
function patternFilterFunc(pattern, once = false) {
return (target, name, descriptor) => {
descriptor.value.filterMeta = { pattern, once };
};
}
function HookDecorator(type) {
return (pattern) => {
return (target, name, descriptor) => {
descriptor.value.hookMeta = {
type,
pattern
};
};
};
}
var reqHook = HookDecorator("request");
var respHook = HookDecorator("response");
// src/filters/bilibili.ts
var BilibiliFilter = class extends WebsiteFilter {
render() {
super.render();
}
commentsButton(parent, name, id, eid) {
let button;
if (button = parent.querySelector(
`${cssByCls(BlockButtonClass)}[button-id="${eid}"]`
)) {
button.setAttribute("user-name", name);
button.setAttribute("user-id", id);
return;
}
return createBlockButton({
name,
id,
css: ButtonCSSText,
listeners: [DomainStore.listener, this.render.bind(this)],
eid
});
}
hoverButtonFunc({ element, user, eid }) {
if (element.querySelector(`${cssByCls(BlockButtonClass)}[button-id="${eid}"]`)) {
return;
}
return createBlockButton({
name: user.name,
id: user.id,
subclass: HoverButtonClass,
listeners: [DomainStore.listener, this.render.bind(this)],
eid
});
}
filterReplies(e) {
let replies = e.shadowRoot?.querySelector("div#replies")?.querySelector("bili-comment-replies-renderer")?.shadowRoot;
let replyRenderers = replies?.querySelectorAll(
"bili-comment-reply-renderer"
);
const eid = "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 {
const button = this.commentsButton(replyUser.parentNode, name, id, eid);
if (!button) {
return;
}
replyUser.parentNode.appendChild(button);
}
});
}
filterComments() {
const srw = document.querySelector("bili-comments")?.shadowRoot;
if (!srw) {
return;
}
const comments = srw.querySelectorAll(
"#feed > bili-comment-thread-renderer"
);
const eid = "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");
const commentContents = comment?.querySelector(
"#content > bili-rich-text"
)?.shadowRoot;
const contents = commentContents.querySelector("#contents").textContent;
let userName = userInfo?.textContent;
let userId = userInfo?.getAttribute("data-user-profile-id") || "";
if (this.inBlackList({ name: userName, id: userId }, contents)) {
e.parentNode.removeChild(e);
} else {
const button = this.commentsButton(
buttonWrapper,
userName,
userId,
eid
);
if (!button) {
return;
}
buttonWrapper.appendChild(button);
}
});
}
filterVideoSearch() {
const selector = {
videos: ".col_3.col_xs_1_5.col_md_2.col_xl_1_7.mb_x40",
author: ".bili-video-card__info--owner",
title: ".bili-video-card__info--tit"
};
this.filterVideoCards(
locator(selector.videos, selector.author, selector.title),
this.hoverButtonFunc.bind(this)
);
}
filterVideoCards(l, buttonFunc) {
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) };
};
l.w = ".bili-video-card__image--wrap";
this.modifyDom({
locators: [l],
nameFn,
elementButtonFunc: buttonFunc
});
}
filterVideoList() {
const selector = {
l: ".feed-card",
u: ".bili-video-card__info--owner",
c: ".bili-video-card__info--tit"
};
this.filterVideoCards(selector, this.hoverButtonFunc.bind(this));
const videoCards = selector;
videoCards.l = ".bili-video-card";
this.filterVideoCards(videoCards, this.hoverButtonFunc.bind(this));
}
filterVideoPlaylist() {
const videos = {
l: ".video-page-card-small",
u: ".upname a",
c: "div.info a p.title",
w: "div.playinfo"
};
const nameFn = (element) => {
return {
name: element.querySelector("span.name").textContent,
id: element.getAttribute("href").split("/").at(-2)
};
};
this.removeElements([videos], document, nameFn);
setTimeout(() => {
this.injectButton({
locators: [videos],
nameFn
// elementButtonFunc: this.hoverButtonFunc.bind(this),
});
}, 5e3);
}
hookMain(url, res) {
return this.hookComments(url, res);
}
hookReplies(url, res) {
return this.hookComments(url, res);
}
hookRecommends(url, res) {
const cards = res.data.item;
res.data.item = cards.filter((card) => {
const { mid, name } = card.owner;
const title = card.title;
const keep = !this.inBlackList({ name, id: mid }, title);
if (!keep) {
}
return keep;
});
}
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([
patternFilterFunc(/com\/video\/\w+/)
], BilibiliFilter.prototype, "filterComments", 1);
__decorateClass([
patternFilterFunc(/search\.bilibili\.com/)
], BilibiliFilter.prototype, "filterVideoSearch", 1);
__decorateClass([
filterFunc
], BilibiliFilter.prototype, "filterVideoList", 1);
__decorateClass([
patternFilterFunc(/com\/video\/\w+/, true)
], BilibiliFilter.prototype, "filterVideoPlaylist", 1);
__decorateClass([
respHook(/reply\/wbi\/main/)
], BilibiliFilter.prototype, "hookMain", 1);
__decorateClass([
respHook(/\/reply\/reply/)
], BilibiliFilter.prototype, "hookReplies", 1);
__decorateClass([
respHook(/top\/feed\/rcmd/)
], BilibiliFilter.prototype, "hookRecommends", 1);
__decorateClass([
respHook(/search\/type/)
], BilibiliFilter.prototype, "hookSearchVideo", 1);
__decorateClass([
respHook(/search\/square/)
], BilibiliFilter.prototype, "hookSearchTrends", 1);
BilibiliFilter = __decorateClass([
RegisterSubclass
], BilibiliFilter);
// src/utils/time.ts
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// src/filters/hupu.ts
var HupuFilter = class extends WebsiteFilter {
constructor() {
super();
this.hideKOL();
}
async hideKOL() {
if (document.location.href.match(/com\/gg$/)) {
while (!document.querySelector(".gg-filters__item:nth-child(1)")) {
await sleep(10);
}
const lol = document.querySelector(
".gg-filters__item:nth-child(2)"
);
lol.click();
const kol = document.querySelector(
".gg-filters__item:nth-child(1)"
);
if (kol.style.display !== "none") {
kol.style.display = "none";
}
}
}
async filterZone() {
const posts = {
l: "div.exposure",
u: "h6.post-header span",
c: "p.post-body",
w: "h6.post-header"
};
this.modifyDom({
locators: [posts]
});
}
async updateHrefTarget() {
const items = document.querySelectorAll("a.news-item:not([target])");
for (const item of items) {
item.setAttribute("target", "_blank");
}
}
async filterPosts() {
const contentFunc = (element) => {
const title = element.querySelector(
"p.bbs-header-title.hupu-font-title1"
);
const content = element.querySelector(
"div.bbs-content-font.hupu-font-body5"
);
return title.textContent + content.textContent;
};
const posts = {
l: ".post-detail_post-detail-wrapper__yB_pb",
u: "p.first-line-user-info a span",
c: ".hupu-bbs-post"
};
this.modifyDom({
locators: [posts],
contentFn: contentFunc
});
}
async filterHupuComments() {
const comments = {
l: "div.index_discuss-card__Nd4MK.hp-m-discuss-card.post-card",
u: "p.discuss-card__user span.discuss-card__username",
c: "p.discuss-card__content",
w: "p.discuss-card__user"
};
const replies = {
l: "div.index_discuss-card__Nd4MK.hp-m-discuss-card.discuss-card",
u: comments.u,
c: comments.c,
w: comments.w
};
const quotes = {
// l: "div.discuss-card__quote-container-quote",
l: comments.l,
u: "div.discuss-card__quote-container-quote span.discuss-card__quote-container-discusser",
c: "span.discuss-card__quote-content",
w: ".discuss-card__quote-container-discusser"
};
const wrapper = "p.discuss-card__user";
this.modifyDom({
locators: [comments]
});
this.modifyDom({
locators: [quotes]
});
this.modifyDom({ locators: [replies] });
}
filterHupuReplies(replies) {
return replies.reduce((filtered, reply) => {
const user = reply.user.username;
const content = reply.content;
if (!this.inBlackList({ name: user }, content)) {
filtered.push(reply);
}
return filtered;
}, []);
}
hupuRouter(url, res) {
res.data.replies = this.filterHupuReplies(res.data.replies);
}
};
__publicField(HupuFilter, "host", "hupu.com");
__decorateClass([
patternFilterFunc(/zone\/\d+/)
], HupuFilter.prototype, "filterZone", 1);
__decorateClass([
patternFilterFunc(/com\/\w+$/)
], HupuFilter.prototype, "updateHrefTarget", 1);
__decorateClass([
patternFilterFunc(/bbs\/\d+/)
], HupuFilter.prototype, "filterPosts", 1);
__decorateClass([
filterFunc
], HupuFilter.prototype, "filterHupuComments", 1);
__decorateClass([
respHook(/\/bbs-reply-detail/)
], HupuFilter.prototype, "hupuRouter", 1);
HupuFilter = __decorateClass([
RegisterSubclass
], HupuFilter);
// 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 threads = {
l: "li.j_thread_list.clearfix.thread_item_box",
u: "span.tb_icon_author",
c: "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.querySelector("span.frs-author-name-wrap a").textContent,
id
};
};
this.modifyDom({
locators: [threads],
nameFn: fn,
contentFn
});
}
async filterTiebaThreadComments() {
const selector = {};
const comments = {
// l: "div.l_post.l_post_bright.j_l_post.clearfix",
l: "div.l_post",
u: "div.d_author li.d_name",
c: "div.p_content div.d_post_content.j_d_post_content",
w: "li.d_name"
};
const replies = {
l: "div.j_lzl_c_b_a.core_reply_content li.lzl_single_post.j_lzl_s_p",
u: "div.lzl_cnt a.at.j_user_card",
c: "div.lzl_cnt span.lzl_content_main",
w: ".lzl_content_main"
};
const nameFn = (element) => {
let user;
try {
user = defaultNameFn(element);
} catch (e) {
const id = JSON.parse(element.dataset.field).user_id;
user = { name: id, id };
}
return user;
};
this.modifyDom({
locators: [comments, replies],
nameFn
});
}
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([
patternFilterFunc(/com\/f/)
], TiebaFilter.prototype, "filterTiebaThreadListComments", 1);
__decorateClass([
patternFilterFunc(/p\/\d+/)
], 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/twitter.ts
var Twitter = class extends WebsiteFilter {
async blockShortcut() {
const buttons = document.querySelectorAll('button[aria-label="More"]');
buttons.forEach((e) => {
const wrapper = document.querySelector(
".css-175oi2r.r-k4xj1c.r-18u37iz.r-1wtj0ep"
);
if (wrapper.querySelector(cssByCls(BlockButtonClass)) !== null) {
return;
}
const listener = async (ev) => {
ev.stopPropagation();
e.click();
await sleep(200);
let blockButton = document.querySelector(
'div[data-testid="block"]'
);
if (!blockButton) {
return;
}
blockButton.click();
};
const shortcut = createBlockButton({
name: "",
id: "",
eid: "",
listeners: listener
});
wrapper.appendChild(shortcut);
});
}
};
__publicField(Twitter, "host", "x.com");
__decorateClass([
filterFunc
], Twitter.prototype, "blockShortcut", 1);
Twitter = __decorateClass([
RegisterSubclass
], Twitter);
// 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.hardDelete = true;
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",
commentWrapper: "div.content div.txt"
};
const cards = {
l: selector.cards,
u: selector.cardUser,
c: selector.cardContent
};
const comments = {
l: selector.comments,
u: selector.commentUser,
c: selector.commentContent,
w: selector.commentWrapper
};
const retweets = {
l: selector.retweetedCards,
u: selector.retweetedCardUser
};
this.modifyDom({
locators: [cards, comments]
});
this.modifyDom({
locators: [retweets, { l: cards.l, u: retweets.u }]
});
}
async filterFeeds() {
const cards = {
l: "div.vue-recycle-scroller__item-view",
u: "div.Feed_body_3R0rO a.ALink_default_2ibt1"
};
const comments = {
l: "div.wbpro-list",
u: "div.con1.woo-box-item-flex div.text a.ALink_default_2ibt1"
};
const replies = {
l: "div.item2",
u: "div.con2 a.ALink_default_2ibt1"
};
this.modifyDom({
locators: [cards, comments, replies]
});
}
async filterReplies() {
const reply = document.querySelector("div.ReplyModal_scroll3_2kADQ");
if (!reply) {
return;
}
const comments = {
l: "div.wbpro-list",
u: "div.con1.woo-box-item-flex a.ALink_default_2ibt1"
};
const replies = {
l: "div.vue-recycle-scroller__item-view",
u: "div.con2 a.ALink_default_2ibt1"
};
this.modifyDom({
locators: [comments, replies],
doc: reply
});
}
async filterDetailComments() {
const comments = {
l: "div.vue-recycle-scroller__item-view",
u: "div.con1.woo-box-item-flex div.text a.ALink_default_2ibt1"
};
const replies = { l: "div.item2", u: "div.con2 a.ALink_default_2ibt1" };
this.modifyDom({
locators: [comments, replies]
});
}
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([
locator(
"div.vue-recycle-scroller__item-view",
"div.retweet.Feed_retweet_JqZJb a.ALink_default_2ibt1"
)
]);
this.injectButton({
locators: [
{ l: "div.retweet.Feed_retweet_JqZJb", u: "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);
}
}
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([
patternFilterFunc(/s\.weibo\.com/)
], WeiboFilter.prototype, "filterSearchResults", 1);
__decorateClass([
filterFunc
], WeiboFilter.prototype, "filterFeeds", 1);
__decorateClass([
patternFilterFunc(/weibo\.com\/\d+\//)
], WeiboFilter.prototype, "filterReplies", 1);
__decorateClass([
patternFilterFunc(/weibo\.com\/\d+/)
], 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/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 = {};
const comments = {
l: "div.css-18ld3w0 > div[data-id]",
u: "div.css-jp43l4 a.css-10u695f",
c: "div.css-jp43l4 div.CommentContent.css-1jpzztt"
};
const replies = {
l: "div[data-id]",
u: "a.css-10u695f",
c: "div.CommentContent.css-1jpzztt"
};
this.modifyDom({
locators: [comments, replies],
nameFn: userFunc,
contentFn: ZhihuFilter.contentFunc
});
}
static contentFunc(element) {
return element ? element.textContent + element.querySelector("img")?.getAttribute("alt") : "";
}
async filterAnswerComments() {
const selector = {
l: "div.css-16zdamy div[data-id]",
u: "div.css-1tww9qq a.css-10u695f",
c: "div.CommentContent.css-1jpzztt"
};
this.modifyDom({
locators: [selector],
nameFn: userFunc,
contentFn: ZhihuFilter.contentFunc
});
}
async filterSearch() {
const answers = {
l: "div.Card.SearchResult-Card",
u: "b[data-first-child]",
w: "h2.ContentItem-title"
};
this.modifyDom({
locators: [answers],
elementButtonFunc: ({ element, user, eid }) => {
const btn = this.defaultButtonFunc({ element, user, eid });
if (!btn) {
return;
}
btn.style.display = "inline-block";
return btn;
}
});
}
async filterAnswers() {
const cards = {
l: "div.Card.AnswerCard.css-0",
u: "div.ContentItem.AnswerItem",
c: ".RichText.ztext.CopyrightRichText-richText.css-1ygg4xu",
w: "div.AuthorInfo.AnswerItem-authorInfo.AnswerItem-authorInfo--related div.AuthorInfo"
};
this.modifyDom({
locators: [cards],
nameFn: feedUserFunc
});
const answers = {
l: "div.List-item",
u: "div.ContentItem.AnswerItem",
c: cards.c,
w: cards.w
};
this.modifyDom({
locators: [answers],
nameFn: feedUserFunc
});
}
async filterRecommends() {
const selector = {};
const cards = {
l: "div.Card.TopstoryItem.TopstoryItem-isRecommend",
u: "div.ContentItem.AnswerItem",
c: "h2 div a",
w: "h2 div"
};
this.modifyDom({
locators: [cards],
nameFn: feedUserFunc,
elementButtonFunc: ({ element, user, eid }) => {
const btn = this.defaultButtonFunc({ element, user, eid });
if (!btn) {
return;
}
btn.style.display = "inline-block";
return btn;
}
});
}
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 + answer.target.title ? answer.target.title : answer.target.question.title;
return !this.inBlackList({ name, id }, content);
});
}
hookRecommends(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 + answer.target.title ? answer.target.title : answer.target.question.title;
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([
patternFilterFunc(/zhihu\.com\/search/)
], ZhihuFilter.prototype, "filterSearch", 1);
__decorateClass([
patternFilterFunc(/question\/\d+/)
], ZhihuFilter.prototype, "filterAnswers", 1);
__decorateClass([
patternFilterFunc(/zhihu\.com\/$/)
], ZhihuFilter.prototype, "filterRecommends", 1);
__decorateClass([
respHook(/\/root_comment|\/child_comment/)
], ZhihuFilter.prototype, "hookComments", 1);
__decorateClass([
respHook(/questions\/\d+\/feeds/)
], ZhihuFilter.prototype, "hookAnswers", 1);
__decorateClass([
respHook(/feed\/topstory\/recommend/)
], ZhihuFilter.prototype, "hookRecommends", 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/main.ts
async function main() {
const filterClass = WebsiteFilter.fromHost();
await DomainStore.init(filterClass.filterKey);
const controller = new MainView(new filterClass());
controller.render();
}
main();
})();