youtube_helper.streaming module
youtube_helper.streaming
Stream catalog, picker, and direct-URL resolution for
yt-dlp-supported sites. Does NOT decode anything — the resolved
URLs are meant to be consumed by:
video_helper.extract_framesfor video framespodcast_helper.iter_pcm(separate package) for audio PCM
What this module gives you, layered from low-level to high-level:
VideoStreamInfo— typed dict describing one video format.list_video_streams()— enumerate every video format yt-dlp finds for a URL (one entry per resolution / codec / container).pick_video_stream()— pick the single best video stream matching codec / format / fps / language constraints.resolve_direct_url()— quick “give me ONE direct URL ready for ffmpeg” (audio or video flavour). Coarser thanpick_*.
Audio stream catalog / picker intentionally NOT in this module — that
responsibility lives in podcast-helper so the audio decoding path
has a single owner.
- class youtube_helper.streaming.DirectMediaURL[source]
Bases:
TypedDictResolved direct-media URL ready for ffmpeg.
Keys
- urlstr
The direct media URL. Can be an HLS
.m3u8(live), DASH.mpd, or progressive.mp4/.webm— whicheveryt-dlpselected.- containerstr
Container format string (
"hls","dash","mp4","webm","audio", …). Useful for ffmpeg’s-fhint if the URL extension is ambiguous.- is_livebool
True if the source is a live stream. Callers may want to skip
-re(real-time pacing) since live is already real-time.- headersdict[str, str]
HTTP headers the player must send with the request. YouTube often requires a specific
User-AgentandRefererto avoid 403s; pass them to ffmpeg via-headers.
- class youtube_helper.streaming.VideoStreamInfo[source]
Bases:
TypedDictOne video format’s metadata, normalised across extractors.
Keys
- format_idstr
yt-dlp’s stable identifier for this format on this URL.
- urlstr
The direct media URL — ready for ffmpeg / PyAV.
- headersdict[str, str]
HTTP headers ffmpeg must send with the request (User-Agent, Referer, Cookie, …). Pass through to
video_helper.extract_frames(http_headers=...)or to ffmpeg’s-headersflag.- extstr
File extension reported by yt-dlp (
"mp4"/"webm"/"m3u8"/ …).- containerstr
Normalised container hint (
"mp4"/"webm"/"hls"/"dash") — useful when the ext is ambiguous.- vcodecstr
Video codec (
"h264"/"vp9"/"av01"/"none"if audio-only — filtered out of this list).- acodecstr
Audio codec (
"none"for video-only formats — common on YouTube DASH, paired with a separate audio-only format).- width, heightint
Pixels.
0if unknown (rare).- fpsfloat
Frames per second.
0.0if unknown.- vbr_kbpsfloat
Estimated video bitrate in kbit/s.
0.0if unknown.- filesize_bytesint
Estimated file size in bytes.
0if unknown (always 0 for live).- is_livebool
True if this is a live stream (URL is an HLS / DASH manifest).
- protocolstr
yt-dlp’s protocol string (
"https"/"m3u8_native"/"http_dash_segments"/ …).- languagestr | None
Language code if the format carries an explicit one (rare for video; common for audio).
- notestr
yt-dlp’s
format_note— typically a human-readable label ("1080p60","Premium", …).
- youtube_helper.streaming.extract_frames_stream(url, *, prefer_codec=None, prefer_format=None, max_fps=None, language=None, include_video_only=True, include_combined=True, cookies_from_browser=None, verbose=False, **extract_frames_kwargs)[source]
Stream frames from any yt-dlp-supported URL through
video_helper.extract_frames().One-call composition of:
pick_video_stream()— resolvesurlto a singleVideoStreamInfomatching the codec / format / fps / language constraints.video_helper.extract_frames()— opens the resolved direct media URL with the righthttp_headersand yields frames under the destination of your choice (numpy BGR, torch RGB, or PIL).
Why this exists
The two-step pattern is the published recipe (see
ai-helpers/EXAMPLES.mdandyoutube-helper/EXAMPLES.md):>>> stream = yth.pick_video_stream(url, prefer_codec="h264") >>> for frame in vh.extract_frames( ... stream["url"], http_headers=stream["headers"], ... destination="torch", device="auto", batch_size=32, ... ): ... model(frame)
extract_frames_streamcollapses both calls into one, plumbs the headers automatically, and lets the caller forward anyextract_frameskwarg (destination,device,batch_size,output_width,frame_step, …) verbatim.- param url:
Any URL
yt-dlpcan extract (YouTube / Vimeo / DailyMotion / Twitch VOD / …). Live streams are accepted as well — the returned iterator runs until the live source ends.- type url:
str
- param prefer_codec:
Forwarded to
pick_video_stream(). See its docstring for the matching semantics. Defaults pick yt-dlp’s best candidate.- type prefer_codec:
optional
- param prefer_format:
Forwarded to
pick_video_stream(). See its docstring for the matching semantics. Defaults pick yt-dlp’s best candidate.- type prefer_format:
optional
- param max_fps:
Forwarded to
pick_video_stream(). See its docstring for the matching semantics. Defaults pick yt-dlp’s best candidate.- type max_fps:
optional
- param language:
Forwarded to
pick_video_stream(). See its docstring for the matching semantics. Defaults pick yt-dlp’s best candidate.- type language:
optional
- param include_video_only:
Forwarded to
pick_video_stream(). Defaults keep both.- type include_video_only:
bool, optional
- param include_combined:
Forwarded to
pick_video_stream(). Defaults keep both.- type include_combined:
bool, optional
- param cookies_from_browser:
Forwarded to
pick_video_stream(). Required for age-gated / members-only content.- type cookies_from_browser:
str, optional
- param verbose:
Forwarded to
pick_video_stream().- type verbose:
bool, optional
- param **extract_frames_kwargs:
Any keyword accepted by
video_helper.extract_frames():start_index/end_index/start_instant/end_instant/stabilize/frame_step/frame_interval/frame_indices/frame_times/backend/hwaccel/output_width/output_height/pad_color/destination/device/batch_size/layout.Note:
http_headersis wired automatically from the resolved stream — passing it yourself overrides the resolver’s headers (rare; mostly useful when the caller already authored a stable header dict).- returns:
The same iterator type that
video_helper.extract_frames()returns — numpy / torch / PIL frames or batches per the passed-indestinationandbatch_size.- rtype:
Iterator
- raises RuntimeError:
If yt-dlp can’t extract the URL (private / removed / geo-blocked).
- raises ValueError:
If no stream matches the codec / format / fps / language constraints (the catalog itself was non-empty, but every entry got filtered out).
Examples
>>> import youtube_helper as yth >>> # Sequential decode at 1 frame per second, 224×224 letterboxed. >>> for frame in yth.extract_frames_stream( ... "https://www.youtube.com/watch?v=YE7VzlLtp-4", ... prefer_codec="h264", prefer_format="mp4", max_fps=30, ... frame_interval=1.0, output_width=224, output_height=224, ... ): ... model(frame)
>>> # Batched torch tensors on a GPU device — same downstream code as >>> # the file-based path. >>> for batch in yth.extract_frames_stream( ... "https://vimeo.com/123", ... destination="torch", device="auto", batch_size=32, ... ): ... logits = model(batch.float() / 255.0)
- youtube_helper.streaming.list_video_streams(url, *, include_video_only=True, include_combined=True, cookies_from_browser=None, verbose=False)[source]
Enumerate every video format yt-dlp finds for this URL.
Results are ordered by yt-dlp’s quality ranking (best last). Pure video-only formats and combined (video + audio) formats are both included by default — adjust with the boolean flags.
- Parameters:
url (str) – Any URL yt-dlp can extract.
include_video_only (bool, optional) – Keep formats with
acodec="none"(DASH-style streams that need a separate audio mux). Default True.include_combined (bool, optional) – Keep formats with both video and audio (legacy progressive streams; common on Vimeo, rare on YouTube high-quality). Default True.
cookies_from_browser (str, optional) – Pass through to yt-dlp’s
--cookies-from-browser(e.g."firefox"/"chrome"/"safari") for age-gated or login-required content.verbose (bool, optional) – Echo yt-dlp’s output to stderr (off by default).
- Returns:
Possibly empty if the URL has no video (audio-only podcast, for example).
- Return type:
- Raises:
RuntimeError – If yt-dlp could not extract info at all (private video, geo-blocked without bypass, removed, …).
- youtube_helper.streaming.pick_video_stream(url, *, prefer_codec=None, prefer_format=None, max_fps=None, language=None, include_video_only=True, include_combined=True, cookies_from_browser=None, verbose=False)[source]
Pick a single best video stream matching the given constraints.
Among the catalog returned by
list_video_streams(), applies each non-None constraint as a hard filter, then returns the highest-ranked remaining candidate (yt-dlp’s native order — typically sorts by height × bitrate).- Parameters:
url (str) – Source URL (any yt-dlp-supported site).
prefer_codec (str, optional) – Substring match against
vcodec("h264"matches both"avc1.640028"and"h264"once normalised;"vp9"matches"vp09.00.40.08";"av1"matches"av01...").prefer_format (str, optional) – Equality match against
ext("mp4"/"webm").max_fps (float, optional) – Drop formats with
fps > max_fps.language (str, optional) – Equality match against the format’s
language(rarely set for video — primarily useful when the source carries multi-track video).include_video_only (bool, optional) – See
list_video_streams().include_combined (bool, optional) – See
list_video_streams().cookies_from_browser (same as
list_video_streams().)verbose (same as
list_video_streams().)
- Returns:
The chosen stream.
- Return type:
- Raises:
RuntimeError – If yt-dlp can’t extract the URL.
ValueError – If no stream matches the constraints (the catalog itself was non-empty, but every entry got filtered out).
- youtube_helper.streaming.resolve_direct_url(url, *, prefer='audio', live='auto')[source]
Resolve
urlto a direct, ffmpeg-readable media URL.- Parameters:
url (str) – Any URL
yt-dlpcan extract (YouTube / Vimeo / DailyMotion / Twitch / …).prefer (
"audio"|"video") – Format preference."audio"selectsbestaudio— cheapest path for ASR + diarization."video"selectsbest(video + audio muxed), useful for the/videoview (Phase 7) that needs the visual track too.live (
"auto"|"force_live"|"force_vod") –"auto"propagates whatever the info dict says (the usual case). The other two override — handy for testing or when the site mislabels a stream.
- Returns:
See class docstring.
- Return type:
- Raises:
RuntimeError – If
yt-dlpcould not extract a usable URL (private video, geo-blocked without bypass, removed, …).