From 9b2fae2b044963027ced8597229dba92668c1653 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Wed, 20 Nov 2024 12:35:36 +0800 Subject: [PATCH 1/4] fix: comment filter self related (#177) --- CHANGELOG.md | 5 + src/modules/filters/index.ts | 30 +- .../comment/pages/{video.ts => common.ts} | 73 +- .../filters/variety/comment/pages/dynamic.ts | 797 ------------------ .../variety/comment/subFilters/white.ts | 2 + vite.config.ts | 2 +- 6 files changed, 75 insertions(+), 834 deletions(-) rename src/modules/filters/variety/comment/pages/{video.ts => common.ts} (91%) delete mode 100644 src/modules/filters/variety/comment/pages/dynamic.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a6f2a8..38f5ea0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 4.0.11 + +- 更新:评论过滤 统一全站设定,不再按页面分类 +- 更新:评论过滤 排除自己的评论和@自己的评论 + ## 4.0.10 - 新增:评论区过滤 过滤@其他用户的无回复评论 diff --git a/src/modules/filters/index.ts b/src/modules/filters/index.ts index 273ca92f..b24145a4 100644 --- a/src/modules/filters/index.ts +++ b/src/modules/filters/index.ts @@ -14,20 +14,15 @@ import { } from '../../utils/pageType' import { BiliCleanerStorage } from '../../utils/storage' import { - commentFilterDynamicEntry, - commentFilterDynamicGroups, - commentFilterDynamicHandler, -} from './variety/comment/pages/dynamic' + commentFilterCommonEntry, + commentFilterCommonGroups, + commentFilterCommonHandler, +} from './variety/comment/pages/common' import { commentFilterSpaceEntry, commentFilterSpaceGroups, commentFilterSpaceHandler, } from './variety/comment/pages/space' -import { - commentFilterVideoEntry, - commentFilterVideoGroups, - commentFilterVideoHandler, -} from './variety/comment/pages/video' import { dynamicFilterDynamicEntry, dynamicFilterDynamicGroups, @@ -96,16 +91,10 @@ export const videoFilters: Filter[] = [ /** 评论过滤器 */ export const commentFilters: Filter[] = [ { - name: '视频页/番剧页 视频评论过滤', - groups: commentFilterVideoGroups, - entry: commentFilterVideoEntry, - checkFn: () => isPageVideo() || isPageBangumi() || isPagePlaylist(), - }, - { - name: '动态页 动态评论过滤', - groups: commentFilterDynamicGroups, - entry: commentFilterDynamicEntry, - checkFn: () => isPageDynamic(), + name: '视频页/番剧页/动态页 视频评论过滤', + groups: commentFilterCommonGroups, + entry: commentFilterCommonEntry, + checkFn: () => isPageVideo() || isPageBangumi() || isPagePlaylist() || isPageDynamic(), }, { name: '空间页 动态评论过滤', @@ -181,7 +170,6 @@ export const filterContextMenuHandlers = [ videoFilterPopularHandler, videoFilterHomepageHandler, dynamicFilterDynamicHandler, - commentFilterVideoHandler, - commentFilterDynamicHandler, + commentFilterCommonHandler, commentFilterSpaceHandler, ] diff --git a/src/modules/filters/variety/comment/pages/video.ts b/src/modules/filters/variety/comment/pages/common.ts similarity index 91% rename from src/modules/filters/variety/comment/pages/video.ts rename to src/modules/filters/variety/comment/pages/common.ts index cb7c5185..b0ec7446 100644 --- a/src/modules/filters/variety/comment/pages/video.ts +++ b/src/modules/filters/variety/comment/pages/common.ts @@ -9,7 +9,7 @@ import { } from '../../../../../types/filter' import fetchHook from '../../../../../utils/fetch' import { debugFilter as debug, error } from '../../../../../utils/logger' -import { isPageBangumi, isPagePlaylist, isPageVideo } from '../../../../../utils/pageType' +import { isPageBangumi, isPageDynamic, isPagePlaylist, isPageVideo } from '../../../../../utils/pageType' import ShadowInstance from '../../../../../utils/shadow' import { BiliCleanerStorage } from '../../../../../utils/storage' import { orderedUniq, showEle } from '../../../../../utils/tool' @@ -26,7 +26,13 @@ import { CommentLevelFilter, CommentUsernameFilter, } from '../subFilters/black' -import { CommentIsLinkFilter, CommentIsNoteFilter, CommentIsPinFilter, CommentIsUpFilter } from '../subFilters/white' +import { + CommentIsLinkFilter, + CommentIsMeFilter, + CommentIsNoteFilter, + CommentIsPinFilter, + CommentIsUpFilter, +} from '../subFilters/white' const GM_KEYS = { black: { @@ -145,6 +151,20 @@ const selectorFns = { } return false }, + // 自己发布 or @自己 的评论 + isMe: (comment: HTMLElement): SelectorResult => { + const me = (comment as any).__user?.uname + if (!me) { + return false + } + if ( + (comment as any).__data?.member?.uname === me || + (comment as any).__data?.content?.message?.includes(`@${me}`) + ) { + return true + } + return false + }, }, sub: { username: (comment: HTMLElement): SelectorResult => { @@ -193,6 +213,23 @@ const selectorFns = { } return false }, + // 自己发布 or @自己 的评论 + isMe: (comment: HTMLElement): SelectorResult => { + const me = (comment as any).__user?.uname + if (!me) { + return false + } + if ( + (comment as any).__data?.member?.uname === me || + (comment as any).__data?.content?.message + ?.trim() + ?.replace(/^回复\s?@[^@\s]+\s?:/, '') + .includes(`@${me}`) + ) { + return true + } + return false + }, }, } @@ -200,7 +237,7 @@ const selectorFns = { let isRootWhite = false let isSubWhite = false -class CommentFilterVideo implements IMainFilter { +class CommentFilterCommon implements IMainFilter { target: HTMLElement | undefined // 黑名单 @@ -218,6 +255,7 @@ class CommentFilterVideo implements IMainFilter { commentIsPinFilter = new CommentIsPinFilter() commentIsNoteFilter = new CommentIsNoteFilter() commentIsLinkFilter = new CommentIsLinkFilter() + commentIsMeFilter = new CommentIsMeFilter() init() { // 黑名单 @@ -271,7 +309,7 @@ class CommentFilterVideo implements IMainFilter { rootComments.forEach((v) => { debug( [ - `CommentFilterVideo rootComments`, + `CommentFilterCommon rootComments`, `username: ${selectorFns.root.username(v)}`, `content: ${selectorFns.root.content(v)}`, `callUser: ${selectorFns.root.callUser(v)}`, @@ -283,6 +321,7 @@ class CommentFilterVideo implements IMainFilter { `isPin: ${selectorFns.root.isPin(v)}`, `isNote: ${selectorFns.root.isNote(v)}`, `isLink: ${selectorFns.root.isLink(v)}`, + `isMe: ${selectorFns.root.isMe(v)}`, ].join('\n'), ) }) @@ -312,11 +351,12 @@ class CommentFilterVideo implements IMainFilter { this.commentIsPinFilter.isEnable && whitePairs.push([this.commentIsPinFilter, selectorFns.root.isPin]) this.commentIsNoteFilter.isEnable && whitePairs.push([this.commentIsNoteFilter, selectorFns.root.isNote]) this.commentIsLinkFilter.isEnable && whitePairs.push([this.commentIsLinkFilter, selectorFns.root.isLink]) + this.commentIsMeFilter.isEnable && whitePairs.push([this.commentIsMeFilter, selectorFns.root.isMe]) const rootBlackCnt = await coreCheck(rootComments, true, blackPairs, whitePairs) const time = (performance.now() - timer).toFixed(1) debug( - `CommentFilterVideo hide ${rootBlackCnt} in ${rootComments.length} root comments, mode=${mode}, time=${time}`, + `CommentFilterCommon hide ${rootBlackCnt} in ${rootComments.length} root comments, mode=${mode}, time=${time}`, ) } @@ -359,7 +399,7 @@ class CommentFilterVideo implements IMainFilter { subComments.forEach((v) => { debug( [ - `CommentFilterVideo subComments`, + `CommentFilterCommon subComments`, `username: ${selectorFns.sub.username(v)}`, `content: ${selectorFns.sub.content(v)}`, `callUser: ${selectorFns.sub.callUser(v)}`, @@ -367,6 +407,7 @@ class CommentFilterVideo implements IMainFilter { `level: ${selectorFns.sub.level(v)}`, `isUp: ${selectorFns.sub.isUp(v)}`, `isLink: ${selectorFns.sub.isLink(v)}`, + `isMe: ${selectorFns.sub.isMe(v)}`, ].join('\n'), ) }) @@ -390,11 +431,12 @@ class CommentFilterVideo implements IMainFilter { const whitePairs: SubFilterPair[] = [] this.commentIsUpFilter.isEnable && whitePairs.push([this.commentIsUpFilter, selectorFns.sub.isUp]) this.commentIsLinkFilter.isEnable && whitePairs.push([this.commentIsLinkFilter, selectorFns.sub.isLink]) + this.commentIsMeFilter.isEnable && whitePairs.push([this.commentIsMeFilter, selectorFns.sub.isMe]) const subBlackCnt = await coreCheck(subComments, false, blackPairs, whitePairs) const time = (performance.now() - timer).toFixed(1) debug( - `CommentFilterVideo hide ${subBlackCnt} in ${subComments.length} sub comments, mode=${mode}, time=${time}`, + `CommentFilterCommon hide ${subBlackCnt} in ${subComments.length} sub comments, mode=${mode}, time=${time}`, ) } @@ -402,12 +444,12 @@ class CommentFilterVideo implements IMainFilter { this.checkRoot(mode) .then() .catch((err) => { - error(`CommentFilterVideo checkRoot mode=${mode} error`, err) + error(`CommentFilterCommon checkRoot mode=${mode} error`, err) }) this.checkSub(mode) .then() .catch((err) => { - error(`CommentFilterVideo checkSub mode=${mode} error`, err) + error(`CommentFilterCommon checkSub mode=${mode} error`, err) }) } @@ -442,14 +484,15 @@ class CommentFilterVideo implements IMainFilter { //================================================================================================== -const mainFilter = new CommentFilterVideo() +const mainFilter = new CommentFilterCommon() -export const commentFilterVideoEntry = async () => { +export const commentFilterCommonEntry = async () => { mainFilter.init() + mainFilter.commentIsMeFilter.enable() mainFilter.observe() } -export const commentFilterVideoGroups: Group[] = [ +export const commentFilterCommonGroups: Group[] = [ { name: '评论用户过滤', items: [ @@ -772,8 +815,8 @@ export const commentFilterVideoGroups: Group[] = [ ] // 右键菜单handler -export const commentFilterVideoHandler: ContextMenuTargetHandler = (target: HTMLElement): FilterContextMenu[] => { - if (!(isPageVideo() || isPagePlaylist() || isPageBangumi())) { +export const commentFilterCommonHandler: ContextMenuTargetHandler = (target: HTMLElement): FilterContextMenu[] => { + if (!(isPageVideo() || isPagePlaylist() || isPageBangumi() || isPageDynamic())) { return [] } @@ -795,7 +838,7 @@ export const commentFilterVideoHandler: ContextMenuTargetHandler = (target: HTML arr.unshift(username) BiliCleanerStorage.set(GM_KEYS.black.username.valueKey, orderedUniq(arr)) } catch (err) { - error(`commentFilterVideoHandler add username ${username} failed`, err) + error(`commentFilterCommonHandler add username ${username} failed`, err) } }, }) diff --git a/src/modules/filters/variety/comment/pages/dynamic.ts b/src/modules/filters/variety/comment/pages/dynamic.ts deleted file mode 100644 index 94c0b92a..00000000 --- a/src/modules/filters/variety/comment/pages/dynamic.ts +++ /dev/null @@ -1,797 +0,0 @@ -import settings from '../../../../../settings' -import { Group } from '../../../../../types/collection' -import { - ContextMenuTargetHandler, - FilterContextMenu, - IMainFilter, - SelectorResult, - SubFilterPair, -} from '../../../../../types/filter' -import fetchHook from '../../../../../utils/fetch' -import { debugFilter as debug, error } from '../../../../../utils/logger' -import { isPageDynamic } from '../../../../../utils/pageType' -import ShadowInstance from '../../../../../utils/shadow' -import { BiliCleanerStorage } from '../../../../../utils/storage' -import { orderedUniq, showEle } from '../../../../../utils/tool' -import { coreCheck } from '../../../core/core' -import { bots } from '../extra/bots' -import { - CommentBotFilter, - CommentCallBotFilter, - CommentCallUserFilter, - CommentCallUserNoReplyFilter, - CommentCallUserOnlyFilter, - CommentCallUserOnlyNoReplyFilter, - CommentContentFilter, - CommentLevelFilter, - CommentUsernameFilter, -} from '../subFilters/black' -import { CommentIsLinkFilter, CommentIsNoteFilter, CommentIsPinFilter, CommentIsUpFilter } from '../subFilters/white' - -const GM_KEYS = { - black: { - username: { - statusKey: 'dynamic-comment-username-filter-status', - valueKey: 'global-comment-username-filter-value', - }, - content: { - statusKey: 'dynamic-comment-content-filter-status', - valueKey: 'global-comment-content-filter-value', - }, - level: { - statusKey: 'dynamic-comment-level-filter-status', - valueKey: 'global-comment-level-filter-value', - }, - bot: { - statusKey: 'dynamic-comment-bot-filter-status', - }, - callBot: { - statusKey: 'dynamic-comment-call-bot-filter-status', - }, - callUser: { - statusKey: 'dynamic-comment-call-user-filter-status', - }, - callUserNoReply: { - statusKey: 'dynamic-comment-call-user-noreply-filter-status', - }, - callUserOnly: { - statusKey: 'dynamic-comment-call-user-only-filter-status', - }, - callUserOnlyNoReply: { - statusKey: 'dynamic-comment-call-user-only-noreply-filter-status', - }, - isAD: { - statusKey: 'dynamic-comment-ad-filter-status', - }, - }, - white: { - root: { - statusKey: 'dynamic-comment-root-whitelist-status', - }, - sub: { - statusKey: 'dynamic-comment-sub-whitelist-status', - }, - isUp: { - statusKey: 'dynamic-comment-uploader-whitelist-status', - }, - isPin: { - statusKey: 'dynamic-comment-pinned-whitelist-status', - }, - isNote: { - statusKey: 'dynamic-comment-note-whitelist-status', - }, - isLink: { - statusKey: 'dynamic-comment-link-whitelist-status', - }, - }, -} - -// 一二级评论信息提取 -const selectorFns = { - root: { - username: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.member?.uname?.trim() - }, - content: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.content?.message?.replace(/@[^@\s]+/g, ' ').trim() - }, - callUser: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.content?.members[0]?.uname - }, - callUserNoReply: (comment: HTMLElement): SelectorResult => { - if ((comment as any).__data?.rcount !== 0) { - return undefined - } - return (comment as any).__data?.content?.members[0]?.uname - }, - callUserOnly: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.content?.message?.replace(/@[^@\s]+/g, ' ').trim() === '' - }, - callUserOnlyNoReply: (comment: HTMLElement): SelectorResult => { - if ((comment as any).__data?.rcount !== 0) { - return undefined - } - return (comment as any).__data?.content?.message?.replace(/@[^@\s]+/g, ' ').trim() === '' - }, - level: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.member?.level_info?.current_level - }, - isUp: (comment: HTMLElement): SelectorResult => { - const mid = (comment as any).__data?.mid - const upMid = (comment as any).__upMid - return typeof mid === 'number' && mid === upMid - }, - isPin: (comment: HTMLElement): SelectorResult => { - return !!(comment as any).__data?.reply_control?.is_up_top - }, - isNote: (comment: HTMLElement): SelectorResult => { - return !!(comment as any).__data?.reply_control?.is_note_v2 - }, - isLink: (comment: HTMLElement): SelectorResult => { - const jump_url = (comment as any).__data?.content?.jump_url - if (jump_url) { - for (const k of Object.keys(jump_url)) { - if (!jump_url[k]?.pc_url?.includes('search.bilibili.com')) { - return true - } - } - } - return false - }, - }, - sub: { - username: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.member?.uname?.trim() - }, - content: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.content?.message - ?.trim() - ?.replace(/^回复\s?@[^@\s]+\s?:/, '') - ?.replace(/@[^@\s]+/g, ' ') - .trim() - }, - callUser: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.content?.message - ?.trim() - ?.replace(/^回复\s?@[^@\s]+\s?:/, '') - ?.match(/@[^@\s]+/)?.[0] - .replace('@', '') - .trim() - }, - callUserOnly: (comment: HTMLElement): SelectorResult => { - return ( - (comment as any).__data?.content?.message - ?.trim() - ?.replace(/^回复\s?@[^@\s]+\s?:/, '') - ?.replace(/@[^@\s]+/g, ' ') - .trim() === '' - ) - }, - level: (comment: HTMLElement): SelectorResult => { - return (comment as any).__data?.member?.level_info?.current_level - }, - isUp: (comment: HTMLElement): SelectorResult => { - const mid = (comment as any).__data?.mid - const upMid = (comment as any).__upMid - return typeof mid === 'number' && mid === upMid - }, - isLink: (comment: HTMLElement): SelectorResult => { - const urls = (comment as any).__data?.content?.jump_url - if (urls) { - for (const k of Object.keys(urls)) { - if (!urls[k]?.pc_url?.includes('search.bilibili.com')) { - return true - } - } - } - return false - }, - }, -} -// 一二级评论是否检测 -let isRootWhite = false -let isSubWhite = false - -class CommentFilterDynamic implements IMainFilter { - target: HTMLElement | undefined - - // 黑名单 - commentUsernameFilter = new CommentUsernameFilter() - commentContentFilter = new CommentContentFilter() - commentLevelFilter = new CommentLevelFilter() - commentBotFilter = new CommentBotFilter() - commentCallBotFilter = new CommentCallBotFilter() - commentCallUserFilter = new CommentCallUserFilter() - commentCallUserNoReplyFilter = new CommentCallUserNoReplyFilter() - commentCallUserOnlyFilter = new CommentCallUserOnlyFilter() - commentCallUserOnlyNoReplyFilter = new CommentCallUserOnlyNoReplyFilter() - // 白名单 - commentIsUpFilter = new CommentIsUpFilter() - commentIsPinFilter = new CommentIsPinFilter() - commentIsNoteFilter = new CommentIsNoteFilter() - commentIsLinkFilter = new CommentIsLinkFilter() - - init() { - // 黑名单 - this.commentUsernameFilter.setParam(BiliCleanerStorage.get(GM_KEYS.black.username.valueKey, [])) - this.commentContentFilter.setParam(BiliCleanerStorage.get(GM_KEYS.black.content.valueKey, [])) - this.commentLevelFilter.setParam(BiliCleanerStorage.get(GM_KEYS.black.level.valueKey, 0)) - this.commentBotFilter.setParam(bots) - this.commentCallBotFilter.setParam(bots) - this.commentCallUserFilter.setParam([`/./`]) - this.commentCallUserNoReplyFilter.setParam([`/./`]) - } - - /** - * 检测一级评论 - * @param mode full全量,incr增量 - * @returns - */ - async checkRoot(mode?: 'full' | 'incr') { - const timer = performance.now() - let revertAll = false - if ( - !( - this.commentUsernameFilter.isEnable || - this.commentContentFilter.isEnable || - this.commentLevelFilter.isEnable || - this.commentBotFilter.isEnable || - this.commentCallBotFilter.isEnable || - this.commentCallUserFilter.isEnable || - this.commentCallUserNoReplyFilter.isEnable || - this.commentCallUserOnlyFilter.isEnable || - this.commentCallUserOnlyNoReplyFilter.isEnable - ) - ) { - revertAll = true - } - - let rootComments: HTMLElement[] = [] - if (ShadowInstance.shadowStore.has('BILI-COMMENT-THREAD-RENDERER')) { - rootComments = Array.from(ShadowInstance.shadowStore.get('BILI-COMMENT-THREAD-RENDERER')!).map( - (v) => v.host as HTMLElement, - ) - if (mode === 'incr') { - rootComments = rootComments.filter((v) => !v.hasAttribute(settings.filterSign)) - } - } - if (!rootComments.length) { - return - } - - if (settings.enableDebugFilter) { - rootComments.forEach((v) => { - debug( - [ - `CommentFilterDynamic rootComments`, - `username: ${selectorFns.root.username(v)}`, - `content: ${selectorFns.root.content(v)}`, - `callUser: ${selectorFns.root.callUser(v)}`, - `callUserNoReply: ${selectorFns.root.callUserNoReply(v)}`, - `callUserOnly: ${selectorFns.root.callUserOnly(v)}`, - `callUserOnlyNoReply: ${selectorFns.root.callUserOnlyNoReply(v)}`, - `level: ${selectorFns.root.level(v)}`, - `isUp: ${selectorFns.root.isUp(v)}`, - `isPin: ${selectorFns.root.isPin(v)}`, - `isNote: ${selectorFns.root.isNote(v)}`, - `isLink: ${selectorFns.root.isLink(v)}`, - ].join('\n'), - ) - }) - } - - if (isRootWhite || revertAll) { - rootComments.forEach((el) => showEle(el)) - return - } - - const blackPairs: SubFilterPair[] = [] - this.commentUsernameFilter.isEnable && blackPairs.push([this.commentUsernameFilter, selectorFns.root.username]) - this.commentContentFilter.isEnable && blackPairs.push([this.commentContentFilter, selectorFns.root.content]) - this.commentLevelFilter.isEnable && blackPairs.push([this.commentLevelFilter, selectorFns.root.level]) - this.commentBotFilter.isEnable && blackPairs.push([this.commentBotFilter, selectorFns.root.username]) - this.commentCallBotFilter.isEnable && blackPairs.push([this.commentCallBotFilter, selectorFns.root.callUser]) - this.commentCallUserFilter.isEnable && blackPairs.push([this.commentCallUserFilter, selectorFns.root.callUser]) - this.commentCallUserNoReplyFilter.isEnable && - blackPairs.push([this.commentCallUserNoReplyFilter, selectorFns.root.callUserNoReply]) - this.commentCallUserOnlyFilter.isEnable && - blackPairs.push([this.commentCallUserOnlyFilter, selectorFns.root.callUserOnly]) - this.commentCallUserOnlyNoReplyFilter.isEnable && - blackPairs.push([this.commentCallUserOnlyNoReplyFilter, selectorFns.root.callUserOnlyNoReply]) - - const whitePairs: SubFilterPair[] = [] - this.commentIsUpFilter.isEnable && whitePairs.push([this.commentIsUpFilter, selectorFns.root.isUp]) - this.commentIsPinFilter.isEnable && whitePairs.push([this.commentIsPinFilter, selectorFns.root.isPin]) - this.commentIsNoteFilter.isEnable && whitePairs.push([this.commentIsNoteFilter, selectorFns.root.isNote]) - this.commentIsLinkFilter.isEnable && whitePairs.push([this.commentIsLinkFilter, selectorFns.root.isLink]) - - const rootBlackCnt = await coreCheck(rootComments, true, blackPairs, whitePairs) - const time = (performance.now() - timer).toFixed(1) - debug( - `CommentFilterDynamic hide ${rootBlackCnt} in ${rootComments.length} root comments, mode=${mode}, time=${time}`, - ) - } - - /** - * 检测二级评论 - * @param mode full全量,incr增量 - * @returns - */ - async checkSub(mode?: 'full' | 'incr') { - const timer = performance.now() - let revertAll = false - if ( - !( - this.commentUsernameFilter.isEnable || - this.commentContentFilter.isEnable || - this.commentLevelFilter.isEnable || - this.commentBotFilter.isEnable || - this.commentCallBotFilter.isEnable || - this.commentCallUserFilter.isEnable || - this.commentCallUserOnlyFilter.isEnable - ) - ) { - revertAll = true - } - - let subComments: HTMLElement[] = [] - if (ShadowInstance.shadowStore.has('BILI-COMMENT-REPLY-RENDERER')) { - subComments = Array.from(ShadowInstance.shadowStore.get('BILI-COMMENT-REPLY-RENDERER')!).map( - (v) => v.host as HTMLElement, - ) - if (mode === 'incr') { - subComments = subComments.filter((v) => !v.hasAttribute(settings.filterSign)) - } - } - if (!subComments.length) { - return - } - - if (settings.enableDebugFilter) { - subComments.forEach((v) => { - debug( - [ - `CommentFilterDynamic subComments`, - `username: ${selectorFns.sub.username(v)}`, - `content: ${selectorFns.sub.content(v)}`, - `callUser: ${selectorFns.sub.callUser(v)}`, - `callUserOnly: ${selectorFns.sub.callUserOnly(v)}`, - `level: ${selectorFns.sub.level(v)}`, - `isUp: ${selectorFns.sub.isUp(v)}`, - `isLink: ${selectorFns.sub.isLink(v)}`, - ].join('\n'), - ) - }) - } - - if (isSubWhite || revertAll) { - subComments.forEach((el) => showEle(el)) - return - } - - const blackPairs: SubFilterPair[] = [] - this.commentUsernameFilter.isEnable && blackPairs.push([this.commentUsernameFilter, selectorFns.sub.username]) - this.commentContentFilter.isEnable && blackPairs.push([this.commentContentFilter, selectorFns.sub.content]) - this.commentLevelFilter.isEnable && blackPairs.push([this.commentLevelFilter, selectorFns.sub.level]) - this.commentBotFilter.isEnable && blackPairs.push([this.commentBotFilter, selectorFns.sub.username]) - this.commentCallBotFilter.isEnable && blackPairs.push([this.commentCallBotFilter, selectorFns.sub.callUser]) - this.commentCallUserFilter.isEnable && blackPairs.push([this.commentCallUserFilter, selectorFns.sub.callUser]) - this.commentCallUserOnlyFilter.isEnable && - blackPairs.push([this.commentCallUserOnlyFilter, selectorFns.sub.callUserOnly]) - - const whitePairs: SubFilterPair[] = [] - this.commentIsUpFilter.isEnable && whitePairs.push([this.commentIsUpFilter, selectorFns.sub.isUp]) - this.commentIsLinkFilter.isEnable && whitePairs.push([this.commentIsLinkFilter, selectorFns.sub.isLink]) - - const subBlackCnt = await coreCheck(subComments, false, blackPairs, whitePairs) - const time = (performance.now() - timer).toFixed(1) - debug( - `CommentFilterDynamic hide ${subBlackCnt} in ${subComments.length} sub comments, mode=${mode}, time=${time}`, - ) - } - - check(mode?: 'full' | 'incr') { - this.checkRoot(mode) - .then() - .catch((err) => { - error('checkRoot failed', err) - }) - this.checkSub(mode) - .then() - .catch((err) => { - error('checkSub failed', err) - }) - } - - /** - * 监听一级/二级评论container - * 使用同一Observer监视所有二级评论上级节点,所有变化只触发一次回调 - */ - observe() { - ShadowInstance.addShadowObserver( - 'BILI-COMMENTS', - new MutationObserver(() => { - this.checkRoot('incr').then().catch() - }), - { - subtree: true, - childList: true, - }, - ) - - ShadowInstance.addShadowObserver( - 'BILI-COMMENT-REPLIES-RENDERER', - new MutationObserver(() => { - this.checkSub('full').then().catch() - }), - { - subtree: true, - childList: true, - }, - ) - } -} - -//================================================================================================== - -const mainFilter = new CommentFilterDynamic() - -export const commentFilterDynamicEntry = async () => { - mainFilter.init() - mainFilter.observe() -} - -export const commentFilterDynamicGroups: Group[] = [ - { - name: '评论用户过滤', - items: [ - { - type: 'switch', - id: GM_KEYS.black.username.statusKey, - name: '启用 评论用户过滤 (右键单击用户名)', - noStyle: true, - enableFn: () => { - mainFilter.commentUsernameFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentUsernameFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'editor', - id: GM_KEYS.black.username.valueKey, - name: '编辑 评论用户黑名单', - description: ['本黑名单与UP主黑名单互不影响', '右键屏蔽的用户会出现在首行'], - editorTitle: '评论区 用户黑名单', - editorDescription: ['每行一个用户名,保存时自动去重'], - saveFn: async () => { - mainFilter.commentUsernameFilter.setParam( - BiliCleanerStorage.get(GM_KEYS.black.username.valueKey, []), - ) - mainFilter.check('full') - }, - }, - ], - }, - { - name: '评论内容过滤', - items: [ - { - type: 'switch', - id: GM_KEYS.black.content.statusKey, - name: '启用 评论关键词过滤', - noStyle: true, - enableFn: () => { - mainFilter.commentContentFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentContentFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'editor', - id: GM_KEYS.black.content.valueKey, - name: '编辑 评论关键词黑名单', - editorTitle: '评论关键词 黑名单', - editorDescription: [ - '每行一个关键词或正则,不区分大小写', - '请勿使用过于激进的关键词或正则', - '正则默认 iu 模式,无需 flag,语法:/abc|\\d+/', - ], - saveFn: async () => { - mainFilter.commentContentFilter.setParam(BiliCleanerStorage.get(GM_KEYS.black.content.valueKey, [])) - mainFilter.check('full') - }, - }, - ], - }, - { - name: '按类型过滤', - items: [ - { - type: 'switch', - id: GM_KEYS.black.callBot.statusKey, - name: '过滤 召唤AI的评论', - noStyle: true, - enableFn: () => { - mainFilter.commentCallBotFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentCallBotFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.black.bot.statusKey, - name: '过滤 AI发布的评论', - noStyle: true, - enableFn: () => { - mainFilter.commentBotFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentBotFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.black.isAD.statusKey, - name: '过滤 带货评论 (实验功能)', - noStyle: true, - enableFn: () => { - fetchHook.addPostFn( - async ( - input: RequestInfo | URL, - init: RequestInit | undefined, - resp?: Response, - ): Promise => { - if (!resp) { - return - } - if ( - typeof input === 'string' && - init?.method?.toUpperCase() === 'GET' && - input.includes('api.bilibili.com/x/v2/reply/wbi/main') - ) { - try { - const respData = await resp.clone().json() - const msg = respData?.data?.top?.upper?.content?.message - if (msg && /b23\.tv\/mall-|领券|gaoneng\.bilibili\.com/.test(msg)) { - respData.data.top = null - respData.data.top_replies = null - return new Response(JSON.stringify(respData), { - status: resp.status, - statusText: resp.statusText, - headers: resp.headers, - }) - } - } catch { - return resp - } - return resp - } - }, - ) - }, - }, - { - type: 'switch', - id: GM_KEYS.black.callUserOnly.statusKey, - name: '过滤 只含 @其他用户 的全部评论', - noStyle: true, - enableFn: () => { - mainFilter.commentCallUserOnlyFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentCallUserOnlyFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.black.callUserOnlyNoReply.statusKey, - name: '过滤 只含 @其他用户 的无回复评论', - noStyle: true, - enableFn: () => { - mainFilter.commentCallUserOnlyNoReplyFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentCallUserOnlyNoReplyFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.black.callUser.statusKey, - name: '过滤 包含 @其他用户 的全部评论', - noStyle: true, - enableFn: () => { - mainFilter.commentCallUserFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentCallUserFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.black.callUserNoReply.statusKey, - name: '过滤 包含 @其他用户 的无回复评论', - noStyle: true, - enableFn: () => { - mainFilter.commentCallUserNoReplyFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentCallUserNoReplyFilter.disable() - mainFilter.check('full') - }, - }, - ], - }, - { - name: '等级过滤', - items: [ - { - type: 'switch', - id: GM_KEYS.black.level.statusKey, - name: '启用 用户等级过滤', - noStyle: true, - enableFn: () => { - mainFilter.commentLevelFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentLevelFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'number', - id: GM_KEYS.black.level.valueKey, - name: '设定最低等级 (0~6)', - minValue: 0, - maxValue: 6, - step: 1, - defaultValue: 0, - disableValue: 0, - fn: (value: number) => { - mainFilter.commentLevelFilter.setParam(value) - mainFilter.check('full') - }, - }, - ], - }, - { - name: '白名单 免过滤', - items: [ - { - type: 'switch', - id: GM_KEYS.white.root.statusKey, - name: '一级评论(主评论) 免过滤', - noStyle: true, - enableFn: () => { - isRootWhite = true - mainFilter.check('full') - }, - disableFn: () => { - isRootWhite = false - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.white.sub.statusKey, - name: '二级评论(回复) 免过滤', - noStyle: true, - enableFn: () => { - isSubWhite = true - mainFilter.check('full') - }, - disableFn: () => { - isSubWhite = false - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.white.isUp.statusKey, - name: 'UP主的评论 免过滤', - noStyle: true, - enableFn: () => { - mainFilter.commentIsUpFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentIsUpFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.white.isPin.statusKey, - name: '置顶评论 免过滤', - noStyle: true, - enableFn: () => { - mainFilter.commentIsPinFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentIsPinFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.white.isNote.statusKey, - name: '笔记/图片评论 免过滤', - noStyle: true, - enableFn: () => { - mainFilter.commentIsNoteFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentIsNoteFilter.disable() - mainFilter.check('full') - }, - }, - { - type: 'switch', - id: GM_KEYS.white.isLink.statusKey, - name: '含超链接的评论 免过滤', - noStyle: true, - enableFn: () => { - mainFilter.commentIsLinkFilter.enable() - mainFilter.check('full') - }, - disableFn: () => { - mainFilter.commentIsLinkFilter.disable() - mainFilter.check('full') - }, - }, - ], - }, -] - -// 右键菜单handler -export const commentFilterDynamicHandler: ContextMenuTargetHandler = (target: HTMLElement): FilterContextMenu[] => { - if (!isPageDynamic()) { - return [] - } - - const menus: FilterContextMenu[] = [] - if ( - target.parentElement?.id === 'user-name' || - target.classList.contains('user-name') || - target.classList.contains('sub-user-name') - ) { - const username = target.textContent?.trim() - if (username && mainFilter.commentUsernameFilter.isEnable) { - menus.push({ - name: `屏蔽用户:${username}`, - fn: async () => { - try { - mainFilter.commentUsernameFilter.addParam(username) - mainFilter.check('full') - const arr: string[] = BiliCleanerStorage.get(GM_KEYS.black.username.valueKey, []) - arr.unshift(username) - BiliCleanerStorage.set(GM_KEYS.black.username.valueKey, orderedUniq(arr)) - } catch (err) { - error(`commentFilterDynamicHandler add username ${username} failed`, err) - } - }, - }) - } - } - return menus -} diff --git a/src/modules/filters/variety/comment/subFilters/white.ts b/src/modules/filters/variety/comment/subFilters/white.ts index 90d67416..8df95215 100644 --- a/src/modules/filters/variety/comment/subFilters/white.ts +++ b/src/modules/filters/variety/comment/subFilters/white.ts @@ -7,3 +7,5 @@ export class CommentIsPinFilter extends BooleanFilter {} export class CommentIsNoteFilter extends BooleanFilter {} export class CommentIsLinkFilter extends BooleanFilter {} + +export class CommentIsMeFilter extends BooleanFilter {} diff --git a/vite.config.ts b/vite.config.ts index b5875e7e..94553e64 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ userscript: { name: 'bilibili 页面净化大师', namespace: 'http://tampermonkey.net/', - version: '4.0.10', + version: '4.0.11', description: '净化 B站/哔哩哔哩 页面,支持「精简功能、播放器净化、过滤视频、过滤评论、全站黑白名单」,提供 300+ 功能,定制自己的 B 站', author: 'festoney8', From 9f3992d6664ca425b718cea293645c4d3ae931f9 Mon Sep 17 00:00:00 2001 From: festoney8 Date: Wed, 20 Nov 2024 12:20:57 +0800 Subject: [PATCH 2/4] update: unify comment filter setting --- CHANGELOG.md | 4 +- src/modules/filters/index.ts | 14 ++--- .../comment/pages/{space.ts => legacy.ts} | 52 +++++++++---------- src/views/CommentFilterPanelView.vue | 2 +- 4 files changed, 36 insertions(+), 36 deletions(-) rename src/modules/filters/variety/comment/pages/{space.ts => legacy.ts} (93%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f5ea0d..09ed69fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ## 4.0.11 -- 更新:评论过滤 统一全站设定,不再按页面分类 -- 更新:评论过滤 排除自己的评论和@自己的评论 +- 更新:评论过滤 开关设定对全站通用 +- 修复:评论过滤 排除自己的评论和@自己的评论 ## 4.0.10 diff --git a/src/modules/filters/index.ts b/src/modules/filters/index.ts index b24145a4..7216bb21 100644 --- a/src/modules/filters/index.ts +++ b/src/modules/filters/index.ts @@ -19,10 +19,10 @@ import { commentFilterCommonHandler, } from './variety/comment/pages/common' import { - commentFilterSpaceEntry, - commentFilterSpaceGroups, - commentFilterSpaceHandler, -} from './variety/comment/pages/space' + commentFilterLegacyEntry, + commentFilterLegacyGroups, + commentFilterLegacyHandler, +} from './variety/comment/pages/legacy' import { dynamicFilterDynamicEntry, dynamicFilterDynamicGroups, @@ -98,8 +98,8 @@ export const commentFilters: Filter[] = [ }, { name: '空间页 动态评论过滤', - groups: commentFilterSpaceGroups, - entry: commentFilterSpaceEntry, + groups: commentFilterLegacyGroups, + entry: commentFilterLegacyEntry, checkFn: () => isPageSpace(), }, ] @@ -171,5 +171,5 @@ export const filterContextMenuHandlers = [ videoFilterHomepageHandler, dynamicFilterDynamicHandler, commentFilterCommonHandler, - commentFilterSpaceHandler, + commentFilterLegacyHandler, ] diff --git a/src/modules/filters/variety/comment/pages/space.ts b/src/modules/filters/variety/comment/pages/legacy.ts similarity index 93% rename from src/modules/filters/variety/comment/pages/space.ts rename to src/modules/filters/variety/comment/pages/legacy.ts index 95c5c6ac..7b48ef42 100644 --- a/src/modules/filters/variety/comment/pages/space.ts +++ b/src/modules/filters/variety/comment/pages/legacy.ts @@ -28,51 +28,51 @@ import { CommentIsLinkFilter, CommentIsNoteFilter, CommentIsPinFilter, CommentIs const GM_KEYS = { black: { username: { - statusKey: 'dynamic-comment-username-filter-status', + statusKey: 'video-comment-username-filter-status', valueKey: 'global-comment-username-filter-value', }, content: { - statusKey: 'dynamic-comment-content-filter-status', + statusKey: 'video-comment-content-filter-status', valueKey: 'global-comment-content-filter-value', }, level: { - statusKey: 'dynamic-comment-level-filter-status', + statusKey: 'video-comment-level-filter-status', valueKey: 'global-comment-level-filter-value', }, bot: { - statusKey: 'dynamic-comment-bot-filter-status', + statusKey: 'video-comment-bot-filter-status', }, callBot: { - statusKey: 'dynamic-comment-call-bot-filter-status', + statusKey: 'video-comment-call-bot-filter-status', }, callUser: { - statusKey: 'dynamic-comment-call-user-filter-status', + statusKey: 'video-comment-call-user-filter-status', }, callUserOnly: { - statusKey: 'dynamic-comment-call-user-only-filter-status', + statusKey: 'video-comment-call-user-only-filter-status', }, isAD: { - statusKey: 'dynamic-comment-ad-filter-status', + statusKey: 'video-comment-ad-filter-status', }, }, white: { root: { - statusKey: 'dynamic-comment-root-whitelist-status', + statusKey: 'video-comment-root-whitelist-status', }, sub: { - statusKey: 'dynamic-comment-sub-whitelist-status', + statusKey: 'video-comment-sub-whitelist-status', }, isUp: { - statusKey: 'dynamic-comment-uploader-whitelist-status', + statusKey: 'video-comment-uploader-whitelist-status', }, isPin: { - statusKey: 'dynamic-comment-pinned-whitelist-status', + statusKey: 'video-comment-pinned-whitelist-status', }, isNote: { - statusKey: 'dynamic-comment-note-whitelist-status', + statusKey: 'video-comment-note-whitelist-status', }, isLink: { - statusKey: 'dynamic-comment-link-whitelist-status', + statusKey: 'video-comment-link-whitelist-status', }, }, } @@ -170,7 +170,7 @@ const selectorFns = { let isRootWhite = false let isSubWhite = false -class CommentFilterSpace implements IMainFilter { +class CommentFilterLegacy implements IMainFilter { target: HTMLElement | undefined // 黑名单 @@ -231,7 +231,7 @@ class CommentFilterSpace implements IMainFilter { rootComments.forEach((v) => { debug( [ - `CommentFilterSpace rootComments`, + `CommentFilterLegacy rootComments`, `username: ${selectorFns.root.username(v)}`, `content: ${selectorFns.root.content(v)}`, `callUser: ${selectorFns.root.callUser(v)}`, @@ -247,7 +247,7 @@ class CommentFilterSpace implements IMainFilter { subComments.forEach((v) => { debug( [ - `CommentFilterSpace subComments`, + `CommentFilterLegacy subComments`, `username: ${selectorFns.sub.username(v)}`, `content: ${selectorFns.sub.content(v)}`, `callUser: ${selectorFns.sub.callUser(v)}`, @@ -320,7 +320,7 @@ class CommentFilterSpace implements IMainFilter { const time = (performance.now() - timer).toFixed(1) debug( - `CommentFilterSpace hide ${rootBlackCnt} in ${rootComments.length} root, ${subBlackCnt} in ${subComments.length} sub, mode=${mode}, time=${time}`, + `CommentFilterLegacy hide ${rootBlackCnt} in ${rootComments.length} root, ${subBlackCnt} in ${subComments.length} sub, mode=${mode}, time=${time}`, ) } @@ -328,7 +328,7 @@ class CommentFilterSpace implements IMainFilter { this.check('full') .then() .catch((err) => { - error('CommentFilterSpace check full error', err) + error('CommentFilterLegacy check full error', err) }) } @@ -336,7 +336,7 @@ class CommentFilterSpace implements IMainFilter { this.check('incr') .then() .catch((err) => { - error('CommentFilterSpace check incr error', err) + error('CommentFilterLegacy check incr error', err) }) } @@ -345,7 +345,7 @@ class CommentFilterSpace implements IMainFilter { return node.id === 'app' }).then((ele) => { if (ele) { - debug('CommentFilterSpace target appear') + debug('CommentFilterLegacy target appear') this.target = ele this.checkFull() const commentObserver = new MutationObserver(() => { @@ -358,14 +358,14 @@ class CommentFilterSpace implements IMainFilter { } //================================================================================================== -const mainFilter = new CommentFilterSpace() +const mainFilter = new CommentFilterLegacy() -export const commentFilterSpaceEntry = async () => { +export const commentFilterLegacyEntry = async () => { mainFilter.init() mainFilter.observe() } -export const commentFilterSpaceGroups: Group[] = [ +export const commentFilterLegacyGroups: Group[] = [ { name: '评论用户过滤', items: [ @@ -660,7 +660,7 @@ export const commentFilterSpaceGroups: Group[] = [ ] // 右键菜单handler -export const commentFilterSpaceHandler: ContextMenuTargetHandler = (target: HTMLElement): FilterContextMenu[] => { +export const commentFilterLegacyHandler: ContextMenuTargetHandler = (target: HTMLElement): FilterContextMenu[] => { if (!isPageSpace()) { return [] } @@ -683,7 +683,7 @@ export const commentFilterSpaceHandler: ContextMenuTargetHandler = (target: HTML arr.unshift(username) BiliCleanerStorage.set(GM_KEYS.black.username.valueKey, orderedUniq(arr)) } catch (err) { - error(`commentFilterSpaceHandler add username ${username} failed`, err) + error(`commentFilterLegacyHandler add username ${username} failed`, err) } }, }) diff --git a/src/views/CommentFilterPanelView.vue b/src/views/CommentFilterPanelView.vue index 6ec2df0c..3d0b0525 100644 --- a/src/views/CommentFilterPanelView.vue +++ b/src/views/CommentFilterPanelView.vue @@ -1,7 +1,7 @@