Wyzie Subs
Extract Embedded Subtitles#
Movies and episodes often carry their subtitles inside the video file. POST /extract pulls those embedded tracks out of an MKV, MP4, WebM, MKS or any other container ffmpeg can read, and hands them back as ordinary subtitle files.
The API: POST /extract#
Send the file as the request body, or as a multipart field named media, with your key in the query string. First list what is inside:
curl -X POST "https://sub.wyzie.io/extract?key=YOUR_KEY&list=1" \
-H "Content-Type: video/x-matroska" --data-binary @movie.mkv{
"tracks": [
{
"index": 0,
"codec": "subrip",
"language": "eng",
"title": "English",
"default": true,
"forced": false,
"text": true
},
{
"index": 1,
"codec": "hdmv_pgs_subtitle",
"language": "fre",
"title": null,
"default": false,
"forced": false,
"text": false
}
],
"duration": 5400
}index counts the subtitle streams from 0 in file order. text: false marks an image-based track (PGS, VobSub, DVB), which cannot be turned into text.
Then pull one out:
curl -X POST "https://sub.wyzie.io/extract?key=YOUR_KEY&language=en&to=vtt" \
-H "Content-Type: video/x-matroska" --data-binary @movie.mkv -o movie.en.vtt| Parameter | Example | Description |
|---|---|---|
| key | YOUR_KEY | Any valid API key, free or Pro. Browser-safe keys are refused. |
| list | 1 | 1 returns the tracks as JSON and extracts nothing. Costs 1 request. |
| track | 0 | The track to extract: the index from the list. Default: the first text track. |
| language | en | Pick the first text track in this language instead (ISO 639-1 or 639-2, e.g. en or eng). |
| all | 1 | 1 returns every text track in a zip, with entries named <name>.<lang>.<ext>. Costs 1 request per track in the zip. |
| to, shift, lines... | to=vtt&shift=-1.5 | Any download option, such as to=vtt, shift or lines. |
A single track is served as a file in its own format: subrip becomes srt, ass and ssa become ass, webvtt becomes vtt and mov_text becomes srt. Add to= to convert it.
Big Files#
Cloudflare caps a request body at about 100 MB, so for a full film send only the subtitle tracks. ffmpeg copies them into a tiny file without re-encoding anything:
ffmpeg -i movie.mkv -map 0:s -c copy subs.mksResponse#
A track comes back with these headers, plus the X-Wyzie-* billing headers:
| Header | Example | Description |
|---|---|---|
X-Subtitle-Track | 0 | The track index. |
X-Subtitle-Language | eng | The 3-letter language code, or und when the file does not say. |
X-Subtitle-Codec | subrip | The codec the track was stored in, e.g. subrip. |
X-Extract-Tracks | 3 | How many text tracks the file has. |
Cost#
A track costs 1 request, charged after the file was read successfully; all=1 costs one per track in the zip and list=1 costs 1. A file with no tracks costs nothing.
Errors
| Status | Meaning |
|---|---|
| 400 | No file, or a bad option value. |
| 401 | No key. |
| 402 | The Pro balance is exhausted (same body as /search). |
| 403 | An invalid key, a key on hold, or a browser-safe key. |
| 413 | The file is over 100 MB. Send only the subtitle tracks (see above). |
| 422 | No subtitle tracks, Not a media file, or No text subtitle tracks when every track is image-based. That last body includes tracks, the list, so you can see what is there. Nothing is charged. |
| 429 | A free key is over its daily cap, or Too many extractions (60 per key per hour). |
| 503 | ffmpeg is unavailable. Try again soon. |
With wyzie-lib#
With wyzie-lib, extractSubtitles sends the file and returns the track:
import { extractSubtitles } from 'wyzie-lib';
const result = await extractSubtitles({
media: subsMks, // a File, Blob or Buffer
language: 'en',
options: { to: 'vtt' },
});
if ('subtitle' in result) console.log(result.language, result.subtitle);
// Or list the tracks first (1 request), then pick one by index
const listed = await extractSubtitles({ media: subsMks, list: true });