Bilibili-Evolved v1 设置迁移功能详解:从旧版设置导出到 v2 自动安装的完整流程与源码原理
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
Bilibili-Evolved v2 重构了组件库与设置体系,为了让老用户平滑过渡,官方在 v2 组件库中提供了「v1 设置迁移」功能:读取 v1(旧版脚本)导出的settings.json,根据其中开启的选项自动下载并安装 v2 中对应的功能组件。本文以 v1 设置迁移组件文档 为骨架,结合其 组件入口、核心迁移逻辑 与 官方迁移教程,讲解迁移机制的整体设计、功能/选项两级映射原理,以及从导出设置到完成迁移的完整实操步骤。
迁移功能定位与触发方式
「v1 设置迁移」是一个注册在组件库 utils 分类下的组件,组件名v1Migrate,显示名「v1 设置迁移」。从 组件入口 可以看到,它并不像普通功能那样直接注入页面,而是通过数据注册机制在设置面板的「关于」页注入一个动作按钮:
export const component = defineComponentMetadata({ name: 'v1Migrate', displayName: 'v1 设置迁移', tags: [componentsTags.utils], entry: () => { addData('settingsPanel.about.actions', (actions: AboutPageAction[]) => { actions.push({ icon: 'mdi-inbox-arrow-down-outline', name: 'importV1Settings', displayName: '导入 v1 设置', run: async () => { /* ... */ }, }) }) }, })这里的关键机制是addData('settingsPanel.about.actions', ...):关于面板的动作列表本身由 src/components/settings-panel/sub-pages/about-page.ts 维护,内置了「导出设置」「导入设置」两个动作,任何组件/插件都可以通过数据钩子追加自己的动作。该文件中定义了动作的数据结构:
export interface AboutPageAction { icon: string iconSize?: number disabled?: boolean name: string displayName: string actionName?: string run: (event?: MouseEvent) => void | Promise<void> }因此安装该组件并刷新页面后,设置面板左下角「关于」页就会多出「导入 v1 设置」按钮,点击后:
- 调用 file-picker 的
pickFile({ accept: '*.json' })打开文件选择框,只接受 JSON 文件; - 读取选中文件内容并
JSON.parse解析为 v1 设置对象; - 将解析结果交给
runMigrate(settings)执行迁移; - 解析或迁移过程中抛出的异常统一由
logError记录。
核心迁移流程:runMigrate 的四个阶段
整个迁移逻辑集中在 migrate.ts 的 runMigrate 中,大致分为四个阶段:
阶段一:从 CDN 拉取在线功能索引
迁移开始时会显示Toast.info('下载功能列表中', '导入 v1 设置'),然后根据当前设置的 CDN 源与编译分支构造功能索引地址并下载:
const featuresDataUrl = `${cdnRootsgetGeneralSettings().cdnRoot}doc/features/features.json` const featuresDataText = await monkey({ url: featuresDataUrl }) const features: DocSourceItem[] = JSON.parse(featuresDataText)cdnRoots定义在 src/core/cdn-types.ts,支持jsDelivr(已废弃)、AltCdn、GitHub三种更新源;features.json是仓库在线文档生成的组件/插件索引,其条目类型DocSourceItem定义在 registry/lib/docs/index.ts,包含type(component或plugin)、name、fullAbsolutePath、owner等字段,用于后续定位功能的下载地址。
阶段二:构造迁移动作清单
migrate.ts的核心是一个包含约 200 多条动作的migrateActions: Executable[]数组,每条动作都基于下面几类工厂函数生成:
featureMap:功能级迁移(安装/跳过)
const featureMap = (oldKey: string, newKey: string, type: 'component' | 'plugin') => async () => { const oldValue = v1Settings[oldKey] if (!oldValue) { console.log(`跳过了未开启的选项 ${oldKey}`) return } if (!(newKey in map[type])) { // 从 features.json 找到新功能地址, 从 CDN 下载代码并安装 const code = await monkey({ url }) const { before, after } = getHook(`user${lodash.startCase(type)}s.add`, code, url) await before() const { metadata, message } = await installerMaptype await after(metadata) } else { console.log(`${newKey} 已经存在, 跳过安装`) } }其行为是:只有当 v1 设置中oldKey为真值(该功能在 v1 中开启)时才处理;若 v2 中对应功能尚未安装,则从 CDN 下载代码,通过installComponent/installPlugin安装,并用 src/plugins/hook.ts 提供的getHook在执行安装前后触发userComponents.add/userPlugins.add钩子;若已安装则跳过。注释中magic: guiSettings is always enabled揭示了getPlugin的巧妙用法——利用 v1 的guiSettings选项恒为开启的特性,把「某个插件是否安装」绑定到该选项上。
optionMap:选项级迁移(写入 v2 配置)
const optionMap = (oldKey: string, newKey: string, mapFunction?: (value: any) => any) => () => { const oldValue = v1Settings[oldKey] const newValue = mapFunction?.(oldValue) ?? oldValue if (newValue !== undefined) { const [componentName, ...optionPath] = newKey.split('.') const { options } = getComponentSettings(componentName) lodash.set(options, optionPath, newValue) } }它通过getComponentSettings(定义在 src/core/settings/helpers.ts)拿到目标组件当前的options,再用lodash.set按点分路径写入 v1 的旧值。newKey中的第一个点分段是组件名,其余是选项路径,例如'expandDanmakuList.ignoreMediaList'表示写入expandDanmakuList组件的ignoreMediaList选项。
stylesMap:自定义样式迁移
const stylesMap = () => () => { const { customStyles } = v1Settings customStyles .filter((style: any) => style.enabled) .forEach((style: any) => { settings.userStyles[style.name] = lodash.omit(style, 'enabled') as Required<UserStyle> }) }只迁移 v1 中处于启用状态的用户自定义样式,写入 v2 的settings.userStyles,并剔除enabled字段。此外i18nMap目前被注释为none,说明 v1 的多语言/翻译相关设置(i18n、i18nLanguage)暂未纳入迁移范围(对应的语言映射逻辑以注释形式保留在源码中)。
navbarItemMappings:导航栏项重命名映射
v1 与 v2 的导航栏项命名不同,迁移时通过一张映射表完成新旧命名转换:
const navbarItemMappings = { category: 'home', activities: 'feeds', bangumi: 'subscriptions', watchlaterList: 'watchlater', favoritesList: 'favorites', historyList: 'history', rankingLink: 'ranking', drawingLink: 'drawing', bangumiLink: 'bangumi', musicLink: 'music', matchLink: 'match', shopLink: 'shop', }它被用于customNavbar.order(导航栏排序)与customNavbar.hidden(隐藏项)的迁移:旧键先映射为新键再删除旧键,同时显式删除mangaLink(v2 中已不存在的项)。
阶段三:顺序执行全部迁移动作
let completed = 0 toast.message = `导入中... (${completed}/${migrateActions.length})` for (const action of migrateActions) { try { await action() success++ } catch (error) { console.log(error) fail++ } finally { completed++ toast.message = `导入中... (${completed}/${migrateActions.length})` } }每条动作被独立包裹在 try/catch 中,单条失败不会中断整体迁移,进度通过 Toast 实时刷新,最终汇总为导入完成. 成功 X 个, 失败 Y 个, 可在控制台查看详细日志.。
阶段四:结果反馈
外层 catch 捕获整体性错误(如features.json下载失败),关闭 Toast 并用logError记录;各条动作的详细执行日志(跳过的选项、下载的功能、迁移的选项等)通过console.log输出,方便用户在控制台核对。
典型迁移映射一览
migrateActions中的映射涵盖了 v2 组件库的大部分分类,以下是几组有代表性的映射(完整清单见 migrate.ts):
| v1 设置键(oldKey) | v2 目标(newKey) | 类型 | 说明 |
|---|---|---|---|
useDarkStyle | darkMode | 组件 | 深色模式开关 |
darkColorScheme | darkModeFollowSystem | 组件 | 跟随系统深色模式 |
darkSchedule/darkScheduleStart/darkScheduleEnd | darkModeSchedule/.range.start/.range.end | 组件 + 选项 | 深色模式定时 |
hideBanner | hideBanner | 组件 | 隐藏横幅 |
expandDanmakuList/expandDanmakuListIgnoreMediaList | expandDanmakuList/.ignoreMediaList | 组件 + 选项 | 展开弹幕列表 |
expandDescription | fullVideoDescription | 组件 | 展开视频简介 |
removeAds/showBlockedAdsTip/preserveEventBanner | removePromotions/.showPlaceholder/.preserveEventBanner | 组件 + 选项 | 移除广告 |
touchVideoPlayer | touchPlayerGestures+touchPlayerControl | 组件 ×2 | 触屏操作拆分为两个组件 |
touchVideoPlayerDoubleTapControl | doubleClickControl | 组件 | 双击控制 |
customNavbar及一系列customNavbar*选项 | customNavbar组件内对应选项 | 组件 + 选项 | 自定义导航栏(含顺序/隐藏项重命名映射) |
keymap/keymapPreset/customKeyBindings | keymap/.preset/.customKeyBindings | 组件 + 选项 | 快捷键 |
downloadVideo/downloadVideoQuality/downloadVideoFormat | downloadVideo/.basicConfig.quality/.basicConfig.api | 组件 + 选项 | 视频下载(格式映射见下) |
downloadVideo.outputs.aria2/.idm | getPlugin(...) | 插件 | 下载输出插件(借 guiSettings 恒真特性安装) |
feedsFilter/feedsFilterPatterns/feedsFilterSideCards | feedsFilter/.patterns/.sideCards | 组件 + 选项 | 动态过滤 |
foregroundColorMode | settingsPanel.textColor | 选项 | 面板文字颜色 |
updateCdn | settingsPanel.cdnRoot | 选项 | 更新源 |
customStyles | settings.userStyles | 样式 | 用户自定义样式 |
值得注意的是部分映射带有值转换函数,例如:
customControlBackgroundOpacity(字符串百分比)→playerControlBackground.opacity时先parseFloat再Math.round(value * 100);downloadVideoFormat的flv→'video.flv'、dash→ 根据downloadVideoDashCodec是否以HEVC开头映射为'video.dash.hevc'或'video.dash.avc';scriptLoadingMode会先去掉值中的(自动)后缀;downloadPackageEmitMode会把 v1 的「分别下载」规范为 v2 的「单独下载」。
这些转换保证了新旧版本数据模型不一致时仍能正确落地。
完整迁移实操步骤
根据 官方迁移教程,从尚未安装 v2 脚本的状态开始,完整迁移共分四步:
导出 v1 设置:打开旧版脚本的设置面板,在搜索框旁边的菜单中选择「导出设置」,得到
settings.json文件(与 v2 内置的「导出设置」动作同源,见 about-page.ts)。安装 v2 脚本:删除 v1 脚本,参照 README 安装章节 安装 v2 脚本。
安装 v1 设置迁移组件:刷新 b 站页面使 v2 生效(设置面板默认仍位于页面左侧中央),打开设置 → 左下角「组件管理」→「在线仓库」,搜索
v1 设置迁移并安装,安装完成后刷新页面。开始迁移:再次打开设置面板,进入左下角「关于」,此时应出现「导入 v1 设置」按钮。点击后选择第一步导出的
settings.json,脚本会依次下载 v1 中开启过的功能并安装。等待 Toast 显示「导入完成」后刷新页面,迁移即完成。
迁移后的检查与限制
- 检查方式:迁移完成后可前往「组件管理」查看自动安装的组件清单,对照 v1 中开启的功能确认是否齐全;迁移明细(跳过/安装/迁移的项)在浏览器控制台中按
console.log输出,可用「导入完成」后的提示配合控制台排查失败的条目。 - 已知限制:从源码注释可以看到部分功能尚未纳入迁移或已被禁用,包括:
defaultVideoQuality(默认清晰度)、feedsTranslate、commentsTranslate、restoreFloors、volumeOverdrive、simpleHome/minimalHome等(对应行以注释形式保留);v1 的 i18n 多语言设置同样未迁移。这些功能需要用户在 v2 中手动重新配置或等待后续版本支持。
小结
「v1 设置迁移」是 Bilibili-Evolved v2 平滑升级体验的关键组件:对外,它以「关于」面板动作按钮的形式提供一键导入;对内,它通过featureMap(功能级自动安装)、optionMap(选项级值写入与转换)、stylesMap(自定义样式迁移)与导航栏项重命名映射,将 v1 的扁平设置键精确翻译为 v2 的组件体系。对于想要理解迁移机制或自行编写类似配置导入工具的开发者,migrate.ts 是一份完整且可直接参考的实现范例。
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考