Live streams
A live video lists two kinds of format:
- HLS formats (
isHLS), with audio and video together. - DASH formats (
isLiveand notisHLS), with audio or video only.
import { Quality, Ytdl } from "@distube/ytdl-core";
declare const yt: Ytdl;declare const liveUrl: string;
const live = await yt.getInfo(liveUrl);
live.videoDetails.isLive; // trueyt.download(live, { filter: (format) => format.isHLS });yt.download(live, { quality: Quality.HighestAudio, filter: { isLive: true, hasAudio: true, hasVideo: false } });Both kinds start liveBuffer milliseconds behind the live edge, 20 seconds by default, and end when the broadcast does:
import { Ytdl, type VideoInfo } from "@distube/ytdl-core";
declare const yt: Ytdl;declare const live: VideoInfo;
yt.download(live, { filter: (format) => format.isHLS, liveBuffer: 5_000 });A channel’s live URL works too. Ytdl looks up the stream the channel plays now, so a 24/7 stream that restarts under a new ID needs no change:
import { Ytdl } from "@distube/ytdl-core";
declare const yt: Ytdl;
const live = await yt.getInfo("https://www.youtube.com/@NASA/live");It also takes /channel/<id>/live, /c/<name>/live and /user/<name>/live. A channel that isn’t live, or doesn’t exist, fails with NOT_FOUND.
Live formats have no fixed size, so range is ignored. Stop a live download with signal.
Quality and start point
Section titled “Quality and start point”A live video never streams over SABR, so its formats are the ones its HLS manifest and DASH list name. startTimeMs throws INVALID_ARGUMENT for them, and a download cannot rewind to the start of the broadcast.
Resume and end
Section titled “Resume and end”A live download resumes like any other. An expired URL, an HTTP 403, 429 or 5xx, or a broken request looks the video up again and continues at the same segment, calling onRetry. After a 429 or 5xx the download waits one segment (HLS: one target duration) first. If YouTube no longer has the missed segments, the download skips to the newest one, so the recording has a gap.
The stream ends when the HLS playlist says the broadcast is over, or when no new segment arrives for 30 seconds. Both end the stream normally. To keep recording through a long stall, call getInfo again and start a new download while videoDetails.isLive is true.
A stream that just ended stays in its DVR window until YouTube turns it into a regular video. Its videoDetails.isLive is false, and a download reads the window from its oldest segment to the newest, then ends.
Record to a file
Section titled “Record to a file”An HLS format sends MPEG-TS with audio and video together. ffmpeg remuxes it without re-encoding:
import { spawn } from "node:child_process";import { Ytdl, type VideoInfo } from "@distube/ytdl-core";
declare const yt: Ytdl;declare const live: VideoInfo;
const ffmpeg = spawn("ffmpeg", ["-i", "pipe:0", "-c", "copy", "live.mkv"], { stdio: ["pipe", "inherit", "inherit"] });yt.download(live, { filter: (format) => format.isHLS && format.hasAudio }).pipe(ffmpeg.stdin);A DASH format carries one track, so a recording with both takes one download for audio and one for video, merged afterwards.
A premiere or scheduled stream that hasn’t started fails with NOT_STARTED, and error.startTime says when it begins.