// ==UserScript==
// @name 哔哩哔哩屏蔽增强器
// @namespace http://tampermonkey.net/
// @license Apache-2.0
// @version 2.1
// @author byhgz
// @description 对B站视频或评论进行屏蔽,支持关键词模糊正则等,支持时长播放弹幕过滤等,如视频、评论、动态、直播间的评论等,详情可看下面支持的屏蔽类型
// @icon https://static.hdslb.com/images/favicon.ico
// @noframes
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_addStyle
// @grant GM_unregisterMenuCommand
// @grant GM_registerMenuCommand
// @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://update.greasyfork.org/scripts/517928/gz_ui_css-v1.js
// @require https://update.greasyfork.org/scripts/521941/about_and_feedback_components.js
// @require https://greasyfork.org/scripts/462234-message/code/Message.js
// @require https://update.greasyfork.org/scripts/449512/Xtiper.js
// @require https://update.greasyfork.org/scripts/516282/Drawer_gz%E9%A1%B5%E9%9D%A2%E4%BE%A7%E8%BE%B9%E6%8A%BD%E5%B1%89%E7%BB%84%E4%BB%B6.js
// @require https://update.greasyfork.org/scripts/517538/DynamicTabs_gz.js
// ==/UserScript==
"use strict";
(function (Vue) {
'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);
},
};
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 isHideMainButSwitch = () => {
return gmUtil.getData("hideMainButSwitch", false) === true;
};
const setHideMainButSwitch = (bool) => {
gmUtil.setData("hideMainButSwitch", bool === true);
};
const isHideRightTopMainButSwitch = () => {
return gmUtil.getData("hideRightTopMainButSwitch", true) === true;
};
const setHideRightTopMainButSwitch = (bool) => {
gmUtil.setData("hideRightTopMainButSwitch", 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;
};
var localMKData = {
setBorderColor,
getBorderColor,
setOutputInformationFontColor,
getOutputInformationFontColor,
setHighlightInformationColor,
getHighlightInformationColor,
setBOnlyTheHomepageIsBlocked,
getBOnlyTheHomepageIsBlocked,
getAdaptationBAppCommerce,
setAdaptationBAppCommerce,
setDefaultColorInfo,
isHideMainButSwitch,
setHideMainButSwitch,
isCompatible_BEWLY_BEWLY,
setCompatible_BEWLY_BEWLY,
setDiscardOldCommentAreas,
isDiscardOldCommentAreas,
isHideRightTopMainButSwitch,
setHideRightTopMainButSwitch
};
const mainDrawer = new Drawer_gz({
show: false,
height: "50vh",
headerShow: false,
title: "屏蔽器主面板",
direction: "top",
externalButtonText: "屏蔽器",
externalButtonWidth: "80px",
externalButtonShow: !localMKData.isHideMainButSwitch(),
zIndex: 9000,
drawerBorder: `1px solid ${localMKData.getBorderColor()}`,
bodyHtml: `
`,
});
const options = {
styles: `
.my-custom-tab-button {
font-size: 16px;
}
.my-custom-tab-content {
background-color: #f9f9f9;
}
`,
classes: {
tabButton: 'my-custom-tab-button',
tabButtonActive: 'my-custom-tab-button-active',
tabContent: 'my-custom-tab-content',
tabContentActive: 'my-custom-tab-content-active'
},
backgroundColor: '#eee',
borderColor: '#ddd',
textColor: '#333',
fontWeight: 'bold',
activeBackgroundColor: '#0056b3',
activeTextColor: '#fff',
contentBorderColor: '#bbb',
contentBackgroundColor: '#ffffff',
onTabClick: (id, title, content) => {
const tab = tabsConfig.find(item => item.title === title);
const height = tab.height;
mainDrawer.setHeight(height ? height : '50vh');
},
};
const tabsConfig = [
{
id: 'tab01',
title: '面板设置',
content: '',
height: "23vh",
},
{
id: 'tab02',
title: '规则管理',
content: '',
height: "96vh"
},
{
id: 'tab03',
title: '其他参数过滤',
content: ``,
},
{
id:'id04',
title: '兼容设置',
content: ``,
},
{
id: 'tab05',
title: '输出信息',
content: ``,
height: "96vh"
},
{
id: 'tab06',
title: '支持打赏',
content: '',
height: "80vh"
},
{
id: 'tab07',
title: '关于和问题反馈',
content: ``,
height: '53vh'
}
];
new DynamicTabs_gz('#shield', tabsConfig,
options
);
class EventEmitter {
constructor() {
this.events = {}; // 存储事件和回调函数
this.handlers = {}; // 存储事件处理函数
}
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
once(eventName, callback) {
const onceCallback = (...args) => {
callback(...args);
this.off(eventName, onceCallback);
};
this.on(eventName, onceCallback);
}
emit(eventName, data) {
if (this.events[eventName]) {
this.events[eventName].forEach(callback => {
try {
callback(data);
} catch (error) {
console.error(`Error in event listener for "${eventName}":`, error);
}
});
return
}
throw new Error(`No event listeners registered for "${eventName}"`);
}
off(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
}
}
removeAllListeners(eventName) {
if (eventName) {
delete this.events[eventName];
delete this.handlers[eventName];
} else {
this.events = {};
this.handlers = {};
}
}
listenerCount(eventName) {
return this.events[eventName] ? this.events[eventName].length : 0;
}
handle(eventName, handler) {
this.handlers[eventName] = handler;
}
invoke(eventName, data) {
if (this.handlers[eventName]) {
return this.handlers[eventName](data);
}
return null;
}
}
const eventEmitter = new EventEmitter();
const returnVue$4 = () => {
return new Vue({
template: `
`,
el: '#shield #panel_settings_vue',
data() {
return {
input_color: "",
hideMainButSwitch: localMKData.isHideMainButSwitch(),
hideRightTopMainButSwitch: localMKData.isHideRightTopMainButSwitch()
}
},
methods: {
setBorderColorBut() {
console.log(this.input_color);
xtip.confirm("是要否设置面板边框颜色吗?", {
icon: "a",
btn1: () => {
localMKData.setBorderColor(this.input_color);
xtip.alert("已设置面板边框颜色,刷新生效");
}
});
},
setDefFontColorForOutputInformationBut() {
xtip.confirm("是要否设置输出信息默认字体颜色吗?", {
icon: "a",
btn1: () => {
localMKData.setOutputInformationFontColor(this.input_color);
xtip.alert("已设置输出信息默认字体颜色,刷新生效");
}
});
},
setTheFontColorForOutputInformationBut() {
xtip.confirm("是要否设置输出信息高亮字体颜色吗?", {
icon: "a",
btn1: () => {
localMKData.setHighlightInformationColor(this.input_color);
xtip.alert("已设置输出信息高亮字体颜色,刷新生效");
}
});
},
setDefInfoBut() {
localMKData.setDefaultColorInfo();
xtip.alert("已恢复默认颜色,刷新生效");
}
},
watch: {
hideMainButSwitch(newVal) {
localMKData.setHideMainButSwitch(newVal);
mainDrawer.externalButtonShow(!newVal);
},
hideRightTopMainButSwitch(newVal) {
localMKData.setHideRightTopMainButSwitch(newVal);
eventEmitter.emit('右上角开关按钮显隐', newVal);
}
}
});
};
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 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
};
};
var defUtil = {
wait,
fileDownload,
toTimeString,
smoothScroll,
debounce,
debounceAsync,
throttle,
throttleAsync,
parseUrl
};
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: "直播分区黑名单(精确匹配)"
}
];
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", []);
};
var ruleKeyListData$1 = {
getNameArr,
getPreciseNameArr,
getNameCanonical,
getPreciseUidArr,
getPreciseUidWhiteArr,
getTitleArr,
getTitleCanonicalArr,
getCommentOnArr,
getCommentOnCanonicalArr,
getRuleKeyListData,
getPreciseTagArr,
getTagArr,
getTagCanonicalArr,
getPreciseFanCardArr,
getPrecisePartitionArr
};
const verificationInputValue = (ruleValue, type) => {
if (ruleValue === null) return null;
if (type === "precise_uid" || type === "precise_uid_white") {
ruleValue = parseInt(ruleValue);
if (isNaN(ruleValue)) {
Qmsg.info('请输入数字!');
return null;
}
} else {
ruleValue.trim();
}
if (ruleValue === '') {
Qmsg.info('内容为空');
return null;
}
return ruleValue;
};
const addRule = (ruleValue, type) => {
const inputValue = verificationInputValue(ruleValue, type);
return new Promise((resolve, reject) => {
if (inputValue === null) {
reject('取消添加');
return;
}
const arr = gmUtil.getData(type, []);
if (arr.includes(inputValue)) {
reject('已存在此内容');
return;
}
arr.push(inputValue);
gmUtil.setData(type, arr);
resolve('添加成功');
}
)
};
const showAddRuleInput = (type) => {
const ruleValue = window.prompt('请输入要添加的规则内容', '');
return addRule(ruleValue, type);
};
const showDelRuleInput = (type) => {
let prompt = window.prompt('请输入要移除的规则内容', '');
const inputValue = verificationInputValue(prompt, type);
return new Promise((resolve, reject) => {
if (inputValue === null) {
reject('取消添加');
return;
}
const arr = gmUtil.getData(type, []);
const indexOf = arr.indexOf(inputValue);
if (indexOf === -1) {
reject('不存在此内容');
return;
}
arr.splice(indexOf, 1);
gmUtil.setData(type, arr);
resolve('移除成功');
})
};
const showSetRuleInput = (type) => {
let prompt = window.prompt('请输入要修改的规则内容', '');
const inputValue = verificationInputValue(prompt, type);
return new Promise((resolve, reject) => {
if (inputValue === null) return;
const arr = gmUtil.getData(type, []);
const indexOf = arr.indexOf(inputValue);
if (indexOf === -1) {
reject('不存在此内容');
return;
}
prompt = window.prompt('请输入要修改的内容', '');
const newInputValue = verificationInputValue(prompt, type);
if (newInputValue === null) return;
if (arr.includes(newInputValue)) {
reject('已存在要修改过后的值内容');
return;
}
arr[indexOf] = newInputValue;
gmUtil.setData(type, arr);
resolve('修改成功');
})
};
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 (let key of keyArr) {
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 getNewRuleKeyList = () => {
return ruleKeyListData$1.getRuleKeyListData();
};
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) => {
return addRule(uid, "precise_uid").then(msg => {
xtip.msg(msg, {icon: 's'});
}).catch(msg => {
xtip.msg(msg, {icon: 'e'});
})
};
const addRulePreciseName= (name) => {
return addRule(name, "precise_name").then(msg => {
xtip.msg(msg, {icon: 's'});
}).catch(msg => {
xtip.msg(msg, {icon: 'e'});
})
};
var ruleUtil = {
addRule,
showAddRuleInput,
showDelRuleInput,
showSetRuleInput,
getRuleContent,
overwriteImportRules,
appendImportRules,
overwriteImportRulesV1,
getNewRuleKeyList,
addRulePreciseUid,
addRulePreciseName
};
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 returnVue$3 = () => {
return new Vue({
template: `
使用说明
- 脚本中会对要匹配的内容进行去除空格和转成小写,比如有个内容是【不 要 笑 挑 战
ChallEnGE】,会被识别称为【不要笑挑战challenge】
- 在上述一点的情况下,模糊匹配和正则匹配的方式时不用考虑要匹配的内容中大写问题
- 大部分情况下模糊匹配比精确匹配好用
- 如果用户要添加自己的正则匹配相关的规则时,建议先去该网址进行测试再添加,避免浪费时间
>>>正则表达式在线测试<<<
-
如果更新脚本之后规则全吗,没了请点击下面的【旧规则自动转新规则】按钮,进行转换,如不行请通过关于和问题反馈选项卡中的反馈渠道联系作者
《====可点击切换条件
导出规则
导入规则
- 规则内容请在下面编辑框中导入
- 旧版本的需要使用下面的v1旧版本导入规则
- 旧版本的只能覆盖导入
- v1之后的版本可以选择覆盖和追加
-
规则信息
{{ item.name }}
个
`,
el: '#shield #rule_management_vue',
data() {
return {
selectVal: 'name',
selectText: "",
ruleContentImport: "",
ruleActions: [
{
type: "uid",
name: "uid(精确)",
}
],
ruleKeyArr: [],
ruleInfoArr: [],
ruleReference: [
{
title: "旧版本规则参考",
content: ` {"用户名黑名单模式(精确匹配)":["账号已注销"],"BV号黑名单模式(精确匹配)":[],
"用户名黑名单模式(模糊匹配)":["bili_","_bili"],"用户uid黑名单模式(精确匹配)":[442010132,76525078,225219967,3493283164588093],
"用户uid白名单模式(精确匹配)":[344490740,1861980711],"标题黑名单模式(模糊匹配)":["激励计划","蚌不住","手游激励","游戏活动打卡"],
"标题黑名单模式(正则匹配)":["感觉.*不如","不要笑.*挑战"],"评论关键词黑名单模式(模糊匹配)":["感觉不如","差不多的了"],
"评论关键词黑名单模式(正则匹配)":["这不.+吗","玩.*的","不要笑.*挑战"],"粉丝牌黑名单模式(精确匹配)":[],
"专栏关键词内容黑名单模式(模糊匹配)":[],"动态关键词内容黑名单模式(模糊匹配)":["拼多多","京东红包","京东618红包","618活动"]}`
},
{
title: "新版本规则参考",
content: "待补充"
}
],
bOnlyTheHomepageIsBlocked: localMKData.getBOnlyTheHomepageIsBlocked()
}
},
methods: {
operationBut(model) {
const type = this.selectVal;
if (model === "add") {
ruleUtil.showAddRuleInput(type).then((msg) => {
this.refreshInfoBut();
alert(msg);
}).catch(errMsg => {
Qmsg.info(errMsg);
});
}
if (model === "del") {
ruleUtil.showDelRuleInput(type).then((msg) => {
this.refreshInfoBut();
alert(msg);
}).catch(errMsg => {
Qmsg.info(errMsg);
});
}
if (model === "set") {
ruleUtil.showSetRuleInput(type).then((msg) => {
this.refreshInfoBut();
alert(msg);
}).catch(errMsg => {
Qmsg.info(errMsg);
});
}
if (model === "del_all") {
if (!window.confirm("确定要删除所有规则吗?")) {
Qmsg.info('取消删除全部操作');
return;
}
for (let x of this.ruleKeyArr) {
gmUtil.delData(x);
}
alert("删除全部规则成功");
this.refreshInfoBut();
}
},
ruleOutToFIleBut() {
const ruleContent = ruleUtil.getRuleContent(4);
let fileName = "b站屏蔽器规则-" + defUtil.toTimeString();
const s = prompt("保存为", fileName);
if (s === null) return;
if (!(s.includes(" ") || s === "" || s.length === 0)) fileName = s;
defUtil.fileDownload(ruleContent, fileName + ".json");
},
ruleOutToConsoleBut() {
xtip.msg('已导出到控制台上!', {icon: 's'});
console.log(ruleUtil.getRuleContent());
},
refreshInfoBut() {
for (let x of this.ruleInfoArr) {
x.len = gmUtil.getData(x.type, []).length;
}
Qmsg.info('已刷新规则信息');
},
overwriteImportRulesBut() {
const trim = this.ruleContentImport.trim();
if (ruleUtil.overwriteImportRules(this.ruleKeyArr, trim)) {
xtip.msg('已导入成功!', {icon: 's'});
this.refreshInfoBut();
}
},
appendImportRulesBut() {
const trim = this.ruleContentImport.trim();
if (ruleUtil.appendImportRules(this.ruleKeyArr, trim)) {
xtip.msg('已导入成功!', {icon: 's'});
this.refreshInfoBut();
}
},
overwriteImportRulesV1But() {
const trim = this.ruleContentImport.trim();
if (ruleUtil.overwriteImportRulesV1(trim)) {
xtip.msg('已导入成功!', {icon: 's'});
this.refreshInfoBut();
}
},
xtipAlertBut(content, title) {
xtip.alert(content,
{title: title});
},
ruleOldToNewBut() {
ruleConversion.oldToNewRule();
this.refreshInfoBut();
xtip.msg('已转换成功!', {icon: 's'});
}
},
watch: {
bOnlyTheHomepageIsBlocked(newVal) {
localMKData.setBOnlyTheHomepageIsBlocked(newVal);
},
selectVal(newVal) {
console.log(newVal);
const find = this.ruleInfoArr.find(item => item.type === newVal);
this.selectText = find.name;
}
},
created() {
for (let newRuleKeyListElement of ruleUtil.getNewRuleKeyList()) {
this.ruleKeyArr.push(newRuleKeyListElement.key);
this.ruleInfoArr.push({
type: newRuleKeyListElement.key,
name: newRuleKeyListElement.name,
len: 0
});
}
const find = this.ruleInfoArr.find(item => item.type === this.selectVal);
this.selectText = find.name;
this.refreshInfoBut();
}
});
};
const returnVue$2 = () => {
return new Vue({
el: "#station_b_shield_donate",
template: `
零钱赞助
- 1元不嫌少,10元不嫌多哦!感谢支持!
- 生活不易,作者叹息
- 您的支持是我最大的更新动力
{{ item.name }}
打赏点猫粮
`,
data: {
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"},
]
}
});
};
const returnVue$1 = () => {
return new Vue({
el: '#other_parameter_filter',
template: `
{{ item.name }}
{{ item.name.includes('时长') ? '秒' : '' }}
`,
data() {
return {
index: 0,
selectList: [
{
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
}
],
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.index > associatedVal && associatedVal !== -1) {
if (associatedFind.bLarge) {
xtip.alert(`要设置的${find.name}值不能大于${associatedFind.name}的值`);
return
}
console.log('正常修改');
}
xtip.alert(`已设置${find.name},值为${this.index}`);
gmUtil.setData(this.selectValue, this.index);
this.updateInfo();
},
cancelBut() {
gmUtil.setData(this.selectValue, -1);
const find = this.selectList.find(item => item.value === this.selectValue);
xtip.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();
xtip.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.index > 6) {
this.index = 6;
}
if (this.index < 3) {
this.index = 3;
}
} else {
this.inputMin = 0;
this.inputMax = '';
}
}
},
created() {
this.updateInfo();
}
})
};
const returnVue = () => {
return new Vue({
el: "#shield #compatible_setting",
template: `
`,
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);
}
}
})
};
document.querySelector("#output_information button")?.addEventListener("click", () => {
olEL.innerHTML = "";
alert("已清空消息");
});
const olEL = document.querySelector("#output_information>.info");
const addInfo = (content) => {
const liEL = document.createElement("li");
liEL.innerHTML = content;
olEL.appendChild(liEL);
};
const outputInformationFontColor = localMKData.getOutputInformationFontColor();
const highlightInformationColor = localMKData.getHighlightInformationColor();
eventEmitter.on('正则匹配时异常', (errorData) => {
const {msg, e} = errorData;
addInfo(msg);
console.log(msg);
throw new Error(e)
});
const getVideoInfoHtml = (type, matching, videoData) => {
const toTimeString = defUtil.toTimeString();
const {name, uid, title, videoUrl} = videoData;
return `
${toTimeString}-根据${type}-${matching ? `【${matching}】` : ""}-屏蔽用户【${name}】uid=
【${uid}】
标题【${title}】
`
};
const getCommentInfoHtml = (type, matching, commentData) => {
const toTimeString = defUtil.toTimeString();
const {name, uid, content} = commentData;
return `
${toTimeString}-根据${type}-${matching ? `【${matching}】` : ""}-屏蔽用户【${name}】uid=
【${uid}】
评论【${content}】
`
};
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 = {
addInfo,
getVideoInfoHtml,
getCommentInfoHtml,
getLiveRoomCommentInfoHtml,
getDynamicContentInfoHtml,
getLiveRoomInfoHtml
};
var css = `button {
position: fixed;
right: 5%;
top: 13%;
width: 60px;
height: 60px;
border-radius: 50%;
border-width: 0;
cursor: pointer;
background: #0056b3;
}
`;
const addLayout = () => {
const div = document.createElement('div');
div.style.position = 'fixed';
div.style.zIndex = '9001';
div.style.display = localMKData.isHideRightTopMainButSwitch() ? 'none' : '';
const but = document.createElement('button');
but.textContent = '屏蔽器';
const shadowRoot = div.attachShadow({mode: 'open'});
const styleElement = document.createElement('style');
styleElement.textContent = css;
shadowRoot.appendChild(but);
shadowRoot.appendChild(styleElement);
document.querySelector('body').appendChild(div);
but.addEventListener('click', () => mainDrawer.showDrawer());
eventEmitter.on('右上角开关按钮显隐', (loop) => {
div.style.display = !loop ? '' : 'none';
});
};
var externalHoverSwitchPanelButton = {
addLayout
};
returnVue$4();
returnVue$3();
returnVue$2();
returnVue$1();
returnVue();
installAboutAndFeedbackComponentsVue('#station_b_shield_problem_feedback',
{
title: 'B站屏蔽增强器',
gfFeedbackUrl: 'https://greasyfork.org/zh-CN/scripts/461382'
}
);
gmUtil.addStyle(`
[gz_bezel]{
border:1px solid ${localMKData.getBorderColor()}
}
`);
externalHoverSwitchPanelButton.addLayout();
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 eventRegistry = new Map();
function addEventListenerWithTracking(element, eventName, handler) {
if (!eventRegistry.has(element)) {
eventRegistry.set(element, new Map());
}
const elementEvents = eventRegistry.get(element);
if (!elementEvents.has(eventName)) {
elementEvents.set(eventName, new Set());
}
elementEvents.get(eventName).add(handler);
element.addEventListener(eventName, handler);
}
function findElementUntilFound(selector, config = {}) {
const defConfig = {doc: document, interval: 1000};
config = {...defConfig, ...config};
return new Promise((resolve) => {
const i1 = setInterval(() => {
const element = config.doc.querySelector(selector);
if (element) {
resolve(element);
clearInterval(i1);
}
}, config.interval);
});
}
function findElementsUntilFound(selector, config = {}) {
const defConfig = {doc: document, interval: 1000};
config = {...defConfig, ...config};
return new Promise((resolve) => {
function attemptToFind() {
const elements = config.doc.querySelectorAll(selector);
if (elements.length > 0) {
resolve(elements);
} else {
setTimeout(attemptToFind, config.interval);
}
}
attemptToFind();
});
}
function findElementWithTimeout(selector, config = {}) {
const defConfig = {
doc: document,
interval: 1000,
timeout: 60000
};
config = {...defConfig, ...config};
return new Promise((resolve) => {
let intervalId;
function attemptToFind() {
const element = config.doc.querySelector(selector);
if (element) {
clearInterval(intervalId);
resolve({
state: true,
msg: "已找到元素",
el: element
});
}
}
intervalId = setInterval(attemptToFind, config.interval);
const timeout = setTimeout(() => {
clearInterval(intervalId);
resolve({
state: false,
msg: "已超时:" + config.timeout
}); // 超时后提示信息
clearTimeout(timeout);
}, config.timeout);
attemptToFind(); // 立即尝试一次
});
}
function findElementsWithTimeout(selector, config = {}) {
const defConfig = {
doc: document,
interval: 1000,
timeout: 60000
};
config = {...defConfig, ...config};
return new Promise((resolve, reject) => {
let timer;
let intervalId;
function attemptToFind() {
const elements = config.doc.querySelectorAll(selector);
if (elements.length > 0) {
clearTimeout(timer);
clearInterval(intervalId);
resolve(elements);
}
}
intervalId = setInterval(attemptToFind, config.interval);
timer = setTimeout(() => {
clearInterval(intervalId);
reject(null); // 超时后返回 null
}, config.timeout);
attemptToFind(); // 立即尝试一次
});
}
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,
addEventListenerWithTracking,
findElementUntilFound,
findElementWithTimeout,
findElementsUntilFound,
findElementsWithTimeout,
findElementsAndBindEvents
};
const exactMatch = (ruleList, value) => {
if (ruleList === null || ruleList === undefined) return false;
if (!Array.isArray(ruleList)) return false
return ruleList.some(item => item === value);
};
const regexMatch = (ruleList, value) => {
if (ruleList === null || ruleList === undefined) return null;
if (!Array.isArray(ruleList)) return null
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.emit('正则匹配时异常', {e, msg});
return false;
}
});
return find === undefined ? null : find;
};
const fuzzyMatch = (ruleList, value) => {
if (ruleList === null || ruleList === undefined) return null;
if (!Array.isArray(ruleList)) return null
const find = ruleList.find(item => value.includes(item));
return find === undefined ? null : find;
};
var ruleMatchingUtil = {
exactMatch,
regexMatch,
fuzzyMatch
};
const Tip = {
success(text, config) {
Qmsg.success(text, config);
},
successBottomRight(text) {
this.success(text, {position: "bottomright"});
},
videoBlock(text) {//屏蔽了视频的提示
this.success(text, {position: "bottomright"});
},
info(text, config) {
Qmsg.info(text, config);
},
infoBottomRight(text) {
this.info(text, {position: "bottomright"});
},
error(text, config) {
Qmsg.error(text, config);
},
errorBottomRight(text) {
this.error(text, {position: "bottomright"});
},
warning(text, config) {
Qmsg.warning(text, config);
},
config(cfg) {//设置全局Tip配置
Qmsg.config(cfg);
},
loading(text, config) {
return Qmsg.loading(text, config);
},
close(loading) {
try {
loading.close();
} catch (e) {
console.error(e);
this.error("loading关闭失败!");
}
},
printLn(content) {
Util.printElement("#outputInfo", `${content}`);
},
printVideo(color, content, name, uid, title, videoHref) {
Util.printElement("#outputInfo", `
${Util.toTimeString()}${content}屏蔽用户【${name}】uid=【${uid}】标题【${title}】
`);
},
printCommentOn(color, content, name, uid, primaryContent) {
Util.printElement("#outputInfo", `
${Util.toTimeString()}${content} 屏蔽用户【${name}】uid=【${uid}】
原言论=【${primaryContent}】
`);
}
};
const isTopicDetailPage = (url) => {
return url.includes("//www.bilibili.com/v/topic/detail/")
};
const getDataList$1 = async () => {
const elList = await elUtil.findElementsUntilFound(".list__topic-card");
const list = [];
for (let el of elList) {
const name = el.querySelector(".bili-dyn-title").textContent.trim();
const uidEl = el.querySelector(".bili-dyn-item__following");
const uid = parseInt(uidEl.getAttribute("data-mid"));
const judgmentEl = el.querySelector(".bili-dyn-card-video__title");
const data = {name, uid, el, judgmentVideo: judgmentEl !== null};
if (judgmentEl !== null) {
data.title = judgmentEl.textContent.trim();
data.videoUrl = el.querySelector(".bili-dyn-card-video").href;
data.insertionPositionEl = el.querySelector(".bili-dyn-content__orig");
data.explicitSubjectEl = data.insertionPositionEl;
} else {
const dynTitle = el.querySelector(".dyn-card-opus__title");
const contentTitle = dynTitle === null ? "" : dynTitle.textContent.trim();
const contentBody = el.querySelector(".bili-rich-text>div").textContent.trim();
data.insertionPositionEl = el.querySelector(".dyn-card-opus");
data.explicitSubjectEl = data.insertionPositionEl;
data.content = contentTitle + contentBody;
}
list.push(data);
}
return list;
};
const __shieldingVideo = (videoData) => {
if (shielding.shieldingVideoDecorated(videoData)) {
return;
}
shielding.addTopicDetailVideoBlockButton({data: videoData, maskingFunc: startShielding});
};
const __shieldingDynamic = (dynamicData) => {
if (shielding.shieldingCommentDecorated(dynamicData)) {
return;
}
shielding.addTopicDetailContentsBlockButton({data: dynamicData, maskingFunc: startShielding});
};
const startShielding = async () => {
const list = await getDataList$1();
const css = {width: "100%"};
for (let data of list) {
data.css = css;
if (data.judgmentVideo) {
__shieldingVideo(data);
} else {
__shieldingDynamic(data);
}
}
};
var topicDetail = {
isTopicDetailPage,
startShielding
};
const getUrlUserLevel = (src) => {
const levelMath = src?.match(/level_(.+)\.svg/) || null;
let level = -1;
if (levelMath !== null) {
const levelRow = levelMath[1];
if (levelRow === 'h') {
level = 7;
} else {
level = parseInt(levelRow);
}
}
return level;
};
const getOldUserLevel = (iEl) => {
let level = -1;
const levelCLassName = iEl.classList[1];
if (levelCLassName === 'level-hardcore') {
level = 7;
} else {
const levelMatch = levelCLassName.match(/level-(.+)/)?.[1] || '';
level = parseInt(levelMatch);
}
return level
};
const getCommentSectionList = async () => {
const commentApp = await elUtil.findElementUntilFound("bili-comments",
{interval: 500});
const comments = await elUtil.findElementsUntilFound("#feed>bili-comment-thread-renderer",
{doc: commentApp.shadowRoot, interval: 500});
const commentsData = [];
let isLoaded = false;
for (let el of comments) {
const theOPEl = el.shadowRoot.getElementById("comment").shadowRoot;
const theOPUserInfo = theOPEl.querySelector("bili-comment-user-info")
.shadowRoot.getElementById("info");
const userNameEl = theOPUserInfo.querySelector("#user-name>a");
const userLevelSrc = theOPUserInfo.querySelector('#user-level>img')?.src || null;
const level = getUrlUserLevel(userLevelSrc);
isLoaded = theOPEl.querySelector("#content>bili-rich-text")
.shadowRoot.querySelector("#contents>*") !== null;
if (!isLoaded) {
break;
}
const theOPContentEl = theOPEl.querySelector("#content>bili-rich-text")
.shadowRoot.querySelector("#contents");
const theOPContent = theOPContentEl.textContent.trim();
const userName = userNameEl.textContent.trim();
const userUrl = userNameEl.href;
const uid = elUtil.getUrlUID(userUrl);
const replies = [];
commentsData.push({
name: userName,
userUrl,
uid,
level,
content: theOPContent,
replies,
el,
insertionPositionEl: theOPUserInfo,
explicitSubjectEl: theOPEl.querySelector("#body")
});
const inTheBuildingEls = el.shadowRoot.querySelector("bili-comment-replies-renderer")
.shadowRoot.querySelectorAll("bili-comment-reply-renderer");
for (let inTheBuildingEl of inTheBuildingEls) {
const inTheContentEl = inTheBuildingEl.shadowRoot;
const biliCommentUserInfo = inTheContentEl.querySelector("bili-comment-user-info");
biliCommentUserInfo.style.display = 'block';
const inTheBuildingUserInfo = biliCommentUserInfo.shadowRoot.getElementById("info");
const inTheBuildingUserNameEl = inTheBuildingUserInfo.querySelector("#user-name>a");
const inTheBuildingUserName = inTheBuildingUserNameEl.textContent.trim();
const inTheBuildingUserUrl = inTheBuildingUserNameEl.href;
const inTheBuildingUid = elUtil.getUrlUID(inTheBuildingUserUrl);
const biliRichTextEL = inTheContentEl.querySelector("bili-rich-text");
const inTheBuildingContent = biliRichTextEL.shadowRoot.getElementById("contents").textContent.trim();
const userLevelSrc = inTheBuildingUserInfo.querySelector('#user-level>img')?.src || null;
const level = getUrlUserLevel(userLevelSrc);
replies.push({
name: inTheBuildingUserName,
userUrl: inTheBuildingUserUrl,
uid: inTheBuildingUid,
level,
content: inTheBuildingContent,
el: inTheBuildingEl,
insertionPositionEl: inTheBuildingUserInfo,
explicitSubjectEl: inTheContentEl
});
}
}
if (!isLoaded) {
await defUtil.wait(500);
return getCommentSectionList()
}
return commentsData;
};
const getOldCommentSectionList = async () => {
const results = await elUtil.findElementsWithTimeout(".reply-list>.reply-item");
if (results === null) {
return [];
}
const commentsData = [];
for (let el of results) {
const theOPEl = el.querySelector(".root-reply-container");
const theOPUserInfoEl = theOPEl.querySelector(".user-name");
const userName = theOPUserInfoEl.textContent.trim();
const uid = parseInt(theOPUserInfoEl.getAttribute("data-user-id"));
const userUrl = `https://space.bilibili.com/${uid}`;
const theOPContent = theOPEl.querySelector(".reply-content").textContent.trim();
const userInfoEl = el.querySelector(".user-info");
const iEl = userInfoEl.querySelector('i');
const level = getOldUserLevel(iEl);
const replies = [];
commentsData.push({
name: userName,
userUrl,
uid,
content: theOPContent,
level,
replies,
el,
insertionPositionEl: userInfoEl,
explicitSubjectEl: el.querySelector(".content-warp")
});
const inTheBuildingEls = el.querySelectorAll(".sub-reply-container>.sub-reply-list>.sub-reply-item");
for (let inTheBuildingEl of inTheBuildingEls) {
const subUserNameEl = inTheBuildingEl.querySelector(".sub-user-name");
const uid = parseInt(subUserNameEl.getAttribute("data-user-id"));
const userName = subUserNameEl.textContent.trim();
const userUrl = `https://space.bilibili.com/${uid}`;
const subContent = inTheBuildingEl.querySelector(".reply-content").textContent.trim();
const subUserInfoEl = inTheBuildingEl.querySelector(".sub-user-info");
const iEl = subUserInfoEl.querySelector('i');
const level = getOldUserLevel(iEl);
const replyContentContainerEl = inTheBuildingEl.querySelector('span.reply-content-container');
replyContentContainerEl.style.display = 'block';
replies.push({
name: userName,
userUrl,
uid,
level,
content: subContent,
el: inTheBuildingEl,
insertionPositionEl: subUserInfoEl,
explicitSubjectEl: inTheBuildingEl
});
}
}
return commentsData;
};
const startShieldingComments = async () => {
let list;
const href = window.location.href;
if (localMKData.isDiscardOldCommentAreas()) {
list = await getCommentSectionList();
} else if (href.includes("https://space.bilibili.com/") || topicDetail.isTopicDetailPage(href)) {
list = await getOldCommentSectionList();
} else {
list = await getCommentSectionList();
}
shielding.shieldingComments(list);
};
var commentSectionModel = {
startShieldingComments
};
const addBlockButton = (data, tagCss, position = []) => {
const {insertionPositionEl, explicitSubjectEl, css} = data.data;
if (insertionPositionEl.querySelector("." + tagCss)) return;
const buttonEL = document.createElement("button");
buttonEL.setAttribute("gz_type", "");
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];
}
}
buttonEL.style.display = "none";
elUtil.addEventListenerWithTracking(explicitSubjectEl, "mouseover", () => buttonEL.style.display = "");
elUtil.addEventListenerWithTracking(explicitSubjectEl, "mouseout", () => buttonEL.style.display = "none");
insertionPositionEl.appendChild(buttonEL);
buttonEL.addEventListener("click", (event) => {
event.stopImmediatePropagation(); // 阻止事件冒泡和同一元素上的其他事件处理器
event.preventDefault(); // 阻止默认行为
const {uid, name} = data.data;
console.log("该选项数据:", data);
xtip.sheet({
btn: [`uid精确屏蔽-用户uid=${uid}-name=${name}`, `用户名精确屏蔽(不推荐)-用户name=${name}`],
btn1: () => {
if (uid === -1) {
Tip.error("该页面数据不存在uid字段");
return;
}
ruleUtil.addRule(uid, "precise_uid").then(msg => {
xtip.msg(msg);
data.maskingFunc();
}).catch(msg => {
xtip.alert(msg, {icon: 'e'});
});
},
btn2: () => {
if (!name) {
alert("该页面数据不存在name字段" + name);
return;
}
if (!window.confirm('不推荐用户使用精确用户名来屏蔽,确定继续吗?')) return
ruleUtil.addRulePreciseName(name);
},
});
});
};
const addVideoBlockButton$1 = (data) => {
addBlockButton(data, "gz_shielding_button", ["right"]);
};
const addPopularVideoBlockButton = (data) => {
addBlockButton(data, "gz_shielding_button", ["right", "bottom"]);
};
const addTopicDetailVideoBlockButton = (data) => {
addBlockButton(data, "gz_shielding_button");
};
const addTopicDetailContentsBlockButton = (data) => {
const position = data.data.position;
const loop = position !== undefined;
addBlockButton(data, "gz_shielding_topic_detail_button", loop ? position : []);
};
const addCommentBlockButton = (commentsData) => {
const data = {
data: commentsData,
maskingFunc: commentSectionModel.startShieldingComments
};
addBlockButton(data, "gz_shielding_comment_button");
};
const addLiveContentBlockButton = (commentsData) => {
addBlockButton(commentsData, "gz_shielding_live_danmaku_button");
};
const shieldingVideo = (videoData) => {
const {
title, uid = -1,
name, nDuration = -1,
nBulletChat = -1, nPlayCount = -1
} = videoData;
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidWhiteArr(), uid)) {
return {state: false};
}
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
return {state: true, type: "精确匹配uid"};
}
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 (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseNameArr(), name)) {
return {state: true, type: "精确匹配用户名"};
}
matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getNameArr(), name);
if (matching !== null) {
return {state: true, type: "模糊匹配用户名", matching};
}
matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getNameCanonical(), name);
if (matching !== null) {
return {state: true, type: "正则用户名", matching};
}
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 {state: false};
};
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";
}
Tip.successBottomRight("屏蔽了视频");
const videoInfoHtml = output_informationTab.getVideoInfoHtml(type, matching, videoData);
output_informationTab.addInfo(videoInfoHtml);
}
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 {state: false}
};
const shieldingDynamicDecorated = (dynamicData) => {
const {state, type, matching} = shieldingDynamic(dynamicData);
if (state) {
Tip.successBottomRight("屏蔽了视频");
output_informationTab.addInfo(output_informationTab.getDynamicContentInfoHtml(type, matching, dynamicData));
}
return state;
};
const shieldingComment = (commentsData) => {
const {content, uid, name, level = -1} = commentsData;
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidWhiteArr(), uid)) {
return {state: false};
}
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
return {state: true, type: "精确匹配uid"};
}
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseNameArr(), name)) {
return {state: true, type: "精确用户名"};
}
let matching = ruleMatchingUtil.fuzzyMatch(ruleKeyListData$1.getNameArr(), name);
if (matching !== null) {
return {state: true, type: "模糊匹配用户名", matching};
}
matching = ruleMatchingUtil.regexMatch(ruleKeyListData$1.getNameCanonical(), name);
if (matching !== null) {
return {state: true, type: "正则用户名", matching};
}
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) {
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 {state: false};
};
const shieldingCommentDecorated = (commentsData) => {
const {state, type, matching} = shieldingComment(commentsData);
if (state) {
commentsData.el?.remove();
Tip.successBottomRight("屏蔽了评论");
output_informationTab.addInfo(output_informationTab.getCommentInfoHtml(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();
Tip.successBottomRight("屏蔽了直播间评论");
}
if (type) {
output_informationTab.addInfo(output_informationTab.getLiveRoomCommentInfoHtml(type, matching, liveRoomContent));
}
return state;
};
const shieldingComments = (commentsDataList) => {
for (let commentsData of commentsDataList) {
if (shieldingCommentDecorated(commentsData)) continue;
addCommentBlockButton(commentsData);
const {replies = []} = commentsData;
if (replies.length === 0) continue;
for (let reply of replies) {
if (shieldingCommentDecorated(reply)) continue;
addCommentBlockButton(reply);
}
}
};
const shieldingLiveRoom = (liveRoomData) => {
const {name = null, title, partition, uid = -1} = liveRoomData;
if (uid !== -1) {
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidWhiteArr(), uid)) {
return {state: false};
}
if (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPreciseUidArr(), uid)) {
return {state: true, type: "精确用户uid"};
}
}
let matching;
if (name !== null) {
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 (ruleMatchingUtil.exactMatch(ruleKeyListData$1.getPrecisePartitionArr(), partition)) {
return {state: true, type: "精确直播分区"};
}
return {state: false};
};
const shieldingLiveRoomDecorated = (liveRoomData) => {
const {state, type, matching = null} = shieldingLiveRoom(liveRoomData);
if (state) {
liveRoomData.el?.remove();
Tip.successBottomRight("屏蔽了直播间");
output_informationTab.addInfo(output_informationTab.getLiveRoomInfoHtml(type, matching, liveRoomData));
}
return state;
};
const intervalExecutionStartShieldingVideoInert = (func, name = '') => {
let i1 = -1;
const start = () => {
if (i1 !== -1) {
return
}
console.log('开始执行屏蔽' + name);
i1 = setInterval(() => {
func();
console.log(`执行屏蔽${name}列表-定时器正在执行`);
}, 1500);
};
const stop = () => {
if (i1 === -1) {
return
}
clearInterval(i1);
console.log(`已停止执行屏蔽${name}列表`);
i1 = -1;
};
return {start, stop}
};
var shielding = {
shieldingVideoDecorated,
shieldingDynamicDecorated,
shieldingCommentDecorated,
shieldingLiveRoomDecorated,
shieldingComments,
addVideoBlockButton: addVideoBlockButton$1,
addCommentBlockButton,
shieldingLiveRoomContentDecorated,
addLiveContentBlockButton,
addPopularVideoBlockButton,
addTopicDetailVideoBlockButton,
addTopicDetailContentsBlockButton,
intervalExecutionStartShieldingVideoInert,
addBlockButton
};
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 = "已删除下载提示";
Tip.infoBottomRight(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;
if (!userUrl.includes("//space.bilibili.com/")) {
el?.remove();
const log = "遍历换一换视频列表中检测到异常内容,已将该元素移除";
Tip.infoBottomRight(log);
console.log(log, el);
continue;
}
list.push({
...tempData, ...{
videoUrl,
el,
insertionPositionEl: el.querySelector(".bili-video-card__info--bottom"),
explicitSubjectEl: el.querySelector(".bili-video-card__info")
}
});
} catch (e) {
el.remove();
Qmsg.error("获取视频信息失败");
}
}
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 = "遍历换一换视频列表下面列表时检测到异常内容,已将该元素移除";
Tip.infoBottomRight(log);
console.log(log, el);
continue;
}
list.push({
...tempData, ...{
videoUrl: el.querySelector(".bili-video-card__info--tit>a").href,
el,
insertionPositionEl: el.querySelector(".bili-video-card__info--bottom"),
explicitSubjectEl: el.querySelector(".bili-video-card__info")
}
});
} catch (e) {
el?.remove();
Tip.infoBottomRight("遍历视频列表中检测到异常内容,已将该元素移除;");
}
}
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 insertionPositionEl = el.querySelector(".bili-video-card__info--owner");
list.push({
...tempData, ...{
videoUrl,
el,
insertionPositionEl,
explicitSubjectEl: el
}
});
}
return list;
};
const startShieldingGateVideoList = async () => {
const list = await getGateDataList();
for (let videoData of list) {
if (shielding.shieldingVideoDecorated(videoData, "hide")) {
continue;
}
shielding.addVideoBlockButton({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;
}
shielding.addVideoBlockButton({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;
}
shielding.addVideoBlockButton({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
};
const isSearch = (url) => {
return url.includes("search.bilibili.com")
};
const getVideoList$1 = async (css) => {
const elList = await elUtil.findElementsWithTimeout(css);
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");
let userUrl;
try {
userUrl = userEl.getAttribute("href");
} catch (e) {
console.error(e);
}
if (!userUrl.includes("//space.bilibili.com/")) {
el?.remove();
Tip.infoBottomRight("移除了非视频内容");
console.log("移除了非视频内容", userUrl, el);
continue;
}
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,
nPlayCount,
nBulletChat,
nDuration,
el,
videoUrl: el.querySelector(".bili-video-card__info--right>a").href,
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 startShieldingVideoList$6 = () => {
getTabComprehensiveSortedVideoList().then(list => {
for (let videoData of list) {
if (shielding.shieldingVideoDecorated(videoData)) {
continue;
}
shielding.addVideoBlockButton({data: videoData, maskingFunc: startShieldingVideoList$6});
}
console.log("搜索页综合选项卡中的综合排序视频列表已处理完成");
});
getOtherVideoList().then(list => {
for (let videoData of list) {
if (shielding.shieldingVideoDecorated(videoData)) {
continue;
}
shielding.addVideoBlockButton({data: videoData, maskingFunc: startShieldingVideoList$6});
}
});
};
const startDebounceShieldingVideoList$1 = defUtil.debounce(startShieldingVideoList$6, 500);
var searchModel = {
isSearch,
startDebounceShieldingVideoList: startDebounceShieldingVideoList$1
};
const getData = (key,defValue=null) => {
const el = document.querySelector('#mk_data');
if (el === null) {
return defValue
}
const text = el.textContent.trim();
const parse = JSON.parse(text);
if (parse[key]) {
return parse[key]
}
return defValue
};
const addData = (key, value) => {
const el = document.querySelector('#mk_data');
if (el === null) {
const mk_data = document.createElement('div');
mk_data.id = 'mk_data';
mk_data.style.display = 'none';
document.head.appendChild(mk_data);
mk_data.textContent = JSON.stringify({[key]: value});
return
}
const txt = el.textContent.trim();
const parse = JSON.parse(txt);
parse[key] = value;
el.textContent = JSON.stringify(parse);
};
const setData = (key, value) => {
addData(key, value);
};
var elData = {
addData,
getData,
setData
};
const isVideoPlayPage = (url) => {
return url.includes("www.bilibili.com/video");
};
const installSingleUserCreatorButton = async () => {
const el = await elUtil.findElementUntilFound('.up-info-container');
const installPositionEl = el.querySelector('.up-info--right');
const butEl = document.createElement("button");
butEl.setAttribute("gz_type", "");
butEl.textContent = "屏蔽";
butEl.style.width = "100%";
butEl.style.display = 'none';
const nameEl = installPositionEl.querySelector('a.up-name');
butEl.addEventListener('click', () => {
const name = nameEl.textContent.trim();
const userUrl = nameEl.href;
const uid = elUtil.getUrlUID(userUrl);
console.log('点击了屏蔽按钮', name, userUrl, uid);
xtip.confirm(`用户uid=${uid}-name=${name}`, {
title: "uid精确屏蔽方式", icon: "a",
btn1: () => {
if (uid === -1) {
Tip.error("该页面数据不存在uid字段");
return;
}
ruleUtil.addRulePreciseUid(uid);
}
});
});
elUtil.addEventListenerWithTracking(installPositionEl, 'mouseover', () => butEl.style.display = '');
elUtil.addEventListenerWithTracking(installPositionEl, 'mouseout', () => butEl.style.display = 'none');
installPositionEl.appendChild(butEl);
Tip.infoBottomRight(`单作者添加屏蔽按钮成功`);
};
const creationTeamInsertsShieldButton = async () => {
const elList = await elUtil.findElementsUntilFound('.container>.membersinfo-upcard-wrap>.membersinfo-upcard');
for (let item of elList) {
const butEL = document.createElement('button');
butEL.className = "gz_button gz_demo";
butEL.textContent = "屏蔽";
butEL.style.display = 'none';
const userUrl = item.querySelector('.avatar').href;
const uid = elUtil.getUrlUID(userUrl);
const name = item.querySelector('.staff-name').textContent.trim();
butEL.addEventListener('click', () => {
xtip.confirm(`uid=${uid}-name=${name}`, {
title: "uid精确屏蔽方式", icon: "a",
btn1: () => {
if (uid === -1) {
Tip.error("该页面数据不存在uid字段");
return;
}
ruleUtil.addRulePreciseUid(uid);
}
});
});
item.appendChild(butEL);
elUtil.addEventListenerWithTracking(item, 'mouseover', () => butEL.style.display = '');
elUtil.addEventListenerWithTracking(item, 'mouseout', () => butEL.style.display = 'none');
}
Tip.infoBottomRight(`创作团队添加屏蔽按钮成功`);
};
const execAuthorAddBlockButton = () => {
elUtil.findElementWithTimeout('.header.can-pointer', {timeout: 4000}).then(res => {
if (res.state) {
creationTeamInsertsShieldButton();
elData.setData('isSingleAuthor', false);
return
}
if (elData.getData('isSingleAuthor', false)) {
return;
}
elData.setData('isSingleAuthor', true);
installSingleUserCreatorButton();
});
};
const getGetTheVideoListOnTheRight$1 = async () => {
await elUtil.findElementUntilFound(".video-page-card-small .b-img img");
const elList = await elUtil.findElementsUntilFound(".video-page-card-small", {interval: 50});
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();
let nPlayCount = playInfo.match(/<\/svg>(.*)