Captions
getInfo lists the tracks:
const info = await yt.getInfo("yuT7iQC-yro");
info.captionTracks; // [{ languageCode, name, isAutoGenerated, isDefault, url }]The list is empty for a video without captions.
Get the text
Section titled “Get the text”import { CaptionFormat } from "@distube/ytdl-core";
const vtt = await yt.getCaptions("yuT7iQC-yro");const json = await yt.getCaptions(info, { lang: "en", format: CaptionFormat.Json3 });getCaptions returns the text YouTube renders. It does not parse cues. Pass a getInfo result to skip the lookup; the call looks the video up again when the info is about to expire.
CaptionFormat |
Text |
|---|---|
Vtt (default) |
WebVTT |
Srv3 |
XML timed text with per-word timing and styling |
Json3 |
JSON events |
Choose a track
Section titled “Choose a track”lang must equal a track’s languageCode. de does not match de-DE. A manual track wins over an auto-generated one for the same code. Without lang, the call uses the default track, else the first manual track, else the first track.
A language the video lacks rejects with NO_CAPTIONS, and the message lists the codes on offer.
Rate limit
Section titled “Rate limit”YouTube’s caption endpoint answers HTTP 429 after about eight quick requests from one IP. The call rejects with RATE_LIMITED and does not retry. Cache the text and retry later.
Limits
Section titled “Limits”Translation (tlang) is not offered. YouTube answers it with its abuse page (HTTP 429) from server IPs.
Caption URLs need no PO token today. If YouTube starts requiring one, getCaptions fails until it gains a token option. Captions that only a signed-in account can see are not requested with the cookie.