最近我寻找一个能从终端管理 Dev.to 文章的 CLI 工具。我每月撰写 4-5 篇文章,痴迷于追踪分析数据,并希望实现基于 git 的工作流。
我找到了 9 个现有工具,全部尝试后结果如下:
- devto-cli (Node): 最后一次提交是 2 年前。安装即崩溃。
- dev-to-git (Node): 仅支持同步到本地。无法推回。
- slinkity: 已废弃。
- forem-cli: 仅实现了 40+ 个端点中的 3 个。
每个工具都只做同一件事:发布文章。仅此而已。也许能拉取。也许能验证标签。
与此同时,Dev.to API 拥有 40+ 个端点,包括分析、语义搜索、机器学习驱动的内容概念、粉丝互动、趋势追踪和阅读列表管理。没有人使用它们。
于是我构建了 devpub。
目录
devpub 的独特功能
# 基础功能(所有工具都支持)
devpub push -f articles/my-post.md
devpub pull
# 终端中的分析
devpub stats
# Views: 246.5K | Reactions: 4.4K | Comments: 402 | Followers: 18.9K
# 包含热门文章的完整仪表板
devpub dashboard
# AI 驱动搜索(语义而非关键词)
devpub search "building serverless apps" --semantic
# 即时趋势
devpub trends
# 发布前捕捉问题
devpub validate
Enter fullscreen mode Exit fullscreen mode
区别不在于单一功能,而在于覆盖范围。以下是对比:
| 功能 | devpub | 其他工具 |
|---|---|---|
| 发布/更新文章 | Yes | Yes |
| 拉取文章到本地 | Yes | 部分 |
| 分析(7 个端点) | Yes | No |
| 语义搜索 | Yes | No |
| 趋势发现 | Yes | No |
| 文章验证 | Yes | No |
| 速率限制(30 req/30s) | Yes | No |
| 失败重试机制 | Yes | No |
| Concepts API(ML 主题) | Yes | No |
我在 Dev.to API 中发现的内容
在构建 devpub 的过程中,我发现了一些未在明显位置文档化的 API 端点:
1. 语义搜索 -- Dev.to 拥有完整的基于嵌入的搜索系统,使用 Gemini embeddings(768 维向量)和 pgvector。你可以按含义搜索文章,而非仅关键词。该端点返回余弦相似度分数。
2. Concepts API -- 这些是机器学习生成的主题分类,带有每日指标:页面浏览量、反应数、评论数、流行度评分。比手动标签强大得多。
3. V1 Accept Header -- V1 API 需要 Accept: application/vnd.forem.api-v1+json。没有它,你将获得 V0 响应。我未在任何竞争对手的代码中看到这一点。
4. 嵌套分析响应 -- 分析端点返回嵌套对象,如 {"page_views": {"total": 246454, "average_read_time_in_seconds": 306}},而非扁平整数。我检查过的每个工具要么不使用分析,要么会在这种结构上崩溃。
构建故事(真实发生的事)
我在一天内构建了 devpub 的核心。周一下午 2 点开始,当晚就有了可用的 CLI。以下是诚实的开发时间线:
第 1-2 小时:研究
在编写任何代码之前,我分析了 9 个竞争工具。下载、阅读源码,映射每个工具使用的 API 端点。发现最“完整”的工具仅覆盖了 40+ 个端点中的 12 个。大多数仅覆盖 3-5 个。
然后我阅读了完整的 Forem API 文档。不是每个人都读的摘要页,而是完整的 V1 规范。这就是我发现语义搜索、概念和分析端点的地方——没人知道它们存在。
第 3 小时:脚手架
pyproject.toml、src 布局、Click CLI 入口点。无聊的工作,但我用 15 分钟就让 devpub --help 工作了。这里的关键决定是使用 httpx 而非 requests。httpx 提供连接池、适当的超时以及后续异步选项,而无需更改接口。
第 4-5 小时:API 客户端
我在这里花了最多时间。不是因为 HTTP 调用困难。而是因为我希望客户端从第一天起就达到生产级:
- 真正有效的速率限制(滑动窗口,而非仅睡眠计时器)
- 针对 429 和 5xx 的指数退避重试
- 适当的错误消息而非堆栈跟踪
第一个版本没有这些。它只是调用 raise_for_status() 并向用户抛出丑陋的 httpx.HTTPStatusError 异常。我在测试中发现,当我拉取自己的 86 篇文章并在第 30 篇文章时遇到速率限制时,整个程序崩溃了。
第 6 小时:针对真实账户测试
这里事情变得有趣了。我第一次调用 devpub stats 时崩溃了:
TypeError: '>=' not supported between instances of 'dict' and 'int'
Enter fullscreen mode Exit fullscreen mode
原来分析端点返回 {"page_views": {"total": 246454}},而非 {"page_views": 246454}。嵌套字典。现有工具无法正确处理,因为没有工具使用分析。
健康检查端点也让我惊讶。在 V1 API(带 Accept 头)中,/health_checks/app 需要身份验证。没有头,它返回 401。所以我将健康检查改为调用 /users/me。
第 7 小时:push --all 惊吓
在测试中,push --all 差点将我的 README.md 发布到 Dev.to。原始逻辑是:查找任何带有 frontmatter 中 title 的 .md 文件并推送。我的 README 有带标题的 YAML frontmatter。
通过要求同时包含 title 和 published 键,并仅扫描已知目录(articles/、posts/、content/、drafts/)来修复。小事一桩,但想象一下意外将你的 CONTRIBUTING.md 作为 Dev.to 文章发布。
我会做不同的事
从 pull 命令开始,而不是 push。 Pull 迫使你在构建数据模型之前理解 API 响应格式。我先基于文档构建了模型,然后在真实响应看起来不同时不得不修复。
从一开始就进行模拟测试。 我先编写了所有代码,然后编写测试。应该在编写客户端方法的同时编写 API 模拟响应。这样会立即发现嵌套字典问题。
在 v0.0.1 中发布速率限制器。 我最初认为“我稍后添加”。在真实测试的 30 分钟内就遇到了限制。应该从第一个提交开始就存在。
架构(面向贡献者)
src/devpub/
api/ # 带速率限制和重试的 HTTP 客户端
cli/ # Click 命令 + Rich 终端输出
core/ # 业务逻辑(文章、同步、验证、配置)
templates/ # 文章脚手架(5 个模板)
Enter fullscreen mode Exit fullscreen mode
关键决定:
- Python + Click + Rich -- 大多数贡献者熟悉,优秀的终端用户体验
- httpx -- 支持异步,内置超时处理
- 滑动窗口速率限制器 -- 每 30 秒 30 个请求,自动睡眠
- 3 次带退避的重试 -- 处理 429 和 5xx 而不崩溃
- 基于 frontmatter 的追踪 -- 文章 ID 存储在你的 markdown 文件中,无需数据库
57 个测试,全部通过
$ pytest -v
57 passed in 1.08s
Enter fullscreen mode Exit fullscreen mode
测试使用 respx 模拟 HTTP 层。CI 中没有真实 API 调用。覆盖:
- API 客户端(所有端点、错误代码、重试)
- 文章模型(frontmatter 往返、slug 生成、标签解析)
- 同步逻辑(推送新文章、更新现有文章、dry run、错误处理)
- 验证(标题长度、标签数量、正文检查、规范 URL)
试用
pip install devpub
export DEVPUB_API_KEY=your_key_here
devpub doctor
Enter fullscreen mode Exit fullscreen mode
或从源码安装:
git clone https://github.com/simplynadaf/devpub.git
cd devpub
pip install -e .
Enter fullscreen mode Exit fullscreen mode
在以下地址获取你的 API 密钥:https://dev.to/settings/extensions
与 AI 代理配合
每个命令都返回结构化输出,静默处理速率限制,并支持 --dry-run。AI 编码代理(Claude Code、Copilot、Cursor)可以将 devpub 作为其发布层。代理编写文章,devpub 验证、推送并追踪性能。初始设置后无需人工干预。
贡献
该项目处于 beta 阶段。欢迎 PR。一些需要帮助的事项:
- 性能:pull 命令为每篇文章发出一个 API 调用。我们能批量处理吗?
- 图像重写:推送时相对路径应变为 GitHub 原始 URL
-
终端图表:
--graph标志被接受但尚未实现 - Hashnode 适配器:跨平台发布脚手架已就绪,需要实现
在 issues 中查看 good first issue 标签。
GitHub: github.com/simplynadaf/devpub
如果这为你节省了时间,请为仓库加星。如果有问题,请提交 issue。如果你想要一个功能,请发送 PR。
你当前的 Dev.to 工作流是什么?你是在浏览器编辑器中编写,还是有本地设置?好奇人们遇到的痛点是什么。
由 Sarvar Nadaf 构建 - 云架构师
关注我: Dev.to | GitHub | YouTube | LinkedIn
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.