Greasy Fork

Greasy Fork is available in English.

全网内容屏蔽

屏蔽特定用户的帖子和评论

当前为 2024-08-17 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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.9
// @author            no one
// @description       屏蔽特定用户的帖子和评论
// @description:zh    屏蔽特定用户的帖子和评论
// @require           https://update.greasyfork.icu/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: 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();
      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/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/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 {
    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 new 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();
      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);
        }
      };
    }
    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/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 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([
    patternFilterFunc(/question\/\d+/)
  ], ZhihuFilter.prototype, "filterAnswerComments", 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/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);
        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([
    patternFilterFunc(/s\.weibo\.com/)
  ], WeiboFilter.prototype, "filterSearchResults", 1);
  __decorateClass([
    patternFilterFunc(/weibo\.com\/mygroups|(weibo\.com$)/)
  ], 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/hupu.ts
  var HupuFilter = class extends WebsiteFilter {
    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(/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/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 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.getAttribute("title")?.replace("\u4E3B\u9898\u4F5C\u8005: ", ""),
          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",
        u: "div.d_author li.d_name a.p_author_name.j_user_card",
        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"
      };
      this.modifyDom({
        locators: [comments, replies]
      });
    }
    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(/f\?kw=/)
  ], 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/bilibili.ts
  var BilibiliFilter = class extends WebsiteFilter {
    render() {
      super.render();
    }
    commentsButton(parent, name, id, eid) {
      if (parent.querySelector(`${cssByCls(BlockButtonClass)}[button-id="${eid}"]`)) {
        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(
        "#comment > div > 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");
        let userName = userInfo?.textContent;
        let userId = userInfo?.getAttribute("data-user-profile-id") || "";
        if (this.inBlackList({ name: userName, id: userId })) {
          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 = {
        videos: ".feed-card",
        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)
      );
    }
    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);
    }
    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(/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);
    }
    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">
              <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
  if (document.location.host.includes("m.hupu.com")) {
    const originalOpen = window.open.bind(window);
    window.open = (url, target, features) => {
      if (target === "_self") {
        target = "_blank";
      }
      return originalOpen(url, target, features);
    };
  }
  async function main() {
    await DomainStore.init();
    const controller = new MainView();
    controller.render();
  }
  main();
})();