本文档描述 Pluto 项目对外提供的 HTTP API,供 App 接入使用。
{BASE_URL}/api
BASE_URL 为部署域名,例如 https://example.com。
无需鉴权。
需要管理员登录后的 Cookie(photos_admin)。
- Cookie 名称:
photos_admin - HTTP-only
大多数接口返回 JSON:
ok:true | false- 失败时包含
error或err
常用参数:
page(默认 1)pageSize(默认 20)
返回字段:
totaltotalPages
GET /media/list
Query 参数:
q: 关键词(文件名/标题/位置)category: 分类 slug 或 idtag: 标签pagepageSizesort:date | likes | views(默认date)orientation:landscape | portrait | square
排序规则:
date:优先按datetime_original,为空时回退created_at。
响应示例:
{
"ok": true,
"results": [
{
"id": "...",
"url": "...",
"url_thumb": "...",
"url_medium": "...",
"url_large": "...",
"filename": "...",
"alt": "...",
"size": 0,
"width": 0,
"height": 0,
"created_at": "2024-01-01T00:00:00.000Z",
"camera_make": "...",
"camera_model": "...",
"lens_model": "...",
"aperture": "...",
"shutter_speed": "...",
"iso": "...",
"focal_length": "...",
"datetime_original": "2024-01-01T00:00:00.000Z",
"location_name": "...",
"categories": [{ "id": "...", "name": "...", "slug": "..." }],
"category_ids": ["..."],
"tags": ["..."],
"likes": 0,
"view_count": 0,
"liked": false
}
],
"total": 0,
"page": 1,
"pageSize": 20,
"totalPages": 0
}GET /media/categories
说明:仅返回 show_in_frontend = 1 的分类。
响应:
{
"ok": true,
"categories": [
{
"id": "...",
"name": "...",
"slug": "...",
"description": "...",
"media_count": 0
}
]
}GET /media/{id}
说明:获取单张照片的完整信息,仅返回公开的照片(visibility = 'public' 或 NULL)。
响应:
{
"ok": true,
"data": {
"id": "...",
"url": "...",
"url_thumb": "...",
"url_medium": "...",
"url_large": "...",
"filename": "...",
"title": "...",
"alt": "...",
"width": 1920,
"height": 1080,
"size": 123456,
"mime_type": "image/jpeg",
"camera_make": "...",
"camera_model": "...",
"lens_model": "...",
"aperture": "f/2.8",
"shutter_speed": "1/100",
"iso": "100",
"focal_length": "50mm",
"datetime_original": "...",
"location_name": "...",
"categories": [{ "id": "...", "name": "...", "slug": "..." }],
"tags": ["tag1", "tag2"],
"likes": 10,
"view_count": 120,
"liked": false,
"created_at": "2026-02-07T12:34:56.789Z"
}
}GET /media/{id}/view
POST /media/{id}/view
GET:获取当前浏览量。POST:记录一次浏览(会忽略常见爬虫 UA;当配置 KV 时,5 分钟内同 IP 重复浏览会去重)。
响应:
{ "ok": true, "views": 123 }GET /media/{id}/like
POST /media/{id}/like
DELETE /media/{id}/like
- 点赞状态由 HTTP-only Cookie 记录。
响应:
{ "ok": true, "likes": 0, "liked": true }GET /albums
Query 参数:
pagepageSizeqcategory(分类 slug 或 id)
响应:
{
"ok": true,
"albums": [
{
"id": "...",
"title": "...",
"description": "...",
"cover_media_id": "...",
"cover_media": { "id": "...", "url": "...", "url_thumb": "...", "url_medium": "..." },
"created_at": "...",
"updated_at": "...",
"media_count": 0,
"views": 0,
"likes": 0,
"slug": "...",
"is_protected": false,
"categories": [{ "id": "...", "name": "...", "slug": "..." }],
"category_ids": ["..."]
}
],
"total": 0,
"totalPages": 0
}GET /albums/categories
说明:仅返回 show_in_frontend = 1 的分类。
响应:
{
"ok": true,
"categories": [
{
"id": "...",
"name": "...",
"slug": "...",
"description": "...",
"media_count": 0
}
]
}GET /albums/{idOrSlug}
- 密码相册需
Authorization: Bearer {token}。 - 未提供或无效会返回
403和{ code: "PASSWORD_REQUIRED" }。
响应:
{ "ok": true, "data": { ...album } }GET /albums/{idOrSlug}/media
Query 参数:
-
page -
pageSize -
密码相册需
Authorization: Bearer {token}。
响应:
{ "ok": true, "media": [ ...media ], "total": 0 }POST /albums/{idOrSlug}/unlock
Body:
{ "password": "..." }响应:
{ "ok": true, "token": "..." }GET /albums/{id}/view
POST /albums/{id}/view
POST会增加浏览次数(有 IP 限制)。
响应:
{ "views": 0 }GET /albums/{id}/like
POST /albums/{id}/like
DELETE /albums/{id}/like
- 点赞状态由 HTTP-only Cookie 记录。
响应:
{ "ok": true, "likes": 0, "liked": true }GET /albums/{id}/comments
响应:
{ "ok": true, "comments": [ ... ], "isAdmin": false }POST /albums/{id}/comments
Body:
{
"author_name": "...",
"author_email": "...",
"author_url": "...",
"content": "...",
"parent_id": "..."
}响应:
{ "ok": true, "data": { "id": "...", "status": "pending" } }POST /albums/{id}/comments/{commentId}/approve
DELETE /albums/{id}/comments/{commentId}
注意:当前删除接口未做鉴权,生产环境建议限制为管理员。
GET /subscribe
响应:
{ "ok": true, "enabled": true }POST /subscribe
Body:
{ "email": "user@example.com" }响应:
{ "ok": true, "token": "..." }所有后台接口需要 photos_admin Cookie。
-
POST /admin/login- Body:
{ "username": "...", "password": "..." } - 成功会写入
photos_adminCookie
- Body:
-
POST /admin/logout- 清除 Cookie
-
GET /admin/me- 返回
{ ok: true, user: "..." }
- 返回
-
GET /admin/media/list- Query:
q, category, tag, page, pageSize, sort sort:date | date_asc | name | likes | views
- Query:
-
GET /admin/media/{id} -
PUT /admin/media/{id}- Body:
{ title, alt, category_ids, tags, visibility }
- Body:
-
DELETE /admin/media/{id} -
POST /admin/media/uploadmultipart/form-data- 字段:
file或files(支持多文件)、provider、title、alt、folder、category_ids(逗号分隔)、tags(逗号分隔)、visibility
-
GET /admin/media/categories -
POST /admin/media/categories- Body:
{ name, slug, description, display_order, show_in_frontend }
- Body:
-
PUT /admin/media/categories/{id}- Body:
{ name, slug, description, display_order, show_in_frontend }
- Body:
-
DELETE /admin/media/categories/{id}
GET /admin/media/tags
GET /admin/media/devices- 返回相机/镜头统计
GET /admin/providers- 返回可用存储与默认值
-
GET /admin/albums- Query:
page, pageSize, q
- Query:
-
POST /admin/albums- Body:
{ title, description, cover_media_id, slug, tags, category_ids, password, status }
- Body:
-
GET /admin/albums/{id} -
PUT /admin/albums/{id}- Body:
{ title, description, cover_media_id, slug, tags, category_ids, password, status }
- Body:
-
DELETE /admin/albums/{id} -
GET /admin/albums/{id}/media -
POST /admin/albums/{id}/media- Body:
{ media_ids: ["..."] }
- Body:
-
DELETE /admin/albums/{id}/media- Body:
{ media_ids: ["..."] }
- Body:
-
POST /admin/albums/{id}/otp- 返回
{ ok: true, otp: "..." }
- 返回
-
GET /admin/albums/categories -
POST /admin/albums/categories- Body:
{ name, slug, description, display_order, show_in_frontend }
- Body:
-
PUT /admin/albums/categories/{id}- Body:
{ name, slug, description, display_order, show_in_frontend }
- Body:
-
DELETE /admin/albums/categories/{id}
-
GET /admin/album-comments- Query:
page, pageSize, status(all | pending | approved)
- Query:
-
POST /admin/album-comments/{id}/approve -
DELETE /admin/album-comments/{id}
-
GET /admin/newsletters- Query:
page, pageSize
- Query:
-
POST /admin/newsletters- 创建:
{ subject, content, type } - 发送:
{ action: "send", id: "newsletterId" } - 发送成功响应:
{ ok: true, sent, total, failed, failedRecipients? }
- 发送失败响应:
{ ok: false, code, error, sent, total, failed, failedRecipients? }
- 常见发送错误码:
NOT_FOUND(newsletter 不存在或已发送)SERVER_ERROR(邮件服务配置或发送异常)
- 创建:
GET /admin/subscribers- Query:
page, pageSize
- Query: