Skip to content
ShadowzzhPublic

About

将视频链接转换为带时间锚点、截图和大纲的中文文章

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

VideoDoc

把视频链接转成一篇带时间锚点的中文图文文章。

License: MIT

它做什么

粘贴一个 YouTube 或 Bilibili 链接,VideoDoc 会下载视频、生成带时间戳的转写、 用 LLM 拆分大纲并按章节写正文、提取关键帧选配图(macOS 上还会做本地 OCR 取证), 最终产出一篇带配图的图文文章。

操作流程

1. 粘贴链接

把 YouTube / Bilibili 链接粘进输入框,点「开始处理」。

新建任务

2. 看进度

任务页会列出十个阶段,从解析来源、下载、转写到抽帧、写稿、收尾。 每个阶段只执行一次,失败会停下来等你在页面上点「重试当前阶段」。

处理流程

3. 读文章

完成后打开文章:左侧是大纲,中间是正文与配图,右下是视频浮窗。

文章详情

怎么用

点左侧大纲的任意章节,文章和视频会同时跳到那个位置,但视频不会自动播放: 原本暂停就保持暂停,只更新画面;原本在播放则继续播放。 点正文里的「→ 跳到 00:37」或任意配图,视频会跳过去并开始播放; 切到「转写」标签点任一片段,视频同样跳到对应时间点并开始播放。

桌面端快捷键(输入框聚焦时不生效):

键 作用
Space 播放 / 暂停
V 放大 / 缩小视频浮窗
Esc 从大窗还原为小窗

快速开始

需要 Python 3.11+、Node 20.19+ 与 pnpm、FFmpeg。

git clone https://github.com/Shadowzzh/VideoDoc.git
cd VideoDoc

cp .env.example .env      # 填 VIDEODOC_LLM_API_KEY(唯一必填项)
./scripts/serve.sh        # 自动建 venv、装依赖、构建前端

打开 http://127.0.0.1:8765/app/。换端口:./scripts/serve.sh 9000。

或手动分步执行
python3 -m venv .venv
.venv/bin/pip install -e .
pnpm --dir frontend install && pnpm --dir frontend build
.venv/bin/videodoc --port 8765

平台支持

除本地 OCR 外全部跨平台。

能力 范围
下载 / 转写 / 抽帧 / LLM / 网页界面 全平台(macOS 转写自动启用 Metal)
本地 OCR(读取配图文字) 仅 macOS;其他平台记录日志并跳过,任务继续

配置

两个入口,网页设置优先于环境变量:

  • 网页设置(/app/settings):改完对新任务立即生效,不用重启服务; 落在 ~/.config/videodoc/settings.json(权限 600,可用 VIDEODOC_SETTINGS_FILE 改路径)。
  • 环境变量 / .env:提供默认值,也适合无头部署。
设置分类 能配什么
文本模型 大纲和正文的 BaseURL、模型、Key(明文或密钥文件)、超时、重试与输出 token 上限
图像识别 本地 macOS Vision OCR 与云端视觉模型的通道、端点、预算

环境变量完整清单见 .env.example,常用的几项:

变量 默认值 说明
VIDEODOC_LLM_API_KEY — 必填(也可以只在网页设置里填)
VIDEODOC_LLM_BASE_URL https://api.deepseek.com 任意 OpenAI 兼容端点
VIDEODOC_LLM_MODEL deepseek-v4-flash 模型名
VIDEODOC_WHISPER_MODEL large-v3-turbo 模型名或本地 .bin 路径
VIDEODOC_COOKIE_BROWSER chrome 读取哪个浏览器的登录态;设为空则完全关闭
VIDEODOC_RUNTIME_DIR ~/.local/share/videodoc 运行产物目录

VIDEODOC_WHISPER_MODEL 保持默认时,首次运行会自动下载约 1.5GB 的模型。 网络受限可先自行下载 ggml-*.bin,再用该变量指向本地文件; 体积敏感也可以用更小的档位,例如 large-v3-turbo-q5_0(约 570MB)。

已知限制

  • 单用户、单 worker,任务顺序执行;JSON 文件存储,不引入数据库

  • 正式验收 YouTube 与 Bilibili;X 仅 best-effort

  • 本地 OCR 仅 macOS 可用

  • 删除任务走可恢复回收站(等待中也可删,仅运行中拒绝),暂无网页端恢复入口

    回收站默认在 ~/.local/share/videodoc/trash/(可用 VIDEODOC_RUNTIME_DIR 改数据根目录),任务目录名是 <task-id>-<删除时间>,需要恢复时移回:

    mv ~/.local/share/videodoc/trash/<task-id>-<YYYYMMDD-HHMMSS> \
       ~/.local/share/videodoc/tasks/<task-id>

开发

.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest -q        # 85 项,不访问网络
pnpm --dir frontend typecheck
pnpm --dir frontend test
videodoc/
├── cli.py / config.py / server.py
├── pipeline.py            # 十步流水线
├── task_store.py          # JSON 状态与断点续跑
└── integrations/          # crv 抽帧、whisper 转写、macOS OCR
frontend/                  # React + TypeScript + Vite + Tailwind + shadcn/ui
examples/                  # 示例产物(/sample 展示用)

流水线:probe → download → audio → transcribe → outline → frames → select_images → ocr → article → finalize

前端长文本约定

任务没有文章标题时 taskTitle 会退回原始分享链接,抖音链接常有 300+ 字符且 不含空格,渲染时按下面两条处理,否则会撑出容器:

  • 固定宽度的容器(确认框、卡片、提示块)用 [overflow-wrap:anywhere]; break-words(overflow-wrap: break-word)不参与 min-content 计算, Grid/Flex 的 auto 轨道仍会被长串撑开。
  • 需要硬约束的网格容器把列轨道写成 grid-cols-[minmax(0,1fr)], 并在确认框一类弹窗里给 max-h-[calc(100dvh-2rem)] 兜底。

许可

MIT

About

将视频链接转换为带时间锚点、截图和大纲的中文文章

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages