GhifariArsa/soap
GitHub: GhifariArsa/soap
一款键盘驱动的终端参考文献管理工具,支持从多种来源自动抓取元数据并以可版本控制的纯文本格式管理论文、书籍和 PDF。
Stars: 19 | Forks: 0
# 🧼 soap
**一个用于论文、书籍和 PDF 的终端参考文献管理器 —— 添加来源、抓取元数据、审查不确定的内容,并通过键盘驱动的 TUI 浏览所有内容。**
让 soap 指向一个本地文件、DOI、arXiv ID、ISBN、目录或 URL。它会解析
元数据(对于链接,还会尽最大努力下载 PDF),将任何它不确定的内容排入队列
以便快速审查,并将所有内容保存在磁盘上一个纯净、可读且
可进行版本控制的库中。随后你可以浏览、搜索、标记以及
打开它 —— 所有这些都不必离开终端。
[](https://github.com/GhifariArsa/soap/actions/workflows/ci.yml)
[](https://github.com/GhifariArsa/soap/releases)

[](LICENSE)
[](https://pypi.org/project/soap-tui/)
[](https://github.com/GhifariArsa/homebrew-soap)

## 概述
维护一个参考文献库通常意味着运行一个庞大的桌面
应用程序,或者维护一个文件夹,里面塞满名为
`paper (3) final_v2.pdf` 的 PDF 文件。soap 两者都不是。它是一个快速、键盘优先的 TUI,
由一个库提供支持,在该库中**每条记录都是磁盘上的普通 `info.yaml` 文件** ——
因此你可以阅读它、对它进行 diff 操作,以及将它提交到 git。
soap:
- **接受任何来源** —— 本地文件、整个目录、DOI、纯粹的 arXiv
ID、ISBN 或 URL;
- 自动从 Crossref、arXiv 或 Open Library **抓取元数据**,并
尽最大努力为 arXiv 和直接 PDF 链接(以及
开放获取的 DOI)**下载 PDF**;
- **将不确定的记录排入队列**,以便你可以在一轮
快速审查中接受、更正或跳过它们,而不是盲目相信一个糟糕的猜测;
- 并允许你从 TUI **浏览、搜索、标记和打开**整个库 ——
或者通过 CLI 操作同一个库。
磁盘上的记录是唯一事实来源;SQLite 索引只是一个快速、
可重建的视图。soap 绝不会解析你 PDF 的内容。
## 安装
**Homebrew**(推荐 —— 无需 Python):
```
brew install GhifariArsa/soap/soap-tui
```
这将安装一个独立的二进制文件(通过 PyApp 嵌入 CPython 3.14),因此**无需
Python 或 pip**。支持范围涵盖 **Apple Silicon macOS 和 Linux
(arm64 / x86_64)**;没有 Intel-macOS 二进制文件,因此在 Intel
mac 上执行 `brew install` 会迅速失败并给出明确的提示信息。使用 `brew upgrade soap-tui` 进行升级。该
tap 及其关于 Intel-mac 的说明位于
[GhifariArsa/homebrew-soap](https://github.com/GhifariArsa/homebrew-soap)。
**独立二进制文件**(macOS arm64,Linux arm64 / x86_64) —— 安装程序
在将 `soap` 放入 `~/.local/bin` 之前会验证下载:
```
curl -fsSL https://raw.githubusercontent.com/GhifariArsa/soap/main/install.sh | sh
```
设置 `SOAP_VERSION=v0.1.0` 以固定某个版本,或设置 `SOAP_INSTALL_DIR` 来更改
安装目录。安装程序需要已发布的 release。
**从 PyPI**(需要 [uv](https://docs.astral.sh/uv/) 和 Python **3.14+**):
```
uv tool install soap-tui
```
**从代码仓库检出的版本** —— 最简单的尝试方式:
```
git clone https://github.com/GhifariArsa/soap.git
cd soap
uv run soap init
```
该发行版的名称为 **`soap-tui`**(因为 PyPI 上普通的 `soap` 已被占用),
但安装的命令始终为 **`soap`**。
然后一次性设置好你的库:
```
soap init
```
`init` 会创建库、其 SQLite 索引以及一个用于 `SOAP_DIR` 的 shell export。
默认库路径为 `~/.soap`;`SOAP_DIR` 会更改默认值,而 `--path
` 会覆盖这两者。它会写入 `config.yaml`、`inbox/`、`documents/` 和
`soap.db`,并在你的 shell 配置文件中写入带引号的 `SOAP_DIR` export(如果无法检测到
shell,则会打印一条安全的 export 命令)。一个全新的库会设置
`always_review: true`,而且重新运行 `init` 永远不会覆盖现有的配置。
| 选项 | 描述 |
| --- | --- |
| `--path ` | 初始化一个不同的库。 |
| `--shell auto\|zsh\|bash\|fish` | 选择要更新的 shell 配置。 |
| `--force` | 重新初始化现有库;具有破坏性,但会备份旧数据库。 |
## 使用方法
核心工作流程非常直接:**添加来源,进行审查,然后运行
`soap` 来浏览。**
从代码仓库检出运行时,请在命令前加上 `uv run`;而已安装的版本则直接使用 `soap`。
```
# arXiv ID 解析 metadata,并尽最大努力下载其 PDF。
soap add 1706.03762
# 一个新的 `soap init` route 通过 review queue 进行添加。
soap inbox review
# 然后浏览 library。
soap
```
对于本地 PDF,请自行提供标识符或元数据:
```
soap add ~/papers/paper.pdf --doi 10.1145/3292500.3330701
# 或者完全离线工作:
soap add ~/papers/paper.pdf --no-fetch \
--title "Attention Is All You Need" \
--author "Vaswani, Ashish" --year 2017
```

`SOURCE` 可以是本地文件、目录、URL、DOI 或纯 arXiv ID;ISBN
元数据通过 `--isbn` 提供,标识符也可以通过
`--doi` 或 `--arxiv` 显式传递。最常用的选项:
| 选项 | 描述 |
| --- | --- |
| `--title`, `--author`, `--year`, `--type` | 覆盖元数据。`--author` 可重复使用。 |
| `--tag`, `--collection` | 添加可重复的标签或集合。 |
| `--no-fetch` | 跳过网络元数据查找。 |
| `--recursive` | 包含目录来源下的文件。 |
| `--confirm` | 在保存前内联更正核心字段。 |
| `--edit`, `-e` | 在 `$EDITOR` 中编辑生成的 `info.yaml`。 |
| `--dry-run` | 预览添加操作,不写入任何内容。 |
| `--force` | 即使检测到重复也强制添加。 |
| `--path ` | 使用 `$SOAP_DIR` 或 `~/.soap` 之外的库。 |
运行 `soap add --help` 和 `soap inbox review --help` 以列出所有可用选项。
### 审查收件箱
`soap inbox review` 会一次展示一条 `needs_review` 记录:
- `a` —— 按原样接受
- `c` —— 更正标题、作者、年份、类型或出处(venue);按 Enter 键保留当前值
- `e` —— 在 `$EDITOR` 中打开完整的 `info.yaml`
- `s` —— 稍后跳过
- `d` —— 确认后删除它及其附加文件
- `q` —— 退出遍历
TUI 的审查屏幕共享同一个审查核心:`enter`/`a` 归档,`c`
更正,`e` 打开 `$EDITOR`,`s` 跳过,`q`/`esc` 结束。`soap add
--confirm` 在添加过程中提供同样的引导式字段更正。
### 快捷键
运行不带子命令的 `soap` 以打开 TUI。随时按 `?` 查看
应用内参考指南;主屏幕的精简映射如下所示。
```
j / k · g / G move · jump to top / bottom
Ctrl-D / Ctrl-U half-page down / up
Tab / Shift-Tab cycle panes h / l focus left / right
enter / o open the selected file or URL
/ search title, author, tag, or DOI (Enter/Tab → list)
E edit the core fields (title/authors/year/type/venue) in an in-app form
e edit the complete `info.yaml` in $EDITOR (full power option)
d delete — the marked documents in bulk (one confirm), or the single row
t tag — additive bulk-tag across the selection, or the single-document editor
m cycle read status: unread → reading → read
space mark / unmark the row; marks drive t / d / x on the whole selection
u unselect all (clear the whole selection; no-op when nothing is marked)
x export to BibTeX (choose scope: selected / filtered / all)
r review the inbox
Ctrl-R refresh from disk
? / Ctrl-P keyboard reference / command palette
Ctrl-T cycle themes
q quit
```
### 使用选区
按 `space` 键标记行(标记符号会替换状态图标;标记过程保持
安静,这样你就可以快速扫过一列)。标记会将单文档操作转换为
批量操作:
- `t` —— 一次性为每个标记的文档添加标签(累加模式:保留现有标签)
- `d` —— 在经过一次计数确认后,删除每个标记的文档及其文件
- `x` —— 将标记的文档导出为 BibTeX
如果没有任何标记,`t`/`d` 将像以前一样,精确地作用于光标所在的
单行。批量 `t`/`d` 会消耗选区(一旦操作完成,它就会清空);取消
确认则会使文档和选区保持不变。按 `u` 一次性清除整个
选区(当没有标记任何内容时为空操作);它也存在于 `?` 参考指南和命令面板中。
### 导出至 BibTeX
按 `space` 键标记行,然后按 `x` 导出 —— 或者在没有标记任何内容的情况下按 `x`。
导出操作总是会要求指定一个明确的范围,而不是静默地导出整个
库:
- **已选** —— 你标记的行(仅在标记了某些内容时提供)
- **已过滤** —— 当前显示的文档(遵循侧边栏激活的过滤器
和 `/` 搜索)
- **全部** —— 库中的每一条记录
然后你需要输入目标路径。相对名称将保存在你启动
`soap` 的目录下(显示在模态框中),而不是库中;`~` 和绝对
路径同样有效,缺少扩展名时默认为 `.bib`。该模态框会显示
精确解析出的文件的实时 `saves to …` 预览。soap 会写入一个确定性的
`.bib` 文件 —— 条目按引用键(citekey)排序,值被安全转义 —— 使用每个
文档的引用键作为条目键,并使用其元数据作为字段。导出操作仅
读取库:它绝不会修改任何内容,也不会触碰
网络,并且会报告写入了多少条记录(以及由于
元数据不完整而跳过了哪些记录)。同样的操作也可以在 `Ctrl-P` 命令面板中找到,名称为 **Export BibTeX**。
## 工作流程如何协同工作
1. **一次性初始化。** `soap init` 创建库、其 SQLite 索引以及一个
用于 `SOAP_DIR` 的 shell export。
2. **添加来源。** `soap add` 接收文件、目录、DOI、arXiv ID、ISBN 或
URL。根据需要重复使用 `--author`、`--tag` 或 `--collection`;对
目录使用 `--recursive`。
3. **审查。** `soap inbox review` 或 TUI 的 `r` 操作允许你接受、
更正、编辑、跳过或删除每一条 `needs_review` 记录。`--confirm` 将
同样的引导式更正合并到 `add` 中。
4. **浏览。** 运行不带子命令的 `soap`。侧边栏会过滤所有文档、
审查收件箱、阅读状态、标签和集合;`/` 用于搜索。
5. **打开并标记。** `enter`/`o` 使用操作系统默认处理程序打开第一个附加文件(或记录的
URL)。`m` 在未读 → 阅读中 → 已读之间循环。
元数据查找会酌情使用 Crossref、arXiv 或 Open Library。arXiv 和
直接 PDF URL 会尽最大努力下载 PDF,开放获取的 DOI 也可能
会下载;遇到付费墙或下载失败仍然会保存元数据。soap **不会**
解析 PDF 内容。
## 配置与数据
库路径按以下顺序解析:
1. 在支持该选项的地方(`init`、`add`、`inbox review`)使用 `--path `
2. `$SOAP_DIR`
3. `~/.soap`
其重要文件布局如下:
```
$SOAP_DIR/
├── config.yaml
├── soap.db # rebuildable SQLite index
├── inbox/ # library directory created by init
└── documents/
└── /
├── info.yaml # authoritative document record
└── paper.pdf # attached file(s), if any
```
`info.yaml` 是**唯一事实来源**。每一次更改都会首先写入文档文件,
然后再同步 SQLite 索引 —— 该索引只是文件和元数据的快速、
反规范化视图。因此,TUI 和 CLI 读取并
修改的是同一个库,并且在没有索引的情况下,磁盘上的记录依然保持可读性和
可版本控制性。
审查**收件箱是一种 `needs_review` 状态**,而不是文档的
第二个副本:记录及其附件会保留在 `documents//` 下,直到
它们被归档、跳过或删除。新的引用键(citekey)会同时命名文档文件夹
及其 `info.yaml`;在审查期间更正记录会保留该 citekey,并且
只有新的添加操作才会派生出新的键。
## 主题
可以通过 `t` 键从选定的文档编辑标签,标签同时充当侧边栏
过滤器。TUI 附带了 `aqua-slate`(默认)、`one-dark` 和
`catppuccin-mocha` 主题 —— `Ctrl-T` 循环切换它们,并且选择会保存在
`config.yaml` 中。用户主题位于 `$SOAP_DIR/themes/`。
请参阅[主题格式](docs/themes.md)和
[示例主题](docs/example-theme.yaml)来构建你自己的主题。
## 许可证
[MIT](LICENSE)。标签:Python, TUI, 元数据获取, 学术工具, 文献管理, 无后门, 逆向工具