打造一个优雅的视频下载助手:从浏览器到本地的无缝体验
打造一个优雅的视频下载助手:从浏览器到本地的无缝体验
前言
在观看B站或YouTube视频时,你是否遇到过这些场景:
- 想离线观看某个教程,但网络不好时反复卡顿
- 看到优质内容想保存下来,却要打开一堆在线下载网站
- 下载视频后想要字幕文件,又要额外操作一遍
作为一个经常需要保存视频的开发者,我决定打造一个一键下载的解决方案。于是就有了这个项目:Quick Download —— 一个优雅、高效的视频下载助手。
🎯 核心功能
1. 浏览器一键下载
安装用户脚本后,在B站或YouTube的视频页面,右侧会自动出现一个精美的下载按钮。点击即可,无需复制链接、打开网站、等待解析等繁琐步骤。
支持的平台:
- ✅ B站(常规视频、番剧、播放列表)
- ✅ YouTube(所有视频)
2. 智能字幕生成
下载视频的同时,系统会自动使用 AI 语音识别技术生成字幕文件(基于 Whisper 模型)。无论是中文还是英文视频,都能获得准确的字幕文本。
3. 可视化管理界面
访问 http://localhost:2999 即可打开管理界面,功能包括:
- 📊 统计面板:实时显示视频数量和平台分布
- 🔍 搜索功能:快速搜索视频标题和链接
- 📺 在线预览:直接在浏览器中预览已下载的视频
- 📝 字幕查看:查看和搜索视频字幕内容
- 🗑️ 记录管理:删除不需要的视频记录
🏗️ 技术架构
整个项目采用现代化的技术栈,注重性能和开发体验:
后端服务
- 运行时:[Bun](https://bun.sh) - 比 Node.js 快得多的 JavaScript 运行时
- Web 框架:[Hono](https://hono.dev) - 轻量级、高性能的 Web 框架
- 数据库:SQLite(使用
bun:sqlite原生模块) - 视频下载:
- B站:[yutto](https://github.com/siguremo/yutto)(Docker 版本)
- YouTube:[yt-dlp](https://github.com/yt-dlp/yt-dlp)
- 字幕生成:Buzz(基于 OpenAI Whisper)
前端
- 原生 HTML + CSS + JavaScript:无需构建工具,直接由 Bun 服务
- 用户脚本:Tampermonkey 扩展,注入到视频页面
核心代码结构
quick-download/
├── index.ts # 后端服务主入口
├── database.ts # 数据库管理
├── download-helper.user.js # 浏览器用户脚本
├── public/
│ └── index.html # 管理界面
└── videos.db # SQLite 数据库
💡 技术亮点
1. 平台自动识别
系统会智能识别视频链接类型,自动选择对应的下载工具:
function detectLinkType(link: string): "bilibili" | "youtube" | "unknown" {
if (link.includes("bilibili.com")) return "bilibili";
if (link.includes("youtube.com") || link.includes("youtu.be")) return "youtube";
return "unknown";
}
2. B站分P视频支持
B站的分P视频下载是个技术难点,我的解决方案是从URL中提取 p 参数,配合 yutto 的批处理参数实现精确下载:
const url = new URL(link);
const p = url.searchParams.get("p");
if (p) {
// 使用 -b -p 参数组合下载特定集数
batchParam = " -b";
pParam = ` -p ${p}`;
}
3. 视频流式传输
管理界面支持在线预览视频,实现了 HTTP Range 请求,支持视频进度条拖动:
if (range) {
const start = parseInt(parts[0] || "0", 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunk = file.slice(start, end + 1);
return new Response(chunk, {
status: 206,
headers: {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
},
});
}
4. 字幕文件智能匹配
字幕文件名可能有多种格式(如 video.txt, video (transcribed on 2025-10-18).txt),系统采用两级匹配策略:
// 策略1: 精确匹配
for (const ext of subtitleExts) {
const subtitlePath = path.join(dir, baseName + ext);
// 尝试读取
}
// 策略2: 模糊匹配
const matchingFile = files.find(file =>
file.startsWith(baseName) && file.endsWith(ext)
);
5. 优雅的用户体验
用户脚本会根据不同平台自适应样式:
- B站:蓝绿渐变主题色
- YouTube:红色主题色
- 实时状态提示(加载中、成功、失败)
- YouTube SPA 页面切换自动适配
🎮 使用体验
安装配置(5分钟搞定)
# 1. 克隆项目
git clone https://github.com/your-username/quick-download.git
# 2. 安装依赖
bun install
# 3. 安装下载工具
brew install yt-dlp ffmpeg
# 4. 启动服务
bun run start
日常使用(3步完成)
- 打开视频页面:在B站或YouTube浏览想要的视频
- 点击下载按钮:页面右侧的下载按钮会自动出现
- 等待完成:视频自动下载到
~/Downloads文件夹,并生成字幕
整个过程无需离开视频页面,体验极其流畅。
📊 性能表现
得益于 Bun 的高性能,整个系统运行非常高效:
- 启动速度:< 100ms
- API 响应:< 10ms(数据库查询)
- 内存占用:< 50MB(空闲状态)
- 下载速度:取决于网络和视频大小,但系统本身无瓶颈
🔒 隐私与安全
- 完全本地运行:所有数据保存在本地,不上传到任何服务器
- 开源透明:代码完全开源,可以自行审查
- Cookie 管理:B站 Cookie 仅用于下载,可自行配置
🚀 未来规划
这个项目还有很多可以改进的地方:
短期计划
- 支持更多视频平台(Vimeo、Twitch等)
- 批量下载功能
- 下载进度实时显示
- 字幕翻译功能
长期规划
- 桌面客户端(Electron)
- 云端同步(可选)
- 视频格式转换
- 下载队列管理
💭 开发心得
为什么选择 Bun?
在这个项目中,Bun 带来了极致的开发体验:
- 快:启动速度和运行性能都远超 Node.js
- 简洁:自动加载
.env,无需 dotenv - 内置工具:原生支持 SQLite、TypeScript、热重载
- 现代化:完美支持 ES Modules 和最新 Web API
为什么选择 Hono?
相比 Express,Hono 更适合现代 JavaScript 运行时:
- 为 Bun/Deno/Cloudflare Workers 设计
- 路由性能极高(基于 Radix Tree)
- TypeScript 原生支持
- 中间件生态完善
为什么用原生前端?
这个项目的前端足够简单,不需要 React/Vue 这样的框架:
- 零构建时间:Bun 直接服务 HTML
- 更好的性能:无框架开销
- 更易维护:代码简单直观
🎓 技术收获
通过这个项目,我深入学习了:
- Bun 生态系统:从 HTTP 服务到数据库,体验完整的 Bun 开发流程
- 视频下载技术:了解 yt-dlp 和 yutto 的工作原理
- 音频转录:Whisper 模型的实际应用
- 浏览器扩展开发:用户脚本的编写和调试
- HTTP Range 请求:视频流式传输的实现
📝 总结
Quick Download 是一个完全本地化、注重隐私、体验优雅的视频下载解决方案。它不仅解决了我的实际需求,也让我深入学习了现代 Web 技术栈。
如果你也有类似的需求,欢迎试用这个工具。项目完全开源,也欢迎贡献代码或提出建议!
附录:常见问题
Q: 为什么 B站下载需要 Docker?
A: B站的下载工具 yutto 依赖 Python 环境,使用 Docker 可以避免环境配置问题,开箱即用。
Q: 字幕生成需要多久?
A: 取决于视频长度,一般 1 分钟的视频需要 10-30 秒。使用的是 Whisper Small 模型,在速度和准确度之间取得平衡。
Q: 能下载 4K 视频吗?
A: 当前配置下载的是 480p 视频(考虑到文件大小和速度),可以在代码中修改 yt-dlp 的参数来下载更高清晰度。
Q: 支持移动端吗?
A: 目前只支持桌面浏览器。移动端浏览器的用户脚本支持不佳,建议在桌面端使用。