Skip to content

Repository files navigation

夏色祭工坊 TweetToaster 烤推机

夏色祭工坊

简介

这个烤肉机,其实是个推特嵌字机。
出现的初衷因该是,嵌字这件事儿,大家都爱不动了。
来回p图一样的东西,有些伤不起啊。

于是,为了解决重复性工作,工坊招了程序员,也终于搞出来了这个项目。

此项目主要感谢以下贡献者
FzXiao b站
飞雪 b站
鱼鱼 b站

功能

  • 手机首页直接输入链接;编辑与预览一键切换,桌面同时对照两栏,长图按屏幕宽度缩放而不改变下载尺寸
  • 接受 7216_2nd、@7216_2nd、x.com/7216_2nd 等主页输入
  • 接受带或不带 https:// 的 x.com/.../status/...、twitter.com/.../status/... 单推链接
  • 主页模式列出多条近期公开推文,默认预览前三条,可任意勾选
  • 单推模式同时列出上下文、目标推文和其他用户回复,可逐条选择、逐条翻译
  • 保留旧版翻译组 Logo 和 {T} HTML 模板,并内置、逐份验证 toastTemplates 的 49 个可见模板
  • 完整素材库可搜索,只有用户钉住的常用项才进入日常下拉菜单
  • 常用模板、最近选择、自定义 Logo、高级 HTML 草稿和命名模板均保存在浏览器本地,刷新后继续使用
  • Logo 按素材原始 CSS 像素等比显示,仅在超过 568px 出图内容区时防溢出,不再统一压小
  • 预览和下载共用 Chromium 渲染面;导出为 640 CSS px / 1280 实际像素的 2x PNG
  • 下载图片中的推文时间沿用预览的浏览器时区,包括跨日与夏令时;不受服务器时区影响
  • 兼容旧 Bot 的 /api/auto + /api/get_task=<id> 异步协议
  • 默认使用免费公开的 FxTwitter/FxEmbed API,可切换到自建实例

直接部署预构建镜像

镜像由 GitHub Actions 发布到 GHCR,不需要在服务器现场构建:

docker run -d \
  --name tweettoaster \
  --restart unless-stopped \
  --shm-size=512m \
  -p 127.0.0.1:8082:8082 \
  -v tweet-cache:/app/Matsuri_translation/frontend/cache \
  ghcr.io/cn-matsuri/tweettoaster:latest

仓库内的 Compose 文件同样只拉镜像:

docker compose pull
docker compose up -d
curl http://127.0.0.1:8082/api/health

每个同仓库 PR 还会发布 pr-<编号> 测试标签;合并到 master 后发布 latest,版本 tag 会发布同名镜像标签。

镜像清单同时包含 linux/amd64 与 linux/arm64。它可以直接运行在 Linux Docker,以及 macOS/Windows 的 Docker Desktop;这是 Linux 容器,不是 Windows 原生容器。

在 Nginx、Caddy 或 Cloudflare Tunnel 中把域名反代到 127.0.0.1:8082 即可。默认只监听本机,避免绕过反向代理直接暴露端口。

环境变量

变量 默认值 用途
PORT 8082 HTTP 端口
HOST 0.0.0.0 监听地址
CHROMIUM_PATH 自动发现 Bot/下载截图使用的 Chromium;镜像内已配置
TWEET_PROVIDER_URL https://api.fxtwitter.com/2 免费推文数据源根地址;也可指向自建 FxEmbed
TWEET_PROVIDER_TIMEOUT_MS 15000 数据源超时毫秒数
TWEET_TIMELINE_COUNT 12 主页最多显示的近期推文数,范围 1–20
TWEET_REPLY_COUNT 20 单推最多显示的回复数,范围 0–30
TEMPLATE_ALLOWED_HOSTS x.wudifeixue.com,raw.githubusercontent.com Bot 可下载模板的 HTTPS 域名白名单

Bot API 兼容

创建任务:

POST /api/auto
Content-Type: application/json

{
  "tweet": "https://x.com/user/status/123",
  "translate": "翻译文字",
  "template": "https://tweet.wudifeixue.com/template/matsuri.txt",
  "noLikes": false,
  "logo": "official"
}

返回 200 {"task_id":"..."}。轮询 GET /api/get_task=<task_id>;成功时 state 为 SUCCESS,result 是文件名,图片位于 /cache/<result>.png。

任务从提交起最多处理 45 秒,包括排队、获取推文、模板和截图。超时返回 state: "FAILURE"、code: "JOB_TIMEOUT",error / result 为可读错误信息;Bot 应在 SUCCESS 或 FAILURE 时停止轮询。不存在或已过期的任务返回 FAILURE / JOB_NOT_FOUND,不会无限停留在 PENDING。

单进程最多接纳 50 个未释放资源的任务,Chromium 串行截图;满载时创建任务返回 503 QUEUE_FULL。超时会取消网络请求、移除等待中的截图,并终止正在卡住的浏览器进程。只有实际工作清理完成才归还名额,不能通过删除任务记录绕过容量限制。进程内最多保留 500 条任务记录,已完成结果通常保留 1 小时(从完成时计时,容量满时提前淘汰旧结果);重启后任务记录不保留,需要重新提交。

旧 Bot 的多条翻译格式继续可用:

##1
第一条翻译
##2
第二条翻译

tweet 现在也可以传主页或用户名。template 可留空、直接传模板 HTML、传 /template/name.txt 本地路径,或传白名单内的 HTTPS 模板地址。远程模板限制为 64 KB,并拒绝内网地址。

Bot 可选传入 timeZone(例如 Asia/Shanghai、Asia/Tokyo、America/New_York)指定图片中的时区;省略时保留旧版的服务器默认时区。网页下载会自动传入预览所用的浏览器时区。无效时区返回 400 INVALID_TIME_ZONE。

经过整理的 toastTemplates 已随程序和预构建镜像发布,无需在服务器再 clone。/template/*.txt、/templates/*.txt、?template=/template/*.txt 和旧模板的多样式注释格式继续兼容。维护者可以在相邻源码目录运行 pnpm templates:sync 重新导入上游目录;生成的 frontend/templates/ 不包含废弃的 25 MB 远程字体。

个人模板与 Logo

“管理常用与上传”会打开完整素材库;搜索到需要的字幕组后点“加入常用”,它才会出现在日常下拉菜单。上传 Logo 和保存高级 HTML 模板后也会自动加入常用,并写入浏览器 IndexedDB。

  • 自定义 Logo 仅接受 PNG、JPEG、WebP,保留原图尺寸和比例。
  • 本地素材没有 50 KB 的产品限制,实际容量由浏览器配额决定;服务器不会建立用户素材库副本。
  • 下载 PNG 时,当前 Logo 会临时随出图请求送入同一台 TweetToaster 的 Chromium 进程,任务结束后不保留。为防止单次请求耗尽公共服务内存,临时出图数据上限为 32 MB。
  • 如果未来实现账户/服务端同步,服务端持久化 Logo 应另行执行 50 KB 限制;当前版本没有服务端同步。
  • 高级模板必须包含 {T}。输入会自动保存草稿,也可以命名保存多份模板;危险标签、事件属性和远程资源会在出图前移除。

本地开发与测试

需要 Node.js 22+ 和 Chrome/Chromium:

corepack enable
pnpm install
pnpm test
pnpm start

打开 http://localhost:8082。真实免费数据源回归测试单独运行:

pnpm test:live

PR 会执行单元测试、浏览器下载回归、依赖审计,以及 amd64/arm64 镜像构建。回归测试会用 Chromium 逐一真实渲染全部 51 个模板入口,并检查素材加载、原始尺寸、宽高比和 640px 出图面溢出;另有超过 2 MB 的浏览器本地 Logo 与模板刷新持久化测试。

任务生命周期回归覆盖:队列满载、超时后的真实资源释放、响应内容读取卡住、浏览器渲染卡住后恢复、终止任务不产生迟到的 PNG,以及旧 Bot 的失败轮询协议。

数据源与费用

默认数据来自免费的 FxEmbed/FxTwitter 公开 API,不需要 API Key,不接入任何付费 X API。公共实例可能调整限流或可用性;长期部署可自建 FxEmbed,再修改 TWEET_PROVIDER_URL,TweetToaster 本身无需改代码。


旧版项目记忆(保留)

旧版使用演示

发布文章 / Blog

庆贺吧,这是集数码暴龙与嵌字 man 力量于一身的烤推机

旧版使用方法:打开烤肉机后,输入需要查询的推特永久链接;查询、输入翻译内容,满意后下载图片。模板可以完全自定义,自己写 HTML 即可。

烤肉机模板源码地址:cn-matsuri/toastTemplates

使用感想 / Testimonial

茶铺使用感想

Releases

Packages

Used by

Contributors

Languages