Podcast — Post site phụ (secondary / virtual)#
Worker site phụ import RSS feed từ site chính lên các platform podcast khác (anchor.fm, spotify.com, pocketcasts.com, …). Site phụ KHÔNG có row trong podcast_post_link lúc pull — chỉ là virtual task synthesize từ podcast_account.
Base URL: https://manager.likepion.com/api/v1/podcast
Filter param: tất cả GET /podcast/links ở mục này dùng ?type=secondary để chỉ trả site phụ.
1. Lấy danh sách task site phụ #
curl -X GET 'https://manager.likepion.com/api/v1/podcast/links?type=secondary&limit=5' \
-H 'X-API-Key: <api_key>'| Param | Mặc định | Mô tả |
|---|---|---|
type | (không) | secondary để chỉ trả task site phụ. Bỏ trống → trả cả 2 |
limit | 5 | Số task (max 1000) |
Claim guard 15 phút: ngay khi virtual task được trả, BE auto set
podcast_account.posting_started_at = NOW(). Worker khác pull tiếp KHÔNG nhận lại account đó trong 15p. Worker xong gọi/insert→ BE auto clear. Worker crash → 15p sau tự eligible lại.
Response#
Site phụ = virtual task không có row trong DB. id = account_id. request_id = post_id của post chính đang chạy.
{
"success": true,
"data": [
{
"id": "uuid-account",
"request_id": "uuid-post",
"type_request": "post",
"status": "queued",
"account_id": "uuid-account",
"group_id": "uuid",
"target": 100,
"accounts_remaining": 8,
"domain": "anchor.fm",
"website": "https://likepion.com",
"email": "pod.real@anchor.fm",
"username": "realpoduser",
"password": "realPwd!",
"pass_mail": "xxxx xxxx xxxx xxxx",
"twofa": "JBSWY3DPEHPK3PXP",
"app_password": "xxxx xxxx xxxx xxxx",
"link_rss": "https://anchor.fm/s/xxxxx/podcast/rss",
"cookie": "session=abc123"
}
]
}Fields#
| Field | Mô tả |
|---|---|
id | Virtual task ID = account_id |
request_id | UUID podcast_post.id đang chạy cùng group |
type_request | "post" |
status | Status virtual task: luôn "queued" (chưa có row, đợi worker import RSS) |
account_id | UUID account site phụ (= id) |
group_id | UUID group |
target | Số tập (= podcast_post.target) |
accounts_remaining | Số account site phụ trong group chưa có task post |
link_rss | URL RSS feed của site chính → worker import vào site phụ. BẮT BUỘC site chính phải xong trước, gọi /account set link_rss |
email/username/password/… | Credentials account site phụ |
cookie | Session cookie (cuối) |
2. Claim explicit account — /podcast/accounts/claim
#
Worker chủ động claim 1 hoặc nhiều account để block worker khác trong 15p. BE set posting_started_at = NOW().
Khi nào dùng?
- Sau pull virtual task → re-affirm claim (BE đã auto set, gọi này extend TTL).
- Worker xử lý dài > 15p → định kỳ gọi để refresh (tránh stale).
- Claim batch trước khi xử lý.
Idempotent — gọi nhiều lần với cùng account chỉ refresh timestamp.
# Single
curl -X POST 'https://manager.likepion.com/api/v1/podcast/accounts/claim' \
-H 'X-API-Key: <api_key>' \
-H 'Content-Type: application/json' \
-d '{"account_id": "uuid-account"}'
# Bulk (max 200)
curl -X POST 'https://manager.likepion.com/api/v1/podcast/accounts/claim' \
-H 'X-API-Key: <api_key>' \
-H 'Content-Type: application/json' \
-d '{"account_ids": ["uuid1","uuid2","uuid3"]}'| Field | Bắt buộc | Mô tả |
|---|---|---|
account_id | ✔* | UUID 1 account |
account_ids | ✔* | Mảng UUID account (max 200) |
* phải có ít nhất 1 trong 2.
Response:
{
"success": true,
"claimed": ["uuid1", "uuid2"],
"count": 2,
"ttl_min": 15,
"not_found": ["uuid3"]
}3. Insert link sau import — /podcast/links/insert
#
Worker import RSS xong → gọi endpoint này tạo record podcast_post_link với link_post sẵn. BE auto clear posting_started_at (nhả claim).
Format: 1 input item = 1 site (domain) × N URL (link_post chuỗi phân tách bởi ,) → BE expand thành N record.
Hỗ trợ:
- Single object: 1 site, N link_post → N record.
- Bulk array
[{...},{...}]hoặc{"items": [...]}: nhiều site, max 200 record sau expand.
Resolve account 2 cách:
- Theo
domain(khuyến nghị): BE lookup account trong group cósite_name = domain. - Theo
account_id: explicit UUID.
KHÔNG dedupe: 1 account có thể có N row trong cùng post (vd N episode trên cùng platform). Mỗi URL trong link_post = 1 row mới, kể cả cùng (post_id, account_id). Worker tự chịu trách nhiệm không gửi cùng URL 2 lần.
Format theo domain#
curl -X POST 'https://manager.likepion.com/api/v1/podcast/links/insert' \
-H 'X-API-Key: <api_key>' \
-H 'Content-Type: application/json' \
-d '{
"request_id": "uuid-post-request",
"domain": "anchor.fm",
"status": "completed",
"link_post": "https://anchor.fm/ep-1,https://anchor.fm/ep-2,https://anchor.fm/ep-3",
"cookie": "session=abc123"
}'→ Resolve account = account đầu tiên trong group có site_name = "anchor.fm". Insert 3 record.
Bulk#
curl -X POST 'https://manager.likepion.com/api/v1/podcast/links/insert' \
-H 'X-API-Key: <api_key>' \
-H 'Content-Type: application/json' \
-d '[
{ "request_id": "uuid-post", "domain": "anchor.fm", "status": "completed", "link_post": "https://anchor.fm/ep-1,https://anchor.fm/ep-2" },
{ "request_id": "uuid-post", "domain": "spotify.com", "status": "completed", "link_post": "https://open.spotify.com/episode/abc" }
]'Body fields#
| Field | Bắt buộc | Mô tả |
|---|---|---|
request_id (alias post_id) | ✔ | UUID podcast_post.id |
domain | ✔* | Site name. BE lookup account trong group |
account_id | ✔* | UUID account explicit (skip domain lookup) |
status | tuỳ chọn | "completed" (default) / "failed" / "cancel" |
link_post | ✔ | 1 URL hoặc nhiều URL phân tách bởi ,. Mỗi URL = 1 record |
cookie/email/password/… | tuỳ chọn | Credentials → propagate sang podcast_account (1 lần per account) |
note | tuỳ chọn | Ghi chú |
* phải có 1 trong domain hoặc account_id.
Response#
{
"success": true,
"input": 2,
"count": 3,
"inserted": 3,
"failed": 0,
"results": [
{ "index": 0, "link_index": 0, "post_id": "uuid", "account_id": "uuid-anchor", "domain": "anchor.fm", "link_post": "https://anchor.fm/ep-1", "success": true },
{ "index": 0, "link_index": 1, "post_id": "uuid", "account_id": "uuid-anchor", "domain": "anchor.fm", "link_post": "https://anchor.fm/ep-2", "success": true },
{ "index": 1, "link_index": 0, "post_id": "uuid", "account_id": "uuid-spotify", "domain": "spotify.com", "link_post": "https://open.spotify.com/episode/abc", "success": true }
]
}4. Lấy chi tiết account — GET /podcast/accounts/:id
#
Trả 1 account dưới shape giống virtual secondary task (mục 1). Worker pull task xong giữ account_id, sau này cần refetch (token expired, retry import RSS, sync state) gọi endpoint này → nhận lại JSON cùng cấu trúc, plug-and-play.
Khác GET /podcast/links?type=secondary:
- Không áp claim guard 15p — luôn trả dù worker khác vừa pull.
- Không filter status (active/completed) — trả cả account đang
failed/banned… - Không set
posting_started_at.
Các field request_id / target / accounts_remaining / link_rss tham chiếu podcast_post mới nhất cùng group (status pending/running). Nếu group không có post active → request_id="", target=0, accounts_remaining=0, link_rss="".
curl -X GET 'https://manager.likepion.com/api/v1/podcast/accounts/<account_id>' \
-H 'X-API-Key: <api_key>'Response#
{
"success": true,
"data": {
"id": "uuid-account",
"request_id": "uuid-post",
"type_request": "post",
"status": "queued",
"account_id": "uuid-account",
"group_id": "uuid-group",
"target": 20,
"accounts_remaining": 10,
"domain": "anchor.fm",
"website": "https://likepion.com",
"email": "pod.real@anchor.fm",
"username": "realpoduser",
"password": "realPwd!",
"pass_mail": "xxxx xxxx xxxx xxxx",
"twofa": "JBSWY3DPEHPK3PXP",
"app_password": "xxxx xxxx xxxx xxxx",
"link_rss": "https://anchor.fm/s/xxxxx/podcast/rss",
"cookie": "session=abc123; csrf=xyz"
}
}Fields#
Tham chiếu mục 1 — schema y hệt secondary task.