# 架构说明 dsh-song-download 是一个标准 DSH Cordis 插件包(Host 侧),随 profile bundle 加载。 ## 包结构 ``` dsh-song-download/ ├── package.json # dsh.bundle.patch 声明插件行 ├── cordis.patch.yml # insert 插件行 { id: song-download } ├── lib/index.js # ESM:export function apply(ctx) ├── README.md / LICENSE / CHANGELOG.md ``` ## 加载方式 `package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`,后者向 profile 的 bundle composition 插入一行插件。DSH 启动时加载该插件,注册两个模型工具并注入 prompt 提示段(`ctx.systemPrompt.section`)。 ## 工具注册 - `ctx.effect(() => ctx.tools.register(tool))`:注册随插件生命周期自动清理 - 工具对象为标准 ToolDefinition(name/description/parameters/output/execute) ## 执行链路 - `ctx.subprocess.spawn` 运行 `python -m yt_dlp`(收集模式读取 stdout/stderr, `PYTHONUTF8=1` 保证中文 JSON 输出) - 搜索:`-J`(JSON dump)+ `bilisearchN:` / `ytsearchN:` 前缀 - 下载:`-f bestaudio/best` + `--print after_move:filepath` 拿最终路径 - MP3 转码:`-x --audio-format mp3 --postprocessor-args "ffmpeg:-b:a 320k ..."`, 需要 ffmpeg(自动发现 PATH 或 imageio-ffmpeg) - 歌词:`--write-sub --sub-langs all --convert-subs lrc`;缺失时 `fetch` 网易云搜索 + 歌词 API 补抓(无需密钥) ## 容错 - UA/Referer 规避 B站 412 反爬 - bilisearch 失败自动换 ytsearch - 下载目录自动创建;`--no-write-danmaku` 避免弹幕杂物