- 前端
- 音视频
【免费下载链接】Bilibili-Evolved
强大的哔哩哔哩增强脚本
Bilibili-Evolved 是一款面向哔哩哔哩网站的增强脚本,其功能以"组件(Component)"为基本单元组织。本篇文章聚焦于其中一个非常轻量却颇具代表性的组件——seoRedirect(SEO 页面重定向),它以极少的代码完成了一个明确的任务:当脚本运行在哔哩哔哩的 SEO 视频页面(https://www.bilibili.com/s/video/)时,自动跳转到对应的原视频页面。读完本文,你将掌握该组件的完整定义方式、URL 匹配与拦截机制、跳转实现细节,以及它在 Bilibili-Evolved 组件体系中的运行原理,并可据此举一反三,理解整个仓库中大量同类"轻量级入口组件"的编写范式。
一、功能背景:为什么需要 SEO 页面重定向
搜索引擎爬虫通常无法执行 JavaScript,因此哔哩哔哩为视频提供了专供搜索引擎收录的静态 SEO 页面,其 URL 结构为:
https://www.bilibili.com/s/video/BVxxxxxxxxxx这类页面与正常的视频播放页(https://www.bilibili.com/video/BVxxxxxxxxxx)内容基本相同,但缺少完整播放器与交互功能。当真实用户(而非爬虫)通过搜索引擎结果进入这类页面时,体验会明显受限。Bilibili-Evolved 的seoRedirect组件正是为解决这一问题而生。
该组件的官方说明非常凝练,仅有一句(见 registry/lib/components/video/seo-redirect/index.md):
进入 SEO 视频页面时 (
https://www.bilibili.com/s/video/) 自动跳转到原视频页面.
而它的完整实现同样精简,全部逻辑集中在一个组件元数据定义中(见 registry/lib/components/video/seo-redirect/index.ts):
import { defineComponentMetadata } from '@/components/define' export const component = defineComponentMetadata({ name: 'seoRedirect', displayName: 'SEO 页面重定向', entry: () => { window.location.assign(document.URL.replace('/s/', '/')) }, urlInclude: ['//www.bilibili.com/s/video/'], tags: [componentsTags.video], })整个组件只有 11 行代码,却覆盖了"定义、匹配、执行"三个环节,下面逐层拆解。
二、组件元数据:defineComponentMetadata与入口函数
Bilibili-Evolved 中的每个组件都通过defineComponentMetadata工厂函数声明,该函数定义在 src/components/define.ts:
export const defineComponentMetadata = <O extends UnknownOptions = EmptyOptions>( m: ComponentMetadata<O>, ): ComponentMetadata<O> => m它本质上是返回一个带类型约束的对象字面量,作用在于让组件声明获得完整的 TypeScript 类型检查。ComponentMetadata接口(见 src/components/types.ts)要求组件至少提供:
name:组件唯一名称,用于在设置面板、组件映射(componentsMap)中索引;displayName:在设置界面中展示给用户的名称;tags:组件分类标签,seoRedirect归类于componentsTags.video,即"视频"分类;entry:主入口函数,组件被加载时执行一次(重新开启时不会再次运行,除非另行定义reload)。
除这些必填字段外,FunctionalMetadata(见 src/components/types.ts)还定义了urlInclude、urlExclude、instantStyles、widget、extraOptions等可选能力。seoRedirect用到的正是entry与urlInclude这一经典组合:用 URL 模式限定生效范围,用入口函数执行实际动作。
三、URL 白名单匹配:urlInclude的判定机制
urlInclude表示"设置匹配的 URL,不匹配则不运行此组件"。seoRedirect将其设为:
urlInclude: ['//www.bilibili.com/s/video/']注意这里使用的是协议相对形式(以//开头,省略了https:),这是仓库内 URL 模式约定中的常见写法,可同时匹配http与https两种协议。该模式既匹配https://www.bilibili.com/s/video/BVxxx,也匹配http://www.bilibili.com/s/video/BVxxx。
组件在运行前必须通过 URL 判定,判定逻辑集中在isComponentEnabled(见 src/core/settings/helpers.ts):
export const isComponentEnabled = (component: ComponentMetadata | string) => { // ... 组件存在性检查与启用状态检查 ... // 若指定了排除URL, 任意URL匹配就不加载 if (component.urlExclude && component.urlExclude.some(matchUrlPattern)) { return false } // 若指定了包含URL, 所有URL都不匹配时不加载 if (component.urlInclude && component.urlInclude.every(lodash.negate(matchUrlPattern))) { return false } return true }判定规则可以总结为:
- 组件必须存在且处于启用状态(不可配置组件的启用状态固定为其默认值
enabledByDefault); - 若定义了
urlExclude,当前 URL 命中任意一条排除规则则不加载(排除优先级高于包含); - 若定义了
urlInclude,当前 URL 必须命中至少一条包含规则,否则不加载。
matchUrlPattern是这套判定的核心工具函数(见 src/core/utils/index.ts):
/** 以`document.URL`作为被测字符串, 移除URL查询参数并调用`matchPattern` */ export const matchUrlPattern = (pattern: string | RegExp) => matchPattern(document.URL.replace(window.location.search, ''), pattern)它有两个关键行为:
- 以当前页面 URL(
document.URL)为被测对象,并先移除查询参数(window.location.search),因此像?from=search这类跟踪参数不会干扰匹配; - 支持字符串与正则表达式两种模式:字符串模式走子串包含判断(
str.includes(pattern)),正则模式走pattern.test(str)。
对seoRedirect而言,//www.bilibili.com/s/video/作为字符串模式执行的是包含匹配——只要当前 URL 包含该子串,组件即被判定为"应在当前页面生效"。这正是该组件能被限制在 SEO 视频页面运行、而不会在其他页面误触发的根本保障。
同一套urlInclude/urlExclude机制还被用于组件加载时(src/components/component.ts)以及设置面板中组件可见性的判断(src/components/settings-panel/WidgetsPanel.vue),是整个组件体系通用的"页面生效范围"约定。
四、跳转实现:一行代码完成 URL 重写
当 URL 匹配通过后,组件入口函数被调用:
entry: () => { window.location.assign(document.URL.replace('/s/', '/')) }这行代码包含两个动作:
URL 重写:
document.URL.replace('/s/', '/')将当前地址中的第一个/s/路径段替换为/。以https://www.bilibili.com/s/video/BV1xx为例,替换后得到https://www.bilibili.com/video/BV1xx,即对应的原视频页面地址。注意String.prototype.replace配合字符串参数只替换第一个匹配,而/s/在 URL 中的出现位置正是路径段,恰好满足需求。整页跳转:
window.location.assign(url)在保留浏览器历史记录的前提下导航到新地址(用户可按后退键返回 SEO 页)。与之相对,若使用window.location.replace(url)则会替换当前历史记录条目。
该组件未定义reload与unload生命周期——跳转是"一次性动作",页面即将离开,无需清理任何副作用,因此保持最小实现是合理的。这一设计也体现了仓库中轻量组件的普遍取舍:能用同步entry完成的逻辑绝不引入状态管理。
五、完整运行链路:从页面加载到跳转发生
将上述机制串起来,seoRedirect在一次真实访问中的完整运行链路如下:
- 用户通过搜索引擎结果进入
https://www.bilibili.com/s/video/BVxxx; - Bilibili-Evolved 脚本初始化,遍历组件列表并逐个调用
isComponentEnabled判定; isComponentEnabled对seoRedirect检查:组件已启用、urlInclude中//www.bilibili.com/s/video/与当前 URL(去除查询参数后)匹配成功;- 组件通过判定,进入
loadComponent(src/components/component.ts),调用其entry; entry执行window.location.assign(...),浏览器导航至原视频页面,用户获得完整的播放器与弹幕体验。
在整个过程中,该组件不注入样式、不修改 DOM、不监听事件,属于"纯入口函数"型组件,这也使其成为理解 Bilibili-Evolved 组件最小形态的理想范例。
六、使用与配置
seoRedirect是 Bilibili-Evolved 的内置组件,随脚本默认分发,无需额外安装。它没有暴露任何可配置选项(OptionsMetadata为空),行为固定为"SEO 页面自动重定向"。用户可以在脚本设置面板的"视频"分类(componentsTags.video)下找到"SEO 页面重定向"(displayName),通过开关控制其启用或停用;停用后再次进入 SEO 视频页面将不再自动跳转。
若需扩展类似行为(例如将其他路径也纳入重定向范围),可以参照该组件的结构自行编写用户组件:通过urlInclude限定目标页面模式,在entry中执行 URL 重写与跳转即可,完整类型定义参考 src/components/types.ts 与 registry/lib/components/video/seo-redirect/index.ts。
七、小结
seoRedirect以 11 行代码展示了 Bilibili-Evolved 组件体系的核心范式:defineComponentMetadata声明元数据、urlInclude限定生效范围、entry执行动作。理解它的实现细节,等于掌握了阅读和编写仓库内绝大多数轻量组件的钥匙——从 URL 模式匹配(matchUrlPattern)到启用判定(isComponentEnabled),再到组件加载(loadComponent),这条链路贯穿整个项目,值得每一位希望深入该项目的开发者仔细研读。
- 前端
- 音视频
【免费下载链接】Bilibili-Evolved
强大的哔哩哔哩增强脚本
相关推荐
Bilibili-Evolved「稍后再看页面-重定向」组件解析:连播页跳转普通视频页的实现原理
Bilibili Evolved「稍后再看页面 重定向」组件解析:连播页跳转普通视频页的实现原理 导读 Bilibili Evolved(哔哩哔哩增强脚本)中有
前端音视频Bilibili-Evolved 极简首页(minimalHome)组件全面解析:配置、实现原理与源码导读
Bilibili Evolved 极简首页(minimalHome)组件全面解析:配置、实现原理与源码导读 极简首页( minimalHome )是 Bilib
前端音视频Bilibili-Evolved架构深度解析:组件化设计与源码实现原理
Bilibili Evolved架构深度解析:组件化设计与源码实现原理 Bilibili Evolved作为一款强大的哔哩哔哩增强脚本,采用基于Webpack的
前端音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考