Greasy Fork

Greasy Fork is available in English.

Internet Content Filterer

block users' posts and comments whom you blocked

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
function _applyDecoratedDescriptor(i, e, r, n, l) { var a = {}; return Object.keys(n).forEach(function (i) { a[i] = n[i]; }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) { return n(i, e, r) || r; }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
// ==UserScript==
// @name              Internet Content Filterer
// @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             *://www.bilibili.com/*
// @exclude           *://weibo.com/tv*
// @grant             GM.getValue
// @grant             GM.setValue
// @grant             GM.deleteValue
// @grant             GM.listValues
// @version           3.8.2
// @author            no one
// @description       block users' posts and comments whom you blocked
// @description:zh    屏蔽特定用户的帖子和评论
// @run-at            document-start
// @require           https://update.greasyfork.icu/scripts/472943/1320613/Itsnotlupus%27%20MiddleMan.js
// ==/UserScript==
/* eslint-disable max-classes-per-file,no-param-reassign,no-console */
/* jshint esversion: 6 */
// eslint-disable-next-line func-names
(async function (_dec, _dec2, _dec3, _dec4, _class, _WeiboFilter, _apiBlackList, _dec5, _class2, _HupuFilter, _dec6, _dec7, _dec8, _class3, _TiebaFilter, _dec9, _class4, _BilibiliFilter, _dec10, _dec11, _dec12, _class5, _ZhihuFilter, _DomainStore) {
  /* 添加样式 */

  const BlockButtonClass = 'block-button';
  const cssByCls = cls => `.${cls}`;
  const 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;
      }

      ${cssByCls(BlockButtonClass)} {
        cursor: pointer;
        height: 12px;
        width: 12px;
        margin-left: 1px;
        float: inherit;
        background: white;
        border-width: 0;
        padding: 0;
        line-height:0px;
        transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
        transformOrigin: '50% bottom;
      }

      ${cssByCls(BlockButtonClass)}:hover {
        transform: translateY(0) scale(1.5);
      }

      .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;
      }


      .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;
      }
    `;

  /* 按钮模板 */
  const btnTemp = `
      <span class="Configs_alink_2Yg6L" yawf-component-tag="woo-box">
        <div class="woo-box-flex woo-box-alignCenter woo-pop-item-main" role="button" tabindex="0" data-focus-visible="true" yawf-component-tag="woo-pop-item woo-box">
          屏蔽词设置
        </div>
      </span>
    `;
  const 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 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);
  }
  const defaultNameFn = elem => elem.innerText || elem.getAttribute('aria-label');
  function createButtonElement(name) {
    // eslint-disable-next-line
    name = name.trim().replace(/^@/, '').replace(':', '');
    const wrapper = document.createElement('div');
    wrapper.innerHTML = svgIcon;
    wrapper.className = BlockButtonClass;
    wrapper.setAttribute('user-name', name);
    return wrapper;
  }
  function newListAndUser(list, user, content = undefined) {
    return {
      listSelector: list,
      userSelector: user,
      contentSelector: content
    };
  }
  function injectButton({
    listSelector,
    userSelector,
    elementButtonFunc,
    doc = document,
    subListSelector,
    subUserSelector,
    nameFn = defaultNameFn
  }) {
    const list = doc.querySelectorAll(listSelector);
    list.forEach(element => {
      if (elementButtonFunc) elementButtonFunc(element);
      let user = element.querySelector(userSelector);
      if (!user) {
        return;
      }
      if (element.querySelector(`${cssByCls(BlockButtonClass)}`)) {
        return;
      }
      const btn = createButtonElement(nameFn(user));
      while (user.parentNode !== element) {
        if (user.parentNode.childElementCount > 1) {
          user.parentNode.appendChild(btn);
          break;
        }
        user = user.parentNode;
      }
      if (user.parentNode === element) {
        user.parentNode.appendChild(btn);
      }
    });
    list.forEach(element => {
      if (subListSelector && subUserSelector) {
        injectButton({
          listSelector: subListSelector,
          userSelector: subUserSelector,
          doc: element,
          nameFn: nameFn
        });
      }
    });
  }
  var _filters = /*#__PURE__*/new WeakMap();
  var _proxyOpt = /*#__PURE__*/new WeakMap();
  var _registered = /*#__PURE__*/new WeakMap();
  class WebsiteFilter {
    /**
     * @param {Array.<{listSelector: String, userSelector: String, contentSelector: String}>} selectors
     * @param {Document | Element} root
     * @param nameFn
     * @param contentFn
     */
    removeElements(selectors, root = document, nameFn = defaultNameFn, contentFn = e => '') {
      if (selectors.length < 1) {
        return;
      }
      const selector = selectors[0];
      const list = root.querySelectorAll(selector.listSelector);
      list.forEach(element => {
        const user = element.querySelector(selector.userSelector);
        if (!user) {
          return;
        }
        const contentElement = element.querySelector(selector.contentSelector);
        const content = contentFn(contentElement);
        const poster = nameFn(user);
        if (this.inBlackList(poster, content)) {
          element.parentNode.removeChild(element);
        } else {
          this.removeElements(selectors.slice(1), element, nameFn);
        }
      });
    }
    inBlackList(name, content = '') {
      return this.store.hasUser(name) || this.store.matchPattern(content);
    }

    /**
     *
     * @param {DomainStore} store
     */
    constructor(store) {
      _classPrivateFieldInitSpec(this, _filters, []);
      _classPrivateFieldInitSpec(this, _proxyOpt, {
        requestRouters: [],
        responseRouters: []
      });
      _classPrivateFieldInitSpec(this, _registered, false);
      /**
       * @type DomainStore
       */
      _defineProperty(this, "store", void 0);
      this.store = store;
      this.addHooks(...Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter(name => Object.getPrototypeOf(this)[name].hookMeta).reduce((hooks, name) => {
        const fn = this[name].bind(this);
        fn.hookMeta = this[name].hookMeta;
        hooks.push(fn);
        return hooks;
      }, []));
      _classPrivateFieldSet(_filters, this, Object.getOwnPropertyNames(Object.getPrototypeOf(this)).reduce((fns, name) => {
        const method = this[name];
        if (method.filterMeta) {
          const fn = method.bind(this);
          fn.hookMeta = this[name].hookMeta;
          fns.push(fn);
        }
        return fns;
      }, []));
    }

    /**
     * @callback onRequest
     * @param {Request} request
     * @property {{pattern: RegExp, type: string}} hookMeta
     */

    /**
     * @callback onResponse
     * @param {string} url
     * @param {Object} res
     * @property {{pattern: RegExp, type: string}} hookMeta
     */

    /**
     *
     * @param {onRequest | onResponse} hooks
     */
    addHooks(...hooks) {
      hooks.forEach(hook => {
        switch (hook.hookMeta.type) {
          case 'request':
            _classPrivateFieldGet(_proxyOpt, this).requestRouters.push(hook);
            break;
          case 'response':
            _classPrivateFieldGet(_proxyOpt, this).responseRouters.push(hook);
            break;
        }
      });
    }
    requestHandler(hook) {
      return {
        async requestHandler(request) {
          return hook(request);
        }
      };
    }
    responseHandler(hook) {
      return {
        async responseHandler(request, response, error) {
          if (error) {
            throw error;
          }
          const res = await response.json();
          const url = request.url;
          hook(url, res);
          return Response.json(res);
        }
      };
    }
    render() {
      _classPrivateFieldGet(_filters, this).forEach(f => {
        if (!_classPrivateFieldGet(_registered, this)) {
          const opt = _classPrivateFieldGet(_proxyOpt, this);
          opt.requestRouters.forEach(router => {
            middleMan.addHook(router.hookMeta.pattern, this.requestHandler(router));
          });
          opt.responseRouters.forEach(router => {
            middleMan.addHook(router.hookMeta.pattern, this.responseHandler(router));
          });
          _classPrivateFieldSet(_registered, this, true);
        }
        f();
      });
    }
  }
  function filterFunc(target, name, descriptor) {
    const fn = descriptor.value;
    fn.filterMeta = true;
    return descriptor;
  }
  function reqHook(regex) {
    return (target, name, descriptor) => {
      descriptor.value.hookMeta = {
        type: 'request',
        pattern: regex
      };
      return descriptor;
    };
  }
  function respHook(pattern) {
    return (target, name, descriptor) => {
      descriptor.value.hookMeta = {
        type: 'response',
        pattern: pattern
      };
      return descriptor;
    };
  }
  let WeiboFilter = (_dec = reqHook(/female_version|rum\/events/), _dec2 = respHook(/\/friendstimeline/), _dec3 = respHook(/\/searchBand/), _dec4 = respHook(/\/buildComments/), (_class = (_apiBlackList = /*#__PURE__*/new WeakMap(), (_WeiboFilter = class WeiboFilter extends WebsiteFilter {
    // 接口黑名单

    mockRequests() {
      return Response.json({}, {
        status: 200
      });
    }
    constructor(store) {
      super(store);
      _classPrivateFieldInitSpec(this, _apiBlackList, ['/female_version.mp3', '/intake/v2/rum/events']);
      this.hideTrends();
    }
    async filterSearchResults() {
      const selector = {
        cards: 'div.card-wrap',
        cardUser: 'div.info a.name',
        retweetedCards: 'div.card-wrap div.card-comment',
        retweetedCardUser: 'div.con a.name',
        comments: 'div.card-review',
        commentUser: 'div.content a.name'
      };
      injectButton({
        listSelector: selector.cards,
        userSelector: selector.cardUser,
        elementButtonFunc: WeiboFilter.createCommentButton
      });
      injectButton({
        listSelector: selector.retweetedCards,
        userSelector: selector.retweetedCardUser
      });
      this.removeElements([{
        listSelector: selector.cards,
        userSelector: selector.cardUser
      }, {
        listSelector: selector.comments,
        userSelector: selector.commentUser
      }]);
      this.removeElements([{
        listSelector: selector.cards,
        userSelector: 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)]);
      injectButton({
        listSelector: selector.cardListSelector,
        userSelector: selector.cardUserSelector
      });
      const feedWrappers = document.querySelectorAll(selector.cardListSelector);
      feedWrappers.forEach(feed => {
        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([{
        listSelector: selector.commentListSelector,
        userSelector: selector.commentUserSelector
      }, {
        listSelector: selector.replyListSelector,
        userSelector: selector.replyUserSelector
      }], reply);
      injectButton({
        listSelector: selector.commentListSelector,
        userSelector: selector.commentUserSelector,
        doc: reply,
        subListSelector: selector.replyListSelector,
        subUserSelector: selector.replyUserSelector
      });
    }
    static async createCommentButton(card) {
      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([{
        listSelector: selector.commentListSelector,
        userSelector: selector.commentUserSelector
      }, {
        listSelector: selector.replyListSelector,
        userSelector: selector.replyUserSelector
      }]);
      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')]);
      injectButton({
        listSelector: 'div.retweet.Feed_retweet_JqZJb',
        userSelector: 'a.ALink_default_2ibt1'
      });
    }

    /**
     *@param {Array.<{user: {screen_name: string}, text: string}>} comments
     * */
    filterComments(comments) {
      return comments.reduce((filtered, comment) => {
        var _comment$user;
        const myText = comment.text || '';
        const ngWordInMyText = this.inBlackList((_comment$user = comment.user) === null || _comment$user === void 0 ? void 0 : _comment$user.screen_name, myText);
        if (!ngWordInMyText) {
          filtered.push(comment);
        }
        return filtered;
      }, []);
    }

    /**
     * @typedef Status
     * @type {object}
     * @property {?User} user
     * @property {string} text
     * @property {?Status} retweeted_status
     *
     * @typedef User
     * @type {object}
     * @property {boolean} following
     * @property {string} screen_name
     *
     *
     * @param {Status[]} statuses
     * */
    filterStatuses(statuses) {
      return statuses.reduce((acc, cur) => {
        if (cur.user.following) {
          var _cur$user;
          const myText = cur.text || '';
          const ngWordInMyText = this.inBlackList((_cur$user = cur.user) === null || _cur$user === void 0 ? void 0 : _cur$user.screen_name, myText);
          if (!ngWordInMyText) {
            if (cur.retweeted_status) {
              var _cur$retweeted_status;
              const oriText = cur.retweeted_status.text || '';
              const ngWordInOriText = this.inBlackList((_cur$retweeted_status = cur.retweeted_status) === null || _cur$retweeted_status === void 0 || (_cur$retweeted_status = _cur$retweeted_status.user) === null || _cur$retweeted_status === void 0 ? void 0 : _cur$retweeted_status.screen_name, oriText);
              if (ngWordInOriText) return acc;
            }
            acc.push(cur);
          }
        }
        return acc;
      }, []);
    }
    filterSearchBand(searchBands) {
      return searchBands.reduce((acc, cur) => {
        if (!this.inBlackList(cur.word)) {
          acc.push(cur);
        }
        return acc;
      }, []);
    }
    onFriendTimeline(url, res) {
      if (url.includes('m.weibo.cn')) {
        res.data.statuses = this.filterStatuses(res.data.statuses);
      } else {
        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);
    }
    hook_buildComments(url, res) {
      res.data = this.filterComments(res.data);
    }
  }, _defineProperty(_WeiboFilter, "host", 'weibo.com'), _WeiboFilter)), (_applyDecoratedDescriptor(_class.prototype, "mockRequests", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "mockRequests"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "filterSearchResults", [filterFunc], Object.getOwnPropertyDescriptor(_class.prototype, "filterSearchResults"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "filterFeeds", [filterFunc], Object.getOwnPropertyDescriptor(_class.prototype, "filterFeeds"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "filterReplies", [filterFunc], Object.getOwnPropertyDescriptor(_class.prototype, "filterReplies"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "filterDetailComments", [filterFunc], Object.getOwnPropertyDescriptor(_class.prototype, "filterDetailComments"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "hideTrends", [filterFunc], Object.getOwnPropertyDescriptor(_class.prototype, "hideTrends"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "createRetweetButton", [filterFunc], Object.getOwnPropertyDescriptor(_class.prototype, "createRetweetButton"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "onFriendTimeline", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "onFriendTimeline"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "onSearchBand", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "onSearchBand"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "hook_buildComments", [_dec4], Object.getOwnPropertyDescriptor(_class.prototype, "hook_buildComments"), _class.prototype)), _class));
  let HupuFilter = (_dec5 = respHook(/\/bbs-reply-detail/), (_class2 = (_HupuFilter = class HupuFilter extends WebsiteFilter {
    async filterHupuComments() {
      const selector = {
        commentsSelector: 'div.index_discuss-card__Nd4MK.hp-m-discuss-card.post-card',
        userSelector: 'p.discuss-card__user span.discuss-card__username',
        repliesSelector: 'div.index_discuss-card__Nd4MK.hp-m-discuss-card.discuss-card',
        quotesSelector: 'div.discuss-card__quote-container-quote',
        quoteUserSelector: 'div.discuss-card__quote-container-quote span.discuss-card__quote-container-discusser'
      };
      this.removeElements([{
        listSelector: selector.commentsSelector,
        userSelector: selector.userSelector
      }]);
      injectButton({
        listSelector: selector.commentsSelector,
        userSelector: selector.userSelector
      });
      this.removeElements([newListAndUser(selector.commentsSelector, selector.quoteUserSelector)]);
      injectButton({
        listSelector: selector.quotesSelector,
        userSelector: selector.quoteUserSelector
      });
      this.removeElements([newListAndUser(selector.repliesSelector, selector.userSelector)]);
      injectButton({
        listSelector: selector.repliesSelector,
        userSelector: selector.userSelector
      });
    }
    hupuRouter(url, res) {
      function filterHupuReplies(replies) {
        return replies.reduce((filtered, reply) => {
          const user = reply.user.username;
          if (!this.inBlackList(user)) {
            filtered.push(reply);
          }
          return filtered;
        }, []);
      }
      res.data.replies = filterHupuReplies(res.data.replies);
    }
  }, _defineProperty(_HupuFilter, "host", 'hupu.com'), _HupuFilter), (_applyDecoratedDescriptor(_class2.prototype, "filterHupuComments", [filterFunc], Object.getOwnPropertyDescriptor(_class2.prototype, "filterHupuComments"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "hupuRouter", [_dec5], Object.getOwnPropertyDescriptor(_class2.prototype, "hupuRouter"), _class2.prototype)), _class2));
  let TiebaFilter = (_dec6 = respHook(/\/p\/totalComment/), _dec7 = respHook(/\/topicList/), _dec8 = respHook(/\/suggestion/), (_class3 = (_TiebaFilter = class TiebaFilter extends WebsiteFilter {
    constructor(store) {
      super(store);
      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 record = mutations[0];
            if (record.target.style.display === 'block') {
              login.style.display = 'none';
            }
          });
          ob.observe(login, {
            attributeFilter: ['style']
          });
          break;
        }
        await sleep(10);
      }
    }
    async filterTiebaThreadListComments() {
      const selector = {
        threadsSelector: 'li.j_thread_list.clearfix.thread_item_box',
        threadUserSelector: 'span.tb_icon_author'
      };
      const fn = user => {
        var _user$getAttribute;
        return (_user$getAttribute = user.getAttribute('title')) === null || _user$getAttribute === void 0 ? void 0 : _user$getAttribute.replace('主题作者: ', '');
      };
      this.removeElements([newListAndUser(selector.threadsSelector, selector.threadUserSelector)], document, fn);
      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',
        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'
      };
      this.removeElements([newListAndUser(selector.commentsSelector, selector.commentUserSelector), newListAndUser(selector.repliesSelector, selector.replyUserSelector)]);
      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);
    }
    hookReplies(url, res) {
      res.data = filterTiebaReplies(res.data);
    }

    /**
     * @typedef Topic
     * @type {object}
     * @property {string[]} topic_list
     *
     * @param {string} url
     * @param {object} res
     * @param {{user_his_topic: Topic, sug_topic: Topic, bang_topic: Topic, manual_topic: Topic}} 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 = [];
    }

    /**
     * @param {string} url
     * @param {{hottopic_list: object}} res
     * */
    hookSuggestion(url, res) {
      res.hottopic_list.search_data = [];
    }
  }, _defineProperty(_TiebaFilter, "host", 'tieba.baidu.com'), _TiebaFilter), (_applyDecoratedDescriptor(_class3.prototype, "hideLoginPopup", [filterFunc], Object.getOwnPropertyDescriptor(_class3.prototype, "hideLoginPopup"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "filterTiebaThreadListComments", [filterFunc], Object.getOwnPropertyDescriptor(_class3.prototype, "filterTiebaThreadListComments"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "filterTiebaThreadComments", [filterFunc], Object.getOwnPropertyDescriptor(_class3.prototype, "filterTiebaThreadComments"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "hideRightBar", [filterFunc], Object.getOwnPropertyDescriptor(_class3.prototype, "hideRightBar"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "hookReplies", [_dec6], Object.getOwnPropertyDescriptor(_class3.prototype, "hookReplies"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "hookTopicList", [_dec7], Object.getOwnPropertyDescriptor(_class3.prototype, "hookTopicList"), _class3.prototype), _applyDecoratedDescriptor(_class3.prototype, "hookSuggestion", [_dec8], Object.getOwnPropertyDescriptor(_class3.prototype, "hookSuggestion"), _class3.prototype)), _class3));
  let BilibiliFilter = (_dec9 = respHook(/search\/square/), (_class4 = (_BilibiliFilter = class BilibiliFilter extends WebsiteFilter {
    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: ''
      }];
    }
  }, _defineProperty(_BilibiliFilter, "host", 'bilibili.com'), _BilibiliFilter), (_applyDecoratedDescriptor(_class4.prototype, "hookSearchTrends", [_dec9], Object.getOwnPropertyDescriptor(_class4.prototype, "hookSearchTrends"), _class4.prototype)), _class4));
  let ZhihuFilter = (_dec10 = reqHook(/zhihu-web-analytics/), _dec11 = respHook(/\/root_comment|\/child_comment/), _dec12 = respHook(/questions\/\d+\/feeds/), (_class5 = (_ZhihuFilter = class ZhihuFilter extends WebsiteFilter {
    interceptAnalytics() {
      return Response.json({}, {
        status: 200
      });
    }
    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: 'div.css-1tww9qq a.css-10u695f',
        replyContent: 'div.css-1tww9qq div.CommentContent.css-1jpzztt'
      };
      const fn = element => {
        const href = element.getAttribute('href');
        return href.split('/').at(-1);
      };
      this.removeElements([newListAndUser(selector.comments, selector.commentUser, selector.commentContent), newListAndUser(selector.replies, selector.replyUser, selector.replyContent)], document, fn, ZhihuFilter.contentFunc);
      injectButton({
        listSelector: selector.comments,
        userSelector: selector.commentUser,
        subListSelector: selector.replies,
        subUserSelector: selector.replyUser,
        nameFn: fn
      });
    }
    static contentFunc(element) {
      var _element$querySelecto;
      return element ? element.textContent + ((_element$querySelecto = element.querySelector('img')) === null || _element$querySelecto === void 0 ? void 0 : _element$querySelecto.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'
      };
      const fn = element => {
        const href = element.getAttribute('href');
        return href.split('/').at(-1);
      };
      this.removeElements([newListAndUser(selector.comments, selector.commentUser, selector.commentContent)], document, fn, ZhihuFilter.contentFunc);
      injectButton({
        listSelector: selector.comments,
        userSelector: selector.commentUser,
        subListSelector: selector.replies,
        subUserSelector: selector.replyUser,
        nameFn: fn
      });
    }
    async filterAnswers() {
      const selector = {
        answers: 'div.List-item',
        answerUser: 'div.ContentItem.AnswerItem'
      };
      const fn = e => {
        const metaText = e.getAttribute('data-za-extra-module');
        const meta = JSON.parse(metaText);
        return meta.card.content.author_member_hash_id;
      };
      this.removeElements([{
        listSelector: selector.answers,
        userSelector: selector.answerUser
      }], document, fn);
      injectButton({
        listSelector: selector.answers,
        userSelector: selector.answerUser,
        nameFn: fn
      });
    }
    async filterRecommends() {
      const selector = {
        listSelector: 'div.Card.TopstoryItem.TopstoryItem-isRecommend',
        userSelector: 'div.ContentItem.AnswerItem'
      };
      const fn = e => {
        const metaText = e.getAttribute('data-za-extra-module');
        const meta = JSON.parse(metaText);
        return meta.card.content.author_member_hash_id;
      };
      this.removeElements([{
        listSelector: selector.listSelector,
        userSelector: selector.userSelector
      }], document, fn);
      injectButton({
        listSelector: selector.listSelector,
        userSelector: selector.userSelector,
        nameFn: fn
      });
    }
    async filterQuestions() {}

    /**
     *
     * @param url
     * @param {{data: Object}} res
     * @property {{author: Object}[]} data
     * @property {{name: string, id: string}} author
     */
    hookComments(url, res) {
      const comments = res.data;
      res.data = comments.filter(comment => {
        const name = comment.author.id;
        const content = comment.content;
        return !this.inBlackList(name, content);
      });
    }

    /**
     * @param url
     * @param res
     */
    hookAnswers(url, res) {
      const answers = res.data;
      res.data = answers.filter(answer => {
        var _answer$target, _answer$target2;
        const name = (_answer$target = answer.target) === null || _answer$target === void 0 || (_answer$target = _answer$target.author) === null || _answer$target === void 0 ? void 0 : _answer$target.name;
        const content = (_answer$target2 = answer.target) === null || _answer$target2 === void 0 ? void 0 : _answer$target2.content;
        return !this.inBlackList(name, content);
      });
    }
  }, _defineProperty(_ZhihuFilter, "host", 'zhihu.com'), _ZhihuFilter), (_applyDecoratedDescriptor(_class5.prototype, "interceptAnalytics", [_dec10], Object.getOwnPropertyDescriptor(_class5.prototype, "interceptAnalytics"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "filterComments", [filterFunc], Object.getOwnPropertyDescriptor(_class5.prototype, "filterComments"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "filterAnswerComments", [filterFunc], Object.getOwnPropertyDescriptor(_class5.prototype, "filterAnswerComments"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "filterAnswers", [filterFunc], Object.getOwnPropertyDescriptor(_class5.prototype, "filterAnswers"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "filterRecommends", [filterFunc], Object.getOwnPropertyDescriptor(_class5.prototype, "filterRecommends"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "filterQuestions", [filterFunc], Object.getOwnPropertyDescriptor(_class5.prototype, "filterQuestions"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "hookComments", [_dec11], Object.getOwnPropertyDescriptor(_class5.prototype, "hookComments"), _class5.prototype), _applyDecoratedDescriptor(_class5.prototype, "hookAnswers", [_dec12], Object.getOwnPropertyDescriptor(_class5.prototype, "hookAnswers"), _class5.prototype)), _class5));
  /**
   * @param {Object} data
   * @property {{user_nickname_v2: string}[]} user_list
   * @property {{comment_info: Object[]}[]} comment_list
   * @property {{show_nickname: string}} comment_info
   * */
  function filterTiebaReplies(data) {
    const userMap = 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(reply.show_nickname));
      comment.comment_list_num = replies.length;
      comment.comment_info = replies;
      if (comment.comment_list_num > 0) {
        filtered = {
          ...filtered,
          [postId]: comment
        };
      }
      return filtered;
    }, {});
    return data;
  }
  var _blackUsers = /*#__PURE__*/new WeakMap();
  var _excludePatterns = /*#__PURE__*/new WeakMap();
  var _DomainStore_brand = /*#__PURE__*/new WeakSet();
  class DomainStore {
    static async init() {
      let list = await this.loadBlackList();
      const val = await GM.getValue(DomainStore.patternKey());
      let patterns = [];
      if (typeof val === 'string') {
        patterns = JSON.parse(val);
      }
      return new DomainStore(list, patterns);
    }

    /**
     * @type {Map.<string, boolean>}
     * */

    get userList() {
      return _classPrivateFieldGet(_blackUsers, this).keys();
    }
    get patternList() {
      return _classPrivateFieldGet(_excludePatterns, this);
    }
    matchPattern(text) {
      return _classPrivateFieldGet(_excludePatterns, this).some(pattern => {
        return text.includes(pattern);
      });
    }
    addPattern(text) {
      let s = new Set(_classPrivateFieldGet(_excludePatterns, this)).add(text);
      _classPrivateFieldSet(_excludePatterns, this, [...s]);
      _assertClassBrand(_DomainStore_brand, this, _flush).call(this);
    }
    removePattern(text) {
      _classPrivateFieldSet(_excludePatterns, this, _classPrivateFieldGet(_excludePatterns, this).filter(pattern => {
        return pattern !== text;
      }));
      _assertClassBrand(_DomainStore_brand, this, _flush).call(this);
    }
    hasUser(name) {
      return _classPrivateFieldGet(_blackUsers, this).has(name);
    }
    addUser(name) {
      _classPrivateFieldGet(_blackUsers, this).set(name, true);
      _assertClassBrand(_DomainStore_brand, this, _flush).call(this);
    }
    removeUser(name) {
      _classPrivateFieldGet(_blackUsers, this).delete(name);
      _assertClassBrand(_DomainStore_brand, this, _flush).call(this);
    }
    static userKey() {
      return `${DomainStore.domainKeyPrefix}:users`;
    }
    static patternKey() {
      return `${DomainStore.domainKeyPrefix}:patterns`;
    }
    /**
     * @param {string[]} list
     * */
    constructor(users, patterns) {
      _classPrivateMethodInitSpec(this, _DomainStore_brand);
      _classPrivateFieldInitSpec(this, _blackUsers, void 0);
      /**
       * @type {string[]}
       */
      _classPrivateFieldInitSpec(this, _excludePatterns, []);
      _classPrivateFieldSet(_blackUsers, this, users.reduce((map, user) => {
        return map.set(user, true);
      }, new Map()));
      _classPrivateFieldSet(_excludePatterns, this, patterns);
    }

    // 获取屏蔽词列表
    static async loadBlackList() {
      let value = await GM.getValue(DomainStore.domainKeyPrefix);
      if (!value) return [];
      const ret = JSON.parse(String(value));
      if (!Array.isArray(ret)) return [];
      console.log(`gm value: ${ret}`);
      return ret;
    }
  }
  _DomainStore = DomainStore;
  async function _flush() {
    const val = JSON.stringify([..._classPrivateFieldGet(_blackUsers, this).keys()]);
    await GM.setValue(_DomainStore.domainKeyPrefix, val);
    await GM.setValue(_DomainStore.userKey(), val);
    const pv = JSON.stringify(_classPrivateFieldGet(_excludePatterns, this));
    await GM.setValue(_DomainStore.patternKey(), pv);
  }
  _defineProperty(DomainStore, "NgListKey", 'NgList');
  (() => {
    const domain = document.location.host;
    let segs = domain.split('.');
    if (segs.length > 2) segs = segs.slice(1);
    _DomainStore.domainKeyPrefix = `${segs.join('.')}:${_DomainStore.NgListKey}`;
  })();
  var _store = /*#__PURE__*/new WeakMap();
  var _filter = /*#__PURE__*/new WeakMap();
  class MainView {
    /**
     *
     * @param {DomainStore} store
     * @param {WebsiteFilter} filter
     */
    constructor({
      store,
      filter
    }) {
      /**
       * @member {DomainStore} #store
       * */
      _classPrivateFieldInitSpec(this, _store, void 0);
      /**
       * @member {WebsiteFilter} #filter
       */
      _classPrivateFieldInitSpec(this, _filter, void 0);
      _classPrivateFieldSet(_store, this, store);
      _classPrivateFieldSet(_filter, this, filter);
      addStyle(css); // 添加样式
      window.addEventListener('load', () => {
        // 屏蔽视频播放后的弱智三连语音
        appObserverInit();
      });
    }
    dialogElement() {
      return document.querySelector(MainView.DialogSelector);
    }
    render() {
      setInterval(() => {
        this.renderSettingButton();
        this.renderSettingPanel();
        _classPrivateFieldGet(_filter, this).render();
        this.renderBlockButtons();
      }, 1000);
    }
    async renderBlockButtons() {
      document.querySelectorAll(`${cssByCls(BlockButtonClass)}`).forEach(button => {
        // 点击按钮展示弹窗
        button.addEventListener('click', ev => {
          ev.stopPropagation();
          let name = button.getAttribute('user-name');
          _classPrivateFieldGet(_store, this).addUser(name);
          _classPrivateFieldGet(_filter, this).render();
        });
      });
    }

    /* 生成添加屏蔽关键词的按钮 */
    async renderSettingButton() {
      if (!document.body) {
        return;
      }
      if (document.body.querySelector('#add_ngList_btn')) {
        return;
      }
      const btn = document.createElement('div');
      btn.title = '添加屏蔽关键词';
      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() {
      /* dialog模板 */
      const dialogTemplate = `
      <div class="my-dialog" style="margin-top: 15vh; width: 40%;">
        <div class="my-dialog__header">
          <span class="my-dialog__title">屏蔽词列表</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>添加</span>
            </button>
          </div>
          <div id="ngList"></div>
          <p class="tips">注:1. 可过滤包含屏蔽词的用户、微博、评论、热搜。 2. 关键词保存在本地的local storage中。 3. 更改关键词后刷新页面生效(不刷新页面的情况下,只有之后加载的微博才会生效)。</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) {
          _classPrivateFieldGet(_store, this).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 = [..._classPrivateFieldGet(_store, this).userList];
      for (const [i, pattern] of _classPrivateFieldGet(_store, this).patternList.entries()) {
        blockedUsersHTML += `<span class="ng_item" data-type="pattern">${pattern}<i class="close-icon" data-index=${i}></i></span>`;
      }
      for (const [i, item] of users.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':
                _classPrivateFieldGet(_store, this).removeUser(name);
                break;
              case 'pattern':
                _classPrivateFieldGet(_store, this).removePattern(name);
                break;
            }
            this.renderBlockedUsers();
          });
        }
      }
    }
  }

  // 创建观察器
  _defineProperty(MainView, "DialogSelector", '.my-dialog__wrapper');
  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('移除了弱智三连');
      }
    };

    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver(callback);

    // 以上述配置开始观察目标节点
    observer.observe(targetNode, config);
  }
  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  const store = await DomainStore.init();
  let filter = null;
  const {
    host
  } = document.location;
  [WeiboFilter, HupuFilter, TiebaFilter, ZhihuFilter, BilibiliFilter].forEach(f => {
    if (filter) {
      return;
    }
    if (host.includes(f.host)) {
      filter = new f(store);
    }
  });
  const controller = new MainView({
    store,
    filter
  });
  controller.render();
})();