@xzxzzx/bilibili-mcp 1.6.4 → 1.7.1
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/README.md +60 -12
- package/README_EN.md +60 -12
- package/dist/bilibili/chapters.d.ts +8 -0
- package/dist/bilibili/chapters.d.ts.map +1 -0
- package/dist/bilibili/chapters.js +35 -0
- package/dist/bilibili/chapters.js.map +1 -0
- package/dist/bilibili/client.d.ts +2 -1
- package/dist/bilibili/client.d.ts.map +1 -1
- package/dist/bilibili/client.js +2 -1
- package/dist/bilibili/client.js.map +1 -1
- package/dist/bilibili/metadata.d.ts +1 -1
- package/dist/bilibili/metadata.d.ts.map +1 -1
- package/dist/bilibili/metadata.js +4 -2
- package/dist/bilibili/metadata.js.map +1 -1
- package/dist/bilibili/navigation.d.ts +25 -0
- package/dist/bilibili/navigation.d.ts.map +1 -0
- package/dist/bilibili/navigation.js +49 -0
- package/dist/bilibili/navigation.js.map +1 -0
- package/dist/bilibili/subtitle.d.ts +4 -3
- package/dist/bilibili/subtitle.d.ts.map +1 -1
- package/dist/bilibili/subtitle.js +64 -31
- package/dist/bilibili/subtitle.js.map +1 -1
- package/dist/bilibili/types.d.ts +26 -0
- package/dist/bilibili/types.d.ts.map +1 -1
- package/dist/bilibili/video-api.d.ts +14 -1
- package/dist/bilibili/video-api.d.ts.map +1 -1
- package/dist/bilibili/video-api.js +15 -1
- package/dist/bilibili/video-api.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/server/tool-handlers.d.ts.map +1 -1
- package/dist/server/tool-handlers.js +30 -4
- package/dist/server/tool-handlers.js.map +1 -1
- package/dist/server/tool-schemas.d.ts.map +1 -1
- package/dist/server/tool-schemas.js +45 -4
- package/dist/server/tool-schemas.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -1
- package/dist/server.js.map +1 -1
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/cache.js +3 -8
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/validation.d.ts +12 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +38 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +2 -9
- package/dist/bilibili/auth.d.ts +0 -72
- package/dist/bilibili/auth.d.ts.map +0 -1
- package/dist/bilibili/auth.js +0 -162
- package/dist/bilibili/auth.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Bilibili MCP server — 让 Claude、Cursor、Codex 等 AI 客户端直接读取 Bilibili 视频字幕、转录、元数据和热门评论的 MCP server。
|
|
8
8
|
|
|
9
|
-
🌐 [English Documentation](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/README_EN.md) · 📜 [更新日志](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/CHANGELOG.md) · 📦 [npm](https://www.npmjs.com/package/@xzxzzx/bilibili-mcp) · 🚀 [Release v1.
|
|
9
|
+
🌐 [English Documentation](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/README_EN.md) · 📜 [更新日志](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/CHANGELOG.md) · 📦 [npm](https://www.npmjs.com/package/@xzxzzx/bilibili-mcp) · 🚀 [Release v1.7.1](https://github.com/XZXZZX-Ai/bilibili-mcp/releases/tag/v1.7.1)
|
|
10
10
|
|
|
11
11
|
> [!TIP]
|
|
12
12
|
> ⚠️ 你可以把下方“用 agent 工具帮你安装”的提示词复制给 Codex、Claude Code、Cursor 等 agent,让它帮你完成 MCP 客户端接入和 Cookie 配置引导。为了稳定获取字幕、转录和评论,安装后仍需配置 B 站 Cookie(agent会引导你);不要把 Cookie 写进 MCP 客户端配置。Metadata 可能无需 Cookie。详见 [**凭证配置**](#️-凭证配置)。
|
|
@@ -84,8 +84,9 @@ npx -y @xzxzzx/bilibili-mcp@latest check
|
|
|
84
84
|
- [2. 评论总结 (`get_video_comments`)](#2-评论总结-get_video_comments)
|
|
85
85
|
- [3. 视频转录 (`get_video_transcript`)](#3-视频转录-get_video_transcript)
|
|
86
86
|
- [4. 视频元数据 (`get_video_metadata`)](#4-视频元数据-get_video_metadata)
|
|
87
|
-
- [5.
|
|
88
|
-
- [6.
|
|
87
|
+
- [5. 视频章节 (`get_video_chapters`)](#5-视频章节-get_video_chapters)
|
|
88
|
+
- [6. 凭证助手工具](#6-凭证助手工具)
|
|
89
|
+
- [7. 行为说明与错误处理](#7-行为说明与错误处理)
|
|
89
90
|
- [📋 环境要求](#-环境要求)
|
|
90
91
|
- [🚀 客户端接入方式](#-客户端接入方式)
|
|
91
92
|
- [⚙️ 凭证配置](#️-凭证配置)
|
|
@@ -121,24 +122,34 @@ npx -y @xzxzzx/bilibili-mcp@latest check
|
|
|
121
122
|
### 3. 视频转录 (`get_video_transcript`)
|
|
122
123
|
- 返回纯字幕文本,按行合并
|
|
123
124
|
- 支持指定偏好语言(默认按 `zh-Hans` > `ai-zh` > `zh-CN` > `zh-Hant` > `en` 优先级选择)
|
|
125
|
+
- 支持多P分集选择、时间戳输出和时间区间过滤
|
|
124
126
|
- 可选参数:
|
|
125
127
|
- `preferred_lang`: 偏好字幕语言代码
|
|
126
128
|
- `fallback_to_description`: 字幕不可用时是否降级为视频描述(默认 `false`)
|
|
129
|
+
- `page`: 多P视频分集编号(从1开始的正整数)
|
|
130
|
+
- `include_timestamps`: 每行添加 `[HH:MM:SS --> HH:MM:SS]` 时间戳前缀
|
|
131
|
+
- `start_seconds` / `end_seconds`: 只返回与此区间重叠的字幕段
|
|
127
132
|
- 默认不降级:无字幕时返回 `SUBTITLE_UNAVAILABLE` 错误
|
|
133
|
+
- 时间戳/区间过滤与描述降级不兼容:请求 timed 输出时不会静默降级
|
|
128
134
|
- Cookie 失效时始终返回 `COOKIE_EXPIRED`,不静默降级
|
|
129
135
|
|
|
130
136
|
### 4. 视频元数据 (`get_video_metadata`)
|
|
131
137
|
- 返回视频标题、作者、时长、发布时间、描述、标签、播放/点赞/投币等统计信息
|
|
138
|
+
- 返回多P分集列表(`pages`),含分集编号、CID、标题和时长
|
|
132
139
|
- 不获取字幕或评论
|
|
133
|
-
- 仅需 `bvid_or_url` 参数
|
|
134
140
|
|
|
135
|
-
### 5.
|
|
141
|
+
### 5. 视频章节 (`get_video_chapters`)
|
|
142
|
+
- 返回 Bilibili 创作者/平台定义的视频章节(进度条分段),含章节标题和起止时间
|
|
143
|
+
- 无章节时返回空列表(`chapters: []`),不推断章节
|
|
144
|
+
- 可选参数 `page`:多P视频分集编号
|
|
145
|
+
|
|
146
|
+
### 6. 凭证助手工具
|
|
136
147
|
|
|
137
148
|
- `get_credential_setup_instructions`: 返回安全的 Bilibili Cookie 配置命令和说明。AI agent 安装此 MCP 后可调用此工具引导用户完成配置。
|
|
138
149
|
- `check_bilibili_credentials`: 检查凭证是否已配置并处于登录状态,不返回任何 Cookie 值。配置缺失或失效时返回下一步操作指引。
|
|
139
150
|
- `check_mcp_update`: 检查本地包版本与 npm latest 是否一致,并返回 `npx @latest` 或全局安装的安全更新指引。
|
|
140
151
|
|
|
141
|
-
###
|
|
152
|
+
### 7. 行为说明与错误处理
|
|
142
153
|
|
|
143
154
|
- **Cookie 过期智能检测**:当字幕获取为空时自动验证登录状态,区分“无字幕视频”与“凭证失效”,并抛出明确的 `COOKIE_EXPIRED` 错误,避免静默降级。
|
|
144
155
|
|
|
@@ -1232,9 +1243,10 @@ BILIBILI_DEDEUSERID=<your_dedeuserid>
|
|
|
1232
1243
|
| 目标 | 推荐工具 | 返回重点 |
|
|
1233
1244
|
|---|---|---|
|
|
1234
1245
|
| 想让 AI 总结一个视频 | `get_video_info` | 字幕优先;无字幕时返回标题、简介、标签 |
|
|
1235
|
-
| 只想拿完整转录文本 | `get_video_transcript` |
|
|
1236
|
-
| 想查看标题、作者、播放量等结构化信息 | `get_video_metadata` |
|
|
1246
|
+
| 只想拿完整转录文本 | `get_video_transcript` | 纯字幕文本、语言、数据来源;支持时间戳和区间过滤 |
|
|
1247
|
+
| 想查看标题、作者、播放量等结构化信息 | `get_video_metadata` | 标题、作者、时长、发布时间、标签、统计数据、多P分集列表(`pages`) |
|
|
1237
1248
|
| 想看观众反馈和热门评论 | `get_video_comments` | 热门评论、时间戳评论、可选回复 |
|
|
1249
|
+
| 想看视频章节/进度条分段 | `get_video_chapters` | 章节标题、起止时间;无章节时返回空列表 |
|
|
1238
1250
|
| 让 agent 引导用户配置 Cookie | `get_credential_setup_instructions` | 安全配置步骤、推荐命令、注意事项 |
|
|
1239
1251
|
| 检查 Cookie 是否已配置/登录 | `check_bilibili_credentials` | configured、source、logged_in、next_steps、next_steps_zh |
|
|
1240
1252
|
| 检查 MCP 包是否需要更新 | `check_mcp_update` | current_version、latest_version、update_available、notes_zh、更新命令 |
|
|
@@ -1305,10 +1317,25 @@ BILIBILI_DEDEUSERID=<your_dedeuserid>
|
|
|
1305
1317
|
}
|
|
1306
1318
|
```
|
|
1307
1319
|
|
|
1308
|
-
返回内容:`bvid`、`title`、`language`、`transcript`(按行合并)、`data_source`(`subtitle` 或 `description
|
|
1320
|
+
返回内容:`bvid`、`title`、`language`、`transcript`(按行合并)、`data_source`(`subtitle` 或 `description`)、`page`(分集编号)。
|
|
1309
1321
|
|
|
1310
1322
|
> 默认无字幕时返回 `SUBTITLE_UNAVAILABLE`。如需降级,设置 `fallback_to_description: true`。
|
|
1311
1323
|
|
|
1324
|
+
**定时区间转录示例**:
|
|
1325
|
+
|
|
1326
|
+
```json
|
|
1327
|
+
{
|
|
1328
|
+
"name": "get_video_transcript",
|
|
1329
|
+
"arguments": {
|
|
1330
|
+
"bvid_or_url": "BV1xx411c7mD",
|
|
1331
|
+
"page": 1,
|
|
1332
|
+
"include_timestamps": true,
|
|
1333
|
+
"start_seconds": 120,
|
|
1334
|
+
"end_seconds": 300
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
```
|
|
1338
|
+
|
|
1312
1339
|
### `get_video_metadata`
|
|
1313
1340
|
|
|
1314
1341
|
**适合**:想快速了解视频基本信息,不需要字幕或评论内容。
|
|
@@ -1324,7 +1351,24 @@ BILIBILI_DEDEUSERID=<your_dedeuserid>
|
|
|
1324
1351
|
}
|
|
1325
1352
|
```
|
|
1326
1353
|
|
|
1327
|
-
返回内容:`bvid`、`title`、`author`、`duration`、`pubdate` / `pubdate_timestamp`、`description`、`tags
|
|
1354
|
+
返回内容:`bvid`、`title`、`author`、`duration`、`pubdate` / `pubdate_timestamp`、`description`、`tags`、`pages`(多P分集列表)和 `stats`(播放、点赞、投币、收藏、分享、评论、弹幕)。
|
|
1355
|
+
|
|
1356
|
+
### `get_video_chapters`
|
|
1357
|
+
|
|
1358
|
+
**适合**:获取 Bilibili 创作者定义的视频章节,用于导航或定位。
|
|
1359
|
+
|
|
1360
|
+
请求示例:
|
|
1361
|
+
|
|
1362
|
+
```json
|
|
1363
|
+
{
|
|
1364
|
+
"name": "get_video_chapters",
|
|
1365
|
+
"arguments": {
|
|
1366
|
+
"bvid_or_url": "BV1vL411G7N7"
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
```
|
|
1370
|
+
|
|
1371
|
+
返回内容:`bvid`、`page`、`cid`、`title`、`chapters`(数组,每项含 `title`、`start_seconds`、`end_seconds`)。无章节时 `chapters` 为空数组。
|
|
1328
1372
|
|
|
1329
1373
|
### `get_video_info`
|
|
1330
1374
|
|
|
@@ -1379,6 +1423,10 @@ BILIBILI_DEDEUSERID=<your_dedeuserid>
|
|
|
1379
1423
|
- **执行方式**:对 API 请求启动做节流,避免瞬时大并发;适合本地单用户 MCP 使用。
|
|
1380
1424
|
- **重试策略**:对 408、429、5xx、网络错误和超时进行最多 3 次指数退避重试。
|
|
1381
1425
|
- **超时控制**:默认 10 秒,可通过 `BILIBILI_REQUEST_TIMEOUT_MS` 调整。
|
|
1426
|
+
- **缓存容量**:默认 100 条,可通过 `BILIBILI_CACHE_SIZE` 调整。
|
|
1427
|
+
- **User-Agent**:可通过 `USER_AGENT` 覆盖默认请求头。
|
|
1428
|
+
|
|
1429
|
+
以上环境变量均在 MCP server 进程启动时读取,修改后需重启 MCP 客户端或重连 MCP server 才能生效。
|
|
1382
1430
|
|
|
1383
1431
|
---
|
|
1384
1432
|
|
|
@@ -1406,7 +1454,7 @@ npm run watch
|
|
|
1406
1454
|
|
|
1407
1455
|
| 命令 | 用途 |
|
|
1408
1456
|
|---|---|
|
|
1409
|
-
| `npm run build` |
|
|
1457
|
+
| `npm run build` | 清理 `dist/` 后编译 TypeScript |
|
|
1410
1458
|
| `npm test` | 运行 Vitest 单元测试 |
|
|
1411
1459
|
| `npm run watch` | 开发时持续编译 |
|
|
1412
1460
|
| `npm start` | 运行已编译的 stdio MCP server |
|
|
@@ -1442,7 +1490,7 @@ npm run watch
|
|
|
1442
1490
|
|
|
1443
1491
|
1. **初版生成**:由 **Claude Code** (搭载 **GLM-4.7** 模型) 快速搭建核心架构与基础逻辑。
|
|
1444
1492
|
2. **调试与优化**:在 **Antigravity** 环境下,利用 **Claude** 和 **Gemini** 模型进行深度的 Bug 修复与功能增强,确保了字幕提取与评论分析的稳定性。
|
|
1445
|
-
3. **迭代与扩展**:由 **Codex**
|
|
1493
|
+
3. **迭代与扩展**:由 **Codex** 进行架构决策与计划分解,通过 **Paseo** 启动 **Claude Code** 执行实现;目前覆盖 30+ AI 客户端的 MCP 接入配置、8 个 MCP 工具、244 个单元测试。
|
|
1446
1494
|
|
|
1447
1495
|
---
|
|
1448
1496
|
|
package/README_EN.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
MCP server that gives AI clients access to Bilibili video subtitles, transcripts, metadata, and popular comments.
|
|
8
8
|
|
|
9
|
-
View in [简体中文](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/README.md) · 📜 [Changelog](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/CHANGELOG_EN.md) · 📦 [npm](https://www.npmjs.com/package/@xzxzzx/bilibili-mcp) · 🚀 [Release v1.
|
|
9
|
+
View in [简体中文](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/README.md) · 📜 [Changelog](https://github.com/XZXZZX-Ai/bilibili-mcp/blob/master/CHANGELOG_EN.md) · 📦 [npm](https://www.npmjs.com/package/@xzxzzx/bilibili-mcp) · 🚀 [Release v1.7.1](https://github.com/XZXZZX-Ai/bilibili-mcp/releases/tag/v1.7.1)
|
|
10
10
|
|
|
11
11
|
> [!TIP]
|
|
12
12
|
> ⚠️ You can copy the "Install With Your Agent" prompt below to Codex, Claude Code, Cursor, or another agent and let it add this MCP server to your client and guide Cookie setup. For reliable subtitles, transcripts, and comments, you still need to configure Bilibili Cookies after installation; do not write Cookies into MCP client config. Metadata may work without cookies. See [**Credential Configuration**](#-credential-configuration).
|
|
@@ -84,8 +84,9 @@ After the MCP server is connected, if available, call get_credential_setup_instr
|
|
|
84
84
|
- [2. Comment Summarization (`get_video_comments`)](#2-comment-summarization-get_video_comments)
|
|
85
85
|
- [3. Video Transcript (`get_video_transcript`)](#3-video-transcript-get_video_transcript)
|
|
86
86
|
- [4. Video Metadata (`get_video_metadata`)](#4-video-metadata-get_video_metadata)
|
|
87
|
-
- [5.
|
|
88
|
-
- [6.
|
|
87
|
+
- [5. Video Chapters (`get_video_chapters`)](#5-video-chapters-get_video_chapters)
|
|
88
|
+
- [6. Credential Helper Tools](#6-credential-helper-tools)
|
|
89
|
+
- [7. Behavior and Error Handling](#7-behavior-and-error-handling)
|
|
89
90
|
- [📋 Requirements](#-requirements)
|
|
90
91
|
- [🚀 Client Setup](#-client-setup)
|
|
91
92
|
- [⚙️ Credential Configuration](#-credential-configuration)
|
|
@@ -121,24 +122,34 @@ After the MCP server is connected, if available, call get_credential_setup_instr
|
|
|
121
122
|
### 3. Video Transcript (`get_video_transcript`)
|
|
122
123
|
- Returns clean subtitle text, joined by newlines.
|
|
123
124
|
- Supports preferred language selection (defaults to `zh-Hans` > `ai-zh` > `zh-CN` > `zh-Hant` > `en` priority).
|
|
125
|
+
- Supports multi-Part selection, timestamp output, and time-range filtering.
|
|
124
126
|
- Optional parameters:
|
|
125
127
|
- `preferred_lang`: Preferred subtitle language code.
|
|
126
128
|
- `fallback_to_description`: Fall back to video description if subtitles unavailable (default `false`).
|
|
129
|
+
- `page`: Multi-Part video page number (1-based positive integer).
|
|
130
|
+
- `include_timestamps`: Prefix each line with `[HH:MM:SS --> HH:MM:SS]`.
|
|
131
|
+
- `start_seconds` / `end_seconds`: Only return segments overlapping this range.
|
|
127
132
|
- By default, returns `SUBTITLE_UNAVAILABLE` error when no subtitles exist.
|
|
133
|
+
- Timestamps/range filtering is incompatible with description fallback.
|
|
128
134
|
- Cookie expiration always returns `COOKIE_EXPIRED`, never silently falls back.
|
|
129
135
|
|
|
130
136
|
### 4. Video Metadata (`get_video_metadata`)
|
|
131
137
|
- Returns video title, author, duration, publish date, description, tags, and stats (views, likes, coins, etc.).
|
|
138
|
+
- Returns multi-Part listing (`pages`) with page number, CID, title, and duration.
|
|
132
139
|
- Does not fetch subtitles or comments.
|
|
133
|
-
- Only requires the `bvid_or_url` parameter.
|
|
134
140
|
|
|
135
|
-
### 5.
|
|
141
|
+
### 5. Video Chapters (`get_video_chapters`)
|
|
142
|
+
- Returns Bilibili creator-defined Chapter intervals (view_points) with title, start, and end seconds.
|
|
143
|
+
- Returns empty `chapters` array when no Chapters exist; never infers Chapters.
|
|
144
|
+
- Accepts optional `page` parameter for multi-Part videos.
|
|
145
|
+
|
|
146
|
+
### 6. Credential Helper Tools
|
|
136
147
|
|
|
137
148
|
- `get_credential_setup_instructions`: Returns safe setup commands for Bilibili Cookie configuration. AI agents installing this MCP can call this tool to guide users through setup.
|
|
138
149
|
- `check_bilibili_credentials`: Checks whether credentials are configured and logged in without returning Cookie values. Returns next steps when credentials are missing or invalid.
|
|
139
150
|
- `check_mcp_update`: Checks the local package version against npm latest and returns safe update guidance for `npx @latest` or global installs.
|
|
140
151
|
|
|
141
|
-
###
|
|
152
|
+
### 7. Behavior and Error Handling
|
|
142
153
|
|
|
143
154
|
- **Intelligent Cookie Expiration Detection**: Automatically verifies login status when subtitles are empty, distinguishing between "videos without subtitles" and "invalid credentials," and throwing a clear `COOKIE_EXPIRED` error to prevent silent degradation.
|
|
144
155
|
|
|
@@ -1232,9 +1243,10 @@ Do not share cookies with others. Do not paste them into public chats, issues, P
|
|
|
1232
1243
|
| Goal | Recommended tool | What you get |
|
|
1233
1244
|
|---|---|---|
|
|
1234
1245
|
| Summarize a video | `get_video_info` | Subtitles first; falls back to title, description, tags |
|
|
1235
|
-
| Get clean transcript text | `get_video_transcript` | Plain subtitle text, language, data source |
|
|
1236
|
-
| See structured metadata | `get_video_metadata` | Title, author, duration, publish date, tags, stats |
|
|
1246
|
+
| Get clean transcript text | `get_video_transcript` | Plain subtitle text, language, data source; supports timestamps and range filtering |
|
|
1247
|
+
| See structured metadata | `get_video_metadata` | Title, author, duration, publish date, tags, stats, multi-Part listing |
|
|
1237
1248
|
| View audience reactions | `get_video_comments` | Popular comments, timestamped highlights, optional replies |
|
|
1249
|
+
| See video Chapters | `get_video_chapters` | Chapter titles, start/end seconds; empty list when absent |
|
|
1238
1250
|
| Guide users through Cookie setup | `get_credential_setup_instructions` | Safe setup steps, recommended commands, security notes |
|
|
1239
1251
|
| Check whether Cookies are configured/logged in | `check_bilibili_credentials` | configured, source, logged_in, next_steps, next_steps_zh |
|
|
1240
1252
|
| Check whether the MCP package needs an update | `check_mcp_update` | current_version, latest_version, update_available, notes_zh, update commands |
|
|
@@ -1305,10 +1317,25 @@ Request:
|
|
|
1305
1317
|
}
|
|
1306
1318
|
```
|
|
1307
1319
|
|
|
1308
|
-
Returns: `bvid`, `title`, `language`, `transcript` (newline-joined), `data_source` (`subtitle` or `description`)
|
|
1320
|
+
Returns: `bvid`, `title`, `language`, `transcript` (newline-joined), `data_source` (`subtitle` or `description`), `page`.
|
|
1309
1321
|
|
|
1310
1322
|
> Returns `SUBTITLE_UNAVAILABLE` when no subtitles exist. Set `fallback_to_description: true` to fall back.
|
|
1311
1323
|
|
|
1324
|
+
**Timed range example**:
|
|
1325
|
+
|
|
1326
|
+
```json
|
|
1327
|
+
{
|
|
1328
|
+
"name": "get_video_transcript",
|
|
1329
|
+
"arguments": {
|
|
1330
|
+
"bvid_or_url": "BV1xx411c7mD",
|
|
1331
|
+
"page": 1,
|
|
1332
|
+
"include_timestamps": true,
|
|
1333
|
+
"start_seconds": 120,
|
|
1334
|
+
"end_seconds": 300
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
```
|
|
1338
|
+
|
|
1312
1339
|
### `get_video_metadata`
|
|
1313
1340
|
|
|
1314
1341
|
**Best for**: quickly checking video basics without subtitles or comments.
|
|
@@ -1324,7 +1351,24 @@ Request:
|
|
|
1324
1351
|
}
|
|
1325
1352
|
```
|
|
1326
1353
|
|
|
1327
|
-
Returns: `bvid`, `title`, `author`, `duration`, `pubdate` / `pubdate_timestamp`, `description`, `tags`, and `stats` (views, likes, coins, favorites, shares, replies, danmaku).
|
|
1354
|
+
Returns: `bvid`, `title`, `author`, `duration`, `pubdate` / `pubdate_timestamp`, `description`, `tags`, `pages` (multi-Part listing), and `stats` (views, likes, coins, favorites, shares, replies, danmaku).
|
|
1355
|
+
|
|
1356
|
+
### `get_video_chapters`
|
|
1357
|
+
|
|
1358
|
+
**Best for**: getting Bilibili creator-defined Chapter intervals for navigation.
|
|
1359
|
+
|
|
1360
|
+
Request:
|
|
1361
|
+
|
|
1362
|
+
```json
|
|
1363
|
+
{
|
|
1364
|
+
"name": "get_video_chapters",
|
|
1365
|
+
"arguments": {
|
|
1366
|
+
"bvid_or_url": "BV1vL411G7N7"
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
```
|
|
1370
|
+
|
|
1371
|
+
Returns: `bvid`, `page`, `cid`, `title`, `chapters` (array with `title`, `start_seconds`, `end_seconds`). Empty array when no Chapters exist.
|
|
1328
1372
|
|
|
1329
1373
|
### `get_video_info`
|
|
1330
1374
|
|
|
@@ -1379,6 +1423,10 @@ Built-in request controls reduce the chance of triggering Bilibili risk checks o
|
|
|
1379
1423
|
- **Execution model**: throttles API request starts to avoid burst concurrency; intended for local single-user MCP usage.
|
|
1380
1424
|
- **Retry strategy**: retries 408, 429, 5xx, network errors, and timeouts up to 3 times with exponential backoff.
|
|
1381
1425
|
- **Timeout**: defaults to 10 seconds, configurable with `BILIBILI_REQUEST_TIMEOUT_MS`.
|
|
1426
|
+
- **Cache capacity**: defaults to 100 entries, configurable with `BILIBILI_CACHE_SIZE`.
|
|
1427
|
+
- **User-Agent**: overridable via `USER_AGENT`.
|
|
1428
|
+
|
|
1429
|
+
All of the above environment variables are read at MCP server process startup. After changing them, restart the MCP client or reconnect the MCP server for the new values to take effect.
|
|
1382
1430
|
|
|
1383
1431
|
---
|
|
1384
1432
|
|
|
@@ -1406,7 +1454,7 @@ Common commands:
|
|
|
1406
1454
|
|
|
1407
1455
|
| Command | Purpose |
|
|
1408
1456
|
|---|---|
|
|
1409
|
-
| `npm run build` |
|
|
1457
|
+
| `npm run build` | Clean `dist/` then compile TypeScript |
|
|
1410
1458
|
| `npm test` | Run the Vitest unit tests |
|
|
1411
1459
|
| `npm run watch` | Continuously compile during development |
|
|
1412
1460
|
| `npm start` | Run the compiled stdio MCP server |
|
|
@@ -1439,7 +1487,7 @@ This project is a crystal of AI-collaborative development, spanning from prototy
|
|
|
1439
1487
|
|
|
1440
1488
|
1. **Initial Generation**: Core architecture and base logic were rapidly built by **Claude Code** (powered by **GLM-4.7** model).
|
|
1441
1489
|
2. **Debugging & Optimization**: Bugs were fixed and features enhanced using **Claude** and **Gemini** models within the **Antigravity** environment, ensuring stable subtitle extraction and comment analysis.
|
|
1442
|
-
3. **Iteration & Expansion**: **Codex** handles architectural decisions and planning,
|
|
1490
|
+
3. **Iteration & Expansion**: **Codex** handles architectural decisions and planning, launching **Claude Code** via **Paseo** for implementation; now covers 30+ AI client MCP configurations, 8 MCP tools, and 244 unit tests.
|
|
1443
1491
|
|
|
1444
1492
|
---
|
|
1445
1493
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { VideoChaptersData } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 获取 Bilibili 提供的视频章节(进度条分段)。
|
|
4
|
+
* 无章节时返回 chapters: []。
|
|
5
|
+
* 播放器/网络错误向上传播,不静默吞掉。
|
|
6
|
+
*/
|
|
7
|
+
export declare function getVideoChaptersData(bvidOrUrl: string, page?: number): Promise<VideoChaptersData>;
|
|
8
|
+
//# sourceMappingURL=chapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapters.d.ts","sourceRoot":"","sources":["../../src/bilibili/chapters.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKjE;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,iBAAiB,CAAC,CA2B5B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Bilibili 视频章节(view_points)检索
|
|
2
|
+
import { getPlayerData, matchPartIdentity, resolvePartCid } from "./client.js";
|
|
3
|
+
import { extractBVId } from "../utils/bvid.js";
|
|
4
|
+
const MAX_CHAPTER_TITLE_LENGTH = 500;
|
|
5
|
+
const MAX_CHAPTERS = 200;
|
|
6
|
+
/**
|
|
7
|
+
* 获取 Bilibili 提供的视频章节(进度条分段)。
|
|
8
|
+
* 无章节时返回 chapters: []。
|
|
9
|
+
* 播放器/网络错误向上传播,不静默吞掉。
|
|
10
|
+
*/
|
|
11
|
+
export async function getVideoChaptersData(bvidOrUrl, page) {
|
|
12
|
+
const bvid = extractBVId(bvidOrUrl);
|
|
13
|
+
const { cid, pages, videoData } = await resolvePartCid(bvidOrUrl, page);
|
|
14
|
+
const { page: displayPage, title: displayTitle } = matchPartIdentity(cid, pages, videoData.title);
|
|
15
|
+
const playerData = await getPlayerData(bvid, cid);
|
|
16
|
+
const viewPoints = playerData?.view_points;
|
|
17
|
+
const chapters = [];
|
|
18
|
+
if (viewPoints && viewPoints.length > 0) {
|
|
19
|
+
for (const vp of viewPoints.slice(0, MAX_CHAPTERS)) {
|
|
20
|
+
chapters.push({
|
|
21
|
+
title: (vp.content || vp.title || "").slice(0, MAX_CHAPTER_TITLE_LENGTH),
|
|
22
|
+
start_seconds: vp.from,
|
|
23
|
+
end_seconds: vp.to,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
bvid,
|
|
29
|
+
page: displayPage,
|
|
30
|
+
cid,
|
|
31
|
+
title: displayTitle,
|
|
32
|
+
chapters,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=chapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapters.js","sourceRoot":"","sources":["../../src/bilibili/chapters.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,MAAM,wBAAwB,GAAG,GAAG,CAAC;AACrC,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB,EACjB,IAAa;IAEb,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAExE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IAElG,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,UAAU,EAAE,WAAW,CAAC;IAC3C,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,KAAK,MAAM,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;YACnD,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,CAAE,EAA8B,CAAC,OAAiB,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC;gBAC/G,aAAa,EAAE,EAAE,CAAC,IAAI;gBACtB,WAAW,EAAE,EAAE,CAAC,EAAE;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,WAAW;QACjB,GAAG;QACH,KAAK,EAAE,YAAY;QACnB,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { checkLoginStatus, fetchWithWBI, fetchWithoutWBI } from "./http.js";
|
|
2
|
-
export { getSubtitleContent, getVideoInfo, getVideoSubtitle, } from "./video-api.js";
|
|
2
|
+
export { getPlayerData, getSubtitleContent, getVideoInfo, getVideoSubtitle, } from "./video-api.js";
|
|
3
3
|
export { getVideoComments } from "./comments-api.js";
|
|
4
|
+
export { matchPartIdentity, normalizePages, resolvePartCid } from "./navigation.js";
|
|
4
5
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bilibili/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/bilibili/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/bilibili/client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// B站 API 客户端 — 兼容性 re-export
|
|
2
2
|
export { checkLoginStatus, fetchWithWBI, fetchWithoutWBI } from "./http.js";
|
|
3
|
-
export { getSubtitleContent, getVideoInfo, getVideoSubtitle, } from "./video-api.js";
|
|
3
|
+
export { getPlayerData, getSubtitleContent, getVideoInfo, getVideoSubtitle, } from "./video-api.js";
|
|
4
4
|
export { getVideoComments } from "./comments-api.js";
|
|
5
|
+
export { matchPartIdentity, normalizePages, resolvePartCid } from "./navigation.js";
|
|
5
6
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/bilibili/client.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/bilibili/client.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/bilibili/metadata.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/bilibili/metadata.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAgC5B"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// 视频元数据 wrapper
|
|
2
|
-
import { getVideoInfo } from "./
|
|
2
|
+
import { getVideoInfo, resolvePartCid } from "./client.js";
|
|
3
3
|
import { extractBVId } from "../utils/bvid.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* 获取视频元数据(不含字幕、评论),含多P pages 列表。
|
|
6
6
|
*/
|
|
7
7
|
export async function getVideoMetadataData(bvidOrUrl) {
|
|
8
8
|
const bvid = extractBVId(bvidOrUrl);
|
|
9
9
|
const videoData = await getVideoInfo(bvid);
|
|
10
|
+
const { pages } = await resolvePartCid(bvidOrUrl, undefined, videoData);
|
|
10
11
|
const pubdate_timestamp = videoData.pubdate
|
|
11
12
|
? videoData.pubdate
|
|
12
13
|
: undefined;
|
|
@@ -22,6 +23,7 @@ export async function getVideoMetadataData(bvidOrUrl) {
|
|
|
22
23
|
pubdate_timestamp,
|
|
23
24
|
description: videoData.desc || "",
|
|
24
25
|
tags: videoData.tag?.map((t) => t.tag_name) || [],
|
|
26
|
+
pages,
|
|
25
27
|
stats: {
|
|
26
28
|
view: videoData.stat?.view,
|
|
27
29
|
like: videoData.stat?.like,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/bilibili/metadata.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/bilibili/metadata.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB;IAEjB,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAExE,MAAM,iBAAiB,GAAG,SAAS,CAAC,OAAO;QACzC,CAAC,CAAC,SAAS,CAAC,OAAO;QACnB,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,OAAO,GAAG,iBAAiB;QAC/B,CAAC,CAAC,IAAI,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;QAClD,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,SAAS,CAAC,KAAK;QACtB,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI;QAC7B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,OAAO;QACP,iBAAiB;QACjB,WAAW,EAAE,SAAS,CAAC,IAAI,IAAI,EAAE;QACjC,IAAI,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE;QACjD,KAAK;QACL,KAAK,EAAE;YACL,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI;YAC1B,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI;YAC1B,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI;YAC1B,QAAQ,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ;YAClC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK;YAC5B,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK;YAC5B,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO;SACjC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getVideoInfo } from "./video-api.js";
|
|
2
|
+
import type { PartInfo, RawPageEntry } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* 将 Bilibili 原始 pages 条目规范化为 PartInfo 列表。
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizePages(rawPages: RawPageEntry[] | undefined): PartInfo[];
|
|
7
|
+
/**
|
|
8
|
+
* 根据可选 page 解析出目标 CID 和完整的 Part 列表。
|
|
9
|
+
* page 为 undefined 时使用 top-level videoData.cid。
|
|
10
|
+
* 接受可选的 preFetchedVideoData 以避免重复请求。
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolvePartCid(bvidOrUrl: string, page?: number, preFetchedVideoData?: Awaited<ReturnType<typeof getVideoInfo>>): Promise<{
|
|
13
|
+
cid: number;
|
|
14
|
+
pages: PartInfo[];
|
|
15
|
+
videoData: Awaited<ReturnType<typeof getVideoInfo>>;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* 在 Part 列表中匹配给定 CID 的条目,返回其 page 和 title。
|
|
19
|
+
* 无匹配时返回 page=1 和 fallbackTitle。
|
|
20
|
+
*/
|
|
21
|
+
export declare function matchPartIdentity(cid: number, pages: PartInfo[], fallbackTitle: string): {
|
|
22
|
+
page: number;
|
|
23
|
+
title: string;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/bilibili/navigation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,GAAG,QAAQ,EAAE,CAQ/E;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,GAC7D,OAAO,CAAC;IACT,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC;CACrD,CAAC,CAmBD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,QAAQ,EAAE,EACjB,aAAa,EAAE,MAAM,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAIjC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// 共享 Part/CID 解析模块 — 所有 page 选择工具共用
|
|
2
|
+
import { getVideoInfo } from "./video-api.js";
|
|
3
|
+
import { extractBVId } from "../utils/bvid.js";
|
|
4
|
+
import { ValidationError } from "../utils/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* 将 Bilibili 原始 pages 条目规范化为 PartInfo 列表。
|
|
7
|
+
*/
|
|
8
|
+
export function normalizePages(rawPages) {
|
|
9
|
+
if (!rawPages || rawPages.length === 0)
|
|
10
|
+
return [];
|
|
11
|
+
return rawPages.map((p) => ({
|
|
12
|
+
page: p.page,
|
|
13
|
+
cid: p.cid,
|
|
14
|
+
title: p.part || `P${p.page}`,
|
|
15
|
+
duration: p.duration,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 根据可选 page 解析出目标 CID 和完整的 Part 列表。
|
|
20
|
+
* page 为 undefined 时使用 top-level videoData.cid。
|
|
21
|
+
* 接受可选的 preFetchedVideoData 以避免重复请求。
|
|
22
|
+
*/
|
|
23
|
+
export async function resolvePartCid(bvidOrUrl, page, preFetchedVideoData) {
|
|
24
|
+
const bvid = extractBVId(bvidOrUrl);
|
|
25
|
+
const videoData = preFetchedVideoData ?? await getVideoInfo(bvid);
|
|
26
|
+
const pages = normalizePages(videoData.pages);
|
|
27
|
+
if (page !== undefined) {
|
|
28
|
+
if (!Number.isInteger(page) || page < 1) {
|
|
29
|
+
throw new ValidationError("page must be a positive integer");
|
|
30
|
+
}
|
|
31
|
+
const part = pages.find((p) => p.page === page);
|
|
32
|
+
if (!part) {
|
|
33
|
+
throw new ValidationError(`Page ${page} not found. Valid pages: ${pages.length > 0 ? `1-${pages.length}` : "none (single-Part video)"}`);
|
|
34
|
+
}
|
|
35
|
+
return { cid: part.cid, pages, videoData };
|
|
36
|
+
}
|
|
37
|
+
return { cid: videoData.cid, pages, videoData };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 在 Part 列表中匹配给定 CID 的条目,返回其 page 和 title。
|
|
41
|
+
* 无匹配时返回 page=1 和 fallbackTitle。
|
|
42
|
+
*/
|
|
43
|
+
export function matchPartIdentity(cid, pages, fallbackTitle) {
|
|
44
|
+
const match = pages.find((p) => p.cid === cid);
|
|
45
|
+
if (match)
|
|
46
|
+
return { page: match.page, title: match.title };
|
|
47
|
+
return { page: 1, title: fallbackTitle };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/bilibili/navigation.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAoC;IACjE,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,KAAK,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE;QAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ;KACrB,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB,EACjB,IAAa,EACb,mBAA8D;IAM9D,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,mBAAmB,IAAI,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAE9C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,eAAe,CAAC,iCAAiC,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,eAAe,CACvB,QAAQ,IAAI,4BAA4B,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,0BAA0B,EAAE,CAC9G,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC7C,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAW,EACX,KAAiB,EACjB,aAAqB;IAErB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAC/C,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAC3D,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -11,16 +11,17 @@ export interface SubtitleData {
|
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* 获取纯视频转录文本
|
|
15
15
|
*
|
|
16
16
|
* 不自动降级到描述。如果字幕不可用:
|
|
17
17
|
* - fallbackToDescription=false -> throw NoSubtitleError
|
|
18
18
|
* - fallbackToDescription=true -> return description text
|
|
19
19
|
* - COOKIE_EXPIRED 错误始终向上传播
|
|
20
|
+
* - 当 timestamps 或 range 被请求时,拒绝 description fallback
|
|
20
21
|
*/
|
|
21
|
-
export declare function getVideoTranscriptData(bvidOrUrl: string, preferredLang?: string, fallbackToDescription?: boolean): Promise<VideoTranscriptData>;
|
|
22
|
+
export declare function getVideoTranscriptData(bvidOrUrl: string, preferredLang?: string, fallbackToDescription?: boolean, page?: number, includeTimestamps?: boolean, startSeconds?: number, endSeconds?: number): Promise<VideoTranscriptData>;
|
|
22
23
|
/**
|
|
23
24
|
* 获取视频信息及字幕
|
|
24
25
|
*/
|
|
25
|
-
export declare function getVideoInfoWithSubtitle(bvidOrUrl: string, preferredLang?: string): Promise<SubtitleData>;
|
|
26
|
+
export declare function getVideoInfoWithSubtitle(bvidOrUrl: string, preferredLang?: string, page?: number): Promise<SubtitleData>;
|
|
26
27
|
//# sourceMappingURL=subtitle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtitle.d.ts","sourceRoot":"","sources":["../../src/bilibili/subtitle.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"subtitle.d.ts","sourceRoot":"","sources":["../../src/bilibili/subtitle.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,UAAU,GAAG,aAAa,CAAC;IACxC,UAAU,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH;AAkID;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,EACtB,qBAAqB,CAAC,EAAE,OAAO,EAC/B,IAAI,CAAC,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,OAAO,EAC3B,YAAY,CAAC,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,CAAC,CAoI9B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,EACtB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAuJvB"}
|