<< All versions

Skill v1.0.0

currentAutomated scan100/100
hjdhnx/drpy-node-skill/drpy-node-play-debug
──Details
PublishedNovember 1, 2026 at 03:15 AM
Content Hashsha256:dffd30c547f99b4f...
Git SHA0727d5f9262e
──Files
Files (1 file, 24.1 KB)
SKILL.md24.1 KBactive
SKILL.md · 569 lines · 24.1 KB

name: drpy-node-play-debug description: 适用于 drpy-node 源播放链路排查与 lazy 修复。用户提到"播放不通""lazy 不对""play.html 被当直链""iframe 提取""m3u8 提取""parse:0/1 判断""假播放""站外解析""加密链接""webplay""不能播""播放空白""播放器打不开""花屏""解密""防盗链"时使用。专注判断播放是否真实可播;detail 不稳定、整体修源和仓库上传应分流。 metadata: version: "1.0.0"


⚠️ 已归档(2026-07-17):本 skill 已被 `drpy-node-coder` 取代。coder 融合了 4 个旧 skill(workflow/create/play-debug/repo-upload)的全部工作流,并自带 scripts/cli.js CLI 替代 drpy-node-mcp 服务——一个 skill、无需安装 MCP。本文件保留仅供历史参考,新工作请直接用 drpy-node-coder。

drpy-node Play Debug

快速索引

播放表现优先判断首选动作
detail 没有 vod_play_url不是播放问题交回 workflow 修二级
parse:0 返回 /play/*.html假直链改 parse:1 或提取 iframe/m3u8
player_* url 乱码encrypt/base64/sign先解密再判直链/解析
浏览器可播但静态 HTML 无 m3u8JS 运行时生成Playwright network 兜底
多线路部分可播按 flag/input 分派不要一刀切 lazy

执行契约

  • 输入:source_name、detail ids、play_url、flag、当前 lazy 返回值或错误表现。
  • 输出:播放类型判断、lazy 修复方案、play 接口验证结果。
  • 停手:detail 不稳定、一级/搜索同时异常、上传/评估整源诉求出现时交回 workflow。

模式闸门:先判断是否允许写入

用户模式允许动作禁止动作
只读 / 规划 / dry-run / 不要改文件读取、诊断、判断 lazy 类型、给修复方案和复测计划drpy_edit_file、重写 lazy、仓库上传/改标签
需要确认后再改读取、诊断、输出播放诊断确认未确认前禁止改 lazy
明确要求执行按同一 play_url + flag 修改并复测detail 不稳定时不得深挖 lazy
自主全流程detail 稳定时自动做低风险 lazy 修复、复测并回传 autonomous_next改 detail、强绕登录/验证码、高风险多分支重写

如果用户说“只判断 / 不要修改 / dry-run”,本 skill 只能输出播放诊断确认、lazy 修改建议和验证计划。

自主全流程调用约定

当 workflow/source-create 为“修到100 / 满分后上传 / 不要中途问我”调用本 skill,且已传入真实 source_name/ids/play_url/flag 并确认 detail 稳定时,本 skill 可自动执行低风险播放修复:

  1. 记录修改前 detail 摘要和 play 返回。
  2. 判断返回类型:直链 / 站外解析 / 播放页 / 特殊协议 / 假通过。
  3. 只修改 lazy 相关最小逻辑,不顺带改一级、二级、搜索。
  4. 用同一 play_url + flag 复测。
  5. 返回 blocker_type 和 autonomous_next 给 workflow。

必须停手的 blocker:

blocker_type判定autonomous_next
detail_unstabledetail 没有稳定 vod_play_from/vod_play_urlreturn_workflow
hard_anti_bot验证码、强 headless 检测、DRM/WASMstop_for_user
missing_credentials播放需要 Cookie/Authorization/登录stop_for_user
high_risk_change需要重写多条线路、删除模板 lazy、影响所有 flagstop_for_user
none低风险修复已完成并复测continue_evaluate

Return Packet 必含:

text
source_name: ...
ids: ...
flag: ...
play_url: ...
修改前 play: {parse, jx, url}
修改后 play: {parse, jx, url} / 未修改
结论: 真实可播 / 假通过 / 需浏览器确认
blocker_type: none / detail_unstable / hard_anti_bot / missing_credentials / high_risk_change
autonomous_next: continue_evaluate / retry_lazy / return_workflow / stop_for_user

------
common_lazy / def_lazy / cj_lazyreferences/references-play-lazy-summary.md
encrypt/base64/player_* 判断references/references-play-lazy-summary.md
playParseAfter / parse/jx 后处理references/references-play-lazy-summary.md
多线路 / 特殊协议references/references-play-lazy-summary.md

调度优先级

当本地环境已安装本 Skill 时:

  • 本 Skill 优先级 高于 drpy-node MCP 的通用调试 prompt
  • 播放链排障必须优先按本 Skill 的判断顺序执行

30 秒速查决策树

当用户说"播放不通 / lazy 不对 / play.html 被当直链"时:

Step 1:检查前提

  • 一级/二级/搜索也同时异常?→ 交回 drpy-node-source-workflow
  • detail 还没稳定产出 vod_play_from/vod_play_url?→ 先修二级,不要判 lazy

工具调用(MCP 真实字段示例):

text
test_spider_interface(source_name='源名', interface='detail', ids='一级返回的真实 vod_id')
test_spider_interface(source_name='源名', interface='play', play_url='二级返回的真实播放地址', flag='线路名')

Step 2:判断当前 lazy 更接近哪类模板默认

类型特征参考
common_lazy播放页有 player_* JSON,可能有 encryptreferences-play-lazy-summary.md §1
def_lazy站点播放页交给解析系统,parse:1references-play-lazy-summary.md §2
cj_lazy采集站/解析接口,有 parse_urlreferences-play-lazy-summary.md §3

Step 3:判断返回类型

类型特征正确返回验真要点
直链媒体m3u8/mp4/m4a/mp3{parse:0, jx:0, url}URL 应可请求且 content-type/内容像媒体或 m3u8
站外解析链接外部解析器地址{parse:0, jx:1, url}不能把普通网页误当直链
网站播放页当前站播放页 URL{parse:1, url:input}parse:1 是嗅探意图,不是失败本身

URL 类型快速判定表

URL 特征类型正确返回格式
以 .m3u8 / .mp4 / .mp3 / .m4a 结尾直链媒体{parse:0, jx:0, url} 或直接返回 URL 字符串
跨域域名,含 jx / 解析 / play / player / url=站外解析链接{parse:0, jx:1, url}
本域名且路径含 /play/ / /vodplay/网站播放页{parse:1, url:input}

🛑 检查点:确认诊断后再修复

在编写或修改 lazy 前,先确认:

  • detail 是否稳定产出 vod_play_from/vod_play_url
  • 当前返回类型是直链/站外解析/播放页中的哪一种
  • 当前是否属于假通过
  • 预期应该返回什么类型

确认模板:

markdown
## 播放诊断确认
-detail 状态:稳定 / 不稳定
-当前 play 返回:...
-类型判断:直链 / 站外解析 / 网站播放页 / 特殊协议
-假通过风险:有 / 无
-拟修复 lazy:...
-验证计划:test_spider_interface(play)

确认后再进入修复;自主全流程模式下,若 detail 稳定且属于低风险 lazy 修复,此处只记录诊断并继续执行。

lazy 编辑验证清单

修改 lazy 前后必须保留证据:

  1. 修改前:记录 detail 输出里的 vod_play_from/vod_play_url。
  2. 修改前:记录 play 当前返回值和假通过判定。
  3. 修改时:只改 lazy 相关逻辑,不顺带重写一级/二级。
  4. 修改后:重新测同一个 play_url + flag。
  5. 多线路:至少测一条直链线路和一条解析/网页线路。

🛑 检查点:确认修复结果

在闭环报告前,必须核对修改前后的 play 返回值:

markdown
## 修改验证确认
-修改前 play 返回:{parse, jx, url}
-修改后 play 返回:{parse, jx, url}
-是否真实可播:是 / 否 / 需要浏览器确认
-是否覆盖多线路:已测线路数 / 总线路数
-是否回传 workflow:需要 / 不需要

同一 play_url + flag 修复后必须复测通过,多线路源至少每条线路测一条。未验证的修改不闭环。

强提醒

  • `parse:1 + 播放页链接` 不一定是错,可能是 def_lazy 的合理输出
  • 拿到 http 链接 ≠ 拿到直链,先判断是不是 m3u8/mp4
  • 遇到 player_* 配置优先查 encrypt,很多站不是没链接而是没解密

假通过识别

test_spider_interface(play) 返回 success 不等于真实可播,必须继续看返回内容:

假通过表现判定下一步
parse:0 但 url 是 /play/...html、API 地址或普通 HTML 页播放页/API 被误当直链查 isVideo/sniffer,改为 parse:1 或提取真实 m3u8/iframe
parse:0 但 url 不是 http/特殊协议/媒体后缀加密或拼接错误查 encrypt/base64/sign
jx:1 但 url 是本站详情/播放页站外解析误判保留本站播放页走 parse:1
返回空 url 或原 inputlazy 没提取到有效目标回到 player_* / iframe / 网络请求排查

如果 play 接口 success 但返回 URL 仍是网页/API,必须继续验证扩展名、content-type、响应内容或浏览器网络请求;必要时检查 play_json/play_parse/sniffer/isVideo 是否改变了最终判断。

以下情况必须二次确认后再改:

  • lazy 需要重写超过一个分支或影响多条线路。
  • 需要从 common_lazy 改为完全自定义 lazy。
  • 需要引入 Playwright 抓到的签名 API 或动态 token。
  • 需要删除模板继承的 lazy 或 parse_url。

真实可播验证清单

拿到 play 返回值后,按返回类型做验真,不要只看接口 success:

返回类型必验项目失败时动作
m3u8请求状态 200/206;响应或首段内容含 #EXTM3U;跳转后仍是 m3u8补 headers/referer;若是播放页伪装则改 parse:1
mp4/mp3/m4a状态 200/206;content-type 或 URL 后缀像媒体;非 HTML 文本若返回 HTML/403,查防盗链或签名时效
站外解析jx:1 且 URL 不是本站详情/播放页;包含目标媒体参数保留为解析,不要误设直链 parse:0
网站播放页parse:1;页面能让嗅探器或浏览器产生媒体请求静态抓不到时走 Playwright 网络兜底
特殊协议pics:// / novel:// / push:// 格式完整转对应内容类型检查,不套视频直链规则

如果媒体 URL 依赖 Referer/Cookie/User-Agent,要把 headers 放进返回结构或 lazy 请求链路里验证;不要只复制裸 URL。


参考与进阶

框架 playParseAfter 后处理机制

lazy 返回后,框架调用 playParseAfter() 做最终判断:

js
// drpysParser.js:683-734 核心逻辑
parse = SPECIAL_URL.test(playUrl) || /^(push:)/.test(playUrl) ||
/\.(m3u8|mp4|m4a|mp3)/.test(playUrl) ? 0 : 1;
jx = tellIsJx(playUrl); // 判断是否站外解析

这意味着:

  • 只要 lazy 返回的 URL 以 m3u8/mp4/m4a/mp3 结尾 → 自动设 parse:0
  • 即使 lazy 返回 `{parse:1, url}`,但 url 是直链 → 框架会覆盖为 parse:0
  • `tellIsJx(url)` 判断站外解析(源码锚点:drpysParser.js 的 playParseAfter() 调用链)→ 自动设 jx:1

所以在 lazy 中返回字符串 "https://example.com/movie.m3u8" 也是安全的——框架会自动处理。

播放相关 rule 字段速查

字段典型症状检查重点
play_jsonlazy 表面返回与最终 parse/jx/url 不一致用 get_resolved_rule 看继承后的最终字段,再测 play
play_parse是否解析/嗅探的行为不符合预期确认不是用配置掩盖错误直链判断
sniffer页面 URL 需要嗅探真实媒体请求静态工具找不到时用浏览器网络证据确认
isVideoHTML/API 地址被误判为媒体,或媒体地址未识别对照 URL 后缀、content-type、网络响应内容

这些字段会影响 lazy 前后处理,但不能替代真实播放验证;最终仍以 test_spider_interface(play) 加媒体证据为准。

tellIsJx 判断规则(站外解析识别)

框架的 tellIsJx(url) 通过 URL 特征判断是否为站外解析链接:

匹配站外解析的典型特征:
- 域名与当前站点 host 不同(跨域)
- URL 含常见解析关键字: jx, 解析, api, player, parse, open, url
- URL 指向已知解析服务商域名模式

手动判断时可参考此规则,但最终以框架 tellIsJx 正式行为为准。

特殊情况:webplay 线路

部分站点同时提供多条播放线路,其中某些线路是「webplay」需要特殊处理:

线路A: /play/1-1.html (普通播放页)
线路B: /webplay/1-1.html (webplay 模式)

对于 webplay 线路,通常需要在 lazy 中检测 URL 特征并做不同处理:

  1. 普通线路 → 模板默认 lazy(common_lazy 或 def_lazy)
  2. webplay 线路 → 可能需要 fetch 页面内容并提取 iframe/m3u8

模板默认 lazy 逻辑

完整代码与边界见 references/references-play-lazy-summary.md;本节只保留执行判断:

类型触发正确处理
common_lazy播放页有 player_* JSON解 encrypt 后判断直链/站外解析/回退 input
def_lazy站点播放页交给嗅探{parse:1, url:input, js:''}
cj_lazy采集站或 parse_url检查直链、json: 解析接口或拼接 parse_url

高级排查技术

iframe / m3u8 提取

iframe 提取

用 extract_iframe_src(url) 工具从播放页中提取 iframe 的 src。

m3u8 嗅探

用 fetch_spider_url(url) 请求播放页 URL,在响应中搜索 .m3u8 链接。

Playwright 网络兜底

如果 fetch_spider_url / extract_iframe_src 都找不到 m3u8,但浏览器里能播放,说明媒体 URL 可能由 JS 运行时/XHR 生成:

  1. 用 browser_navigate(play_url) 打开播放页。
  2. 用 browser_network_requests(filter='m3u8|mp4|api|play|url') 查看运行时请求。
  3. 若请求需要点击播放按钮,先 browser_snapshot 找按钮,再点击后重新看网络。
  4. 从网络请求中提取真实媒体 URL 或签名 API,再回写 lazy。

不要用静态 HTML 抓取失败直接判定站点无直链。

Playwright 失败降级: 如果 Playwright 也无法获取媒体请求(疑似 headless 检测/WASM 解密/DRM):

  1. 检查是否需要登录或验证码 → 需要则返回 missing_credentials 或 hard_anti_bot,不绕过
  2. 只允许做不规避保护的环境一致性复核(如使用正常 viewport 重新打开页面);确认存在 headless/验证码/DRM/登录墙后立即停手
  3. 若无强反爬但最终仍拿不到直链 → 在修复结论中标注“需浏览器确认”,不要强行返回空直链
  4. 单条线路失败不判定整源播放不可用 → 标为“某线路需浏览器确认”

player_* 配置提取

部分站的播放器配置(含视频地址)不在 HTML 元素属性中,而是嵌入在 <script> 标签的 JSON 对象里:

  1. 用 pdfa(html, 'script') 列出所有 script 标签内容
  2. 搜索含 player_ 前缀的变量(如 player_0、player_data、player_js)
  3. 找到后用 JSON.parse 或正则提取 url 字段

(若 player_* 配置在 HTML 属性中,仍优先用模板默认 common_lazy 处理)

多线路排障诊断流程

当用户报告"多线路部分能播部分不能"时,不要直接改 lazy。先做对比诊断:

Step 1: 分别测试每条线路
test_spider_interface(play, play_url='线路A真实URL', flag='线路A')
test_spider_interface(play, play_url='线路B真实URL', flag='线路B')
记录每条线路的返回 {parse, jx, url}。
Step 2: 对比能播与不能播线路的差异
- flag 名称是否暗示不同处理(如 "直链" vs "解析" / "线路1" vs "webplay")?
- input URL 路径/域名模式有何不同?
- 返回的 url 是什么类型(m3u8/mp4/play.html/跨域解析)?
Step 3: 检查 lazy 来源
get_resolved_rule(path) 确认当前 lazy 是模板继承还是自定义。
如果是模板继承(common_lazy/def_lazy/cj_lazy),先读 references/references-play-lazy-summary.md
确认该模板默认行为是否已覆盖其中一条线路。
Step 4: 判断停手条件
- 能播/不能播的差异在 input URL 模式上 → 本 skill 可修复(见下方"多线路混合处理")
- 不能播是因为 detail 未产出对应线路的 vod_play_url → 交回 workflow 修 detail
- 涉及修改 detail 的线路名/分组/选集生成逻辑 → 立即停手,交回 workflow

工具调用示例(分别测试两条线路):

text
# 先确认 detail 稳定产出所有线路
test_spider_interface(source_name='源名', interface='detail', ids='一级返回的真实 vod_id')
# 分别测试各线路
test_spider_interface(source_name='源名', interface='play', play_url='线路A的播放地址', flag='线路A')
test_spider_interface(source_name='源名', interface='play', play_url='线路B的播放地址', flag='线路B')
# 如果某线路返回假通过(parse:0 但 url 仍是 play.html),按"假通过识别"处理

🛑 检查点:确认多线路诊断方向

完成 Step 1-4 对比诊断后,向用户确认差异分析结论:

markdown
## 多线路诊断确认
-能播线路:...(flag + 返回类型)
-不能播线路:...(flag + 返回类型)
-差异根因:input URL 模式 / detail 未产出 / 线路分组逻辑
-是否本 skill 修复:是 / 否(转 workflow)
-拟修改策略:按 flag 分派 / 统一 lazy / 不修改

确认后再进入多线路混合处理或回传 workflow。

多线路混合处理

当一个源有多条线路(如"线路A直链m3u8 + 线路B需要解析"),lazy 不应一刀切。 应根据 input 的 URL 特征分别处理:

js
lazy: async function () {
let {input} = this;
if (/\.m3u8/.test(input)) return {parse: 0, url: input}; // 直链线路
if (/\.mp4/.test(input)) return {parse: 0, url: input}; // 直链线路
return {parse: 1, url: input}; // 需解析线路
}

加密链接处理

部分站的播放链接是加密的(如 base64 编码的 m3u8 地址),需要在 lazy 中先解密:

js
lazy: async function () {
let {input} = this;
// 如果链接是加密的,先解密
if (!input.startsWith('http')) {
try { input = base64Decode(input); } catch(e) {}
}
if (/\.m3u8/.test(input)) return {parse: 0, url: input};
return {parse: 1, url: input};
}

加密排查子流程(从乱码到解密)

当播放页有 player_* JSON 配置且 url 看起来像乱码时,按下述顺序排查:

1. 找到 player_* JSON → 查找 encrypt 字段的值
2. 如果 encrypt: '1' → 对 url 执行 unescape() 解码
3. 如果 encrypt: '2' → 对 url 执行 base64Decode() → unescape() 解码
4. 如果无 encrypt 字段 → url 可能是 base64 编码字符串,尝试 base64Decode()
5. 如果解码后仍是乱码 → 检查是否包含自定义签名(time/sign/key)
6. 验证:解码后的 URL 是否以 .m3u8/.mp4 结尾,或为有效 http 链接

常见加密模式(从真实源中总结)

加密方式特征处理
encrypt: '1'player_* JSON 中unescape(url)
encrypt: '2'player_* JSON 中base64Decode(url) → unescape()
URL 非 http 开头如 base64 字符串base64Decode(input)
自定义签名URL 含 time/sign/key需逆向签名算法
动态解密 WASM页面加载 wasm 解密需调用 wasm 或预解密映射

边界与合作

特殊协议处理

播放链不仅处理视频,还处理小说、漫画、音乐等内容类型:

comic (漫画) — pics:// 协议

js
lazy: async function () {
let html = await request(input);
let urls = pdfa(html, '.comic-pages&&img')
.map(it => pdfh(it, 'img&&data-src'));
return { parse: 0, url: 'pics://' + urls.join('&&'), js: '' };
}

novel (小说) — novel:// 协议

js
lazy: async function () {
let html = await request(content_url);
let json = JSON.parse(html);
let ret = JSON.stringify({ title, content: json.data.content });
return { parse: 0, url: 'novel://' + ret, js: '' };
}

audio (音乐) — 直链 m4a/mp3

js
lazy: async function () {
let html = await request(input);
let music = html.match(/var\s+music\s*=\s*(\{[\s\S]*?\})/)[1];
music = JSON5.parse(music);
return urljoin(input, music.file + ".m4a"); // 返回字符串
}

push (投屏) — push:// 协议

js
return { parse: 0, url: 'push://' + playUrl, js: '' };

与其他 Skill 的边界

本 Skill 负责

  • 判断播放结果是否真实可播
  • 修复 lazy 逻辑
  • 判断 parse:0/1、jx:0/1
  • 提取 iframe / m3u8 / 站外解析链接

本 Skill 不负责

  • 从零写完整源
  • 系统性重建首页/一级/二级规则
  • 仓库上传决策

何时交回 workflow

  • 一级/二级/搜索也同时异常
  • 问题已超出播放链,涉及整体重建
  • 用户目标是评估/上传/回滚

Return Packet to workflow

播放专项结束或停手时必须回传:

  • source_name、ids、flag、play_url
  • 修改前 play 返回
  • 修改后 play 返回(如未修改则写“未修改”)
  • 结论:真实可播 / 假通过 / 需浏览器确认
  • blocker_type:none / detail_unstable / hard_anti_bot / missing_credentials / high_risk_change
  • autonomous_next:continue_evaluate / retry_lazy / return_workflow / stop_for_user
  • 是否需要整源 evaluate

强制停手检查点

出现以下任一情况时,暂停深挖 lazy,交回 workflow:

  • detail 还没稳定产出 vod_play_from/vod_play_url
  • 需要修改 detail 的线路名、分组或选集生成逻辑
  • 问题已明显超出播放链
  • 用户目标已变成"评估整份源是否可用"

最小化原则

本 Skill 默认目标是让播放链路可用,不是把整份源补全。

不要在播放排障时顺带做的

  • 补年份/地区/演员/导演
  • 美化搜索字段
  • 整体源评估

这些属于源整体完善项,应交回 create/workflow。


实战参考

实战排查案例:从 play.html 到正确 lazy

场景

某源 play 测试返回 {"url": "/play/1-1.html", "parse": 0},播放器不工作。

排查步骤

1. 前提检查:test_spider_interface(detail) → detail 通,vod_play_url 有值 ✓
2. lazy 类型:源未写自定义 lazy → 走模板默认(mxpro → common_lazy)
3. 返回类型:url 是 /play/1-1.html → 网站播放页,不是直链
4. 根因诊断:common_lazy 预期提取 player_* JSON 输出直链,
但实际返回了 /play/1-1.html → 说明播放页可能没有 player_* 配置,
或 common_lazy 解析失败
5. 修复方案 A(简单):去掉自定义 lazy,让框架用 def_lazy 兜底
→ 返回 {parse:1, url:input},交由嗅探系统
6. 修复方案 B(直链):用 extract_iframe_src 提取 iframe → m3u8
→ 返回 {parse:0, url: 'https://...m3u8'}
7. 验证:test_spider_interface(play) 确认修复后返回值

关键教训

  • 不要见 play.html 就判 lazy 写错 — 先区分是预期行为还是解析失败
  • 修复应优先选简单方案 — 嗅探可用就不必强行提取直链
  • 始终从 detail 状态开始排查 — detail 不通时排查 lazy 毫无意义

收尾输出模板

markdown
## 播放修复结果
-源:...
-detail 状态:稳定 / 不稳定
-play_url / flag:...
-根因:假直链 / encrypt / iframe / 站外解析 / 多线路 / 其他
-lazy 改动:...
-验证结果:
-修改前 play:...
-修改后 play:...
-是否真实可播:是 / 否 / 需要浏览器确认
-下一步:交回 workflow / 继续播放专项 / 结束

排查顺序总结

1. detail 真通? → No → 交回 workflow
2. lazy 类型判断 → common_lazy / def_lazy / cj_lazy
├─ Step 2: 判断模板默认 lazy 类型
3. 返回类型判断 → 直链 / 站外 / 播放页
├─ Step 3: 用 URL 类型判定表判类型
├─ 🛑 检查点:确认诊断后再修复
4. 假通过识别 → 检查 parse/jx/url 是否真实
5. 加密检查 → encrypt 1/2 → base64Decode/unescape
6. 修复 lazy → 用正确 parse/jx 返回
├─ 编辑 → 验证 → 🛑 确认修复结果
7. 验证 → test_spider_interface(play)
8. 多线路? → 分别测试各线路 → 🛑 确认诊断方向 → 按 flag 分派
9. 闭环 → 收尾输出模板 / 交回 workflow
All versions