Skip to main content
Glama
README.md
<p align="center">
  <img src="assets/banner.svg" alt="vidnote" width="100%">
</p>

<h1 align="center">vidnote</h1>

<p align="center">
  <b>把 B 站视频变成一篇带时间戳的 Markdown 笔记。</b><br>
  <sub>标题 · UP 主 · 分P · 简介 · 字幕,一个文件装完,点时间戳直接跳到视频对应位置。</sub><br>
  <sub>只做 B 站——分P、UP 主语义、中文字幕格式,通用转写工具不会替你处理这些。</sub>
</p>

<p align="center">
  <a href="https://github.com/paper-k1te/vidnote/actions/workflows/ci.yml"><img src="https://github.com/paper-k1te/vidnote/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
  <img src="https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white" alt="Python 3.10+">
  <img src="https://img.shields.io/badge/license-MIT-07C160" alt="MIT License">
  <img src="https://img.shields.io/badge/MCP-ready-00A1D6" alt="MCP ready">
  <img src="https://img.shields.io/badge/本地转写-无需_API_Key-8957E5" alt="Local transcription">
</p>

<p align="center">
  <a href="#-它能做什么">它能做什么</a> ·
  <a href="#-快速开始">快速开始</a> ·
  <a href="#-没有字幕怎么办">本地转写</a> ·
  <a href="#-给-agent-用">给 agent 用</a> ·
  <a href="#-常见问题">FAQ</a> ·
  <a href="#english">English</a>
</p>

---

```console
$ vidnote fetch BV1xx411c7mD --whisper
✓ 已生成 2026-11-04_标题_BV1xx411c7mD.md  (本地转写,412 条)
```

打开就是这个样子:

```markdown
---
title: 一个测试视频
platform: bilibili
bvid: BV1xx411c7mD
url: https://www.bilibili.com/video/BV1xx411c7mD
owner: 某UP
duration: 1:02:03
published: 2024-05-01
fetched: 2026-11-04
language: zh
subtitle: available
tags:
- bilibili
- vidnote
---

## 字幕

**00:00** 大家好,今天想聊一个很多人问过的问题。

**12:34** 这里是重点,我把它拆成三步。
```

## ✨ 它能做什么

- **一条命令归档**:链接、BV 号、av 号都支持识别,自动抓标题、UP 主、时长、发布时间、简介、标签。
- **分P 不迷路**:多P 视频会记录当前在第几集,时间戳链接自动添加 `&p=`。
- **字幕优先,转写兜底**:视频有字幕就直接用;没有就在本机跑 Whisper,音频不出你的电脑。
- **时间戳可点**:`[12:34](…?t=754)`,在 Obsidian、Logseq、浏览器里都能跳转。
- **YAML frontmatter**:字段固定,能被 Dataview 之类的工具直接查询、筛选、聚合。

## 🚀 快速开始

```bash
pip install vidnote
```

```bash
# 链接、BV 号、av 号都行
vidnote fetch "https://www.bilibili.com/video/BV1xx411c7mD"

# 第 2 个分P
vidnote fetch "https://www.bilibili.com/video/BV1xx411c7mD/?p=2"

# 只打印,不写文件
vidnote fetch BV1xx411c7mD --stdout

# 存到笔记库,并标记来源
vidnote fetch BV1xx411c7mD --dir ~/Notes/videos --source my-blog
```

没装包也可以直接跑:

```bash
uvx vidnote fetch BV1xx411c7mD
```

### 退出码

|  码  | 含义                                 |
| :---: | ------------------------------------ |
| `0` | 成功                                 |
| `1` | 输入无法解析、接口报错、网络失败     |
| `2` | 缺少可选依赖(如转写所需的 whisper) |
| `3` | 目标文件已存在,且没有加 `--force` |

脚本里判断退出码即可,不需要解析输出。

## 🔊 没有字幕怎么办

B 站对字幕接口做了登录限制,**未登录时大多数视频拿不到字幕**。所以真正的主力是本地转写:

```bash
pip install 'vidnote[whisper]'
vidnote fetch BV1xx411c7mD --whisper
```

流程:`yt-dlp` 取音频 → `faster-whisper` 在本机转写 → 生成带时间戳的笔记。**音频不会上传到任何服务器。**

首次运行会下载模型:

| 模型              |   大小 | 速度 | 建议                           |
| ----------------- | -----: | ---- | ------------------------------ |
| `tiny`          |  75 MB | 最快 | 只用来验证流程,中文质量差     |
| `base`          | 145 MB | 快   | 英文内容                       |
| `small`(默认) | 485 MB | 中等 | 中文内容,速度与准确率的平衡点 |
| `medium`        | 1.5 GB | 慢   | 对准确率要求高                 |

```bash
vidnote fetch BV1xx411c7mD --whisper --model medium
```

转写结果按 `视频 + 分P + 模型` 缓存在本地(Windows 在 `%LOCALAPPDATA%\vidnote`,其他系统在 `~/.cache/vidnote`),同一个视频第二次跑秒出。加 `--no-cache` 可跳过。

## 🤖 给 agent 用

装上 MCP 依赖后,把 vidnote 注册成一个 MCP server:

```bash
pip install 'vidnote[mcp]'
vidnote serve
```

Claude Code / Codex / Cursor 的配置:

```json
{
  "mcpServers": {
    "vidnote": {
      "command": "vidnote",
      "args": ["serve"]
    }
  }
}
```

agent 会多出一个工具 `fetch_note`:

| 参数             | 说明                                   |
| ---------------- | -------------------------------------- |
| `target`       | 链接、BV 号或 av 号                    |
| `page`         | 分P 序号,默认 1                       |
| `include_desc` | 是否包含简介,默认 `true`            |
| `transcribe`   | 没有字幕时是否本地转写,默认 `false` |

## 🧭 设计原则

三条承诺,都能在代码里验证:**只读公开接口**,不模拟登录、不批量抓取;**不编造内容**,没有字幕就说没有,不会用模型编一段假的;**不覆盖你的文件**,笔记里可能有你手写的东西,除非你显式 `--force`。

## ❓ 常见问题

<details>
<summary><b>会被 B 站封号吗?</b></summary>

这个工具只读取公开的视频信息和匿名可访问的接口,不登录、不发布、不改动你的账号。但**请控制请求频率**,不要拿它做批量爬取。用 shell 循环处理很多视频时,加上 `--delay 3`,让两次请求之间等 3 秒。

</details>

<details>
<summary><b>需要 OpenAI 或其他 API Key 吗?</b></summary>

不需要。转写在本地用 `faster-whisper` 跑,不联网、不调用任何云端模型。

</details>

<details>
<summary><b>转写太慢怎么办?</b></summary>

换小模型(`--model base` 或 `tiny`)。长视频(1 小时以上)用 `small` 在普通笔记本上大约需要 10–20 分钟。

</details>

<details>
<summary><b>为什么笔记里没有字幕?</b></summary>

说明这个视频没有可用字幕,而你也没加 `--whisper`。工具会明确写出"没有可用字幕"。

</details>

<details>
<summary><b>支持抖音、小红书、YouTube 吗?</b></summary>

暂不支持,见路线图,后续会更新

</details>

<details>
<summary><b>Windows 上有什么坑?</b></summary>

`faster-whisper` 依赖的 PyAV 在 14 之后改了接口,和部分版本不兼容。项目的 `[whisper]` 依赖已经锁定了可用版本,正常 `pip install` 不会踩到。

</details>

## 🗺 路线图

- [X] B 站单P/多P 抓取、字幕、时间戳
- [X] 无字幕视频的本地转写
- [X] CLI + MCP
- [ ] 按简介里的时间点自动生成章节
- [ ] 批量:一个收藏夹 / 一个 UP 主的所有视频
- [ ] 抖音、小红书
- [ ] 导出为 SRT / VTT

## 🛠 开发

```bash
git clone https://github.com/paper-k1te/vidnote.git
cd vidnote
pip install -e '.[dev]'

pytest          # 22 个测试
ruff check .    # 代码检查
```

CI 覆盖 Ubuntu 与 Windows,Python 3.10 / 3.12 / 3.13。

## 📄 许可证

[MIT](LICENSE)。可自由使用、修改、商用,保留版权声明即可。

---

<a id="english"></a>

## English

**vidnote** turns a Bilibili video into a timestamped Markdown note: title, uploader,
multi-part awareness, description, and a transcript — all in one portable file with
clickable timestamps.

```bash
vidnote fetch "https://www.bilibili.com/video/BV1xx411c7mD" --whisper
```

- Uses Bilibili's public web API; no login, no scraping workarounds.
- If a video has no captions (most don't without a session), transcribe locally with
  `faster-whisper` — audio never leaves your machine.
- Output is plain Markdown with YAML frontmatter, ready for Obsidian or any tool.
- Ships a CLI and an MCP server (`vidnote serve`) for coding agents.

MIT licensed.