Skip to content

Commit

Permalink
feat: popular page add quality filter, dimension filter
Browse files Browse the repository at this point in the history
  • Loading branch information
festoney8 committed Apr 30, 2024
1 parent b1e936f commit bccb866
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 32 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## 3.5.0

- 新增:热门/每周必看/排行榜页 支持时长过滤
- 新增:热门/每周必看/排行榜页 时长过滤
- 新增:热门/每周必看/排行榜页 竖屏视频过滤
- 新增:热门/每周必看/排行榜页 视频质量过滤(实验功能)
- 新增:右键菜单中复制链接功能

## 3.4.7
Expand Down
4 changes: 2 additions & 2 deletions src/components/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,11 @@ export class NumberItem implements IItem {

constructor(private option: INumberItemOption) {}

/** 获取数值, 初次安装使用禁用值 */
/** 获取数值, 初次安装使用默认值 */
getValue() {
this.itemValue = GM_getValue(`BILICLEANER_${this.option.itemID}`)
if (this.itemValue === undefined) {
this.itemValue = this.option.disableValue
this.itemValue = this.option.defaultValue
this.setValue(this.itemValue)
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/filters/videoFilter/agency/agency.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import bvidFilterInstance from '../filters/subfilters/bvid'
import dimensionFilterInstance from '../filters/subfilters/dimension'
import durationFilterInstance from '../filters/subfilters/duration'
import qualityFilterInstance from '../filters/subfilters/quality'
import titleKeywordFilterInstance from '../filters/subfilters/titleKeyword'
import titleKeywordWhitelistFilterInstance from '../filters/subfilters/titleKeywordWhitelist'
import uploaderFilterInstance from '../filters/subfilters/uploader'
Expand Down Expand Up @@ -45,6 +47,31 @@ class VideoFilterAgency {
break
}
}
notifyQuality(event: string, value?: number) {
switch (event) {
case 'disable':
qualityFilterInstance.setStatus(false)
break
case 'enable':
qualityFilterInstance.setStatus(true)
break
case 'change':
if (typeof value === 'number') {
qualityFilterInstance.setParams(value)
}
break
}
}
notifyDimension(event: string) {
switch (event) {
case 'disable':
dimensionFilterInstance.setStatus(false)
break
case 'enable':
dimensionFilterInstance.setStatus(true)
break
}
}
notifyBvid(event: string, value?: string | string[]) {
switch (event) {
case 'disable':
Expand Down
38 changes: 32 additions & 6 deletions src/filters/videoFilter/filters/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import settings from '../../../settings'
import { debugVideoFilter as debug, error, log } from '../../../utils/logger'
import { hideEle, isEleHide, showEle } from '../../../utils/tool'
import bvidFilterInstance from './subfilters/bvid'
import dimensionFilterInstance from './subfilters/dimension'
import durationFilterInstance from './subfilters/duration'
import qualityFilterInstance from './subfilters/quality'
import titleKeywordFilterInstance from './subfilters/titleKeyword'
import titleKeywordWhitelistFilterInstance from './subfilters/titleKeywordWhitelist'
import uploaderFilterInstance from './subfilters/uploader'
Expand All @@ -13,7 +15,7 @@ import uploaderWhitelistFilterInstance from './subfilters/uploaderWhitelist'
export interface IVideoSubFilter {
isEnable: boolean
setStatus(status: boolean): void
setParams(value: string[] | number): void
setParams?(value: string[] | number): void
addParam?(value: string): void
check(value: string | boolean | number): Promise<string>
}
Expand All @@ -24,7 +26,7 @@ export type VideoSelectorFunc = {
bvid?: (video: HTMLElement) => string | null
uploader?: (video: HTMLElement) => string | null
coinLikeRatio?: (video: HTMLElement) => number | null
isVertical?: (video: HTMLElement) => boolean | null
dimension?: (video: HTMLElement) => boolean | null
}

interface VideoInfo {
Expand All @@ -33,7 +35,7 @@ interface VideoInfo {
uploader?: string | undefined
bvid?: string | undefined
coinLikeRatio?: number | undefined
isVertical?: boolean | undefined
dimension?: boolean | undefined // true横屏 false竖屏
}

class CoreVideoFilter {
Expand All @@ -48,6 +50,8 @@ class CoreVideoFilter {
debug(`checkAll start`)
try {
const checkDuration = durationFilterInstance.isEnable && selectorFunc.duration !== undefined
const checkQuality = qualityFilterInstance.isEnable && selectorFunc.coinLikeRatio !== undefined
const checkDimension = dimensionFilterInstance.isEnable && selectorFunc.dimension !== undefined
const checkTitleKeyword = titleKeywordFilterInstance.isEnable && selectorFunc.titleKeyword !== undefined
const checkUploader = uploaderFilterInstance.isEnable && selectorFunc.uploader !== undefined
const checkUploaderKeyword = uploaderKeywordFilterInstance.isEnable && selectorFunc.uploader !== undefined
Expand All @@ -57,7 +61,15 @@ class CoreVideoFilter {
const checkTitleKeywordWhitelist =
titleKeywordWhitelistFilterInstance.isEnable && selectorFunc.titleKeyword !== undefined

if (!checkDuration && !checkTitleKeyword && !checkUploader && !checkBvid) {
if (
!checkDuration &&
!checkQuality &&
!checkDimension &&
!checkTitleKeyword &&
!checkUploader &&
!checkUploaderKeyword &&
!checkBvid
) {
// 黑名单全部关闭时 恢复全部视频
videos.forEach((video) => showEle(video))
return
Expand All @@ -76,6 +88,20 @@ class CoreVideoFilter {
info.duration = duration
}
}
if (checkQuality) {
const ratio = selectorFunc.coinLikeRatio!(video)
if (ratio) {
blackTasks.push(qualityFilterInstance.check(ratio))
info.coinLikeRatio = ratio
}
}
if (checkDimension) {
const dimension = selectorFunc.dimension!(video)
if (dimension !== null) {
blackTasks.push(dimensionFilterInstance.check(dimension))
info.dimension = dimension
}
}
if (checkBvid) {
const bvid = selectorFunc.bvid!(video)
if (bvid) {
Expand Down Expand Up @@ -139,7 +165,7 @@ class CoreVideoFilter {
// debug(_result)
if (!isEleHide(video)) {
log(
`hide video\nbvid: ${info.bvid}\ntime: ${info.duration}\nup: ${info.uploader}\ntitle: ${info.title}`,
`hide video\nbvid: ${info.bvid}\ntime: ${info.duration}\nup: ${info.uploader}\nratio: ${info.coinLikeRatio}\ntitle: ${info.title}`,
)
}
hideEle(video)
Expand All @@ -152,7 +178,7 @@ class CoreVideoFilter {
} else {
if (!isEleHide(video)) {
log(
`hide video\nbvid: ${info.bvid}\ntime: ${info.duration}\nup: ${info.uploader}\ntitle: ${info.title}`,
`hide video\nbvid: ${info.bvid}\ntime: ${info.duration}\nup: ${info.uploader}\nratio: ${info.coinLikeRatio}\ntitle: ${info.title}`,
)
}
hideEle(video)
Expand Down
27 changes: 27 additions & 0 deletions src/filters/videoFilter/filters/subfilters/dimension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { IVideoSubFilter } from '../core'

class DimensionFilter implements IVideoSubFilter {
isEnable = false

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

check(dimension: boolean): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (!this.isEnable) {
resolve(`Dimension filter disable`)
} else {
if (dimension) {
resolve(`Dimension is horizontal`)
} else {
reject(`Dimension is vertical`)
}
}
})
}
}

// 单例
const dimensionFilterInstance = new DimensionFilter()
export default dimensionFilterInstance
44 changes: 44 additions & 0 deletions src/filters/videoFilter/filters/subfilters/quality.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { IVideoSubFilter } from '../core'

class QualityFilter implements IVideoSubFilter {
// 质量过滤阈值
private threshold = 0
isEnable = false

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

setParams(threshold: number) {
this.threshold = threshold
}

// 根据coinLikeRatio计算视频质量, 参数源于爬虫数据拟合
calcQuality = (ratio: number): number => {
const A = -1.201e1
const B = 6.861e-1
const C = 7.369e-2
const D = 1.192e2
const ans = (A - D) / (1 + Math.pow(ratio / C, B)) + D
return ans > 0 ? ans : 0
}

check(ratio: number): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (!this.isEnable || this.threshold === 0) {
resolve(`Quality resolve, disable or 0`)
} else {
const score = this.calcQuality(ratio)
if (score > 0 && score > this.threshold) {
resolve(`Quality OK`)
} else {
reject(`Quality too bad`)
}
}
})
}
}

// 单例
const qualityFilterInstance = new QualityFilter()
export default qualityFilterInstance
78 changes: 76 additions & 2 deletions src/filters/videoFilter/pages/actions/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { debugVideoFilter as debug } from '../../../../utils/logger'
import agencyInstance from '../../agency/agency'
import bvidFilterInstance from '../../filters/subfilters/bvid'
import durationFilterInstance from '../../filters/subfilters/duration'
import dimensionFilterInstance from '../../filters/subfilters/dimension'
import qualityFilterInstance from '../../filters/subfilters/quality'
import titleKeywordFilterInstance from '../../filters/subfilters/titleKeyword'
import titleKeywordWhitelistFilterInstance from '../../filters/subfilters/titleKeywordWhitelist'
import uploaderFilterInstance from '../../filters/subfilters/uploader'
Expand All @@ -13,9 +15,9 @@ import uploaderWhitelistFilterInstance from '../../filters/subfilters/uploaderWh
// 定义各种黑名单功能、白名单功能的属性和行为
interface VideoFilterAction {
statusKey: string
valueKey: string
valueKey?: string
status: boolean
value: number | string | string[]
value?: number | string | string[]
// 检测视频列表的函数
checkVideoList(fullSite: boolean): void
blacklist?: WordList
Expand Down Expand Up @@ -130,6 +132,78 @@ export class UploaderAction implements VideoFilterAction {
}
}

export class QualityAction implements VideoFilterAction {
statusKey: string
valueKey: string
checkVideoList: (fullSite: boolean) => void
status: boolean
value: number

/**
* 视频质量过滤操作
* @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.checkVideoList = checkVideoList
this.status = GM_getValue(`BILICLEANER_${this.statusKey}`, false)
this.value = GM_getValue(`BILICLEANER_${this.valueKey}`, 20)
qualityFilterInstance.setStatus(this.status)
qualityFilterInstance.setParams(this.value)
}
enable() {
debug(`QualityAction enable`)
agencyInstance.notifyQuality('enable')
this.checkVideoList(true)
this.status = true
}
disable() {
debug(`QualityAction disable`)
agencyInstance.notifyQuality('disable')
this.checkVideoList(true)
this.status = false
}
change(value: number) {
debug(`QualityAction change ${value}`)
agencyInstance.notifyQuality('change', value)
this.checkVideoList(true)
}
}

export class DimensionAction implements VideoFilterAction {
statusKey: string
checkVideoList: (fullSite: boolean) => void
status: boolean

/**
* 视频横竖屏过滤操作
* @param statusKey 是否启用的GM key
* @param valueKey 存储数据的GM key
* @param checkVideoList 检测视频列表函数
*/
constructor(statusKey: string, checkVideoList: (fullSite: boolean) => void) {
this.statusKey = statusKey
this.checkVideoList = checkVideoList
this.status = GM_getValue(`BILICLEANER_${this.statusKey}`, false)
dimensionFilterInstance.setStatus(this.status)
}
enable() {
debug(`DimensionAction enable`)
agencyInstance.notifyDimension('enable')
this.checkVideoList(true)
this.status = true
}
disable() {
debug(`DimensionAction disable`)
agencyInstance.notifyDimension('disable')
this.checkVideoList(true)
this.status = false
}
}

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

0 comments on commit bccb866

Please sign in to comment.