Greasy Fork

Greasy Fork is available in English.

全网内容屏蔽

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

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

您需要先安装一款用户脚本管理器扩展,例如 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.4
// @author            no one
// @description       屏蔽特定用户的帖子和评论
// @description:zh    屏蔽特定用户的帖子和评论
// @run-at            document-start
// @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: white;
        border-width: 0;
        padding: 0;
        display: 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
  }) {
    const wrapper = document.createElement("div");
    wrapper.innerHTML = svgIcon;
    wrapper.className = BlockButtonClass;
    if (subclass) wrapper.classList.add(subclass);
    wrapper.setAttribute("user-name", name);
    wrapper.setAttribute("user-id", id);
    if (css2) {
      const style = document.createElement("style");
      style.textContent = css2;
      wrapper.appendChild(style);
    }
    wrapper.addEventListener("click", (ev) => {
      ev.preventDefault();
      ev.stopPropagation();
      if (typeof listeners === "function") {
        listeners({ name, id });
      } else {
        listeners.forEach((listener) => {
          listener({ name, id });
        });
      }
    });
    return wrapper;
  }
  function addStyle(cssStyle) {
    if (!cssStyle) return;
    const head = document.querySelector("head");
    const style = document.createElement("style");
    style.type = "text/css";
    style.innerHTML = cssStyle;
    head?.appendChild(style);
  }

  // src/filters/base.ts
  var defaultNameFn = (elem) => {
    const href = elem.getAttribute("href");
    const id = href?.split("/").at(-1);
    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 newListAndUser(list, user, content) {
    return {
      listSelector: list,
      userSelector: user,
      contentSelector: content ? content : ""
    };
  }
  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;
    removeElements(selectors, root = document, nameFn = defaultNameFn, contentFn = defaultContentFn) {
      if (selectors.length < 1) {
        return;
      }
      const selector = selectors[0];
      const list = root.querySelectorAll(selector.listSelector);
      list.forEach((element) => {
        if (element.style.display === "none") {
          return;
        }
        const user = element.querySelector(selector.userSelector);
        if (!user) {
          return;
        }
        let content;
        if (selector.contentSelector) {
          const contentElement = element.querySelector(selector.contentSelector);
          content = contentFn(contentElement);
        } else {
          content = "";
        }
        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 }) {
      if (element.querySelector(`${cssByCls(BlockButtonClass)}`)) {
        return;
      }
      const { name, id } = user;
      return createBlockButton({
        name,
        id,
        listeners: [DomainStore.listener, this.render.bind(this)]
      });
    }
    injectButton({
      listSelector,
      userSelector,
      elementButtonFunc,
      doc = document,
      subListSelector,
      subUserSelector,
      nameFn = defaultNameFn,
      buttonWrapper
    }) {
      const list = doc.querySelectorAll(listSelector);
      const defaultWrapperFunc = (userNode, root) => {
        while (userNode && userNode.parentNode !== root) {
          if (userNode.parentNode.childElementCount > 1) {
            return userNode.parentNode;
          }
          userNode = userNode.parentNode;
        }
        return userNode.parentNode;
      };
      list.forEach((element) => {
        let ue = element.querySelector(userSelector);
        if (!ue) {
          return;
        }
        const user = nameFn(ue);
        if (!elementButtonFunc)
          elementButtonFunc = this.defaultButtonFunc.bind(this);
        const btn = elementButtonFunc({ element, user });
        if (btn === void 0) {
          return;
        }
        if (!buttonWrapper) {
          buttonWrapper = defaultWrapperFunc;
        }
        let wrapper;
        if (typeof buttonWrapper === "function") {
          wrapper = buttonWrapper(ue, element);
        } else {
          wrapper = element.querySelector(buttonWrapper);
        }
        wrapper.appendChild(btn);
      });
      list.forEach((element) => {
        if (subListSelector && subUserSelector) {
          this.injectButton({
            listSelector: subListSelector,
            userSelector: subUserSelector,
            doc: element,
            nameFn
          });
        }
      });
    }
    render() {
      this.renderers.forEach((f) => {
        if (typeof f.filterMeta === "boolean") {
          f();
        } else {
          const href = document.location.href;
          if (href.match(f.filterMeta.pattern)) {
            f();
          }
        }
      });
    }
  };
  function filterFunc(target, name, descriptor) {
    const fn = descriptor.value;
    fn.filterMeta = true;
  }
  function patternFilterFunc(pattern) {
    return (target, name, descriptor) => {
      descriptor.value.filterMeta = { pattern };
    };
  }
  function HookDecorator(type) {
    return (pattern) => {
      return (target, name, descriptor) => {
        descriptor.value.hookMeta = {
          type,
          pattern
        };
      };
    };
  }
  var reqHook = HookDecorator("request");
  var respHook = HookDecorator("response");

  // src/filters/zhihu.ts
  var userFunc = (element) => {
    const href = element.getAttribute("href");
    return {
      id: href.split("/").at(-1),
      name: element.textContent
    };
  };
  var feedUserFunc = (e) => {
    const metaText = e.dataset.zaExtraModule;
    let id = "";
    if (metaText) {
      const meta = JSON.parse(metaText);
      id = meta?.card?.content?.author_member_hash_id;
    }
    const zop = e.dataset.zop;
    const name = JSON.parse(zop).authorName;
    return { id, name };
  };
  var ZhihuFilter = class extends WebsiteFilter {
    interceptAnalytics() {
      return Response.json({}, { status: 200 });
    }
    interceptTouch() {
      return Response.json({ success: true }, { status: 201 });
    }
    async filterComments() {
      const selector = {
        comments: "div.css-18ld3w0 > div[data-id]",
        commentUser: "div.css-jp43l4 a.css-10u695f",
        commentContent: "div.css-jp43l4 div.CommentContent.css-1jpzztt",
        replies: "div[data-id]",
        replyUser: "a.css-10u695f",
        replyContent: "div.CommentContent.css-1jpzztt"
      };
      this.removeElements(
        [
          newListAndUser(
            selector.comments,
            selector.commentUser,
            selector.commentContent
          ),
          newListAndUser(
            selector.replies,
            selector.replyUser,
            selector.replyContent
          )
        ],
        document,
        userFunc,
        ZhihuFilter.contentFunc
      );
      this.injectButton({
        listSelector: selector.comments,
        userSelector: selector.commentUser,
        subListSelector: selector.replies,
        subUserSelector: selector.replyUser,
        nameFn: userFunc
      });
    }
    static contentFunc(element) {
      return element ? element.textContent + element.querySelector("img")?.getAttribute("alt") : "";
    }
    async filterAnswerComments() {
      const selector = {
        comments: "div.css-16zdamy div[data-id]",
        commentUser: "div.css-1tww9qq a.css-10u695f",
        commentContent: "div.CommentContent.css-1jpzztt"
      };
      this.removeElements(
        [
          newListAndUser(
            selector.comments,
            selector.commentUser,
            selector.commentContent
          )
        ],
        document,
        userFunc,
        ZhihuFilter.contentFunc
      );
      this.injectButton({
        listSelector: selector.comments,
        userSelector: selector.commentUser,
        nameFn: userFunc
      });
    }
    async filterAnswers() {
      const cardSelector = {
        card: "div.Card.AnswerCard.css-0",
        user: "div.ContentItem.AnswerItem",
        content: ".RichText.ztext.CopyrightRichText-richText.css-1ygg4xu"
      };
      const buttonWrapper = "div.AuthorInfo.AnswerItem-authorInfo.AnswerItem-authorInfo--related div.AuthorInfo";
      this.removeElements(
        [
          newListAndUser(
            cardSelector.card,
            cardSelector.user,
            cardSelector.content
          )
        ],
        document,
        feedUserFunc
      );
      this.injectButton({
        listSelector: cardSelector.card,
        userSelector: cardSelector.user,
        nameFn: feedUserFunc,
        buttonWrapper
      });
      const selector = {
        answers: "div.List-item",
        answerUser: "div.ContentItem.AnswerItem"
      };
      this.removeElements(
        [
          newListAndUser(
            selector.answers,
            selector.answerUser,
            cardSelector.content
          )
        ],
        document,
        feedUserFunc
      );
      this.injectButton({
        listSelector: selector.answers,
        userSelector: selector.answerUser,
        nameFn: feedUserFunc,
        buttonWrapper
      });
    }
    async filterRecommends() {
      const selector = {
        listSelector: "div.Card.TopstoryItem.TopstoryItem-isRecommend",
        userSelector: "div.ContentItem.AnswerItem",
        content: "h2 div a",
        wrapper: "h2 div"
      };
      this.removeElements(
        [
          newListAndUser(
            selector.listSelector,
            selector.userSelector,
            selector.content
          )
        ],
        document,
        feedUserFunc
      );
      this.injectButton({
        listSelector: selector.listSelector,
        userSelector: selector.userSelector,
        nameFn: feedUserFunc,
        elementButtonFunc: ({ element, user }) => {
          const btn = this.defaultButtonFunc({ element, user });
          btn.style.display = "block";
          return btn;
        },
        buttonWrapper: selector.wrapper
      });
    }
    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([
    filterFunc
  ], ZhihuFilter.prototype, "filterAnswers", 1);
  __decorateClass([
    filterFunc
  ], 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"
      };
      this.injectButton({
        listSelector: selector.cards,
        userSelector: selector.cardUser,
        subListSelector: selector.comments,
        subUserSelector: selector.commentUser
      });
      this.injectButton({
        listSelector: selector.retweetedCards,
        userSelector: selector.retweetedCardUser
      });
      this.removeElements([
        newListAndUser(selector.cards, selector.cardUser, selector.cardContent),
        newListAndUser(
          selector.comments,
          selector.commentUser,
          selector.commentContent
        )
      ]);
      this.removeElements([
        newListAndUser(selector.cards, selector.retweetedCardUser)
      ]);
    }
    async filterFeeds() {
      const selector = {
        cardListSelector: "div.vue-recycle-scroller__item-view",
        cardUserSelector: "div.Feed_body_3R0rO a.ALink_default_2ibt1",
        commentListSelector: "div.wbpro-list",
        commentUserSelector: "div.con1.woo-box-item-flex div.text a.ALink_default_2ibt1",
        replyListSelector: "div.item2",
        replyUserSelector: "div.con2 a.ALink_default_2ibt1"
      };
      this.removeElements([
        newListAndUser(selector.cardListSelector, selector.cardUserSelector),
        newListAndUser(
          selector.commentListSelector,
          selector.commentUserSelector
        ),
        newListAndUser(selector.replyListSelector, selector.replyUserSelector)
      ]);
      this.injectButton({
        listSelector: selector.cardListSelector,
        userSelector: selector.cardUserSelector
      });
      const feedWrappers = document.querySelectorAll(selector.cardListSelector);
      feedWrappers.forEach((feed) => {
        this.injectButton({
          listSelector: selector.commentListSelector,
          userSelector: selector.commentUserSelector,
          doc: feed,
          subListSelector: selector.replyListSelector,
          subUserSelector: selector.replyUserSelector
        });
      });
    }
    async filterReplies() {
      const reply = document.querySelector("div.ReplyModal_scroll3_2kADQ");
      if (!reply) {
        return;
      }
      const selector = {
        commentListSelector: "div.wbpro-list",
        commentUserSelector: "div.con1.woo-box-item-flex a.ALink_default_2ibt1",
        root: reply,
        replyListSelector: "div.vue-recycle-scroller__item-view",
        replyUserSelector: "div.con2 a.ALink_default_2ibt1"
      };
      this.removeElements(
        [
          newListAndUser(
            selector.commentListSelector,
            selector.commentUserSelector
          ),
          newListAndUser(selector.replyListSelector, selector.replyUserSelector)
        ],
        reply
      );
      this.injectButton({
        listSelector: selector.commentListSelector,
        userSelector: selector.commentUserSelector,
        doc: reply,
        subListSelector: selector.replyListSelector,
        subUserSelector: selector.replyUserSelector
      });
    }
    createCommentButton(card, user) {
      this.injectButton({
        listSelector: "div.card-together div.list div.card-review",
        userSelector: "a.name",
        doc: card
      });
    }
    async filterDetailComments() {
      const selector = {
        commentListSelector: "div.vue-recycle-scroller__item-view",
        commentUserSelector: "div.con1.woo-box-item-flex div.text a.ALink_default_2ibt1",
        replyListSelector: "div.item2",
        replyUserSelector: "div.con2 a.ALink_default_2ibt1"
      };
      this.removeElements([
        newListAndUser(
          selector.commentListSelector,
          selector.commentUserSelector
        ),
        newListAndUser(selector.replyListSelector, selector.replyUserSelector)
      ]);
      this.injectButton({
        listSelector: selector.commentListSelector,
        userSelector: selector.commentUserSelector,
        subListSelector: selector.replyListSelector,
        subUserSelector: selector.replyUserSelector
      });
    }
    async hideTrends() {
      let trend = document.querySelector("div.main-side");
      if (trend) trend.style.display = "none";
      if (trend = document.querySelector("div.Main_side_i7Vti"))
        trend.style.display = "none";
    }
    async createRetweetButton() {
      this.removeElements([
        newListAndUser(
          "div.vue-recycle-scroller__item-view",
          "div.retweet.Feed_retweet_JqZJb a.ALink_default_2ibt1"
        )
      ]);
      this.injectButton({
        listSelector: "div.retweet.Feed_retweet_JqZJb",
        userSelector: "a.ALink_default_2ibt1"
      });
    }
    filterComments(comments) {
      return comments.reduce((filtered, comment) => {
        const myText = comment.text || "";
        const ngWordInMyText = this.inBlackList(
          { name: comment.user?.screen_name },
          myText
        );
        if (!ngWordInMyText) {
          filtered.push(comment);
        }
        return filtered;
      }, []);
    }
    filterStatuses(statuses) {
      return statuses.reduce((acc, cur) => {
        if (cur.user.following) {
          const myText = cur.text || "";
          const ngWordInMyText = this.inBlackList(
            { name: cur.user?.screen_name },
            myText
          );
          if (!ngWordInMyText) {
            if (cur.retweeted_status) {
              const oriText = cur.retweeted_status.text || "";
              const ngWordInOriText = this.inBlackList(
                { name: cur.retweeted_status?.user?.screen_name },
                oriText
              );
              if (ngWordInOriText) return acc;
            }
            acc.push(cur);
          }
        }
        return acc;
      }, []);
    }
    filterSearchBand(searchBands) {
      return searchBands.reduce((acc, cur) => {
        if (!this.inBlackList({ name: "" }, cur.word)) {
          acc.push(cur);
        }
        return acc;
      }, []);
    }
    onFriendTimeline(url, res) {
      if (url.includes("m.weibo.cn")) {
        res = res;
        res.data.statuses = this.filterStatuses(res.data.statuses);
      } else {
        res = res;
        res.statuses = this.filterStatuses(res.statuses);
        console.log(
          `filtered url: ${url}, users: ${res.statuses.reduce((pre, cur) => {
            pre.push(cur.user.screen_name);
            return pre;
          }, [])}`
        );
      }
    }
    onSearchBand(url, res) {
      res.data.realtime = this.filterSearchBand(res.data.realtime);
    }
    onTrendsBand(url, res) {
      res.data.list = [];
    }
    hook_buildComments(url, res) {
      res.data = this.filterComments(res.data);
    }
  };
  __publicField(WeiboFilter, "host", "weibo.com");
  __decorateClass([
    reqHook(/female_version|rum\/events/)
  ], WeiboFilter.prototype, "mockRequests", 1);
  __decorateClass([
    reqHook(/log\/read/)
  ], WeiboFilter.prototype, "interceptRead", 1);
  __decorateClass([
    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 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 selector = {
        post: ".hupu-bbs-post",
        user: "p.first-line-user-info a span",
        content: ".hupu-bbs-post"
      };
      this.injectButton({
        listSelector: selector.post,
        userSelector: selector.user
      });
      this.removeElements(
        [newListAndUser(selector.post, selector.user, selector.content)],
        document,
        void 0,
        contentFunc
      );
    }
    async filterHupuComments() {
      const selector = {
        comments: "div.index_discuss-card__Nd4MK.hp-m-discuss-card.post-card",
        commentUser: "p.discuss-card__user span.discuss-card__username",
        comment: "p.discuss-card__content",
        replies: "div.index_discuss-card__Nd4MK.hp-m-discuss-card.discuss-card",
        quotes: "div.discuss-card__quote-container-quote",
        quoteUser: "div.discuss-card__quote-container-quote span.discuss-card__quote-container-discusser",
        quote: "span.discuss-card__quote-content"
      };
      const wrapper = "p.discuss-card__user";
      this.removeElements([
        newListAndUser(selector.comments, selector.commentUser, selector.comment)
      ]);
      this.injectButton({
        listSelector: selector.comments,
        userSelector: selector.commentUser,
        buttonWrapper: wrapper
      });
      this.removeElements([
        newListAndUser(selector.comments, selector.quoteUser, selector.quote)
      ]);
      this.injectButton({
        listSelector: selector.quotes,
        userSelector: selector.quoteUser,
        buttonWrapper: wrapper
      });
      this.removeElements([
        newListAndUser(selector.replies, selector.commentUser, selector.comment)
      ]);
      this.injectButton({
        listSelector: selector.replies,
        userSelector: selector.commentUser,
        buttonWrapper: wrapper
      });
    }
    hupuRouter(url, res) {
      function 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;
        }, []);
      }
      res.data.replies = filterHupuReplies(res.data.replies);
    }
  };
  __publicField(HupuFilter, "host", "hupu.com");
  __decorateClass([
    filterFunc
  ], HupuFilter.prototype, "filterHupuComments", 1);
  __decorateClass([
    respHook(/\/bbs-reply-detail/)
  ], HupuFilter.prototype, "hupuRouter", 1);
  HupuFilter = __decorateClass([
    RegisterSubclass
  ], HupuFilter);

  // src/utils/time.ts
  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  // src/filters/tieba.ts
  var TiebaFilter = class extends WebsiteFilter {
    constructor() {
      super();
      this.hideLoginPopup();
    }
    async hideLoginPopup() {
      let login = null;
      while (!login) {
        login = document.querySelector("div.tieba-custom-pass-login");
        if (login) {
          const ob = new MutationObserver((mutations) => {
            const popup = document.querySelector("div.tieba-custom-pass-login");
            const closeButton = document.querySelector("span.close-btn");
            if (closeButton) {
              closeButton.click();
            } else {
              popup.style.display = "none";
            }
          });
          ob.observe(login, {
            attributeFilter: ["style"],
            subtree: true
          });
          break;
        }
        await sleep(10);
      }
    }
    async filterTiebaThreadListComments() {
      const selector = {
        threadsSelector: "li.j_thread_list.clearfix.thread_item_box",
        threadUserSelector: "span.tb_icon_author",
        content: "div.col2_right.j_threadlist_li_right"
      };
      const contentFn = (element) => {
        const title = element.querySelector(
          "div.threadlist_abs.threadlist_abs_onlyline"
        );
        const preview = element.querySelector(
          "div.threadlist_title.pull_left.j_th_tit"
        );
        return title?.textContent + preview?.textContent;
      };
      const fn = (user) => {
        const field = user.dataset.field;
        const id = JSON.parse(field)?.user_id;
        return {
          name: user.getAttribute("title")?.replace("\u4E3B\u9898\u4F5C\u8005: ", ""),
          id
        };
      };
      this.removeElements(
        [
          newListAndUser(
            selector.threadsSelector,
            selector.threadUserSelector,
            selector.content
          )
        ],
        document,
        fn,
        contentFn
      );
      this.injectButton({
        listSelector: selector.threadsSelector,
        userSelector: selector.threadUserSelector,
        nameFn: fn
      });
    }
    async filterTiebaThreadComments() {
      const selector = {
        commentsSelector: "div.l_post.l_post_bright.j_l_post.clearfix",
        commentUserSelector: "div.d_author li.d_name a.p_author_name.j_user_card",
        commentContent: "div.p_content div.d_post_content.j_d_post_content",
        repliesSelector: "div.j_lzl_c_b_a.core_reply_content li.lzl_single_post.j_lzl_s_p",
        replyUserSelector: "div.lzl_cnt a.at.j_user_card",
        replyContent: "div.lzl_cnt span.lzl_content_main"
      };
      this.removeElements([
        newListAndUser(
          selector.commentsSelector,
          selector.commentUserSelector,
          selector.commentContent
        ),
        newListAndUser(
          selector.repliesSelector,
          selector.replyUserSelector,
          selector.replyContent
        )
      ]);
      this.injectButton({
        listSelector: selector.commentsSelector,
        userSelector: selector.commentUserSelector,
        subListSelector: selector.repliesSelector,
        subUserSelector: selector.replyUserSelector
      });
    }
    async hideRightBar() {
      const rightBar = document.querySelector("div.right_section.right_bright");
      if (!rightBar) {
        return;
      }
      rightBar.parentNode.removeChild(rightBar);
    }
    filterTiebaReplies(data) {
      const userMap = /* @__PURE__ */ new Map();
      for (const user of Object.values(data.user_list)) {
        userMap.set(user.user_nickname_v2, true);
      }
      const comments = data.comment_list;
      data.comment_list = Object.entries(comments).reduce(
        (filtered, [postId, comment]) => {
          let replies = comment.comment_info;
          replies = replies.filter(
            (reply) => !this.inBlackList({ name: reply.show_nickname }, reply.content)
          );
          comment.comment_list_num = replies.length;
          comment.comment_info = replies;
          if (comment.comment_list_num > 0) {
            filtered = {
              ...filtered,
              [postId]: comment
            };
          }
          return filtered;
        },
        {}
      );
      return data;
    }
    hookReplies(url, res) {
      res.data = this.filterTiebaReplies(res.data);
    }
    hookTopicList(url, res) {
      res.data.user_his_topic.topic_list = [];
      res.data.sug_topic.topic_list = [];
      res.data.bang_topic.topic_list = [];
      res.data.manual_topic.topic_list = [];
    }
    hookSuggestion(url, res) {
      res.hottopic_list.search_data = [];
      res.query_tips.search_data = [];
    }
  };
  __publicField(TiebaFilter, "host", "tieba.baidu.com");
  __decorateClass([
    filterFunc
  ], TiebaFilter.prototype, "hideLoginPopup", 1);
  __decorateClass([
    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(name, id) {
      return createBlockButton({
        name,
        id,
        css: ButtonCSSText,
        listeners: [DomainStore.listener, this.render.bind(this)]
      });
    }
    hoverButtonFunc({ element, user }) {
      if (element.querySelector(cssByCls(BlockButtonClass))) {
        return;
      }
      return createBlockButton({
        name: user.name,
        id: user.id,
        subclass: HoverButtonClass,
        listeners: [DomainStore.listener, this.render.bind(this)]
      });
    }
    filterReplies(e) {
      let replies = e.shadowRoot?.querySelector("div#replies")?.querySelector("bili-comment-replies-renderer")?.shadowRoot;
      let replyRenderers = replies?.querySelectorAll(
        "bili-comment-reply-renderer"
      );
      replyRenderers?.forEach((replyShadowRoot) => {
        let reply = replyShadowRoot?.shadowRoot;
        let replyUser = reply?.querySelector("bili-comment-user-info")?.shadowRoot?.querySelector("#user-name");
        let name = replyUser?.textContent || "";
        let id = replyUser?.getAttribute("data-user-profile-id") || "";
        if (this.inBlackList({ name, id })) {
          replyShadowRoot.parentElement?.removeChild(replyShadowRoot);
        } else {
          if (replyUser.parentNode.querySelector(cssByCls(BlockButtonClass))) {
            return;
          }
          const button = this.commentsButton(name, id);
          replyUser.parentNode.appendChild(button);
        }
      });
    }
    filterComments() {
      const srw = document.querySelector(
        "#comment > div > bili-comments"
      )?.shadowRoot;
      if (!srw) {
        return;
      }
      const comments = srw.querySelectorAll(
        "#feed > bili-comment-thread-renderer"
      );
      comments?.forEach((e) => {
        this.filterReplies(e);
        const comment = e.shadowRoot?.querySelector(
          "bili-comment-renderer"
        )?.shadowRoot;
        let commentUser = comment?.querySelector(
          "#header > bili-comment-user-info"
        )?.shadowRoot;
        const userInfo = commentUser.querySelector("#user-name");
        const buttonWrapper = commentUser.querySelector("div#info");
        let userName = userInfo?.textContent;
        let userId = userInfo?.getAttribute("data-user-profile-id") || "";
        if (this.inBlackList({ name: userName, id: userId })) {
          e.parentNode.removeChild(e);
        } else {
          if (buttonWrapper.querySelector(cssByCls(BlockButtonClass))) {
            return;
          }
          const button = this.commentsButton(userName, userId);
          buttonWrapper.appendChild(button);
        }
      });
    }
    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"
      };
      const nameFn = (element) => {
        const author = element.querySelector(".bili-video-card__info--author");
        const href = element.getAttribute("href");
        return { name: author.textContent, id: href.split("/").at(-1) };
      };
      this.removeElements(
        [newListAndUser(selector.videos, selector.author, selector.title)],
        document,
        nameFn
      );
      this.injectButton({
        listSelector: selector.videos,
        userSelector: selector.author,
        elementButtonFunc: this.hoverButtonFunc.bind(this),
        buttonWrapper: ".bili-video-card__image--wrap",
        nameFn
      });
    }
    filterVideoList() {
      const selector = {
        videos: ".feed-card",
        author: ".bili-video-card__info--owner",
        title: ".bili-video-card__info--tit"
      };
      const nameFn = (element) => {
        const author = element.querySelector(".bili-video-card__info--author");
        const href = element.getAttribute("href");
        return { name: author.textContent, id: href.split("/").at(-1) };
      };
      this.removeElements(
        [newListAndUser(selector.videos, selector.author, selector.title)],
        document,
        nameFn
      );
      this.injectButton({
        listSelector: selector.videos,
        userSelector: selector.author,
        elementButtonFunc: this.hoverButtonFunc.bind(this),
        nameFn,
        buttonWrapper: ".bili-video-card__image--wrap"
      });
    }
    filterVideoPlaylist() {
      const selector = {
        videos: ".video-page-card-small",
        videoAuthor: ".upname a",
        title: "div.info a p.title"
      };
      const nameFn = (element) => {
        return {
          name: element.querySelector("span.name").textContent,
          id: element.getAttribute("href").split("/").at(-2)
        };
      };
      this.removeElements(
        [newListAndUser(selector.videos, selector.videoAuthor, selector.title)],
        document,
        nameFn
      );
      this.injectButton({
        listSelector: selector.videos,
        userSelector: selector.videoAuthor,
        nameFn,
        elementButtonFunc: this.hoverButtonFunc.bind(this),
        buttonWrapper: ".pic-box"
      });
    }
    hookMain(url, res) {
      return this.hookComments(url, res);
    }
    hookReplies(url, res) {
      return this.hookComments(url, res);
    }
    hookComments(url, res) {
      const filterReplyFunc = (reply) => {
        const id = reply.mid_str;
        const name = reply.member.uname;
        const content = reply.content.message;
        return !this.inBlackList({ name, id }, content);
      };
      let { replies } = res.data;
      replies = replies.filter(filterReplyFunc);
      replies.forEach((reply) => {
        const subReplies = reply.replies;
        reply.replies = subReplies.filter(filterReplyFunc);
      });
      res.data.replies = replies;
    }
    hookSearchVideo(url, res) {
      res.data.result = res.data.result.filter((item) => {
        const name = item.author;
        const id = item.mid;
        const desc = item.description;
        return !this.inBlackList({ name, id }, desc);
      });
    }
    hookSearchTrends(url, res) {
      res.data.trending.list = [
        {
          keyword: "fsd",
          show_name: "FSD",
          icon: "http://i0.hdslb.com/bfs/activity-plat/static/20221213/eaf2dd702d7cc14d8d9511190245d057/lrx9rnKo24.png",
          uri: "",
          goto: ""
        }
      ];
    }
  };
  __publicField(BilibiliFilter, "host", "bilibili.com");
  __decorateClass([
    patternFilterFunc(/com\/video\/\w+/)
  ], BilibiliFilter.prototype, "filterComments", 1);
  __decorateClass([
    filterFunc
  ], BilibiliFilter.prototype, "filterVideoSearch", 1);
  __decorateClass([
    filterFunc
  ], BilibiliFilter.prototype, "filterVideoList", 1);
  __decorateClass([
    patternFilterFunc(/com\/video\/\w+/)
  ], BilibiliFilter.prototype, "filterVideoPlaylist", 1);
  __decorateClass([
    respHook(/reply\/wbi\/main/)
  ], BilibiliFilter.prototype, "hookMain", 1);
  __decorateClass([
    respHook(/\/reply\/reply/)
  ], BilibiliFilter.prototype, "hookReplies", 1);
  __decorateClass([
    respHook(/search\/type/)
  ], BilibiliFilter.prototype, "hookSearchVideo", 1);
  __decorateClass([
    respHook(/search\/square/)
  ], BilibiliFilter.prototype, "hookSearchTrends", 1);
  BilibiliFilter = __decorateClass([
    RegisterSubclass
  ], BilibiliFilter);

  // src/views/panel.ts
  var MainView = class _MainView {
    store;
    filter;
    static instance;
    constructor() {
      if (_MainView.instance) {
        return _MainView.instance;
      }
      this.filter = WebsiteFilter.fromHost();
      this.store = new DomainStore();
      addStyle(css);
      window.addEventListener("load", () => {
        appObserverInit();
      });
      _MainView.instance = this;
    }
    static DialogSelector = ".my-dialog__wrapper";
    dialogElement() {
      return document.querySelector(_MainView.DialogSelector);
    }
    freshPage() {
      this.filter.render();
    }
    render() {
      setInterval(() => {
        this.renderSettingButton();
        this.renderSettingPanel();
        this.filter.render();
      }, 1e3);
    }
    /* 生成添加屏蔽关键词的按钮 */
    async renderSettingButton() {
      if (!document.body) {
        return;
      }
      if (document.body.querySelector("#add_ngList_btn")) {
        return;
      }
      const btn = document.createElement("div");
      btn.title = "\u6DFB\u52A0\u5C4F\u853D\u5173\u952E\u8BCD";
      const span = document.createElement("span");
      span.innerText = "";
      btn.appendChild(span);
      btn.id = "add_ngList_btn";
      document.body.appendChild(btn);
      btn.addEventListener("click", () => {
        this.renderBlockedUsers();
        this.showDialog();
      });
    }
    async renderSettingPanel() {
      const dialogTemplate = `
      <div class="my-dialog" style="margin-top: 15vh; width: 40%;">
        <div class="my-dialog__header">
          <span class="my-dialog__title">\u5C4F\u853D\u8BCD\u5217\u8868</span>
          <button type="button" aria-label="Close" class="my-dialog__headerbtn">
            <i class="my-dialog__close"></i>
          </button>
        </div>
        <div class="my-dialog__body">
          <div class="input_container">
            <div class="el-input">
              <input id="ngWord_input" class="el-input__inner" type="text" />
            </div>
            <button type="button" class="el-button" id="add_btn">
              <span>\u6DFB\u52A0</span>
            </button>
          </div>
          <div id="ngList"></div>
          <p class="tips">\u6CE8\uFF1A1. \u53EF\u8FC7\u6EE4\u5305\u542B\u5C4F\u853D\u8BCD\u7684\u7528\u6237\u3001\u5FAE\u535A\u3001\u8BC4\u8BBA\u3001\u70ED\u641C\u3002 2. \u5173\u952E\u8BCD\u4FDD\u5B58\u5728\u672C\u5730\u7684local storage\u4E2D\u3002 3. \u66F4\u6539\u5173\u952E\u8BCD\u540E\u5237\u65B0\u9875\u9762\u751F\u6548\uFF08\u4E0D\u5237\u65B0\u9875\u9762\u7684\u60C5\u51B5\u4E0B\uFF0C\u53EA\u6709\u4E4B\u540E\u52A0\u8F7D\u7684\u5FAE\u535A\u624D\u4F1A\u751F\u6548\uFF09\u3002</p>
        </div>
        <div class="my-dialog__footer"></div>
      </div>
    `;
      if (!document.body) {
        return;
      }
      if (document.body.querySelector(".my-dialog__wrapper")) {
        return;
      }
      const wrapper = document.createElement("div");
      wrapper.classList.add("my-dialog__wrapper");
      wrapper.innerHTML = dialogTemplate;
      document.body.appendChild(wrapper);
      document.querySelector(".my-dialog__headerbtn").addEventListener("click", () => {
        this.hideDialog();
      });
      document.querySelector("#add_btn").addEventListener("click", () => {
        const ngWord_input = document.querySelector(
          "#ngWord_input"
        );
        if (ngWord_input && ngWord_input.value) {
          this.store.addPattern(ngWord_input.value);
          ngWord_input.value = "";
          this.renderBlockedUsers();
        }
      });
    }
    showDialog() {
      this.dialogElement().style.display = "initial";
    }
    hideDialog() {
      this.dialogElement().style.display = "none";
    }
    renderBlockedUsers() {
      let blockedUsersHTML = "";
      const users = [...this.store.userList];
      for (const [i, pattern] of this.store.patternList.reverse().entries()) {
        blockedUsersHTML += `<span class="ng_pattern" data-type="pattern">${pattern}<i class="close-icon" data-index=${i}></i></span>`;
      }
      for (const [i, item] of users.reverse().entries()) {
        blockedUsersHTML += `<span class="ng_item" data-type="user">${item}<i class="close-icon" data-index=${i}></i></span>`;
      }
      const ngListNode = document.querySelector("#ngList");
      if (ngListNode) {
        ngListNode.innerHTML = blockedUsersHTML;
        const buttons = ngListNode.querySelectorAll(".close-icon");
        for (const button of buttons) {
          button.addEventListener("click", () => {
            const name = button.parentNode.textContent;
            const type = button.parentElement.dataset.type;
            switch (type) {
              case "user":
                this.store.removeUser({ name, id: name });
                break;
              case "pattern":
                this.store.removePattern(name);
                break;
            }
            this.renderBlockedUsers();
          });
        }
      }
    }
  };
  function appObserverInit() {
    const targetNode = document.getElementById("app");
    if (!targetNode) {
      return;
    }
    const config = {
      childList: true,
      subtree: true
    };
    const callback = function() {
      const audioList = document.querySelectorAll(".AfterPatch_bg_34rqc");
      for (const audio of audioList) {
        audio.remove();
        console.log("\u79FB\u9664\u4E86\u5F31\u667A\u4E09\u8FDE");
      }
    };
    const observer = new MutationObserver(callback);
    observer.observe(targetNode, config);
  }

  // src/main.ts
  async function main() {
    await DomainStore.init();
    const controller = new MainView();
    controller.render();
  }
  main();
})();