Greasy Fork

Greasy Fork is available in English.

哔哩哔哩屏蔽增强器

对B站视频或评论进行屏蔽,支持关键词模糊正则等,支持时长播放弹幕过滤等,如视频、评论、动态、直播间的评论等,详情可看下面支持的屏蔽类型

当前为 2025-04-06 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        哔哩哔哩屏蔽增强器
// @namespace   http://tampermonkey.net/
// @license     Apache-2.0
// @version     2.9.1
// @author      byhgz
// @description 对B站视频或评论进行屏蔽,支持关键词模糊正则等,支持时长播放弹幕过滤等,如视频、评论、动态、直播间的评论等,详情可看下面支持的屏蔽类型
// @icon        https://static.hdslb.com/images/favicon.ico
// @noframes    
// @run-at      document-start
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_deleteValue
// @grant       GM_addStyle
// @grant       GM_unregisterMenuCommand
// @grant       GM_registerMenuCommand
// @grant       GM_openInTab
// @exclude     *://message.bilibili.com/pages/nav/header_sync
// @exclude     *://message.bilibili.com/pages/nav/index_new_pc_sync
// @exclude     *://live.bilibili.com/blackboard/dropdown-menu.html
// @exclude     *://live.bilibili.com/p/html/live-web-mng/*
// @exclude     *://www.bilibili.com/correspond/*
// @match       *://search.bilibili.com/*
// @match       *://t.bilibili.com/*
// @match       *://space.bilibili.com/*
// @match       *://live.bilibili.com/*
// @match       *://www.bilibili.com/*
// @require     https://cdn.jsdelivr.net/npm/vue@2
// @require     https://unpkg.com/element-ui/lib/index.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/dist/dexie.min.js
// @require     https://update.greasyfork.icu/scripts/517928/gz_ui_css-v1.js
// @source      https://gitee.com/hangexi/BiBiBSPUserVideoMonkeyScript
// homepage     https://scriptcat.org/zh-CN/script-show-page/1029
// ==/UserScript==
"use strict";
(function (Vue, Dexie) {
    'use strict';
    var gmUtil = {
        setData(key, content) {
            GM_setValue(key, content);
        },
        getData(key, defaultValue) {
            return GM_getValue(key, defaultValue);
        },
        delData(key) {
            if (!this.isData(key)) {
                return false;
            }
            GM_deleteValue(key);
            return true;
        },
        isData(key) {
            return this.getData(key) !== undefined;
        },
        addStyle(style) {
            GM_addStyle(style);
        },
        addGMMenu(text, func, shortcutKey = null) {
            return GM_registerMenuCommand(text, func, shortcutKey);
        },
        openInTab(url, options = {active: true, insert: true, setParent: true}) {
            GM_openInTab(url, options);
        }
    };
    class EventEmitter {
        #regularEvents = {
            events: {},
            futures: {}
        }
        #callbackEvents = {
            events: {},
            callbackInterval: 1500
        }
        on(eventName, callback) {
            const events = this.#regularEvents.events;
            if (events[eventName]) {
                events[eventName].push(callback);
                return
            }
            events[eventName] = [];
            events[eventName].push(callback);
            const futureEvents = this.#regularEvents.futures;
            if (futureEvents[eventName]) {
                for (const futureEvent of futureEvents[eventName]) {
                    callback(...futureEvent);
                }
                delete futureEvents[eventName];
            }
        }
        once(eventName, callback) {
            const onceCallback = (...args) => {
                callback(...args);
                this.#removeCallback(eventName, onceCallback);
            };
            this.on(eventName, onceCallback);
        }
        handler(eventName, callback) {
            const handlerEvents = this.#callbackEvents.events;
            if (handlerEvents[eventName]) {
                throw new Error('该事件名已经存在,请更换事件名')
            }
            handlerEvents[eventName] = callback;
        }
        invoke(eventName, ...data) {
            return new Promise(resolve => {
                const handlerEvents = this.#callbackEvents.events;
                if (handlerEvents[eventName]) {
                    resolve(handlerEvents[eventName](...data));
                    return
                }
                const i1 = setInterval(() => {
                    if (handlerEvents[eventName]) {
                        clearInterval(i1);
                        resolve(handlerEvents[eventName](...data));
                    }
                }, this.#callbackEvents.callbackInterval);
            })
        }
        send(eventName, ...data) {
            const ordinaryEvents = this.#regularEvents;
            const events = ordinaryEvents.events;
            const event = events[eventName];
            if (event) {
                for (const callback of event) {
                    callback(...data);
                }
                return;
            }
            const futures = ordinaryEvents.futures;
            if (futures[eventName]) {
                futures[eventName].push(data);
                return;
            }
            futures[eventName] = [];
            futures[eventName].push(data);
        }
        #removeCallback(eventName, callback) {
            const events = this.#regularEvents.events;
            if (events[eventName]) {
                events[eventName] = events[eventName].filter(cb => cb !== callback);
            }
            const handlerEvents = this.#callbackEvents.events;
            if (handlerEvents[eventName]) {
                handlerEvents[eventName] = handlerEvents[eventName].filter(cb => cb !== callback);
            }
        }
        off(eventName) {
            const events = this.#regularEvents.events;
            if (events[eventName]) {
                delete events[eventName];
                return true
            }
            const handlerEvents = this.#callbackEvents.events;
            if (handlerEvents[eventName]) {
                delete handlerEvents[eventName];
                return true
            }
            return false
        }
        setInvokeInterval(interval) {
            this.#callbackEvents.callbackInterval = interval;
        }
        getEvents() {
            return {
                regularEvents: this.#regularEvents,
                callbackEvents: this.#callbackEvents
            }
        }
    }
    const eventEmitter = new EventEmitter();
    const setBorderColor = (color) => {
        gmUtil.setData("borderColor", color);
    };
    const defBorderColor = "rgb(0, 243, 255)";
    const getBorderColor = () => {
        return gmUtil.getData("borderColor", defBorderColor)
    };
    const setOutputInformationFontColor = (color) => {
        gmUtil.setData("output_information_font_color", color);
    };
    const defOutputInformationFontColor = "rgb(119,128,248)";
    const getOutputInformationFontColor = () => {
        return gmUtil.getData("output_information_font_color", defOutputInformationFontColor)
    };
    const setHighlightInformationColor = (color) => {
        gmUtil.setData("highlight_information_color", color);
    };
    const defHighlightInformationColor = "rgb(234, 93, 93)";
    const getHighlightInformationColor = () => {
        return gmUtil.getData("highlight_information_color", defHighlightInformationColor);
    };
    const setDefaultColorInfo = () => {
        setBorderColor(defBorderColor);
        setOutputInformationFontColor(defOutputInformationFontColor);
        setHighlightInformationColor(defHighlightInformationColor);
    };
    const getBOnlyTheHomepageIsBlocked = () => {
        return gmUtil.getData("bOnlyTheHomepageIsBlocked", false);
    };
    const getAdaptationBAppCommerce = () => {
        return gmUtil.getData("adaptation-b-app-recommend", false) === true;
    };
    const isShowRightTopMainButSwitch = () => {
        return gmUtil.getData("showRightTopMainButSwitch", true) === true;
    };
    const isFirstFullDisplay = () => {
        return gmUtil.getData('isFirstFullDisplay', true) === true
    };
    const isHalfHiddenIntervalAfterInitialDisplay = () => {
        return gmUtil.getData('is_half_hidden_interval_after_initial_display', true) === true
    };
    const isCompatible_BEWLY_BEWLY = () => {
        return gmUtil.getData("compatible_BEWLY_BEWLY", false) === true;
    };
    const isDiscardOldCommentAreas = () => {
        return gmUtil.getData("discardOldCommentAreas", false) === true;
    };
    const isDelPlayerPageRightVideoList = () => {
        return gmUtil.getData("isDelPlayerPageRightVideoList", false) === true
    };
    const bFuzzyAndRegularMatchingWordsToLowercase$1 = () => {
        return gmUtil.getData("bFuzzyAndRegularMatchingWordsToLowercase", false)
    };
    const isRequestFrequencyVal = () => {
        return gmUtil.getData("requestFrequencyVal", 0.2)
    };
    const isDisableNetRequestsBvVideoInfo = () => {
        return gmUtil.getData('isDisableNetRequestsBvVideoInfo', false)
    };
    const isBlockFollowed = () => {
        return gmUtil.getData('blockFollowed', false)
    };
    const isUpOwnerExclusive = () => {
        return gmUtil.getData('is_up_owner_exclusive', false)
    };
    const isGenderRadioVal = () => {
        return gmUtil.getData('genderRadioVal', '不处理');
    };
    const isVipTypeRadioVal = () => {
        return gmUtil.getData('vipTypeRadioVal', '不处理');
    };
    const isSeniorMember = () => {
        return gmUtil.getData('is_senior_member', false)
    };
    const isCopyrightRadio = () => {
        return gmUtil.getData('copyrightRadioVal', '不处理');
    };
    const isDelBottomComment = () => {
        return gmUtil.getData('isDelBottomComment', false)
    };
    const isBlockVerticalVideo = () => {
        return gmUtil.getData('blockVerticalVideo', false)
    };
    const isCheckTeamMember = () => {
        return gmUtil.getData('checkTeamMember', false)
    };
    const getVideoLikeRate = () => {
        return gmUtil.getData('video_like_rate', 0.05)
    };
    const isVideoLikeRateBlockingStatus = () => {
        return gmUtil.getData('video_like_rate_blocking_status', false)
    };
    const isCoinLikesRatioRateBlockingStatus = () => {
        return gmUtil.getData('coin_likes_ratio_rate_blocking_status', false)
    };
    const getCoinLikesRatioRate = () => {
        return gmUtil.getData('coin_likes_ratio_rate', 0.05)
    };
    const isCoinLikesRatioRateDisabled = () => {
        return gmUtil.getData('coin_likes_ratio_rate_blocking_status', false)
    };
    const isInteractiveRateBlockingStatus = () => {
        return gmUtil.getData('interactive_rate_blocking_status', false)
    };
    const getInteractiveRate = () => {
        return gmUtil.getData('interactive_rate', 0.05)
    };
    const isTripleRateBlockingStatus = () => {
        return gmUtil.getData('triple_rate_blocking_status', false)
    };
    const getTripleRate = () => {
        return gmUtil.getData('triple_rate', 0.05)
    };
    const getUidRangeMasking = () => {
        return gmUtil.getData('uid_range_masking', [0, 100])
    };
    const isUidRangeMaskingStatus = () => {
        return gmUtil.getData('uid_range_masking_status', false)
    };
    const isTimeRangeMaskingStatus = () => {
        return gmUtil.getData('time_range_masking_status', false)
    };
    const getTimeRangeMaskingArr = () => {
        return gmUtil.getData('time_range_masking', [])
    };
    const isDelPlayerEndingPanel = () => {
        return gmUtil.getData('is_del_player_ending_panel', false)
    };
    const isOpenDev = () => {
        return gmUtil.getData('open-dev', false)
    };
    const setOpenDev = (bool) => {
        gmUtil.setData('open-dev', bool);
    };
    const getCommentWordLimitVal = () => {
        return gmUtil.getData('comment_word_limit', -1)
    };
    const getSubstituteWordsArr = () => {
        return gmUtil.getData('substitute_words', [])
    };
    const isClearCommentEmoticons = () => {
        return gmUtil.getData('is_clear_comment_emoticons', false)
    };
    const isReplaceCommentSearchTerms = () => {
        return gmUtil.getData('is_replace_comment_search_terms', false)
    };
    const enableReplacementProcessing = () => {
        return gmUtil.getData('enable_replacement_processing', false)
    };
    var localMKData = {
        getTripleRate,
        isTripleRateBlockingStatus,
        setBorderColor,
        getBorderColor,
        setOutputInformationFontColor,
        getOutputInformationFontColor,
        setHighlightInformationColor,
        getHighlightInformationColor,
        getBOnlyTheHomepageIsBlocked,
        getAdaptationBAppCommerce,
        setDefaultColorInfo,
        isCompatible_BEWLY_BEWLY,
        isDiscardOldCommentAreas,
        isShowRightTopMainButSwitch,
        isFirstFullDisplay,
        isHalfHiddenIntervalAfterInitialDisplay,
        isDelPlayerPageRightVideoList,
        bFuzzyAndRegularMatchingWordsToLowercase: bFuzzyAndRegularMatchingWordsToLowercase$1,
        isRequestFrequencyVal,
        isDisableNetRequestsBvVideoInfo,
        isBlockFollowed,
        isUpOwnerExclusive,
        isGenderRadioVal,
        isVipTypeRadioVal,
        isSeniorMember,
        isCopyrightRadio,
        isDelBottomComment,
        isBlockVerticalVideo,
        isCheckTeamMember,
        getVideoLikeRate,
        isVideoLikeRateBlockingStatus,
        isCoinLikesRatioRateBlockingStatus,
        getCoinLikesRatioRate,
        isCoinLikesRatioRateDisabled,
        isInteractiveRateBlockingStatus,
        getInteractiveRate,
        getUidRangeMasking,
        isUidRangeMaskingStatus,
        isTimeRangeMaskingStatus,
        isDelPlayerEndingPanel,
        getTimeRangeMaskingArr,
        getCommentWordLimitVal
    };
    const group_url = 'http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=tFU0xLt1uO5u5CXI2ktQRLh_XGAHBl7C&authKey=KAf4rICQYjfYUi66WelJAGhYtbJLILVWumOm%2BO9nM5fNaaVuF9Iiw3dJoPsVRUak&noverify=0&group_code=876295632';
    const scriptCat_js_url = 'https://scriptcat.org/zh-CN/script-show-page/1029';
    const b_url = 'https://space.bilibili.com/473239155';
    const common_question_url = 'https://docs.qq.com/doc/DSlJNR1NVcGR3eEto';
    const update_log_url = 'https://docs.qq.com/doc/DSnhjSVZmRkpCd0Nj';
    const adaptationBAppCommerce = localMKData.getAdaptationBAppCommerce();
    const compatibleBEWLYBEWLY = localMKData.isCompatible_BEWLY_BEWLY();
    const bOnlyTheHomepageIsBlocked = localMKData.getBOnlyTheHomepageIsBlocked();
    const returnTempVal = {state: false};
    var globalValue = {
        group_url,
        scriptCat_js_url,
        b_url,
        common_question_url,
        update_log_url,
        adaptationBAppCommerce,
        compatibleBEWLYBEWLY,
        bOnlyTheHomepageIsBlocked
    };
    gmUtil.addGMMenu('主面板', () => {
        eventEmitter.send('主面板开关');
    }, 'Q');
    gmUtil.addGMMenu('脚本猫脚本更新页', () => {
        gmUtil.openInTab(globalValue.scriptCat_js_url);
    }, 'E');
    gmUtil.addGMMenu('gf脚本更新页', () => {
        gmUtil.openInTab('http://greasyfork.icu/zh-CN/scripts/461382');
    }, 'W');
    gmUtil.addGMMenu('加入or反馈', () => {
        gmUtil.openInTab(globalValue.group_url);
    }, "T");
    gmUtil.addGMMenu('常见问题', () => {
        gmUtil.openInTab(globalValue.common_question_url);
    }, 'Y');
    gmUtil.addGMMenu('更新日志', () => {
        gmUtil.openInTab(globalValue.update_log_url);
    }, 'U');
    const start = () => {
        let loop = false;
        let msg;
        if (!Vue) {
            loop = true;
            msg = 'Vue is not defined,Vue未定义,请检查是否引入了Vue';
        }
        if (!Dexie) {
            loop = true;
            msg = 'Dexie is not defined,Dexie未定义,请检查是否引入了Dexie';
        }
        if (loop) {
            if (confirm('外部库验证失败:' + msg + `\n请联系作者核查问题\n可通过点击确定按钮跳转。
        \n脚本主页信息中,有相关解决文档
        \n或通过脚本信息底下联系方式联系作者解决`)) {
                gmUtil.openInTab(globalValue.scriptCat_js_url);
                gmUtil.openInTab(globalValue.group_url);
            }
            throw new Error(`外部库验证失败:${msg}`)
        }
    };
    start();
    const panel_settings_vue = {
        template: `
      <div>
        <el-card shadow="never">
          <template #header>
            <span>颜色设置</span>
          </template>
          <div class="el-horizontal-center">
            选择器
            <el-color-picker v-model="input_color"/>
          </div>
          <el-button @click="setBorderColorBut">设置边框色</el-button>
          <el-button @click="setDefFontColorForOutputInformationBut">设置输出信息默认字体色</el-button>
          <el-button @click="setTheFontColorForOutputInformationBut">设置输出信息高亮字体色</el-button>
          <el-tooltip content="刷新页面生效">
            <el-button @click="setDefInfoBut">恢复默认</el-button>
          </el-tooltip>
        </el-card>
        <el-card shadow="never">
          <template #header>
            <span>页面右侧悬浮按钮设置</span>
          </template>
          <el-switch v-model="showRightTopMainButSwitch" active-text="显示按钮"></el-switch>
          <el-tooltip content="页面每次加载完之后是否完整展示按钮,否则半隐藏">
            <el-switch v-model="isFirstFullDisplay" active-text="初次完整显示"></el-switch>
          </el-tooltip>
          <el-tooltip content="页面每次加载完之后如完整展示按钮时,间隔10秒后半隐藏处理">
            <el-switch v-model="isHalfHiddenIntervalAfterInitialDisplay"
                       active-text="初次显示后间隔半隐藏"/>
          </el-tooltip>
        </el-card>
        <el-card shadow="never">
          <template #header>
            <span>说明</span>
          </template>
          <div>按键盘tab键上的~键为展开关闭主面板</div>
        </el-card>
        <el-card shadow="never">
          <template #header>
            <span>devTools</span>
          </template>
          <el-input v-model.trim="devToolsInputVal" @keyup.enter.native="changeDevToolsInput"></el-input>
        </el-card>
      </div>`,
        data() {
            return {
                input_color: null,
                showRightTopMainButSwitch: localMKData.isShowRightTopMainButSwitch(),
                isFirstFullDisplay: localMKData.isFirstFullDisplay(),
                isHalfHiddenIntervalAfterInitialDisplay: localMKData.isHalfHiddenIntervalAfterInitialDisplay(),
                devToolsInputVal: ''
            }
        },
        methods: {
            setBorderColorBut() {
                this.$confirm('是否设置面板边框颜色', '提示').then(() => {
                    localMKData.setBorderColor(this.input_color);
                    this.$alert("已设置面板边框颜色,刷新生效");
                });
            },
            setDefFontColorForOutputInformationBut() {
                this.$confirm("是否设置输出信息默认字体颜色", "提示").then(() => {
                    localMKData.setOutputInformationFontColor(this.input_color);
                    this.$alert("已设置输出信息默认字体颜色,刷新生效");
                });
            },
            setTheFontColorForOutputInformationBut() {
                this.$confirm('是要设置输出信息高亮字体颜色吗?').then(() => {
                    localMKData.setHighlightInformationColor(this.input_color);
                    this.$alert("已设置输出信息高亮字体颜色,刷新生效");
                });
            },
            setDefInfoBut() {
                localMKData.setDefaultColorInfo();
                this.$alert("已恢复默认颜色,刷新生效");
            },
            changeDevToolsInput() {
                const toolsInputVal = this.devToolsInputVal;
                if (toolsInputVal === 'show-dev') {
                    setOpenDev(true);
                    eventEmitter.send('debugger-dev-show', true);
                    this.devToolsInputVal = '';
                    return
                }
                if (toolsInputVal === 'stop-dev') {
                    setOpenDev(false);
                    eventEmitter.send('debugger-dev-show', false);
                    this.devToolsInputVal = '';
                    return;
                }
                if (isOpenDev()) {
                    eventEmitter.send(toolsInputVal);
                }
            }
        },
        watch: {
            showRightTopMainButSwitch(newVal) {
                gmUtil.setData("showRightTopMainButSwitch", newVal === true);
                eventEmitter.send('显隐主面板开关', newVal);
            },
            isFirstFullDisplay(newVal) {
                gmUtil.setData('isFirstFullDisplay', newVal === true);
            },
            isHalfHiddenIntervalAfterInitialDisplay(newBool) {
                gmUtil.setData('is_half_hidden_interval_after_initial_display', newBool === true);
            }
        }
    };
    const getSelectOptions = () => {
        const options = [
            {
                value: '模糊匹配',
                label: '模糊匹配',
                children: []
            },
            {
                value: '正则匹配',
                label: '正则匹配',
                children: []
            },
            {
                value: '多重匹配',
                label: '多重匹配',
                children: []
            },
            {
                value: '精确匹配',
                label: '精确匹配',
                children: []
            }
        ];
        for (let {name, key} of ruleKeyListData) {
            let children;
            if (name.includes('(模糊匹配)')) {
                children = options[0].children;
            }
            if (name.includes('(正则匹配)')) {
                children = options[1].children;
            }
            if (name.includes('(组合精确匹配)')) {
                children = options[2].children;
            }
            if (name.includes('(精确匹配)')) {
                children = options[3].children;
            }
            children.push({
                value: key,
                label: name
            });
        }
        return options
    };
    const ruleKeyListData = [{
        key: "name",
        name: "用户名(模糊匹配)",
        oldKey: "userNameKeyArr",
        oldName: "用户名黑名单模式(模糊匹配)"
    }, {
        key: "precise_name",
        name: "用户名(精确匹配)",
        oldKey: "userNameArr",
        oldName: "用户名黑名单模式(精确匹配)"
    }, {
        key: "nameCanonical",
        name: "用户名(正则匹配)"
    }, {
        key: "precise_uid",
        name: "用户uid(精确匹配)",
        oldKey: "userUIDArr",
        oldName: "用户uid黑名单模式(精确匹配)"
    }, {
        key: "precise_uid_white",
        name: "用户uid白名单(精确匹配)",
        oldKey: "userWhiteUIDArr",
        oldName: "用户uid白名单模式(精确匹配)"
    }, {
        key: "title",
        name: "标题(模糊匹配)",
        oldKey: "titleKeyArr",
        oldName: "标题黑名单模式(模糊匹配)"
    }, {
        key: "titleCanonical",
        name: "标题(正则匹配)",
        oldKey: "titleKeyCanonicalArr",
        oldName: "标题黑名单模式(正则匹配)"
    }, {
        key: "commentOn",
        name: "评论关键词(模糊匹配)",
        oldKey: "commentOnKeyArr",
        oldName: "评论关键词黑名单模式(模糊匹配)"
    }, {
        key: "commentOnCanonical",
        name: "评论关键词(正则匹配)",
        oldKey: "contentOnKeyCanonicalArr",
        oldName: "评论关键词黑名单模式(正则匹配)"
    }, {
        key: "precise_fanCard",
        name: "粉丝牌(精确匹配)",
        oldKey: "fanCardArr",
        oldName: "粉丝牌黑名单模式(精确匹配)"
    }, {
        key: "dynamic",
        name: "动态关键词(模糊匹配)",
        oldKey: "dynamicArr",
        oldName: "动态关键词内容黑名单模式(模糊匹配)"
    }, {
        key: "precise_tag",
        name: "话题tag标签(精确匹配)",
    }, {
        key: "tag",
        name: "话题tag标签(模糊匹配)",
    }, {
        key: "tagCanonical",
        name: "话题tag标签(正则匹配)"
    }, {
        key: "precise_partition",
        name: "直播分区(精确匹配)"
    }, {
        key: 'videoTag',
        name: '视频tag(模糊匹配)',
    }, {
        key: 'precise_videoTag',
        name: '视频tag(精确匹配)',
    }, {
        key: 'videoTagCanonical',
        name: '视频tag(正则匹配)',
    }, {
        key: 'videoTag_preciseCombination',
        name: '视频tag(组合精确匹配)'
    }, {
        key: 'hotSearchKey',
        name: '热搜关键词(模糊匹配)',
    }, {
        key: 'hotSearchKeyCanonical',
        name: '热搜关键词(正则匹配)'
    }, {
        key: 'precise_avatarPendantName',
        name: '头像挂件名(精确匹配)'
    }, {
        key: 'avatarPendantName',
        name: '头像挂件名(模糊匹配)'
    }, {
        key: 'signature',
        name: '用户签名(模糊匹配)'
    }, {
        key: 'signatureCanonical',
        name: '用户签名(正则匹配)'
    }, {
        key: 'videoDesc',
        name: '视频简介(模糊匹配)'
    }, {
        key: 'videoDescCanonical',
        name: '视频简介(正则匹配)'
    }, {
        key: 'precise_video_bv',
        name: '视频bv号(精确匹配)'
    }
    ];
    const otherKeyListData = [
        {
            name: '最小播放量',
            value: 'nMinimumPlay',
            associated: 'nMaximumPlayback',
            defVal: -1
        },
        {
            name: '最大播放量',
            value: 'nMaximumPlayback',
            associated: 'nMinimumPlay',
            bLarge: true,
            defVal: -1
        },
        {
            name: '最小弹幕数',
            value: 'nMinimumBarrage',
            associated: 'nMaximumBarrage',
            defVal: -1
        },
        {
            name: '最大弹幕数',
            value: 'nMaximumBarrage',
            associated: 'nMinimumBarrage',
            bLarge: true,
            defVal: -1
        },
        {
            name: '最小时长',
            value: 'nMinimumDuration',
            associated: 'nMaximumDuration',
            defVal: -1
        },
        {
            name: '最大时长',
            value: 'nMaximumDuration',
            associated: 'nMinimumDuration',
            bLarge: true,
            defVal: -1
        },
        {
            name: '最小用户等级过滤',
            value: 'nMinimumLevel',
            associated: 'nMaximumLevel',
            defVal: -1
        },
        {
            name: '最大用户等级过滤',
            value: 'nMaximumLevel',
            associated: 'nMinimumLevel',
            bLarge: true,
            defVal: -1
        }
    ];
    const getRuleKeyListData = () => {
        return ruleKeyListData;
    };
    const getRuleKeyList = () => {
        return ruleKeyListData.map(item => {
            return item.key
        })
    };
    const getNameArr = () => {
        return gmUtil.getData("name", []);
    };
    const getPreciseNameArr = () => {
        return gmUtil.getData("precise_name", []);
    };
    const getNameCanonical = () => {
        return gmUtil.getData("nameCanonical", []);
    };
    const getPreciseUidArr = () => {
        return gmUtil.getData("precise_uid", []);
    };
    const getPreciseUidWhiteArr = () => {
        return gmUtil.getData("precise_uid_white", []);
    };
    const getTitleArr = () => {
        return gmUtil.getData("title", []);
    };
    const getTitleCanonicalArr = () => {
        return gmUtil.getData("titleCanonical", []);
    };
    const getCommentOnArr = () => {
        return gmUtil.getData("commentOn", []);
    };
    const getCommentOnCanonicalArr = () => {
        return gmUtil.getData("commentOnCanonical", []);
    };
    const getPreciseTagArr = () => {
        return gmUtil.getData("precise_tag", []);
    };
    const getTagArr = () => {
        return gmUtil.getData("tag", []);
    };
    const getTagCanonicalArr = () => {
        return gmUtil.getData("tagCanonical", []);
    };
    const getPreciseFanCardArr = () => {
        return gmUtil.getData("precise_fanCard", []);
    };
    const getPrecisePartitionArr = () => {
        return gmUtil.getData("precise_partition", []);
    };
    const getVideoTagArr = () => {
        return gmUtil.getData("videoTag", []);
    };
    const getPreciseVideoTagArr = () => {
        return gmUtil.getData("precise_videoTag", []);
    };
    const getVideoTagCanonicalArr = () => {
        return gmUtil.getData("videoTagCanonical", []);
    };
    const getHotSearchKeyArr = () => {
        return gmUtil.getData("hotSearchKey", []);
    };
    const getHotSearchKeyCanonicalArr = () => {
        return gmUtil.getData("hotSearchKeyCanonical", []);
    };
    const clearKeyItem = (ruleKey) => {
        gmUtil.delData(ruleKey);
    };
    const getVideoTagPreciseCombination = () => {
        return gmUtil.getData("videoTag_preciseCombination", []);
    };
    const setVideoTagPreciseCombination = (list) => {
        gmUtil.setData("videoTag_preciseCombination", list);
    };
    const getPreciseVideoBV = () => {
        return gmUtil.getData("precise_video_bv", []);
    };
    var ruleKeyListData$1 = {
        getNameArr,
        getPreciseNameArr,
        getNameCanonical,
        getPreciseUidArr,
        getPreciseUidWhiteArr,
        getTitleArr,
        getTitleCanonicalArr,
        getCommentOnArr,
        getCommentOnCanonicalArr,
        getRuleKeyListData,
        getPreciseTagArr,
        getTagArr,
        getTagCanonicalArr,
        getPreciseFanCardArr,
        getPrecisePartitionArr,
        getVideoTagArr,
        getPreciseVideoTagArr,
        getVideoTagCanonicalArr,
        getHotSearchKeyArr,
        getHotSearchKeyCanonicalArr,
        otherKeyListData,
        clearKeyItem,
        getSelectOptions,
        getVideoTagPreciseCombination,
        setVideoTagPreciseCombination,
        getRuleKeyList,
        getPreciseVideoBV
    };
    const verificationInputValue = (ruleValue, type) => {
        if (ruleValue === null) return {status: false, res: '内容不能为空'};
        if (type === "precise_uid" || type === "precise_uid_white") {
            ruleValue = parseInt(ruleValue);
            if (isNaN(ruleValue)) {
                return {
                    status: false,
                    res: '请输入数字!'
                };
            }
        } else {
            ruleValue.trim();
        }
        if (ruleValue === '') {
            return {status: false, res: '内容不能为空'};
        }
        return {status: true, res: ruleValue};
    };
    const addRule = (ruleValue, type) => {
        const verificationRes = verificationInputValue(ruleValue, type);
        if (!verificationRes.status) {
            return verificationRes
        }
        const arr = gmUtil.getData(type, []);
        if (arr.includes(verificationRes.res)) {
            return {status: false, res: '已存在此内容'};
        }
        arr.push(verificationRes.res);
        gmUtil.setData(type, arr);
        return {status: true, res: '添加成功'};
    };
    const showAddRuleInput = async (type) => {
        let ruleValue;
        try {
            const {value} = await eventEmitter.invoke('el-prompt', '请输入要添加的规则内容', 'tip');
            ruleValue = value;
        } catch (e) {
            return
        }
        const {res, status} = addRule(ruleValue, type);
        eventEmitter.send('el-msg', res);
        status && eventEmitter.send('刷新规则信息');
        status && eventEmitter.send('通知屏蔽');
    };
    const delRule = (type, value) => {
        const verificationRes = verificationInputValue(value, type);
        if (!verificationRes.status) {
            return verificationRes
        }
        const {res} = verificationRes;
        const arr = gmUtil.getData(type, []);
        const indexOf = arr.indexOf(res);
        if (indexOf === -1) {
            return {status: false, res: '不存在此内容'};
        }
        arr.splice(indexOf, 1);
        gmUtil.setData(type, arr);
        return {status: true, res: "移除成功"}
    };
    const showDelRuleInput = async (type) => {
        let ruleValue;
        try {
            const {value} = await eventEmitter.invoke('el-prompt', '请输入要删除的规则内容', '删除指定规则');
            ruleValue = value;
        } catch (e) {
            return
        }
        const {status, res} = delRule(type, ruleValue);
        eventEmitter.send('el-msg', res);
        status && eventEmitter.send('刷新规则信息');
    };
    const getRuleContent = (space = 0) => {
        const ruleMap = {};
        for (let ruleKeyListDatum of ruleKeyListData$1.getRuleKeyListData()) {
            const key = ruleKeyListDatum.key;
            ruleMap[key] = gmUtil.getData(key, []);
        }
        return JSON.stringify(ruleMap, null, space);
    };
    const verificationRuleMap = (keyArr, content) => {
        let parse;
        try {
            parse = JSON.parse(content);
        } catch (e) {
            alert('规则内容有误');
            return false;
        }
        const newRule = {};
        for (const key in parse) {
            if (!Array.isArray(parse[key])) {
                continue;
            }
            if (parse[key].length === 0) {
                continue;
            }
            newRule[key] = parse[key];
        }
        if (Object.keys(newRule).length === 0) {
            alert('规则内容为空');
            return false;
        }
        return newRule;
    };
    const overwriteImportRules = (content) => {
        const map = verificationRuleMap(ruleKeyListData$1.getRuleKeyList(), content);
        if (map === false) return false;
        for (let key of Object.keys(map)) {
            gmUtil.setData(key, map[key]);
        }
        return true;
    };
    const appendImportRules = (content) => {
        const map = verificationRuleMap(ruleKeyListData$1.getRuleKeyList(), content);
        if (map === false) return false;
        for (let key of Object.keys(map)) {
            const arr = gmUtil.getData(key, []);
            for (let item of map[key]) {
                if (!arr.includes(item)) {
                    arr.push(item);
                }
            }
            gmUtil.setData(key, arr);
        }
        return true;
    };
    const overwriteImportRulesV1 = (content) => {
        let parse;
        try {
            parse = JSON.parse(content);
        } catch (e) {
            alert('规则内容有误');
            return false;
        }
        for (let ruleKeyListDatum of ruleKeyListData$1.getRuleKeyListData()) {
            const name = ruleKeyListDatum.oldName;
            const jsonRuleList = parse[name];
            if (!jsonRuleList) {
                continue;
            }
            if (jsonRuleList.length === 0) {
                continue;
            }
            gmUtil.setData(ruleKeyListDatum.key, jsonRuleList);
        }
        return true;
    };
    const addRulePreciseUid = (uid, isTip = true) => {
        const results = addRule(uid, "precise_uid");
        if (isTip) {
            eventEmitter.send('el-notify', {
                title: '添加精确uid操作提示',
                message: results.res
            });
            return results
        }
        return results;
    };
    const delRUlePreciseUid = (uid, isTip = true) => {
        const results = delRule('precise_uid', uid);
        if (isTip) {
            eventEmitter.send('el-alert', results.res);
            return null
        }
        return results
    };
    const addRulePreciseName = (name, tip = true) => {
        const results = addRule(name, "precise_name");
        if (tip) {
            eventEmitter.send('el-msg', results.res);
        }
        return results;
    };
    const findRuleItemValue = (type, value) => {
        return gmUtil.getData(type, []).find(item => item === value) || null
    };
    const addItemRule = (arr, key, coverage = true) => {
        const complianceList = [];
        for (let v of arr) {
            const {status, res} = verificationInputValue(v, key);
            if (!status) return {status: false, msg: `内容中有误:${res}`}
            complianceList.push(v);
        }
        if (coverage) {
            gmUtil.setData(key, complianceList);
            return {status: true, msg: `添加成功-覆盖模式,数量:${complianceList.length}`}
        }
        const oldArr = gmUtil.getData(key, []);
        const newList = complianceList.filter(item => !oldArr.includes(item));
        if (newList.length === 0) {
            return {status: false, msg: '内容重复'}
        }
        gmUtil.setData(key, oldArr.concat(newList));
        return {status: true, msg: '添加成功-追加模式,新增数量:' + newList.length}
    };
    const addPreciseUidItemRule = (uidArr, isTip = true, coverage = true) => {
        const {status, msg} = addItemRule(uidArr, 'precise_uid', coverage);
        if (isTip) {
            eventEmitter.send('el-alert', msg);
            return status
        }
        return {status, msg}
    };
    var ruleUtil = {
        addRule,
        showAddRuleInput,
        showDelRuleInput,
        getRuleContent,
        overwriteImportRules,
        appendImportRules,
        overwriteImportRulesV1,
        addRulePreciseUid,
        addRulePreciseName,
        delRUlePreciseUid,
        findRuleItemValue,
        addItemRule,
        addPreciseUidItemRule
    };
    const rule_set_value_dialog = {
        template: `
      <div>
      <el-dialog :visible="show" width="30%" title="修改单项规则值"
                 :close-on-click-modal="false" :modal="false">
        {{ ruleName }}-{{ ruleType }}
        <el-form>
          <el-form-item label="要修改的值">
            <el-input type="text" v-model="oldVal" clearable/>
          </el-form-item>
          <el-form-item label="修改后的值">
            <el-input v-model="newVal" clearable/>
          </el-form-item>
        </el-form>
        <template #footer class="dialog-footer">
          <el-button @click="show=false">取消</el-button>
          <el-button @click="okBut">确定</el-button>
        </template>
      </el-dialog>
      </div>`,
        data() {
            return {
                show: false,
                ruleType: "",
                ruleName: "",
                oldVal: '',
                newVal: ''
            }
        },
        methods: {
            okBut() {
                let tempOldVal = this.oldVal.trim();
                let tempNewVal = this.newVal.trim();
                if (tempOldVal.length === 0 || tempNewVal.length === 0) {
                    this.$alert("请输入要修改的值或新值");
                    return
                }
                if (tempNewVal === tempOldVal) {
                    this.$alert("新值不能和旧值相同");
                    return;
                }
                const tempRuleType = this.ruleType;
                if (tempRuleType === 'precise_uid' || tempRuleType === 'precise_uid_white') {
                    tempOldVal = parseInt(tempOldVal);
                    tempNewVal = parseInt(tempNewVal);
                    if (isNaN(tempOldVal) || isNaN(tempNewVal)) {
                        this.$alert("请输入整数数字");
                        return
                    }
                }
                if (!ruleUtil.findRuleItemValue(tempRuleType, tempOldVal)) {
                    this.$alert("要修改的值不存在");
                    return;
                }
                if (ruleUtil.findRuleItemValue(tempRuleType, tempNewVal)) {
                    this.$alert("新值已存在");
                    return;
                }
                const ruleArr = gmUtil.getData(tempRuleType, []);
                const indexOf = ruleArr.indexOf(tempOldVal);
                ruleArr[indexOf] = tempNewVal;
                gmUtil.setData(tempRuleType, ruleArr);
                this.$alert(`已将旧值【${tempOldVal}】修改成【${tempNewVal}】`);
                this.show = false;
            }
        },
        watch: {
            show(newVal) {
                if (newVal === false) this.oldVal = this.newVal = '';
            }
        },
        created() {
            eventEmitter.on('修改规则对话框', ({type, name}) => {
                this.show = true;
                this.ruleType = type;
                this.ruleName = name;
            });
        }
    };
    const arraysLooseEqual = (arr1, arr2) => {
        if (arr1.length !== arr2.length) return false;
        const countMap = {};
        const getKey = (value) => {
            if (typeof value === 'number' && Number.isNaN(value)) return '__NaN';
            return JSON.stringify(value);
        };
        for (const elem of arr1) {
            const key = getKey(elem);
            countMap[key] = (countMap[key] || 0) + 1;
        }
        for (const elem of arr2) {
            const key = getKey(elem);
            if (!countMap[key]) return false; // 不存在或数量不足
            countMap[key]--;
        }
        return true;
    };
    const arrayContains = (a, b) => {
        if (b.length === 0) return true;
        if (a.length < b.length) return false;
        const countMap = {};
        const getKey = (value) => {
            if (typeof value === 'number' && Number.isNaN(value)) return '__NaN';
            return JSON.stringify(value);
        };
        for (const elem of a) {
            const key = getKey(elem);
            countMap[key] = (countMap[key] || 0) + 1;
        }
        for (const elem of b) {
            const key = getKey(elem);
            if (!countMap[key] || countMap[key] <= 0) return false;
            countMap[key]--;
        }
        return true;
    };
    var arrUtil = {
        arraysLooseEqual,
        arrayContains
    };
    const multiple_rule_edit_dialog_vue = {
        template: `
      <div>
        <el-dialog :visible.sync="dialogVisible" title="多重规则"
                   :modal="false"
                   :close-on-click-modal="false" :close-on-press-escape="false">
          <el-tag>{{ typeMap.name }}</el-tag>
          <el-card>
            <template #header>说明</template>
            <div>1.组合类型每条项至少大于1</div>
            <div>2.不能添加空项</div>
            <div>3.每组中的项不能超过15个字符</div>
            <div>4.不能重复添加已有的组合</div>
            <div>5.每组不能添加过包括已有的组合</div>
            <div>6.不能添加视频tag(精确匹配)已有的项,如需要,请先移除对应的项!包括视频tag(模糊匹配)</div>
          </el-card>
          <el-card>
            <el-input
                class="input-new-tag"
                v-if="inputVisible"
                v-model="inputValue"
                ref="saveTagInput"
                size="small"
                placeholder="多个项时请用英文符号分割"
                @keyup.enter.native="handleInputConfirm"
                @blur="handleInputConfirm"
            >
            </el-input>
            <el-button v-else size="small" @click="showInput">+ New Tag</el-button>
            <el-tag closable v-for="(item,index) in showTags" @close="handleTagClose(item,index)">{{ item|filterTag }}
            </el-tag>
          </el-card>
        </el-dialog>
      </div>`,
        data() {
            return {
                dialogVisible: false,
                inputVisible: false,
                inputValue: '',
                min: 2,
                typeMap: {},
                showTags: [],
            }
        },
        methods: {
            updateShowTags() {
                this.showTags = ruleKeyListData$1.getVideoTagPreciseCombination();
            },
            handleTagClose(tag, index) {
                if (tag === '') return;
                this.$confirm(`确定要删除 ${tag} 吗?`, '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.showTags.splice(index, 1);
                    ruleKeyListData$1.setVideoTagPreciseCombination(this.showTags);
                    this.$message.success(`已移除 ${tag}`);
                    eventEmitter.send('刷新规则信息', false);
                });
            },
            showInput() {
                this.inputVisible = true;
                this.$nextTick(_ => {
                    this.$refs.saveTagInput.$refs.input.focus();
                });
            },
            handleInputConfirm() {
                let inputValue = this.inputValue;
                this.inputVisible = false;
                if (inputValue === '') return;
                this.submitBut(inputValue);
                this.inputValue = '';
            },
            submitBut(inputValue) {
                const split = inputValue.split(',');
                if (split.length < this.min) {
                    this.$message.error('最少添加' + this.min + '项');
                    return;
                }
                const preciseVideoTagArr = ruleKeyListData$1.getPreciseVideoTagArr();
                const videoTagArr = ruleKeyListData$1.getVideoTagArr();
                for (let showTag of split) {
                    showTag = showTag.trim();
                    if (showTag === "") {
                        this.$message.error('不能添加空项');
                        return;
                    }
                    if (preciseVideoTagArr.includes(showTag)) {
                        this.$message.error('不能添加视频tag(精确匹配)已有的项,请先移除对应的项!');
                        return;
                    }
                    if (videoTagArr.includes(showTag)) {
                        this.$message.error('不能添加视频tag(模糊匹配)已有的项,请先移除对应的项!');
                        return;
                    }
                    if (showTag.length > 15) {
                        this.$message.error('项不能超过15个字符');
                        return;
                    }
                }
                const arr = ruleKeyListData$1.getVideoTagPreciseCombination();
                for (let mk_arr of arr) {
                    if (arrUtil.arraysLooseEqual(mk_arr, split)) {
                        this.$message.error('不能重复添加已有的组合!');
                        return
                    }
                    if (arrUtil.arrayContains(mk_arr, split)) {
                        this.$message.error('该组合已添加过或包括该组合');
                        return
                    }
                }
                arr.push(split);
                ruleKeyListData$1.setVideoTagPreciseCombination(arr);
                console.log(this.typeMap, split, arr);
                this.$message.success(`${this.typeMap.name}添加成功`);
                this.updateShowTags();
                eventEmitter.send('刷新规则信息', false);
            }
        },
        created() {
            eventEmitter.on('打开多重规则编辑对话框', (typeMap) => {
                this.typeMap = typeMap;
                this.dialogVisible = true;
                this.updateShowTags();
            });
        },
        filters: {
            filterTag(tag) {
                return tag.join('||')
            }
        }
    };
    const basic_rules_vue = {
        components: {rule_set_value_dialog, multiple_rule_edit_dialog_vue},
        template: `
      <div>
        <el-card shadow="never">
          <template #header>
            <span>使用说明</span>
          </template>
          <div>1.基础规则类型较多,下拉框支持搜索定位,鼠标点击出现光标时支持筛选</div>
          <div>2.大部分情况下模糊匹配比精确匹配好用</div>
          <div>3.如果可以的话,请优先考虑根据uid精确屏蔽,而非使用用户名相关屏蔽,因用户名可以随意更改</div>
          <div>4.如果用户要添加自己的正则匹配相关的规则时,建议先去该网址进行测试再添加,避免浪费时间
            <el-link href="https://www.jyshare.com/front-end/854/" target="_blank"
                     type="primary">>>>正则表达式在线测试<<<
            </el-link>
          </div>
          <div>
            5.如果更新脚本之后规则全没了,请点击下面的【旧规则自动转新规则】按钮,进行转换,如不行请通过关于和问题反馈选项卡中的反馈渠道联系作者
          </div>
          <div>6.改动实时生效</div>
          <div>7. 分区包括子分区属于视频tag范畴,如需按分区屏蔽在对应视频tag类型添加</div>
          <div>8.
            基础规则中的项和组合规则互斥,如xxx添加到视频tag多重规则,则不能添加到对应基础规则视频tag,反之同理,限类型,如组合精确匹配
          </div>
        </el-card>
        <el-card shadow="never">
          <template #header>选择规则</template>
          <el-cascader v-model="cascaderVal" @change="handleChangeCascader"
                       :options="cascaderOptions" :show-all-levels="false"
                       :props="{ expandTrigger: 'hover' }" filterable/>
          <el-divider/>
          <el-row>
            <el-col :span="12">
              <el-button-group>
                <el-button @click="addRuleBut">添加</el-button>
                <el-button @click="setRuleBut">修改</el-button>
                <el-button @click="findItemAllBut">查询</el-button>
                <el-button @click="delBut">移除</el-button>
              </el-button-group>
            </el-col>
            <el-col :span="12">
              <div class="el-horizontal-right">
                <el-button-group>
                  <el-button @click="clearItemRuleBut" type="danger">清空项</el-button>
                  <el-button type="danger" @click="delAllBut">全部移除</el-button>
                </el-button-group>
              </div>
            </el-col>
          </el-row>
        </el-card>
        <rule_set_value_dialog/>
        <multiple_rule_edit_dialog_vue/>
      </div>`,
        data() {
            return {
                cascaderVal: ["精确匹配", "precise_uid"],
                cascaderOptions: ruleKeyListData$1.getSelectOptions(),
                ruleInfoArr: [],
            }
        },
        methods: {
            handleChangeCascader(val) {
                console.log(val);
            },
            addRuleBut() {
                const [model, mk_type] = this.cascaderVal;
                if (model === '多重匹配') {
                    const typeMap = this.ruleInfoArr.find(item => item.type === mk_type);
                    eventEmitter.send('打开多重规则编辑对话框', typeMap);
                    return
                }
                ruleUtil.showAddRuleInput(mk_type);
            },
            setRuleBut() {
                const [model, type] = this.cascaderVal;
                const typeMap = this.ruleInfoArr.find(item => item.type === type);
                if (model === '多重匹配') {
                    eventEmitter.send('打开多重规则编辑对话框', typeMap);
                    return
                }
                eventEmitter.send('修改规则对话框', typeMap);
            },
            findItemAllBut() {
                const [model, type] = this.cascaderVal;
                const typeMap = this.ruleInfoArr.find(item => item.type === type);
                if (model === '多重匹配') {
                    eventEmitter.send('打开多重规则编辑对话框', typeMap);
                    return
                }
                const ruleData = gmUtil.getData(type, []);
                eventEmitter.send('展示内容对话框', JSON.stringify(ruleData, null, 4));
            },
            delAllBut() {
                this.$confirm('确定要删除所有规则吗?').then(() => {
                    for (let x of this.ruleInfoArr) {
                        gmUtil.delData(x.type);
                    }
                    this.$alert("删除全部规则成功");
                    eventEmitter.send('刷新规则信息');
                });
            },
            delBut() {
                const [model, type] = this.cascaderVal;
                const typeMap = this.ruleInfoArr.find(item => item.type === type);
                if (model === '多重匹配') {
                    eventEmitter.send('打开多重规则编辑对话框', typeMap);
                    return
                }
                ruleUtil.showDelRuleInput(type);
            },
            clearItemRuleBut() {
                const type = this.cascaderVal[1];
                const find = this.ruleInfoArr.find(item => item.type === type);
                this.$confirm(`是要清空${find.name}的规则内容吗?`, 'tip').then(() => {
                    ruleKeyListData$1.clearKeyItem(type);
                    this.$alert(`已清空${find.name}的规则内容`);
                });
            }
        },
        watch: {},
        created() {
            for (let newRuleKeyListElement of ruleKeyListData$1.getRuleKeyListData()) {
                this.ruleInfoArr.push({
                    type: newRuleKeyListElement.key,
                    name: newRuleKeyListElement.name,
                });
            }
        }
    };
    const oldToNewRule = () => {
        const listData = ruleKeyListData$1.getRuleKeyListData().filter(item => item.oldKey);
        for (let data of listData) {
            const oldKeyDataArr = gmUtil.getData(data.oldKey, []);
            if (oldKeyDataArr.length === 0) {
                continue
            }
            const newKeyDataArr = gmUtil.getData(data.key, []);
            if (newKeyDataArr.length === 0) {
                gmUtil.setData(data.key, oldKeyDataArr);
                gmUtil.delData(data.oldKey);
                continue
            }
            for (let v of oldKeyDataArr) {
                const isExist = newKeyDataArr.find(item => item === v);
                if (!isExist) {
                    newKeyDataArr.push(v);
                }
            }
            gmUtil.setData(data.key, newKeyDataArr);
        }
    };
    var ruleConversion = {
        oldToNewRule
    };
    const wait = (milliseconds = 1000) => {
        return new Promise(resolve => setTimeout(resolve, milliseconds));
    };
    const fileDownload = (content, fileName) => {
        const element = document.createElement('a');
        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
        element.setAttribute('download', fileName);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    };
    const handleFileReader = (event) => {
        return new Promise((resolve, reject) => {
            const file = event.target.files[0];
            if (!file) {
                reject('未读取到文件');
                return;
            }
            let reader = new FileReader();
            reader.onload = (e) => {
                const fileContent = e.target.result;
                resolve({file, content: fileContent});
                reader = null;
            };
            reader.readAsText(file);
        });
    };
    const isIterable = (obj) => {
        return obj != null && typeof obj[Symbol.iterator] === 'function';
    };
    const toTimeString = () => {
        return new Date().toLocaleString();
    };
    function smoothScroll(toTop = false, duration = 1000) {
        return new Promise((resolve) => {
            const start = window.scrollY;
            const end = toTop ? 0 : document.documentElement.scrollHeight - window.innerHeight;
            const change = end - start;
            const startTime = performance.now();
            function animateScroll(currentTime) {
                const elapsedTime = currentTime - startTime;
                const progress = Math.min(elapsedTime / duration, 1);
                const easeInOutQuad = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
                window.scrollTo(0, start + change * easeInOutQuad);
                if (progress < 1) {
                    requestAnimationFrame(animateScroll);
                } else {
                    resolve();
                }
            }
            requestAnimationFrame(animateScroll);
        });
    }
    function debounce(func, wait = 1000) {
        let timeout;
        return function (...args) {
            const context = this;
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(context, args), wait);
        };
    }
    function debounceAsync(asyncFunc, wait = 1000) {
        let timeout;
        let pendingPromise;
        return async function (...args) {
            const context = this;
            if (pendingPromise) {
                clearTimeout(timeout);
                await pendingPromise;
            }
            pendingPromise = new Promise((resolve) => {
                timeout = setTimeout(() => {
                    pendingPromise = null; // 清除引用
                    resolve(asyncFunc.apply(context, args));
                }, wait);
            });
            return pendingPromise;
        };
    }
    function throttle(func, limit) {
        let inThrottle;
        return function (...args) {
            const context = this;
            if (!inThrottle) {
                func.apply(context, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }
    function throttleAsync(asyncFunc, limit) {
        let isThrottled = false;
        let pendingArgs = null;
        let pendingContext = null;
        let timeoutId;
        let pendingPromiseResolve;
        const throttled = async function (...args) {
            const context = this;
            if (isThrottled) {
                return new Promise((resolve) => {
                    pendingArgs = args;
                    pendingContext = context;
                    pendingPromiseResolve = resolve;
                });
            }
            isThrottled = true;
            try {
                return await asyncFunc.apply(context, args);
            } finally {
                timeoutId = setTimeout(() => {
                    isThrottled = false;
                    if (pendingArgs) {
                        throttled.apply(pendingContext, pendingArgs).then(pendingPromiseResolve);
                        pendingArgs = null;
                        pendingContext = null;
                        pendingPromiseResolve = null;
                    }
                }, limit);
            }
        };
        throttled.cancel = () => {
            clearTimeout(timeoutId);
            isThrottled = false;
            pendingArgs = null;
            pendingContext = null;
            pendingPromiseResolve = null;
        };
        return throttled;
    }
    const parseUrl = (urlString) => {
        const url = new URL(urlString);
        const pathSegments = url.pathname.split('/').filter(segment => segment !== '');
        const searchParams = new URLSearchParams(url.search.slice(1));
        const queryParams = {};
        for (const [key, value] of searchParams.entries()) {
            queryParams[key] = value;
        }
        return {
            protocol: url.protocol,
            hostname: url.hostname,
            port: url.port,
            pathname: url.pathname,
            pathSegments,
            search: url.search,
            queryParams,
            hash: url.hash
        };
    };
    const getLocalStorage = (key, isList = false, defaultValue = null) => {
        const item = localStorage.getItem(key);
        if (item === null) {
            return defaultValue
        }
        if (isList) {
            try {
                return JSON.parse(item)
            } catch (e) {
                console.error(`读取localStorage时尝试转换${key}的值失败`, e);
                return defaultValue
            }
        }
        return item
    };
    const formatTimestamp = (timestamp, options = {}) => {
        if (!timestamp || isNaN(timestamp)) return 'Invalid Timestamp'
        const ts = String(timestamp).length === 10 ? +timestamp * 1000 : +timestamp;
        const timezoneOffset = (options.timezone || 0) * 60 * 60 * 1000;
        const date = new Date(ts + timezoneOffset);
        if (isNaN(date.getTime())) return 'Invalid Date'
        const timeObj = {
            year: date.getUTCFullYear(),
            month: date.getUTCMonth() + 1,
            day: date.getUTCDate(),
            hours: date.getUTCHours(),
            minutes: date.getUTCMinutes(),
            seconds: date.getUTCSeconds()
        };
        if (options.returnObject) return timeObj
        const format = options.format || 'YYYY-MM-DD HH:mm:ss';
        const pad = (n) => n.toString().padStart(2, '0');
        return format
            .replace(/YYYY/g, timeObj.year)
            .replace(/YY/g, String(timeObj.year).slice(-2))
            .replace(/MM/g, pad(timeObj.month))
            .replace(/M/g, timeObj.month)
            .replace(/DD/g, pad(timeObj.day))
            .replace(/D/g, timeObj.day)
            .replace(/HH/g, pad(timeObj.hours))
            .replace(/H/g, timeObj.hours)
            .replace(/mm/g, pad(timeObj.minutes))
            .replace(/m/g, timeObj.minutes)
            .replace(/ss/g, pad(timeObj.seconds))
            .replace(/s/g, timeObj.seconds)
    };
    const calculateLikeRate = (likeCount, viewCount) => {
        if (viewCount === 0) {
            return 0;
        }
        return parseInt((likeCount / viewCount) * 100)
    };
    const calculateInteractionRate = (danmaku, reply, view) => {
        return parseInt((danmaku + reply) / view * 100)
    };
    const calculateTripleRate = (favorite, coin, share, view) => {
        return parseInt((favorite + coin + share) / view * 100)
    };
    const calculateCoinLikesRatioRate = (coin, like) => {
        return parseInt((coin + like) / view * 100)
    };
    var defUtil = {
        wait,
        fileDownload,
        toTimeString,
        smoothScroll,
        debounce,
        debounceAsync,
        throttle,
        throttleAsync,
        parseUrl,
        handleFileReader,
        isIterable,
        getLocalStorage,
        formatTimestamp,
        calculateLikeRate,
        calculateInteractionRate,
        calculateTripleRate,
        calculateCoinLikesRatioRate
    };
    var rule_export_import_vue = {
        template: `
      <div>
        <el-card shadow="never">
          <template #header>
            <span>导出规则</span>
          </template>
          <el-button @click="ruleOutToFIleBut">导出到文件</el-button>
          <el-button @click="outToInputBut">导出到编辑框</el-button>
          <el-button @click="ruleOutToConsoleBut">导出到控制台</el-button>
        </el-card>
        <el-card shadow="never">
          <template #header>
            <el-row>
              <el-col :span="12">
                <div class="el-horizontal-left">导入规则</div>
              </el-col>
              <el-col :span="12">
                <div class="el-horizontal-right">
                  <el-button v-for="item in ruleReference" @click="xtipAlertBut(item.content,item.title)">
                    {{ item.title }}
                  </el-button>
                </div>
              </el-col>
            </el-row>
          </template>
          <div>规则内容请在下面编辑框中导入</div>
          <div>旧版本的需要使用下面的v1旧版本导入规则</div>
          <div>旧版本的只能覆盖导入</div>
          <div>v1之后的版本可以选择覆盖和追加</div>
          <div>旧规则转新规则,用于2.0之前版本升上来旧规则内容丢失问题</div>
          <el-divider/>
          <div>
            <el-button @click="inputFIleRuleBut">读取外部规则文件</el-button>
            <el-button @click="overwriteImportRulesBut">覆盖导入规则</el-button>
            <el-button @click="appendImportRulesBut">追加导入规则</el-button>
            <el-button @click="overwriteImportRulesV1But">v1旧版本覆盖导入规则</el-button>
            <el-button @click="ruleOldToNewBut">旧规则自动转新规则</el-button>
          </div>
          <el-divider/>
          <div>
            <el-input autosize
                      :autosize="{ minRows: 10, maxRows: 50}"
                      type="textarea" v-model="ruleContentImport" placeholder="要导入的规则内容"></el-input>
          </div>
        </el-card>
        <input ref="file" type="file" accept="application/json" @change="handleFileUpload"
               style="display: none">
      </div>`,
        data() {
            return {
                ruleContentImport: "",
                ruleReference: [
                    {
                        title: "旧版本规则参考",
                        content: ` {"用户名黑名单模式(精确匹配)":["账号已注销"],"BV号黑名单模式(精确匹配)":[],
                        "用户名黑名单模式(模糊匹配)":["bili_","_bili"],"用户uid黑名单模式(精确匹配)":[442010132,76525078,225219967,3493283164588093],
                        "用户uid白名单模式(精确匹配)":[344490740,1861980711],"标题黑名单模式(模糊匹配)":["激励计划","蚌不住","手游激励","游戏活动打卡"],
                        "标题黑名单模式(正则匹配)":["感觉.*不如","不要笑.*挑战"],"评论关键词黑名单模式(模糊匹配)":["感觉不如","差不多的了"],
                        "评论关键词黑名单模式(正则匹配)":["这不.+吗","玩.*的","不要笑.*挑战"],"粉丝牌黑名单模式(精确匹配)":[],
                        "专栏关键词内容黑名单模式(模糊匹配)":[],"动态关键词内容黑名单模式(模糊匹配)":["拼多多","京东红包","京东618红包","618活动"]}`
                    },
                    {
                        title: "新版本规则参考",
                        content: "待补充"
                    }
                ],
            }
        },
        methods: {
            overwriteImportRulesBut() {
                this.$confirm('是否要覆盖导入规则?').then(() => {
                    const trim = this.ruleContentImport.trim();
                    if (ruleUtil.overwriteImportRules(trim)) {
                        this.$alert('已覆盖导入成功!');
                        eventEmitter.send('刷新规则信息');
                    }
                });
            },
            appendImportRulesBut() {
                this.$confirm('是否要追加导入规则?').then(() => {
                    const trim = this.ruleContentImport.trim();
                    if (ruleUtil.appendImportRules(trim)) {
                        this.$message('已追加导入成功!');
                        eventEmitter.send('刷新规则信息');
                    }
                });
            },
            overwriteImportRulesV1But() {
                this.$confirm('旧版本-是否导入规则?').then(() => {
                    const trim = this.ruleContentImport.trim();
                    if (ruleUtil.overwriteImportRulesV1(trim)) {
                        this.$message('已导入成功!');
                        eventEmitter.send('刷新规则信息');
                    }
                });
            },
            xtipAlertBut(content, title) {
                this.$alert(content, title);
            },
            ruleOldToNewBut() {
                ruleConversion.oldToNewRule();
                eventEmitter.send('刷新规则信息');
                this.$message('已转换成功!');
            },
            handleFileUpload(event) {
                defUtil.handleFileReader(event).then(data => {
                    const {content} = data;
                    try {
                        JSON.parse(content);
                    } catch (e) {
                        this.$message('文件内容有误');
                        return;
                    }
                    this.ruleContentImport = content;
                    this.$message('读取到内容,请按需覆盖或追加');
                });
            },
            inputFIleRuleBut() {
                this.$refs.file.click();
            },
            outToInputBut() {
                this.ruleContentImport = ruleUtil.getRuleContent(2);
                this.$message('已导出到输入框中');
            },
            ruleOutToFIleBut() {
                let fileName = "b站屏蔽器规则-" + defUtil.toTimeString();
                this.$prompt('请输入文件名', '保存为', {
                    inputValue: fileName
                }).then(({value}) => {
                    if (value === "" && value.includes(' ')) {
                        this.$alert('文件名不能为空或包含空格');
                        return
                    }
                    const ruleContent = ruleUtil.getRuleContent(4);
                    defUtil.fileDownload(ruleContent, value + ".json");
                });
            },
            ruleOutToConsoleBut() {
                console.log(ruleUtil.getRuleContent());
                this.$message('已导出到控制台上,F12打开控制台查看');
            },
        },
    };
    const comment_word_limit_vue = {
        template: `
      <div>
        <el-card>
          <template #header>评论字数限制</template>
          <div>超出设置限制的字数时屏蔽(不包括),低于3则不生效</div>
          <div>改动即生效</div>
          <el-input-number v-model="value"/>
        </el-card>
      </div>`,
        data() {
            return {
                value: localMKData.getCommentWordLimitVal()
            }
        },
        watch: {
            value(newVal, oldVal) {
                if (oldVal <= 3) return;
                if (newVal < 3) {
                    this.$notify({
                        message: '已关闭屏蔽字数限制功能',
                        type: 'warning',
                    });
                }
                gmUtil.setData('comment_word_limit', newVal);
            }
        }
    };
    var other_parameter_filter = {
        components: {comment_word_limit_vue},
        template: `
      <div>
        <div style="display: flex">
          <div style="width: 70vw">
            <el-card>
              <template #header>
                <span>使用说明</span>
              </template>
              <ol>
                <li>如设置时长相关单位为秒</li>
                <li>如设置播放量和弹幕量相关单位为个</li>
                <li>设置最小播放量则小于该值的视频会屏蔽</li>
                <li>设置最大播放量则大于该值的视频会屏蔽</li>
                <li>设置最小弹幕量则小于该值的视频会屏蔽</li>
                <li>设置最大弹幕量则大于该值的视频会屏蔽</li>
                <li>设置最小时长则小于该值的视频会屏蔽</li>
                <li>设置最大时长则大于该值的视频会屏蔽</li>
                <li>设置最小用户等级则小于该值的会屏蔽,低于该值的会屏蔽掉</li>
                <li>设置最大用户等级则大于该值的会屏蔽,高于该值的会屏蔽掉</li>
                <li>取消相关限制条件则不做限制处理</li>
                <li>右侧信息关键条件-1则为未做任何限制处理</li>
                <li>最后因为设置限制条件冲突或限制太多,视频未能限制的情况下,请按需设置限制条件</li>
              </ol>
            </el-card>
            <input gz_type type="number" :min="inputMin" :max="inputMax" v-model="num">
            <el-select v-model="selectValue" filterable>
              <el-option :value="item.value" v-for="item in selectList" :label="item.name"></el-option>
            </el-select>
            <div>
              <el-button @click="okVideoSelectBut">设置</el-button>
              <el-button @click="cancelBut">取消</el-button>
              <el-button @click="allCancelBut">全部取消</el-button>
            </div>
          </div>
          <div>
            <el-button @click="updateInfoBut">刷新</el-button>
            <div v-for="item in selectList" style="padding: 5px">
              {{ item.name }}{{ item.defVal }}
              {{ item.name.includes('时长') ? '秒' : '' }}
            </div>
          </div>
        </div>
        <comment_word_limit_vue/>
      </div>`,
        data() {
            return {
                num: 0,
                selectList: ruleKeyListData$1.otherKeyListData,
                selectValue: 'nMinimumPlay',
                inputMax: "",
                inputMin: 0
            }
        },
        methods: {
            okVideoSelectBut() {
                const find = this.selectList.find(item => item.value === this.selectValue);
                const associatedVal = gmUtil.getData(find.associated, -1);
                const associatedFind = this.selectList.find(item => item.value === find.associated);
                if (this.num > associatedVal && associatedVal !== -1) {
                    if (associatedFind.bLarge) {
                        this.$alert(`要设置的${find.name}值不能大于${associatedFind.name}的值`);
                        return
                    }
                    console.log('正常修改');
                }
                this.$alert(`已设置${find.name},值为${this.num}`);
                gmUtil.setData(this.selectValue, this.num);
                this.updateInfo();
            },
            cancelBut() {
                gmUtil.setData(this.selectValue, -1);
                const find = this.selectList.find(item => item.value === this.selectValue);
                this.$alert(`已取消${find.name}的限制`);
                this.updateInfo();
            },
            allCancelBut() {
                for (let item of this.selectList) {
                    gmUtil.setData(item.value, -1);
                }
                this.updateInfo();
            },
            updateInfo() {
                for (let item of this.selectList) {
                    item.defVal = gmUtil.getData(item.value, -1);
                }
            },
            updateInfoBut() {
                this.updateInfo();
                this.$alert('已刷新');
            },
        },
        watch: {
            selectValue(newVal) {
                const find = this.selectList.find(item => item.value === newVal);
                if (find.name.includes('用户等级')) {
                    this.inputMin = 3;
                    this.inputMax = 6;
                    if (this.num > 6) {
                        this.num = 6;
                    }
                    if (this.num < 3) {
                        this.num = 3;
                    }
                } else {
                    this.inputMin = 0;
                    this.inputMax = '';
                }
            }
        },
        created() {
            this.updateInfo();
        }
    };
    var rule_information_vue = {
        template: `
      <div>
        <el-card>
          <template #header>
            <el-button @click="refreshInfoBut">刷新信息</el-button>
          </template>
          <div style=" display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;">
            <div v-for="item in ruleInfoArr" :key="item.name">
              <el-badge :value="item.len">
                <el-button>{{ item.name }}</el-button>
              </el-badge>
            </div>
          </div>
        </el-card>
      </div>`,
        data() {
            return {
                ruleInfoArr: [],
            }
        },
        methods: {
            refreshInfo(isTip = true) {
                for (let x of this.ruleInfoArr) {
                    x.len = gmUtil.getData(x.type, []).length;
                }
                if (!isTip) return;
                this.$notify({
                    title: 'tip',
                    message: '刷新规则信息成功',
                    type: 'success',
                });
            },
            refreshInfoBut() {
                this.refreshInfo();
            },
        },
        created() {
            for (let newRuleKeyListElement of ruleKeyListData$1.getRuleKeyListData()) {
                this.ruleInfoArr.push({
                    type: newRuleKeyListElement.key,
                    name: newRuleKeyListElement.name,
                    len: 0
                });
            }
            this.refreshInfo(false);
            eventEmitter.on('刷新规则信息', (isTip = true) => {
                this.refreshInfo(isTip);
            });
        }
    };
    class asynchronousIntervalQueue {
        #isProcessing = false;
        #pendingQueue = [];
        #interval = 200;
        constructor(options = {}) {
            this.#interval = options.interval || 200;
        }
        setInterval(interval) {
            this.#interval = interval;
        }
        add(func, config = {}) {
            return new Promise((resolve, reject) => {
                this.#pendingQueue.push({
                    funcFn: func,
                    config: {
                        interval: config.interval || null,
                    },
                    resolve,
                    reject
                });
                if (!this.#isProcessing) {
                    this.#processQueue();
                }
            });
        }
        async #processQueue() {
            this.#isProcessing = true;
            while (this.#pendingQueue.length > 0) {
                const task = this.#pendingQueue.shift();
                try {
                    let result;
                    const funcFn = task.funcFn;
                    if (funcFn instanceof Promise) {
                        const template = await funcFn;
                        if (template instanceof Function) {
                            result = template();
                        } else {
                            result = template;
                        }
                    }
                    if (funcFn instanceof Function) {
                        const template = funcFn();
                        if (template instanceof Promise) {
                            result = await template;
                        } else {
                            result = template;
                        }
                    }
                    task.resolve(result);
                } catch (error) {
                    task.reject(error);
                } finally {
                    const interval = task.config.interval || this.#interval;
                    await new Promise(resolve =>
                        setTimeout(resolve, interval)
                    );
                }
            }
            this.#isProcessing = false;
        }
        clearPendingQueue() {
            this.#pendingQueue = [];
            this.#isProcessing = false;
        }
    }
    const requestIntervalQueue = new asynchronousIntervalQueue({
        interval: localMKData.isRequestFrequencyVal() * 1000
    });
    var conditionalityVue = {
        template: `
      <div>
        <el-switch v-model="bOnlyTheHomepageIsBlocked" active-text="仅首页屏蔽生效屏蔽"/>
        <el-tooltip content="模糊和正则匹配时,将匹配词转小写与规则值匹配。修改后刷新页面生效">
          <el-switch v-model="bFuzzyAndRegularMatchingWordsToLowercase"
                     active-text="模糊和正则匹配词转小写"/>
        </el-tooltip>
        <el-card>
          <template #header>
            <span>网络请求频率(单位秒)</span>
            <div>如设置0,则为不限制,比如设置2,则为每个请求之间隔2秒,可有效降低对B站api接口的压力,降低风控</div>
            <div>注意:设置过低可能会导致部分接口风控</div>
            <div>如接口风控了请先勾选下面的【禁用根据bv号网络请求获取视频信息】</div>
            <div>修改实时生效</div>
          </template>
          <el-switch v-model="isDisableNetRequestsBvVideoInfo" active-text="禁用根据bv号网络请求获取视频信息"/>
          <el-slider v-model="requestFrequencyVal" max="5" step="0.1" show-stops show-input
                     :disabled="isDisableNetRequestsBvVideoInfo"
          ></el-slider>
        </el-card>
      </div>`,
        data() {
            return {
                requestFrequencyVal: localMKData.isRequestFrequencyVal(),
                bOnlyTheHomepageIsBlocked: globalValue.bOnlyTheHomepageIsBlocked,
                bFuzzyAndRegularMatchingWordsToLowercase: localMKData.bFuzzyAndRegularMatchingWordsToLowercase(),
                isDisableNetRequestsBvVideoInfo: false
            }
        },
        methods: {},
        watch: {
            bOnlyTheHomepageIsBlocked(newVal) {
                gmUtil.setData("bOnlyTheHomepageIsBlocked", newVal === true);
            },
            bFuzzyAndRegularMatchingWordsToLowercase(newVal) {
                gmUtil.setData("bFuzzyAndRegularMatchingWordsToLowercase", newVal === true);
            },
            isDisableNetRequestsBvVideoInfo(b) {
                gmUtil.setData('isDisableNetRequestsBvVideoInfo', b);
            },
            requestFrequencyVal(n) {
                gmUtil.setData('requestFrequencyVal', n > 0 && n <= 5 ? n : 0.2);
                requestIntervalQueue.setInterval(n * 1000);
            }
        },
        created() {
            eventEmitter.on('更新根据bv号网络请求获取视频信息状态', (b) => {
                this.isDisableNetRequestsBvVideoInfo = b;
            });
        }
    };
    const queue = new asynchronousIntervalQueue();
    const getData = async (page = 1) => {
        const response = await fetch(`https://api.bilibili.com/x/relation/blacks?pn=${page}&ps=50&jsonp=jsonp`, {
            credentials: 'include'
        });
        if (response.status !== 200) {
            eventEmitter.send('el-msg', '拉取黑名单数据响应失败.');
            return {state: false}
        }
        const resJson = await response.json();
        const {data: {list, total}, message, code} = resJson;
        if (code !== 0) {
            eventEmitter.send('el-msg', '请求相应内容失败:code=' + code);
            return {state: false, msg: `请求相应内容失败:msg=${message} code=` + code}
        }
        const newList = list.map(({face, mid, mtime, uname, sign}) => {
            return {face, mid, mtime, uname, sign}
        });
        return {state: true, list: newList, total};
    };
    const blacklist_management_vue = {
        template: `
      <div>
        <div>1.注意:该功能为b站自身的黑名单</div>
        <div>1.对应地址
          <el-link target="_blank" href="https://account.bilibili.com/account/blacklist">
            https://account.bilibili.com/account/blacklist
          </el-link>
        </div>
        <div>3.需要登录才可以使用</div>
        <el-card shadow="never" v-loading="isDivLoading" element-loading-text="拼命加载中">
          <template #header>
            <el-row>
              <el-col :span="8">
                <el-badge :value="total">
                  <el-tag>累计</el-tag>
                </el-badge>
                <el-badge :value="showList.length" style="margin-left: 45px">
                  <el-tag>显示数</el-tag>
                </el-badge>
                <div>
                  <el-card shadow="never">
                    <template #header>请求的间隔({{ sliderInterval }}S)</template>
                    <el-slider v-model="sliderInterval" step="0.1" max="10"></el-slider>
                  </el-card>
                  <el-button @click="getOnePageDataBut">获取第一页</el-button>
                  <el-button @click="getAllBut">获取全部</el-button>
                  <el-button type="warning" @click="clearTableBut">清空列表</el-button>
                  <el-button @click="outDataToConsoleBut">导出控制台</el-button>
                  <el-button @click="outDataToFileBut">导出文件</el-button>
                </div>
              </el-col>
              <el-col :span="16">
                <el-card shadow="never">
                  <template #header><span>过滤</span></template>
                  <div>
                    <el-switch v-model="isCancelMaxLimit" active-text="取消列表显示最大限制"/>
                  </div>
                  <el-select v-model="select.val">
                    <el-option
                        v-for="item in select.options"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value">
                    </el-option>
                  </el-select>
                  <el-input v-model="findVal"></el-input>
                </el-card>
              </el-col>
            </el-row>
          </template>
          <el-table :data="showList" stripe border>
            <el-table-column prop="mtime" label="时间" width="155px">
              <template v-slot="scope">
                {{ new Date(scope.row.mtime * 1000).toLocaleString() }}
              </template>
            </el-table-column>
            <el-table-column label="头像" width="55px">
              <template v-slot="scope">
                <el-avatar shape="square" :src="scope.row.face"></el-avatar>
              </template>
            </el-table-column>
            <el-table-column prop="uname" label="用户名" width="190px"></el-table-column>
            <el-table-column prop="mid" label="用户ID" width="180px"></el-table-column>
            <el-table-column prop="sign" label="签名"></el-table-column>
            <el-table-column label="标记" width="50px">
              <template v-slot="scope">
                未定
              </template>
            </el-table-column>
            <el-table-column label="操作">
              <template #header>
                <el-button @click="tableAddUidBlackButAll">一键添加uid屏蔽</el-button>
              </template>
              <template v-slot="scope">
                <el-button @click="tableOpenAddressBut(scope.row)">打开地址</el-button>
                <el-button @click="tableAddUidBlackBut(scope.row)">uid屏蔽</el-button>
              </template>
            </el-table-column>
          </el-table>
          <el-pagination
              :page-size="pageSize"
              background
              layout="prev, pager, next"
              :total="list.length"
              @current-change="handleCurrentChange"
          >
          </el-pagination>
        </el-card>
      </div>`,
        data() {
            return {
                select: {
                    val: 'uname',
                    options: [{
                        label: "用户UID",
                        value: 'mid',
                    }, {
                        label: "用户名",
                        value: 'uname',
                    }, {
                        label: '用户签名',
                        value: 'sign'
                    }]
                },
                total: 0,
                list: [],
                showList: [],
                findVal: '',
                sliderInterval: 0.6,
                isDivLoading: false,
                isCancelMaxLimit: false,
                pageSize: 50
            }
        },
        methods: {
            filterTable(list, val) {
                const filter = list.filter(x => {
                    const x1 = x[this.select.val];
                    if (Number.isInteger(x1)) {
                        return x1.toString().includes(val)
                    }
                    return x1.includes(val);
                });
                if (filter.length === 0) {
                    this.$notify({
                        title: '没有匹配到数据',
                        type: 'warning',
                        duration: 2000
                    });
                    return []
                }
                if (filter.length > 50 && !this.isCancelMaxLimit) {
                    this.$notify({
                        title: '数据过多,已截取前50条',
                        type: 'warning',
                        duration: 2000
                    });
                    return filter.slice(0, 50);
                }
                return filter;
            },
            async getOnePageDataBut() {
                const {state, list, total} = await getData();
                if (!state) {
                    return
                }
                this.list = list;
                this.showList = list;
                this.total = total;
                this.$message('获取成功');
            },
            tableOpenAddressBut(row) {
                gmUtil.openInTab(`https://space.bilibili.com/${row.mid}`);
            },
            tableAddUidBlackBut(row) {
                const uid = row.mid;
                const name = row.uname;
                if (ruleUtil.findRuleItemValue('precise_uid', uid)) {
                    this.$message(`该用户:${name}的uid:${uid}已添加过`);
                    return;
                }
                this.$confirm(`确定添加${name}的uid:${uid}到uid精确屏蔽吗?`).then(() => {
                    ruleUtil.addRulePreciseUid(uid);
                });
                console.log(row);
            },
            outDataToConsoleBut() {
                console.log('黑名单管理列表====start');
                console.log(JSON.parse(JSON.stringify(this.list)));
                console.log('黑名单管理列表====end');
                this.$alert('已导出到控制台,可通过f12查看');
            },
            outDataToFileBut() {
                this.$prompt('请输入文件名', '保存为', {
                    inputValue: 'B站黑名单列表'
                }).then(({value}) => {
                    if (value.trim() === '') {
                        return
                    }
                    const tempData = {
                        total: this.total,
                        list: this.list
                    };
                    const s = JSON.stringify(tempData, null, 4);
                    defUtil.fileDownload(s, +value.trim() + '.json');
                    this.$alert('已导出到文件,请按需保存');
                });
            },
            async getAllBut() {
                this.isDivLoading = true;
                const {state, list, total} = await getData();
                if (!state) return
                if (total === 0) {
                    this.isDivLoading = false;
                    this.$message('没有更多数据了');
                    return;
                }
                this.total = total;
                const totalPage = Math.ceil(total / 50);
                if (totalPage === 1) {
                    this.list = list;
                    this.isDivLoading = false;
                    return
                }
                this.list = list;
                for (let i = 2; i <= totalPage; i++) {
                    const {state, list: resList} = await queue.add(() => getData(i));
                    if (!state) return
                    list.push(...resList);
                }
                if (this.list.length > 50 && !this.isCancelMaxLimit) {
                    this.showList = list.slice(0, 50);
                } else {
                    this.showList = list;
                }
                this.showList = list;
                this.$message('获取成功');
                this.isDivLoading = false;
            },
            handleCurrentChange(page) {
                this.showList = this.list.slice((page - 1) * 50, page * 50);
            },
            clearTableBut() {
                this.showList = this.list = [];
                this.$message('已清空列表');
            },
            tableAddUidBlackButAll() {
                if (this.list.length === 0) {
                    this.$message('列表为空');
                    return
                }
                this.$confirm(`确定添加所有用户到uid精确屏蔽吗?`).then(() => {
                    if (ruleUtil.addPreciseUidItemRule(this.list.map(x => x.mid), true, false)) {
                        eventEmitter.send('刷新规则信息');
                    }
                });
            }
        },
        watch: {
            findVal(n) {
                this.showList = this.filterTable(this.list, n);
            },
            sliderInterval(n) {
                queue.setInterval(n * 1000);
            },
            isCancelMaxLimit(n) {
                this.pageSize = n ? 1000000 : 50;
            }
        },
        created() {
            queue.setInterval(this.sliderInterval * 1000);
        }
    };
    const uid_range_masking_vue = {
        template: `
      <div>
        <el-card>
          <template #header>
            uid范围屏蔽
          </template>
          <el-switch v-model="status" active-text="启用" style="margin-bottom: 10px"/>
          <div style="margin-bottom: 10px">
            范围内的uid都会被屏蔽掉,改动需重新设置方可生效,且再下次检查时屏蔽(如视频列表加载,评论加载)。比较关系【最小>=uid<=最大】
          </div>
          <el-form label-position="left" :disabled="!status" style="width: 20%">
            <el-form-item label="最小">
              <el-input v-model.number="head"></el-input>
            </el-form-item>
            <el-form-item label="最大">
              <el-input v-model.number="tail"></el-input>
            </el-form-item>
            <el-form-item class="el-horizontal-right">
              <el-button @click="setRangeBut">设置</el-button>
            </el-form-item>
          </el-form>
        </el-card>
      </div>`,
        data() {
            return {
                status: localMKData.isUidRangeMaskingStatus(),
                head: 0,
                tail: 100
            }
        },
        methods: {
            setRangeBut() {
                this.$alert('设置成功');
                gmUtil.setData('uid_range_masking', [this.head, this.tail]);
            }
        },
        watch: {
            head(newVal, oldVal) {
                if (newVal > this.tail) {
                    this.$message('最小值不能大于最大值');
                    this.head = oldVal;
                }
            },
            tail(newVal, oldVal) {
                if (newVal < this.head) {
                    this.$message('最大值不能小于最小值');
                    this.tail = oldVal;
                }
            },
            status(n) {
                gmUtil.setData('uid_range_masking_status', n);
            }
        },
        created() {
            const arr = localMKData.getUidRangeMasking();
            this.head = arr[0];
            this.tail = arr[1];
        }
    };
    const high_level_rule_vue = {
        components: {
            uid_range_masking_vue,
        },
        template: `
      <div>
        <uid_range_masking_vue/>
        <el-card>
          <template #header>视频类型</template>
          <div>选中的类型会被屏蔽</div>
          <el-radio-group v-model="copyrightRadioVal">
            <el-radio-button label="原创"></el-radio-button>
            <el-radio-button label="转载"></el-radio-button>
            <el-radio-button label="不处理"></el-radio-button>
          </el-radio-group>
          <el-divider/>
          <el-switch v-model="is_vertical_val" active-text="屏蔽竖屏类视频"/>
          <el-switch v-model="blockFollowed" active-text="屏蔽已关注"/>
          <el-switch v-model="is_up_owner_exclusive" active-text="屏蔽充电专属视频"></el-switch>
          <el-switch v-model="is_senior_member_val" active-text="屏蔽硬核会员"/>
          <el-row>
            <el-col :span="12">
              <el-card shadow="never">
                <template #header>会员类型屏蔽</template>
                <el-radio-group v-model="vipTypeRadioVal">
                  <el-radio-button label="无"></el-radio-button>
                  <el-radio-button label="月大会员"></el-radio-button>
                  <el-radio-button label="年度及以上大会员"></el-radio-button>
                  <el-radio-button label="不处理"></el-radio-button>
                </el-radio-group>
              </el-card>
            </el-col>
            <el-col :span="12">
              <el-card shadow="never">
                <template #header>性别屏蔽</template>
                <el-radio-group v-model="genderRadioVal">
                  <el-radio-button label="男性"></el-radio-button>
                  <el-radio-button label="女性"></el-radio-button>
                  <el-radio-button label="保密"></el-radio-button>
                  <el-radio-button label="不处理"></el-radio-button>
                </el-radio-group>
              </el-card>
            </el-col>
          </el-row>
        </el-card>
        <el-card>
          <template #header>计算创作团队</template>
          <el-tooltip content="当作者未匹配上时检查其他成员"></el-tooltip>
          <el-switch v-model="is_check_team_member" active-text="检查创作团队中成员"/>
        </el-card>
      </div>`,
        data() {
            return {
                blockFollowed: localMKData.isBlockFollowed(),
                is_up_owner_exclusive: localMKData.isUpOwnerExclusive(),
                genderRadioVal: localMKData.isGenderRadioVal(),
                vipTypeRadioVal: localMKData.isVipTypeRadioVal(),
                is_senior_member_val: localMKData.isSeniorMember(),
                copyrightRadioVal: localMKData.isCopyrightRadio(),
                is_vertical_val: localMKData.isBlockVerticalVideo(),
                is_check_team_member: localMKData.isCheckTeamMember()
            }
        },
        methods: {},
        watch: {
            blockFollowed(n) {
                gmUtil.setData('blockFollowed', n);
            },
            is_up_owner_exclusive(n) {
                gmUtil.setData('is_up_owner_exclusive', n);
            },
            genderRadioVal(n) {
                gmUtil.setData('genderRadioVal', n);
            },
            vipTypeRadioVal(n) {
                gmUtil.setData('vipTypeRadioVal', n);
            },
            is_senior_member_val(n) {
                gmUtil.setData('is_senior_member', n);
            },
            copyrightRadioVal(n) {
                gmUtil.setData('copyrightRadioVal', n);
            },
            is_vertical_val(n) {
                gmUtil.setData('blockVerticalVideo', n);
            },
            is_check_team_member(n) {
                gmUtil.setData('checkTeamMember', n);
            }
        }
    };
    const card_slider_vue = {
        template: `
      <div>
        <el-card shadow="never">
          <template #header>
            <slot name="header"></slot>
          </template>
          <slot name="describe"></slot>
          <div style="display: flex; align-items: center">
            <el-switch v-model="local_switchVal" :active-text="switchActiveText"/>
            <div style="flex: 1;margin-left: 15px">
              <el-slider v-model="sliderVal" :step="step" :min="min" :max="max" show-input :range="range"
                         :format-tooltip="formatTooltip"
                         :disabled="disabled"></el-slider>
            </div>
          </div>
        </el-card>
      </div>`,
        props: {
            formatTooltip: {
                type: Function
            },
            switchActiveText: {type: String, default: '启用'},
            step: {type: Number, default: 1},
            min: {type: Number, default: 0},
            max: {type: Number, default: 100},
            value: {type: Number, default: 0},
            switchVal: {type: Boolean, default: false},
            range: {type: Boolean, default: false}
        },
        data() {
            return {
                local_switchVal: this.switchVal,
                disabled: !this.switchVal,
                sliderVal: this.value
            }
        },
        methods: {},
        watch: {
            value(n) {
                this.sliderVal = n;
            },
            sliderVal(n) {
                this.$emit('input', n);
            },
            disabled(n) {
                this.$emit('slider-disabled-change', n);
            },
            switchVal(n) {
                this.local_switchVal = n;
            },
            local_switchVal(n) {
                this.disabled = !n;
                this.$emit('update:switchVal', n);
            }
        }
    };
    const video_metrics_filter_item_vue = {
        components: {card_slider_vue},
        props: {
            headerTitle: {type: String},
            describe: {type: String},
            mkTypeRateKey: {type: String},
            mkRateStatusKey: {type: String},
        },
        template: `
      <div>
        <card_slider_vue v-model="ratioRateVal" :step="0.01" :min="0" :max="1"
                         :switch-val.sync="rateBlockingStatus" :format-tooltip="reteFormatTooltip">
          <template #header>{{ headerTitle }}</template>
          <template #describe>{{ describe }}</template>
        </card_slider_vue>
      </div>`,
        data() {
            return {
                rateBlockingStatus: gmUtil.getData(this.mkRateStatusKey, false),
                ratioRateVal: gmUtil.getData(this.mkTypeRateKey, 0.05),
            }
        },
        methods: {
            reteFormatTooltip(val) {
                return (val * 100).toFixed(0) + '%'
            }
        },
        watch: {
            ratioRateVal(n) {
                gmUtil.setData(this.mkTypeRateKey, n);
            },
            rateBlockingStatus(n) {
                gmUtil.setData(this.mkRateStatusKey, n);
            }
        }
    };
    const video_metrics_filter_vue = {
        components: {video_metrics_filter_item_vue},
        template: `
      <div>
        <el-card>
          <template #header>指标屏蔽(改动实时生效)</template>
          <video_metrics_filter_item_vue v-for="item in metricsFilterList" :key="item.headerTitle"
                                         :header-title="item.headerTitle"
                                         :describe="item.describe"
                                         :mk-rate-status-key="item.mkRateStatusKey"
                                         :mk-type-rate-key="item.mkTypeRateKey"
          />
        </el-card>
      </div>`,
        data() {
            return {
                metricsFilterList: [
                    {
                        headerTitle: '视频点赞率屏蔽',
                        describe: '限制的点赞率,默认为2%,小于或等于值限时制的屏蔽该视频,公式【点赞率=点赞数/播放量*100】',
                        mkRateStatusKey: 'video_like_rate_blocking_status',
                        mkTypeRateKey: 'video_like_rate'
                    },
                    {
                        headerTitle: '视频互动率屏蔽',
                        describe: '限制的占比率,默认为2%,小于或等于值限时制的屏蔽该视频,公式【(弹幕数+评论数)/播放数*100】',
                        mkRateStatusKey: 'interactive_rate_blocking_status',
                        mkTypeRateKey: 'interactive_rate'
                    },
                    {
                        headerTitle: '视频三连率屏蔽',
                        describe: '限制的占比率,默认为2%,小于或等于值限时制的屏蔽该视频,公式【(收藏数+投币数+分享数)/播放数*100】',
                        mkRateStatusKey: 'triple_rate_blocking_status',
                        mkTypeRateKey: 'triple_rate'
                    },
                    {
                        headerTitle: '视频投币/点赞比(内容价值)屏蔽',
                        describe: '限制的占比率,默认为2%,小于或等于值限时制的屏蔽该视频,投币成本较高,比值越高内容越优质。公式【投币数 / 获赞数】',
                        mkRateStatusKey: 'coin_likes_ratio_rate_blocking_status',
                        mkTypeRateKey: 'coin_likes_ratio_rate'
                    }
                ]
            }
        }
    };
    const saveTable = (tableData) => {
        const newList = [];
        for (let {status, r} of tableData) {
            if (r === null) {
                eventEmitter.send('el-alert', '表格内还有未设置时间范围的项,请先设置或删除才可以保存!');
                return
            }
            const [startTime, endTime] = r;
            newList.push({
                status,
                r: [startTime.getTime(), endTime.getTime()]
            });
        }
        if (newList.length === 0) return;
        gmUtil.setData('time_range_masking', newList);
        eventEmitter.send('el-notify', {
            title: '保存成功',
            message: '已保存该时间范围屏蔽',
            type: 'success'
        });
    };
    const time_range_masking_table_vue = {
        template: `
      <div>
        <el-table :data="tableData" stripe border>
          <el-table-column label="状态" width="120px">
            <template v-slot="scope">
              <el-switch v-model="scope.row.status" active-text="启用" @change="tableSwitchChange(scope.row)"/>
            </template>
          </el-table-column>
          <el-table-column label="时间范围" width="400px">
            <template v-slot="scope">
              <el-date-picker
                  @change="tableDatePickerChange(scope.row)"
                  v-model="scope.row.r"
                  type="datetimerange"
                  :picker-options="pickerOptions"
                  range-separator="至"
                  start-placeholder="开始日期"
                  end-placeholder="结束日期">
              </el-date-picker>
              <el-tag>{{ scope.row.r }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column>
            <template #header>
              <el-button type="info" @click="addBut">添加</el-button>
              <el-button @click="refreshTableData">刷新</el-button>
              <el-button @click="saveTableBut">保存</el-button>
            </template>
            <template v-slot="scope">
              <el-button type="warning" @click="delItemBut(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>`,
        data() {
            return {
                tableData: [],
                pickerOptions: {
                    shortcuts: [
                        {
                            text: '最近一周',
                            onClick(picker) {
                                const end = new Date();
                                const start = new Date();
                                start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
                                picker.$emit('pick', [start, end]);
                            }
                        },
                        {
                            text: '最近一个月',
                            onClick(picker) {
                                const end = new Date();
                                const start = new Date();
                                start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
                                picker.$emit('pick', [start, end]);
                            }
                        },
                        {
                            text: '最近三个月',
                            onClick(picker) {
                                const end = new Date();
                                const start = new Date();
                                start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
                                picker.$emit('pick', [start, end]);
                            }
                        }
                    ]
                }
            }
        },
        methods: {
            refreshTableData() {
                if (this.tableData.length > 0) {
                    this.tableData.splice(0, this.tableData.length);
                }
                const timeRangeMaskingArr = localMKData.getTimeRangeMaskingArr();
                if (timeRangeMaskingArr.length !== 0) {
                    let index = 0;
                    for (let {status, r} of timeRangeMaskingArr) {
                        this.tableData.push({
                            index: index++,
                            status,
                            r: [new Date(r[0]), new Date(r[1])],
                            startTimeStamp: r[0],
                            endTimeStamp: r[1],
                        });
                    }
                }
            },
            restoreTheLastTimeRange(row) {
                let {startTimeStamp, endTimeStamp} = row;
                console.log('上次时间戳', startTimeStamp, endTimeStamp);
                if (startTimeStamp === null || startTimeStamp === undefined) {
                    row.r = null;
                    return
                }
                row.r = [new Date(startTimeStamp), new Date(endTimeStamp)];
                console.log('已恢复上次时间范围', row);
            },
            tableDatePickerChange(row) {
                const rowR = row.r;
                if (rowR === null) return
                let {oldStartTimeStamp, oldEndTimeStamp} = row;
                const newStartTimeStamp = rowR[0].getTime();
                const newEndTimeStamp = rowR[1].getTime();
                const comparisonSTS = newStartTimeStamp || oldStartTimeStamp;
                const comparisonETS = newEndTimeStamp || oldEndTimeStamp;
                for (let v of this.tableData) {
                    if (v.r === null) continue;
                    if (v.index === row.index) continue;
                    const tempStartTimeStamp = v.r[0].getTime();
                    const tempEndTimeStamp = v.r[1].getTime();
                    if (tempStartTimeStamp === comparisonSTS && tempEndTimeStamp === comparisonETS) {
                        this.$alert('已存在该时间范围屏蔽');
                        this.restoreTheLastTimeRange(row);
                        return;
                    }
                    if (comparisonSTS >= tempStartTimeStamp && comparisonETS <= tempEndTimeStamp) {
                        this.$alert('小于已添加过的时间范围');
                        this.restoreTheLastTimeRange(row);
                        return;
                    }
                }
                row.startTimeStamp = newStartTimeStamp;
                row.endTimeStamp = newEndTimeStamp;
                saveTable(this.tableData);
            },
            tableSwitchChange(row) {
                if (row.r === null) return
                saveTable(this.tableData);
            },
            addBut() {
                const length = this.tableData.length;
                this.tableData.push({
                    index: length, status: true, r: null,
                    startTimeStamp: null, endTimeStamp: null
                });
                this.$notify({message: '已添加一条时间范围屏蔽到底部'});
            },
            delItemBut(row) {
                if (row.startTimeStamp === null) {
                    this.tableData.splice(row.index, 1);
                    return;
                }
                for (let {r} of this.tableData) {
                    if (r === null) {
                        this.$alert('表格内还有未设置时间范围的项,请先设置或删除才可以保存!');
                        return
                    }
                }
                this.$confirm('确定删除该条时间范围屏蔽吗?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.tableData.splice(row.index, 1);
                    saveTable(this.tableData);
                    this.$message({
                        type: 'success',
                        message: '删除成功!'
                    });
                });
            },
            saveTableBut() {
                saveTable(this.tableData);
            }
        },
        created() {
            this.refreshTableData();
        }
    };
    const time_range_masking_vue = {
        components: {time_range_masking_table_vue},
        template: `
      <div>
        <el-card>
          <template #header>时间范围</template>
          <div>使用说明</div>
          <div>1.不能添加重复的时间范围或者小于已添加过的时间范围</div>
          <div>2.修改时间范围的值和状态会自动保存(包括删除),会有提示</div>
          <div>3.每个时间范围可独立控制开关状态,关闭则该条范围不生效</div>
          <div>4.总开关优先级最高,关闭则所有时间范围不生效</div>
          <el-switch v-model="status" active-text="总开关"/>
        </el-card>
        <time_range_masking_table_vue/>
      </div>`,
        data() {
            return {
                status: localMKData.isTimeRangeMaskingStatus()
            }
        },
        methods: {
        },
        watch: {
            status(n) {
                this.$notify({
                    message: n ? '时间范围屏蔽已开启' : '时间范围屏蔽已关闭',
                    type: n ? 'success' : 'warning'
                });
                gmUtil.setData('time_range_masking_status', n);
            }
        },
        created() {
        }
    };
    const repl_processing_vue = {
        template: `
      <div>
        <el-card shadow="never">
          <template #header>说明
            <el-row>
              <el-col :span="12">
                <div>1.评论内容暂不支持替换表情</div>
                <div>2.如修改后或添加数据需保存方可生效</div>
                <div>3.暂不支持标题替换</div>
                <div>4.支持正则替换,
                  <el-link target="_blank" type="primary"
                           href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll">
                    详情参考js中的replaceAll用法
                  </el-link>
                </div>
                <div>5.搜索暂时先用快捷键ctrl+f代替</div>
                <div>6.作用域中,选择了评论表情再选其他之前需要取消选项评论表情</div>
                <div>7.评论表情,查找时要用英文输入法[]包裹表情关键词,留空为评论中移除该表情。反之替换普通文本内容。
                  <el-link target="_blank" href="https://docs.qq.com/doc/DSlJNR1NVcGR3eEto"
                           title="页面中用搜索定位表情包对照表" type="primary">表情包对照表
                  </el-link>
                </div>
              </el-col>
              <el-col :span="12">
                <el-card shadow="never">
                  <template #header>全局</template>
                  <el-tooltip content="当该选项未启用时下面表格中的不生效">
                    <el-switch active-text="启用" v-model="enableReplacementProcessingVal"/>
                  </el-tooltip>
                  <el-switch v-model="clearCommentEmoticonsVal" active-text="清除评论表情"/>
                  <el-tooltip content="将评论中的蓝色关键词带搜索小图标的内容替换成普通文本内容">
                    <el-switch v-model="isReplaceCommentSearchTermsVal" active-text="替换评论搜索词"/>
                  </el-tooltip>
                </el-card>
              </el-col>
            </el-row>
          </template>
        </el-card>
        <el-table :data="tableData" border stripe>
          <el-table-column label="作用域" width="450px">
            <template v-slot="scope">
              <el-checkbox-group v-model="scope.row.actionScopes" @change="actionScopesChange">
                <el-checkbox disabled border label="视频标题"/>
                <el-checkbox border label="评论内容"/>
                <el-checkbox border label="评论表情"/>
              </el-checkbox-group>
            </template>
          </el-table-column>
          <el-table-column label="查找">
            <template v-slot="scope">
              <el-input v-model="scope.row.findVal" maxlength="10" clearable @change="verifyDuplicate"/>
            </template>
          </el-table-column>
          <el-table-column label="替换">
            <template v-slot="scope">
              <el-input v-model="scope.row.replaceVal" maxlength="10" clearable/>
            </template>
          </el-table-column>
          <el-table-column label="操作">
            <template #header>
              <el-button @click="addBut">添加</el-button>
              <el-button @click="refreshBut">刷新</el-button>
              <el-button type="success" @click="saveBut">保存</el-button>
            </template>
            <template v-slot="scope">
              <el-button type="warning" @click="delItemBut(scope.row,scope.$index)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>`,
        data() {
            return {
                tableData: getSubstituteWordsArr(),
                enableReplacementProcessingVal: enableReplacementProcessing(),
                clearCommentEmoticonsVal: isClearCommentEmoticons(),
                isReplaceCommentSearchTermsVal: isReplaceCommentSearchTerms()
            }
        },
        methods: {
            validate(item) {
                if (item.actionScopes.length === 0) {
                    this.$message.error('请选择作用域再后续处理');
                    return
                }
                if (item.findVal === '') {
                    this.$message.error('请输入查找内容再后续处理');
                    return
                }
                return true
            },
            verifyDuplicate(val) {
                if (val === '') return;
                const set = new Set();
                for (const v of this.tableData) {
                    if (set.has(v.findVal)) {
                        this.$alert(`已添加过该查找值,不可重复添加【${v.findVal}】`, '错误', {
                            type: 'error'
                        });
                        return;
                    }
                    set.add(v.findVal);
                }
            },
            addBut() {
                this.tableData.unshift({
                    actionScopes: ['评论内容'],
                    findVal: '',
                    replaceVal: ''
                });
                this.$notify({message: '已添加一条替换处理到顶部'});
            },
            delItemBut(row, index) {
                if (row.findVal === '' && row.replaceVal === '') {
                    this.tableData.splice(index, 1);
                    this.$notify({message: '已删除一条替换处理'});
                    return;
                }
                if (this.validate(row) !== true) return;
                this.$confirm('确定删除该条替换处理吗?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.tableData.splice(index, 1);
                    this.$notify({message: '已删除一条替换处理'});
                });
            },
            refreshBut() {
                this.tableData = getSubstituteWordsArr();
                this.$message.info('已刷新');
            },
            saveBut() {
                if (this.tableData.length === 0) {
                    this.$message.error('请先添加数据再保存!');
                    return
                }
                for (let item of this.tableData) {
                    if (this.validate(item) !== true) return;
                }
                const duplicateRemoval = new Set();
                for (const v of this.tableData) {
                    if (duplicateRemoval.has(v.findVal)) {
                        this.$alert(`查找内容不能重复【${v.findVal}】`, '错误', {
                            type: 'error'
                        });
                        return;
                    }
                    duplicateRemoval.add(v.findVal);
                }
                gmUtil.setData('substitute_words', this.tableData);
                this.$message.success('已保存');
            },
            actionScopesChange(newArr) {
                if (newArr.length === 0) return;
                if (newArr.some(v => v === '评论表情')) {
                    newArr.splice(0, newArr.length, '评论表情');
                }
            }
        },
        watch: {
            clearCommentEmoticonsVal(n) {
                gmUtil.setData('is_clear_comment_emoticons', n);
            },
            isReplaceCommentSearchTermsVal(n) {
                gmUtil.setData('is_replace_comment_search_terms', n);
            }
        }
    };
    var ruleManagementVue = {
        components: {
            rule_export_import_vue,
            other_parameter_filter,
            rule_information_vue,
            conditionalityVue,
            basic_rules_vue,
            blacklist_management_vue,
            high_level_rule_vue,
            video_metrics_filter_vue,
            time_range_masking_vue,
            repl_processing_vue
        },
        template: `
      <div>
        <el-tabs type="border-card" tab-position="left">
          <el-tab-pane label="基础规则">
            <basic_rules_vue/>
          </el-tab-pane>
          <el-tab-pane label="高级规则" lazy>
            <high_level_rule_vue/>
          </el-tab-pane>
          <el-tab-pane label="其他规则" lazy>
            <other_parameter_filter/>
          </el-tab-pane>
          <el-tab-pane label="指标屏蔽" lazy>
            <video_metrics_filter_vue/>
          </el-tab-pane>
          <el-tab-pane label="范围屏蔽" lazy>
            <time_range_masking_vue/>
          </el-tab-pane>
          <el-tab-pane label="替换处理" lazy>
            <repl_processing_vue/>
          </el-tab-pane>
          <el-tab-pane label="导出导入" lazy>
            <rule_export_import_vue/>
          </el-tab-pane>
          <el-tab-pane label="条件限制" lazy>
            <conditionalityVue/>
          </el-tab-pane>
          <el-tab-pane label="规则信息">
            <rule_information_vue/>
          </el-tab-pane>
          <el-tab-pane label="黑名单管理" lazy>
            <blacklist_management_vue/>
          </el-tab-pane>
        </el-tabs>
      </div>`,
        data() {
            return {}
        }
    };
    const compatible_setting_vue = {
        template: `
      <div>
        <el-card>
          <template #header>说明</template>
          <div>如果用户没有安装并使用对应脚本或插件,就不要开启相关兼容选项</div>
        </el-card>
        <el-card>
          <template #header>Bilibili-Gate脚本(bilibili-app-recommend)</template>
          <el-switch v-model="adaptationBAppRecommend" active-text="首页屏蔽适配"/>
        </el-card>
        <el-card>
          <template #header>BewlyBewly插件</template>
          <el-switch v-model="compatible_BEWLY_BEWLY" active-text="首页适配"/>
        </el-card>
        <el-card>
          <template #header>评论区</template>
          使用之后需刷新对应页面才可生效,勾选即评论区使用新版获取方式,不再使用旧版方式
          <div>
            <el-switch v-model="discardOldCommentAreasV" active-text="弃用旧版评论区处理"/>
          </div>
        </el-card>
      </div>`,
        data() {
            return {
                adaptationBAppRecommend: globalValue.adaptationBAppCommerce,
                compatible_BEWLY_BEWLY: globalValue.compatibleBEWLYBEWLY,
                discardOldCommentAreasV: localMKData.isDiscardOldCommentAreas()
            }
        },
        watch: {
            adaptationBAppRecommend(newVal) {
                gmUtil.setData("adaptation-b-app-recommend", newVal === true);
            },
            compatible_BEWLY_BEWLY(newVal) {
                gmUtil.setData("compatible_BEWLY_BEWLY", newVal === true);
            },
            discardOldCommentAreasV(newVal) {
                gmUtil.setData("discardOldCommentAreas", newVal === true);
            }
        }
    };
    const mk_db = new Dexie('mk-db');
    mk_db.version(1).stores({
        videoInfos: 'bv,tags,userInfo,videoInfo',
    });
    const addVideoData = async (bv, data) => {
        const {tags, userInfo, videoInfo} = data;
        try {
            await mk_db.videoInfos.add({
                bv, tags, userInfo, videoInfo
            });
        } catch (e) {
            console.log(`添加视频数据失败`, data, e);
            return false
        }
        return true
    };
    const bulkImportVideoInfos = async (friendsData) => {
        try {
            const lastKeyItem = await mk_db.videoInfos.bulkPut(friendsData);
            console.info('批量导入成功,最后一个插入的主键:', lastKeyItem);
            return {state: true, lastKeyItem}
        } catch (error) {
            console.error('批量导入时出错:', error);
            return {state: false, error}
        }
    };
    const getVideoInfo = async () => {
        return await mk_db.videoInfos.toArray()
    };
    const getVideoInfoCount = async () => {
        return await mk_db.videoInfos.count()
    };
    const findVideoInfoByBv = async (bv) => {
        return await mk_db.videoInfos.get(bv)
    };
    const clearVideoInfosTable = async () => {
        try {
            await mk_db.videoInfos.clear();
            return true
        } catch (e) {
            console.log('清除videoInfos表失败', e);
            return false
        }
    };
    const delVideoInfoItem = async (bv) => {
        try {
            const item = await findVideoInfoByBv(bv);
            if (!item) return false;
            await mk_db.videoInfos.delete(bv);
            return true
        } catch (e) {
            return false
        }
    };
    const bulkDelVideoInfoItem = async (bvArr) => {
        const data = {state: false, success: [], fail: []};
        try {
            const existingItem = await mk_db.videoInfos.bulkGet(bvArr);
            const existingKeys = existingItem.filter(item => item).map(item => item.bv);
            if (existingKeys.length === 0) {
                data.fail = bvArr;
                return data
            }
            data.state = true;
            data.success.push(...existingKeys);
            if (existingKeys.length !== bvArr.length) {
                data.fail.push(...bvArr.filter(item => !existingKeys.includes(item)));
            }
            await mk_db.videoInfos.bulkDelete(bvArr);
            return data
        } catch (e) {
            console.log('批量删除数据库中指定bv号失败:', e);
            return data
        }
    };
    var bvDexie = {
        addVideoData,
        clearVideoInfosTable,
        bulkImportVideoInfos,
        getVideoInfo,
        getVideoInfoCount,
        delVideoInfoItem,
        bulkDelVideoInfoItem
    };
    const cache_management_vue = {
        template: `
      <div>
        <el-card>
          <template #header>说明</template>
          <div>1.每个域名中的缓存数据不同</div>
          <div>2.仅仅支持导入json格式</div>
          <div>3.下面导入默认追加模式</div>
          <div>4.当前域名
            <el-tag>{{ hostname }}</el-tag>
          </div>
        </el-card>
        <el-card>
          <template #header>操作</template>
          <el-button @click="inputFIleBut">追加导入视频缓存数据</el-button>
          <input ref="inputDemo" type="file" @change="handleFileUpload" accept="application/json"
                 style="display: none">
          <el-button @click="clearPageVideoCacheDataBut">清空当前域名的视频缓存数据</el-button>
          <el-button @click="lookContentBut">查看内容</el-button>
          <el-button @click="lookContentLenBut">查看数据量</el-button>
          <el-button type="warning" @click="batchDelBut">批量删除</el-button>
        </el-card>
        <el-card>
          <template #header>导出</template>
          <el-button @click="outDbDataBut">导出至文件</el-button>
          <el-button @click="outToConsoleBut">导出至控制台</el-button>
        </el-card>
      </div>`,
        data() {
            return {
                hostname: window.location.hostname
            }
        },
        methods: {
            outDbDataBut() {
                bvDexie.getVideoInfo().then((data) => {
                    if (data.length === 0) {
                        this.$message('当前域名下没有缓存视频数据');
                        return
                    }
                    data = {
                        hostName: this.hostname,
                        size: data.length,
                        data: data
                    };
                    defUtil.fileDownload(JSON.stringify(data, null, 4), 'mk-db-videoInfos-cache.json');
                    this.$message('已导出当前域名的缓存数据');
                    console.log(data);
                });
            },
            handleFileUpload(event) {
                defUtil.handleFileReader(event).then(data => {
                    const {content} = data;
                    let parse;
                    try {
                        parse = JSON.parse(content);
                    } catch (e) {
                        this.$message('文件内容有误');
                        return;
                    }
                    const {hostName = null, videoInfos = []} = parse;
                    if (!hostName) {
                        this.$message('hostName字段不存在');
                        return;
                    }
                    if (!defUtil.isIterable(videoInfos)) {
                        this.$message('文件内容有误,非可迭代的数组!');
                        return;
                    }
                    if (videoInfos.length === 0) {
                        this.$message('tags数据为空');
                        return;
                    }
                    for (let item of videoInfos) {
                        if (!item['bv']) {
                            this.$message('bv字段不存在');
                            return;
                        }
                        if (!item['tags']) {
                            this.$message('tags字段不存在');
                            return;
                        }
                        if (!item['userInfo']) {
                            this.$message('userInfo字段不存在');
                            return;
                        }
                        if (!item['videoInfo']) {
                            this.$message('videoInfo字段不存在');
                            return;
                        }
                    }
                    bvDexie.bulkImportVideoInfos(videoInfos).then((bool) => {
                        if (bool) {
                            this.$message('导入成功');
                        } else {
                            this.$message('导入失败');
                        }
                    });
                });
            },
            inputFIleBut() {
                this.$refs.inputDemo.click();
            },
            clearPageVideoCacheDataBut() {
                this.$confirm('是否清空当前域名下的tags数据').then(() => {
                    bvDexie.clearVideoInfosTable().then((bool) => {
                        if (bool) {
                            this.$message('已清空当前域名下的视频缓存数据');
                        } else {
                            this.$message('清空失败');
                        }
                    });
                });
            },
            lookContentBut() {
                this.$confirm('当数据量过大时,可能卡顿,等待时间会较为长,是要继续吗').then(async () => {
                    const loading = this.$loading({text: "获取中..."});
                    const r = await bvDexie.getVideoInfo();
                    loading.close();
                    eventEmitter.send('展示内容对话框', JSON.stringify(r));
                    this.$message('获取成功');
                });
            },
            outToConsoleBut() {
                bvDexie.getVideoInfo().then(r => {
                    this.$alert('已导出至控制台上,可通过f12等方式查看');
                    const hostname = this.hostname;
                    console.log(`${hostname}的视频数据===start`);
                    console.log(r);
                    console.log(`${hostname}的视频数据=====end`);
                });
            },
            lookContentLenBut() {
                bvDexie.getVideoInfoCount().then((len) => {
                    this.$alert(`数据量${len}`);
                });
            },
            batchDelBut() {
                this.$prompt('请输入删除的bv号,多个bv号用逗号隔开', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                }).then(async ({value}) => {
                    value = value?.trim() || null || "";
                    if (value === null) return;
                    const bvs = value.split(',');
                    if (bvs.length === 1) {
                        const bool = await bvDexie.delVideoInfoItem(bvs[0]);
                        if (bool) {
                            this.$message.success(`删除${value}的视频缓存数据成功`);
                        } else {
                            this.$message.warning(`删除失败,未找到${value}的视频缓存数据`);
                        }
                        return
                    }
                    const data = await bvDexie.bulkDelVideoInfoItem(bvs);
                    if (data.state) {
                        if (data.success.length === bvs.length) {
                            this.$alert(`删除${data.success.join(',')}的视频缓存数据成功`, {
                                type: 'success'
                            });
                        } else {
                            this.$alert(`删除${data.success.join(',')}的视频缓存数据成功,${data.fail.join(',')}的视频缓存数据未找到`, {
                                type: 'warning'
                            });
                        }
                    } else {
                        this.$message.warning(`删除失败,错误信息请看控制台`);
                    }
                });
            }
        },
        created() {
        }
    };
    var donateLayoutVue = {
        template: `
      <div>
        <el-card shadow="hover">
          <template #header>
            <span>零钱赞助</span>
          </template>
          <span>1元不嫌少,10元不嫌多,感谢支持!</span>
          <el-divider/>
          <span>生活不易,作者叹息</span>
          <el-divider/>
          <span>用爱发电不容易,您的支持是我最大的更新动力</span>
        </el-card>
        <el-divider/>
        <div class="el-vertical-center" @click="gotoAuthorBut">
          <el-avatar size="large"
                     src="//i0.hdslb.com/bfs/face/87e9c69a15f7d2b68294be165073c8e07a541e28.jpg@128w_128h_1c_1s.webp"></el-avatar>
        </div>
        <div class="el-vertical-center">
          <el-button round type="primary" @click="showDialogBut">打赏点猫粮</el-button>
        </div>
        <el-dialog
            center
            :title="dialogIni.title"
            :visible.sync="dialogIni.show">
          <div class="el-vertical-center">
            <el-image v-for="item in list"
                      :src="item.src"
                      style="height: 300px"
                      :preview-src-list="dialogIni.srcList"/>
          </div>
        </el-dialog>
      </div>`,
        data() {
            return {
                list: [
                    {
                        name: "支付宝赞助",
                        alt: "支付宝支持",
                        src: "https://www.mikuchase.ltd/img/paymentCodeZFB.webp"
                    },
                    {name: "微信赞助", alt: "微信支持", src: "https://www.mikuchase.ltd/img/paymentCodeWX.webp"},
                    {name: "QQ赞助", alt: "QQ支持", src: "https://www.mikuchase.ltd/img/paymentCodeQQ.webp"},
                ],
                dialogIni: {
                    title: "打赏点猫粮",
                    show: false,
                    srcList: []
                }
            }
        },
        methods: {
            showDialogBut() {
                this.dialogIni.show = true;
            },
            gotoAuthorBut() {
                gmUtil.openInTab(globalValue.b_url);
            }
        },
        created() {
            this.dialogIni.srcList = this.list.map(x => x.src);
        }
    };
    const outputInformationFontColor$1 = localMKData.getOutputInformationFontColor();
    const highlightInformationColor$1 = localMKData.getHighlightInformationColor();
    var outputInformationVue = {
        template: `
      <div>
      <el-button type="info" @click="clearInfoBut">清空消息</el-button>
      <div v-for="item in outputInfoArr" v-html="item"></div>
      </div>`,
        data() {
            return {
                outputInfoArr: [],
            }
        },
        methods: {
            clearInfoBut() {
                this.$confirm('是否清空信息', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.outputInfoArr = [];
                    this.$message('已清空信息');
                });
            }
        },
        created() {
            eventEmitter.on('打印信息', (content) => {
                const liEL = document.createElement("li");
                liEL.innerHTML = content;
                this.outputInfoArr.push(liEL.innerHTML);
            });
            eventEmitter.on('屏蔽视频信息', (type, matching, videoData) => {
                const toTimeString = defUtil.toTimeString();
                const {name, uid, title, videoUrl} = videoData;
                const info = `<b style="color: ${outputInformationFontColor$1}; " gz_bezel>
${toTimeString}-根据${type}-${matching ? `<b style="color: ${highlightInformationColor$1}">【${matching}】</b>` : ""}-屏蔽用户【${name}】uid=
            <a href="https://space.bilibili.com/${uid}" 
            style="color: ${highlightInformationColor$1}"
            target="_blank">【${uid}】</a>
            标题【<a href="${videoUrl}" target="_blank" style="color: ${highlightInformationColor$1}">${title}</a>】
            </b>`;
                this.outputInfoArr.push(info);
            });
            eventEmitter.on('屏蔽评论信息', (type, matching, commentData) => {
                const toTimeString = defUtil.toTimeString();
                const {name, uid, content} = commentData;
                this.outputInfoArr.push(`<b style="color: ${outputInformationFontColor$1}; " gz_bezel>
${toTimeString}-根据${type}-${matching ? `<b style="color: ${highlightInformationColor$1}">【${matching}】</b>` : ""}-屏蔽用户【${name}】uid=
            <a href="https://space.bilibili.com/${uid}" 
            style="color: ${highlightInformationColor$1}"
            target="_blank">【${uid}】</a>
            评论【${content}】
            </b>`);
            });
            eventEmitter.on('正则匹配时异常', (errorData) => {
                const {msg, e} = errorData;
                this.outputInfoArr.push(msg);
                console.error(msg);
                throw new Error(e)
            });
        }
    };
    const look_content_dialog_vue = {
        template: `
      <div>
      <el-dialog
          :fullscreen="true"
          title="提示"
          :visible.sync="dialogVisible"
          width="30%"
          :before-close="handleClose">
        <el-input autosize
                  type="textarea"
                  v-model="content"></el-input>
        <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
  </span>
      </el-dialog>
      </div>`,
        data() {
            return {
                dialogVisible: false,
                content: ''
            }
        },
        methods: {
            handleClose(done) {
                this.$confirm('确认关闭?')
                    .then(_ => {
                        done();
                    })
                    .catch(_ => {
                    });
            }
        },
        created() {
            eventEmitter.on('展示内容对话框', (newContent) => {
                this.content = newContent;
                this.$message('已更新内容');
                this.dialogVisible = true;
            });
        }
    };
    class ValueCache {
        #mapCache = new Map();
        set(key, value) {
            this.#mapCache.set(key, value);
            return value;
        }
        get(key, defaultValue = null) {
            const newVar = this.#mapCache.get(key);
            if (newVar) {
                return newVar;
            }
            return defaultValue;
        }
        getAll() {
            return this.#mapCache;
        }
    }
    const valueCache = new ValueCache();
    var video_zone = {
      "动画": [
        "MAD·AMV",
        "MMD·3D",
        "短片·手书",
        "配音",
        "手办·模玩",
        "特摄",
        "动漫杂谈"
      ],
      "番剧": [
        "资讯",
        "官方延伸",
        "完结动画"
      ],
      "国创": [
        "国产动画",
        "国产原创相关",
        "布袋戏",
        "资讯"
      ],
      "音乐": [
        "原创音乐",
        "翻唱",
        "VOCALOID·UTAU",
        "演奏",
        "MV",
        "音乐现场",
        "音乐综合",
        "乐评盘点",
        "音乐教学"
      ],
      "舞蹈": [
        "宅舞",
        "舞蹈综合",
        "舞蹈教程",
        "街舞",
        "明星舞蹈",
        "国风舞蹈"
      ],
      "游戏": [
        "单机游戏",
        "电子竞技",
        "手机游戏",
        "网络游戏",
        "桌游棋牌",
        "GMV",
        "音游"
      ],
      "知识": [
        "科学科普",
        "社科·法律·心理(原社科人文、原趣味科普人文)",
        "人文历史",
        "财经商业",
        "校园学习",
        "职业职场",
        "设计·创意",
        "野生技术协会",
        "演讲·公开课(已下线)",
        "星海(已下线)"
      ],
      "科技": [
        "数码(原手机平板)",
        "软件应用",
        "计算机技术",
        "科工机械 (原工业·工程·机械)",
        "极客DIY",
        "电脑装机(已下线)",
        "摄影摄像(已下线)"
      ],
      "运动": [
        "篮球",
        "足球",
        "健身",
        "竞技体育",
        "运动文化"
      ],
      "汽车": [
        "汽车知识科普",
        "赛车",
        "改装玩车",
        "新能源车",
        "房车",
        "摩托车",
        "购车攻略",
        "汽车生活",
        "汽车文化(已下线)",
        "汽车极客(已下线)"
      ],
      "生活": [
        "搞笑",
        "出行",
        "三农",
        "家居房产",
        "手工",
        "绘画",
        "日常",
        "亲子",
        "美食圈(重定向)",
        "动物圈(重定向)",
        "运动(重定向)",
        "汽车(重定向)"
      ],
      "美食": [
        "美食制作(原[生活]->[美食圈])",
        "美食侦探",
        "美食测评",
        "田园美食"
      ],
      "动物圈": [
        "喵星人",
        "汪星人",
        "动物二创",
        "野生动物",
        "小宠异宠"
      ],
      "鬼畜": [
        "鬼畜调教",
        "音MAD",
        "人力VOCALOID",
        "鬼畜剧场"
      ],
      "时尚": [
        "美妆护肤",
        "仿妆cos",
        "穿搭",
        "时尚潮流",
        "健身(重定向)"
      ],
      "资讯": [
        "热点",
        "环球",
        "社会"
      ],
      "广告": [],
      "娱乐": [
        "综艺",
        "娱乐杂谈",
        "粉丝创作",
        "明星综合"
      ],
      "影视": [
        "影视杂谈",
        "影视剪辑",
        "小剧场",
        "预告·资讯"
      ],
      "纪录片": [
        "人文·历史",
        "科学·探索·自然",
        "军事"
      ],
      "电影": [
        "华语电影",
        "欧美电影",
        "日本电影"
      ],
      "电视剧": [
        "国产剧"
      ]
    };
    const findKey = (itemKey) => {
        for (let key in video_zone) {
            const arr = video_zone[key];
            if (arr.some((i) => i === itemKey)) return key;
        }
        return null;
    };
    var video_zoneData = {findKey};
    const fetchGetBarrageBlockingWords = () => {
        return new Promise((resolve, reject) => {
            fetch('https://api.bilibili.com/x/dm/filter/user', {
                credentials: 'include'
            })
                .then(response => response.json())
                .then(({code, data, message}) => {
                    if (code !== 0) {
                        reject({state: false, msg: `请求相应内容失败:msg=${message} code=` + code});
                        return
                    }
                    const {rule} = data;
                    const list = [];
                    for (let r of rule) {
                        const {type, filter, ctime} = r;
                        if (type === 2) {
                            continue
                        }
                        list.push({type, filter, ctime});
                    }
                    resolve({state: true, data, list, msg: '获取成功'});
                });
        })
    };
    const fetchGetVideoInfo = async (bvId) => {
        const response = await fetch(`https://api.bilibili.com/x/web-interface/view/detail?bvid=${bvId}`);
        if (response.status !== 200) {
            eventEmitter.send('请求获取视频信息失败', response, bvId);
            return {state: false, msg: '网络请求失败', data: response}
        }
        const {code, data, message} = await response.json();
        const defData = {state: false, msg: '默认失败信息'};
        if (code !== 0) {
            defData.msg = message;
            return defData
        }
        defData.state = true;
        defData.msg = '获取成功';
        const {
            View: {
                staff,
                tname,
                tname_v2,
                desc,
                pubdate,
                ctime,
                copyright,
                is_upower_exclusive,
                duration,
                dimension,
                stat: {
                    view,
                    danmaku,
                    reply,
                    favorite,
                    coin,
                    share,
                    like
                },
            }, Card: {
                follower,
                like_num,
                archive_count,
                following,
                article_count, card: {
                    mid: uid,
                    name,
                    sex, level_info: {
                        current_level
                    },
                    pendant,
                    nameplate,
                    Official,
                    official_verify,
                    vip,
                    sign,
                    is_senior_member
                }
            }, Tags,
            participle
        } = data;
        const videoInfo = {
            staff,
            tname,
            tname_v2,
            desc,
            pubdate,
            ctime,
            copyright,
            is_upower_exclusive,
            duration,
            view,
            danmaku,
            reply,
            favorite,
            coin,
            share,
            participle,
            dimension,
            like
        };
        const userInfo = {
            follower,
            like_num,
            archive_count,
            article_count,
            Official,
            official_verify,
            vip,
            uid,
            name,
            sex,
            current_level,
            pendant,
            nameplate,
            following,
            sign,
            is_senior_member
        };
        const tags = [];
        for (let tag of Tags) {
            tags.push(tag['tag_name']);
        }
        tags.unshift(tname, tname_v2);
        const findKey = video_zoneData.findKey(tname);
        if (findKey) {
            tags.unshift(findKey);
        }
        defData.data = {videoInfo, userInfo, tags};
        return defData
    };
    var bFetch = {
        fetchGetVideoInfo,
        fetchGetBarrageBlockingWords
    };
    const bAfterLoadingThePageOpenMainPanel = () => {
        return gmUtil.getData('bAfterLoadingThePageOpenMainPanel', false)
    };
    const setBAfterLoadingThePageOpenMainPanel = (b) => {
        gmUtil.setData('bAfterLoadingThePageOpenMainPanel', b === true);
    };
    const debugger_management_vue = {
        template: `
      <div>
        <el-tabs tab-position="left">
          <el-tab-pane label="基础">
            <el-card shadow="never">
              <template #header><span>测试</span></template>
              <el-button @click="demoBut">测试网络请求</el-button>
              <el-button @click="fetchGetVideoInfoBut">请求获取视频信息</el-button>
              <el-button @click="printValueCacheBut">打印valueCache值</el-button>
              <el-button @click="printEventBut">打印事件中心值</el-button>
              <el-button @click="printReqIntervalQueueVal">打印requestIntervalQueue值</el-button>
              <el-divider/>
              <el-switch v-model="bAfterLoadingThePageOpenMainPanel" active-text="加载完页面打开主面板"/>
            </el-card>
          </el-tab-pane>
        </el-tabs>
      </div>`,
        data() {
            return {
                bAfterLoadingThePageOpenMainPanel: bAfterLoadingThePageOpenMainPanel()
            }
        },
        methods: {
            printValueCacheBut() {
                console.log(valueCache.getAll());
            },
            demoBut() {
                bFetch.fetchGetVideoInfo('BV152cWeXEhW').then(data => {
                    console.log(data);
                    debugger
                });
            },
            fetchGetVideoInfoBut() {
                this.$prompt('请输入视频bv号', {
                    title: '请输入视频bv号',
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    inputPattern: /^BV[A-Za-z0-9]{10}$/,
                    inputErrorMessage: '请输入正确的视频bv号'
                }).then(({value}) => {
                    bFetch.fetchGetVideoInfo(value).then(data => {
                        console.log(data);
                        debugger
                    });
                });
            },
            printEventBut() {
                console.log(eventEmitter.getEvents());
            },
            printReqIntervalQueueVal() {
                console.log(requestIntervalQueue);
            }
        },
        watch: {
            bAfterLoadingThePageOpenMainPanel(b) {
                setBAfterLoadingThePageOpenMainPanel(b);
            }
        }
    };
    const getUrlUID = (url) => {
        let uid;
        if (url.startsWith('http')) {
            const parseUrl = defUtil.parseUrl(url);
            uid = parseUrl.pathSegments[0]?.trim();
            return parseInt(uid)
        }
        const isDoYouHaveAnyParameters = url.indexOf('?');
        const lastIndexOf = url.lastIndexOf("/");
        if (isDoYouHaveAnyParameters === -1) {
            if (url.endsWith('/')) {
                const nTheIndexOfTheLastSecondOccurrenceOfTheSlash = url.lastIndexOf('/', url.length - 2);
                uid = url.substring(nTheIndexOfTheLastSecondOccurrenceOfTheSlash + 1, url.length - 1);
            } else {
                uid = url.substring(lastIndexOf + 1);
            }
        } else {
            uid = url.substring(lastIndexOf + 1, isDoYouHaveAnyParameters);
        }
        return parseInt(uid);
    };
    const getUrlBV = (url) => {
        let match = url.match(/video\/(.+)\//);
        if (match === null) {
            match = url.match(/video\/(.+)\?/);
        }
        if (match === null) {
            match = url.match(/video\/(.+)/);
        }
        return match?.[1]?.trim() || null;
    };
    function findElementUntilFound(selector, config = {}) {
        const defConfig = {
            doc: document,
            interval: 1000,
            timeout: -1,
        };
        config = {...defConfig, ...config};
        return new Promise((resolve, reject) => {
            const i1 = setInterval(() => {
                const element = config.doc.querySelector(selector);
                if (element) {
                    resolve(element);
                    clearInterval(i1);
                }
            }, config.interval);
            if (config.timeout > 0) {
                setTimeout(() => {
                    clearInterval(i1);
                    reject(null); // 超时则返回 null
                }, config.timeout);
            }
        });
    }
    const findElement = async (selector, config = {}) => {
        try {
            const defConfig = {
                doc: document,
                interval: 1000,
                timeout: -1,
            };
            config = {...defConfig, ...config};
            const el = await findElementUntilFound(selector, config);
            if (config.timeout === -1) {
                return el
            }
            return {state: true, data: el}
        } catch (e) {
            return {state: false, data: e}
        }
    };
    const findElements = async (selector, config = {}) => {
        const defConfig = {doc: document, interval: 1000, timeout: -1};
        config = {...defConfig, ...config};
        try {
            const elList = await findElementsUntilFound(selector, config);
            if (config.timeout === -1) {
                return elList
            }
            return {state: true, data: elList}
        } catch (e) {
            return {state: false, data: e}
        }
    };
    function findElementsUntilFound(selector, config = {}) {
        const defConfig = {doc: document, interval: 1000, timeout: -1};
        config = {...defConfig, ...config};
        return new Promise((resolve, reject) => {
            const i1 = setInterval(() => {
                const elements = config.doc.querySelectorAll(selector);
                if (elements.length > 0) {
                    resolve(Array.from(elements));
                    clearInterval(i1);
                }
            }, config.interval);
            if (config.timeout > 0) {
                setTimeout(() => {
                    clearInterval(i1);
                    reject(null); // 超时则返回 null
                }, config.timeout);
            }
        });
    }
    const findElementsAndBindEvents = (css, callback, config = {}) => {
        config = {
            ...{
                interval: 2000,
                timeOut: 3000
            }, config
        };
        setTimeout(() => {
            findElementUntilFound(css, {interval: config.interval}).then((el) => {
                el.addEventListener("click", () => {
                    callback();
                });
            });
        }, config.timeOut);
    };
    const updateCssVModal = () => {
        findElement('.v-modal').then(() => {
            const styleEl = document.createElement('style');
            styleEl.innerHTML = `.v-modal  {
    z-index: auto !important;
}`;
            document.head.appendChild(styleEl);
        });
    };
    var elUtil = {
        getUrlUID,
        getUrlBV,
        findElement,
        findElements,
        findElementUntilFound,
        findElementsUntilFound,
        findElementsAndBindEvents,
        updateCssVModal
    };
    const setTopInputPlaceholder = async () => {
        if (globalValue.compatibleBEWLYBEWLY) {
            return
        }
        const placeholder = valueCache.get('topInputPlaceholder');
        if (placeholder === null) {
            return
        }
        const targetInput = await elUtil.findElement('.nav-search-input');
        targetInput.placeholder = placeholder;
        eventEmitter.send('el-notify', {
            title: "tip",
            message: '已恢复顶部搜索框提示内容',
            position: 'bottom-right',
        });
    };
    const processTopInputContent = async () => {
        if (globalValue.compatibleBEWLYBEWLY) {
            return
        }
        if (!gmUtil.getData('isClearTopInputTipContent', false)) {
            return;
        }
        const targetInput = await elUtil.findElement('.nav-search-input');
        if (targetInput.placeholder === '') {
            await defUtil.wait(1500);
            await processTopInputContent();
            return
        }
        valueCache.set('topInputPlaceholder', targetInput.placeholder);
        targetInput.placeholder = '';
        eventEmitter.send('el-msg', '清空了搜索框提示内容');
    };
    eventEmitter.on('执行清空顶部搜索框提示内容', () => {
        processTopInputContent();
    });
    var topInput = {processTopInputContent, setTopInputPlaceholder};
    const page_processing_vue = {
        template: `
      <div>
        <el-card>
          <template #header>
            <span>搜索页</span>
          </template>
          <el-switch v-model="isRemoveSearchBottomContent"
                     active-text="屏蔽底部额外内容"/>
        </el-card>
        <el-card>
          <template #header>
            <span>播放页</span>
          </template>
          <el-switch v-model="isDelPlayerPageAd" active-text="屏蔽页面元素广告"/>
          <el-switch v-model="isDelPlayerPageRightGameAd" active-text="屏蔽右侧游戏推荐"/>
          <el-tooltip content="移除整个推荐列表,状态刷新生效">
            <el-switch v-model="isDelPlayerPageRightVideoList" active-text="移除右侧推荐列表"/>
          </el-tooltip>
          <el-tooltip content="状态刷新生效">
            <el-switch v-model="isDelBottomComment" active-text="移除评论区"/>
          </el-tooltip>
          <el-tooltip content="视频播放完之后会在播放器上显示推荐内容,开启之后移除播放器上整个推荐内容">
            <el-switch v-model="isDelPlayerEndingPanelVal" active-text="移除播放完推荐层"/>
          </el-tooltip>
        </el-card>
        <el-card>
          <template #header>
            <span>顶部搜索框</span>
          </template>
          <el-switch v-model="isClearTopInputTipContent" active-text="清空内容"/>
        </el-card>
      </div>`,
        data() {
            return {
                isRemoveSearchBottomContent: gmUtil.getData('isRemoveSearchBottomContent', false),
                isDelPlayerPageAd: gmUtil.getData('isDelPlayerPageAd', false),
                isDelPlayerPageRightGameAd: gmUtil.getData('isDelPlayerPageRightGameAd', false),
                isDelPlayerPageRightVideoList: localMKData.isDelPlayerPageRightVideoList(),
                isDelBottomComment: localMKData.isDelBottomComment(),
                isClearTopInputTipContent: gmUtil.getData('isClearTopInputTipContent', false),
                isDelPlayerEndingPanelVal: localMKData.isDelPlayerEndingPanel()
            }
        },
        methods: {},
        watch: {
            isRemoveSearchBottomContent(b) {
                gmUtil.setData('isRemoveSearchBottomContent', b);
            },
            isDelPlayerPageAd(b) {
                gmUtil.setData('isDelPlayerPageAd', b);
            },
            isDelPlayerPageRightGameAd(b) {
                gmUtil.setData('isDelPlayerPageRightGameAd', b);
            },
            isDelPlayerPageRightVideoList(b) {
                gmUtil.setData('isDelPlayerPageRightVideoList', b);
            },
            isDelBottomComment(b) {
                gmUtil.setData('isDelBottomComment', b);
            },
            isClearTopInputTipContent(b) {
                gmUtil.setData('isClearTopInputTipContent', b);
                if (b) {
                    eventEmitter.send('执行清空顶部搜索框提示内容');
                    return
                }
                topInput.setTopInputPlaceholder();
            },
            isDelPlayerEndingPanelVal(n) {
                gmUtil.setData('is_del_player_ending_panel', n);
            }
        }
    };
    const about_and_feedback_vue = {
        template: `
      <div>
        <el-card>
          <template #header>
            <span>作者b站</span>
          </template>
          <el-link target="_blank" :href="b_url" type="primary">b站传送门</el-link>
        </el-card>
        <el-card>
          <template #header>
            <span>交流群</span>
          </template>
          <el-link
              :href='group_url' target="_blank" type="primary">====》Q群传送门《====
          </el-link>
          <el-tooltip content="点击查看群二维码">
            <el-tag @click="lookImgBut">876295632</el-tag>
          </el-tooltip>
        </el-card>
        <el-card>
          <template #header>
            <span>发布、更新、反馈地址</span>
          </template>
          <el-row>
            <el-col :span="12">
              <el-card>
                <span>greasyfork</span>
                <el-link target="_blank" type="primary" href="http://greasyfork.icu/scripts/461382/">===》传送门《===
                </el-link>
              </el-card>
            </el-col>
            <el-col :span="12">
              <el-card>
                <span>脚本猫</span>
                <el-link target="_blank" type="primary" :href="scriptCat_js_url">
                  ===》传送门《===
                </el-link>
              </el-card>
            </el-col>
          </el-row>
        </el-card>
        <el-card>
          <template #header>
            <span>开源地址</span>
          </template>
          <el-row>
            <el-col :span="12">
              <el-card>
                <span>gitee</span>
                <el-link target="_blank" type="primary" href="https://gitee.com/hangexi/BiBiBSPUserVideoMonkeyScript"
                >https://gitee.com/hangexi/BiBiBSPUserVideoMonkeyScript
                </el-link>
              </el-card>
            </el-col>
            <el-col :span="12">
              <el-card>
                <span>github</span>
                <el-link target="_blank" type="primary" href="https://github.com/hgztask/BiBiBSPUserVideoMonkeyScript"
                >https://github.com/hgztask/BiBiBSPUserVideoMonkeyScript
                </el-link>
              </el-card>
            </el-col>
          </el-row>
        </el-card>
        <el-card>
          <template #header>常见问题和使用文档</template>
          <el-row>
            <el-col :span="12">
              常见问题
              <el-link target="_blank" type="primary" :href="common_question_url">==>传送门<==
              </el-link>
            </el-col>
            <el-col :span="12">
              使用文档
              <el-link target="_blank" type="primary"
                       href="https://docs.qq.com/doc/DSmJqSkhFaktBeUdk?u=1a1ff7b128d64f188a8bfb71b5acb28c">==>传送门<==
              </el-link>
            </el-col>
            <div>
              更新日志
              <el-link target="_blank" type="primary" :href="update_log_url">==>传送门<==</el-link>
            </div>
          </el-row>
        </el-card>
      </div>`,
        data() {
            return {
                group_url: globalValue.group_url,
                scriptCat_js_url: globalValue.scriptCat_js_url,
                b_url: globalValue.b_url,
                common_question_url: globalValue.common_question_url,
                update_log_url: globalValue.update_log_url
            }
        },
        methods: {
            lookImgBut() {
                eventEmitter.send('显示图片对话框', {image: "https://www.mikuchase.ltd/img/qq_group_876295632.webp"});
            }
        },
        created() {
        }
    };
    const show_img_dialog_vue = {
        template: `
      <div>
      <el-dialog
          center
          :title="title"
          :modal="isModal"
          :visible.sync="show">
        <div class="el-vertical-center">
          <el-image
              :src="imgSrc" :preview-src-list="imgList"/>
        </div>
      </el-dialog>
      </div>`,
        data() {
            return {
                show: false,
                title: "图片查看",
                imgList: [],
                imgSrc: '',
                isModal: true
            }
        },
        created() {
            eventEmitter.on('显示图片对话框', ({image, title, images, isModal}) => {
                this.imgSrc = image;
                if (title) {
                    this.title = title;
                }
                if (images) {
                    this.imgList = images;
                } else {
                    this.imgList = [image];
                }
                if (isModal) {
                    this.isModal = isModal;
                }
                this.show = true;
            });
        }
    };
    const sheet_dialog_vue = {
        props: {
            show: {
                type: Boolean,
                default: false
            },
            list: {
                type: Array,
                default: () => []
            },
            closeOnClickModal: {
                type: Boolean,
                default: true
            },
            title: {
                type: String,
                default: '选项'
            },
            clickItemClose: {
                type: Boolean,
                default: false
            }
        },
        template: `
      <div>
      <el-dialog :visible="show" :title="title"
                 width="30%" center
                 :close-on-click-modal="closeOnClickModal"
                 @close="$emit('close')">
        <div>
          <el-row>
            <el-col v-for="item in list" :key="item.label">
              <el-button style="width: 100%" @click="handleClick(item)">项目{{ item.label }}</el-button>
            </el-col>
          </el-row>
        </div>
      </el-dialog>
      </div>`,
        data() {
            return {
                dialogShow: true,
                list: []
            }
        },
        methods: {
            handleClick(item) {
                if (this.clickItemClose) {
                    return;
                }
                this.$emit('options-click', item);
            }
        }
    };
    const bullet_word_management_vue = {
        template: `
      <div>
        <el-button @click="fetchGetBarrageBlockingWordsBut">获取弹幕屏蔽词</el-button>
        <el-button @click="outToJsonFIleBut">导出至json文件</el-button>
      </div>`,
        data: () => {
            return {
                resData: {},
                resList: [],
            }
        },
        methods: {
            async initial() {
                const {state, list, msg} = await bFetch.fetchGetBarrageBlockingWords();
                if (!state) {
                    this.$message.warning(msg);
                    return false
                }
                this.resList = list;
                this.$notify({message: '已初始化', type: 'success'});
                return true
            },
            fetchGetBarrageBlockingWordsBut() {
                if (this.resList.length === 0) {
                    this.$message.info('未有弹幕屏蔽词内容或未初始化');
                    return
                }
                const list = this.resList;
                this.$message.success(`已打印在控制台上,数量${list.length}`);
                console.log('获取弹幕屏蔽词_start=====');
                console.log(list);
                console.log('获取弹幕屏蔽词_end=======');
            },
            outToJsonFIleBut() {
            }
        },
        created() {
            this.initial();
        }
    };
    const mainLayoutEl = document.createElement('div');
    if (document.head.querySelector('#element-ui-css') === null) {
        const linkElement = document.createElement('link');
        linkElement.rel = 'stylesheet';
        linkElement.href = 'https://unpkg.com/element-ui/lib/theme-chalk/index.css';
        linkElement.id = 'element-ui-css';
        document.head.appendChild(linkElement);
        console.log('挂载element-ui样式成功');
    }
    window.addEventListener('load', () => {
        document.body.appendChild(mainLayoutEl);
        new Vue({
            el: mainLayoutEl,
            template: `
          <div>
            <el-drawer style="position: fixed"
                       :visible.sync="drawer"
                       direction="ltr"
                       size="100%"
                       :modal="false"
                       :with-header="false">
              <el-tabs type="border-card" v-model="tabsActiveName"
                       @tab-click="tabClick">
                <el-tab-pane label="面板设置" name="面板设置" lazy>
                  <panel_settings_vue/>
                </el-tab-pane>
                <el-tab-pane label="规则管理" name="规则管理" lazy>
                  <rule_management_vue/>
                </el-tab-pane>
                <el-tab-pane label="兼容设置" name="兼容设置" lazy>
                  <compatible_setting_vue/>
                </el-tab-pane>
                <el-tab-pane label="缓存管理" name="缓存管理" lazy>
                  <cache_management_vue/>
                </el-tab-pane>
                <el-tab-pane label="页面处理" name="页面处理" lazy>
                  <page_processing_vue/>
                </el-tab-pane>
                <el-tab-pane v-if="debug_panel_show" label="弹幕词管理" name="弹幕词管理" lazy>
                  <bullet_word_management_vue/>
                </el-tab-pane>
                <el-tab-pane label="输出信息" name="输出信息" lazy>
                  <output_information_vue/>
                </el-tab-pane>
                <el-tab-pane label="支持打赏" name="支持打赏" lazy>
                  <donate_layout_vue/>
                </el-tab-pane>
                <el-tab-pane label="关于和问题反馈" name="关于和问题反馈" lazy>
                  <about_and_feedback_vue/>
                </el-tab-pane>
                <el-tab-pane label="调试测试" name="调试测试" lazy v-if="debug_panel_show">
                  <div v-show="debug_panel_show">
                    <debugger_management_vue/>
                  </div>
                </el-tab-pane>
              </el-tabs>
            </el-drawer>
            <look_content_dialog_vue/>
            <show_img_dialog_vue/>
            <sheet_dialog_vue :show="sheet_dialog.show" :list="sheet_dialog.list" :title="sheet_dialog.title"
                              @close="handleClose"
                              :close-on-click-modal="sheet_dialog.closeOnClickModal"
                              @options-click="handleOptionsClick"/>
          </div>`,
            components: {
                output_information_vue: outputInformationVue,
                donate_layout_vue: donateLayoutVue,
                rule_management_vue: ruleManagementVue,
                cache_management_vue,
                panel_settings_vue,
                compatible_setting_vue,
                look_content_dialog_vue,
                debugger_management_vue,
                page_processing_vue,
                about_and_feedback_vue,
                show_img_dialog_vue,
                sheet_dialog_vue,
                bullet_word_management_vue
            },
            data() {
                return {
                    drawer: false,
                    tabsActiveName: gmUtil.getData('mainTabsActiveName', '规则管理'),
                    debug_panel_show: isOpenDev(),
                    sheet_dialog: {
                        show: false,
                        list: [],
                        title: "",
                        optionsClick: null,
                        closeOnClickModal: true
                    }
                }
            },
            methods: {
                tabClick(tab) {
                    gmUtil.setData('mainTabsActiveName', tab.name);
                },
                handleClose() {
                    this.sheet_dialog.show = false;
                },
                handleOptionsClick(item) {
                    let tempBool;
                    const temp = this.sheet_dialog.optionsClick(item);
                    if (temp === undefined) {
                        tempBool = false;
                    } else {
                        tempBool = temp;
                    }
                    this.sheet_dialog.show = tempBool === true;
                }
            },
            created() {
                eventEmitter.on('主面板开关', () => {
                    const tempBool = this.drawer;
                    this.drawer = !tempBool;
                });
                eventEmitter.on('el-notify', (options) => {
                    this.$notify(options);
                });
                eventEmitter.on('el-msg', (...options) => {
                    this.$message(...options);
                });
                eventEmitter.on('el-alert', (...options) => {
                    this.$alert(...options);
                });
                eventEmitter.handler('el-confirm', (...options) => {
                    return this.$confirm(...options);
                });
                eventEmitter.on('debugger-dev-show', (bool) => {
                    debugger
                    this.debug_panel_show = bool;
                    if (bool) {
                        this.$alert('已开启测试调试面板', 'tip');
                    } else {
                        this.$alert('已关闭测试调试面板', 'tip');
                    }
                });
                eventEmitter.on('sheet-dialog', ({list, optionsClick, title = '选项', closeOnClickModal = false}) => {
                    this.sheet_dialog.show = true;
                    this.sheet_dialog.list = list;
                    this.sheet_dialog.title = title;
                    this.sheet_dialog.optionsClick = optionsClick;
                    this.sheet_dialog.closeOnClickModal = closeOnClickModal;
                });
                eventEmitter.handler('el-prompt', (...options) => {
                    return this.$prompt(...options)
                });
                eventEmitter.on('请求获取视频信息失败', (response, bvId) => {
                    requestIntervalQueue.clearPendingQueue();
                    eventEmitter.send('更新根据bv号网络请求获取视频信息状态', true);
                    this.$alert(`请求获取视频信息失败,状态码:${response.status},bv号:${bvId}
                \n。已自动禁用根据bv号网络请求获取视频信息状态
                \n如需关闭,请在面板条件限制里手动关闭。`, '错误', {
                        confirmButtonText: '确定',
                        type: 'error'
                    });
                });
                if (bAfterLoadingThePageOpenMainPanel()) {
                    this.drawer = true;
                }
            }
        });
    });
    var defCss = `
.el-vertical-center {
    display: flex;
    justify-content: center;
}
.el-horizontal-center {
    display: flex;
    align-items: center;
}
.el-horizontal-right {
    display: flex;
    justify-content: flex-end;
}
.el-horizontal-left {
    display: flex;
    justify-content: flex-start;
}
`;
    gmUtil.addStyle(`
[gz_bezel]{
border:1px solid ${localMKData.getBorderColor()}
}
`);
    gmUtil.addStyle(defCss);
    const toPlayCountOrBulletChat = (str) => {
        if (!str) {
            return -1
        }
        str = str.split(/[\t\r\f\n\s]*/g).join("");
        const replace = str.replace(/[^\d.]/g, '');
        if (str.endsWith('万') || str.endsWith('万次') || str.endsWith('万弹幕')) {
            return parseFloat(replace) * 10000;
        }
        if (str.endsWith('次') || str.endsWith('弹幕')) {
            return parseInt(replace);
        }
        return parseInt(str)
    };
    const timeStringToSeconds = (timeStr) => {
        if (!timeStr) {
            return -1
        }
        const parts = timeStr.split(':');
        switch (parts.length) {
            case 1: // 只有秒
                return Number(parts[0]);
            case 2: // 分钟和秒
                return Number(parts[0]) * 60 + Number(parts[1]);
            case 3: // 小时、分钟和秒
                return Number(parts[0]) * 3600 + Number(parts[1]) * 60 + Number(parts[2]);
            default:
                throw new Error('Invalid time format');
        }
    };
    var sFormatUtil = {
        toPlayCountOrBulletChat,
        timeStringToSeconds
    };
    const exactMatch = (ruleList, value) => {
        if (ruleList === null || ruleList === undefined) return false;
        if (!Array.isArray(ruleList)) return false
        return ruleList.some(item => item === value);
    };
    const bFuzzyAndRegularMatchingWordsToLowercase = localMKData.bFuzzyAndRegularMatchingWordsToLowercase();
    const regexMatch = (ruleList, value) => {
        if (ruleList === null || ruleList === undefined) return null;
        if (!Array.isArray(ruleList)) return null
        if (bFuzzyAndRegularMatchingWordsToLowercase) {
            value = value.toLowerCase();
        }
        value = value.split(/[\t\r\f\n\s]*/g).join("");
        const find = ruleList.find(item => {
            try {
                return value.search(item) !== -1;
            } catch (e) {
                const msg = `正则匹配失败,请检查规则列表中的正则表达式是否正确,错误信息:${e.message}`;
                eventEmitter.send('正则匹配时异常', {e, msg});
                return false;
            }
        });
        return find === undefined ? null : find;
    };
    const fuzzyMatch = (ruleList, value) => {
        if (ruleList === null || ruleList === undefined || value === null) return null;
        if (!Array.isArray(ruleList)) return null
        const find = ruleList.find(item => value.toLowerCase().includes(item));
        return find === undefined ? null : find;
    };
    var ruleMatchingUtil = {
        exactMatch,
        regexMatch,
        fuzzyMatch
    };
    const outputInformationFontColor = localMKData.getOutputInformationFontColor();
    const highlightInformationColor = localMKData.getHighlightInformationColor();
    const getLiveRoomCommentInfoHtml = (type, matching, commentData) => {
        const toTimeString = defUtil.toTimeString();
        const {name, uid, content} = commentData;
        return `<b style="color: ${outputInformationFontColor}; " gz_bezel>
${toTimeString}-根据${type}-${matching ? `<b style="color: ${highlightInformationColor}">【${matching}】</b>` : ""}-屏蔽用户【${name}】uid=
            <a href="https://space.bilibili.com/${uid}" 
            style="color: ${highlightInformationColor}"
            target="_blank">【${uid}】</a>
            直播评论【${content}】
            </b>`
    };
    const getDynamicContentInfoHtml = (type, matching, dynamicData) => {
        const toTimeString = defUtil.toTimeString();
        const {name, uid, content} = dynamicData;
        return `<b style="color: ${outputInformationFontColor}; " gz_bezel>
${toTimeString}-根据${type}-${matching ? `<b style="color: ${highlightInformationColor}">【${matching}】</b>` : ""}-屏蔽用户【${name}】uid=
            <a href="https://space.bilibili.com/${uid}" 
            style="color: ${highlightInformationColor}"
            target="_blank">【${uid}】</a>
            动态【${content}】
            </b>`
    };
    const getLiveRoomInfoHtml = (type, matching, liveRoomData) => {
        const toTimeString = defUtil.toTimeString();
        const {name = null, uid = -1, title, liveUrl} = liveRoomData;
        return `<b style="color: ${outputInformationFontColor};" gz_bezel>
${toTimeString}-根据${type}${matching ? `<b style="color: ${highlightInformationColor}">【${matching}】</b>` : ""}-屏蔽用户【${name === null ? '' : name}】${uid === -1 ? "" : `uid=
            <a href="https://space.bilibili.com/${uid}"
            style="color: ${highlightInformationColor}"
            target="_blank">【${uid}】</a>`}
            直播间标题【<a href="${liveUrl}" target="_blank" style="color: ${highlightInformationColor}">${title}</a>】
</b>`
    };
    var output_informationTab = {
        getLiveRoomCommentInfoHtml,
        getDynamicContentInfoHtml,
        getLiveRoomInfoHtml
    };
    class ElEventEmitter {
        #elEvents = new Map()
        addEvent(el, eventName, callback, repeated = false) {
            const elEvents = this.#elEvents;
            if (!elEvents.has(el)) {
                elEvents.set(el, {events: [], attrs: []});
            }
            const {events, attrs} = elEvents.get(el);
            if (!repeated) {
                if (attrs.includes(eventName)) {
                    return
                }
            }
            attrs.push(eventName);
            events.push({eventName, callback});
            el.setAttribute(`gz-event`, JSON.stringify(attrs));
            el.addEventListener(eventName, callback);
        }
        hasEventName(el, eventName) {
            const elEvents = this.#elEvents;
            if (elEvents.has(el)) {
                return true
            }
            const {attrs} = elEvents.get(el);
            return attrs.includes(eventName)
        }
    }
    const elEventEmitter = new ElEventEmitter();
    const addBlockButton$1 = (data, tagCss = '', position = []) => {
        const {insertionPositionEl, explicitSubjectEl, css} = data.data;
        if (tagCss !== '') {
            if (insertionPositionEl.querySelector("." + tagCss)) return;
        }
        const buttonEL = document.createElement("button");
        buttonEL.setAttribute("gz_type", "");
        if (tagCss !== '') {
            buttonEL.className = tagCss;
        }
        buttonEL.textContent = "屏蔽";
        if (position.length !== 0) {
            buttonEL.style.position = "absolute";
        }
        if (position.includes("right")) {
            buttonEL.style.right = "0";
        }
        if (position.includes("bottom")) {
            buttonEL.style.bottom = "0";
        }
        if (css !== undefined) {
            for (let key of Object.keys(css)) {
                buttonEL.style[key] = css[key];
            }
        }
        if (explicitSubjectEl) {
            buttonEL.style.display = "none";
            elEventEmitter.addEvent(explicitSubjectEl, "mouseout", () => buttonEL.style.display = "none");
            elEventEmitter.addEvent(explicitSubjectEl, "mouseover", () => buttonEL.style.display = "");
        }
        insertionPositionEl.appendChild(buttonEL);
        buttonEL.addEventListener("click", (event) => {
            event.stopImmediatePropagation(); // 阻止事件冒泡和同一元素上的其他事件处理器
            event.preventDefault(); // 阻止默认行为
            const {uid = -1, name = null} = data.data;
            const showList = [];
            showList.push(uid !== -1 ? {
                label: `uid精确屏蔽-用户uid=${uid}-name=${name}`,
                value: "uid"
            } : {
                label: `用户名精确屏蔽(不推荐)-用户name=${name}`,
                value: 'name'
            });
            eventEmitter.send('sheet-dialog', {
                title: "屏蔽选项",
                list: showList,
                optionsClick: (item) => {
                    const {value} = item;
                    if (value === 'uid') {
                        if (uid === -1) {
                            eventEmitter.send('el-msg', "该页面数据不存在uid字段");
                            return;
                        }
                        const {status} = ruleUtil.addRulePreciseUid(uid);
                        if (status) {
                            data.maskingFunc();
                        }
                        return;
                    }
                    eventEmitter.invoke('el-confirm', '不推荐用户使用精确用户名来屏蔽,确定继续吗?').then(() => {
                        ruleUtil.addRulePreciseName(name);
                    });
                }
            });
        });
    };
    const addTopicDetailVideoBlockButton = (data) => {
        addBlockButton$1(data, "gz_shielding_button");
    };
    const addTopicDetailContentsBlockButton = (data) => {
        const position = data.data.position;
        const loop = position !== undefined;
        addBlockButton$1(data, "gz_shielding_topic_detail_button", loop ? position : []);
    };
    const blockUserUid = (uid) => {
        if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
            return {state: true, type: "精确uid"};
        }
        return returnTempVal;
    };
    const blockCheckWhiteUserUid = (uid) => {
        return ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidWhiteArr(), uid);
    };
    const blockExactAndFuzzyMatching = (val, config) => {
        if (!val) {
            return returnTempVal
        }
        if (config.exactKey) {
            if (ruleMatchingUtil.exactMatch(gmUtil.getData(config.exactKey, []), val)) {
                return {state: true, type: config.exactTypeName, matching: val}
            }
        }
        let matching;
        if (config.fuzzyKey) {
            matching = ruleMatchingUtil.fuzzyMatch(gmUtil.getData(config.fuzzyKey, []), val);
            if (matching) {
                return {state: true, type: config.fuzzyTypeName, matching}
            }
        }
        if (config.regexKey) {
            matching = ruleMatchingUtil.regexMatch(gmUtil.getData(config.regexKey, []), val);
            if (matching) {
                return {state: true, type: config.regexTypeName, matching}
            }
        }
        return returnTempVal
    };
    const blockComment = (comment) => {
        return blockExactAndFuzzyMatching(comment, {
            fuzzyKey: 'commentOn', fuzzyTypeName: '模糊评论',
            regexKey: 'commentOnCanonical', regexTypeName: '正则评论'
        })
    };
    const blockAvatarPendant = (name) => {
        return blockExactAndFuzzyMatching(name, {
            exactKey: 'precise_avatarPendantName',
            exactTypeName: '精确头像挂件名', fuzzyKey: 'avatarPendantName', fuzzyTypeName: '模糊头像挂件名'
        })
    };
    const asyncBlockAvatarPendant = async (name) => {
        const res = blockAvatarPendant(name);
        if (res.state) return Promise.reject(res);
    };
    const blockSignature = (signature) => {
        return blockExactAndFuzzyMatching(signature, {
            fuzzyKey: 'signature', fuzzyTypeName: '模糊用户签名', regexKey: 'signatureCanonical', regexTypeName: '正则用户签名'
        })
    };
    const asyncBlockSignature = async (signature) => {
        const res = blockSignature(signature);
        if (res.state) return Promise.reject(res);
    };
    const blockVideoDesc = (desc) => {
        return blockExactAndFuzzyMatching(desc, {
            fuzzyKey: 'videoDesc', fuzzyTypeName: '视频简介(模糊匹配)'
            , regexKey: 'videoDescCanonical', regexTypeName: '视频简介(正则匹配)'
        })
    };
    const asyncBlockVideoDesc = async (desc) => {
        const res = blockVideoDesc(desc);
        if (res.state) return Promise.reject(res);
    };
    const blockGender = (gender) => {
        const val = localMKData.isGenderRadioVal();
        const state = val === gender && val !== '不处理';
        if (state) {
            return {state: true, type: '性别屏蔽', matching: val}
        }
        return returnTempVal;
    };
    const asyncBlockGender = async (gender) => {
        const res = blockGender(gender);
        if (res.state) {
            return Promise.reject(res)
        }
    };
    const blockUserVip = (vipId) => {
        const val = localMKData.isVipTypeRadioVal();
        const vipMap = {
            0: '无',
            1: '月大会员',
            2: '年度及以上大会员'
        };
        if (val === vipMap[vipId]) {
            return {state: true, type: '会员类型屏蔽', matching: val}
        }
        return returnTempVal
    };
    const asyncBlockUserVip = async (vipId) => {
        const res = blockUserVip(vipId);
        if (res.state) {
            return Promise.reject(res)
        }
    };
    const blockSeniorMember = (num) => {
        if (num === 1 && localMKData.isSeniorMember()) {
            return {state: true, type: '屏蔽硬核会员'}
        }
        return returnTempVal
    };
    const asyncBlockSeniorMember = async (num) => {
        const res = blockSeniorMember(num);
        if (res.state) {
            return Promise.reject(res)
        }
    };
    const blockVideoCopyright = (num) => {
        const val = localMKData.isCopyrightRadio();
        const tempMap = {
            1: '原创',
            2: '转载'
        };
        if (val === tempMap[num]) {
            return {state: true, type: '视频类型屏蔽', matching: val}
        }
        return returnTempVal
    };
    const asyncBlockVideoCopyright = async (num) => {
        const res = blockVideoCopyright(num);
        if (res.state) {
            return Promise.reject(res)
        }
    };
    const blockVerticalVideo = (dimension) => {
        if (!localMKData.isBlockVerticalVideo()) {
            return returnTempVal
        }
        if (!dimension) {
            return returnTempVal
        }
        const vertical = dimension.width < dimension.height;
        if (vertical) {
            return {state: true, type: '竖屏视频屏蔽', matching: vertical}
        }
        return returnTempVal
    };
    const asyncBlockVerticalVideo = async (dimension) => {
        const res = blockVerticalVideo(dimension);
        if (res.state) return Promise.reject(res);
    };
    const blockVideoLikeRate = (like, view) => {
        if (!like || !view || !localMKData.isVideoLikeRateBlockingStatus()) {
            return returnTempVal
        }
        const mk_likeRate = parseInt(localMKData.getVideoLikeRate() * 100);
        if (isNaN(mk_likeRate)) {
            return returnTempVal
        }
        const likeRate = defUtil.calculateLikeRate(like, view);
        if (likeRate <= mk_likeRate) {
            return {
                state: true, type: '视频点赞率屏蔽', matching: mk_likeRate + '%'
                , msg: `视频的点赞率为${likeRate}%,低于用户指定的限制${mk_likeRate}%,屏蔽该视频`
            }
        }
        return returnTempVal
    };
    const asyncBlockVideoLikeRate = async (like, view) => {
        const res = blockVideoLikeRate(like, view);
        if (res.state) return Promise.reject(res);
    };
    const blockVideoInteractiveRate = (danmaku, reply, view) => {
        if (!danmaku || !view || !localMKData.isInteractiveRateBlockingStatus()) {
            return returnTempVal
        }
        const mk_interactionRate = parseInt(localMKData.getInteractiveRate() * 100);
        const interactionRate = defUtil.calculateInteractionRate(danmaku, reply, view);
        if (interactionRate <= mk_interactionRate) {
            return {
                state: true, type: '视频互动率屏蔽', matching: mk_interactionRate + '%'
                , msg: `视频的互动率为${interactionRate}%,低于用户指定的限制${mk_interactionRate}%,屏蔽该视频`
            }
        }
        return returnTempVal
    };
    const asyncBlockVideoInteractiveRate = async (danmaku, reply, view) => {
        const res = blockVideoInteractiveRate(danmaku, reply, view);
        if (res.state) return Promise.reject(res);
    };
    const blockVideoTripleRate = (favorite, coin, share, view) => {
        if (!favorite || !coin || !share || !view || !localMKData.isTripleRateBlockingStatus()) {
            return returnTempVal
        }
        const mk_tripleRate = parseInt(localMKData.getTripleRate() * 100);
        const tripleRate = defUtil.calculateTripleRate(favorite, coin, share, view);
        if (tripleRate <= mk_tripleRate) {
            return {
                state: true, type: '视频三连率屏蔽', matching: mk_tripleRate + '%'
                , msg: `视频的三连率为${tripleRate}%,低于用户指定的限制${mk_tripleRate}%,屏蔽该视频`
            }
        }
        return returnTempVal
    };
    const asyncBlockVideoTripleRate = async (favorite, coin, share, view) => {
        const res = blockVideoTripleRate(favorite, coin, share, view);
        if (res.state) return Promise.reject(res);
    };
    const blockVideoCoinLikesRatioRate = (coin, like) => {
        if (!coin || !like || !localMKData.isCoinLikesRatioRateBlockingStatus()) {
            return returnTempVal
        }
        const mk_coinLikesRatioRate = parseInt(localMKData.getCoinLikesRatioRate() * 100);
        const coinLikesRatioRate = defUtil.calculateCoinLikesRatioRate(coin, like);
        if (coinLikesRatioRate <= mk_coinLikesRatioRate) {
            return {
                state: true,
                type: '视频投币/点赞比(内容价值)屏蔽',
                matching: mk_coinLikesRatioRate + '%',
                msg: `视频的投币/点赞比(内容价值)为${coinLikesRatioRate}%,低于用户指定的限制${mk_coinLikesRatioRate}%,屏蔽该视频`
            }
        }
        return returnTempVal
    };
    const asyncBlockVideoCoinLikesRatioRate = async (coin, like) => {
        const res = blockVideoCoinLikesRatioRate(coin, like);
        if (res.state) return Promise.reject(res);
    };
    const blockByLevel = (level) => {
        if (!level) {
            return returnTempVal
        }
        const min = gmUtil.getData('nMinimumLevel', -1);
        if (min > level) {
            return {state: true, type: "最小用户等级过滤", matching: min};
        }
        const max = gmUtil.getData('nMaximumLevel', -1);
        if (max > level) {
            return {state: true, type: "最大用户等级过滤", matching: max};
        }
        return returnTempVal
    };
    const asyncBlockByLevel = async (level) => {
        const res = blockByLevel(level);
        if (res.state) return Promise.reject(res);
    };
    const blockUserUidAndName = (uid, name) => {
        if (!uid || !name) {
            return returnTempVal
        }
        let returnVal = blockUidWholeProcess(uid);
        if (returnVal.state) {
            return returnVal
        }
        returnVal = blockUserName(name);
        if (returnVal.state) {
            return returnVal
        }
        return returnTempVal
    };
    const asyncBlockUserUidAndName = async (uid, name) => {
        const res = blockUserUidAndName(uid, name);
        if (res.state) {
            return Promise.reject(res)
        }
    };
    const blockVideoTeamMember = (teamMember) => {
        if (!teamMember) {
            return returnTempVal
        }
        for (let u of teamMember) {
            const returnVal = blockUserUidAndName(u.mid, u.name);
            if (returnVal.state) {
                return returnVal
            }
        }
        return returnTempVal
    };
    const asyncBlockVideoTeamMember = async (teamMember) => {
        const res = blockVideoTeamMember(teamMember);
        if (res.state) return Promise.reject(res)
    };
    const blockUserName = (name) => {
        return blockExactAndFuzzyMatching(name, {
            exactKey: 'precise_name',
            exactTypeName: '精确用户名', fuzzyKey: 'name', fuzzyTypeName: '模糊用户名',
            regexKey: 'nameCanonical', regexTypeName: '正则用户名'
        })
    };
    const blockVideoOrOtherTitle = (title) => {
        return blockExactAndFuzzyMatching(title, {
            fuzzyKey: 'title', fuzzyTypeName: '模糊标题',
            regexKey: 'titleCanonical', regexTypeName: '正则标题'
        })
    };
    const blockBasedVideoTag = (tags) => {
        const preciseVideoTagArr = ruleKeyListData$1.getPreciseVideoTagArr();
        const videoTagArr = ruleKeyListData$1.getVideoTagArr();
        if (preciseVideoTagArr.length <= 0 && videoTagArr.length <= 0) {
            return returnTempVal
        }
        for (let tag of tags) {
            if (ruleMatchingUtil.exactMatch(preciseVideoTagArr, tag)) {
                return {state: true, type: "精确视频tag", matching: tag}
            }
            let fuzzyMatch = ruleMatchingUtil.fuzzyMatch(videoTagArr, tag);
            if (fuzzyMatch) {
                return {state: true, type: "模糊视频tag", matching: fuzzyMatch}
            }
            fuzzyMatch = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getVideoTagCanonicalArr(), tag);
            if (fuzzyMatch) {
                return {state: true, type: "正则视频tag", matching: fuzzyMatch}
            }
        }
        return returnTempVal
    };
    const asyncBlockBasedVideoTag = async (tags) => {
        const res = blockBasedVideoTag(tags);
        if (res.state) return Promise.reject(res);
    };
    const blockByUidRange = (uid) => {
        if (!localMKData.isUidRangeMaskingStatus()) {
            return returnTempVal
        }
        const [head, tail] = localMKData.getUidRangeMasking();
        if (head >= uid <= tail) {
            return {state: true, type: "uid范围屏蔽", matching: `${head}=>${uid}<=${tail}`}
        }
        return returnTempVal
    };
    const blockUidWholeProcess = (uid) => {
        if (!uid || blockCheckWhiteUserUid(uid)) return returnTempVal
        let returnVal = blockUserUid(uid);
        if (returnVal.state) {
            return returnVal;
        }
        return blockByUidRange(uid)
    };
    const asyncBlockFollowedVideo = (following) => {
        if (following && localMKData.isBlockFollowed()) {
            return Promise.reject({state: true, type: '已关注'})
        }
    };
    const asyncBlockChargeVideo = (isUpOwnerExclusive) => {
        if (isUpOwnerExclusive && localMKData.isUpOwnerExclusive()) {
            return Promise.reject({state: true, type: '充电专属视频'})
        }
    };
    const blockTimeRangeMasking = (timestamp) => {
        if (!timestamp || !localMKData.isTimeRangeMaskingStatus()) {
            return returnTempVal
        }
        const timeRangeMaskingArr = localMKData.getTimeRangeMaskingArr();
        if (timeRangeMaskingArr.length === 0) {
            return returnTempVal;
        }
        for (let {status, r: [startTimestamp, endTimestamp]} of timeRangeMaskingArr) {
            if (!status) continue
            const startSecondsTimestamp = Math.floor(startTimestamp / 1000);
            const endSecondsTimestamp = Math.floor(endTimestamp / 1000);
            if (startSecondsTimestamp >= timestamp <= endSecondsTimestamp) {
                const startToTime = new Date(startTimestamp).toLocaleString();
                const endToTime = new Date(endTimestamp).toLocaleString();
                const timestampToTime = new Date(timestamp * 1000).toLocaleString();
                return {state: true, type: "时间范围屏蔽", matching: `${startToTime}=>${timestampToTime}<=${endToTime}`}
            }
        }
        return returnTempVal
    };
    const asyncBlockTimeRangeMasking = async (timestamp) => {
        const res = blockTimeRangeMasking(timestamp);
        if (res.state) return Promise.reject(res);
    };
    const shieldingDynamic = (dynamicData) => {
        const {
            content = null,
            el,
            title = null,
            tag = null
        } = dynamicData;
        let matching = null;
        if (content !== null) {
            matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getCommentOnArr(), content);
            if (matching !== null) {
                el?.remove();
                return {state: true, type: "模糊评论内容", matching};
            }
            matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getCommentOnCanonicalArr(), content);
            if (matching !== null) {
                el?.remove();
                return {state: true, type: "正则评论内容", matching};
            }
        }
        if (title !== null) {
            matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getTitleArr(), title);
            if (matching !== null) {
                el?.remove();
                return {state: true, type: "模糊标题", matching};
            }
            matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getTitleCanonicalArr(), title);
            if (matching !== null) {
                el?.remove();
                return {state: true, type: "正则标题", matching};
            }
        }
        if (tag !== null) {
            if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseTagArr(), tag)) {
                el?.remove();
                return {state: true, type: "精确话题tag"};
            }
            matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getTagArr(), tag);
            if (matching !== null) {
                el?.remove();
                return {state: true, type: "模糊话题tag", matching};
            }
            matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getTagCanonicalArr(), tag);
            if (matching !== null) {
                el?.remove();
                return {state: true, type: "正则话题tag", matching};
            }
        }
        return returnTempVal
    };
    const shieldingDynamicDecorated = (dynamicData) => {
        const {state, type, matching} = shieldingDynamic(dynamicData);
        if (state) {
            const infoHtml = output_informationTab.getDynamicContentInfoHtml(type, matching, dynamicData);
            eventEmitter.send('打印信息', infoHtml);
        }
        return state;
    };
    const intervalExecutionStartShieldingVideoInert = (func, name = '') => {
        let i1 = -1;
        const start = () => {
            if (i1 !== -1) {
                return
            }
            console.log('开始执行屏蔽' + name);
            i1 = setInterval(() => {
                func();
                console.log(`执行屏蔽${name}列表-定时器正在执行`);
            }, 800);
        };
        const stop = () => {
            if (i1 === -1) {
                return
            }
            clearInterval(i1);
            console.log(`已停止执行屏蔽${name}列表`);
            i1 = -1;
        };
        return {start, stop}
    };
    var shielding = {
        shieldingDynamicDecorated,
        addTopicDetailVideoBlockButton,
        addTopicDetailContentsBlockButton,
        intervalExecutionStartShieldingVideoInert,
        addBlockButton: addBlockButton$1
    };
    class VideoInfoCache {
        #caches = [];
        getCaches() {
            return this.#caches;
        }
        getCount() {
            return this.#caches.length;
        }
        addData(data) {
            this.#caches.push(data);
        }
        is(bv) {
            return this.#caches.some(item => item.bv === bv);
        }
        find(bv) {
            const find = this.#caches.find(item => item.bv === bv);
            if (find) {
                return find
            }
            return null
        }
        async update() {
            this.#caches = await bvDexie.getVideoInfo();
            return this.getCaches();
        }
    }
    const videoInfoCache = new VideoInfoCache();
    const asyncBlockVideoTagPreciseCombination = async (tags) => {
        if (tags.length <= 0) return;
        const mkArrTags = ruleKeyListData$1.getVideoTagPreciseCombination();
        for (let mkTags of mkArrTags) {
            if (arrUtil.arrayContains(tags, mkTags)) return Promise.reject({
                state: true,
                type: "多重tag屏蔽",
                matching: mkTags
            })
        }
    };
    const blockVideoBV = (bv) => {
        const bvs = ruleKeyListData$1.getPreciseVideoBV();
        if (bvs.includes(bv)) return Promise.reject({
            state: true,
            type: "精确bv号屏蔽",
            matching: bv
        })
        return returnTempVal
    };
    const shieldingVideo = (videoData) => {
        const {
            title, uid = -1,
            name, nDuration = -1,
            nBulletChat = -1, nPlayCount = -1,
            bv = null
        } = videoData;
        let returnVal = blockUserUidAndName(uid, name);
        if (returnVal.state) {
            return returnVal;
        }
        returnVal = blockVideoOrOtherTitle(title);
        if (returnVal.state) {
            return returnVal
        }
        returnVal = blockVideoBV(bv);
        if (returnVal.state) return returnVal;
        if (nDuration !== -1) {
            const min = gmUtil.getData('nMinimumDuration', -1);
            if (min > nDuration && min !== -1) {
                return {state: true, type: '最小时长', matching: min}
            }
            const max = gmUtil.getData('nMaximumDuration', -1);
            if (max < nDuration && max !== -1) {
                return {state: true, type: '最大时长', matching: max}
            }
        }
        if (nBulletChat !== -1) {
            const min = gmUtil.getData('nMinimumBarrage', -1);
            if (min > nBulletChat && min !== -1) {
                return {state: true, type: '最小弹幕数', matching: min}
            }
            const max = gmUtil.getData('nMaximumBarrage', -1);
            if (max < nBulletChat && max !== -1) {
                return {state: true, type: '最大弹幕数', matching: max}
            }
        }
        if (nPlayCount !== -1) {
            const min = gmUtil.getData('nMinimumPlay', -1);
            if (min > nPlayCount && min !== -1) {
                return {state: true, type: '最小播放量', matching: min}
            }
            const max = gmUtil.getData('nMaximumPlayback', -1);
            if (max < nPlayCount && max !== -1) {
                return {state: true, type: '最大播放量', matching: max}
            }
        }
        return returnTempVal;
    };
    const shieldingVideoDecorated = (videoData, method = "remove") => {
        const {el} = videoData;
        if (el.style.display === "none") return true;
        const {state, type, matching = null} = shieldingVideo(videoData);
        if (state) {
            eventEmitter.send('event-屏蔽视频元素', {res: {state, type, matching}, method, videoData});
            return true;
        }
        if (localMKData.isDisableNetRequestsBvVideoInfo()) return state;
        shieldingOtherVideoParameter(videoData, method);
        return state;
    };
    eventEmitter.on('event-屏蔽视频元素', ({res, method = "remove", videoData}) => {
        if (!res) return
        const {type, matching} = res;
        const {el} = videoData;
        if (method === "remove") {
            el?.remove();
        } else {
            el.style.display = "none";
        }
        eventEmitter.send('屏蔽视频信息', type, matching, videoData);
    });
    const shieldingOtherVideoParameter = async (videoData, method) => {
        const {bv = '-1'} = videoData;
        if (bv === '-1') return
        if (videoInfoCache.getCount() === 0) {
            await videoInfoCache.update();
        }
        const find = videoInfoCache.find(bv);
        let result;
        if (find === null) {
            const {state, data, msg} = await requestIntervalQueue.add(() => bFetch.fetchGetVideoInfo(bv));
            if (!state) {
                console.warn('获取视频信息失败:' + msg);
                return
            }
            result = data;
            if (await bvDexie.addVideoData(bv, result)) {
                await videoInfoCache.update();
                console.log('mk-db-添加视频信息到数据库成功', result, videoData);
            }
        } else {
            result = find;
        }
        const {tags = [], userInfo, videoInfo} = result;
        asyncBlockUserUidAndName(userInfo.mid, userInfo.name)
            .then(() => asyncBlockVideoTagPreciseCombination(tags))
            .then(() => asyncBlockBasedVideoTag(tags))
            .then(() => asyncBlockVerticalVideo(videoInfo.dimension))
            .then(() => asyncBlockVideoCopyright(videoInfo.copyright))
            .then(() => asyncBlockChargeVideo(videoInfo?.is_upower_exclusive))
            .then(() => asyncBlockFollowedVideo(videoInfo?.following))
            .then(() => asyncBlockSeniorMember(userInfo.is_senior_member))
            .then(() => asyncBlockVideoTeamMember(userInfo.mid))
            .then(() => asyncBlockVideoLikeRate(videoInfo.like, videoInfo.view))
            .then(() => asyncBlockVideoInteractiveRate(videoInfo.danmaku, videoInfo.reply, videoInfo.view))
            .then(() => asyncBlockVideoTripleRate(videoInfo.favorite, videoInfo.coin, videoInfo.share, videoInfo.view))
            .then(() => asyncBlockVideoCoinLikesRatioRate(videoInfo.coin, videoInfo.like))
            .then(() => asyncBlockTimeRangeMasking(videoInfo.pubdate))
            .then(() => asyncBlockVideoDesc(videoInfo?.desc))
            .then(() => asyncBlockSignature(videoInfo?.sign))
            .then(() => asyncBlockAvatarPendant(userInfo?.pendant?.name))
            .then(() => asyncBlockByLevel(userInfo?.current_level || -1))
            .then(() => asyncBlockGender(userInfo?.sex))
            .then(() => asyncBlockUserVip(userInfo.vip.type))
            .catch((v) => {
                const msg = v['msg'];
                if (msg) {
                    console.warn(msg);
                }
                eventEmitter.send('event-屏蔽视频元素', {res: v, method, videoData});
            });
    };
    eventEmitter.on('添加热门视频屏蔽按钮', (data) => {
        shielding.addBlockButton(data, "gz_shielding_button", ["right", "bottom"]);
    });
    eventEmitter.on('视频添加屏蔽按钮-BewlyBewly', (data) => {
        shielding.addBlockButton(data, "gz_shielding_button", ['right', 'bottom']);
    });
    eventEmitter.on('视频添加屏蔽按钮', (data) => {
        shielding.addBlockButton(data, "gz_shielding_button", ["right"]);
    });
    var video_shielding = {
        shieldingVideoDecorated
    };
    const isHome = (url, title) => {
        if (title !== "哔哩哔哩 (゜-゜)つロ 干杯~-bilibili") {
            return false
        }
        if (url === 'https://www.bilibili.com/') {
            return true
        }
        return url.includes('https://www.bilibili.com/?spm_id_from=')
    };
    const deDesktopDownloadTipEl = async () => {
        const el = await elUtil.findElementUntilFound(".desktop-download-tip");
        el?.remove();
        const log = "已删除下载提示";
        console.log(log, el);
    };
    const getChangeTheVideoElList = async () => {
        const elList = await elUtil.findElementsUntilFound(".container.is-version8>.feed-card");
        const list = [];
        for (let el of elList) {
            try {
                const tempData = getVideoData(el);
                const {userUrl} = tempData;
                const videoUrl = el.querySelector(".bili-video-card__info--tit>a")?.href || null;
                if (!userUrl.includes("//space.bilibili.com/")) {
                    el?.remove();
                    const log = "遍历换一换视频列表中检测到异常内容,已将该元素移除";
                    console.log(log, el);
                    continue;
                }
                const items = {
                    ...tempData, ...{
                        videoUrl,
                        el,
                        insertionPositionEl: el.querySelector(".bili-video-card__info--bottom"),
                        explicitSubjectEl: el.querySelector(".bili-video-card__info")
                    }
                };
                if (videoUrl?.includes('www.bilibili.com/video')) {
                    items.bv = elUtil.getUrlBV(videoUrl);
                }
                list.push(items);
            } catch (e) {
                el.remove();
                console.warn("获取视频信息失败");
            }
        }
        return list
    };
    const getVideoData = (el) => {
        const title = el.querySelector(".bili-video-card__info--tit").title;
        const name = el.querySelector(".bili-video-card__info--author").textContent.trim();
        let nPlayCount = el.querySelector('.bili-video-card__stats--text')?.textContent.trim();
        nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
        let nBulletChat = el.querySelector('.bili-video-card__stats--text')?.textContent.trim();
        nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
        let nDuration = el.querySelector('.bili-video-card__stats__duration')?.textContent.trim();
        nDuration = sFormatUtil.timeStringToSeconds(nDuration);
        const userUrl = el.querySelector(".bili-video-card__info--owner").getAttribute("href");
        const uid = elUtil.getUrlUID(userUrl);
        return {
            title,
            name,
            uid,
            nPlayCount,
            nBulletChat,
            nDuration,
            userUrl
        }
    };
    const getHomeVideoELList = async () => {
        const elList = await elUtil.findElementsUntilFound(".container.is-version8>.bili-video-card");
        let list = [];
        for (let el of elList) {
            try {
                const tempData = getVideoData(el);
                const {userUrl} = tempData;
                if (!userUrl.includes("//space.bilibili.com/")) {
                    el?.remove();
                    const log = "遍历换一换视频列表下面列表时检测到异常内容,已将该元素移除";
                    eventEmitter.send('打印信息', log);
                    console.log(log, el);
                    continue;
                }
                const videoUrl = el.querySelector(".bili-video-card__info--tit>a")?.href;
                const items = {
                    ...tempData, ...{
                        videoUrl,
                        el,
                        insertionPositionEl: el.querySelector(".bili-video-card__info--bottom"),
                        explicitSubjectEl: el.querySelector(".bili-video-card__info")
                    }
                };
                if (videoUrl?.includes('www.bilibili.com/video')) {
                    items.bv = elUtil.getUrlBV(videoUrl);
                }
                list.push(items);
            } catch (e) {
                el?.remove();
                console.log("遍历视频列表中检测到异常内容,已将该元素移除;");
            }
        }
        return list;
    };
    const startClearExcessContentList = () => {
        if (globalValue.adaptationBAppCommerce) return;
        setInterval(() => {
            const otherElList = document.querySelectorAll(".floor-single-card");
            const liveList = document.querySelectorAll(".bili-live-card");
            const elList = [...otherElList, ...liveList];
            let rightAdEl = document.querySelector('.adcard');
            if (rightAdEl) {
                elList.push(rightAdEl);
            }
            rightAdEl = document.querySelector('.fixed-card');
            if (rightAdEl) {
                elList.push(rightAdEl);
            }
            for (let el of elList) {
                el?.remove();
                console.log("已清理首页视频列表中多余的内容,直播选项卡,右侧大卡片广告,右侧小卡片广告等", el);
            }
        }, 1000);
        console.log("已启动每秒清理首页视频列表中多余的内容");
    };
    const startShieldingChangeVideoList = async () => {
        const list = await getChangeTheVideoElList();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingChangeVideoList});
        }
    };
    const startDebounceShieldingChangeVideoList = defUtil.debounce(startShieldingChangeVideoList, 200);
    const startShieldingHomeVideoList = async () => {
        const homeVideoELList = await getHomeVideoELList();
        for (const videoData of homeVideoELList) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingHomeVideoList});
        }
    };
    const startDebounceShieldingHomeVideoList = defUtil.debounce(startShieldingHomeVideoList, 500);
    const scrollMouseUpAndDown = async () => {
        if (globalValue.adaptationBAppCommerce) return;
        await defUtil.smoothScroll(false, 100);
        return defUtil.smoothScroll(true, 600);
    };
    var bilibiliHome = {
        isHome,
        startClearExcessContentList,
        startDebounceShieldingChangeVideoList,
        startDebounceShieldingHomeVideoList,
        scrollMouseUpAndDown,
        deDesktopDownloadTipEl,
        getVideoData
    };
    const isSearch = (url) => {
        return url.includes("search.bilibili.com")
    };
    const isSearchVideoNetWorkUrl = (netUrl) => {
        if (netUrl.includes('api.bilibili.com/x/web-interface/wbi/search/all/v2')) return true;
        if (!netUrl.includes('api.bilibili.com/x/web-interface/wbi/search/type')) return false;
        const parseUrl = defUtil.parseUrl(netUrl);
        const search_type = parseUrl.queryParams['search_type'] || null;
        return search_type === 'video';
    };
    const isSearchLiveRoomNetWorkUrl = (netUrl) => {
        if (!netUrl.includes('api.bilibili.com/x/web-interface/wbi/search/type')) return false;
        const parseUrl = defUtil.parseUrl(netUrl);
        const search_type = parseUrl.queryParams['search_type'] || null;
        return search_type === 'live';
    };
    const getVideoList$1 = async (css) => {
        const elList = await elUtil.findElements(css, {interval: 200});
        const list = [];
        for (let el of elList) {
            const title = el.querySelector(".bili-video-card__info--tit").title;
            const userEl = el.querySelector(".bili-video-card__info--owner");
            if (userEl === null) {
                console.log("获取不到该视频卡片的用户地址,", el);
                el?.remove();
                continue
            }
            const userUrl = userEl.getAttribute("href");
            if (!userUrl.includes("//space.bilibili.com/")) {
                el?.remove();
                console.log("移除了非视频内容", userUrl, el);
                continue;
            }
            const videoUrl = el.querySelector(".bili-video-card__info--right>a")?.href;
            if (videoUrl?.includes('live.bilibili.com/')) {
                continue
            }
            const bv = elUtil.getUrlBV(videoUrl);
            const uid = elUtil.getUrlUID(userUrl);
            const name = userEl.querySelector(".bili-video-card__info--author").textContent.trim();
            const bili_video_card__stats_item = el.querySelectorAll('.bili-video-card__stats--item');
            let nPlayCount = bili_video_card__stats_item[0]?.textContent.trim();
            nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
            let nBulletChat = bili_video_card__stats_item[1]?.textContent.trim();
            nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
            let nDuration = el.querySelector('.bili-video-card__stats__duration')?.textContent.trim();
            nDuration = sFormatUtil.timeStringToSeconds(nDuration);
            list.push({
                title,
                userUrl,
                name,
                uid,
                bv,
                nPlayCount,
                nBulletChat,
                nDuration,
                el,
                videoUrl,
                insertionPositionEl: el.querySelector(".bili-video-card__info--bottom"),
                explicitSubjectEl: el.querySelector(".bili-video-card__info")
            });
        }
        return list;
    };
    const getTabComprehensiveSortedVideoList = () => {
        return getVideoList$1(".video.i_wrapper.search-all-list>.video-list>div");
    };
    const getOtherVideoList = () => {
        return getVideoList$1(".search-page.search-page-video>.video-list.row>div:not(:empty)");
    };
    const startShieldingCSVideoList = async () => {
        const list = await getTabComprehensiveSortedVideoList();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingCSVideoList});
        }
    };
    const startShieldingOtherVideoList = async () => {
        const list = await getOtherVideoList();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingOtherVideoList});
        }
    };
    const getTwTabActiveItem = async () => {
        const twoTabActiveItem = await elUtil.findElement('.vui_button.vui_button--tab.vui_button--active.mr_sm', {interval: 200});
        const twoTabActiveItemLabel = twoTabActiveItem.textContent.trim();
        return {el: twoTabActiveItemLabel, label: twoTabActiveItemLabel}
    };
    const startShieldingVideoList$6 = async () => {
        const topTabActiveItem = await elUtil.findElement('.vui_tabs--nav-item.vui_tabs--nav-item-active', {interval: 200});
        const topTabActiveItemLabel = topTabActiveItem.textContent.trim();
        console.log(topTabActiveItemLabel);
        if (topTabActiveItemLabel !== '综合') {
            await startShieldingOtherVideoList();
            return
        }
        const {label} = await getTwTabActiveItem();
        if (label !== '综合排序') {
            await startShieldingOtherVideoList();
            return
        }
        const parseUrl = defUtil.parseUrl(window.location.href);
        if (parseUrl.queryParams['page']) {
            await startShieldingOtherVideoList();
        } else {
            await startShieldingCSVideoList();
            await processingExactSearchVideoCardContent();
        }
    };
    const processingExactSearchVideoCardContent = async () => {
        let res;
        try {
            res = await elUtil.findElement('.user-list.search-all-list', {interval: 50, timeout: 4000});
        } catch (e) {
            return
        }
        let el;
        if (!res.state) {
            return
        }
        el = res.data;
        const infoCardEl = el.querySelector('.info-card');
        const userNameEl = infoCardEl.querySelector('.user-name');
        const name = userNameEl.textContent.trim();
        const userUrl = userNameEl.href;
        const uid = elUtil.getUrlUID(userUrl);
        if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
            el.remove();
            eventEmitter.send('打印信息', `根据精确uid匹配到用户${name}-【${uid}】`);
            return
        }
        let fuzzyMatch = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getNameArr(), name);
        if (fuzzyMatch) {
            el.remove();
            eventEmitter.send('打印信息', `根据模糊用户名【${fuzzyMatch}】匹配到用户${name}-【${uid}】`);
            return
        }
        fuzzyMatch = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getNameCanonical(), name);
        if (fuzzyMatch) {
            el.remove();
            eventEmitter.send('打印信息', `根据正则用户名【${fuzzyMatch}】匹配到用户${name}-【${uid}】`);
            return
        }
        const insertionPositionEl = el.querySelector('.info-card.flex_start');
        shielding.addBlockButton({
            data: {
                name,
                uid,
                insertionPositionEl,
            }
        });
        const videoElList = el.querySelectorAll('.video-list>.video-list-item');
        const list = [];
        for (let videoEl of videoElList) {
            const titleEl = videoEl.querySelector('.bili-video-card__info--right>a');
            const videoUrl = titleEl.href;
            const bv = elUtil.getUrlBV(videoUrl);
            const title = titleEl.textContent.trim();
            let nDuration = videoEl.querySelector('.bili-video-card__stats__duration')?.textContent.trim();
            nDuration = sFormatUtil.timeStringToSeconds(nDuration);
            let nPlayCount = videoEl.querySelector('.bili-video-card__stats--item>span')?.textContent.trim();
            nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
            list.push({
                title,
                userUrl,
                name,
                uid,
                bv,
                nPlayCount,
                nDuration,
                el: videoEl,
                videoUrl
            });
        }
        for (let videoData of list) {
            video_shielding.shieldingVideoDecorated(videoData);
        }
    };
    const delFooterContent = () => {
        if (!gmUtil.getData('isRemoveSearchBottomContent', false)) {
            return
        }
        elUtil.findElement('#biliMainFooter').then(el => {
            el.remove();
            eventEmitter.send('打印信息', '已删除底部内容');
        });
    };
    var searchModel = {
        isSearch,
        startShieldingVideoList: startShieldingVideoList$6,
        delFooterContent,
        isSearchVideoNetWorkUrl,
        isSearchLiveRoomNetWorkUrl
    };
    const isVideoPlayPage = (url = window.location.href) => {
        return url.includes("www.bilibili.com/video");
    };
    const selectUserBlocking = async () => {
        const {state} = await elUtil.findElement('.header.can-pointer', {timeout: 1800});
        if (state) {
            const elList = document.querySelectorAll('.container>.membersinfo-upcard-wrap>.membersinfo-upcard');
            const list = [];
            for (const el of elList) {
                const userUrl = el.querySelector('.avatar').href;
                const uid = elUtil.getUrlUID(userUrl);
                const name = el.querySelector('.staff-name').textContent.trim();
                list.push({
                    label: `用户-name=${name}-uid=${uid}`,
                    uid
                });
            }
            eventEmitter.send('sheet-dialog', {
                title: '选择要屏蔽的用户(uid精确)',
                list,
                optionsClick: (item) => {
                    ruleUtil.addRulePreciseUid(item.uid);
                    return true
                }
            });
        } else {
            const el = document.querySelector('.up-info-container');
            const nameEl = el.querySelector('.up-info--right a.up-name');
            const name = nameEl.textContent.trim();
            const userUrl = nameEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            console.log('点击了屏蔽按钮', name, userUrl, uid);
            eventEmitter.invoke('el-confirm', `用户uid=${uid}-name=${name}`, 'uid精确屏蔽方式').then(() => {
                if (uid === -1) {
                    eventEmitter.send('el-msg', "该页面数据不存在uid字段");
                    return;
                }
                ruleUtil.addRulePreciseUid(uid);
            });
        }
    };
    const getGetTheVideoListOnTheRight$1 = async () => {
        await elUtil.findElementUntilFound(".video-page-card-small .b-img img");
        delAd();
        delGameAd();
        const elList = await elUtil.findElements(".rec-list>.video-page-card-small", {interval: 1000});
        const nextPlayEl = document.querySelector('.next-play>.video-page-card-small');
        if (nextPlayEl) {
            elList.push(nextPlayEl);
        }
        const list = [];
        for (let el of elList) {
            try {
                const elInfo = el.querySelector(".info");
                const title = elInfo.querySelector(".title").title;
                const name = elInfo.querySelector(".upname .name").textContent.trim();
                const userUrl = elInfo.querySelector(".upname>a").href;
                const uid = elUtil.getUrlUID(userUrl);
                const playInfo = el.querySelector('.playinfo').innerHTML.trim();
                const videoUrl = el.querySelector(".info>a").href;
                const bv = elUtil.getUrlBV(videoUrl);
                let nPlayCount = playInfo.match(/<\/svg>(.*)<svg/s)?.[1].trim();
                nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
                let nBulletChat = playInfo.match(/class="dm".+<\/svg>(.+)$/s)?.[1].trim();
                nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
                let nDuration = el.querySelector('.duration')?.textContent.trim();
                nDuration = sFormatUtil.timeStringToSeconds(nDuration);
                list.push({
                    title,
                    userUrl,
                    name,
                    uid,
                    bv,
                    nPlayCount,
                    nBulletChat,
                    nDuration,
                    el,
                    videoUrl,
                    insertionPositionEl: el.querySelector(".playinfo"),
                    explicitSubjectEl: elInfo
                });
            } catch (e) {
                console.error("获取右侧视频列表失败:", e);
            }
        }
        return list;
    };
    const startShieldingVideoList$5 = () => {
        if (localMKData.isDelPlayerPageRightVideoList()) {
            return
        }
        getGetTheVideoListOnTheRight$1().then((videoList) => {
            for (let videoData of videoList) {
                if (video_shielding.shieldingVideoDecorated(videoData)) {
                    continue;
                }
                eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingVideoList$5});
            }
        });
    };
    const findTheExpandButtonForTheListOnTheRightAndBindTheEvent$2 = () => {
        setTimeout(() => {
            elUtil.findElementUntilFound(".rec-footer", {interval: 2000}).then((el) => {
                console.log("找到右侧视频列表的展开按钮", el);
                el.addEventListener("click", () => {
                    startShieldingVideoList$5();
                });
            });
        }, 3000);
    };
    const getPlayerVideoList = async () => {
        const elList = await elUtil.findElements('.bpx-player-ending-related>.bpx-player-ending-related-item');
        const data = {list: [], cancelEl: null};
        for (const el of elList) {
            const title = el.querySelector('.bpx-player-ending-related-item-title')?.textContent.trim();
            const cancelEl = el.querySelector('.bpx-player-ending-related-item-cancel');
            if (cancelEl) {
                data.cancelEl = cancelEl;
            }
            data.list.push({
                title,
                el
            });
        }
        return data
    };
    const getVideoPlayerEndingPanelEl = async () => {
        return await elUtil.findElement('#bilibili-player .bpx-player-ending-wrap>.bpx-player-ending-panel',
            {interval: 50})
    };
    const setVideoPlayerEnded = async () => {
        const videoEl = await elUtil.findElement('#bilibili-player video');
        const funcStart = async () => {
            const res = await getPlayerVideoList();
            for (let {el, title} of res.list) {
                let matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getTitleArr(), title);
                if (matching !== null) {
                    eventEmitter.send('打印信息', `根据-模糊标题-【${matching}】-屏蔽视频:${title}`);
                    el.remove();
                    continue
                }
                matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getTitleCanonicalArr(), title);
                if (matching !== null) {
                    eventEmitter.send('打印信息', `根据-正则标题-【${matching}】-屏蔽视频:${title}`);
                    el.remove();
                }
            }
        };
        videoEl.addEventListener('ended', () => {
            console.log('视频播放结束');
            funcStart();
            if (localMKData.isDelPlayerEndingPanel()) {
                getVideoPlayerEndingPanelEl().then(el => {
                    el.remove();
                    eventEmitter.send('打印信息', '已删除播放页播放器中推荐层');
                });
            }
        });
    };
    const delAd = () => {
        if (!gmUtil.getData('isDelPlayerPageAd', false)) {
            return
        }
        elUtil.findElements('[class|=ad],#slide_ad').then(elList => {
            for (const el of elList) {
                el.style.display = 'none';
            }
            eventEmitter.send('打印信息', '隐藏了播放页的页面广告');
        });
    };
    const delRightVideoList = () => {
        if (!localMKData.isDelPlayerPageRightVideoList()) {
            return
        }
        elUtil.findElement('.recommend-list-v1').then(el => {
            el.style.visibility = "hidden";
            eventEmitter.send('打印信息', '屏蔽了播放页的右侧推荐列表');
        });
    };
    const delGameAd = () => {
        if (!gmUtil.getData('isDelPlayerPageRightGameAd', false)) {
            return
        }
        elUtil.findElement('.video-page-game-card-small', {timeout: 10000}).then(({state, data}) => {
            if (!state) {
                eventEmitter.send('打印信息', '没有找到播放页的右侧游戏推荐');
                return
            }
            data?.remove();
            eventEmitter.send('打印信息', '屏蔽了游戏推荐');
        });
    };
    const delBottomCommentApp = () => {
        if (!localMKData.isDelBottomComment()) {
            return
        }
        elUtil.findElement('#commentapp').then(el => {
            el?.remove();
            eventEmitter.send('打印信息', '移除了页面底部的评论区');
        });
    };
    const delElManagement = () => {
        if (localMKData.isDelPlayerPageRightVideoList()) {
            delAd();
        }
        delRightVideoList();
        delBottomCommentApp();
    };
    var videoPlayModel = {
        isVideoPlayPage,
        startShieldingVideoList: startShieldingVideoList$5,
        findTheExpandButtonForTheListOnTheRightAndBindTheEvent: findTheExpandButtonForTheListOnTheRightAndBindTheEvent$2,
        selectUserBlocking,
        setVideoPlayerEnded,
        delElManagement
    };
    const getPlayCountAndBulletChatAndDuration = (el) => {
        const playInfo = el.querySelector('.playinfo').innerHTML.trim();
        let nPlayCount = playInfo.match(/<\/svg>(.*)<svg/s)?.[1].trim();
        nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
        let nBulletChat = playInfo.match(/class="dm-icon".+<\/svg>(.+)$/s)?.[1].trim();
        nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
        let nDuration = el.querySelector('.duration')?.textContent.trim();
        nDuration = sFormatUtil.timeStringToSeconds(nDuration);
        return {
            nPlayCount, nBulletChat, nDuration
        }
    };
    const getRightVideoDataList$1=(elList)=>{
        const list = [];
        for (let el of elList) {
            const title = el.querySelector(".title").textContent.trim();
            const userInfoEl = el.querySelector(".upname");
            const name = userInfoEl.querySelector(".name").textContent.trim();
            const userUrl = userInfoEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            const videoUrl = el.querySelector(".info>a").href;
            const bv = elUtil.getUrlBV(videoUrl);
            list.push({
                ...getPlayCountAndBulletChatAndDuration(el), ...{
                    title,
                    name,
                    userUrl,
                    videoUrl,
                    uid,
                    bv,
                    el,
                    insertionPositionEl: el.querySelector(".playinfo"),
                    explicitSubjectEl: el.querySelector(".info")
                }
            });
        }
        return list;
    };
    var generalFuc = {getRightVideoDataList: getRightVideoDataList$1};
    const iscCollectionVideoPlayPage = (url) => {
        return url.includes("www.bilibili.com/list/ml")
    };
    const getGetTheVideoListOnTheRight = async () => {
        const elList = await elUtil.findElementsUntilFound(".recommend-list-container>.video-card");
        return generalFuc.getRightVideoDataList(elList);
    };
    const startShieldingVideoList$4 = () => {
        getGetTheVideoListOnTheRight().then((videoList) => {
            const css = {right: "123px"};
            for (let videoData of videoList) {
                if (video_shielding.shieldingVideoDecorated(videoData)) continue;
                videoData.css = css;
                eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingVideoList$4});
            }
        });
    };
    const findTheExpandButtonForTheListOnTheRightAndBindTheEvent$1 = () => {
        setTimeout(() => {
            elUtil.findElementUntilFound(".rec-footer", {interval: 2000}).then((el) => {
                el.addEventListener("click", () => {
                    startShieldingVideoList$4();
                });
            });
        }, 3000);
    };
    var collectionVideoPlayPageModel = {
        iscCollectionVideoPlayPage,
        startShieldingVideoList: startShieldingVideoList$4,
        findTheExpandButtonForTheListOnTheRightAndBindTheEvent: findTheExpandButtonForTheListOnTheRightAndBindTheEvent$1
    };
    const addEventListenerUrlChange = (callback) => {
        let oldUrl = window.location.href;
        setInterval(() => {
            const newUrl = window.location.href;
            if (oldUrl === newUrl) return;
            oldUrl = newUrl;
            const title = document.title;
            callback(newUrl, oldUrl, title);
        }, 1000);
    };
    const addEventListenerNetwork = (callback) => {
        new PerformanceObserver(() => {
            const entries = performance.getEntriesByType('resource');
            const windowUrl = window.location.href;
            const winTitle = document.title;
            for (let entry of entries) {
                const url = entry.name;
                const initiatorType = entry.initiatorType;
                if (initiatorType === "img" || initiatorType === "css" || initiatorType === "link" || initiatorType === "beacon") {
                    continue;
                }
                callback(url, windowUrl,winTitle, initiatorType);
            }
            performance.clearResourceTimings();//清除资源时间
        }).observe({entryTypes: ['resource']});
    };
    function watchElementListLengthWithInterval(selector, callback, config={}) {
        const defConfig = {};
        config = {...defConfig, ...config};
        let previousLength = -1;
        const timer = setInterval(() => {
                if (previousLength === -1) {
                    previousLength = document.querySelectorAll(selector).length;
                    return
                }
                const currentElements = document.querySelectorAll(selector);
                const currentLength = currentElements.length;
                if (currentLength !== previousLength) {
                    previousLength = currentLength;
                    callback({
                            action: currentLength > previousLength ? 'add' : 'del',
                            elements: currentElements,
                            length: currentLength
                        }
                    );
                }
            },
            config.interval
        );
        return stop = () => {
            clearInterval(timer);
        };
    }
    var watch = {
        addEventListenerUrlChange,
        addEventListenerNetwork,
        watchElementListLengthWithInterval
    };
    const blockCommentWordLimit = (content) => {
        const commentWordLimit = localMKData.getCommentWordLimitVal();
        if (commentWordLimit.length < 3) {
            return returnTempVal
        }
        if (content.length > commentWordLimit) {
            return {state: true, type: '屏蔽字数限制', matching: `字数限制为${commentWordLimit}`}
        }
        return returnTempVal;
    };
    const shieldingComment = (commentsData) => {
        const {content, uid, name, level = -1} = commentsData;
        let returnVal = blockUserUidAndName(uid, name);
        if (returnVal.state) {
            return returnVal
        }
        returnVal = blockComment(content);
        if (returnVal.state) {
            return returnVal
        }
        if (level !== -1) {
            return blockByLevel(level);
        }
        return blockCommentWordLimit(content);
    };
    const shieldingComments = (commentsDataList) => {
        for (let commentsData of commentsDataList) {
            if (shieldingCommentDecorated(commentsData)) continue;
            eventEmitter.send('评论添加屏蔽按钮', commentsData);
            const {replies = []} = commentsData;
            if (replies.length === 0) continue;
            for (let reply of replies) {
                if (shieldingCommentDecorated(reply)) continue;
                eventEmitter.send('评论添加屏蔽按钮', reply);
            }
        }
    };
    const shieldingCommentDecorated = (commentsData) => {
        const {state, type, matching} = shieldingComment(commentsData);
        if (state) {
            commentsData.el?.remove();
            eventEmitter.send('屏蔽评论信息', type, matching, commentsData);
        }
        eventEmitter.send('event-评论通知替换关键词', commentsData);
        return state;
    };
    var comments_shielding = {
        shieldingComment,
        shieldingComments,
        shieldingCommentDecorated
    };
    const shieldingLiveRoomContentDecorated = (liveRoomContent) => {
        let {state, type, matching} = comments_shielding.shieldingComment(liveRoomContent);
        const {el, fansMedal} = liveRoomContent;
        if (fansMedal !== null) {
            if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseFanCardArr(), fansMedal)) {
                el?.remove();
                state = true;
                type = "精确粉丝牌";
            }
        }
        if (state) {
            el?.remove();
        }
        if (type) {
            const infoHtml = output_informationTab.getLiveRoomCommentInfoHtml(type, matching, liveRoomContent);
            eventEmitter.send('打印信息', infoHtml);
        }
        return state;
    };
    const shieldingLiveRoom = (liveRoomData) => {
        const {name, title, partition, uid = -1} = liveRoomData;
        let returnVal;
        if (uid !== -1) {
            if (blockCheckWhiteUserUid(uid)) {
                return returnTempVal;
            }
            returnVal = blockUserUidAndName(uid, name);
            if (returnVal.state) {
                return returnVal
            }
        }
        returnVal = blockVideoOrOtherTitle(title);
        if (returnVal.state) {
            return returnVal
        }
        if (partition) {
            if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPrecisePartitionArr(), partition)) {
                return {state: true, type: "精确直播分区"};
            }
        }
        return returnTempVal;
    };
    const shieldingLiveRoomDecorated = (liveRoomData) => {
        const {state, type, matching = null} = shieldingLiveRoom(liveRoomData);
        if (state) {
            liveRoomData.el?.remove();
            const infoHtml = output_informationTab.getLiveRoomInfoHtml(type, matching, liveRoomData);
            eventEmitter.send('打印信息', infoHtml);
        }
        return state;
    };
    const addLiveContentBlockButton = (commentsData) => {
        shielding.addBlockButton(commentsData, "gz_shielding_live_danmaku_button");
    };
    var live_shielding = {
        shieldingLiveRoomDecorated,
        addLiveContentBlockButton
    };
    const isLiveRoom = (url) => {
        return url.search('/live.bilibili.com/\\d+') !== -1;
    };
    const getChatItems = async () => {
        const elList = await elUtil.findElementsUntilFound("#chat-items>div");
        if (elList.length >= 200) {
            for (let i = 0; i < 100; i++) {
                elList[i]?.remove();
            }
            console.log("弹幕列表超过200,已删除前100条");
        }
        const list = [];
        for (let el of elList) {
            if (el.className === "chat-item  convention-msg border-box") {
                continue;
            }
            if (el.className === "chat-item misc-msg guard-buy") {
                continue;
            }
            const name = el.getAttribute("data-uname");
            if (name === null) {
                continue;
            }
            const uid = el.getAttribute("data-uid");
            const content = el.getAttribute("data-danmaku");
            const timeStamp = el.getAttribute("data-timestamp");
            const fansMedalEl = el.querySelector(".fans-medal-content");
            const fansMedal = fansMedalEl === null ? null : fansMedalEl.textContent.trim();
            list.push({
                name,
                uid,
                content,
                timeStamp,
                fansMedal,
                el,
                insertionPositionEl: el,
                explicitSubjectEl: el
            });
        }
        return list;
    };
    const startShieldingLiveChatContents = async () => {
        const commentsDataList = await getChatItems();
        for (let commentsData of commentsDataList) {
            if (shieldingLiveRoomContentDecorated(commentsData)) {
                continue;
            }
            live_shielding.addLiveContentBlockButton({data: commentsData, maskingFunc: startShieldingLiveChatContents});
        }
    };
    const addWatchLiveRoomChatItemsListener = () => {
        const throttle = defUtil.throttle(startShieldingLiveChatContents, 1000);
        watch.watchElementListLengthWithInterval("#chat-items>div", throttle);
    };
    var liveRoomModel = {
        isLiveRoom,
        addWatchLiveRoomChatItemsListener
    };
    const isVideoPlayWatchLaterPage = (url) => {
        return url.startsWith("https://www.bilibili.com/list/watchlater")
    };
    const getRightVideoDataList = async () => {
        const elList = await elUtil.findElementsUntilFound(".recommend-video-card.video-card");
        return generalFuc.getRightVideoDataList(elList);
    };
    const startShieldingVideoList$3 = async () => {
        const videoList = await getRightVideoDataList();
        const css = {right: "123px"};
        for (let videoData of videoList) {
            videoData.css = css;
            if (video_shielding.shieldingVideoDecorated(videoData)) continue;
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingVideoList$3});
        }
    };
    const startDebounceShieldingVideoList = defUtil.debounce(startShieldingVideoList$3, 1000);
    const findTheExpandButtonForTheListOnTheRightAndBindTheEvent = () => {
        elUtil.findElementsAndBindEvents(".rec-footer", startDebounceShieldingVideoList);
    };
    var videoPlayWatchLater = {
        isVideoPlayWatchLaterPage,
        startDebounceShieldingVideoList,
        findTheExpandButtonForTheListOnTheRightAndBindTheEvent
    };
    const getBewlyEl = async () => {
        let el = await elUtil.findElementUntilFound('#bewly', {interval: 500});
        return el.shadowRoot;
    };
    const isBEWLYPage = (url) => {
        return url.includes('www.bilibili.com/?page=') ||
            url === 'https://www.bilibili.com/'
            || url.startsWith('https://www.bilibili.com/?spm_id_from=')
    };
    const check_BEWLYPage_compatibility = async () => {
        const {state} = await elUtil.findElement('#bewly', {interval: 200, timeout: 5000});
        if (state) {
            if (!globalValue.compatibleBEWLYBEWLY) {
                eventEmitter.send('el-alert', '检测到使用BewlyBewly插件但未开启兼容选项,需要启用相关兼容选项才可正常使用');
            }
        } else {
            if (globalValue.compatibleBEWLYBEWLY) {
                eventEmitter.send('el-alert', '检测到未使用BewlyBewly插件却开启了兼容选项,请关闭兼容选项或启用bilibili_gate脚本后再启用相关兼容选项');
            }
        }
    };
    const getVideoList = async () => {
        const beEl = await getBewlyEl();
        const elList = await elUtil.findElementsUntilFound('.video-card.group', {doc: beEl});
        const list = [];
        for (let el of elList) {
            const parentElement = el.parentElement.parentElement;
            const title = el.querySelector('.keep-two-lines>a[title]').textContent.trim();
            const userUrlEl = el.querySelector('.channel-name');
            const userUrl = userUrlEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            const name = userUrlEl.textContent.trim();
            const playInfoEl = el.querySelector('[flex="~ items-center gap-1 wrap"]>div');
            let playCount = playInfoEl.querySelector('span:first-child')?.textContent.trim() || null;
            playCount = sFormatUtil.toPlayCountOrBulletChat(playCount);
            let bulletChat = playInfoEl.querySelector('span:last-of-type')?.textContent.trim() || null;
            if (playInfoEl.querySelectorAll('span').length < 2) {
                bulletChat = -1;
            } else {
                bulletChat = sFormatUtil.toPlayCountOrBulletChat(bulletChat);
            }
            let nDuration = el.querySelector('[class*="group-hover:opacity-0"]')?.textContent.trim() || null;
            nDuration = sFormatUtil.timeStringToSeconds(nDuration);
            const videoUrl = el.querySelector('[href*="https://www.bilibili.com/video"]')?.href;
            const bv = elUtil.getUrlBV(videoUrl);
            const insertionPositionEl = el.querySelector('[class="group/desc"]');
            list.push({
                title,
                name,
                uid,
                bv,
                userUrl,
                videoUrl,
                playCount,
                bulletChat,
                nDuration,
                el: parentElement,
                insertionPositionEl,
                explicitSubjectEl: parentElement
            });
        }
        return list
    };
    const getRightTabs = async () => {
        const beEl = await getBewlyEl();
        const els = await elUtil.findElementsUntilFound(".dock-content-inner>.b-tooltip-wrapper", {doc: beEl});
        const list = [];
        for (let el of els) {
            const label = el.querySelector('.b-tooltip').textContent.trim();
            const active = !!el.querySelector('.dock-item.group.active');
            list.push({label, active, el});
        }
        return list;
    };
    const getHistoryVideoDataList = async () => {
        const beEL = await getBewlyEl();
        const elList = await elUtil.findElementsUntilFound("a.group[flex][cursor-pointer]", {doc: beEL});
        const list = [];
        for (let el of elList) {
            const titleEl = el.querySelector('h3.keep-two-lines');
            const videoUrlEl = titleEl.parentElement;
            const userEl = videoUrlEl.nextElementSibling;
            const videoUrl = videoUrlEl.href;
            const bv = elUtil.getUrlBV(videoUrl);
            const userUrl = userEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            const name = userEl.textContent.trim();
            const title = titleEl?.textContent.trim();
            const tempTime = el.querySelector('div[pos][rounded-8]')?.textContent.trim().split(/[\t\r\f\n\s]*/g).join("");
            const match = tempTime?.match(/\/(.*)/);
            let nDuration = match?.[1];
            nDuration = sFormatUtil.timeStringToSeconds(nDuration);
            list.push({
                title,
                userUrl,
                name,
                uid,
                videoUrl,
                nDuration,
                bv,
                el,
                insertionPositionEl: videoUrlEl.parentElement,
                explicitSubjectEl: el
            });
        }
        return list
    };
    const startShieldingHistoryVideoList = async () => {
        const list = await getHistoryVideoDataList();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingHistoryVideoList});
        }
    };
    const startShieldingVideoList$2 = async () => {
        const list = await getVideoList();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue
            }
            eventEmitter.send('视频添加屏蔽按钮-BewlyBewly', {data: videoData, maskingFunc: startShieldingVideoList$2});
        }
    };
    const intervalExecutionStartShieldingVideo$2 = () => {
        const res = shielding.intervalExecutionStartShieldingVideoInert(startShieldingVideoList$2, '视频');
        return () => {
            return res
        }
    };
    const intervalExecutionStartShieldingHistoryVideo = () => {
        const res = shielding.intervalExecutionStartShieldingVideoInert(startShieldingHistoryVideoList, '历史记录');
        return () => {
            return res
        }
    };
    const startShieldingVideo$1 = intervalExecutionStartShieldingVideo$2();
    const startShieldingHistoryVideo = intervalExecutionStartShieldingHistoryVideo();
    const rightTabsInsertListener = () => {
        getRightTabs().then(list => {
                for (let {el, label, active} of list) {
                    el.addEventListener('click', () => {
                            console.log('右侧选项卡栏点击了' + label, active);
                            if (label === '首页') {
                                homeTopTabsInsertListener();
                                startShieldingVideo$1().start();
                            } else {
                                startShieldingVideo$1().stop();
                            }
                            if (label === '观看历史') {
                                startShieldingHistoryVideo().start();
                            } else {
                                startShieldingHistoryVideo().stop();
                            }
                        }
                    );
                }
            }
        );
    };
    const getHomeTopTabs = async () => {
        const beEl = await getBewlyEl();
        const els = beEl.querySelectorAll('.home-tabs-inside>[data-overlayscrollbars-contents]>button');
        const list = [];
        for (let el of els) {
            const label = el.textContent.trim();
            const active = el.classList.contains('tab-activated');
            list.push({label, active, el});
        }
        if (list.some(tab => tab.active === true)) {
            return list
        }
        return await getHomeTopTabs()
    };
    const excludeTabNames = ['正在关注', '订阅剧集', '直播'];
    const excludeRankingLeftTabNames = ['番剧', '综艺', '电视剧', '纪录片', '中国动画'];
    const homeTopTabsInsertListener = () => {
        getHomeTopTabs().then(list => {
            for (let {el, label} of list) {
                el.addEventListener('click', () => {
                    console.log('点击了' + label);
                    if (excludeTabNames.includes(label)) {
                        startShieldingVideo$1().stop();
                        return
                    }
                    if (label === '排行') {
                        rankingLeftTabsInsertListener();
                    }
                    startShieldingVideo$1().start();
                });
            }
        });
    };
    const getRankingLeftTabs = async () => {
        const beEl = await getBewlyEl();
        const elList = await elUtil.findElementsUntilFound('ul[flex="~ col gap-2"]>li', {doc: beEl});
        const list = [];
        for (let el of elList) {
            const label = el.textContent.trim();
            list.push({label, el});
        }
        return list
    };
    const rankingLeftTabsInsertListener = () => {
        getRankingLeftTabs().then(list => {
            for (let {el, label} of list) {
                el.addEventListener('click', () => {
                    console.log('点击了' + label);
                    if (excludeRankingLeftTabNames.includes(label)) {
                        startShieldingVideo$1().stop();
                        return
                    }
                    startShieldingVideo$1().start();
                });
            }
        });
    };
    const installBEWLStyle = () => {
        getBewlyEl().then(el => {
            gz_ui_css.addStyle(el, el);
        });
    };
    const searchBoxInsertListener = async () => {
        const beEl = await getBewlyEl();
        const input = await elUtil.findElementUntilFound('[placeholder="搜索观看历史"]', {doc: beEl});
        input.addEventListener('keydown', (event) => {
            if (event.key === 'Enter' || event.keyCode === 13) {
                console.log('回车键被按下');
                if (input['value'].length === 0) return
                setTimeout(startShieldingHistoryVideoList, 1500);
            }
        });
    };
    const startRun$1 = async (url) => {
        const parseUrl = defUtil.parseUrl(url);
        const {page} = parseUrl.queryParams;
        installBEWLStyle();
        if (page === 'Home' ||
            url.startsWith('https://www.bilibili.com/?spm_id_from=') ||
            url === 'https://www.bilibili.com/'
        ) {
            startShieldingVideo$1().start();
            homeTopTabsInsertListener();
        }
        if (page === 'History') {
            startShieldingHistoryVideo().start();
            searchBoxInsertListener();
        }
        rightTabsInsertListener();
    };
    var compatibleBewlyBewly = {
        startRun: startRun$1,
        isBEWLYPage,
        check_BEWLYPage_compatibility
    };
    const isNewHistoryPage = (url) => {
        return url.includes('://www.bilibili.com/history')
    };
    const getDuration = (str) => {
        if (str === null) {
            return -1
        }
        if (str.includes('已看完') || str === '') {
            return -1
        } else {
            const match = str?.match(/\/(.*)/);
            if (match) {
                return sFormatUtil.timeStringToSeconds(match[1]);
            }
        }
        return -1
    };
    const getVideoDataList$2 = async () => {
        const elList = await elUtil.findElementsUntilFound('.section-cards.grid-mode>div');
        const list = [];
        for (let el of elList) {
            const titleEl = el.querySelector('.bili-video-card__title');
            const title = titleEl.textContent.trim();
            const videoUrl = titleEl.firstElementChild.href||null;
            if (videoUrl?.includes('live.bilibili.com')) {
                continue
            }
            const bv=elUtil.getUrlBV(videoUrl);
            const userEl = el.querySelector('.bili-video-card__author');
            const cardTag = el.querySelector('.bili-cover-card__tag')?.textContent.trim() || null;
            const name = userEl.textContent.trim();
            const userUrl = userEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            let nDuration = -1;
            if (cardTag !== '专栏') {
                nDuration = el.querySelector('.bili-cover-card__stat')?.textContent.trim() || null;
                nDuration = getDuration(nDuration);
            }
            const tempEL = el.querySelector('.bili-video-card__details');
            list.push({
                title,
                videoUrl,
                name,
                userUrl,
                nDuration,
                uid,
                el,
                bv,
                insertionPositionEl: tempEL,
                explicitSubjectEl: tempEL
            });
        }
        return list
    };
    const startShieldingVideoList$1 = async () => {
        const list = await getVideoDataList$2();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            shielding.addBlockButton({data: videoData, maskingFunc: startShieldingVideoList$1}, "gz_shielding_button");
        }
    };
    const intervalExecutionStartShieldingVideo$1 = () => {
        const res = shielding.intervalExecutionStartShieldingVideoInert(startShieldingVideoList$1, '历史记录项');
        return () => {
            return res
        }
    };
    const executionStartShieldingVideo = intervalExecutionStartShieldingVideo$1();
    const getTopFilterLabel = async () => {
        const el = await elUtil.findElementUntilFound('.radio-filter>.radio-filter__item--active');
        return el.textContent?.trim()
    };
    const topFilterInsertListener = () => {
        elUtil.findElementUntilFound('.radio-filter').then((el => {
            el.addEventListener('click', (e) => {
                const target = e.target;
                const label = target.textContent?.trim();
                console.log(`点击了${label}`);
                if (label === '直播') {
                    executionStartShieldingVideo().stop();
                    return
                }
                executionStartShieldingVideo().start();
            });
        }));
    };
    const startRun = () => {
        getTopFilterLabel().then(label => {
            if (label === '直播') {
                return
            }
            executionStartShieldingVideo().start();
        });
        topFilterInsertListener();
    };
    var newHistory = {
        isNewHistoryPage,
        intervalExecutionStartShieldingVideo: intervalExecutionStartShieldingVideo$1,
        startRun
    };
    var css = `.to_hide_xl {
    display: block !important;
}
`;
    const isSearchLivePage = (url = window.location.href) => {
        return url.includes('search.bilibili.com/live')
    };
    const installStyle = () => {
        const styleElement = document.createElement('style');
        styleElement.textContent = css;
        document.head.appendChild(styleElement);
    };
    const getLiveRoomList = async () => {
        const elList = await elUtil.findElements('.live-room-cards>.video-list-item');
        const list = [];
        for (let el of elList) {
            const titleAEl = el.querySelector('.bili-live-card__info--tit>a');
            const titleEl = el.querySelector('.bili-live-card__info--tit>a>span');
            const userEl = el.querySelector('.bili-live-card__info--uname');
            const liveUrl = titleAEl.href;
            const title = titleEl.textContent.trim();
            const userUrl = userEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            const name = userEl.textContent.trim();
            list.push({
                title,
                liveUrl,
                name,
                userUrl,
                uid,
                el,
                explicitSubjectEl: el.querySelector('.bili-live-card__info'),
                insertionPositionEl: userEl
            });
        }
        return list
    };
    const addBlockButton = (data) => {
        shielding.addBlockButton(data, '', ['right']);
    };
    const startShieldingLiveRoomList = async () => {
        const list = await getLiveRoomList();
        for (let liveData of list) {
            if (live_shielding.shieldingLiveRoomDecorated(liveData)) {
                continue
            }
            addBlockButton({data: liveData, maskingFunc: startShieldingLiveRoomList});
        }
    };
    var searchLive = {
        installStyle,
        startShieldingLiveRoomList,
        isSearchLivePage
    };
    const startShieldingHotList = async () => {
        const elList = await elUtil.findElements(".trendings-col>.trending-item",
            {interval: 2000});
        console.log("检查热搜关键词中...");
        const hotSearchKeyArr = ruleKeyListData$1.getHotSearchKeyArr();
        const hotSearchKeyCanonicalArr = ruleKeyListData$1.getHotSearchKeyCanonicalArr();
        for (let el of elList) {
            const label = el.textContent.trim();
            let match = ruleMatchingUtil.fuzzyMatch(hotSearchKeyArr, label);
            if (match) {
                el.remove();
                eventEmitter.send('打印信息', `根据模糊热搜关键词-【${match}】-屏蔽-${label}`);
                continue;
            }
            match = ruleMatchingUtil.regexMatch(hotSearchKeyCanonicalArr, label);
            if (match) {
                eventEmitter.send('打印信息', `根据正则热搜关键词-【${match}】-屏蔽-${label}`);
                el.remove();
            }
        }
    };
    var hotSearch = {
        startShieldingHotList
    };
    const isMessagePage = (url = window.location.href) => {
        return url.includes("message.bilibili.com");
    };
    const modifyTopItemsZIndex = () => {
        elUtil.findElement('#home_nav').then(el => {
            el.style.zIndex = 1000;
            eventEmitter.send('打印信息', '已修改顶部的z-index值为1');
        });
    };
    var messagePage = {
        isMessagePage,
        modifyTopItemsZIndex,
    };
    const isSpacePage = (url = window.location.href) => {
        return url.startsWith('https://space.bilibili.com/')
    };
    const isPersonalHomepage = async () => {
        const keyStr = 'isPersonalHomepage';
        const cache = valueCache.get(keyStr);
        if (cache) {
            return cache
        }
        const {
            state: newState,
            data: newData
        } = await elUtil.findElements('.nav-tab__item .nav-tab__item-text', {timeout: 2500});
        if (newState) {
            const bool = newData.some(el => el.textContent.trim() === '设置');
            valueCache.set('space_version', 'new');
            return valueCache.set(keyStr, bool);
        }
        let {state} = await elUtil.findElement('.n-tab-links>.n-btn.n-setting>.n-text', {timeout: 1500});
        valueCache.set('space_version', 'old');
        return valueCache.set(keyStr, state);
    };
    const getUserInfo = async () => {
        const spaceUserInfo = valueCache.get('space_userInfo');
        if (spaceUserInfo) {
            return spaceUserInfo
        }
        await isPersonalHomepage();
        const nameData = {};
        nameData.uid = elUtil.getUrlUID(window.location.href);
        if (valueCache.get('space_version', 'new') === 'new') {
            nameData.name = await elUtil.findElement('.nickname').then(el => el.textContent.trim());
        } else {
            nameData.name = await elUtil.findElement('#h-name').then(el => el.textContent.trim());
        }
        if (!nameData.name) {
            const title = document.title;
            nameData.name = title.match(/(.+)的个人空间/)[1];
        }
        valueCache.set('space_userInfo', nameData);
        return nameData
    };
    var space = {
        isPersonalHomepage,
        isSpacePage,
        getUserInfo
    };
    const getGateActivatedTab = async () => {
        const el = await elUtil.findElementUntilFound(".ant-radio-group>.ant-radio-button-wrapper-checked .css-1k4kcw8");
        return el?.textContent.trim();
    };
    const check_bilibili_gate_compatibility = async () => {
        const {state} = await elUtil.findElement('.bilibili-gate-root', {interval: 300, timeout: 5000});
        if (state) {
            if (!globalValue.adaptationBAppCommerce) {
                eventEmitter.send('el-alert', "检测到使用bilibili_gate脚本但未开启兼容选项,需要启用相关兼容选项才可正常使用");
            } else {
                eventEmitter.send('el-notify', {
                    title: "tip",
                    message: '启用兼容bilibili-gate脚本',
                    position: 'bottom-right',
                });
            }
            return
        }
        if (globalValue.adaptationBAppCommerce) {
            eventEmitter.send('el-alert', "检测到未使用bilibili_gate脚本却开启了兼容选项,请关闭兼容选项或启用bilibili_gate脚本后再启用相关兼容选项");
        }
    };
    const getGateDataList = async () => {
        const elList = await elUtil.findElementsUntilFound(".bilibili-gate-video-grid>[data-bvid].bili-video-card");
        const list = [];
        for (let el of elList) {
            const tempData = bilibiliHome.getVideoData(el);
            const videoUrl = el.querySelector("a.css-feo88y")?.href;
            const bv = elUtil.getUrlBV(videoUrl);
            const insertionPositionEl = el.querySelector(".bili-video-card__info--owner");
            list.push({
                ...tempData, ...{
                    videoUrl,
                    el,
                    bv,
                    insertionPositionEl,
                    explicitSubjectEl: el
                }
            });
        }
        return list;
    };
    const startShieldingGateVideoList = async () => {
        const list = await getGateDataList();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData, "hide")) {
                continue;
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingGateVideoList});
        }
    };
    const startIntervalShieldingGateVideoList = () => {
        const throttle = defUtil.throttle(startShieldingGateVideoList, 2000);
        setInterval(async () => {
            await getGateActivatedTab();
            throttle();
        }, 1500);
    };
    var BLBLGate = {
        check_bilibili_gate_compatibility,
        startIntervalShieldingGateVideoList
    };
    const homeStaticRoute = (title, url) => {
        if (compatibleBewlyBewly.isBEWLYPage(url) && globalValue.compatibleBEWLYBEWLY) {
            compatibleBewlyBewly.startRun(url);
        }
        if (bilibiliHome.isHome(url, title)) {
            BLBLGate.check_bilibili_gate_compatibility();
            compatibleBewlyBewly.check_BEWLYPage_compatibility();
            eventEmitter.send('通知屏蔽');
            if (globalValue.compatibleBEWLYBEWLY) return;
            bilibiliHome.scrollMouseUpAndDown().then(() => bilibiliHome.startDebounceShieldingChangeVideoList());
            bilibiliHome.startClearExcessContentList();
            bilibiliHome.deDesktopDownloadTipEl();
        }
    };
    const staticRoute = (title, url) => {
        console.log("静态路由", title, url);
        homeStaticRoute(title, url);
        if (globalValue.bOnlyTheHomepageIsBlocked) return;
        topInput.processTopInputContent();
        hotSearch.startShieldingHotList();
        eventEmitter.send('通知屏蔽');
        if (searchModel.isSearch(url)) {
            searchLive.installStyle();
            searchModel.delFooterContent();
        }
        if (videoPlayModel.isVideoPlayPage(url)) {
            elUtil.updateCssVModal();
            videoPlayModel.findTheExpandButtonForTheListOnTheRightAndBindTheEvent();
            videoPlayModel.setVideoPlayerEnded();
            videoPlayModel.delElManagement();
        }
        if (collectionVideoPlayPageModel.iscCollectionVideoPlayPage(url)) {
            collectionVideoPlayPageModel.findTheExpandButtonForTheListOnTheRightAndBindTheEvent();
        }
        if (liveRoomModel.isLiveRoom(url)) {
            liveRoomModel.addWatchLiveRoomChatItemsListener();
        }
        if (videoPlayWatchLater.isVideoPlayWatchLaterPage(url)) {
            elUtil.updateCssVModal();
            videoPlayWatchLater.findTheExpandButtonForTheListOnTheRightAndBindTheEvent();
        }
        if (newHistory.isNewHistoryPage(url)) {
            newHistory.startRun();
        }
        if (messagePage.isMessagePage(url)) {
            messagePage.modifyTopItemsZIndex();
        }
        if (space.isSpacePage()) {
            space.getUserInfo().then(userInfo => {
                console.info('userInfo', userInfo);
            });
        }
    };
    const dynamicRouting = (title, url) => {
        console.log("动态路由", title, url);
        if (globalValue.bOnlyTheHomepageIsBlocked) return;
        eventEmitter.send('通知屏蔽');
    };
    var router = {
        staticRoute,
        dynamicRouting
    };
    const isTopicDetailPage = (url) => {
        return url.includes("//www.bilibili.com/v/topic/detail/")
    };
    const getDataList$1 = async () => {
        const elList = await elUtil.findElementsUntilFound(".list__topic-card");
        const list = [];
        for (let el of elList) {
            const name = el.querySelector(".bili-dyn-title").textContent.trim();
            const uidEl = el.querySelector(".bili-dyn-item__following");
            const uid = parseInt(uidEl.getAttribute("data-mid"));
            const judgmentEl = el.querySelector(".bili-dyn-card-video__title");
            const data = {name, uid, el, judgmentVideo: judgmentEl !== null};
            if (judgmentEl !== null) {
                data.title = judgmentEl.textContent.trim();
                const videoUrl = el.querySelector(".bili-dyn-card-video").href;
                data.videoUrl = videoUrl;
                data.bv = elUtil.getUrlBV(videoUrl);
                data.insertionPositionEl = el.querySelector(".bili-dyn-content__orig");
                data.explicitSubjectEl = data.insertionPositionEl;
            } else {
                const dynTitle = el.querySelector(".dyn-card-opus__title");
                const contentTitle = dynTitle === null ? "" : dynTitle.textContent.trim();
                const contentBody = el.querySelector(".bili-rich-text>div").textContent.trim();
                data.insertionPositionEl = el.querySelector(".dyn-card-opus");
                data.explicitSubjectEl = data.insertionPositionEl;
                data.content = contentTitle + contentBody;
            }
            list.push(data);
        }
        return list;
    };
    const __shieldingVideo = (videoData) => {
        if (video_shielding.shieldingVideoDecorated(videoData)) {
            return;
        }
        shielding.addTopicDetailVideoBlockButton({data: videoData, maskingFunc: startShielding});
    };
    const __shieldingDynamic = (dynamicData) => {
        if (comments_shielding.shieldingCommentDecorated(dynamicData)) {
            return;
        }
        shielding.addTopicDetailContentsBlockButton({data: dynamicData, maskingFunc: startShielding});
    };
    const startShielding = async () => {
        const list = await getDataList$1();
        const css = {width: "100%"};
        for (let data of list) {
            data.css = css;
            if (data.judgmentVideo) {
                __shieldingVideo(data);
            } else {
                __shieldingDynamic(data);
            }
        }
    };
    var topicDetail = {
        isTopicDetailPage,
        startShielding
    };
    eventEmitter.on('评论添加屏蔽按钮', (commentsData) => {
        shielding.addBlockButton({
            data: commentsData,
            maskingFunc: startShieldingComments
        }, "gz_shielding_comment_button");
    });
    const getUrlUserLevel = (src) => {
        const levelMath = src?.match(/level_(.+)\.svg/) || null;
        let level = -1;
        if (levelMath !== null) {
            const levelRow = levelMath[1];
            if (levelRow === 'h') {
                level = 7;
            } else {
                level = parseInt(levelRow);
            }
        }
        return level;
    };
    const getOldUserLevel = (iEl) => {
        let level;
        const levelCLassName = iEl.classList[1];
        if (levelCLassName === 'level-hardcore') {
            level = 7;
        } else {
            const levelMatch = levelCLassName.match(/level-(.+)/)?.[1] || '';
            level = parseInt(levelMatch);
        }
        return level
    };
    const getCommentSectionList = async () => {
        const commentApp = await elUtil.findElementUntilFound("bili-comments",
            {interval: 500});
        const comments = await elUtil.findElementsUntilFound("#feed>bili-comment-thread-renderer",
            {doc: commentApp.shadowRoot, interval: 500});
        const commentsData = [];
        let isLoaded = false;
        for (let el of comments) {
            const theOPEl = el.shadowRoot.getElementById("comment").shadowRoot;
            const theOPUserInfo = theOPEl.querySelector("bili-comment-user-info")
                .shadowRoot.getElementById("info");
            const userNameEl = theOPUserInfo.querySelector("#user-name>a");
            const userLevelSrc = theOPUserInfo.querySelector('#user-level>img')?.src || null;
            const level = getUrlUserLevel(userLevelSrc);
            isLoaded = theOPEl.querySelector("#content>bili-rich-text")
                .shadowRoot.querySelector("#contents>*") !== null;
            if (!isLoaded) {
                break;
            }
            const theOPContentEl = theOPEl.querySelector("#content>bili-rich-text")
                .shadowRoot.querySelector("#contents");
            const theOPContent = theOPContentEl.textContent.trim();
            const userName = userNameEl.textContent.trim();
            const userUrl = userNameEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            const replies = [];
            commentsData.push({
                name: userName,
                userUrl,
                uid,
                level,
                content: theOPContent,
                replies,
                el,
                insertionPositionEl: theOPUserInfo,
                explicitSubjectEl: theOPEl.querySelector("#body"),
                contentsEl: theOPContentEl
            });
            const inTheBuildingEls = el.shadowRoot.querySelector("bili-comment-replies-renderer")
                .shadowRoot.querySelectorAll("bili-comment-reply-renderer");
            for (let inTheBuildingEl of inTheBuildingEls) {
                const inTheContentEl = inTheBuildingEl.shadowRoot;
                const biliCommentUserInfo = inTheContentEl.querySelector("bili-comment-user-info");
                biliCommentUserInfo.style.display = 'block';
                const inTheBuildingUserInfo = biliCommentUserInfo.shadowRoot.getElementById("info");
                const inTheBuildingUserNameEl = inTheBuildingUserInfo.querySelector("#user-name>a");
                const inTheBuildingUserName = inTheBuildingUserNameEl.textContent.trim();
                const inTheBuildingUserUrl = inTheBuildingUserNameEl.href;
                const inTheBuildingUid = elUtil.getUrlUID(inTheBuildingUserUrl);
                const biliRichTextEL = inTheContentEl.querySelector("bili-rich-text");
                const contentsEl = biliRichTextEL.shadowRoot.querySelector("#contents");
                const inTheBuildingContent = contentsEl.textContent.trim();
                const userLevelSrc = inTheBuildingUserInfo.querySelector('#user-level>img')?.src || null;
                const level = getUrlUserLevel(userLevelSrc);
                replies.push({
                    name: inTheBuildingUserName,
                    userUrl: inTheBuildingUserUrl,
                    uid: inTheBuildingUid,
                    level,
                    content: inTheBuildingContent,
                    el: inTheBuildingEl,
                    insertionPositionEl: inTheBuildingUserInfo,
                    explicitSubjectEl: inTheBuildingEl,
                    contentsEl
                });
            }
        }
        if (!isLoaded) {
            await defUtil.wait(500);
            return getCommentSectionList()
        }
        return commentsData;
    };
    const getOldCommentSectionList = async () => {
        let results;
        try {
            results = await elUtil.findElementsUntilFound(".reply-list>.reply-item", {timeout: 5000});
        } catch (e) {
            return []
        }
        const commentsData = [];
        for (let el of results) {
            const theOPEl = el.querySelector(".root-reply-container");
            const theOPUserInfoEl = theOPEl.querySelector(".user-name");
            const userName = theOPUserInfoEl.textContent.trim();
            const uid = parseInt(theOPUserInfoEl.getAttribute("data-user-id"));
            const userUrl = `https://space.bilibili.com/${uid}`;
            const theOPContent = theOPEl.querySelector(".reply-content").textContent.trim();
            const userInfoEl = el.querySelector(".user-info");
            const iEl = userInfoEl.querySelector('i');
            const level = getOldUserLevel(iEl);
            const replies = [];
            commentsData.push({
                name: userName,
                userUrl,
                uid,
                content: theOPContent,
                level,
                replies,
                el,
                insertionPositionEl: userInfoEl,
                explicitSubjectEl: el.querySelector(".content-warp")
            });
            const inTheBuildingEls = el.querySelectorAll(".sub-reply-container>.sub-reply-list>.sub-reply-item");
            for (let inTheBuildingEl of inTheBuildingEls) {
                const subUserNameEl = inTheBuildingEl.querySelector(".sub-user-name");
                const uid = parseInt(subUserNameEl.getAttribute("data-user-id"));
                const userName = subUserNameEl.textContent.trim();
                const userUrl = `https://space.bilibili.com/${uid}`;
                const subContent = inTheBuildingEl.querySelector(".reply-content").textContent.trim();
                const subUserInfoEl = inTheBuildingEl.querySelector(".sub-user-info");
                const iEl = subUserInfoEl.querySelector('i');
                const level = getOldUserLevel(iEl);
                const replyContentContainerEl = inTheBuildingEl.querySelector('span.reply-content-container');
                replyContentContainerEl.style.display = 'block';
                replies.push({
                    name: userName,
                    userUrl,
                    uid,
                    level,
                    content: subContent,
                    el: inTheBuildingEl,
                    insertionPositionEl: subUserInfoEl,
                    explicitSubjectEl: inTheBuildingEl
                });
            }
        }
        return commentsData;
    };
    const startShieldingComments = async () => {
        if (videoPlayModel.isVideoPlayPage() && localMKData.isDelBottomComment()) {
            return
        }
        let list;
        const href = window.location.href;
        if (localMKData.isDiscardOldCommentAreas()) {
            list = await getCommentSectionList();
        } else if (href.includes("https://space.bilibili.com/") || topicDetail.isTopicDetailPage(href)) {
            list = await getOldCommentSectionList();
        } else {
            list = await getCommentSectionList();
        }
        comments_shielding.shieldingComments(list);
    };
    var commentSectionModel = {
        startShieldingComments
    };
    const getVideDataList = async (isWeekly = false) => {
        const css = isWeekly ? ".video-list>.video-card" : ".card-list>.video-card";
        const elList = await elUtil.findElementsUntilFound(css);
        const list = [];
        for (let el of elList) {
            const videoCardInfoEl = el.querySelector(".video-card__info");
            const title = videoCardInfoEl.querySelector(".video-name").title.trim();
            const name = videoCardInfoEl.querySelector(".up-name__text").title;
            const videoUrl = el.querySelector('.video-card__content>a')?.href || null;
            const bv = elUtil.getUrlBV(videoUrl);
            let nPlayCount = el.querySelector('.play-text').textContent.trim();
            nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
            let nBulletChat = el.querySelector('.like-text').textContent.trim();
            nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
            list.push({
                el,
                title,
                name,
                videoUrl,
                bv,
                nPlayCount,
                nBulletChat,
                insertionPositionEl: videoCardInfoEl.querySelector("div"),
                explicitSubjectEl: videoCardInfoEl
            });
        }
        return list;
    };
    const startShieldingVideoList = async (isWeekly = false) => {
        const list = await getVideDataList(isWeekly);
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            eventEmitter.send('添加热门视频屏蔽按钮', {data: videoData, maskingFunc: startShieldingVideoList});
        }
    };
    var popularAll = {
        startShieldingVideoList
    };
    const isDynamicPage = (url) => {
        return url.search("space.bilibili.com/\\d+/dynamic") !== -1;
    };
    const getDataList = async () => {
        const elList = await elUtil.findElementsUntilFound(".bili-dyn-list__items>.bili-dyn-list__item");
        const list = [];
        for (let el of elList) {
            const videoCardEl = el.querySelector(".bili-dyn-card-video__title");
            const name = el.querySelector(".bili-dyn-title").textContent.trim();
            const tagEl = el.querySelector(".bili-dyn-topic__text");
            const data = {el, name};
            if (tagEl !== null) {
                data.tag = tagEl.textContent.trim();
            }
            data.judgmentVideo = videoCardEl !== null;
            if (data.judgmentVideo) {
                data.title = videoCardEl.textContent.trim();
            } else {
                const contentTitleEL = el.querySelector(".dyn-card-opus>.dyn-card-opus__title");
                const contentTitle = contentTitleEL === null ? "" : contentTitleEL.textContent.trim();
                const contentElBody = el.querySelector(".bili-rich-text").textContent.trim();
                data.content = contentTitle + contentElBody;
            }
            list.push(data);
        }
        return list;
    };
    const startShieldingDynamicContent = async () => {
        const personalHomepage = await space.isPersonalHomepage();
        if (personalHomepage) return;
        const list = await getDataList();
        for (let dynamicContent of list) {
            shielding.shieldingDynamicDecorated(dynamicContent);
        }
    };
    const startThrottleShieldingDynamicContent = defUtil.throttle(startShieldingDynamicContent, 2000);
    var dynamic = {
        isDynamicPage,
        startThrottleShieldingDynamicContent
    };
    const isLiveSection = (url) => {
        return url.includes("live.bilibili.com/p/eden/area-tags")
    };
    const getRoomCardDataList = async () => {
        const elList = await elUtil.findElementsUntilFound("#room-card-list>div");
        const list = [];
        for (let el of elList) {
            const liveUrl = el.querySelector("#card").href;
            const name = el.querySelector(".Item_nickName_KO2QE").textContent.trim();
            const title = el.querySelector(".Item_roomTitle_ax3eD").textContent.trim();
            const partition = el.querySelector(".Item_area-name_PXDG4")?.textContent.trim() || null;
            const popularity = el.querySelector(".Item_onlineCount_FmOW6").textContent.trim();
            list.push({liveUrl, name, title, partition, popularity, el});
        }
        return list;
    };
    const startShieldingLiveRoom$1 = async () => {
        const liveList = await getRoomCardDataList();
        for (let liveData of liveList) {
            live_shielding.shieldingLiveRoomDecorated(liveData);
        }
    };
    var liveSectionModel = {
        isLiveSection,
        startShieldingLiveRoom: startShieldingLiveRoom$1
    };
    const isLiveHomePage = (url) => {
        return url.includes("https://live.bilibili.com/?spm_id_from=333.1007.0.0") ||
            url === "https://live.bilibili.com/"
    };
    const getTopLiveRoomDataList = async () => {
        const verification = await elUtil.findElementUntilFound(".v-top>.aside-item .t-left.aside-item-tips.p-absolute.w-100.border-box");
        if (verification.textContent.trim() === "--") {
            return await getTopLiveRoomDataList();
        }
        const elList = await elUtil.findElementsUntilFound(".v-top>.aside-item", {interval: 2000});
        const list = [];
        for (let el of elList) {
            const classList = el.classList;
            const active = classList.contains("active");
            const title = el.getAttribute("title");
            const {up_id: uid, room_id} = JSON.parse(el.getAttribute("data-report"));
            const liveUrl = `https://live.bilibili.com/${room_id}`;
            list.push({title, uid, active, liveUrl, el});
        }
        return list;
    };
    const getLiveRoomDataList = async () => {
        const elList = await elUtil.findElementsUntilFound(".room-card-wrapper.p-relative.dp-i-block");
        const list = [];
        for (let el of elList) {
            const cardEl = el.querySelector(".room-card-ctnr.p-relative.w-100");
            const cardData = JSON.parse(cardEl.getAttribute("data-bl-report-click") || "");
            const {up_id: uid, room_id} = cardData.msg;
            const liveUrl = `https://live.bilibili.com/${room_id}`;
            const name = el.querySelector(".room-anchor>span").textContent.trim();
            const title = el.querySelector(".room-title.card-text").textContent.trim();
            const partition = el.querySelector(".area-name").textContent.trim();
            const popularity = el.querySelector(".room-anchor .v-middle").textContent.trim();
            list.push({name, title, partition, popularity, liveUrl, uid, el});
        }
        return list;
    };
    const startShieldingLiveRoom = async () => {
        const list = await getLiveRoomDataList();
        for (let liveData of list) {
            live_shielding.shieldingLiveRoomDecorated(liveData);
        }
    };
    const startShieldingTopLiveRoom = async () => {
        const list = await getTopLiveRoomDataList();
        for (let liveData of list) {
            live_shielding.shieldingLiveRoomDecorated(liveData);
        }
    };
    var liveHome = {
        isLiveHomePage,
        startShieldingLiveRoom,
        startShieldingTopLiveRoom
    };
    const isPartition = (url = window.location.href) => {
        return url.includes('www.bilibili.com/v/');
    };
    const isNewPartition = (url = window.location.href) => {
        return url.includes('www.bilibili.com/c/')
    };
    const getHotVideoDayList = async () => {
        const elList = await elUtil.findElementsUntilFound('.bili-rank-list-video__item');
        const list = [];
        for (let el of elList) {
            let videoUrlEl = el.querySelector('a.rank-video-card');
            const titleEl = el.querySelector('.rank-video-card__info--tit');
            const videoUrl = videoUrlEl.href;
            const title = titleEl.textContent.trim();
            const bv = elUtil.getUrlBV(videoUrl);
            list.push({
                title, videoUrl, bv, el
            });
        }
        return list
    };
    const getVVideoDataList = async () => {
        const elList = await elUtil.findElementsUntilFound('.bili-video-card');
        const list = [];
        const oneTitleEl = elList[0].querySelector('.bili-video-card__info--tit>a');
        if (oneTitleEl === null) {
            await defUtil.wait();
            return await getVVideoDataList()
        }
        for (let el of elList) {
            const titleEl = el.querySelector('.bili-video-card__info--tit>a');
            if (titleEl === null) {
                continue
            }
            const userEl = el.querySelector('a.bili-video-card__info--owner');
            const playAndDmu = el.querySelectorAll('.bili-video-card__stats--item>span');
            let nDuration = el.querySelector('.bili-video-card__stats__duration')?.textContent.trim();
            let nPlayCount = playAndDmu[0]?.textContent.trim();
            nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
            let nBulletChat = playAndDmu[1]?.textContent.trim();
            nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
            nDuration = sFormatUtil.toPlayCountOrBulletChat(nDuration);
            const title = titleEl.textContent.trim();
            const videoUrl = titleEl.href;
            const userUrl = userEl.href;
            const name = userEl
                .querySelector('.bili-video-card__info--author')
                ?.textContent.trim() || null;
            const uid = elUtil.getUrlUID(userUrl);
            const bv = elUtil.getUrlBV(videoUrl);
            list.push({
                name, title, uid, bv, userUrl, videoUrl, el,
                nPlayCount, nBulletChat, nDuration,
                explicitSubjectEl: el.querySelector('.bili-video-card__info'),
                insertionPositionEl: el.querySelector('.bili-video-card__info--bottom')
            });
        }
        return list
    };
    const getCVideoDataList = async () => {
        const elList = await elUtil.findElementsUntilFound('.bili-video-card');
        const list = [];
        for (let el of elList) {
            const titleEl = el.querySelector('.bili-video-card__title');
            const title = titleEl.textContent.trim();
            const videoUrl = titleEl.querySelector('a').href;
            const bv = elUtil.getUrlBV(videoUrl);
            const userEl = el.querySelector('.bili-video-card__author');
            const userUrl = userEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            const name = userEl.querySelector('[title]').textContent.trim().split('·')[0].trim();
            const statEls = el.querySelectorAll('.bili-cover-card__stats span');
            const nPlayCount = sFormatUtil.toPlayCountOrBulletChat(statEls[0].textContent.trim());
            const nBulletChat = sFormatUtil.toPlayCountOrBulletChat(statEls[1].textContent.trim());
            const nDuration = sFormatUtil.timeStringToSeconds(statEls[2].textContent.trim());
            const insertionPositionEl = el.querySelector('.bili-video-card__subtitle');
            const explicitSubjectEl = el.querySelector('.bili-video-card__details');
            list.push({
                title,
                userUrl,
                uid,
                name,
                videoUrl,
                bv,
                nPlayCount,
                nBulletChat,
                nDuration,
                el,
                insertionPositionEl,
                explicitSubjectEl
            });
        }
        return list
    };
    const shieldingVideoList = async () => {
        let list;
        if (isPartition()) {
            list = await getVVideoDataList();
        } else {
            list = await getCVideoDataList();
        }
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue
            }
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: shieldingVideoList});
        }
    };
    const startShieldingHotVideoDayList = async () => {
        let list = await getHotVideoDayList();
        for (let videoData of list) {
            video_shielding.shieldingVideoDecorated(videoData);
        }
    };
    const startIntervalShieldingVideoList = () => {
        setInterval(async () => {
            await shieldingVideoList();
            for (let el of document.querySelectorAll('.feed-card:empty')) {
                el?.remove();
                console.log('已移除页面空白视频选项元素');
            }
        }, 1500);
    };
    var partition = {
        isPartition,
        isNewPartition,
        startIntervalShieldingVideoList,
        startShieldingHotVideoDayList
    };
    const observeNetwork = (url, windowUrl, winTitle, initiatorType) => {
        if (!url.includes('api')) return;
        if (globalValue.bOnlyTheHomepageIsBlocked) {
            if (!bilibiliHome.isHome(windowUrl, winTitle)) return;
        }
        if (url.startsWith("https://api.bilibili.com/x/web-interface/wbi/index/top/feed/rcmd?web_location=")) {
            if (globalValue.compatibleBEWLYBEWLY) return;
            bilibiliHome.startDebounceShieldingChangeVideoList();
            bilibiliHome.startDebounceShieldingHomeVideoList();
            console.log("检测到首页加载了换一换视频列表和其下面的视频列表");
            return;
        }
        if (url.startsWith("https://api.bilibili.com/x/v2/reply/wbi/main?oid=")) {
            console.log("检测到评论区楼主评论加载了");
            commentSectionModel.startShieldingComments();
            return;
        }
        if (url.startsWith("https://api.bilibili.com/x/v2/reply/reply?oid=")) {
            console.log("检测到评论区楼主层中的子层评论列表加载了");
            commentSectionModel.startShieldingComments();
        }
        if (url.startsWith("https://api.bilibili.com/x/web-interface/popular?ps=")) {
            popularAll.startShieldingVideoList();
        }
        if (url.startsWith("https://api.bilibili.com/x/web-interface/popular/series/one?number=")) {
            popularAll.startShieldingVideoList(true);
        }
        if (url.startsWith("https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?offset=")) {
            console.log("检测到用户动态加载了");
            dynamic.startThrottleShieldingDynamicContent();
        }
        if (url.startsWith("https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=")) {
            console.log("检测到直播间加载了分区下的房间列表");
            liveSectionModel.startShieldingLiveRoom();
        }
        if (url.startsWith("https://api.live.bilibili.com/xlive/web-interface/v1/index/getList?platform=web")) {
            console.log("检测到直播间加载了推荐房间列表");
            liveHome.startShieldingLiveRoom();
        }
        if (url.startsWith('https://api.bilibili.com/x/web-interface/ranking/region?day=')) {
            console.log("检测到专区热门排行榜加载了");
            partition.startShieldingHotVideoDayList();
        }
        if (searchModel.isSearchVideoNetWorkUrl(url) || searchModel.isSearchLiveRoomNetWorkUrl(url)) {
            eventEmitter.send('通知屏蔽');
        }
    };
    var observeNetwork$1 = {
        observeNetwork
    };
    const shielding_user_vue = {
        template: `
      <div>
      <el-dropdown v-if="shieldingModelShow"
                   @command="dropdownEvent">
        <el-button round>
          屏蔽操作<i class="el-icon-arrow-down el-icon--right"></i>
        </el-button>
        <el-dropdown-menu v-slot="dropdown">
          <el-dropdown-item command="屏蔽uid"
                            v-if="shieldingUseUIDrButShow">屏蔽(uid)
          </el-dropdown-item>
          <el-dropdown-item command="移除屏蔽uid"
                            v-if="removedShieldingUIDrButShow">移除屏蔽(uid)
          </el-dropdown-item>
          <el-dropdown-item command="选择用户屏蔽" v-if="selectUserBlockingButShow">选择用户屏蔽</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      </div>`,
        data() {
            return {
                shieldingModelShow: true,
                shieldingUseUIDrButShow: false,
                removedShieldingUIDrButShow: false,
                selectUserBlockingButShow: false,
                uid: -1
            }
        },
        methods: {
            async dropdownEvent(item) {
                if (item === '屏蔽uid') {
                    const {name, uid} = await space.getUserInfo();
                    this.$confirm(`是否屏蔽当前用户【${name}】uid=【${uid}】`, '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        const {status, res} = ruleUtil.addRulePreciseUid(uid);
                        this.$alert(res);
                        if (status) {
                            this.shieldingUseUIDrButShow = false;
                            this.removedShieldingUIDrButShow = true;
                        }
                    });
                    return
                }
                if (item === '移除屏蔽uid') {
                    const {uid} = await space.getUserInfo();
                    ruleUtil.delRUlePreciseUid(uid);
                    return
                }
                if (item === '选择用户屏蔽') {
                    await videoPlayModel.selectUserBlocking();
                    return
                }
                this.$message('未知选项');
            }
        },
        async created() {
            if (videoPlayModel.isVideoPlayPage()) {
                this.selectUserBlockingButShow = true;
            }
            if (space.isSpacePage()) {
                this.urlUID = elUtil.getUrlUID(window.location.href);
                if (ruleKeyListData$1.getPreciseUidArr().includes(this.urlUID)) {
                    this.shieldingModelShow = true;
                    this.removedShieldingUIDrButShow = true;
                    await this.$alert('当前用户为已标记uid黑名单', '提示');
                    return;
                }
                if (await space.isPersonalHomepage()) {
                    this.shieldingModelShow = false;
                    return;
                }
                this.shieldingModelShow = true;
                this.shieldingUseUIDrButShow = true;
            }
        }
    };
    const addLayout = () => {
        const div = document.createElement('div');
        const divStyle = div.style;
        divStyle.position = 'fixed';
        divStyle.zIndex = '9000';
        divStyle.right = "0";
        divStyle.top = '13%';
        divStyle.transition = 'transform 0.5s';
        if (!localMKData.isFirstFullDisplay()) {
            divStyle.transform = 'translateX(80%)';
        } else {
            if (localMKData.isHalfHiddenIntervalAfterInitialDisplay()) {
                setTimeout(() => {
                    divStyle.transform = 'translateX(80%)';
                    eventEmitter.send('el-msg', '自动隐藏外部主面板显隐按钮');
                }, 8000);
            }
        }
        const vueDiv = document.createElement('div');
        div.appendChild(vueDiv);
        document.body.appendChild(div);
        const config = {
            components: {
                shielding_user_vue,
            },
            el: vueDiv,
            template: `
          <div v-show="panelShow" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
          <div>
            <el-button round @click="showBut">主面板</el-button>
          </div>
          <shielding_user_vue/>
          </div>`,
            data() {
                return {
                    panelShow: localMKData.isShowRightTopMainButSwitch(),
                }
            },
            methods: {
                showBut() {
                    eventEmitter.send('主面板开关');
                },
                handleMouseEnter() {
                    divStyle.transform = "translateX(0)";
                },
                handleMouseLeave() {
                    divStyle.transform = 'translateX(80%)';
                }
            },
            created() {
                eventEmitter.on('显隐主面板开关', (bool) => {
                    this.panelShow = bool;
                });
            }
        };
        new Vue(config);
    };
    var rightFloatingLayoutVue = {
        addLayout
    };
    const generalUrl=[
        "popular/rank/all",
        "popular/rank/douga",
        "popular/rank/music",
        "popular/rank/dance",
        "popular/rank/game",
        "popular/rank/knowledge",
        "popular/rank/tech",
        "popular/rank/sports",
        "popular/rank/car",
        "popular/rank/life",
        "popular/rank/food",
        "popular/rank/animal",
        "popular/rank/kichiku",
        "popular/rank/fashion",
        "popular/rank/ent",
        "popular/rank/cinephile",
        "popular/rank/origin",
        "popular/rank/rookie"
    ];
    const isPopularHistory = (url) => {
        return url.includes("popular/history")
    };
    const isPopularAllPage = (url) => {
        return url.includes("www.bilibili.com/v/popular/all");
    };
    const isPopularWeeklyPage = (url) => {
        return url.includes("www.bilibili.com/v/popular/weekly");
    };
    const isGeneralPopularRank=(url)=>{
        return generalUrl.some(itemUrl => url.includes(itemUrl));
    };
    const getVideoDataList$1 = async () => {
        const elList = await elUtil.findElementsUntilFound(".rank-list>li");
        const list = [];
        for (let el of elList) {
            const title = el.querySelector(".title").textContent.trim();
            const userUrl = el.querySelector(".detail>a").href;
            const uid = elUtil.getUrlUID(userUrl);
            const name = el.querySelector(".up-name").textContent.trim();
            const detailStateEls = el.querySelectorAll('.detail-state>.data-box');
            let nPlayCount = detailStateEls[0].textContent.trim();
            nPlayCount = sFormatUtil.toPlayCountOrBulletChat(nPlayCount);
            let nBulletChat = detailStateEls[1].textContent.trim();
            nBulletChat = sFormatUtil.toPlayCountOrBulletChat(nBulletChat);
            const videoUrl = el.querySelector('.img>a')?.href || null;
            const bv = elUtil.getUrlBV(videoUrl);
            list.push({
                title,
                userUrl,
                uid,
                name,
                videoUrl,
                bv,
                nPlayCount,
                nBulletChat,
                nDuration: -1,
                el,
                insertionPositionEl: el.querySelector(".detail-state"),
                explicitSubjectEl: el.querySelector(".info")
            });
        }
        return list;
    };
    const startShieldingRankVideoList = async () => {
        const list = await getVideoDataList$1();
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            eventEmitter.send('添加热门视频屏蔽按钮', {data: videoData, maskingFunc: startShieldingRankVideoList});
        }
    };
    var popular = {
        isPopularHistory,
        isPopularAllPage,
        isGeneralPopularRank,
        isPopularWeeklyPage,
        startShieldingRankVideoList,
    };
    const isOldHistory = (url) => {
        return url.includes('https://www.bilibili.com/account/history')
    };
    const getVideoDataList = async () => {
        const elList = await elUtil.findElementsUntilFound('#history_list>.history-record');
        const list = [];
        for (let el of elList) {
            const labelEL = el.querySelector('.cover-contain>.label');
            if (labelEL !== null) {
                const label = labelEL.textContent.trim();
                console.log(`排除${label}`);
                continue
            }
            const titleEl = el.querySelector('.title');
            const userEl = el.querySelector('.w-info>span>a');
            const title = titleEl.textContent.trim();
            const videoUrl = titleEl.href;
            const bv = elUtil.getUrlBV(videoUrl);
            const name = userEl.textContent.trim();
            const userUrl = userEl.href;
            const uid = elUtil.getUrlUID(userUrl);
            list.push({
                title,
                videoUrl,
                name,
                userUrl,
                uid,
                el,
                bv,
                explicitSubjectEl: el.querySelector('.r-txt'),
                insertionPositionEl: el.querySelector('.subtitle')
            });
        }
        return list
    };
    const startShieldingVideo = async () => {
        console.log('开始屏蔽旧版历史记录视频列表');
        const list = await getVideoDataList();
        const css = {right: "45px"};
        for (let videoData of list) {
            if (video_shielding.shieldingVideoDecorated(videoData)) {
                continue;
            }
            videoData.css = css;
            eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingVideo});
        }
        console.log('屏蔽旧版历史记录视频列表完成');
    };
    const intervalExecutionStartShieldingVideo = () => {
        setInterval(startShieldingVideo, 2000);
    };
    var oldHistory = {
        isOldHistory,
        intervalExecutionStartShieldingVideo
    };
    eventEmitter.on('通知屏蔽', () => {
        const url = window.location.href;
        const title = document.title;
        if (globalValue.bOnlyTheHomepageIsBlocked) return;
        if (searchLive.isSearchLivePage(url)) {
            searchLive.startShieldingLiveRoomList();
        }
        if (searchModel.isSearch(url)) {
            searchModel.startShieldingVideoList();
        }
        if (bilibiliHome.isHome(url, title)) {
            if (globalValue.compatibleBEWLYBEWLY) return;
            if (globalValue.adaptationBAppCommerce) {
                BLBLGate.startIntervalShieldingGateVideoList();
            }
            bilibiliHome.startDebounceShieldingHomeVideoList();
        }
        if (videoPlayModel.isVideoPlayPage(url)) {
            videoPlayModel.startShieldingVideoList();
        }
        if (collectionVideoPlayPageModel.iscCollectionVideoPlayPage(url)) {
            collectionVideoPlayPageModel.startShieldingVideoList();
        }
        if (popular.isPopularAllPage(url) || popular.isPopularHistory(url)) {
            popularAll.startShieldingVideoList();
        }
        if (popular.isPopularWeeklyPage(url)) {
            popularAll.startShieldingVideoList(true);
        }
        if (popular.isGeneralPopularRank(url)) {
            popular.startShieldingRankVideoList();
        }
        if (topicDetail.isTopicDetailPage(url)) {
            topicDetail.startShielding();
        }
        if (dynamic.isDynamicPage(url)) {
            dynamic.startThrottleShieldingDynamicContent();
        }
        if (videoPlayWatchLater.isVideoPlayWatchLaterPage(url)) {
            videoPlayWatchLater.startDebounceShieldingVideoList();
        }
        if (liveSectionModel.isLiveSection(url)) {
            liveSectionModel.startShieldingLiveRoom();
        }
        if (liveHome.isLiveHomePage(url)) {
            liveHome.startShieldingLiveRoom();
            liveHome.startShieldingTopLiveRoom();
        }
        if (oldHistory.isOldHistory(url)) {
            oldHistory.intervalExecutionStartShieldingVideo();
        }
        if (partition.isPartition(url) || partition.isNewPartition(url)) {
            partition.startIntervalShieldingVideoList();
        }
    });
    const replaceKeywords = (arr, actionScope, content) => {
        if (arr.length === 0 || !enableReplacementProcessing()) return returnTempVal;
        for (const v of arr) {
            if (!content.includes(v.findVal)) continue;
            if (!v.actionScopes.some(aItem => aItem === actionScope)) continue;
            return {
                state: true,
                content: content.replaceAll(v.findVal, v.replaceVal)
            }
        }
        return returnTempVal
    };
    const replaceEmoticons = (arr, el, alt) => {
        if (arr.length === 0 || !enableReplacementProcessing()) return returnTempVal;
        for (const v of arr) {
            if (!v.actionScopes.some(aItem => aItem === '评论表情')) continue;
            if (v.findVal !== alt) continue;
            if (v.replaceVal === '') {
                el?.remove();
                return {state: true, model: 'del', content: alt};
            }
            return {
                state: true,
                model: 'subStr',
                content: v.replaceVal
            }
        }
        return returnTempVal
    };
    eventEmitter.on('event-评论通知替换关键词', (commentsData) => {
        const {contentsEl, name, uid} = commentsData;
        if (!contentsEl) return;
        const spanEls = contentsEl.querySelectorAll('span');
        const imgEls = contentsEl.querySelectorAll('img');
        const aEls = contentsEl.querySelectorAll('a');
        const substituteWordsArr = getSubstituteWordsArr();
        if (isClearCommentEmoticons()) {
            for (let imgEl of imgEls) {
                imgEl?.remove();
                eventEmitter.send('打印信息', `已清除${name}的评论中的表情`);
            }
        } else {
            for (let imgEl of imgEls) {
                if (imgEl.getAttribute('replace') !== null) continue;
                const alt = imgEl.getAttribute('alt');
                imgEl.setAttribute('replace', '');
                if (alt === null) continue;
                imgEl.setAttribute('title', alt);
                const {state, model, content} = replaceEmoticons(substituteWordsArr, imgEl, alt);
                if (!state) continue;
                if (model === 'del') {
                    eventEmitter.send('打印信息', `已清除用户${name}的评论中的表情`);
                    continue;
                }
                if (model === 'subStr') {
                    imgEl.outerHTML = `<span replace>${content}</span>`;
                    eventEmitter.send('打印信息', `已替换用户${name}的评论中的表情:`);
                }
            }
        }
        if (isReplaceCommentSearchTerms()) {
            for (let aEl of aEls) {
                const text = aEl.textContent;
                aEl.outerHTML = `<span replace>${text}</span>`;
                eventEmitter.send('打印信息', `已替换用户${name}的评论中的搜索跳转关键词:`);
            }
        }
        for (let spanEl of spanEls) {
            if (spanEl.getAttribute('replace') !== null) continue;
            const elContent = spanEl.textContent;
            const {state, content} = replaceKeywords(substituteWordsArr, '评论内容', elContent);
            if (!state) continue;
            spanEl.textContent = content;
            spanEl.setAttribute('replace', '');
            eventEmitter.send('打印信息', `已替换用户${name}的评论内容:原\n${elContent}现\n${content}`);
        }
    });
    window.addEventListener('load', () => {
        console.log('页面加载完成');
        rightFloatingLayoutVue.addLayout();
        router.staticRoute(document.title, window.location.href);
        watch.addEventListenerUrlChange((newUrl, oldUrl, title) => {
            router.dynamicRouting(title, newUrl);
        });
    });
    watch.addEventListenerNetwork((url, windowUrl, winTitle, initiatorType) => {
        observeNetwork$1.observeNetwork(url, windowUrl, winTitle, initiatorType);
    });
    document.addEventListener('keydown', function (event) {
        if (event.key === "`") {
            eventEmitter.send('主面板开关');
        }
    });
})(Vue, Dexie);