feat(dandan): 弹弹play弹幕替代机制改用 NipaPlay 中转弹弹play服务端获取弹幕与弹弹302关联链接(需登录) - #487
Merged
Merged
Conversation
|
@wan0ge is attempting to deploy a commit to the huangxd's projects Team on Vercel. A member of the Team first needs to authorize it. |
dandan 源原经弹幕代理获取弹弹缓存弹幕,仅在弹幕为空时借弹弹302关联链接拉取跨平台弹幕。现改为:配置弹弹play账号后,dandan 源经 NipaPlay 中转弹弹play服务端获取弹幕,并把同一请求下发的弹弹302关联链接分发给已接入的对应平台源实时拉取,两部分沿用既有多源去重合并。 - 源配置新增 DANDANPLAY_ACCOUNT 与 DANDANPLAY_PASSWORD,账号与密码同时填写后自动开启,移除 NIPAPLAY_REPLACE_DANDAN 开关 - 密码配置页提供连通性测试,新增 POST /api/nipaplay/verify - NipaPlay 中转弹弹play服务端以香港线路为主、国内线路为备,主线路连续失败达到阈值后临时切换备用线路 - 原生弹幕地址请求失败时保留已解析的弹弹302关联链接,仍交由自采源拉取 - 以内嵌应用密钥与签名换取关联链接的做法改为账号令牌登录,令牌临近过期自动续期 - 凭据类变量与文本类变量同样绕过 dotenv 注释截断,含 # 时无需转义即可完整读取,写入 .env 后即时生效 - AI API Key 与 B站 Cookie 各自独立的编辑器样式合并为通用凭证编辑器样式,供 AI API Key、弹弹play密码与 B站 Cookie 共用 - nipaplay-util.js 日志标签按源与服务模块标注为 [dandan] [nipaplay] - README 与 .env.example 新增两个账号变量的配置项与说明,配置预览新增「NipaPlay 中转弹弹play服务端」分组
httpGet/httpPost 已实现 allow_redirects,httpRequestMethod(PATCH/PUT/DELETE 委托)此前未实现,其 JSDoc 标注「暂未实现」失真。现于 httpRequestMethod 统一实现:默认跟随重定向,false 时禁止以截获 3xx Location,与 GET/POST 行为一致;同步修正 JSDoc,并移除与 JSDoc 语义重复的那行注释。
- setEnv 日志对凭据类变量以 *** 脱敏,避免令牌/密码/Cookie/带令牌 URL 明文进入运行日志;判据为 Envs.sensitiveKeys(由 Envs.get 在 encrypt 为真时登记),非凭据变量保留明文以便排障 - 保存接口对掩码值 *** 跳过写入,避免凭据编辑框未改动直接保存时用星号覆盖服务端已存的真实值 - 补全 Envs.get 缺失的 encrypt 参数说明
原手写实现直接对 p 首字段与 t 做加减,缺少通用偏移工具的非负钳制,负偏移且绝对值大于弹幕时间时会产出负时间戳。 现改为调用 offset-util 的 applyOffset,与手动 @偏移、DANMU_OFFSET 等其余偏移路径行为一致,并保留 isRealTimePulled 标记供 dandan 源 formatComments 跳过专属转换。 worker.test.js 补充负偏移钳制用例。
worker.test.js 补充两处行为的回归用例:httpRequestMethod(经 httpPatch)的 allow_redirects 是否与 GET/POST 一致,以及 dandan 源 formatComments 是否按 isRealTimePulled 区分原生弹幕与实时拉取弹幕。两者均为可稳定回归的纯逻辑,纳入项目测试以免后续回归。
将 DandanUserAgent、SOURCE_TO_PLATFORM、getRelatedDanmuViaNipaplay、fetchDandanComments 下移到导出类之后,使「获取弹弹play弹幕」分节注释与其它源一致地紧随导入与源实例之后。 上述标识符均在函数体或方法体内使用,不在模块加载期求值,故下移不影响运行;已验证导出类方法仍可正常调用下移后的函数。
wan0ge
force-pushed
the
feat/nipaplay-gateway
branch
from
September 22, 2026 07:11
de01969 to
de4213d
Compare
B站 Cookie 检测以请求体中的值向 B 站实时校验,弹弹play 与 AI 的检测则只能取到服务端运行期配置:弹弹play 的账号、AI 的地址与模型都不随检测请求提交。云部署(vercel 等)保存变量需重新部署才会刷新运行期配置,因此这两处检测在重新部署前一直失败。 现改为账号、密码、密钥、地址、模型一律随检测请求提交,取值自设置页已加载的配置;掩码值(当前访问无权限读取明文)视为未知,交由服务端回退到已保存配置。 worker.test.js 补充设置页请求体字段与弹弹play/AI 验证接口以请求体为准的用例。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
为 dandan 源新增一种账号化的弹幕获取路径:以弹弹play 账号登录换取令牌,经 NipaPlay 中转弹弹play服务端获取弹幕。它与既有的「经弹幕代理获取缓存弹幕」路径并存——账号与密码均已填写时启用前者,未填写时维持后者,两种路径由是否配置凭据自动切换。
覆盖五个维度:获取链路、弹幕组合、配置形态、线路可用性、配置读取。另修复四处与本改动同源的既有缺陷。
变更背景
dandan 源原本依靠源码内嵌的
nipaplay应用密钥直连api.dandanplay.net截获 302 关联链接做跨平台兜底。这套机制依赖的密钥已被上游轮换:因此本分支和 NipaPlay 官方沟通确认后决定迁移过去改为以自有弹弹play 账号登录 NipaPlay 中转服务端、由网关代为持有密钥并签名上游请求:我们只需取令牌、请求网关、截获其回传的 302,数据与既往完全一致(解析与分发沿用既有实现,零改动)。
上游原版行为 → 本分支行为
1. dandan 源弹幕获取
getEpisodeDanmu经弹幕代理获取缓存弹幕;弹幕为空时借源码内嵌的 nipaplayv1 应用密钥直连api.dandanplay.net截获 302 关联链接做跨平台兜底,NIPAPLAY_REPLACE_DANDAN开启时以关联弹幕替代原生弹幕。X-AppId/X-Timestamp/X-Signature本地签名。账号已配置时,提交{userName, password}换取令牌后由中转服务端代为请求:一次请求同时得到原生弹幕与弹弹302关联链接;关联链接按平台分发给已接入的对应源实时拉取(同平台串行、间隔 1 秒防风控),两部分沿用既有多源去重合并。账号未配置或中转服务端不可用 → 回退既有路径。2. 令牌与线路
401时清除令牌重登并只重试一次;并发请求共用同一次登录;令牌只绑定账号,换账号才重新登录(改密码不触发)。3. 弹幕组合与标签
realTimeSource,经convertToDanmakuJson组装为[来源&平台](如[dandan&bilibili1]),触发既有多源去重并按来源降噪。alignSourceTimelines仅以 dandan 列表作「文本 → 最早时间」基准;实时拉取条目已按 302 的shift校正到同一时间轴,基准不被污染。4. 配置形态
NIPAPLAY_REPLACE_DANDAN开关及其globals取值,新增DANDANPLAY_ACCOUNT/DANDANPLAY_PASSWORD(同时填写即启用,无额外开关,预览以掩码呈现)。POST /api/nipaplay/verify(对齐既有handleAiVerify:成功ok:true,失败以200返回ok:false),不写入运行期令牌缓存。#截断(RAW_ENV_KEYS扩展到凭据类变量并按掩码写入预览集合);Node 端写/删.env后同步刷新原始解析缓存。5. 与合并源的兼容性
getEpisodeDanmu(id, mergedSources)接收按$$$拆分的合并段(形如<源名>:<真实ID>),据此跳过已参与合并的平台以免重复拉取。dandan 作主源或被合并方时行为一致:dandan 自身的原生弹幕来自fetchNipaplayDanmaku(id),不受跳过逻辑影响。6. 顺带修复的既有缺陷(与上列改动同源,非本功能引入)
node-handler.jssetEnvEnvs.sensitiveKeys(Envs.get在encrypt为真时登记)脱敏http-util.jshttpRequestMethodallow_redirects而 PATCH/PUT/DELETE 未实现、JSDoc 失真 → 统一实现并修正 JSDocsystemsettings.js保存接口***→ 未改动直接保存时跳过写入,避免覆盖服务端已存凭据nipaplay-util.jsapplyShiftToDanmuoffset-util.applyOffset,与其余偏移路径一致影响范围
DANDANPLAY_ACCOUNT/DANDANPLAY_PASSWORD401#等字符/api/nipaplay/verify)***;非凭据类保留明文以便排障已知限制
测试覆盖
node --test danmu_api/worker.test.js150/150 通过(上游基线 144/144);新增关联链接偏移钳制、httpPatch重定向一致性、dandan 按实时拉取标记区分处理、设置页连通性测试请求体字段、弹弹play 与 AI 验证接口以请求体为准等用例Envs加密变量读取契约对照上游387条 +bilibili×4,叠加自有链路后合并去重为398条)#不加引号;错误凭据不误报成功;关联链接含未支持平台;302 无Location;持续401只重登一次;主线路连续失败切备用涉及文件
utils/nipaplay-util.js[dandan] [nipaplay]sources/dandan.jsmergedSources跳过已合并平台;实时拉取弹幕标记realTimeSource;模块级常量与辅助函数下移到导出类之后,分节注释与其它源一致地紧随导入configs/envs.jsNIPAPLAY_REPLACE_DANDAN;新增DANDANPLAY_ACCOUNT/DANDANPLAY_PASSWORD;getRawEnv支持掩码;RAW_ENV_KEYS扩展到凭据类变量;新增sensitiveKeys凭据登记configs/handlers/node-handler.js.env后同步原始解析缓存;setEnv日志按sensitiveKeys脱敏apis/env-api.jshandleDandanplayVerifyworker.jsPOST /api/nipaplay/verify;路径归一化放行/api/nipaplayui/js/systemsettings.js***跳过写入utils/http-util.jshttpRequestMethod统一支持allow_redirects,并修正失真 JSDocui/js/preview.jsui/css/components.css.jsworker.test.jsconfig/.env.exampleREADME.md