Wyzie Subs

Extract Embedded Subtitles#

Extracting works on every key, free keys included, and costs 1 request per track. The file you send is only read to find the subtitle tracks and is not kept.

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
ParameterExampleDescription
keyYOUR_KEYAny valid API key, free or Pro. Browser-safe keys are refused.
list11 returns the tracks as JSON and extracts nothing. Costs 1 request.
track0The track to extract: the index from the list. Default: the first text track.
languageenPick the first text track in this language instead (ISO 639-1 or 639-2, e.g. en or eng).
all11 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.5Any 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.mks

Response#

A track comes back with these headers, plus the X-Wyzie-* billing headers:

HeaderExampleDescription
X-Subtitle-Track0The track index.
X-Subtitle-LanguageengThe 3-letter language code, or und when the file does not say.
X-Subtitle-CodecsubripThe codec the track was stored in, e.g. subrip.
X-Extract-Tracks3How 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
StatusMeaning
400No file, or a bad option value.
401No key.
402The Pro balance is exhausted (same body as /search).
403An invalid key, a key on hold, or a browser-safe key.
413The file is over 100 MB. Send only the subtitle tracks (see above).
422No 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.
429A free key is over its daily cap, or Too many extractions (60 per key per hour).
503ffmpeg 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 });