cctv2333/dsh-vidlens

dsh-vidlens

DSH plugin: 18 local tools that watch a public video the way a person does - metadata, chapters, timestamped frames, subtitle-first transcripts, and 527-class sound events - without downloading the whole video.

待分类audio-analysiscordisdeepseek-harness

VidLens for DeepSeek Harness

把 vidlens 从一个 stdio MCP 外壳变成 DSH 原生插件:18 个 vidlens_* 工具、图片直接进对话、按工具设超时、外加三个零下载的缓存工具。

工程本体(Python)没有改一行逻辑:插件通过一个常驻桥进程调用 vl_mcp.py 里已经测过的工具函数,所以 MCP 外壳和插件的行为不会漂移。

  • 工程仓库(Python + MCP 服务器):
  • 本仓库(DSH 插件):
  • 插件要求:vidlens >= 1.4.0(video_soundscape 起)、Node ≥ 20、DSH >=0.2.1-rc.2 <0.3.0
用户: 这个视频讲了什么? <url>
  → vidlens_meta      0 下载:值不值得看
  → vidlens_plan      0 下载:切章节,挑 2–3 段
  → vidlens_window    只下这一窗的音频(或直接读缓存/字幕)
  → vidlens_sheet     只下这 20 秒,拼图带时间码,图直接附在结果里
  → vidlens_brief     平台字幕优先;无字幕才下音频做本地 ASR
  → vidlens_soundscape 台词之外的声音(吃饭/敲击/水声),带概率

相对 MCP 外壳的增强

能力 · MCP 外壳 · 本插件 工具名 · mcp__vidlens__video_meta · vidlens_meta(短、可读) 超时 · 客户端一个全局 60s · 每个工具自带预算(vidlens_brief 15 分钟,vidlens_scan 15 分钟) 图片 · 取决于客户端是否支持 MCP image content · 走宿主 attachments.saveImage,成为持久图片附件,同轮就能看 缓存意识 · 无 · vidlens_library(零网络列缓存)、vidlens_seek(零网络查原话) 批量筛选 · 无 · vidlens_compare(最多 8 个链接,0 媒体下载) 行为约束 · 只在 MCP instructions 里 · 独立的 system-prompt 小节:先 meta→plan→抽样,绝不下整片 取消 · 断开连接 · exec.signal 取消时重启桥进程,不留下卡死的下载 整片下载 · video_full(confirm=true) 存在 · 故意不提供:需要画面就用 sheet/frames/scan

安装

前置:先有一份 vidlens。 二选一:

pipx install "vidlens-mcp[all]"          # 推荐:无 checkout,命令叫 vidlens / vidlens-mcp
# 或
git clone https://github.com/cctv2333/vidlens && cd vidlens && install.cmd

然后装本插件(三选一):

# A. 本地目录(开发)
plugin_manager action=install_bundle target=D:\vidlens\vidlens-mcp-dsh

# B. GitHub 直装(本包无 build/prepare 脚本,不需要 allowBuilds 权限)
dsh plugin --profile desktop add github:cctv2333/dsh-vidlens#<sha>

# C. npm(发布后)
dsh plugin --profile desktop add dsh-vidlens

插件会自动找 Python 工程:/../vidlens → D:\vidlens\vidlens → $VIDLENS_PROJECT; 找不到时按 $VIDLENS_PYTHON / .venv / python 依次尝试。PyPI 安装的形态下, 把 projectDir 指到 pipx 的 venv 或直接设 VIDLENS_PROJECT 都行(模块名不变)。

安装后这个 bundle 会插入一行 Host 插件:

- insert:
    - id: dsh-vidlens
      name: 'dsh-vidlens'
      config: {}

想改成别的工程位置(例如换机器)就在 config 里写:

- insert:
    - id: dsh-vidlens
      name: 'dsh-vidlens'
      config:
        projectDir: D:\path\to\vidlens
        pythonPath: D:\path\to\vidlens\.venv\Scripts\python.exe
        warm: true

字段都可省略:projectDir 默认依次取 /../vidlens、D:\vidlens\vidlens、$VIDLENS_PROJECT;pythonPath 默认取工程 .venv 里的解释器。

工具(18 个)

基础四件(0 下载)

工具 · 用途 vidlens_meta(url) · 标题/UP主/时长/播放/平台字幕/平台标注音乐 + 注入风险扫描 vidlens_plan(url, window=300) · 按切点/长静音分章节 + 建议顺序 vidlens_subs(url, lang=zh) · 平台字幕(人工优先,其次自动/AI) vidlens_library(limit=20, query='') · 新增:本地缓存清单,避免重复下载

读内容

工具 · 下载量 · 用途 vidlens_window(url, start, end) · 0(有缓存/字幕)或该窗音频 · 某时间窗的台词与停顿 vidlens_brief(url, ...) · 平台字幕 0;无字幕才下音频 · 完整证据报告(结构/停顿/低置信词/广告段落/风险) vidlens_seek(query, url='') · 0(新增) · 在缓存转写里按关键词查原话 → 时间码 vidlens_audio(url, start, end) · 该段音频 · SenseVoice 语种/情感/事件 + 节拍与能量 vidlens_soundscape(url, start, end) · 该段音频 · 新增:AudioSet 527 类声音事件(吃饭/敲击/水声/碰撞…)+ 概率 + 时间码

看画面(图片直接进对话)

工具 · 下载量 · 用途 vidlens_sheet(url, start, end, cols, rows) · 该段(20s≈0.9MB) · 带绝对时间码的拼图 vidlens_frames(url, at=[...]) · 该段 · 最多 6 张精确帧(读小字用) vidlens_scan(url, n=24) · 最低画质整片(7min≈14-21MB,用完即删) · 全片抽样拼图(无音频视频)

判断 / 长视频 / 自检

工具 · 用途 vidlens_comments(url, limit=40) · 评论区互动比、正负面、争议度、高赞评论 + 评论配图 vidlens_compare(urls=[...]) · 新增:批量元数据对比(0 媒体下载,最多 8 个) vidlens_job_start(url, ..., full=False) · 长视频后台任务,立即返回 job_id vidlens_job(job_id, wait_seconds=20) · 轮询阶段/百分比,完成返回报告 vidlens_models(action=list) · 本地模型目录与硬件建议(只读,不自动下载) vidlens_doctor() · 自检 python/ffmpeg/yt-dlp/依赖/模型/磁盘/网络

架构

DSH Host (index.js)
  ├─ 18 × ctx.tools.register(...)        原生工具 + 每工具 timeoutMs
  ├─ ctx.systemPrompt.section('vidlens') 取样协议(meta→plan→抽样)
  └─ Bridge (常驻)  ──stdin/stdout JSONL──▶  python -u bridge/vidlens_bridge.py
                                                │
                                                ├─ import vl_mcp   (复用工具函数)
                                                ├─ import vidlens_web / _extra / _sanitize
                                                └─ out/<id>/        (缓存,进程重启不丢)

为什么不是直接把 MCP 服务器挂上来:MCP 客户端只有一个全局工具超时,长视频 ASR 会被误杀;图片是否进模型取决于客户端实现;也拿不到「缓存清单 / 关键词定位」这类只在本地才有答案的能力。桥进程把「已验证的 Python 逻辑」和「宿主的原生能力」接在一起,两边都不用重写。

协议(每行一个 JSON)

// 启动
{"op":"ready","ok":true,"pid":1234,"project":"D:\\vidlens\\vidlens","python":"3.12.10","tools":["meta",...]}
// 请求 → 响应
{"id":7,"tool":"sheet","args":{"url":"...","start":"0","end":"20"}}
{"id":7,"ok":true,"text":"...","images":[{"path":"...jpg","mediaType":"image/jpeg","name":"sheet_0_20000.jpg"}]}
{"id":8,"ok":false,"error":"ValueError: ...","trace":"..."}

sys.stdout 在导入任何库之前就被指向 stderr,所以依赖里的杂散 print 不可能污染协议;桥只把帧写进保存下来的真实 stdout。

多进程安全:DSH 会话、MCP 服务器、插件桥是不同进程,进程内 threading.Lock 互相看不见。 工程侧用 vidlens_web.CrossProcessLock(进程内 RLock + out/.media.lock 文件锁,msvcrt/flock) 把「一个下载口」扩展到整台机器;超时可用 VIDLENS_LOCK_TIMEOUT(默认 900s)调整。 实测两个进程同时调 video_sheet:第二个的 acq 时间落在第一个 end 之后(串行,不互相踩)。

验证

离线(不联网、不下媒体)

node D:\vidlens\vidlens-mcp-dsh\tools\selftest.mjs
# 96/96 checks passed(工具表 + 桥握手 + library/models/seek + 强制杀进程后自愈)

带真实链路(约 1MB 媒体)

node D:\vidlens\vidlens-mcp-dsh\tools\selftest.mjs --live
# 98/98 checks passed

安装后在 DSH 里的实测(本机 2026-10-25,全部走原生工具通道)

调用 · 结果 vidlens_library(limit=6) · 9 个缓存视频,标题/时长/段数/来源/占用/时间齐全(out/ 里的 bili/、comment_pics/ 等非视频目录已自动排除) vidlens_doctor() · 11/11:python 3.12.10、ffmpeg 7.1、yt-dlp 2026.10.21、4 个依赖、whisper 461MB、磁盘 332GB、B站 API 200 vidlens_meta(BV1PinG6fEPX) · 真实标题/UP主/139514 播放;正确报出「字幕需要登录」 vidlens_plan(window=120) · 3 章节,0 下载 vidlens_window(02:10–02:25) · asr(cached),0 下载直接读缓存 vidlens_seek("宪法") · 3 条原文 + 时间码(00:20.460、02:17.720…),0 网络 vidlens_sheet(60–72s, 3×2) · 下载 12 秒,产出 1440×540 拼图,图片作为持久附件进入对话(时间码 00:00:59.995 … 00:01:09.594) vidlens_frames([63, 68]) · 2 张 960×540 帧,同一条结果里两张图都在 vidlens_compare(2 个链接) · 一张 markdown 表,0 媒体下载 vidlens_job_start → vidlens_job · 起任务拿到 job_id=6652ac4e,轮询后返回完整 brief(asr(cached),含低置信词/停顿/广告段) vidlens_meta(错误 URL) · 可读错误:ERROR: meta failed rc=1: ... HTTP Error 404,工具不崩

拼图实测(时间码烧在每格左上角):

发布(维护者)

  • CI:.github/workflows/ci.yml —— 会 checkout 两个仓库(本插件 + cctv2333/vidlens 作为兄弟目录),

装 Python 核心后跑离线自检;另外两个 job 校验 manifest 可发布、tarball 含 bridge/ 与 LICENSE。

  • 发版:打 tag 即发布 npm。
git tag v1.2.0 && git push origin v1.2.0

release.yml 会 npm pack、npm publish --access public,走 Trusted Publishing(OIDC)—— CI 里没有任何长期 token。npm 的 publisher 只能在包存在后配置,所以首次发布要在本地做一次 (npm stage publish → npm stage approve,全程不需要把 token 交给 CI,见 RELEASING.md),之后打 tag 即可。

注意:PowerShell 5.1 不支持 &&,用 ; 或分行。

实现笔记

  • `output.schema` 不能用 `{type:'json'}`:宿主对工具输出 schema 做严格校验,只接受

object/array/string/number/integer/boolean/null。第一版用了 {type:'json'},安装直接 application: failed(JsonSchemaError: unsupported JSON schema)。现在写成显式的 object schema(text + images[])。

  • 被杀掉的旧进程不能污染新进程:超时/取消会 kill() 工作进程并在同一 tick 重建。旧

进程的 exit 事件是异步到的,必须先判 this.child !== child 再清理,否则它会把新 进程上排队的请求全部 reject(这个 bug 是自检里的「强制杀进程后自愈」用例抓到的)。

  • 本插件不导出 `Config`:Config.listConfigs 里这一行显示 status: absent(没有配置

schema),但 config: 里的 projectDir / pythonPath / warm 仍会原样传给 apply()。 不导出 schema 是刻意的:schema 需要 schemastery,而插件的解析链未必能找到宿主那份 @deepseek-ai/schemastery;宁可少一个设置表单,也不要一个「载入期 import 失败 → 18 个工具整体消失」的失败模式。

  • 图标:icon.svg 是原创矢量图(2042 字节,well-formed XML,256×256,边缘圆角 +

时间码刻度 + 镜头环 + 播放三角)。结构校验通过;Plugin Manager 里的实际渲染效果 没有在浏览器里验证(无头浏览器对 file: / data: 导航超时),这一项留待用户目视确认。

路线图

产品级路线图(已做 / 未做 / 验收标准 / 不做清单)在工程仓库: vidlens/ROADMAP.md。

插件专属待办,按工作量从小到大:

  1. Config schema(现在 status: absent,只能手改 YAML)
  2. /vl 斜杠命令
  3. present 交付物卡片(brief.md / 拼图)
  4. 右侧栏 Web 面板(缓存列表 + brief 预览 + 时间轴)
  5. 设置页(模型路径 / 代理 / cookie)

边界与已知限制

  • job 状态在进程内存:vidlens_job_start 起的任务,桥进程重启(超时/取消/宿主重启)后会消失;已下的缓存不丢,重跑即可。
  • 取消 = 杀桥进程:Python 侧没有协作取消,所以被取消/超时的调用会重启工作进程(缓存在磁盘上,代价很小)。
  • 需要 cookie 的站点(抖音、B 站 AI 字幕)默认不碰:按报错提示设 VIDLENS_COOKIES_FROM_BROWSER=edge 或 VIDLENS_COOKIES=path\cookies.txt。
  • 不下整片:video_full 故意没有移植。整片画面需求用 vidlens_scan(最低画质、用完即删)。
  • PyPI 形态也能接:工程装成 wheel 后没有 vidlens.py 旁边的 checkout 标记,插件的

目录嗅探找不到它;把 config.projectDir 指到 pipx 的 venv 目录(或任意含 vidlens.py 的目录),或设 VIDLENS_PROJECT 即可。安装形态下 out/ 会落在 %LOCALAPPDATA%\vidlens\out。

  • Windows 优先:工程默认路径与 .venv\Scripts\python.exe 是 Windows 习惯;Linux/macOS 用 projectDir + pythonPath 显式指定即可(跨进程锁在 POSIX 用 flock)。
  • 工程本体仍无 LICENSE,公开分发前需项目所有者选定;本包 license 标为 UNLICENSED。