@dsh-gis/dsh-video-studio-skill 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -3
  3. package/THIRD_PARTY_NOTICES.md +41 -0
  4. package/cordis.patch.yml +5 -0
  5. package/docs/demo-pil-sheet.png +0 -0
  6. package/icon.svg +19 -0
  7. package/index.js +96 -0
  8. package/locale/en.json +6 -0
  9. package/locale/zh.json +6 -0
  10. package/package.json +66 -4
  11. package/skills/video-studio/SKILL.md +642 -0
  12. package/skills/video-studio/assets/film.json +97 -0
  13. package/skills/video-studio/assets/scenes.py +227 -0
  14. package/skills/video-studio/assets/score_demo.json +307 -0
  15. package/skills/video-studio/assets/web/engine.js +485 -0
  16. package/skills/video-studio/assets/web/film.js +223 -0
  17. package/skills/video-studio/assets/web/index.html +22 -0
  18. package/skills/video-studio/assets/web/qa_text.js +111 -0
  19. package/skills/video-studio/assets/web/style.css +22 -0
  20. package/skills/video-studio/references/audio.md +392 -0
  21. package/skills/video-studio/references/frame-qa.md +502 -0
  22. package/skills/video-studio/references/pipeline.md +153 -0
  23. package/skills/video-studio/references/pitfalls.md +83 -0
  24. package/skills/video-studio/references/quality-gates.md +225 -0
  25. package/skills/video-studio/references/scene-authoring.md +237 -0
  26. package/skills/video-studio/references/sfx-design.md +246 -0
  27. package/skills/video-studio/references/web-engine.md +175 -0
  28. package/skills/video-studio/requirements.txt +29 -0
  29. package/skills/video-studio/scripts/filmkit.py +1544 -0
  30. package/skills/video-studio/scripts/qa_frames.py +1886 -0
  31. package/skills/video-studio/scripts/render.py +1024 -0
  32. package/skills/video-studio/scripts/scorekit.py +1890 -0
  33. package/skills/video-studio/scripts/selfcheck.py +568 -0
  34. package/skills/video-studio/scripts/sfxkit.py +3310 -0
  35. package/skills/video-studio/scripts/webengine.py +1324 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 tj
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,186 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @dsh-gis/dsh-video-studio-skill
2
+
3
+ ![version](https://img.shields.io/badge/version-0.4.0-blue) ![license](https://img.shields.io/badge/license-MIT-green)
4
+
5
+ **DeepSeek Harness 技能插件:用代码从零生成中文视频。**
6
+
7
+ 写剧本 → edge-tts 旁白 → **实测时长**排时间轴 → **提示点**驱动配乐与音效 → PIL 或浏览器逐帧渲染 →
8
+ ffmpeg 编码 → 采样级混音 → **四层质检**(容器 / 信号 / 时间 / 页面)。
9
+ 零素材、可复现、可断点续跑、可脚本化验收;装成插件后,整片生产流程随技能一起进入每个会话。
10
+
11
+ > 源自 `dsh-v` 资产包的 `02-技能包-video-studio`(817 个 DSH 会话的考古分析 + 5 套现存工程逆向 + 本机实测)。
12
+ > **v0.2.0**:用这套技能真的做出一部 11 分钟成片后,发现 10 处"文档承诺了、代码没做到"的地方
13
+ > (门禁失效、缓存不校验、stage 假独立、mux 二次编码等),全部修掉并补了 14 条回归断言。
14
+ > **v0.3.0**:与另一部 6 分半成片(`ai-history-film`)对照后,补上本项目最缺的四块——
15
+ > 物理建模音效库、程序化配乐、浏览器逐帧渲染引擎、帧级质检,以及把三者串起来的**提示点系统**。
16
+ > **v0.4.0**:修掉 4 处"门禁看着干净、其实没在查"的静默问题(`--resume` 复用旧分块、
17
+ > `music.mode=off` 仍混入旧配乐、PIL 路线音画同步恒空、亮度静止判据误报 4 段),
18
+ > 补上仓库级体检(`tools/ci_check.py`)、CI、`requirements.txt`,并修掉管道中文乱码。
19
+ > 详见 [CHANGELOG.md](CHANGELOG.md) 与 SKILL.md §13。
20
+
21
+ ## 安装
22
+
23
+ 桌面版:插件管理器 → 填 `@dsh-gis/dsh-video-studio-skill`(或本地目录 `D:\self\code\dsh-video-studio-skill`)
24
+
25
+ 命令行:
26
+
27
+ ```bash
28
+ dsh plugin --profile desktop add "@dsh-gis/dsh-video-studio-skill"
29
+ # 本地调试(不发布也能装):
30
+ dsh plugin --profile desktop add "D:/self/code/dsh-video-studio-skill"
31
+ ```
32
+
33
+ 安装后在「插件」页启用 `video-studio` 这一行,新开会话即可在技能目录看到 **video-studio**。
34
+
35
+ ### 与手工技能目录的关系
36
+
37
+ 技能按 rank 解析:`~/.dsh/skills`(rank 400)**优先于**插件提供的 bundled 技能根(rank 600)。
38
+ 如果你之前手工装过 `~/.dsh/skills/video-studio`,它会把插件版本遮住。装好插件后**把旧目录移出 `~/.dsh/skills` 根目录**(只改名不够——扫描认的是 `<root>/<name>/SKILL.md`,`.bak` 后缀的目录照样会被扫到):
39
+
40
+ ```bash
41
+ mkdir -p ~/.dsh/backup
42
+ mv ~/.dsh/skills/video-studio ~/.dsh/backup/video-studio.bak-$(date +%Y%m%d)
43
+ ```
44
+
45
+ 需要回滚时把目录移回 `~/.dsh/skills/video-studio` 即可。
46
+
47
+ ## 效果(不是渲染出来的"宣传图",是默认模板片的真实抽帧)
48
+
49
+ <p align="center"><img src="docs/demo-pil-sheet.png" width="100%" alt="默认模板片联系表:开场 / 正文卡片 / 正文卡片 / 收尾"></p>
50
+
51
+ 上面四帧是用仓库自带的 `assets/film.json` + `assets/scenes.py` 从零跑一遍 `python render.py` 的
52
+ `work/qa/sheet.png`,未经任何修图。配套实测(同一台机器):
53
+ **时长 30.10 s / 1920×1080 / 30 fps / h264+aac 48 kHz / -16.0 LUFS / 真峰 -1.2 dBTP / 黑帧 0 /
54
+ 帧级深检:闪烁 0、空窗 0、画面静止 0**(音画同步在 PIL 路线上需要写 `visual_at` 才会真的查,见 SKILL.md §7)。
55
+
56
+ ## 用法
57
+
58
+ 触发词:做一个视频 / 生成宣传片 / 把报告变成视频 / 做动画 / 配音配字幕 / 出成片 /
59
+ 修视频音画不同步 / 视频画质糊,或提到 ffmpeg、edge-tts、逐帧渲染、字幕、分镜、配乐、混音。
60
+
61
+ 最短路径(技能 `SKILL.md` 第 1 节有完整版):
62
+
63
+ ```bash
64
+ mkdir -p myfilm && cd myfilm
65
+ cp <SKILL_DIR>/assets/film.json . # 剧本模板
66
+ cp <SKILL_DIR>/assets/scenes.py . # 场景模板
67
+ cp <SKILL_DIR>/scripts/*.py . # filmkit/render/selfcheck + sfxkit/scorekit/qa_frames/webengine
68
+ cp -r <SKILL_DIR>/assets/web ./web # 只在走浏览器引擎时需要
69
+
70
+ python selfcheck.py # 24 条环境/回归断言(20 秒,不联网)
71
+ python render.py --stage stills --stills "l01:3,l02:5" # 母版预览(缺 tts/layout 会自动补跑)
72
+ python render.py --script film.json --scenes scenes.py --out out/film.mp4 --work work
73
+ ```
74
+
75
+ 分阶段(每步落盘、可单独重跑):
76
+
77
+ ```
78
+ tts → layout → cues → score → sfx → audio → frames → mux → qa
79
+ ```
80
+
81
+ **三种玩法**:
82
+
83
+ | 想要 | 怎么做 |
84
+ |---|---|
85
+ | 只加"该响的地方响一下" | 写 `film.json` 的 `sfx.cues` 或 `scenes.py` 的 `cues()` 钩子 → `--stage cues sfx audio` |
86
+ | 整片要一段像样的配乐 | 设 `bpm` / `music.mode=score` → `--stage score` |
87
+ | 画面要粒子/形变/着色器 | `--engine web` + 拷 `assets/web/`,改页面里的场景代码 |
88
+
89
+ **v0.4 的两个新开关**(都是"让门禁真的会失败",不是新玩具):
90
+
91
+ | 想要 | 怎么做 |
92
+ |---|---|
93
+ | 让 PIL 路线的音画同步门禁真的生效 | cue 加 `"visual_at": 绝对秒`;CI 里再加 `QA_REQUIRE_SYNC=1` 把"没查"变成失败 |
94
+ | 浏览器渲染要跨会话字节级可复现 | `--deterministic`(或 `WEBENGINE_DETERMINISTIC=1`),代价约 +22%/帧 |
95
+
96
+ `<SKILL_DIR>` 是 `skill` 工具加载时回报的 resourceBase 目录(`.../skills/video-studio/`)。
97
+
98
+ 分阶段(v0.2 起**每个 stage 只做自己的事**;完整 10 个 stage 见上):`--stage tts | layout | cues | score | sfx | audio | frames | mux | qa | stills`。
99
+
100
+ 长片:`--stage frames --jobs 4`(按绝对帧号分块并行)+ `--resume`(中断只补缺块)。
101
+
102
+ ## 这个技能解决什么
103
+
104
+ | 铁律 | 怎么保证 |
105
+ |---|---|
106
+ | 音画不同步 | 时间轴由 TTS **实测时长**反推,绝不按字数估算 |
107
+ | 文字发虚 | PIL 帧走 `rawvideo` 直通 libx264,不用 cv2 中间文件二次压缩 |
108
+ | 后半段静音 | numpy 采样级混音,不用一条 ffmpeg 命令喂上百个输入 |
109
+ | 该有的淡入/字幕静默消失 | 质检门禁查"必须有"和"不能有"两类断言 |
110
+ | 成片"像草稿" | -16 LUFS / 真峰 ≤ -1 dBTP / 编码锐度比 ≥ 0.85 |
111
+ | **声音和画面对不上(v0.3)** | **提示点系统**:画面登记 cue → 音效按 cue 合成,改节奏不用重新对时间 |
112
+ | **声音单薄、只有"叮叮咚咚"(v0.3)** | `sfxkit` 物理建模音效 + `scorekit` 一张和弦表贯穿全片 |
113
+ | **一帧白闪/两秒空窗没人发现(v0.3)** | `qa_frames` 帧级深检:单帧闪烁、画面空窗、音画同步 |
114
+
115
+ ## 文件结构
116
+
117
+ ```
118
+ index.js 插件入口:把 skills/ 挂成 bundled 技能根
119
+ cordis.patch.yml 组合包 patch(insert: video-studio)
120
+ icon.svg / locale/*.json 插件页展示元数据
121
+ skills/video-studio/
122
+ SKILL.md 主线:上手 / 八阶段 / 引擎选型 / 画质 / 声音 / 提示点 / 停留窗口 / 质检 / 故障速查
123
+ references/ pipeline · scene-authoring · audio · sfx-design · web-engine · frame-qa
124
+ quality-gates · pitfalls
125
+ scripts/filmkit.py 生产内核(字体/排版/字幕/音频总线/CueBus/TTS/时间轴/编码/质检)
126
+ scripts/render.py 编排器(10 个独立 stage、pil|web 双引擎、分块并行、断点续跑、母版预览)
127
+ scripts/selfcheck.py 回归自检(24 条"曾真的坏过"的断言)
128
+ scripts/sfxkit.py 物理建模音效库(24 配方,scipy 可选)
129
+ scripts/scorekit.py 程序化配乐(和弦表 / 分段能量 / 吸气)
130
+ scripts/webengine.py 浏览器逐帧渲染(CDP 截图、分块并行、崩溃重开、cue 导出、文字质检)
131
+ scripts/qa_frames.py 帧级深检(单帧闪烁 / 画面空窗 / 画面静止 / 音画同步 / 亮度响度曲线)
132
+ requirements.txt Python 依赖(必需 / 强烈建议 / 可选三档,带注释)
133
+ assets/film.json 剧本模板(含 hold / bpm / music / sfx.cues)
134
+ assets/scenes.py 场景模板(开场 / 正文卡片 / 收尾 + cues() 钩子)
135
+ assets/web/ 浏览器页面模板(原生 Canvas2D 确定性时间轴)
136
+ tools/ci_check.py 仓库级体检(语法/JSON/依赖白名单/打包卫生/文档引用,不需 ffmpeg)
137
+ .github/workflows/ci.yml CI:repo 体检(ubuntu+windows)+ 技能自检(ubuntu)
138
+ ```
139
+
140
+ ## 环境前提
141
+
142
+ **必需**:ffmpeg + Python 的 numpy / Pillow / edge-tts。
143
+ **可选**:cv2(编码锐度比)、scipy(音效滤波加速,缺了走 FFT 卷积)、
144
+ playwright + Chromium/Edge(只在 `--engine web` 时需要)。
145
+ 不需要 moviepy / pydub / soundfile / librosa / manim——本技能一行都不 import 它们。
146
+
147
+ 依赖清单有机器可读的一份,别再手抄:
148
+
149
+ ```bash
150
+ pip install -r skills/video-studio/requirements.txt # 必需 + 强烈建议;可选项目已注释,按需打开
151
+ ```
152
+
153
+ `SKILL.md` 第 12 节是作者机器(Windows 11 + Ryzen AI 9 HX 370)的实测基准,**换机请先重测**:
154
+ `ffmpeg -version`、`python -c "import numpy,PIL,cv2"`、中文字体文件、`edge-tts --list-voices`。
155
+ ffmpeg 路径可用环境变量 `FILMKIT_FFMPEG` 覆盖,字体候选在 `filmkit.FONT_CANDIDATES`。
156
+
157
+ ## 更新日志
158
+
159
+ 见 [CHANGELOG.md](CHANGELOG.md)。
160
+
161
+ ## 兼容性
162
+
163
+ peer 范围 `@deepseek-ai/dsh-skill-filesystem >=0.1.0-rc.6 <0.3.0-0`,覆盖 DSH 0.1.x / 0.2.x 的**正式版**。
164
+
165
+ ⚠️ **预发布版按 semver 规则不满足这个范围**:`>=0.1.0-rc.6 <0.3.0` 这组比较器里没有带预发布标签的
166
+ 基准,所以 `0.2.2-rc.1` 这类版本 `semver.satisfies()` 返回 false(实测)。因为该 peer 标了
167
+ `optional`,pnpm 不会因此阻断安装;插件入口也已经把依赖改成 `apply` 内按需 `import`——
168
+ 缺这个包时**只降级(不挂载 bundled 技能根)并打一条能照着做的日志,不会让整个插件行加载失败**。
169
+
170
+ ## 仓库自检(给贡献者与 CI 用,不是给用户用的)
171
+
172
+ ```bash
173
+ python tools/ci_check.py -v # 11 项:py 语法 / node --check / JSON / 技能清单 / 依赖白名单 /
174
+ # npm pack 打包卫生 / 文档路径引用 / Python 3.9 语法 /
175
+ # Markdown 围栏平衡 / CI workflow 语法 / 单文件体积
176
+ ```
177
+
178
+ 它**不需要 ffmpeg、字体或网络**,任何机器都能跑;它检查的是"这个仓库作为可分发包是否完整"。
179
+ **它不能替代** `skills/video-studio/scripts/selfcheck.py`——那个要 ffmpeg + 中文字体,真的调编码器,
180
+ 查的是"技能本身还能不能出片"。两层都在 `.github/workflows/ci.yml` 里跑。
181
+
182
+ ## License
183
+
184
+ MIT。新增的四个模块(sfxkit / scorekit / webengine / qa_frames)的**算法思想**改编自
185
+ [ai-history-film](https://github.com/Re-Summer75/ai-history-film)(MIT),未复制其文件、未引入其三方依赖;
186
+ 详见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
@@ -0,0 +1,41 @@
1
+ # 第三方组件与改编声明
2
+
3
+ 本项目以 **MIT** 许可发布(见 [LICENSE](LICENSE))。下面是运行期需要留意的东西。
4
+
5
+ ## 1. 算法思想改编(非代码拷贝)
6
+
7
+ `skills/video-studio/scripts/` 下四个 v0.3.0 新增模块的**算法思想**改编自开源项目
8
+ [ai-history-film](https://github.com/Re-Summer75/ai-history-film)(**MIT**,作者 Re-Summer75):
9
+
10
+ | 本项目的文件 | 改编自 | 改编内容 |
11
+ |---|---|---|
12
+ | `sfxkit.py` | `sfx/`(core, synth, filters, modal, texture, space, dynamics, analysis, master, recipes) | 模态合成的物理模型(材质损耗因子、形状模态比、接触力脉冲)、泊松/Cox 事件纹理、镜像声源混响、BS.1770 响度与块级动态处理 |
13
+ | `scorekit.py` | `video/audio/film_score.py`、`inst.py` | 一张和弦表贯穿全片的编排思路、分段能量与律动层、重击前"吸气"、段落边界对齐小节线 |
14
+ | `webengine.py` + `assets/web/` | `video/render.py`、`video/web/js/engine.js` | 无头浏览器逐帧 seek + CDP 截图的确定性渲染流程、分块并行与断点续跑、音效提示点(cue)导出 |
15
+ | `qa_frames.py` | `video/qa_sync.js`、`video/qa_text.js`、`docs/开发日志.md` | 单帧闪烁的分块判据、画面空窗检测、音画事件同步对照、页面文字重叠/出画/一闪而过检查 |
16
+
17
+ **说明**:以上均为"读懂思路后用本项目约束重写",**没有复制上游文件**,也没有引入上游的任何第三方依赖。
18
+ 本项目未使用也不分发 three.js、GSAP(含 CustomEase / SplitText / DrawSVGPlugin)、Inter / JetBrains Mono / Noto Sans SC 字体文件——
19
+ 浏览器渲染模板 `assets/web/` 只用原生 Canvas2D 与系统字体,因此不产生额外的许可义务。
20
+
21
+ ## 2. 运行期依赖(不随仓库分发)
22
+
23
+ | 组件 | 用途 | 许可 | 必需? |
24
+ |---|---|---|---|
25
+ | FFmpeg | 编码 / 解码 / 响度测量 / 黑帧检测 | LGPL-2.1+ / GPL(取决于构建) | **必需** |
26
+ | Python 3.9+ | 运行时 | PSF-2.0 | **必需**(本仓库 `tools/ci_check.py` 用 `ast.parse(feature_version=(3,9))` 校验了 3.9 **语法**兼容;作者机器实际运行在 3.12,未做 3.9 运行期实测) |
27
+ | numpy | 全部数值计算 | BSD-3-Clause | **必需** |
28
+ | Pillow | PIL 引擎逐帧绘制、联系表、深检图 | HPND | **必需**(PIL 引擎) |
29
+ | edge-tts | 旁白合成(走微软在线语音服务) | **LGPLv3**(客户端;实测 7.3.1 的分类器为 `License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)`);**服务本身另有条款** | 有旁白时必需 |
30
+ | opencv-python(cv2) | 编码锐度比(Laplacian 方差) | Apache-2.0 | 可选(缺了跳过锐度门禁) |
31
+ | scipy | sfxkit 的时间域滤波加速 | BSD-3-Clause | 可选(缺了走 FFT 卷积兜底) |
32
+ | playwright | web 引擎驱动 Chromium/Edge | Apache-2.0 | 可选(只在 `--engine web` 时需要) |
33
+ | Chromium / Microsoft Edge | web 引擎的渲染内核 | BSD-3-Clause / 微软条款 | 可选 |
34
+
35
+ **字体**:PIL 引擎使用系统自带中文字体(Windows 的 `msyh.ttc`/`msyhbd.ttc` 等),
36
+ 字体文件**不随本仓库分发**;能否商用请自行确认字体的许可。web 引擎的页面模板默认回落到系统字体。
37
+
38
+ ## 3. 内容许可提醒
39
+
40
+ `ai-history-film` 的**代码**是 MIT,但它的**成片与 `docs/` 文档**是 CC BY-NC-SA 4.0(不可商用)。
41
+ 本项目只借用了代码里的算法思路,**不包含**任何来自该片的画面、音频、文本或图片素材。
@@ -0,0 +1,5 @@
1
+ # dsh bundle patch: inserts this plugin into a profile's layer stack so the
2
+ # filesystem skill provider mounts the bundled skills/ tree (see index.js).
3
+ - insert:
4
+ - id: video-studio
5
+ name: '@dsh-gis/dsh-video-studio-skill'
Binary file
package/icon.svg ADDED
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-label="Video studio">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
4
+ <stop offset="0" stop-color="#13233a"/>
5
+ <stop offset="1" stop-color="#0a1420"/>
6
+ </linearGradient>
7
+ <linearGradient id="play" x1="0" y1="0" x2="0" y2="1">
8
+ <stop offset="0" stop-color="#5ee7ff"/>
9
+ <stop offset="1" stop-color="#2f9dff"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect width="64" height="64" rx="14" fill="url(#bg)"/>
13
+ <g fill="none" stroke="#9fb4cc" stroke-width="2" stroke-linecap="round">
14
+ <rect x="12" y="14" width="40" height="36" rx="5"/>
15
+ <path d="M12 24h40M12 40h40M24 14v36M40 14v36"/>
16
+ </g>
17
+ <path d="M27 27.5v13l11-6.5z" fill="url(#play)"/>
18
+ <circle cx="49" cy="18" r="4.5" fill="#ff5c72"/>
19
+ </svg>
package/index.js ADDED
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @dsh-gis/dsh-video-studio-skill — DeepSeek Harness 技能插件
3
+ *
4
+ * 用代码从零生成中文视频:剧本 → edge-tts 旁白 → 实测时长排时间轴 →
5
+ * 逐帧渲染 → ffmpeg 编码 → numpy 采样级混音 → 自动质检。
6
+ *
7
+ * 启动时把包内 skills/ 挂成 bundled 技能根(rank 600),不改动
8
+ * ~/.dsh/skills,也不写任何用户目录;卸载插件即整体消失。
9
+ *
10
+ * 依赖说明:`@deepseek-ai/dsh-skill-filesystem` 在 package.json 里是**可选 peer**
11
+ * (peerDependenciesMeta.optional)。因此这里**不能**用静态 import——那样在缺依赖的
12
+ * profile 里整个插件行会加载失败,连错误都只能在 loader 日志里看到。
13
+ * 改成 apply 内按需 import:缺依赖时打一条能照着做的日志,本行插件照常加载。
14
+ */
15
+ import { existsSync } from "node:fs";
16
+ import { fileURLToPath } from "node:url";
17
+ import { join } from "node:path";
18
+
19
+ /** 包内技能根:<pkg>/skills/<name>/SKILL.md */
20
+ const bundledSkillDir = fileURLToPath(new URL("./skills/", import.meta.url));
21
+ /** 技能名(与 skills/video-studio/SKILL.md 的 frontmatter name 一致) */
22
+ const SKILL_NAME = "video-studio";
23
+ /** 提供 bundled 技能根的能力包(可选 peer,缺了本插件只是个空行)。 */
24
+ const PROVIDER_PKG = "@deepseek-ai/dsh-skill-filesystem";
25
+
26
+ /** Cordis 插件名(与 cordis.patch.yml 的 row id 一致)。 */
27
+ export const name = "video-studio";
28
+ /** 依赖 DSH 技能注册表。 */
29
+ export const inject = ["skills"];
30
+
31
+ /**
32
+ * 注册 bundled 技能根。
33
+ *
34
+ * 三件事任何一件不成立都只打日志、不抛错——插件本身没有"必须成功"的业务,
35
+ * 挂不上技能是降级,不是崩溃:
36
+ * 1. 找不到包内 SKILL.md(打包漏了文件 / 被裁剪)
37
+ * 2. 运行时没有 ctx.skills(profile 没装技能注册表)
38
+ * 3. 可选 peer 没装(只装了本插件)
39
+ *
40
+ * @param ctx - 携带 skills 服务的 Cordis 上下文。
41
+ */
42
+ export async function apply(ctx) {
43
+ const manifest = join(bundledSkillDir, SKILL_NAME, "SKILL.md");
44
+ if (!existsSync(manifest)) {
45
+ warn(ctx, `找不到 ${manifest},本次不挂载技能(检查包内容是否完整)`);
46
+ return;
47
+ }
48
+ if (!ctx?.skills || typeof ctx.skills.registerProvider !== "function") {
49
+ warn(ctx, "运行时没有 skills 服务,本次不挂载技能(profile 需要 @deepseek-ai/dsh-skill)");
50
+ return;
51
+ }
52
+
53
+ let applyFilesystemProvider;
54
+ try {
55
+ ({ apply: applyFilesystemProvider } = await import(PROVIDER_PKG));
56
+ } catch (error) {
57
+ warn(
58
+ ctx,
59
+ `缺少可选依赖 ${PROVIDER_PKG},本次不挂载技能。` +
60
+ `安装(版本需满足 peer 范围):dsh plugin --profile <profile> add ${PROVIDER_PKG}` +
61
+ `(${error?.code ?? error?.message ?? error})`,
62
+ );
63
+ return;
64
+ }
65
+
66
+ applyFilesystemProvider(ctx, {
67
+ providerName: "video-studio",
68
+ includeDefaultRoots: false,
69
+ bundledSkillDir,
70
+ watch: false,
71
+ });
72
+ }
73
+
74
+ /**
75
+ * 打一条降级日志。
76
+ *
77
+ * Cordis 的 logger 是可选注入(不同版本形态不同:有的是 logger 服务、有的只有
78
+ * console 桥接),这里按能力探测,永不因为"日志打不出来"而让插件加载失败。
79
+ *
80
+ * @param ctx - Cordis 上下文。
81
+ * @param message - 面向用户的说明(中文,带下一步动作)。
82
+ */
83
+ function warn(ctx, message) {
84
+ const text = `[video-studio] ${message}`;
85
+ for (const logger of [ctx?.logger, ctx?.root?.logger]) {
86
+ try {
87
+ if (typeof logger?.warn === "function") {
88
+ logger.warn(text);
89
+ return;
90
+ }
91
+ } catch {
92
+ /* 日志失败不归插件管,落到下面的 console 兜底 */
93
+ }
94
+ }
95
+ console.warn(text);
96
+ }
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Video studio",
4
+ "description": "Code-generated Chinese videos: script, edge-tts narration, measured timeline, deterministic frame rendering, ffmpeg encoding, sample-level mixing and automated QA. Covers promos, report-to-video, narration with subtitles, and A/V sync fixes."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "视频工作室",
4
+ "description": "用代码从零生成中文视频:写剧本 → edge-tts 旁白 → 实测时长排轴 → 逐帧渲染 → ffmpeg 编码 → 采样级混音 → 自动质检。适用于做宣传片、把报告变成视频、配音配字幕、修音画不同步。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "@dsh-gis/dsh-video-studio-skill",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.0",
4
+ "description": "Video Studio skill plugin for DeepSeek Harness: code-generated Chinese videos with measured TTS timeline, deterministic PIL/browser frame rendering, programmatic SFX and score, cue-driven sound sync, ffmpeg encoding, sample-level mixing and multi-layer QA gates.",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./cordis.patch.yml": "./cordis.patch.yml",
10
+ "./icon": "./icon.svg",
11
+ "./locale/*.json": "./locale/*.json",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "dsh": {
15
+ "bundle": {
16
+ "patch": "./cordis.patch.yml"
17
+ }
18
+ },
19
+ "icon": "./icon.svg",
20
+ "files": [
21
+ "index.js",
22
+ "cordis.patch.yml",
23
+ "icon.svg",
24
+ "locale/*.json",
25
+ "docs/demo-pil-sheet.png",
26
+ "THIRD_PARTY_NOTICES.md",
27
+ "skills",
28
+ "!skills/**/__pycache__",
29
+ "!skills/**/*.pyc"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "engines": {
35
+ "node": ">=20"
36
+ },
37
+ "homepage": "https://github.com/znlgis/dsh-video-studio-skill#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/znlgis/dsh-video-studio-skill/issues"
40
+ },
41
+ "keywords": [
42
+ "dsh-plugin",
43
+ "deepseek-harness",
44
+ "skill",
45
+ "video",
46
+ "ffmpeg",
47
+ "edge-tts",
48
+ "playwright",
49
+ "sfx",
50
+ "score",
51
+ "字幕",
52
+ "视频",
53
+ "配音"
54
+ ],
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/znlgis/dsh-video-studio-skill.git"
58
+ },
59
+ "peerDependencies": {
60
+ "@deepseek-ai/dsh-skill-filesystem": ">=0.1.0-rc.6 <0.3.0-0"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "@deepseek-ai/dsh-skill-filesystem": {
64
+ "optional": true
65
+ }
66
+ },
67
+ "license": "MIT"
68
+ }