Overview
Batch downloads allow you to download all videos from a YouTube playlist or all episodes from a Spotify podcast show with a single API call. Tornado automatically extracts all URLs and creates individual jobs for each.
Batch downloads are supported for:
- YouTube Playlists (including mix playlists and channel videos)
- Spotify Shows (podcast episodes)
How It Works
Submit Show URL
Send a Spotify show URL to the /jobs endpoint
Episode Extraction
Tornado extracts all episode URLs from the show (can take 30-120 seconds for large shows)
Batch Creation
A batch job is created with individual jobs for each episode
Parallel Processing
Episodes are downloaded in parallel for maximum speed
Progress Tracking
Track overall progress via the batch status endpoint
Create a Batch
YouTube Playlist
curl -X POST "https://api.tornadoapi.io/jobs" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf",
"folder": "my-playlist-2024"
}'
Spotify Show
curl -X POST "https://api.tornadoapi.io/jobs" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://open.spotify.com/show/7iQXmUT7XGuZSzAMjoNWlX",
"folder": "my-podcast-2024",
"webhook_url": "https://myapp.com/batch-complete"
}'
Batch Response
When you submit a Spotify show URL, the response includes episode metadata and job IDs:
{
"batch_id": "550e8400-e29b-41d4-a716-446655440001",
"total_episodes": 142,
"paused": false,
"episodes": [
{
"job_id": "uuid-1",
"url": "https://open.spotify.com/episode/abc",
"title": "Episode 1 - Introduction"
},
{
"job_id": "uuid-2",
"url": "https://open.spotify.com/episode/def",
"title": "Episode 2 - Deep Dive"
}
],
"episode_jobs": ["uuid-1", "uuid-2", "..."]
}
Check Batch Status
Poll the batch endpoint for progress:
curl -X GET "https://api.tornadoapi.io/batch/550e8400-e29b-41d4-a716-446655440001"
Response
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"show_url": "https://open.spotify.com/show/7iQXmUT7XGuZSzAMjoNWlX",
"status": "processing",
"folder": "my-podcast-2024",
"total_episodes": 142,
"completed_episodes": 45,
"failed_episodes": 2,
"episode_jobs": ["job-uuid-1", "job-uuid-2", "..."]
}
Batch Status Values
| Status | Description |
|---|
paused | Batch created with paused: true, waiting for POST /batch/{id}/start |
processing | Batch is being processed, some episodes may be complete |
completed | All episodes finished successfully |
finished | All episodes done, but some failed or were skipped |
Paused Mode (Rename Before Download)
Create a batch in paused mode to review and rename episodes before downloading:
1. Create Paused Batch
curl -X POST "https://api.tornadoapi.io/jobs" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://open.spotify.com/show/7iQXmUT7XGuZSzAMjoNWlX",
"folder": "my-podcast",
"paused": true
}'
The response includes episode metadata (title and URL) so you can decide how to rename them.
2. Rename Episodes (Optional)
curl -X PATCH "https://api.tornadoapi.io/batch/{batch_id}/jobs" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"renames": [
{"job_id": "uuid-1", "filename": "01 - Custom Name"},
{"job_id": "uuid-2", "filename": "02 - Another Name"}
]
}'
3. Start the Batch
curl -X POST "https://api.tornadoapi.io/batch/{batch_id}/start" \
-H "x-api-key: sk_your_api_key"
Batch Webhook
When a batch completes (all episodes done), a webhook is sent:
{
"type": "batch_completed",
"batch_id": "550e8400-e29b-41d4-a716-446655440001",
"status": "finished",
"show_url": "https://open.spotify.com/show/...",
"folder": "my-podcast-2024",
"total_episodes": 142,
"completed_episodes": 140,
"failed_episodes": 2
}
The batch webhook fires once when all episodes are done (completed + failed + skipped = total), not for each individual episode. Skipped episodes (e.g. audio-only episodes with Widevine DRM) count toward the failed_episodes counter. The status field is "completed" if all succeeded, or "finished" if some failed.
Folder Structure
All episodes are saved with the folder prefix you specify:
my-podcast-2024/
├── Episode 1 - Introduction.mp4
├── Episode 2 - Getting Started.mp4
├── Episode 3 - Deep Dive.mp4
└── ...
Python Example
import requests
import time
API_KEY = "sk_your_api_key"
BASE_URL = "https://api.tornadoapi.io"
def download_podcast(show_url, folder):
# Create batch
response = requests.post(
f"{BASE_URL}/jobs",
headers={"x-api-key": API_KEY},
json={
"url": show_url,
"folder": folder
}
)
data = response.json()
batch_id = data["batch_id"]
total = data["total_episodes"]
print(f"Batch created: {batch_id}")
print(f"Total episodes: {total}")
# Poll for progress
while True:
status = requests.get(
f"{BASE_URL}/batch/{batch_id}",
headers={"x-api-key": API_KEY}
).json()
completed = status["completed_episodes"]
failed = status["failed_episodes"]
print(f"Progress: {completed}/{total} ({failed} failed)")
if status["status"] in ["completed", "finished"]:
break
time.sleep(10)
print(f"Batch complete! Status: {status['status']}")
# Download a podcast
download_podcast(
"https://open.spotify.com/show/7iQXmUT7XGuZSzAMjoNWlX",
"huberman-lab-2024"
)
Skipped Episodes
Some Spotify episodes are audio-only and protected by Widevine DRM — they have no video stream available. These episodes are automatically skipped instead of failing with retries:
- Job status is set to
Skipped (not Failed)
- A
job_skipped webhook is sent for each skipped episode
- Skipped episodes count toward the batch
failed counter for completion tracking
- Skipped jobs are classified as warnings, not errors
You can identify skipped episodes by checking individual job statuses or listening for job_skipped webhooks.
| Metric | Value |
|---|
| Max episodes per batch | Unlimited |
| Concurrent downloads | ~100 per batch |
| Typical speed | 10-50 episodes/minute |
| Extraction timeout | 120 seconds |