// ==UserScript==
// @name 哔哩哔哩屏蔽增强器
// @namespace http://tampermonkey.net/
// @license Apache-2.0
// @version 2.8
// @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 *://www.bilibili.com/v/food/*
// @match *://message.bilibili.com/*
// @match *://www.bilibili.com/read/*
// @match *://www.bilibili.com/v/topic/detail/?topic_id=*
// @match *://www.bilibili.com/v/kichiku/*
// @match *://t.bilibili.com/*
// @match *://space.bilibili.com/*
// @match *://www.bilibili.com/video/*
// @match *://live.bilibili.com/?spm_id_from=*
// @match *://live.bilibili.com/p/eden/area-tags?*
// @match *://live.bilibili.com/*
// @match *://www.bilibili.com/opus/*
// @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/dexie@4.0.10/dist/dexie.min.js
// @require https://scriptcat.org/lib/2697/0.5/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 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';
var globalValue = {
group_url,
scriptCat_js_url,
b_url,
common_question_url,
update_log_url
};
gmUtil.addGMMenu('主面板', () => {
eventEmitter.send('主面板开关');
}, 'Q');
gmUtil.addGMMenu('脚本猫脚本更新页', () => {
gmUtil.openInTab(globalValue.scriptCat_js_url);
}, 'E');
gmUtil.addGMMenu('gf脚本更新页', () => {
gmUtil.openInTab('https://greasyfork.org/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 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 setBOnlyTheHomepageIsBlocked = (bool) => {
gmUtil.setData("bOnlyTheHomepageIsBlocked", bool === true);
};
const getBOnlyTheHomepageIsBlocked = () => {
return gmUtil.getData("bOnlyTheHomepageIsBlocked", false);
};
const getAdaptationBAppCommerce = () => {
return gmUtil.getData("adaptation-b-app-recommend", false) === true;
};
const setAdaptationBAppCommerce = (bool) => {
gmUtil.setData("adaptation-b-app-recommend", bool === true);
};
const isShowRightTopMainButSwitch = () => {
return gmUtil.getData("showRightTopMainButSwitch", true) === true;
};
const setShowRightTopMainButSwitch = (bool) => {
gmUtil.setData("showRightTopMainButSwitch", bool === true);
};
const isFirstFullDisplay = () => {
return gmUtil.getData('isFirstFullDisplay', true) === true
};
const setFirstFullDisplay = (bool) => {
gmUtil.setData('isFirstFullDisplay', bool === true);
};
const isHalfHiddenIntervalAfterInitialDisplay = () => {
return gmUtil.getData('is_half_hidden_interval_after_initial_display', true) === true
};
const setHalfHiddenIntervalAfterInitialDisplay = (bool) => {
gmUtil.setData('is_half_hidden_interval_after_initial_display', bool === true);
};
const isCompatible_BEWLY_BEWLY = () => {
return gmUtil.getData("compatible_BEWLY_BEWLY", false) === true;
};
const setCompatible_BEWLY_BEWLY = (bool) => {
gmUtil.setData("compatible_BEWLY_BEWLY", bool === true);
};
const setDiscardOldCommentAreas = (bool) => {
gmUtil.setData("discardOldCommentAreas", bool === true);
};
const isDiscardOldCommentAreas = () => {
return gmUtil.getData("discardOldCommentAreas", false) === true;
};
const isDelPlayerPageRightVideoList = () => {
return gmUtil.getData("isDelPlayerPageRightVideoList", false) === true
};
const bFuzzyAndRegularMatchingWordsToLowercase$1 = () => {
return gmUtil.getData("bFuzzyAndRegularMatchingWordsToLowercase", true) === true
};
const setFuzzyAndRegularMatchingWordsToLowercase = (bool) => {
gmUtil.setData("bFuzzyAndRegularMatchingWordsToLowercase", bool === true);
};
const isRequestFrequencyVal = () => {
return gmUtil.getData("requestFrequencyVal", 0.2)
};
const isDisableNetRequestsBvVideoInfo = () => {
return gmUtil.getData('isDisableNetRequestsBvVideoInfo', false)
};
const setDisableNetRequestsBvVideoInfo = (b) => {
gmUtil.setData('isDisableNetRequestsBvVideoInfo', b);
};
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)
};
var localMKData = {
getTripleRate,
isTripleRateBlockingStatus,
setBorderColor,
getBorderColor,
setOutputInformationFontColor,
getOutputInformationFontColor,
setHighlightInformationColor,
getHighlightInformationColor,
setBOnlyTheHomepageIsBlocked,
getBOnlyTheHomepageIsBlocked,
getAdaptationBAppCommerce,
setAdaptationBAppCommerce,
setDefaultColorInfo,
isCompatible_BEWLY_BEWLY,
setCompatible_BEWLY_BEWLY,
setDiscardOldCommentAreas,
isDiscardOldCommentAreas,
isShowRightTopMainButSwitch,
setShowRightTopMainButSwitch,
isFirstFullDisplay,
setFirstFullDisplay,
isHalfHiddenIntervalAfterInitialDisplay,
setHalfHiddenIntervalAfterInitialDisplay,
isDelPlayerPageRightVideoList,
bFuzzyAndRegularMatchingWordsToLowercase: bFuzzyAndRegularMatchingWordsToLowercase$1,
setFuzzyAndRegularMatchingWordsToLowercase,
isRequestFrequencyVal,
isDisableNetRequestsBvVideoInfo,
setDisableNetRequestsBvVideoInfo,
isBlockFollowed,
isUpOwnerExclusive,
isGenderRadioVal,
isVipTypeRadioVal,
isSeniorMember,
isCopyrightRadio,
isDelBottomComment,
isBlockVerticalVideo,
isCheckTeamMember,
getVideoLikeRate,
isVideoLikeRateBlockingStatus,
isCoinLikesRatioRateBlockingStatus,
getCoinLikesRatioRate,
isCoinLikesRatioRateDisabled,
isInteractiveRateBlockingStatus,
getInteractiveRate
};
const panel_settings_vue = {
template: `
颜色设置
选择器
设置边框色
设置输出信息默认字体色
设置输出信息高亮字体色
恢复默认
页面右侧悬浮按钮设置
说明
按键盘tab键上的~键为展开关闭主面板
devTools
`,
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() {
if (this.devToolsInputVal === 'show-dev') {
gmUtil.setData('open-dev', true);
eventEmitter.send('debugger-dev-show', true);
this.devToolsInputVal = '';
}
if (this.devToolsInputVal === 'stop-dev') {
gmUtil.setData('open-dev', false);
eventEmitter.send('debugger-dev-show', false);
this.devToolsInputVal = '';
}
}
},
watch: {
showRightTopMainButSwitch(newVal) {
localMKData.setShowRightTopMainButSwitch(newVal);
eventEmitter.send('显隐主面板开关', newVal);
},
isFirstFullDisplay(newVal) {
localMKData.setFirstFullDisplay(newVal);
},
isHalfHiddenIntervalAfterInitialDisplay(newBool) {
localMKData.setHalfHiddenIntervalAfterInitialDisplay(newBool);
}
}
};
const getSelectOptions = () => {
const options = [
{
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;
}
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: "contentOn",
name: "评论内容黑名单(模糊匹配)",
oldKey: "contentOnKeyArr",
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: 'hotSearchKey',
name: '热搜关键词(模糊匹配)',
}, {
key: 'hotSearchKeyCanonical',
name: '热搜关键词(正则匹配)'
}, {
key: 'precise_avatarPendantName',
name: '头像挂件名(精确匹配)'
}, {
key: 'avatarPendantName',
name: '头像挂件名(模糊匹配)'
}, {
key: 'signature',
name: '用户签名(模糊匹配)'
}, {
key: 'signatureCanonical',
name: '用户签名(正则匹配)'
}, {
key: 'videoDesc',
name: '视频简介(模糊匹配)'
}, {
key: 'videoDescCanonical',
name: '视频简介(正则匹配)'
}
];
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 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);
};
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
};
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 = (keyArr, content) => {
const map = verificationRuleMap(keyArr, content);
if (map === false) return false;
for (let key of Object.keys(map)) {
gmUtil.setData(key, map[key]);
}
return true;
};
const appendImportRules = (keyArr, content) => {
const map = verificationRuleMap(keyArr, 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-alert', results.res);
return null
}
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: `
{{ ruleName }}-{{ ruleType }}
`,
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 basic_rules_vue = {
components: {rule_set_value_dialog},
template: `
使用说明
1.基础规则类型较多,下拉框支持搜索定位,鼠标点击出现光标时支持筛选
2.大部分情况下模糊匹配比精确匹配好用
3.如果可以的话,请优先考虑根据uid精确屏蔽,而非使用用户名相关屏蔽,因用户名可以随意更改
4.如果用户要添加自己的正则匹配相关的规则时,建议先去该网址进行测试再添加,避免浪费时间
>>>正则表达式在线测试<<<
5.如果更新脚本之后规则全没了,请点击下面的【旧规则自动转新规则】按钮,进行转换,如不行请通过关于和问题反馈选项卡中的反馈渠道联系作者
6.改动实时生效
选择规则
添加
修改
查询
移除
清空项
全部移除
`,
data() {
return {
cascaderVal: ["精确匹配", "precise_uid"],
cascaderOptions: ruleKeyListData$1.getSelectOptions(),
ruleInfoArr: [],
}
},
methods: {
handleChangeCascader(val) {
console.log(val);
},
setRuleBut() {
const type = this.cascaderVal[1];
const {name} = this.ruleInfoArr.find(item => item.type === type);
eventEmitter.send('修改规则对话框', type, name);
},
operationBut(model) {
const type = this.cascaderVal[1];
if (model === "add") {
ruleUtil.showAddRuleInput(type);
}
if (model === "del") {
ruleUtil.showDelRuleInput(type);
}
if (model === "del_all") {
this.$confirm('确定要删除所有规则吗?').then(() => {
for (let x of this.ruleInfoArr) {
gmUtil.delData(x.type);
}
this.$alert("删除全部规则成功");
eventEmitter.send('刷新规则信息');
});
}
if (model === 'find-item-all') {
const ruleData = gmUtil.getData(type, []);
eventEmitter.send('展示内容对话框', JSON.stringify(ruleData, null, 4));
}
},
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: `
导出规则
导出到文件
导出到编辑框
导出到控制台
导入规则
{{ item.title }}
规则内容请在下面编辑框中导入
旧版本的需要使用下面的v1旧版本导入规则
旧版本的只能覆盖导入
v1之后的版本可以选择覆盖和追加
旧规则转新规则,用于2.0之前版本升上来旧规则内容丢失问题
读取外部规则文件
覆盖导入规则
追加导入规则
v1旧版本覆盖导入规则
旧规则自动转新规则
`,
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();
debugger
if (ruleUtil.overwriteImportRules(this.ruleKeyArr, trim)) {
this.$alert('已覆盖导入成功!');
eventEmitter.send('刷新规则信息');
}
});
},
appendImportRulesBut() {
this.$confirm('是否要追加导入规则?').then(() => {
const trim = this.ruleContentImport.trim();
if (ruleUtil.appendImportRules(this.ruleKeyArr, 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打开控制台查看');
},
},
};
var other_parameter_filter = {
template: `
刷新
{{ item.name }}{{ item.defVal }}
{{ item.name.includes('时长') ? '秒' : '' }}
`,
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: `
刷新信息
个
`,
data() {
return {
ruleInfoArr: [],
}
},
methods: {
refreshInfoBut() {
for (let x of this.ruleInfoArr) {
x.len = gmUtil.getData(x.type, []).length;
}
this.$notify({
title: 'tip',
message: '刷新规则信息成功',
type: 'success',
});
},
},
created() {
for (let newRuleKeyListElement of ruleKeyListData$1.getRuleKeyListData()) {
this.ruleInfoArr.push({
type: newRuleKeyListElement.key,
name: newRuleKeyListElement.name,
len: 0
});
}
this.refreshInfoBut();
eventEmitter.on('刷新规则信息', () => {
this.refreshInfoBut();
});
}
};
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
});
const setRequestFrequencyVal = (v) => {
gmUtil.setData('requestFrequencyVal', v > 0 && v <= 5 ? v : 0.2);
};
var conditionalityVue = {
template: `
网络请求频率(单位秒)
如设置0,则为不限制,比如设置2,则为每个请求之间隔2秒,可有效降低对B站api接口的压力,降低风控
注意:设置过低可能会导致部分接口风控
如接口风控了请先勾选下面的【禁用根据bv号网络请求获取视频信息】
修改实时生效
`,
data() {
return {
requestFrequencyVal: localMKData.isRequestFrequencyVal(),
bOnlyTheHomepageIsBlocked: localMKData.getBOnlyTheHomepageIsBlocked(),
bFuzzyAndRegularMatchingWordsToLowercase: localMKData.bFuzzyAndRegularMatchingWordsToLowercase(),
isDisableNetRequestsBvVideoInfo: false
}
},
methods: {},
watch: {
bOnlyTheHomepageIsBlocked(newVal) {
localMKData.setBOnlyTheHomepageIsBlocked(newVal);
},
bFuzzyAndRegularMatchingWordsToLowercase(newVal) {
localMKData.setFuzzyAndRegularMatchingWordsToLowercase(newVal);
},
isDisableNetRequestsBvVideoInfo(b) {
localMKData.setDisableNetRequestsBvVideoInfo(b);
},
requestFrequencyVal(n) {
setRequestFrequencyVal(n);
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: `
1.注意:该功能为b站自身的黑名单
1.对应地址
https://account.bilibili.com/account/blacklist
3.需要登录才可以使用
累计
显示数
请求的间隔({{ sliderInterval }}S)
获取第一页
获取全部
清空列表
导出控制台
导出文件
过滤
{{ new Date(scope.row.mtime * 1000).toLocaleString() }}
未定
一键添加uid屏蔽
打开地址
uid屏蔽
`,
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 video_metrics_filter_item_vue = {
props: {
headerTitle: {type: String},
describe: {type: String},
mkTypeRateKey: {type: String},
mkRateStatusKey: {type: String},
},
template: `
{{ headerTitle }}
{{ describe }}
`,
data() {
return {
rateBlockingStatus: false,
ratioRateVal: 0,
rateDisabled: false,
}
},
methods: {
reteFormatTooltip(val) {
return (val * 100).toFixed(0) + '%'
}
},
watch: {
ratioRateVal(n) {
gmUtil.setData(this.mkTypeRateKey, n);
},
rateBlockingStatus(n) {
this.rateDisabled = !n;
gmUtil.setData(this.mkRateStatusKey, n);
}
},
created() {
this.ratioRateVal = gmUtil.getData(this.mkTypeRateKey, 0.05);
const bool = gmUtil.getData(this.mkRateStatusKey, false);
this.rateBlockingStatus = bool;
this.rateDisabled = !bool;
}
};
const video_metrics_filter_vue = {
components: {video_metrics_filter_item_vue},
template: `
`,
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 high_level_rule_vue = {
components: {video_metrics_filter_vue},
template: `
指标屏蔽(改动实时生效)
视频类型
选中的类型会被屏蔽
会员类型屏蔽
性别屏蔽
计算创作团队
`,
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);
}
}
};
var ruleManagementVue = {
components: {
rule_export_import_vue,
other_parameter_filter,
rule_information_vue,
conditionalityVue,
basic_rules_vue,
blacklist_management_vue,
high_level_rule_vue
},
template: `
`,
data() {
return {}
}
};
const compatible_setting_vue = {
template: `
说明
如果用户没有安装并使用对应脚本或插件,就不要开启相关兼容选项
Bilibili-Gate脚本(bilibili-app-recommend)
BewlyBewly插件
评论区
使用之后需刷新对应页面才可生效,勾选即评论区使用新版获取方式,不再使用旧版方式
`,
data() {
return {
adaptationBAppRecommend: localMKData.getAdaptationBAppCommerce(),
compatible_BEWLY_BEWLY: localMKData.isCompatible_BEWLY_BEWLY(),
discardOldCommentAreasV: localMKData.isDiscardOldCommentAreas()
}
},
watch: {
adaptationBAppRecommend(newVal) {
localMKData.setAdaptationBAppCommerce(newVal);
},
compatible_BEWLY_BEWLY(newVal) {
localMKData.setCompatible_BEWLY_BEWLY(newVal);
},
discardOldCommentAreasV(newVal) {
localMKData.setDiscardOldCommentAreas(newVal);
}
}
};
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 clearVideoInfosTable = async () => {
try {
await mk_db.videoInfos.clear();
return true
} catch (e) {
console.log('清除videoInfos表失败', e);
return false
}
};
var bvDexie = {
addVideoData,
clearVideoInfosTable,
bulkImportVideoInfos,
getVideoInfo,
getVideoInfoCount
};
const cache_management_vue = {
template: `
说明
1.每个域名中的缓存数据不同
2.仅仅支持导入json格式
3.下面导入默认追加模式
4.当前域名
{{ hostname }}
操作
追加导入视频缓存数据
清空当前域名的视频缓存数据
查看内容
查看数据量
导出
导出至文件
导出至控制台
`,
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}`);
});
}
},
created() {
}
};
var donateLayoutVue = {
template: `
零钱赞助
1元不嫌少,10元不嫌多,感谢支持!
生活不易,作者叹息
用爱发电不容易,您的支持是我最大的更新动力
打赏点猫粮
`,
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: `
`,
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 = `
${toTimeString}-根据${type}-${matching ? `【${matching}】` : ""}-屏蔽用户【${name}】uid=
【${uid}】
标题【${title}】
`;
this.outputInfoArr.push(info);
});
eventEmitter.on('屏蔽评论信息', (type, matching, commentData) => {
const toTimeString = defUtil.toTimeString();
const {name, uid, content} = commentData;
this.outputInfoArr.push(`
${toTimeString}-根据${type}-${matching ? `【${matching}】` : ""}-屏蔽用户【${name}】uid=
【${uid}】
评论【${content}】
`);
});
eventEmitter.on('正则匹配时异常', (errorData) => {
const {msg, e} = errorData;
this.outputInfoArr.push(msg);
console.error(msg);
throw new Error(e)
});
}
};
const look_content_dialog_vue = {
template: `
`,
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 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
};
const bAfterLoadingThePageOpenMainPanel = () => {
return gmUtil.getData('bAfterLoadingThePageOpenMainPanel', false)
};
const setBAfterLoadingThePageOpenMainPanel = (b) => {
gmUtil.setData('bAfterLoadingThePageOpenMainPanel', b === true);
};
const debugger_management_vue = {
template: `
测试
测试网络请求
打印valueCache值
打印事件中心值
打印requestIntervalQueue值
`,
data() {
return {
bAfterLoadingThePageOpenMainPanel: bAfterLoadingThePageOpenMainPanel()
}
},
methods: {
printValueCacheBut() {
console.log(valueCache.getAll());
},
demoBut() {
bFetch.fetchGetVideoInfo('BV152cWeXEhW').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);
};
var elUtil = {
getUrlUID,
getUrlBV,
findElement,
findElements,
findElementUntilFound,
findElementsUntilFound,
findElementsAndBindEvents
};
const setTopInputPlaceholder = async () => {
if (localMKData.isCompatible_BEWLY_BEWLY()) {
return
}
const placeholder = valueCache.get('topInputPlaceholder');
if (placeholder === null) {
return
}
const targetInput = await elUtil.findElement('.nav-search-input');
targetInput.placeholder = placeholder;
eventEmitter.send('el-notification', {
title: "tip",
message: '已恢复顶部搜索框提示内容',
position: 'bottom-right',
});
};
const processTopInputContent = async () => {
if (localMKData.isCompatible_BEWLY_BEWLY()) {
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: `
搜索页
播放页
顶部搜索框
`,
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),
}
},
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();
}
}
};
const about_and_feedback_vue = {
template: `
作者b站
b站传送门
交流群
====》Q群传送门《====
876295632
发布、更新、反馈地址
greasyfork
===》传送门《===
脚本猫
===》传送门《===
开源地址
gitee
https://gitee.com/hangexi/BiBiBSPUserVideoMonkeyScript
github
https://github.com/hgztask/BiBiBSPUserVideoMonkeyScript
常见问题和使用文档
常见问题
==>传送门<==
使用文档
==>传送门<==
更新日志
==>传送门<==
`,
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: `
`,
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: `
`,
data() {
return {
dialogShow: true,
list: []
}
},
methods: {
handleClick(item) {
if (this.clickItemClose) {
return;
}
this.$emit('options-click', item);
}
}
};
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: `
`,
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
},
data() {
return {
drawer: false,
tabsActiveName: '规则管理',
debug_panel_show: gmUtil.getData('open-dev', false),
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-notification', (...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);
});
this.tabsActiveName = gmUtil.getData('mainTabsActiveName', '规则管理');
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 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 `
${toTimeString}-根据${type}-${matching ? `【${matching}】` : ""}-屏蔽用户【${name}】uid=
【${uid}】
直播评论【${content}】
`
};
const getDynamicContentInfoHtml = (type, matching, dynamicData) => {
const toTimeString = defUtil.toTimeString();
const {name, uid, content} = dynamicData;
return `
${toTimeString}-根据${type}-${matching ? `【${matching}】` : ""}-屏蔽用户【${name}】uid=
【${uid}】
动态【${content}】
`
};
const getLiveRoomInfoHtml = (type, matching, liveRoomData) => {
const toTimeString = defUtil.toTimeString();
const {name = null, uid = -1, title, liveUrl} = liveRoomData;
return `
${toTimeString}-根据${type}${matching ? `【${matching}】` : ""}-屏蔽用户【${name === null ? '' : name}】${uid === -1 ? "" : `uid=
【${uid}】`}
直播间标题【${title}】
`
};
var output_informationTab = {
getLiveRoomCommentInfoHtml,
getDynamicContentInfoHtml,
getLiveRoomInfoHtml
};
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();
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 returnTempVal = {state: false};
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, name} = data.data;
eventEmitter.send('sheet-dialog', {
title: "屏蔽选项",
list: [
{
label: `uid精确屏蔽-用户uid=${uid}-name=${name}`,
value: "uid"
}, {
label: `用户名精确屏蔽(不推荐)-用户name=${name}`,
value: 'name'
}
],
optionsClick: (item) => {
const {value} = item;
if (value === 'uid') {
if (uid === -1) {
eventEmitter.send('el-msg', "该页面数据不存在uid字段");
return;
}
const {status, res} = ruleUtil.addRulePreciseUid(uid, false);
if (status) {
data.maskingFunc();
}
eventEmitter.send('el-alert', res);
return;
}
if (!name) {
eventEmitter.send('el-alert', "该页面数据不存在name字段" + name);
return;
}
eventEmitter.invoke('el-confirm', '不推荐用户使用精确用户名来屏蔽,确定继续吗?').then(() => {
ruleUtil.addRulePreciseName(name);
});
}
});
});
};
eventEmitter.on('视频添加屏蔽按钮', (data) => {
addBlockButton$1(data, "gz_shielding_button", ["right"]);
});
eventEmitter.on('视频添加屏蔽按钮-BewlyBewly', (data) => {
addBlockButton$1(data, "gz_shielding_button", ['right', 'bottom']);
});
eventEmitter.on('添加热门视频屏蔽按钮', (data) => {
addBlockButton$1(data, "gz_shielding_button", ["right", "bottom"]);
});
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 addLiveContentBlockButton = (commentsData) => {
addBlockButton$1(commentsData, "gz_shielding_live_danmaku_button");
};
const blockUserUid = (uid) => {
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
return {state: true, type: "精确uid"};
}
return returnTempVal;
};
const checkWhiteUserUid = (uid) => {
return ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidWhiteArr(), uid);
};
const shieldingVideo = (videoData) => {
const {
title, uid = -1,
name, nDuration = -1,
nBulletChat = -1, nPlayCount = -1
} = videoData;
if (checkWhiteUserUid(uid)) {
return returnTempVal;
}
let returnVal = blockUserUid(uid);
if (returnVal.state) {
return returnVal;
}
let matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getTitleArr(), title);
if (matching !== null) {
return {state: true, type: "模糊标题", matching};
}
matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getTitleCanonicalArr(), title);
if (matching !== null) {
return {state: true, type: "正则标题", matching};
}
if (name) {
returnVal = blockUserName(name);
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 blockExactAndFuzzyMatching = (val, config) => {
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 blockAvatarPendant = (name) => {
return blockExactAndFuzzyMatching(name, {
exactKey: 'precise_avatarPendantName',
exactTypeName: '精确头像挂件名', fuzzyKey: 'avatarPendantName', fuzzyTypeName: '模糊头像挂件名'
})
};
const blockSignature = (signature) => {
return blockExactAndFuzzyMatching(signature, {
fuzzyKey: 'signature', fuzzyTypeName: '模糊用户签名', regexKey: 'signatureCanonical', regexTypeName: '正则用户签名'
})
};
const blockVideoDesc = (desc) => {
return blockExactAndFuzzyMatching(desc, {
fuzzyKey: 'videoDesc', fuzzyTypeName: '视频简介(模糊匹配)'
, regexKey: 'videoDescCanonical', regexTypeName: '视频简介(正则匹配)'
})
};
const blockGender = (gender) => {
const val = localMKData.isGenderRadioVal();
const state = val === gender && val !== '不处理';
if (state) {
return {state: true, type: '性别屏蔽', matching: val}
}
return returnTempVal;
};
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 blockSeniorMember = (num) => {
if (num === 1 && localMKData.isSeniorMember()) {
return {state: true, type: '屏蔽硬核会员'}
}
return returnTempVal
};
const blockVideoCopyright = (num) => {
const val = localMKData.isCopyrightRadio();
const tempMap = {
1: '原创',
2: '转载'
};
if (val === tempMap[num]) {
return {state: true, type: '视频类型屏蔽', matching: val}
}
return returnTempVal
};
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 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 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 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 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 blockUserUidAndName = (uid, name) => {
if (!uid || !name) {
return returnTempVal
}
let returnVal = blockUserUid(uid);
if (returnVal.state) {
return returnVal
}
returnVal = blockUserName(name);
if (returnVal.state) {
return returnVal
}
return returnTempVal
};
const blockVideoTeamMember = (teamMember) => {
if (!teamMember) {
return returnTempVal
}
for (let u of teamMember) {
if (checkWhiteUserUid(u.mid)) {
continue
}
const returnVal = blockUserUidAndName(u.mid, u.name);
if (returnVal.state) {
return returnVal
}
}
return returnTempVal
};
const blockUserName = (name) => {
return blockExactAndFuzzyMatching(name, {
exactKey: 'precise_name',
exactTypeName: '精确用户名', fuzzyKey: 'name', fuzzyTypeName: '模糊用户名',
regexKey: 'nameCanonical', regexTypeName: '正则用户名'
})
};
const shieldingOtherVideoParameter = async (videoData) => {
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;
if (videoInfo?.following && localMKData.isBlockFollowed()) {
return {state: true, type: '已关注'}
}
const isUpOwnerExclusive = videoInfo?.is_upower_exclusive;
if (isUpOwnerExclusive && localMKData.isUpOwnerExclusive()) {
return {state: true, type: '充电专属视频'}
}
let returnValue;
if (tags.length !== 0) {
returnValue = blockBasedVideoTag(tags);
if (returnValue.state) {
return returnValue
}
}
const currentLevel = userInfo?.current_level || -1;
returnValue = shieldingByLevel(currentLevel);
if (returnValue.state) {
return returnValue
}
const avatarPendantName = userInfo?.pendant?.name || null;
if (avatarPendantName) {
returnValue = blockAvatarPendant(avatarPendantName);
if (returnValue.state) {
return returnValue
}
}
const signContent = userInfo?.sign;
if (signContent) {
returnValue = blockSignature(signContent);
if (returnValue.state) {
return returnValue
}
}
const desc = videoInfo?.desc || null;
if (desc) {
returnValue = blockVideoDesc(desc);
if (returnValue.state) {
return returnValue
}
}
const tempList = [
blockGender(userInfo?.sex), blockUserVip(userInfo.vip.type),
blockSeniorMember(userInfo.is_senior_member), blockVideoCopyright(videoInfo.copyright),
blockVerticalVideo(videoInfo.dimension), blockVideoTeamMember(videoInfo.staff),
blockVideoLikeRate(videoInfo.like, videoInfo.view), blockVideoInteractiveRate(videoInfo.danmaku, videoInfo.reply, videoInfo.view),
blockVideoTripleRate(videoInfo.favorite, videoInfo.coin, videoInfo.share, videoInfo.view), blockVideoCoinLikesRatioRate(videoInfo.coin, videoInfo.like)
];
for (let v of tempList) {
if (v.state) {
return v
}
const msg = v.msg;
if (msg) {
console.warn(msg);
}
}
};
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 shieldingVideoDecorated = (videoData, method = "remove") => {
const {el} = videoData;
if (el.style.display === "none") {
return true
}
const {state, type, matching = null} = shieldingVideo(videoData);
if (state) {
if (method === "remove") {
el?.remove();
} else {
el.style.display = "none";
}
eventEmitter.send('屏蔽视频信息', type, matching, videoData);
return true;
}
if (localMKData.isDisableNetRequestsBvVideoInfo()) {
return state
}
shieldingOtherVideoParameter(videoData).then(res => {
if (!res) {
return
}
const {type, matching} = res;
if (method === "remove") {
el.remove();
} else {
el.style.display = "none";
}
eventEmitter.send('屏蔽视频信息', type, matching, videoData);
});
return state;
};
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 shieldingComment = (commentsData) => {
const {content, uid, name, level = -1} = commentsData;
if (checkWhiteUserUid(uid)) {
return returnTempVal;
}
let returnVal = blockUserUid(uid);
if (returnVal.state) {
return returnVal
}
if (name) {
returnVal = blockUserName(name);
if (returnVal.state) {
return returnVal
}
}
let matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getCommentOnArr(), content);
if (matching !== null) {
return {state: true, type: "模糊评论内容", matching};
}
matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getCommentOnCanonicalArr(), content);
if (matching !== null) {
return {state: true, type: "正则评论内容", matching};
}
if (level !== -1) {
return shieldingByLevel(level);
}
return returnTempVal;
};
const shieldingByLevel = (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 shieldingCommentDecorated = (commentsData) => {
const {state, type, matching} = shieldingComment(commentsData);
if (state) {
commentsData.el?.remove();
eventEmitter.send('屏蔽评论信息', type, matching, commentsData);
}
return state;
};
const shieldingLiveRoomContentDecorated = (liveRoomContent) => {
let {state, type, matching} = 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 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 shieldingLiveRoom = (liveRoomData) => {
const {name, title, partition, uid = -1} = liveRoomData;
if (uid !== -1) {
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidWhiteArr(), uid)) {
return returnTempVal;
}
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
return {state: true, type: "精确用户uid"};
}
}
let matching;
if (name) {
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseNameArr(), name)) {
return {state: true, type: "精确用户名"};
}
matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getNameArr(), name);
if (matching) {
return {state: true, type: "模糊用户名", matching};
}
}
matching = ruleMatchingUtil.exactMatch(ruleKeyListData$1.getTitleArr(), title);
if (matching) {
return {state: true, type: "模糊标题", matching};
}
matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getTitleCanonicalArr(), title);
if (matching) {
return {state: true, type: "正则标题", matching};
}
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 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 = {
shieldingVideo,
shieldingVideoDecorated,
shieldingDynamicDecorated,
shieldingCommentDecorated,
shieldingLiveRoomDecorated,
shieldingComments,
shieldingLiveRoomContentDecorated,
addLiveContentBlockButton,
addTopicDetailVideoBlockButton,
addTopicDetailContentsBlockButton,
intervalExecutionStartShieldingVideoInert,
addBlockButton: addBlockButton$1
};
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 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 adaptationBAppCommerce$1 = localMKData.getAdaptationBAppCommerce();
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 getGateActivatedTab = async () => {
const el = await elUtil.findElementUntilFound(".ant-radio-group>.ant-radio-button-wrapper-checked .css-1k4kcw8");
return el?.textContent.trim();
};
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 = 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 (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);
};
const startClearExcessContentList = () => {
if (adaptationBAppCommerce$1) return;
setInterval(() => {
const otherElList = document.querySelectorAll(".floor-single-card");
const liveList = document.querySelectorAll(".bili-live-card");
const elList = [...otherElList, ...liveList];
for (let el of elList) {
el?.remove();
}
}, 1000);
console.log("已启动每秒清理首页视频列表中多余的内容");
};
const startShieldingChangeVideoList = async () => {
const list = await getChangeTheVideoElList();
for (let videoData of list) {
if (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 (shielding.shieldingVideoDecorated(videoData)) {
continue;
}
eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingHomeVideoList});
}
};
const startDebounceShieldingHomeVideoList = defUtil.debounce(startShieldingHomeVideoList, 500);
const scrollMouseUpAndDown = async () => {
if (adaptationBAppCommerce$1) return;
await defUtil.smoothScroll(false, 100);
return defUtil.smoothScroll(true, 600);
};
var bilibiliHome = {
isHome,
startClearExcessContentList,
startDebounceShieldingChangeVideoList,
startDebounceShieldingHomeVideoList,
scrollMouseUpAndDown,
deDesktopDownloadTipEl,
startIntervalShieldingGateVideoList
};
var css = `.to_hide_xl {
display: block !important;
}
`;
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 (shielding.shieldingLiveRoomDecorated(liveData)) {
continue
}
addBlockButton({data: liveData, maskingFunc: startShieldingLiveRoomList});
}
};
const InstallLiveTopTabsListener = async () => {
const el = await elUtil.findElement('.live-condition');
if (elEventEmitter.hasEventName(el, 'click')) return
elEventEmitter.addEvent(el, 'click', async (event) => {
const target = event.target;
const label = target.textContent.trim();
if (label === '主播') {
return
}
await startShieldingLiveRoomList();
InstallBottomPagingListener();
installTopRoomOrderListener();
});
console.log("直播顶部选项卡安装监听器已安装");
};
const InstallBottomPagingListener = async () => {
const el = await elUtil.findElement('.vui_pagenation--btns');
if (elEventEmitter.hasEventName(el, 'click')) return
elEventEmitter.addEvent(el, 'click', async (event) => {
const target = event.target;
if (target.tagName !== 'BUTTON') {
return
}
await startShieldingLiveRoomList();
installTopRoomOrderListener();
});
console.log("底部分页安装监听器已安装");
};
const installTopRoomOrderListener = async () => {
const el = await elUtil.findElement('.room-order');
if (elEventEmitter.hasEventName(el, 'click')) return
elEventEmitter.addEvent(el, 'click', async (event) => {
const target = event.target;
console.log('顶部房间排序监听器触发了', target.textContent.trim(), target);
await startShieldingLiveRoomList();
InstallBottomPagingListener();
installTopRoomOrderListener();
});
console.log('顶部房间排序监听器已安装');
};
var searchLive = {
InstallLiveTopTabsListener,
installStyle,
startShieldingLiveRoomList,
InstallBottomPagingListener,
installTopRoomOrderListener
};
const isSearch = (url) => {
return url.includes("search.bilibili.com")
};
const currentlyActivatedOptions = async () => {
const el = await elUtil.findElement('.vui_tabs--nav-item-active .vui_tabs--nav-text');
const label = el.textContent.trim();
if (label === '直播') {
await searchLive.startShieldingLiveRoomList();
searchLive.InstallLiveTopTabsListener();
searchLive.InstallBottomPagingListener();
elUtil.findElementUntilFound('.live-condition>.vui_button--active').then(activeEl => {
if (activeEl.textContent.trim() !== '主播') {
searchLive.installTopRoomOrderListener();
}
});
}
};
const searchTopTabsIWrapperInstallListener = async () => {
const tempTabs = ['番剧', '影视', '用户'];
const el = await elUtil.findElement('.vui_tabs--navbar>ul');
el.addEventListener("click", async (event) => {
const eventTarget = event.target;
if (eventTarget.className !== 'vui_tabs--nav-text') {
return
}
const tabName = eventTarget.textContent.trim();
if (tempTabs.includes(tabName)) {
return
}
if (tabName === '直播') {
searchLive.installTopRoomOrderListener();
return
}
console.log("搜索页顶部选项卡监听器触发了", tabName);
});
console.log("搜索页顶部选项卡安装监听器已安装");
};
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");
};
const startShieldingCSVideoList = async () => {
const list = await getTabComprehensiveSortedVideoList();
for (let videoData of list) {
if (shielding.shieldingVideoDecorated(videoData)) {
continue;
}
eventEmitter.send('视频添加屏蔽按钮', {data: videoData, maskingFunc: startShieldingCSVideoList});
}
};
const startShieldingOtherVideoList = async () => {
const list = await getOtherVideoList();
for (let videoData of list) {
if (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();
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) {
shielding.shieldingVideoDecorated(videoData);
}
};
const delFooterContent = () => {
if (!gmUtil.getData('isRemoveSearchBottomContent', false)) {
return
}
elUtil.findElement('#biliMainFooter').then(el => {
el.remove();
eventEmitter.send('打印信息', '已删除底部内容');
});
};
var searchModel = {
isSearch,
searchTopTabsIWrapperInstallListener,
startShieldingVideoList: startShieldingVideoList$6,
currentlyActivatedOptions,
delFooterContent
};
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>(.*)