本项目旨在开发一个基于 Node.js 的轻量级服务,通过伪装成标准的 DLNA 数字媒体渲染器(DMR),欺骗局域网内的控制端(如 Bilibili、爱奇艺 App)向其投送视频。 核心目标不是播放视频,而是截获视频直链并自动下载保存,同时解决视频平台的时效性验证与 User-Agent 反爬限制。
- 功能描述: 实现 SSDP (Simple Service Discovery Protocol) 协议,监听 UDP 1900 端口。
- 输入: 局域网内的 UDP 组播
M-SEARCH请求。 - 行为:
- 收到
M-SEARCH * HTTP/1.1时,识别 ST 字段为urn:schemas-upnp-org:device:MediaRenderer:1或ssdp:all。 - 向请求方发送单播响应,声明自己是一台合法的媒体渲染器。
- 关键参数配置:
Server: 伪装为索尼或三星电视系统 (e.g.,Linux/3.10.0 UPnP/1.0 DLNADOC/1.50)。Location: 指向本机的 HTTP 描述文件地址 (e.g.,http://{local_ip}:8080/description.xml)。USN: 生成固定的 UUID,防止重启后被识别为新设备。
- 收到
- 功能描述: 提供 HTTP Server,响应设备描述 XML 请求。
- 接口:
GET /description.xml - 输出: 标准 UPnP XML 文档。
- 关键字段:
<friendlyName>: 自定义显示名称(如 "Living Room TV"),增加可信度。<manufacturer>: "Sony Corporation" (伪装品牌)。<modelName>: "Bravia 4K 2024"。<serviceList>: 必须包含AVTransport和RenderingControl服务定义。
- 功能描述: 拦截投屏指令,提取视频真实地址。
- 接口:
POST /avtransport/control - 行为:
- 解析 SOAP XML 请求体 (XML Body)。
- 核心动作: 监听
SetAVTransportURI动作。 - 提取数据:
CurrentURI: 视频直链(核心目标)。CurrentURIMetaData: 视频元数据(标题、封面图),用于生成文件名。
- 响应欺骗:
- 提取成功后,立即向 App 返回标准的
200 OKSOAP 响应。 - 若不返回或返回慢,App 会认为投屏失败并断开连接。
- 提取成功后,立即向 App 返回标准的
- 功能描述: 使用伪造的指纹下载视频流。
- 策略配置:
- Bilibili 策略:
- User-Agent:
Lavf/58.29.100或Bilibili/TV-API。 - Referer:
https://www.bilibili.com/。 - 时效性: 链接获取后
< 10min内必须开始下载。
- User-Agent:
- 爱奇艺 策略:
- User-Agent:
Dalvik/2.1.0 (Linux; U; Android 9; Sony Bravia Build/UR3)。 - Headers: 必须包含
Range: bytes=0-和Connection: keep-alive。
- User-Agent:
- 通用兜底策略:
- 默认使用
ExoPlayer风格的 UA。
- 默认使用
- Bilibili 策略:
- 下载管理:
- 支持断点续传(通过
Range头)。 - 自动命名:使用
CurrentURIMetaData中的<dc:title>作为文件名,若为空则使用时间戳。 - 流式写入:避免大文件占用过多内存,使用 Stream Pipe 写入磁盘。
- 支持断点续传(通过
- Runtime: Node.js (v18+)
- 核心库:
node-ssdp: 处理 SSDP 广播与发现。fast-xml-parser或xml2js: 解析 SOAP XML 指令。express或fastify: 搭建轻量级 HTTP Server。axios或got: 处理流式下载(支持 Stream 和自定义 Headers)。
- 端口冲突: 确保 UDP 1900 端口未被其他 DLNA 服务(如 Windows Media Player)占用。
- 网络环境: 服务必须运行在与手机同一网段(桥接模式),Docker 部署需使用
host网络模式。 - 心跳机制: 部分 App 需要定期收到
GetTransportInfo请求的“播放中”状态响应,否则会自动暂停。建议在收到Play指令后,对后续的状态查询请求伪造 "PLAYING" 状态。
- 手机端(B站/爱奇艺)点击投屏,能搜索到设备 "Living Room TV"。
- 点击连接后,手机端显示“正在投屏”或进入遥控器界面,且不报错。
- Node.js 服务端控制台打印出捕获的视频 URL。
- 服务端
downloads/目录下成功生成可播放的.mp4或.flv文件。