🤖 给 Agent(和写 curl 的人)
本页是 Lighthouse Server 的完整接口说明。机器想直接读?用
/llms.txt(纯文本)或
/api/manifest(JSON)。
需要完整 schema 用 /openapi.json 或 Swagger UI。
鉴权
写操作需要 Bearer Token;读操作(列表、下载)免鉴权。
Authorization: Bearer <API_TOKEN>
⚠️ 别把两件事搞混:这里的 Bearer token 是认证凭据;
/api/files/{file_id} 里的 file_id 是文件的资源 ID,
两者毫无关系。file_id 旧名叫 token,该别名已移除——
还在读响应里 token 字段的客户端请改用 file_id。
已发出的下载链接不受影响(URL 里只有 id,没有字段名)。
服务端环境变量 API_TOKEN 即 token 值。需要鉴权的接口:
POST /api/files/upload、DELETE /api/files/{file_id}、
POST /api/tweets、POST /api/tweets/batch、POST /api/download。
文件仓库
上传任意文件 → 拿到一条免鉴权、可分享的下载链接;列表返回每个文件的上传时间。
上传
curl -X POST $BASE/api/files/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@./report.pdf" \
-F "description=Q3 report"
返回 201:{ file_id, filename, size, content_type, uploaded_at, description, public, download_url }
想让大家都能下载(例如 APK)?上传时加 -F "public=true"。
公开文件会出现在 /files 页面的「公开文件」区,并可免 Token 调用
GET /api/public/files 与 GET /api/public/files/{file_id}/{filename}。
列出(带时间)
curl "$BASE/api/files?page=1&page_size=50&order=recent&q=report"
order:recent(默认,最新在前)| oldest | name | largest。
q 匹配文件名与备注。返回 { total, page, page_size, items: [FileMeta] }。
下载 / 预览 / 删除
curl -OJ $BASE/api/files/{file_id}/{filename}
curl "$BASE/api/files/{file_id}/{filename}?inline=1" # 图片/视频浏览器内预览
curl -X DELETE $BASE/api/files/{file_id} -H "Authorization: Bearer $TOKEN"
推文归档
两条路:贴 URL 交给 gallery-dl 抓;或直接提交 JSON(批量导入最快,无需下载器)。
直接导入(推荐给 Agent)
curl -X POST $BASE/api/tweets \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"tweet_id": "1234567890",
"author_name": "Jane Doe",
"author_handle": "janedoe",
"content": "hello world",
"date": "2026-09-06T12:00:00Z",
"source_url": "https://x.com/janedoe/status/1234567890",
"media_urls": [], "media_types": [],
"stats": {"likes": 42, "retweets": 7}
}'
# 批量:1–500 条,部分失败不会中断整批
curl -X POST $BASE/api/tweets/batch \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"tweets": [{ "tweet_id": "1", "author_name": "A", "author_handle": "a" }]}'
tweet_id 即主键,重复提交会覆盖(幂等)。必填:tweet_id、author_name、author_handle。
浏览
curl "$BASE/api/tweets?page=1&page_size=20&q=python&author=janedoe&order=score"
curl $BASE/api/tweets/authors # 作者 + 推文数 + 最近归档时间
curl $BASE/api/tweets/{tweet_id} # 单条,media_urls 每次重新签发
curl -X POST $BASE/api/tweets/{tweet_id}/vote -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"delta": 1}'
curl -X POST $BASE/api/tweets/{tweet_id}/comments -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"content": "nice"}'
curl $BASE/api/tweets/{tweet_id}/comments # 按分数降序
默认 order=score:按净票数降序,同分按时间倒序;order=timeline 为纯时间倒序。投票与留言为单用户模式,无需账号。
故事 / 个人笔记
卡片流 /stories:只写正文,无需标题;按最后编辑时间倒序,可筛选标签、搜索、编辑与删除。
curl "$BASE/api/stories?page=1&page_size=20&tag=日记"
curl -X POST $BASE/api/stories -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"content": "去了海边", "tags": "日记, 旅行、随想; #读书"}'
curl -X PUT $BASE/api/stories/{story_id} -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"content": "改过的正文", "tags": ["日记"]}'
curl -X DELETE $BASE/api/stories/{story_id} -H "Authorization: Bearer $TOKEN"
标签可用中英文逗号、顿号、分号、空格(含「逗号+空格」)分隔;tags 也可直接传字符串,服务端会拆分并去掉 # 前缀与重复项。列表额外返回 tags[{name,count}] 标签云。
按 URL 抓取(gallery-dl)
异步任务:提交后轮询 job,直到 done 或 failed。
curl -X POST $BASE/api/download \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"url": "https://x.com/janedoe/status/1234567890"}'
# → 202 { job_id, status: "pending" }
curl $BASE/api/jobs/{job_id}
# pending → downloading → uploading → done | failed(失败时带 error 字段)
优先用 gallery-dl(需服务端配置 TWITTER_AUTH_TOKEN + TWITTER_CT0);若 gallery-dl 缺失或失败,自动回退到公开的 FxTwitter / VxTwitter 接口(无需 cookie,可取公开帖子)。
错误处理
错误响应统一为 {"detail": "给人看的", "code": "给程序看的"}。请按 code 分支,把 detail 展示给人。
| code | HTTP | 含义 / 怎么修 |
|---|---|---|
| unauthorized | 401 | 缺 Bearer Token 或 token 错误 —— 检查请求头与服务端 API_TOKEN |
| invalid_order | 422 | /api/files 的 order 只能是 recent / oldest / name / largest |
| file_not_found | 404 | token 不存在,或文件名不匹配 —— 先 GET /api/files/{file_id} 取准确文件名 |
| invalid_token | 404 | token 格式非法(长度/字符不对),多半是拼错了 |
| upload_too_large | 413 | 超过服务端 MAX_UPLOAD_SIZE_MB(默认 2048,即 2GB) |
| write_failed | 500 | 服务端写盘失败(磁盘满 / 权限)—— 重试或联系运维 |
| delete_failed | 500 | 服务端删除失败 |
| storage_error | 502 | 推文存储后端(local / COS)不可用 |
| internal_error | 500 | 其它 —— 把响应体里的 request_id 给运维查日志 |
两个例外
- 字段校验失败(422)由 FastAPI 生成,格式是数组:
{"detail":[{"loc":["body","tweet_id"],"msg":"Field required"}]} POST /api/tweets/batch仍返回 200,逐条结果放在failed里(含index/tweet_id/code/error)—— 部分成功是正常情况
每个响应都带 X-Request-ID 头;5xx 响应体里重复一次 request_id,便于凭它查服务端日志。
约定
- 时间格式
- UTC ISO-8601,例如 2026-09-06T12:34:56.789012+00:00
- 分页
page从 1 开始;响应含total / page / page_size / items- 媒体 URL
- 可能是相对路径(如
/storage/media/…),需拼上服务器地址 - 错误
- 非 2xx 返回
{ "detail": "…" } - CORS
- 全部放开(
Access-Control-Allow-Origin: *) - 健康检查
GET /health→{ status, queue_size, storage_backend }
数据字段
| 对象 | 字段 |
|---|---|
| FileMeta | token, filename, size, content_type, uploaded_at, description, download_url |
| TweetMeta | tweet_id, author_name, author_handle, author_avatar, content, date, media_urls, media_types, stats{likes,retweets,replies,bookmarks,views}, status, source_url, archived_at, score, comment_count |
| AuthorInfo | handle, name, avatar, tweet_count, latest_date |
| JobStatus | job_id, url, status, created_at, tweet_id, error |