dsh-media-inspect
v0.3.1
Published
Identify any common audio or video format by reading its real container structure, codec headers, or playlist text — MP4/MOV, Matroska/WebM, WAV/AVI, Ogg, FLAC, ASF/WMV/WMA, MP3, AAC, AC-3, MPEG-TS, and M3U/M3U8. Read-only and offline: reports findings an
Maintainers
Readme
dsh-media-inspect
一个 DSH(DeepSeek Harness)插件:识别所有常见音频与视频格式,只说话、不做事。
它直接解析文件的真实二进制结构(容器头、编解码器头、标签)或播放列表文本,因此扩展名说谎也能识破。 纯 Node 实现,不需要 ffmpeg、不需要任何原生依赖、不联网。
安装
把仓库克隆(或下载解压)到任意目录,然后在该目录的上一级执行:
dsh plugin --profile web add "file:/path/to/dsh-media-inspect"Windows 下路径写法示例:
dsh plugin --profile web add "file:C:/path/to/dsh-media-inspect"然后在 %APPDATA%\dsh-desktop\harness\profiles\web\package.json 的
dsh.profile.bundles 数组末尾追加 "dsh-media-inspect",重启 DSH 即可。
提供的工具
inspect_media
| 参数 | 类型 | 说明 |
|---|---|---|
| path | string(必填) | 文件绝对路径 |
| paths | string[] | 一次比较多达 16 个文件 |
| headBytes | integer | 头部读取字节数,默认 8 MiB |
| includeTags | boolean | 是否输出标签,默认 true |
支持的格式
判定一律基于真实字节(magic bytes),扩展名只作提示。 扩展名与内容不符时会给出提示。
容器 / 编解码器
| 格式 | 覆盖范围 | 报告内容 |
|---|---|---|
| ISO-BMFF | MP4 / MOV / M4A / M4B / 3GP / HEIC / AVIF | 品牌、时长、视频编码、分辨率、帧率、音频编码、声道、采样率、码率、轨道清单、创建时间、iTunes ilst 与 QuickTime mdta 标签 |
| Matroska / WebM | MKV / MKA / MKS / MK3D / WebM | DocType、TimestampScale、时长、EBML 元素树、各轨道类型与 CodecID、分辨率、帧率、声道、采样率、位深、Tags |
| RIFF | WAV / AVI(以及其他 RIFF form) | WAVE fmt (含 WAVE_FORMAT_EXTENSIBLE 子格式 GUID)、声道布局、采样率、位深、码率、data 字节数、时长、LIST/INFO 标签、AVI avih/strh/strf 流清单 |
| Ogg | Vorbis / Opus / Ogg-FLAC / Theora / Speex / Skeleton | 页与逻辑流计数、编解码器识别头字段、声道、采样率、标称码率、Theora 尺寸与帧率、Vorbis comment / OpusTags 标签、末页 granule |
| FLAC | 原生 .flac | STREAMINFO 全部字段(块大小、采样率、声道、位深、总样本数)、精确时长、metadata block 链、VORBIS_COMMENT 标签、PICTURE 封面 |
| ASF | WMV / WMA / ASF | 对象树、File Properties(时长已扣除 preroll)、WAVEFORMATEX 音频编码、视频尺寸与压缩 FOURCC、Content Description / Extended Content Description 标签、Windows FILETIME 创建时间 |
| MPEG 音频 | MP3 / MP2 / MP1 | MPEG-1/2/2.5 各 Layer、时长(优先 Xing/Info/VBRI)、采样率、声道与立体声模式、码率与 CBR/VBR 判定、ID3v2.2/2.3/2.4、ID3v1/1.1 |
| AAC (ADTS) | .aac / .adts | Profile(LC/HE-AAC…)、采样率、声道配置、帧长度、帧链校验、估算时长与平均码率 |
| AC-3 / E-AC-3 | .ac3 / .ec3 / .eac3 | bsid、fscod、acmod 声道模式、LFE、A/52 帧长表、标称码率、估算时长 |
| MPEG-TS | TS / M2TS / MTS / TP | 包长(188/192/204)自动判定、PAT/PMT 解析、节目与 PID 清单、流类型表、M2TS timecode 前缀识别 |
| MPEG 基本流 | .mpg / .m2v / .vob 等 | 序列头尺寸、帧率码、宽高比码、Program Stream 识别 |
| M3U / M3U8 | 纯文本播放列表 | 见下节 |
M3U / M3U8 播放列表
先澄清一个常见误解:M3U8 不是媒体容器,而是 HLS 的纯文本播放列表,内容是一份「分片在哪」的清单。 它本身不含音频或视频数据。本插件只解析这份清单文本,报告它的结构:
- 三种类型判定:普通 M3U 文件列表、HLS 媒体播放列表(分片清单)、HLS 主播放列表(多码率变体)。
- 媒体播放列表:分片数量、
#EXTINF时长累加总时长、#EXT-X-TARGETDURATION、媒体序号、 VOD 与直播判定(有无#EXT-X-ENDLIST)、#EXT-X-BYTERANGE字节范围、#EXT-X-DISCONTINUITY断点、#EXT-X-MAP初始化分片。 - 主播放列表:各变体流的码率 / 分辨率 / 编码 / 帧率 / 音频组,以及
#EXT-X-MEDIA备用音轨与字幕轨道。 - 加密声明:
#EXT-X-KEY的方法(AES-128 / SAMPLE-AES)、密钥 URI、IV —— 仅报告声明,绝不取用。 - 类型判定依据 RFC 8216:
#EXT-X-命名空间出现即视为 HLS;仅含#EXTINF的本地列表判为普通 M3U。
设计约束:只说话,不做事
这是刻意的设计,不是能力缺失:
- 工具只读。不写入、不复制、不移动、不重命名、不删除、不转码、不抽取、不转换、不播放。
- 不调用 ffmpeg 或任何外部程序,进程里没有任何
spawn/exec。 - 完全不联网。 进程里没有
fetch、没有node:http/node:https、没有node:net。 M3U8 里的分片 URL(即使是https://)只作为引用列出,绝不下载、不解密、不拼接、不合成媒体文件。 - 工具描述里写死了行为约束:报告完结论就停,让用户决定下一步; 除非用户另行明确要求,否则不得自行发起转码、剪辑、抽轨、打标签、下载、上传等后续动作。
已知限制(诚实说明)
- 不做语音转文字。 本插件读取的是容器、编解码器头与标签,不会识别音频/视频里说了什么内容。 本机没有 ffmpeg 和 whisper,因此转写功能不具备可行性,也未包含。
- 部分格式的时长是估算值,报告中会明确标注。 ADTS、AC-3、MPEG-TS 这类无索引的
「裸流」格式不含总时长字段,时长只能由「固定帧长 ÷ 文件大小」推算,因此:
- ADTS / AC-3 的报告会写出
durationBasis(估算依据); - MPEG-TS 不给时长,因为那需要遍历整个文件的 PCR/PTS 时间线,仅读头部做不到。 有索引的容器(MP4/MKV/FLAC/ASF 等)给出的是精确时长。
- ADTS / AC-3 的报告会写出
- 大文件只读头尾。 默认读前 8 MiB + 末 512 KiB。若
moov位于文件中部且超出该范围, 会提示需要调大headBytes;mdat巨大的文件不会整体读入。 - MPEG-TS 只扫描头部有限个包。 节目表(PAT/PMT)通常出现在文件开头,但若被截断或加密, 会明确报告「未找到 Program Map Table」而不是猜测。
- 码率为估算值。 由样本大小表或音频流字节数 ÷ 时长推算,与容器开销和真实播放统计略有出入。
- Ogg 不推导时长。 Ogg 存的是编解码器相关的 granule position 而非时间;精确时长需要读取文件 最后一个页,仅读头部做不到。因此报告给出末页 granule 值并说明这一点。
- M3U8 只读清单本身。 不下载任何分片,因此无法得知分片真实是否存在、是否可访问,
也无法验证分片内的实际编码参数与时长。报告中的时长来自
#EXTINF声明值,是声明值而非实测值。 - 不解码编解码器私有配置。 例如 Matroska 中 AAC 的
CodecPrivate(AudioSpecificConfig)只报告其存在,不解析内部字段。 - 不解析自定义标签。 未识别的
#EXT-*标签会被归类列出,不做语义解读。
自测
# 1) 生成 14 个结构正确的合成样本(覆盖全部新增容器)
node test/make-fixtures.mjs <fixture-dir>
# 2) 解析器单元测试(141 项断言)
node test/run-formats.mjs <fixture-dir>
# 3) EBML 变长整数专项测试(18 项断言,最高风险逻辑)
node test/probe-ebml.mjs
# 4) M3U8 解析器单元测试(75 项断言,无需外部文件)
node test/run-m3u8.mjs
# 5) 端到端:走真实的 defineTool 注册与 execute()/render() 全链路(14 格式)
node test/e2e-formats.mjs <fixture-dir>
# 6) 回归:用真实 MP3/MP4 文件验证旧路径未被破坏
node test/run.mjs <media-file>
node test/regression.mjs <media-file> [...]注意(依赖解析边界):
@deepseek-ai/dsh-tools是 peer dependency,它从 DSH 应用自己的node_modules解析,不在本插件目录内。因此:
- 解析器单元测试(1–4)不需要该依赖,可在源码目录直接运行;
- 端到端测试(5)需要该依赖,必须在能解析到 DSH 应用
node_modules的位置运行, 例如安装到 profile 后在 profile 目录内执行,或为插件目录建立@deepseek-ai/dsh-tools链接。这与插件本身无关,是 ESM 按脚本位置解析依赖的固有行为。
目录结构
dsh-media-inspect/
├── cordis.patch.yml # bundle 补丁层:把插件插入 profile
├── package.json # 声明 dsh.bundle.patch
├── lib/
│ ├── index.js # 工具注册、文件读取、格式嗅探、报告渲染
│ ├── mp4.js # ISO-BMFF(MP4/MOV/M4A)解析
│ ├── mp3.js # MPEG 音频帧 + ID3v2/ID3v1 解析
│ ├── m3u8.js # M3U / HLS 播放列表文本解析(纯本地,无网络)
│ ├── riff.js # RIFF:WAV / AVI(含奇数块对齐、嵌套 LIST 递归)
│ ├── flac.js # 原生 FLAC:位打包 STREAMINFO + metadata block 链
│ ├── ogg.js # Ogg:页/段装帧、Vorbis/Opus/FLAC/Theora/Speex 识别头
│ ├── matroska.js # Matroska/WebM:EBML 变长整数元素树
│ ├── asf.js # ASF:GUID 对象树(WMV/WMA)
│ └── elementary.js # 裸流:ADTS AAC、AC-3、MPEG-TS、MPEG 基本流
└── test/
├── make-fixtures.mjs # 合成样本生成器
├── run-formats.mjs # 新增容器解析器单元测试
├── probe-ebml.mjs # EBML 变长整数专项测试
├── run.mjs # MP4/MP3 解析器自测
├── run-m3u8.mjs # M3U8 解析单元测试
├── e2e-formats.mjs # 全格式端到端工具调用测试
├── e2e.mjs # M3U8 端到端测试
├── regression.mjs # MP4/MP3 回归测试
└── load-installed.mjs