@pls-compile-owo/fisheye 0.7.2 → 0.8.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.
- package/CHANGELOG.md +18 -0
- package/README.en.md +10 -0
- package/README.md +21 -0
- package/fisheye.mjs +2 -1
- package/lib/i18n.mjs +2 -2
- package/lib/stages.mjs +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 规范与 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [0.8.0] - 2026-11-14
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **auto 默认策略**:无官方字幕时自动尝试 whisper 转写(比抽帧省 token),转写成功则跳过字幕带;用 `--no-audio` 或环境变量 `FISHEYE_AUTO_AUDIO=0` 关闭。`--audio` 保留为显式请求。
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- 转写成功后不再多余生成烧录字幕带图。
|
|
14
|
+
|
|
15
|
+
## [0.7.3] - 2026-11-14
|
|
16
|
+
|
|
17
|
+
### Docs
|
|
18
|
+
|
|
19
|
+
纯文档同步版本(功能与 0.7.2 一致)。
|
|
20
|
+
|
|
21
|
+
- README 新增「自检」专节:selftest 检查项、输出标记([OK]/[--]/[!!])、--deep 说明。
|
|
22
|
+
|
|
5
23
|
## [0.7.2] - 2026-11-14
|
|
6
24
|
|
|
7
25
|
### Docs
|
package/README.en.md
CHANGED
|
@@ -79,6 +79,16 @@ node fisheye.mjs clean [--target out] [--yes] # clean artifacts
|
|
|
79
79
|
`auto --resume` reuses existing grids and skips frame extraction; `--force` re-runs everything.
|
|
80
80
|
Optional integrations: whisper.cpp (audio), tesseract (OCR), yt-dlp (any URL), and `mcp-video-server.js` (MCP tools, needs `npm i @modelcontextprotocol/sdk zod`).
|
|
81
81
|
|
|
82
|
+
## Self-check
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node fisheye.mjs selftest # dependencies / credentials / APIs / optional tools / disk
|
|
86
|
+
node fisheye.mjs selftest --deep # plus frame-extraction and subtitle-band probes
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Marks: `[OK]` pass, `[--]` skipped (optional tool missing / no data), `[!!]` failed.
|
|
90
|
+
Failures print fix hints at the end.
|
|
91
|
+
|
|
82
92
|
## Docs
|
|
83
93
|
|
|
84
94
|
- `docs/DESIGN.md` — design rationale
|
package/README.md
CHANGED
|
@@ -232,6 +232,8 @@ node fisheye.mjs transcribe BV1xxx [--lang zh]
|
|
|
232
232
|
模型放 `~/.dsh/surfcore/whisper/`(`ggml-*.bin`)或用 `FISHEYE_WHISPER_MODEL` 指定。
|
|
233
233
|
转写文本落 `out/<BV>-audio-transcript.txt`。
|
|
234
234
|
|
|
235
|
+
> **默认策略**:`auto` 发现视频没有官方字幕时,会自动尝试 whisper 转写(口播/播客类比抽帧省 token);转写文本作为台词源,跳过烧录字幕带。不想用加 `--no-audio` 或设 `FISHEYE_AUTO_AUDIO=0`。
|
|
236
|
+
|
|
235
237
|
### 字幕翻译
|
|
236
238
|
|
|
237
239
|
外文视频(英文/日文等)的官方字幕会同时读取 B站 的**中文翻译轨**(l2 机器翻译),
|
|
@@ -283,6 +285,25 @@ node fisheye.mjs clean # 预览将清理的缓存/产物(dr
|
|
|
283
285
|
node fisheye.mjs clean --target out --yes # 实际删除 out/
|
|
284
286
|
```
|
|
285
287
|
|
|
288
|
+
## 自检
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
node fisheye.mjs selftest # 快速检查依赖 / 凭证 / API / 可选组件 / 磁盘
|
|
292
|
+
node fisheye.mjs selftest --deep # 额外做抽帧 + 字幕带实测(需缓存视频)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
检查项:
|
|
296
|
+
|
|
297
|
+
| 类别 | 检查内容 |
|
|
298
|
+
|---|---|
|
|
299
|
+
| 基础 | Node 版本、ffmpeg、python(可选)、analyze_subs.py |
|
|
300
|
+
| 环境 | 输出目录可写、B站 凭证、缓存目录、磁盘剩余 |
|
|
301
|
+
| API | 视频 API、弹幕 API、官方字幕 API(含翻译轨) |
|
|
302
|
+
| 可选组件 | 音频转写(whisper)、OCR(tesseract)、yt-dlp |
|
|
303
|
+
|
|
304
|
+
输出标记:`[OK]` 通过、`[--]` 跳过(可选依赖未装/无数据)、`[!!]` 失败。
|
|
305
|
+
失败时末尾会打印修复提示;`--deep` 会额外实测抽帧与字幕带检测。
|
|
306
|
+
|
|
286
307
|
## MCP server(可选)
|
|
287
308
|
|
|
288
309
|
`mcp-video-server.js` 把 fisheye 包装成 [MCP](https://modelcontextprotocol.io/)(Model Context Protocol)工具,让支持 MCP 的 agent 环境(DSH / Claude Code / Cursor 等)**不必自己拼命令行**就能看视频。
|
package/fisheye.mjs
CHANGED
|
@@ -162,7 +162,8 @@ try {
|
|
|
162
162
|
num(opt('budget', 20000), 'budget', { min: 2000, max: 200000 }),
|
|
163
163
|
{ density: d === null ? null : num(d, 'density', { min: 0.5, max: 60 }), page, from, to,
|
|
164
164
|
useDanmakuFrames: !argv.includes('--no-danmaku-frames'),
|
|
165
|
-
audio: argv.includes('--audio')
|
|
165
|
+
audio: argv.includes('--audio') ? true : (argv.includes('--no-audio') ? false : undefined),
|
|
166
|
+
audioLang: opt('lang', null),
|
|
166
167
|
resume: argv.includes('--resume'), force: argv.includes('--force') })
|
|
167
168
|
} else if (stage === 'refine') {
|
|
168
169
|
await stageRefine(bvid, { template: argv.includes('--template'), decisions: opt('decisions', null) })
|
package/lib/i18n.mjs
CHANGED
|
@@ -19,7 +19,7 @@ const MESSAGES = {
|
|
|
19
19
|
zh: {
|
|
20
20
|
// —— 用法帮助 ——
|
|
21
21
|
usage: `用法:
|
|
22
|
-
node fisheye.mjs auto <BV> [--budget 20000] [--density 6] [--audio] ←
|
|
22
|
+
node fisheye.mjs auto <BV> [--budget 20000] [--density 6] [--audio] ← 推荐:自动规划并铺网(无字幕自动转写;--no-audio 关闭 / --resume 断点续跑)
|
|
23
23
|
node fisheye.mjs refine <BV> --template ← 生成精读决策模板
|
|
24
24
|
node fisheye.mjs refine <BV> --decisions <file.json> ← 按模型判断精读
|
|
25
25
|
node fisheye.mjs refine <BV> ← 几何兜底(零 token)
|
|
@@ -79,7 +79,7 @@ const MESSAGES = {
|
|
|
79
79
|
|
|
80
80
|
en: {
|
|
81
81
|
usage: `Usage:
|
|
82
|
-
node fisheye.mjs auto <BV> [--budget 20000] [--density 6] [--audio] # recommended: auto-plan and build grids (
|
|
82
|
+
node fisheye.mjs auto <BV> [--budget 20000] [--density 6] [--audio] # recommended: auto-plan and build grids (auto-transcribe when no subtitles; --no-audio disables)
|
|
83
83
|
node fisheye.mjs refine <BV> --template # generate a refine decision template
|
|
84
84
|
node fisheye.mjs refine <BV> --decisions <file.json> # refine using model decisions
|
|
85
85
|
node fisheye.mjs refine <BV> # geometric fallback (zero tokens)
|
package/lib/stages.mjs
CHANGED
|
@@ -534,7 +534,9 @@ export async function stageAuto(bvid, budget, opts = {}) {
|
|
|
534
534
|
if (officialRaw) {
|
|
535
535
|
console.log(`[字幕] 官方字幕质量差(平均有效 ${officialRaw.avgEff} 字/行、去重率 ${officialRaw.uniqueRatio})——疑为音乐/音效噪声,不采用`)
|
|
536
536
|
}
|
|
537
|
-
|
|
537
|
+
// 默认策略:无官方字幕时尝试 whisper 转写(比抽帧省 token);--no-audio 或 FISHEYE_AUTO_AUDIO=0 关闭
|
|
538
|
+
const wantAudio = opts.audio !== false && process.env.FISHEYE_AUTO_AUDIO !== '0'
|
|
539
|
+
if (wantAudio) {
|
|
538
540
|
const caps = audioCaps()
|
|
539
541
|
console.log(`[音频] ${caps.summary}`)
|
|
540
542
|
if (!caps.available) {
|
|
@@ -670,7 +672,7 @@ export async function stageAuto(bvid, budget, opts = {}) {
|
|
|
670
672
|
} else {
|
|
671
673
|
manifest = await stageGrid(bvid, chunk, '3x3', pre)
|
|
672
674
|
}
|
|
673
|
-
if (hasSubs) await stageSubs(bvid, subsRows, 'auto', { mp4, view, bandResult, scenes, range, page: pageNo })
|
|
675
|
+
if (hasSubs && !transcript) await stageSubs(bvid, subsRows, 'auto', { mp4, view, bandResult, scenes, range, page: pageNo })
|
|
674
676
|
|
|
675
677
|
// 7. 精读建议 = 几何规则(画面变化剧烈)+ 弹幕热区(观众反应最激烈)
|
|
676
678
|
// 两个信号互补:几何只看像素,弹幕看人的反应;合并后按时间排序、同一时刻只留一个
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pls-compile-owo/fisheye",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Token-budget-aware video understanding for AI agents: official subtitles -> burned-in subtitle band -> danmaku highlights -> adaptive keyframe grids -> targeted refine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|