Skip to content

Commit

Permalink
Merge pull request #52 from festoney8/dev
Browse files Browse the repository at this point in the history
merge dev to main, v3.3.0
  • Loading branch information
festoney8 authored Mar 27, 2024
2 parents e9842f4 + 6df9d27 commit b81493f
Show file tree
Hide file tree
Showing 19 changed files with 471 additions and 159 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# CHANGELOG

## 3.3.0

- 新增:UP主昵称关键词过滤(首页、热门页、播放页、频道页、搜索页)
- 新增:UP主昵称关键词黑名单
- 新增:播放页隐藏接下来播放
- 更新:净化分享适配新版标题
- 优化:一些页面净化功能细节
- 优化:对播放列表页的支持
- 修复:一些bug

## 3.2.1

- 新增:播放页隐藏UP主头像icon
Expand Down
6 changes: 1 addition & 5 deletions src/components/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ type Menu = {
name: string
onclick: () => void
}
class ContextMenu {
export class ContextMenu {
private nodeHTML = `
<div id="bili-cleaner-context-menu-container">
<ul>
Expand Down Expand Up @@ -108,7 +108,3 @@ class ContextMenu {
this.isShowing = false
}
}

// 单例
const contextMenuInstance = new ContextMenu()
export default contextMenuInstance
14 changes: 14 additions & 0 deletions src/components/wordlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,20 @@ export class WordList {
const diffY = e.clientY - initY
wordlist.style.left = `${initLeft + diffX}px`
wordlist.style.top = `${initTop + diffY}px`
// 限制bar不超出视口
const rect = bar.getBoundingClientRect()
if (rect.left < 0) {
wordlist.style.left = `${initLeft + diffX - rect.left}px`
}
if (rect.top < 0) {
wordlist.style.top = `${initTop + diffY - rect.top}px`
}
if (rect.right > window.innerWidth) {
wordlist.style.left = `${initLeft + diffX - (rect.right - window.innerWidth)}px`
}
if (rect.bottom > window.innerHeight) {
wordlist.style.top = `${initTop + diffY - (rect.bottom - window.innerHeight)}px`
}
}
})
document.addEventListener('mouseup', () => {
Expand Down
19 changes: 12 additions & 7 deletions src/filters/commentFilter/pages/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { GM_getValue } from '$'
import { Group } from '../../../components/group'
import { CheckboxItem, ButtonItem } from '../../../components/item'
import { debugCommentFilter as debug, error } from '../../../utils/logger'
import { isPageBangumi, isPageVideo } from '../../../utils/page-type'
import { isPageBangumi, isPagePlaylist, isPageVideo } from '../../../utils/page-type'
import { showEle, waitForEle } from '../../../utils/tool'
import { ContentAction, UsernameAction } from './actions/action'
import contextMenuInstance from '../../../components/contextmenu'
import coreCommentFilterInstance, { CommentSelectorFunc } from '../filters/core'
import settings from '../../../settings'
import { ContextMenu } from '../../../components/contextmenu'

const videoPageCommentFilterGroupList: Group[] = []

Expand All @@ -23,7 +23,7 @@ let isPinnedCommentWhitelistEnable: boolean = GM_getValue('BILICLEANER_video-com
let isNoteCommentWhitelistEnable: boolean = GM_getValue('BILICLEANER_video-comment-note-whitelist-status', true)
let isLinkCommentWhitelistEnable: boolean = GM_getValue('BILICLEANER_video-comment-link-whitelist-status', true)

if (isPageVideo() || isPageBangumi()) {
if (isPageVideo() || isPageBangumi() || isPagePlaylist()) {
let commentListContainer: HTMLElement
// 一级评论
const rootCommentSelectorFunc: CommentSelectorFunc = {
Expand Down Expand Up @@ -177,7 +177,9 @@ if (isPageVideo() || isPageBangumi()) {
return
}
isContextMenuFuncRunning = true
const menu = new ContextMenu()
document.addEventListener('contextmenu', (e) => {
menu.hide()
if (e.target instanceof HTMLElement) {
const target = e.target
if (
Expand All @@ -188,19 +190,22 @@ if (isPageVideo() || isPageBangumi()) {
const username = target.textContent?.trim()
if (username) {
e.preventDefault()
contextMenuInstance.registerMenu(`屏蔽用户:${username}`, () => {
menu.registerMenu(`屏蔽用户:${username}`, () => {
usernameAction.add(username)
})
contextMenuInstance.show(e.clientX, e.clientY)
menu.show(e.clientX, e.clientY)
}
} else {
contextMenuInstance.hide()
menu.hide()
}
}
})
// 关闭右键菜单
document.addEventListener('click', () => {
contextMenuInstance.hide()
menu.hide()
})
document.addEventListener('wheel', () => {
menu.hide()
})
debug('contextMenuFunc listen contextmenu')
}
Expand Down
21 changes: 21 additions & 0 deletions src/filters/videoFilter/agency/agency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import durationFilterInstance from '../filters/subfilters/duration'
import titleKeywordFilterInstance from '../filters/subfilters/titleKeyword'
import titleKeywordWhitelistFilterInstance from '../filters/subfilters/titleKeywordWhitelist'
import uploaderFilterInstance from '../filters/subfilters/uploader'
import uploaderKeywordFilterInstance from '../filters/subfilters/uploaderKeyword'
import uploaderWhitelistFilterInstance from '../filters/subfilters/uploaderWhitelist'

// 代理, 接收页面操作通知, 更新子过滤器的参数
Expand Down Expand Up @@ -86,6 +87,26 @@ class VideoFilterAgency {
break
}
}
notifyUploaderKeyword(event: string, value?: string | string[]) {
switch (event) {
case 'disable':
uploaderKeywordFilterInstance.setStatus(false)
break
case 'enable':
uploaderKeywordFilterInstance.setStatus(true)
break
case 'add':
if (typeof value === 'string' && value.trim()) {
uploaderKeywordFilterInstance.addParam(value.trim())
}
break
case 'edit':
if (Array.isArray(value)) {
uploaderKeywordFilterInstance.setParams(value.map((v) => v.trim()).filter((v) => v))
}
break
}
}
notifyUploaderWhitelist(event: string, value?: string | string[]) {
switch (event) {
case 'disable':
Expand Down
9 changes: 9 additions & 0 deletions src/filters/videoFilter/filters/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import durationFilterInstance from './subfilters/duration'
import titleKeywordFilterInstance from './subfilters/titleKeyword'
import titleKeywordWhitelistFilterInstance from './subfilters/titleKeywordWhitelist'
import uploaderFilterInstance from './subfilters/uploader'
import uploaderKeywordFilterInstance from './subfilters/uploaderKeyword'
import uploaderWhitelistFilterInstance from './subfilters/uploaderWhitelist'

// 子过滤器实现IVideoSubFilter,包括白名单
Expand Down Expand Up @@ -45,6 +46,7 @@ class CoreVideoFilter {
const checkDuration = durationFilterInstance.isEnable && selectorFunc.duration !== undefined
const checkTitleKeyword = titleKeywordFilterInstance.isEnable && selectorFunc.titleKeyword !== undefined
const checkUploader = uploaderFilterInstance.isEnable && selectorFunc.uploader !== undefined
const checkUploaderKeyword = uploaderKeywordFilterInstance.isEnable && selectorFunc.uploader !== undefined
const checkBvid = bvidFilterInstance.isEnable && selectorFunc.bvid !== undefined
const checkUploaderWhitelist =
uploaderWhitelistFilterInstance.isEnable && selectorFunc.uploader !== undefined
Expand Down Expand Up @@ -84,6 +86,13 @@ class CoreVideoFilter {
info.uploader = uploader
}
}
if (checkUploaderKeyword) {
const uploader = selectorFunc.uploader!(video)?.trim()
if (uploader) {
blackTasks.push(uploaderKeywordFilterInstance.check(uploader))
info.uploader = uploader
}
}
if (checkTitleKeyword) {
const title = selectorFunc.titleKeyword!(video)?.trim()
if (title) {
Expand Down
2 changes: 1 addition & 1 deletion src/filters/videoFilter/filters/subfilters/titleKeyword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class TitleKeywordFilter implements IVideoSubFilter {
// 关键词为正则表达式(反斜杠使用单斜杠),大小写不敏感,支持unicodeSets
const pattern = new RegExp(word.slice(1, -1), 'iv')
if (title.match(pattern)) {
// 命中白名单正则
// 命中黑名单正则
flag = true
reject(`TitleKeyword reject, ${title} match ${word} in blacklist`)
}
Expand Down
60 changes: 60 additions & 0 deletions src/filters/videoFilter/filters/subfilters/uploaderKeyword.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { error } from '../../../../utils/logger'
import { IVideoSubFilter } from '../core'

class UploaderKeywordFilter implements IVideoSubFilter {
isEnable = false
private uploaderKeywordSet = new Set<string>()

setStatus(status: boolean) {
this.isEnable = status
}

setParams(values: string[]) {
this.uploaderKeywordSet = new Set(values.map((v) => v.trim()).filter((v) => v))
}

addParam(value: string) {
if (value.trim()) {
this.uploaderKeywordSet.add(value.trim())
}
}

check(uploader: string): Promise<string> {
// 忽略大小写
uploader = uploader.trim().toLowerCase()
return new Promise<string>((resolve, reject) => {
try {
if (!this.isEnable || uploader.length === 0 || this.uploaderKeywordSet.size === 0) {
resolve(`UploaderKeyword resolve, disable or empty`)
}
let flag = false
this.uploaderKeywordSet.forEach((word) => {
if (word.startsWith('/') && word.endsWith('/')) {
// 关键词为正则表达式(反斜杠使用单斜杠),大小写不敏感
const pattern = new RegExp(word.slice(1, -1), 'iv')
if (uploader.match(pattern)) {
// 命中黑名单正则
flag = true
reject(`UploaderKeyword reject, ${uploader} match ${word} in blacklist`)
}
} else {
if (word && uploader.includes(word.toLowerCase())) {
flag = true
reject(`UploaderKeyword reject, ${uploader} match ${word} in blacklist`)
}
}
})
if (!flag) {
resolve(`UploaderKeyword resolve, uploader not match blacklist`)
}
} catch (err) {
error(err)
resolve(`UploaderKeyword resolve, error`)
}
})
}
}

// 单例
const uploaderKeywordFilterInstance = new UploaderKeywordFilter()
export default uploaderKeywordFilterInstance
58 changes: 58 additions & 0 deletions src/filters/videoFilter/pages/actions/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import durationFilterInstance from '../../filters/subfilters/duration'
import titleKeywordFilterInstance from '../../filters/subfilters/titleKeyword'
import titleKeywordWhitelistFilterInstance from '../../filters/subfilters/titleKeywordWhitelist'
import uploaderFilterInstance from '../../filters/subfilters/uploader'
import uploaderKeywordFilterInstance from '../../filters/subfilters/uploaderKeyword'
import uploaderWhitelistFilterInstance from '../../filters/subfilters/uploaderWhitelist'

// 定义各种黑名单功能、白名单功能的属性和行为
Expand Down Expand Up @@ -234,6 +235,63 @@ export class TitleKeywordAction implements VideoFilterAction {
}
}

export class UploaderKeywordAction implements VideoFilterAction {
statusKey: string
valueKey: string
checkVideoList: (fullSite: boolean) => void
status: boolean
value: string[]
blacklist: WordList

/**
* 昵称关键字过滤操作
* @param statusKey 是否启用的GM key
* @param valueKey 存储数据的GM key
* @param checkVideoList 检测视频列表函数
*/
constructor(statusKey: string, valueKey: string, checkVideoList: (fullSite: boolean) => void) {
this.statusKey = statusKey
this.valueKey = valueKey
this.status = GM_getValue(`BILICLEANER_${this.statusKey}`, false)
this.value = GM_getValue(`BILICLEANER_${this.valueKey}`, [])
this.checkVideoList = checkVideoList

// 配置子过滤器
uploaderKeywordFilterInstance.setStatus(this.status)
uploaderKeywordFilterInstance.setParams(this.value)
// 初始化黑名单, callback触发edit
this.blacklist = new WordList(
this.valueKey,
'UP主昵称关键词 黑名单',
`每行一个关键词,支持正则(iv),语法:/abc|\\d+/`,
(values: string[]) => {
this.edit(values)
},
)
}

enable() {
// 告知agency
agencyInstance.notifyUploaderKeyword('enable')
// 触发全站过滤
this.checkVideoList(true)
}
disable() {
agencyInstance.notifyUploaderKeyword('disable')
this.checkVideoList(true)
}
add(value: string) {
this.blacklist.addValue(value)
agencyInstance.notifyUploaderKeyword('add', value)
this.checkVideoList(true)
}
// edit由编辑黑名单的保存动作回调, 数据由编辑器实例存储
edit(values: string[]) {
agencyInstance.notifyUploaderKeyword('edit', values)
this.checkVideoList(true)
}
}

export class UploaderWhitelistAction implements VideoFilterAction {
statusKey: string
valueKey: string
Expand Down
Loading

0 comments on commit b81493f

Please sign in to comment.