Auto-generated documentation is available at
/docs(Swagger UI) and/redoc(ReDoc) when the FastAPI server is running.
http://localhost:8000/api
All endpoints below are relative to this base.
All protected endpoints require:
Authorization: Bearer <access_token>
| Method | Path | Description | Auth |
|---|---|---|---|
POST |
/signup |
Register a new user | ✗ |
POST |
/login |
Login, returns token pair | ✗ |
POST |
/logout |
Logout | ✓ |
POST |
/auth/refresh |
Exchange refresh → new access token | ✗ |
GET |
/me |
Current user profile | ✓ |
PATCH |
/me |
Update profile | ✓ |
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer"
}- Access token TTL: 15 minutes
- Refresh token TTL: 7 days
| Method | Path | Description | Auth |
|---|---|---|---|
POST |
/videos/upload |
Upload video → creates Job | ✓ |
POST |
/videos/upload/audio |
Upload audio → creates Job | ✓ |
POST |
/videos/upload/text |
Upload text (no Job) | ✓ |
POST |
/videos/upload/hls |
Upload video → HLS Job | ✓ |
GET |
/videos/ |
List user's videos (paginated) | ✓ |
GET |
/videos/dashboard |
Active + recent videos | ✓ |
GET |
/videos/{id} |
Get video detail | ✓ |
DELETE |
/videos/{id} |
Delete video + files | ✓ |
POST |
/videos/{id}/reprocess |
Re-run pipeline on existing media | ✓ |
GET |
/videos/youtube/info |
YouTube metadata for trim UI | ✓ |
POST |
/videos/upload/youtube |
Queue YouTube download + processing | ✓ |
GET |
/config/pipeline-languages |
Supported input/output language lists | ✗ |
Processing uploads (/videos/upload, /upload/audio, /upload/text, /upload/youtube) accept multipart/form-data with:
| Field | Required | Default | Description |
|---|---|---|---|
file |
✓ (upload) | — | Media file |
output_type |
✗ | fullDubbing |
Pipeline depth |
domain |
✗ | general |
Domain hint |
voice |
✗ | male1 |
TTS voice preset |
translation_style |
✗ | neutral |
Translation style |
source_lang |
✓ | — | Input language for STT: en, es, or it (ISO-639-1) |
target_lang |
✗ | arb_Arab |
Output language (NLLB code; only Arabic MSA supported) |
POST /videos/{id}/reprocess accepts JSON with the same processing fields (ProcessingOptions schema). source_lang is required.
User profile fields default_source_lang and default_target_lang persist dashboard defaults.
| Layer | Format | Example |
|---|---|---|
UI / STT (source_lang, Whisper language) |
ISO-639-1 | en, es, it |
NMT / pipeline output (target_lang) |
NLLB-200 | arb_Arab (Arabic MSA) |
The backend copies source_lang into job input_data.language so the STT worker forces Whisper to the user-selected input language.
| Method | Path | Description |
|---|---|---|
GET |
/videos/youtube/info?url=... |
Metadata only (title, duration, thumbnail) for the trim UI |
POST |
/videos/upload/youtube |
Validate URL, create video record, queue background download |
POST /videos/upload/youtube form fields:
| Field | Required | Default | Description |
|---|---|---|---|
youtube_url |
✓ | — | YouTube video URL |
format |
✗ | video |
video or audio |
quality |
✗ | 720p |
Max video height (1080p, 720p, etc.) |
output_type |
✗ | uploadOnly |
Same pipeline modes as file upload |
source_lang |
✓ | — | STT input language |
target_lang |
✗ | arb_Arab |
NMT output language |
trim_start, trim_end |
✗ | — | Seconds; applied after download |
YouTube blocks anonymous server-side downloads from many cloud/VPS IPs. The stack runs a youtube-pot sidecar that auto-generates Proof-of-Origin tokens (no manual cookie export or rotation).
Important: A healthy POT sidecar does not guarantee success on datacenter/VPS IPs. YouTube may still block the server's egress IP even when valid PO tokens are generated. If imports fail with a bot-check error while POT logs show token generation, try client rotation (default below) or set YOUTUBE_PROXY to route yt-dlp through a residential/SOCKS egress.
| Variable | Description |
|---|---|
YOUTUBE_POT_BASE_URL |
POT HTTP server URL (default: http://youtube-pot:4416) |
YOUTUBE_PLAYER_CLIENTS |
Comma-separated yt-dlp clients (default: android_vr,tv_downgraded,mweb) |
YOUTUBE_PROXY |
Optional HTTP/SOCKS proxy for yt-dlp egress (escape hatch for flagged VPS IPs) |
YOUTUBE_YTDLP_VERBOSE |
Set true to enable verbose yt-dlp debug logging (default: false) |
The youtube-pot service uses the brainicism/bgutil-ytdlp-pot-provider:1.3.1 image. The backend installs the matching bgutil-ytdlp-pot-provider pip plugin and Deno (for yt-dlp EJS challenge solving).
Default client order: android_vr and tv_downgraded do not require PO tokens and work better on server IPs; mweb is the POT-backed fallback.
Limitation: public videos only. Age-restricted, private, and members-only videos will fail with a restricted error.
Post-deploy verification (run inside the backend container):
python -c "
from app.media.youtube import build_ydl_opts
import yt_dlp, json
opts = build_ydl_opts(download=False)
opts.update(verbose=True, quiet=False)
print(json.dumps(opts['extractor_args'], indent=2))
with yt_dlp.YoutubeDL(opts) as ydl:
ydl.extract_info('https://www.youtube.com/watch?v=dQw4w9WgXcQ', download=False)
"Expected: player_client includes android_vr, tv_downgraded, mweb; base_url is ["http://youtube-pot:4416"]; debug shows PO Token Providers: bgutil:http-1.3.1; metadata fetch succeeds.
To test a previously failing video:
docker exec -it dabljaar_backend python -c "
from app.media.youtube import build_ydl_opts
import yt_dlp
opts = build_ydl_opts(download=False)
opts.update(verbose=True, quiet=False)
with yt_dlp.YoutubeDL(opts) as ydl:
ydl.extract_info('https://www.youtube.com/watch?v=n2Fluyr3lbc', download=False)
"If all clients still fail with a bot error, set YOUTUBE_PROXY in .env.production and redeploy the backend.
{
"id": "uuid-of-video",
"job_id": "uuid-of-job",
"message": "The media is being processed",
"status": "PENDING"
}| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number |
limit |
int | 10 | Items per page (max 100) |
search |
string | — | Search title or filename |
sortBy |
string | date-desc |
Sort: date-desc, date-asc, name-asc, name-desc, size-desc, size-asc |
dateRange |
string | allTime |
today, thisWeek, thisMonth, last7Days, last30Days, last90Days, allTime |
status |
string | — | PENDING, PROCESSING, COMPLETED, FAILED |
mediaType |
string | — | VIDEO, AUDIO, TEXT |
| Method | Path | Description | Auth |
|---|---|---|---|
GET |
/jobs/{id} |
Get job status + progress | ✓ |
GET |
/jobs/video/{video_id} |
All jobs for a video | ✓ |
GET |
/jobs/ |
List jobs (query params) | ✓ |
POST |
/jobs/{id}/cancel |
Cancel a queued/processing job | ✓ |
PATCH |
/jobs/{id}/progress |
Update job progress (internal) | ✓ |
{
"id": "uuid",
"video_id": "uuid",
"user_id": 1,
"job_type": "VIDEO_PROCESS",
"status": "PROCESSING",
"progress": 60.0,
"celery_task_id": "abc-123",
"parent_job_id": null,
"input_data": { "file_path_key": "videos/1/test.mp4" },
"output_data": null,
"error_message": null,
"retry_count": 0,
"max_retries": 3,
"created_at": "2026-02-20T12:00:00",
"updated_at": "2026-02-20T12:01:00",
"started_at": "2026-02-20T12:00:05",
"completed_at": null
}| Type | Queue | Description |
|---|---|---|
VIDEO_PROCESS |
media |
Extract metadata, audio, thumbnail |
VIDEO_HLS |
media |
Generate HLS stream |
STT_TRANSCRIBE |
pipeline |
Whisper speech-to-text |
NMT_TRANSLATE |
pipeline |
NLLB-200 translation |
TTS_SYNTHESIZE |
pipeline |
MMS Arabic voice synthesis |
DUBBING_MERGE |
pipeline |
FFmpeg merge dubbed audio |
FULL_DUBBING_PIPELINE |
pipeline |
Orchestrates all AI stages |
| Status | Description |
|---|---|
QUEUED |
Job created, waiting for worker pickup |
PROCESSING |
Worker is executing the task |
COMPLETED |
Finished successfully |
FAILED |
Task raised an exception |
RETRYING |
Failed and waiting for retry |
CANCELLED |
Cancelled via API |
Standard error:
{ "detail": "Human-readable error message" }Validation error (422):
{
"detail": [
{ "loc": ["body", "email"], "msg": "invalid email", "type": "value_error" }
]
}Rate limit (429):
{ "detail": "Too many requests, wait 1 min and after 1 min make it can send request again" }