미디어 다운로더 API
v1 · 베이스 URL https://ytdl.blbt.app ·
웹 UI로 돌아가기
인증
환경변수 API_TOKEN 에 선언한 값을 그대로
Authorization 헤더에 넣는다. 별도의 토큰 발급 절차는 없다.
Authorization: Bearer <API_TOKEN>
Bearer 접두사 없이 토큰만 보내도 동작한다. 비교는 상수 시간으로
수행한다. 웹 UI가 쓰는 /api/* (Turnstile 세션 쿠키)와는 완전히
분리된 인증 체계다.
에러 형식
{ "error": { "code": "invalid_request", "message": "`url` must be an http(s) URL" } }
| code | HTTP | 의미 |
|---|---|---|
invalid_request | 400 | 본문·쿼리 파라미터가 규약에 맞지 않음 |
unauthorized | 401 | 헤더 누락 또는 토큰 불일치 |
not_found | 404 | 없는 작업·파일·엔드포인트 |
method_not_allowed | 405 | 경로는 맞으나 메서드가 다름 |
job_not_ready | 409 | 아직 done 이 아닌 작업의 파일 요청 |
info_failed | 422 | 해당 URL의 메타데이터를 읽지 못함 |
engine_unavailable | 502 | 다운로드 엔진에 도달 불가 |
not_configured | 503 | 배포에 API_TOKEN 이 없음 |
엔드포인트
GET/v1 · GET/v1/health
인증 없이 호출할 수 있다. /v1 은 엔드포인트 목록과 제한값을 담은 자기서술 인덱스,
/v1/health 는 컨테이너를 깨우지 않는 라이브니스 프로브다.
POST/v1/info
다운로드 전에 제목·길이·선택 가능한 화질을 확인한다.
curl -s https://ytdl.blbt.app/v1/info \
-H "Authorization: Bearer $API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
{
"title": "Rick Astley - Never Gonna Give You Up",
"id": "dQw4w9WgXcQ",
"extractor": "Youtube",
"duration": 213,
"is_playlist": false,
"entries_count": 1,
"heights": [2160, 1440, 1080, 720, 480, 360]
}
POST/v1/jobs
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
url | string | (필수) | http/https URL |
mode | "video" | "audio" | "video" | audio 는 mp3로 추출 |
quality | integer | null | null | 해상도 상한(예: 1080). null = 최고 화질 |
playlist | boolean | false | 재생목록 전체 다운로드 |
browser_auth | object | null | 쿠키·PO 토큰 주입(선택) |
curl -s https://ytdl.blbt.app/v1/jobs \
-H "Authorization: Bearer $API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"...","mode":"video","quality":1080}'
202 Accepted + 작업 객체를 반환하고 Location 헤더에 조회 URL이 담긴다.
GET/v1/jobs
이 토큰으로 만든 작업만 최신순으로 반환한다. ?limit=(1~50),
?status=(예: done) 로 걸러낼 수 있다.
GET/v1/jobs/{job_id}
작업 객체를 반환한다. done 이면 files[].download_url 에
1시간짜리 서명 URL이 채워진다.
GET/v1/jobs/{job_id}/download
서명 URL로 302 리다이렉트한다. 파일이 여러 개면 ?file=<인덱스> 로 고른다.
curl -L -OJ "https://ytdl.blbt.app/v1/jobs/$JOB/download" \
-H "Authorization: Bearer $API_TOKEN"
/files/... 는 서명으로만 보호되며 헤더 인증을
요구하지 않는다. 1시간 동안 누구에게나 유효하니 공유에 주의할 것.
DELETE/v1/jobs/{job_id}
기록과 R2 파일을 삭제한다. 진행 중인 다운로드 자체는 중단되지 않는다.
{ "deleted": true, "job_id": "j_ab12cd34ef56", "files_deleted": 1 }
작업 객체
{
"job_id": "j_ab12cd34ef56",
"status": "done",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"mode": "video",
"quality": 1080,
"playlist": false,
"title": "Rick Astley - Never Gonna Give You Up",
"progress": { "percent": 100.0, "speed": null, "eta": null },
"files": [
{
"filename": "Rick Astley ... [dQw4w9WgXcQ].mp4",
"size": 18234567,
"download_url": "https://ytdl.blbt.app/files/...?exp=...&sig=...",
"expires_at": "2026-08-16T10:00:00.000Z"
}
],
"error": null,
"created_at": "2026-08-16T09:00:00.000Z",
"updated_at": "2026-08-16T09:01:12.000Z"
}
상태 전이: queued → downloading → processing → uploading → done,
실패 시 error. 두 종료 상태에서만 폴링을 멈추면 된다.
전체 예제
API=https://ytdl.blbt.app
JOB=$(curl -s $API/v1/jobs \
-H "Authorization: Bearer $API_TOKEN" -H 'Content-Type: application/json' \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ","mode":"audio"}' \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["job_id"])')
while :; do
ST=$(curl -s $API/v1/jobs/$JOB -H "Authorization: Bearer $API_TOKEN" \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["status"])')
echo "status=$ST"
[ "$ST" = done ] || [ "$ST" = error ] && break
sleep 5
done
curl -L -OJ "$API/v1/jobs/$JOB/download" -H "Authorization: Bearer $API_TOKEN"
권장 폴링 주기는 3~5초. 컨테이너는 활성 작업이 없으면 10분 뒤 잠들며, 첫 요청은 콜드 스타트로 수 초 더 걸릴 수 있다.
제한
| 서명 다운로드 URL 유효기간 | 1시간 |
| 작업 기록 보존 | 20시간 |
| R2 파일 보존 | 1일 |
| 목록 최대 항목 수 | 50 |
| 동시 다운로드 | 2 |
레이트 리밋은 없다. API_TOKEN 이 유일한 방어선이므로 유출되지 않게 관리할 것.