Merge pull request #5339 from WakelessSloth56/preview-features

[组件 - 网址参数清理] 直接清理视频页面中的链接
This commit is contained in:
Grant Howard 2025-08-22 08:00:40 +08:00 committed by GitHub
commit ba2cd3bc03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 110 additions and 4 deletions

View File

@ -0,0 +1,82 @@
import { CommentAreaV3, forEachCommentArea } from '@/components/utils/comment-apis'
import { contentLoaded } from '@/core/life-cycle'
import { ShadowRootEvents } from '@/core/shadow-root'
import { console } from './index'
const isAnchor = (n: Node): n is HTMLAnchorElement => n.nodeName === 'A'
const observe = async (
target: Node,
options: MutationObserverInit,
callback: (mutation: MutationRecord, observer: MutationObserver) => void,
) => {
if (target) {
const observer = new MutationObserver((d, ob) => d.forEach(r => callback(r, ob)))
observer.observe(target, options)
}
}
const observeChildListSubtreeHref = {
attributes: true,
attributeFilter: ['href'],
childList: true,
subtree: true,
characterData: false,
}
export const cleanAnchors = async (getCleanUrl: (u: string) => string) => {
const clean = (a: Node) => {
if (!isAnchor(a) || !a.href) {
return
}
const newUrl = getCleanUrl(a.href)
if (a.href === newUrl) {
return
}
console.info('清理A标签', a, a.href, newUrl)
a.href = newUrl
}
const cleanAll = (anchors: Iterable<Node> | ArrayLike<Node>) => {
Array.from(anchors).forEach(clean)
}
const cleanMutationAnchors = (r: MutationRecord) => {
if (r.attributeName === 'href') {
clean(r.target)
} else if (r.addedNodes[0] && r.addedNodes[0] instanceof HTMLElement) {
cleanAll(r.addedNodes[0].querySelectorAll('a'))
}
}
contentLoaded(() => {
// DOMContentLoaded 时标签的垃圾参数在 HTML 中自带, 不会触发 MutationObserver
cleanAll(dqa('.tag-panel .tag-link'))
// 切换视频时的标签由 JS 添加,需要使用监听
observe(dq('.tag-panel'), observeChildListSubtreeHref, cleanMutationAnchors)
// 视频简介
observe(dq('#v_desc'), { childList: true, subtree: true, characterData: false }, r => {
if (r.addedNodes.length > 0 && r.target instanceof HTMLElement) {
cleanAll(r.target.querySelectorAll('a'))
}
})
// 视频推荐列表
observe(dq('.rcmd-tab'), observeChildListSubtreeHref, cleanMutationAnchors)
// 评论区
forEachCommentArea(async area => {
if (area instanceof CommentAreaV3) {
area.commentAreaEntry.addEventListener(
ShadowRootEvents.Updated,
(ev: CustomEvent<MutationRecord[]>) =>
ev.detail.forEach(r => {
r.addedNodes.forEach(node => clean(node))
}),
)
}
})
})
}

View File

@ -1 +1,3 @@
自动删除网址中的多余跟踪参数。请注意这会导致浏览器历史记录出现重复的标题(分别是转换前后的网址),并可能导致后退要多退几次。
- `清理页面中的 A 标签`: 清理视频简介、推荐列表、标签、评论中的链接。

View File

@ -1,10 +1,17 @@
import { registerAndGetData } from '@/plugins/data'
import { defineComponentMetadata } from '@/components/define'
import {
defineComponentMetadata,
defineOptionsMetadata,
OptionsOfMetadata,
} from '@/components/define'
import { getComponentSettings } from '@/core/settings'
import { isIframe, isNotHtml, matchPattern } from '@/core/utils'
import { useScopedConsole } from '@/core/utils/log'
import { registerAndGetData } from '@/plugins/data'
import { cleanAnchors } from './anchor'
const displayName = '网址参数清理'
const console = useScopedConsole(displayName)
const name = 'urlParamsClean'
export const console = useScopedConsole(displayName)
const entry = async () => {
if (isNotHtml() || isIframe()) {
return
@ -177,16 +184,31 @@ const entry = async () => {
}
}
if (getComponentSettings<Options>(name).options.cleanAnchors) {
cleanAnchors(getCleanUrl)
}
const { fullyLoaded } = await import('@/core/life-cycle')
const { urlChange } = await import('@/core/observer')
fullyLoaded(() => {
urlChange(() => clean())
})
}
const options = defineOptionsMetadata({
cleanAnchors: {
defaultValue: true,
displayName: '清理页面中的 A 标签',
},
})
type Options = OptionsOfMetadata<typeof options>
export const component = defineComponentMetadata({
name: 'urlParamsClean',
name,
displayName,
entry,
options,
tags: [componentsTags.utils],
/* spell-checker: disable */
urlExclude: [/game\.bilibili\.com\/fgo/, /live\.bilibili\.com\/p\/html\/live-app-hotrank\//],