跳到主要内容

音乐与 MV 系统

音乐页由静态前端、Netlify Function 解析服务和本地维护工具组成。页面展示本地音乐库和 Project SEKAI MV;B 站登录 Cookie 与管理员令牌不写入浏览器脚本,浏览器只取得短时媒体 URL。

当前部署分为两个环境:开发环境使用 local-bili-parser;生产环境将静态页面发布至 blog_static,并由其中的 Netlify Function 在同源 /api 下提供解析。页面构建时通过 BILI_PARSER_API=/api 指向生产接口,不包含管理员令牌或登录 Cookie。

功能范围

  • 音乐页按歌单展示曲目,支持自定义播放列表、HQ/SQ/Hi-Res 选择、搜索和显示数量设置;
  • MV 列表支持组合标签横向滚动、歌名搜索、网格/列表视图与观看状态;
  • MV 播放器从 B 站实际返回的 DASH 轨道生成画质菜单,只有源站提供时才显示 1080P、1080P60、2K、4K、HDR 等选项;
  • 所有画质首先使用 DASH 视频、音频分轨;该数据通路发生错误时,标准画质可尝试同档位单段 MP4,再依次尝试备用 CDN 与重新解析;
  • 播放器、MV 视图、分组、主题、音量、循环方式和特效帧率写入浏览器本地存储;
  • 全站浅色/深色切换使用一层合成遮罩,避免对大量 DOM 节点逐一做颜色过渡;
  • Live2D Cubism R5 运行时由构建脚本从 vendor/ 打包至静态资源目录,避免手工维护生成文件。

目录说明

位置作用
src/pages/music/音乐页面的 React 骨架和页面布局样式。
src/pages/settings/显示设置:主题、特效及帧率限制。
static/custom/js/aplayer.js音乐列表、APlayer、MV 列表、解析请求、画质切换和本地设置逻辑。
static/custom/css/APlayer、Video.js、MV 卡片、深色模式和全局主题遮罩样式。
static/data/JSON-streaming 格式的音乐、MV、分类与 B 站来源数据。
scripts/import-bilibili-season.mjs从指定 B 站合集更新 mv_bilibili.0.jsonl
scripts/build-bili-parser-catalog.mjs从 MV 数据生成后端白名单目录。
local-bili-parser/仅监听本机回环地址的解析服务。
../blog_static/netlify/functions/bili.mjs生产环境的 Netlify Function;保存会话、查询播放信息并返回受限 MV 的播放清单。
../blog_static/netlify/functions/catalog.mjs由构建脚本生成的 BVID 与分 P 白名单。
tools/bili_qr_login_gui.pyNetlify 后端扫码登录的图形化管理工具。
vendor/live2d-cubism-r5/Live2D Cubism R5 上游运行时源文件与许可证。

前端数据流

JSON-streaming 数据文件

├── 音乐列表 / APlayer
└── MV 卡片 ──点击或预取──> /api/resolve

Netlify Function:短时 DASH 清单 + 实际轨道

Video.js DASH / 同档位单段 MP4

B 站 UPOS CDN

页面只取得短时媒体 URL 和播放清单,不取得 B 站登录 Cookie。解析服务只接受收录在 MV 目录内的 BVID 与分 P,不能用作任意 URL 的开放代理。

画质与播放策略

  1. 页面请求 /api/resolve?bvid=…&p=…
  2. Function 先检查 catalog.mjs 中的 BVID 与分 P,再以服务器保存的登录会话查询视频资料和 x/player/playurl。请求使用 fnval=4048fourk=1platform=html5,以取得 DASH 视频轨道、音频轨道和实际支持的档位。
  3. Function 按返回的轨道建立画质菜单,保留分辨率、编码、码率、初始化范围和备用 URL。没有对应轨道时,菜单中不会出现该档位。
  4. 页面首先将 Function 返回的 MPD 内容交给 Video.js/VHS,使视频轨道与音频轨道同步播放。默认选择已保存的画质;没有已保存的档位时选择 720P,仍不存在时选择最高实际档位。
  5. DASH 首次装载失败后,页面对相同清单重试一次;其后仅在接口确实返回同档位、单分段 durl 时使用单段 MP4。MP4 及其备用 URL 失败后,页面继续尝试 DASH 备用 URL,并在需要时重新请求 /api/resolve

画质菜单的内容由当次 playurl 响应决定,因此可显示 1080P、1080P60、2K、4K、HDR 等实际返回的档位。

MV 数据维护

当前导入器读取 UP 主 13148307 的合集 1547037。执行以下命令会拉取合集全部分页、去重、清理标题中的投稿前缀,并写回 BVID、封面、时长、组合和 MV 类型:

npm run import:bili-season

标题清理遵循以下原则:优先保留书名号或日文引号中的歌名;去掉常见投稿标签;保留原始条目无法识别时的可读标题。组合和类型可由旧资料继承,缺失时按标题规则归类。导入完成后重新生成允许解析的目录:

npm run build:bili-catalog

该命令会写入部署仓库的 ../blog_static/netlify/functions/catalog.mjs。数据变更与目录变更必须一起部署,否则新导入的 MV 会被后端拒绝。

本地开发:local-bili-parser

本地方案适合开发和直接测试。服务默认只监听 127.0.0.1:19180,会话保存在用户私有目录,页面默认访问 http://127.0.0.1:19180/api

cd local-bili-parser
npm install
npm start

# 另一个终端:启动静态站
cd ..
npm start

打开音乐页后,通过页面的登录流程扫码。服务的 --allow-origin 只接受精确 Origin;若页面不是 http://localhost:3000,应显式传入自己的站点 Origin:

npm start -- --allow-origin https://example.com

本地实现会代理已经解析好的 Range 请求,让浏览器能安全读取独立的音视频轨道;它不接受任意外部媒体 URL。

生产环境的解析 Function

生产静态站将 build/ 同步到 blog_static,由 netlify/functions/bili.mjs 提供同源 /api。构建时必须指定同源 API:

BILI_PARSER_API=/api BILI_PARSER_MODE=netlify npm run build

Netlify Functions 需要以下仅服务端可见的环境变量:

变量用途
BILI_SESSION_ENCRYPTION_KEY至少 24 个字符的随机密钥,用于加密 Netlify Blobs 中的 Cookie。
BILI_PARSER_ADMIN_TOKEN管理二维码登录、状态和退出接口的高强度令牌。
BILI_ALLOWED_ORIGIN可选。静态站和 Function 同源时不必设置。

不要将上述变量写入仓库、Docusaurus 构建变量或浏览器脚本。使用 tools/bili_qr_login_gui.py 时,令牌只保留在当前 GUI 进程内。完整的环境变量和接口说明位于部署仓库的 NETLIFY-BILI-PARSER.md