yoinks 终端视频下载器全攻略:1800+ 站点、Ink 全屏 TUI、零广告干扰
视频下载这件事,桌面上从来不缺工具,缺的是「干净」。要么弹窗、要么假按钮、要么把页面劫持到广告站。GitHub 上由 Pablo Stanley 开源的 yoinks(4.3k⭐、MIT、TypeScript)走了一条完全相反的路:把 yt-dlp 塞进一个用 React 写的全屏 TUI,敲回车就下载,零干扰、零脚本、零浏览器扩展。
本文把这套工具的安装命令、核心特性、底层架构、Roadmap 一次拆完。
项目地址:https://github.com/pablostanley/yoinks
许可证:MIT
技术栈:Node 18+ + Ink(React for terminal)+ yt-dlp + ffmpeg-static
当前版本:0.3.1(2026-07-17)
一、它到底解决了什么问题
视频下载工具并不稀缺,稀缺的是「不污染你」的工具。市面上常见的方案都有硬伤:
| 方案 | 痛点 |
|---|---|
| 浏览器在线下载站 | 满屏广告、假按钮、跳转追踪、捆绑安装 |
| 浏览器扩展 | 需要为每种浏览器装一次,权限大、隐私风险高 |
| Python 命令行(yt-dlp 原生) | 需要装 Python、终端界面简陋、参数表长 |
| 桌面客户端 | 体量大、跨平台分裂、经常塞推广 |
yoinks 想做的是装一行 npm 就跑、全屏终端 UI、零广告的实现。它直接站在 yt-dlp 这个”已经支持 1800+ 站点的成熟下载引擎”肩膀上,把下载的人本身做成一份有质感的终端应用:
- 没有 Python 依赖(Node 18+ 即可)
- 没有”哪个分辨率下哪个参数”的记忆负担(UI 里直接选)
- 没有假按钮、推广、捆绑(MIT、纯终端、无浏览器污染)

二、三分钟跑起来
1. 一行安装
1 | npm install -g yoinks |
或者不想装全局:
1 | npx yoinks |
要求系统装了 Node 18+。yt-dlp 和 ffmpeg 都不用自己准备——yoinks 第一次运行时会把独立 yt-dlp 二进制下载到 ~/.yoinks/bin;ffmpeg 会从 PATH 找,没有就用 ffmpeg-static 兜底。
2. 三种启动方式
1 | yoinks https://youtu.be/dQw4w9WgXcQ # 直接进入下载器,没有就不问 |
支持站点包括但不限于:
- YouTube / YouTube Music
- X / Twitter
- Threads
- TikTok
- Vimeo / Twitch / Reddit / Facebook
- 以及 yt-dlp 支持的 1800+ 其他站点
3. 五秒操作流程
下图是选择下载格式的全屏 UI——左侧是视频标题 + 平台标签 + 时长 + UP 主,右侧是格式列表,每行都标了分辨率 + 估算大小,末行是音频 only:

1 | yoinks https://youtu.be/xxx |
整个过程对电脑和手机都是键盘 + 鼠标都能用:
- 键盘:
↑↓或j/k或数字键选格式,↵下载,esc返回,^c退出,^t切换主题 - 鼠标:yoink 按钮、格式列表、底部快捷键提示、Logo 全部可点(点击 Logo 直接回首页)
文件默认保存到 ~/Downloads,完成后在终端打印 ✓ yoinked → <文件路径>。
三、核心特性拆解
下面这些是 README 没全展开、但源码里实打实存在的功能。
1. 全屏 TUI,进入即接管
进入 yoinks 后,终端会切换到 alternate screen(\x1b[?1049h),整个屏幕交给 Ink 渲染,退出时恢复 scrollback。src/cli.tsx 里同时为 uncaughtException / unhandledRejection 注册了退出前强制还原屏幕的逻辑,避免崩溃时栈跟踪被 alternate screen 一起擦掉、看起来像静默崩溃。
1 | app.tsx 里 phase 是个 discriminated union: 'input' | 'probing' | 'picking' | 'downloading' | 'done' | 'error' |
整个生命周期是一个有限状态机,每种 phase 对应一组快捷键提示(HINTS 字典),底部 <Shortcuts> 组件统一渲染。
2. 三档主题:auto / light / dark
src/theme.ts 维护 auto light dark 三个主题对象:
- auto(默认):不设颜色,让 ANSI 颜色跟终端原生前景/背景。比”尝试检测终端深浅色”更靠谱,避免误判。
- light / dark:显式指定调色板(
#18181b主色,#52525b灰等)。
按 ^t 或点击底部主题按钮可在三档之间循环。--theme auto|light|dark 可为单次启动指定初始主题。
3. 解析度信息自动对齐:probe 元数据复用
这是 yoinks 性能上最聪明的一笔。下载流程是两步:
- probe:
ytdlp -J --no-playlist --no-warnings <url>拿 JSON 元数据,顺便写到os.tmpdir()/yoinks-info-<pid>-<ts>.json - download:直接传
--load-info-json <path>给 yt-dlp,跳过重新提取媒体 URL
媒体直链经常有过期时间,第一次失败时 yoinks 会自动 refreshing: true 状态重试一次,用 URL 重跑而非缓存 JSON,所以即便链接过期也不会卡死。
4. 自定义进度模板:让 yt-dlp 输出能解析
yt-dlp 默认进度输出是一段自然语言,yoinks 用 --progress-template 让它输出机器可解析的格式化串:
1 | download:YOINK|<downloaded>|<total>|<estimate>|<speed>|<eta> |
然后在 lib/ytdlp.ts 里逐行切割 buffer、以 YOINK| 前缀识别:
1 | if (line.startsWith(PROGRESS_PREFIX)) { |
进度条宽度按当前显示长度固定槽位(speed.padStart(10) eta.padEnd(12)),所以进度更新时整体布局不会抖——这在 Ink 的 yoga 布局下是个常见坑。
5. 鼠标点击 hit-testing:靠 frame 内容反查
ink 没有”绝对坐标”API,每个组件的命中区得自己算。yoinks 的做法很特别:
把 ink 每帧写出去的 stdout 缓存一份,点击时按文本内容反查哪一行是哪个可点击元素。
实现见 src/lib/click-map.ts:
1 | export function captureFrames<T extends NodeJS.WriteStream>(stream: T): T { |
命中检查时遍历候选 ClickTarget,按 match 字符串在 frameLines 里 indexOf,加上 padX/padY 容差。这样不需要维护任何”组件 → 矩形”的布局数学,布局改了不影响命中,代码量极小。
6. 平台识别 + URL 校验
src/lib/platforms.ts 维护了一份知名平台 → 显示名映射:
| hosts | 平台 |
|---|---|
| youtube.com / youtu.be / music.youtube.com | YouTube |
| x.com / twitter.com | X / Twitter |
| instagram.com | |
| threads.net / threads.com | Threads |
| tiktok.com | TikTok |
| vimeo.com / twitch.tv / reddit.com / facebook.com / fb.watch | … |
URL 校验用 new URL() 校验协议(只接受 http: / https:),避免把”看起来像 URL”的脏字符串(比如多行剪贴板内容)当 URL 处理。
7. 剪贴板预检测:Tab 一键粘贴
不带 URL 启动时,yoinks 会用 execFileSync 调平台命令读剪贴板:
| 平台 | 命令 |
|---|---|
| macOS | pbpaste |
| Windows | powershell Get-Clipboard |
| Linux | wl-paste / xclip / xsel(按顺序尝试) |
剪贴板里有合法 URL 时,输入框下方会提示「link in your clipboard — ⇥ to paste it」,按 Tab 一键填入。剪贴板内容会做单行校验(/\s/.test()),避免 new URL() 静默吃掉换行后误判。
8. 历史记录
输入过的 URL 会被存到本地(src/lib/history.ts 的 addToHistory / loadHistory),下次启动 ↑ 方向键可在历史里翻。文件位置和具体持久化格式以源码为准。
9. 取消清理 part 文件
downloading 阶段按 esc 或 ^c 取消时,ytdlp 子进程会被 abort signal 跟踪到过的 AbortController 中断,然后 removePartials() 把 yt-dlp 写过的 .part / .ytdl 半成品清掉,不会留垃圾。
process.on('exit', () => activeChild?.kill('SIGTERM')) 保证即便 React effect 没清理,yt-dlp 子进程也不会变孤儿。
10. ffmpeg 自动寻路
findFfmpeg() 顺序:
- PATH 里有
ffmpeg→ 返回undefined(让 yt-dlp 自己找) - PATH 里没有 → 加载
ffmpeg-static,验证可执行后返回绝对路径 - 都没有 → 返回
undefined(yt-dlp 仍能下载单文件格式,但合并 / mp3 提取就跳过了)
四、底层架构:从代码看工程质感
1. 目录结构
1 | src/ |
2. 关键设计取舍
异步 vs 同步:检测 yt-dlp --version 这种”必须”检查,用 child_process.spawn + Promise 异步跑。注释里明确写了”async on purpose: a spawnSync here blocks the event loop, which freezes ink mid-frame”——这就是 Ink + sync spawn 的经典坑。
布局稳定:下载阶段每个分支都固定三行(bar / gap / meta),保证状态切换时不会跳位。Gap 组件用显式 <Text> </Text> 行而非 <Box height={1}/> 空盒,因为 yoga 会优先压缩空盒 spacer。
Alt screen 恢复:exit 事件 + uncaughtException/unhandledRejection 都注册了 leaveAltScreen(),崩溃时栈跟踪能正常显示。
OS-aware 文件名:默认输出模板是 %(title).60s.%(ext)s,避免文件名过长触发文件系统错误。
3. 测试与质量门禁
1 | "scripts": { |
发布前强制走完「测试 + 类型检查 + 构建」三关。tsconfig 用 strict: true + ES2022 + react-jsx,模块系统走 Bundler。
五、Roadmap:接下来会加什么
README 列出的待办:
-
--best/--mp3flags,跳过 picker 直接下载(脚本化模式) -
-o <dir>自定义输出目录 - 播放列表 / 多视频 Threads 支持
- 不带参数启动时自动建议剪贴板 URL(部分已实现)
- 内置 yt-dlp 自更新(
yt-dlp -U) - 发布到 npm(已完成)
-
curl yoinks.sh | sh一键安装脚本
其中「剪贴板启动时自动建议」已经做了检测,但没自动填入——刻意保留一个 Tab 按键,避免误触发消耗输入。
七、判断:什么时候用 yoinks
适合:
- 经常从 YouTube / X / Threads / Instagram / TikTok 下载视频保存到本地
- 想在终端里直接完成”复制链接 → 下载”全链路,不开浏览器
- 不喜欢 yt-dlp 原生 CLI 的参数表,记不住
-f bv*+ba/b这种 selector - Node 开发者、终端控,对工具链有审美要求
- 需要在脚本里调用(等
--best/--mp3落地后会更顺手)
不适合:
- 想批量下载整个频道 / 播放列表(目前未支持,Roadmap 中)
- 想抓取需要登录的内容(和 yt-dlp 一样需要自己带 cookie)
- 找能转码 / 剪辑 / 加字幕的全功能工具(yoinks 只做下载,剪辑请接 ffmpeg 或剪辑软件)
- Windows 旧版本用户(要求 Node 18+,且 ffmpeg-static 对 Win7 之前的支持不一定全)
八、合规提醒
yoinks 是一个个人归档工具。README 明确说:
Downloading content may violate a platform’s terms of service — only download what you have the right to keep, and be excellent to creators.
简单说就是:只下载自己有权利保留的内容,不要拿去做二次分发,尊重创作者。这点和 yt-dlp、youtube-dl、gallery-dl、wx_channels_download 等同类工具的立场一致。
九、总结
yoinks 不是一个”颠覆性”的工具——它的下载能力完全来自成熟的 yt-dlp。它的真正价值是把”装 Python、记参数表、看错误日志”这套流程打包成一份三分钟能上手、有质感、零干扰的终端体验:
- 底层:yt-dlp + ffmpeg-static,1800+ 站点覆盖
- 界面:Ink 全屏 TUI,鼠标+键盘双操作,三档主题
- 工程:progress-template 解析进度、frame 内容反查做 hit-testing、info.json 复用加速、取消自动清理
- 分发:
npm i -g yoinks或npx yoinks,无需 Python
如果你是终端里干活的人,且经常从网上保存视频,yoinks 是目前最值得装的那一个。
延伸阅读:想了解另一个”为下载这件事做工程化”的工具,可以看 微信视频号下载神器 wx_channels_download 全解析——它走的是 MITM + 注入下载按钮路线,覆盖的站点完全不同;想了解 AI 工具链怎么省 Token,可以看 Codex(ChatGPT) 半年更新盘点:4 个省 Token 硬技巧 + 8 个新奇玩法;想看更多 GitHub 开源周榜的玩法切片,可以看 GitHub 9 月第一周开源热榜 Top 5。
欢迎在评论区聊聊你用 yoinks 录下的第一个视频、或者你常用的另一个下载神器。