sharoon7171/doodstream-direct-resolver

GitHub: sharoon7171/doodstream-direct-resolver

零依赖的 Node.js 服务,通过逆向 DoodStream 播放器握手协议将视频 ID 解析为 CDN 直链,并提供浏览器代理播放能力。

Stars: 0 | Forks: 0

# DoodStream 直连解析器 这是一个零依赖的 Node.js 服务,用于将 DoodStream 的**视频 ID** 解析为直接的 CDN MP4 链接。该实现逆向了内嵌播放器的握手过程,并使用原生的 Chrome 指纹 HTTP 客户端进行重放——无需 npm 依赖项、无头浏览器,也无需验证码自动化。 ## 技术栈 | 层级 | 技术 | | --- | --- | | 运行时 | Node.js (ES modules) | | HTTP 服务器 | `node:http` | | 上游客户端 | `node:http2`, `node:https`, `node:tls`, `node:zlib` | | 前端 | 静态 HTML/CSS/ES module(由同一进程提供服务) | ``` npm start # node src/server/index.js PORT=8787 npm start ``` 默认监听地址:`http://localhost:8787` ## 架构 ``` flowchart TB subgraph client [Browser / API consumer] UI[public/app.js] API[POST /api/resolve] Proxy[GET/HEAD /api/stream] end subgraph server [src/server/] Index[index.js] ResolveRoute[routes/resolve.js] StreamRoute[routes/stream.js] Resolver[doodstream/resolver.js] HttpClient[http/client.js] Headers[http/browser-headers.js] HttpResp[lib/http-response.js] end subgraph shared [src/lib/] ParseId[parse-video-id.js] end subgraph external [External] Bootstrap[doodstream.com] Mirror[Active mirror / Cloudflare] CDN[CDN origin] end UI --> ParseId UI --> API UI --> Proxy API --> Index Proxy --> Index Index --> ResolveRoute Index --> StreamRoute ResolveRoute --> ParseId ResolveRoute --> Resolver StreamRoute --> HttpClient Resolver --> HttpClient HttpClient --> Headers ResolveRoute --> HttpResp StreamRoute --> HttpResp HttpClient --> Bootstrap Bootstrap --> Mirror HttpClient --> Mirror HttpClient --> CDN Proxy --> CDN ``` ### 模块映射 ``` / ├── public/ │ ├── index.html Dev/test UI shell │ ├── app.js Resolve client, live timers, copy links, proxy playback │ └── app.css └── src/ ├── lib/ │ └── parse-video-id.js Video ID validation (shared by server + browser) └── server/ ├── index.js Entry point: API routing + static file server ├── lib/ │ └── http-response.js readJsonBody, sendJson ├── routes/ │ ├── resolve.js POST /api/resolve orchestration │ └── stream.js GET/HEAD /api/stream byte proxy ├── doodstream/ │ └── resolver.js Bootstrap, embed decode, pass_md5, direct link build └── http/ ├── client.js Chrome TLS + HTTP/2 client (fetchText, fetchStream) └── browser-headers.js document vs fetch header profiles ``` ### 职责划分 | 模块 | 作用 | | --- | --- | | `parse-video-id.js` | 服务器路由和浏览器客户端共享的单一解析器,用于实现一致的验证 | | `src/server/index.js` | 路由 `POST /api/resolve`、`GET/HEAD /api/stream`,并在 `/lib/*` 路径下提供 `public/` 和 `src/lib/` 的服务 | | `routes/resolve.js` | 解析 `videoId`,调用解析器,验证链接,返回 JSON | | `routes/stream.js` | 代理带有注入 `Referer` 的 CDN range 请求;支持外部播放器的 `HEAD` 请求 | | `doodstream/resolver.js` | 实现 DoodStream embed → CDN URL 协议 | | `http/client.js` | 处理所有上游 HTTPS 请求;会话池;H2 优先,H1 后备 | | `http/browser-headers.js` | 用于 document 和类似 XHR 模式的 Chrome 131 UA 及 `sec-*` 标头 | | `public/app.js` | 针对两个 API endpoint 的集成参考 | ## 解析管道 DoodStream 在 CDN 上提供普通的 `video/mp4`。访问控制在于 **URL 发现**和 **CDN Referer 检查**,而不是流加密。 ``` sequenceDiagram participant R as routes/resolve.js participant V as doodstream/resolver.js participant H as http/client.js participant B as doodstream.com participant M as Active mirror participant C as CDN R->>V: resolveDirectLink(videoId) V->>H: fetchText GET doodstream.com/e/{id} (document mode) H->>B: Chrome TLS + H2 B-->>M: redirect M-->>H: embed HTML V->>V: decodeEmbedPage(html) Note over V: passMd5Path, playbackToken V->>H: fetchText GET /pass_md5/... (fetch mode, Referer) H->>M: Chrome TLS + H2 M-->>H: plaintext CDN prefix V->>V: buildDirectLink(prefix, token) R->>V: verifyDirectLink(directLink, referer) V->>H: fetchText Range bytes=0-15 (fetch mode, Referer) H->>C: Chrome TLS + H2 C-->>H: 206 Partial Content R-->>R: JSON response ``` ### 详细步骤 (resolver.js) 1. **`GET https://doodstream.com/e/{videoId}`** — document 标头;跟随重定向到当前活跃的镜像站点;从最终 URL 获取规范 origin。 2. **`decodeEmbedPage(html)`** — 通过正则提取: - `/pass_md5/{hash}/{token}` 路径(内联 `$.get`、带引号的字符串,或裸路径) - 来自 `makePlay()` 查询字符串或 pass_md5 路径片段的播放 token 3. **`GET {origin}{passMd5Path}`** — fetch 标头;`Referer: {origin}/e/{videoId}`。 4. **`decodePassMd5Response(body)`** — body 可能是: - 纯文本 `https://...` CDN 前缀 - `RELOAD` → 会话已过期 - 非 URL 文本 → 触发限速 / token 重用 5. **`buildDirectLink(cdnPrefix, token)`** — 模拟站点播放器:10 个随机字符 `[A-Za-z0-9]` + `?token={token}&expiry={Date.now()}`。 6. **`verifyDirectLink`** — 使用 `Referer: {origin}/` 请求 CDN 的 `Range: bytes=0-15`;要求返回 HTTP 200 或 206;从 `Content-Range` 读取总大小。 没有 WASM,也不需要对媒体字节进行二次解密。 ### 镜像发现 不需要镜像 URL 或环境变量。`doodstream.com/e/{videoId}` 会重定向到当前托管嵌入内容的镜像站点(例如 `playmogo.com`)。解析器将重定向后的 origin 用于 `pass_md5`,并将 `referer` 设置为 `{origin}/`。 ## HTTP 客户端与 Cloudflare 镜像主机会以 **403** 拒绝默认的 Node/curl TLS 指纹。`http/client.js` 在传输层模拟 Chrome: | 机制 | 实现 | | --- | --- | | TLS ciphers | 通过 `tls.connect` 实现 Chrome cipher suite 顺序 | | TLS 扩展 | `SSL_OP_TLSEXT_PADDING`, `SSL_OP_NO_ENCRYPT_THEN_MAC`, X25519/P-256 curves | | ALPN | `h2`, `http/1.1` | | HTTP/2 | Chrome SETTINGS(window 6291456, max streams 1000 等) | | 会话 | 在 `sessions` Map 中实现按 origin 的 H2 会话缓存 | | 后备策略 | H2 失败 → 使用相同 TLS 配置的 H1 | | Headers | 页面加载使用 `documentHeaders()`;API/CDN 使用 `fetchHeaders()` | | 压缩 | 缓冲文本使用 br/gzip (`fetchText`);流式传输使用 br/gzip/deflate (`fetchStream`) | `fetchText(url, extraHeaders, mode)` — 用于 HTML 和 pass_md5 的缓冲响应;遵循重定向。 `fetchStream(url, extraHeaders)` — 用于 CDN 代理的流式响应;转发 `Range`。 ## 流代理 CDN 强制要求 **`Referer: {mirror-origin}/`**。浏览器无法在 `
标签:GNU通用公共许可证, HTTP/2, MITM代理, Node.js, 云资产清单, 免依赖, 多模态安全, 安全合规, 底层编程, 流媒体解析, 网络代理, 视频下载, 逆向工程