// ==UserScript==
// @name 哔哩哔哩过滤评论区
// @description 根据关键词/用户等级过滤评论区
// @version 1.0.4
// @author girl-dream
// @license The Unlicense
// @namespace https://github.com/girl-dream/
// @icon https://www.bilibili.com/favicon.ico
// @match https://www.bilibili.com/video/*
// @match https://www.bilibili.com/list/*
// @match https://www.bilibili.com/bangumi/play/*
// @match https://t.bilibili.com/*
// @match https://www.bilibili.com/opus/*
// @match https://space.bilibili.com/*/dynamic
// @match https://www.bilibili.com/v/topic/detail/*
// @match https://www.bilibili.com/cheese/play/*
// @match https://www.bilibili.com/festival/*
// @match https://www.bilibili.com/blackboard/*
// @match https://www.bilibili.com/blackroom/ban/*
// @match https://www.bilibili.com/read/*
// @match https://manga.bilibili.com/*
// @match https://www.bilibili.com/v/topic/detail*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant unsafeWindow
// @run-at document-end
// ==/UserScript==
(async () => {
'use strict'
let keyWords = GM_getValue('filter_keywords', [
'关于我升',
'六级不在',
'拍个照',
'合个影'
])
// 账号等级排除:勾选的等级(LV1~LV6)对应的账号评论将被过滤
let excludedLevels = GM_getValue('filter_excluded_levels', [])
GM_registerMenuCommand('设置过滤关键词', () => {
if (document.getElementById('bili-filter-settings')) return
const div = document.createElement('div')
div.id = 'bili-filter-settings'
div.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999999;
`
const content = document.createElement('div')
content.style.cssText = `
background: var(--bg1_float);
padding: 20px;
border-radius: 8px;
width: 400px;
max-width: 90%;
max-height: 80vh;
overflow-y: auto;
color:var(--text1);
`
content.innerHTML = `
过滤关键词设置
每行一个关键词,评论包含任意关键词即被过滤
`
// 填充当前关键词
const textarea = content.querySelector('#keywords-input')
textarea.value = keyWords.join('\n')
content.querySelector('#cancel-btn').onclick = () => {
div.remove()
}
content.querySelector('#save-btn').onclick = () => {
const newKeywords = textarea.value
.split('\n')
.map(k => k.trim())
.filter(k => k.length > 0)
const newExcluded = Array.from(content.querySelectorAll('.excl-level-cb'))
.filter(cb => cb.checked)
.map(cb => parseInt(cb.value, 10))
GM_setValue('filter_keywords', newKeywords)
GM_setValue('filter_excluded_levels', newExcluded)
keyWords = newKeywords
excludedLevels = newExcluded
div.remove()
location.reload()
}
div.appendChild(content)
document.body.appendChild(div)
})
const filterReplies = (replies) => {
return replies.filter(reply => {
const msg = reply.content?.message || ''
const hasKeyword = keyWords.some(keyword => msg.includes(keyword))
if (hasKeyword) {
return false
}
// 账号等级排除:勾选等级的账号评论直接过滤
if (excludedLevels.length > 0) {
const level = reply.member?.level_info?.current_level
if (typeof level === 'number' && excludedLevels.includes(level)) {
return false
}
}
if (reply.replies && Array.isArray(reply.replies)) {
reply.replies = filterReplies(reply.replies)
if (reply.replies.length == 0) {
reply.replies = null
}
}
return true
})
}
const originalFetch = window.fetch
unsafeWindow.fetch = async (...args) => {
const response = await originalFetch.apply(this, args)
const clonedResponse = response.clone()
if (args[0].includes('reply')) {
let data = await clonedResponse.json()
let modified = false
if (data.data?.replies && Array.isArray(data.data.replies)) {
data.data.replies = filterReplies(data.data.replies)
modified = true
}
// 置顶评论单独存放,同样需要过滤
if (data.data?.top_replies && Array.isArray(data.data.top_replies)) {
data.data.top_replies = filterReplies(data.data.top_replies)
modified = true
}
if (modified) {
return new Response(JSON.stringify(data), response)
}
}
return response
}
})()