aytube
Extract direct YouTube stream URLs — without yt-dlp, pytube, or any external tool.
Fully custom implementation from scratch. Supports video/audio quality selection, cookies, proxies, and automatic rate-limit handling.
Features
- Any URL format — watch, shorts, embed, youtu.be
- Video quality — 4K, 1080p, 720p, 480p, 360p, best, worst
- Audio only — high/medium/low quality (opus, mp4a)
- Cookie support — Netscape-format cookies_file for age-restricted videos
- Proxy support — HTTP/HTTPS proxies
- Stream verification — confirms URLs have real bytes to play
- Modern cipher — AES-128-CTR signature decryption via Node.js worker
- Zero heavy dependencies — only stdlib + Node.js (for cipher only)
Installation
pip install -e .
Requirements:
- Python 3.10+
- Node.js (for signature cipher decryption on modern YouTube)
Quick Start
from aytube import get_stream_url
# Basic usage
result = get_stream_url("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
print(result.url) # Direct playable stream URL
print(result.quality) # e.g. "2160p"
print(result.size) # File size in bytes
print(result.title) # Video title
# With cookies (for age-restricted / rate-limited videos)
result = get_stream_url(url, cookies_file="/path/to/cookies_file")
# With proxy
result = get_stream_url(url, proxy="http://127.0.0.1:8080")
# Quality selection
result = get_stream_url(url, quality="1080p")
# Audio only
result = get_stream_url(url, audio_only=True, quality="high")
CLI Usage
# Install the package, then:
aytube "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
aytube "https://youtube.com/shorts/abc123" --quality 720p --audio
aytube "https://youtu.be/dQw4w9WgXcQ" --cookies cookies_file
aytube "lofi hip hop" --search --max-results 5
aytube "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --list
aytube "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --info --json
aytube "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --subs
aytube "dQw4w9WgXcQ" --thumb --output thumb.jpg
aytube "https://www.youtube.com/watch?v=dQw4w9WgXcQ" --chapters
CLI Options
| Option | Description |
|---|---|
-q, --quality QUALITY |
Quality: best/1080p/720p/480p/360p/audio |
-a, --audio |
Audio only |
-o, --output OUTPUT |
Output file path |
-c, --cookies COOKIES |
Cookies file (Netscape format) |
-p, --proxy PROXY |
HTTP/HTTPS proxy URL |
-f, --format FORMAT |
Format itag (137, 251, etc.) |
-j, --json |
JSON output |
-v, --verbose |
Verbose output |
-n, --concurrent N |
Concurrent downloads |
-N, --max-results N |
Max search results |
Supported Commands
| Command | Description |
|---|---|
aytube <url> |
Download video (default) |
aytube get <url> |
Get stream URL |
aytube list <url> |
List all available formats |
aytube download <url> |
Download video |
aytube info <url> |
Show video metadata |
aytube search <query> |
Search YouTube |
aytube subs <url> |
List available subtitles |
aytube thumb <id> |
Download thumbnail |
aytube chapters <url> |
Show video chapters |
aytube setup |
Setup wizard (cookies, config) |
aytube show |
Show current configuration |
API Reference
get_stream_url(url, cookies_file=None, proxy=None, quality=None, audio_only=False, verify=True, timeout=30)
Extract a playable stream URL from a YouTube video.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
str |
required | Any YouTube URL (watch, shorts, embed, youtu.be) |
cookies_file |
str | None |
None |
Path to Netscape-format cookies_file. Auto-discovered from package dir, CWD, or ~/.config/aytube/ on rate limits |
proxy |
str | None |
None |
HTTP/HTTPS proxy URL (e.g. "http://127.0.0.1:8080") |
quality |
str | None |
None |
Target quality: "1080p", "720p", "480p", "360p", "4k", "best", "worst" |
audio_only |
bool |
False |
If True, return audio-only stream (opus/m4a) |
verify |
bool |
True |
Verify the stream URL is accessible before returning |
timeout |
int |
30 |
Request timeout in seconds |
Returns: StreamResult
StreamResult
Dataclass with the following fields:
| Field | Type | Description |
|---|---|---|
url |
str |
Direct playable stream URL |
quality |
str |
Quality label (e.g. "1080p", "medium") |
container |
str |
Container format ("mp4", "webm") |
video_codec |
str |
Video codec (e.g. "avc1.640028", "av01.0.12M.08") |
audio_codec |
str |
Audio codec (e.g. "mp4a.40.2", "opus") |
size |
int |
File size in bytes |
title |
str |
Video title |
video_id |
str |
YouTube video ID |
itag |
int |
YouTube itag number |
mime_type |
str |
Full MIME type string |
raw |
dict |
Original format dict from YouTube |
extract_video_id(url)
Extract the YouTube video ID from any YouTube URL format.
from aytube import extract_video_id
extract_video_id("https://www.youtube.com/watch?v=dQw4w9WgXcQ") # "dQw4w9WgXcQ"
extract_video_id("https://youtu.be/dQw4w9WgXcQ") # "dQw4w9WgXcQ"
extract_video_id("https://www.youtube.com/shorts/dQw4w9WgXcQ") # "dQw4w9WgXcQ"
extract_video_id("https://www.youtube.com/embed/dQw4w9WgXcQ") # "dQw4w9WgXcQ"
list_formats(url, cookies_file=None, proxy=None)
List all available stream formats for a video.
from aytube import list_formats
formats = list_formats("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
for f in formats:
print(f"itag={f['itag']} {f['quality']} {f['container']} {f['video_codec'] or f['audio_codec']}")
get_metadata(url, cookies_file=None, proxy=None)
Get video metadata without extracting stream URL.
from aytube import get_metadata
meta = get_metadata("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
print(meta["title"])
print(meta["duration"])
print(meta["view_count"])
download(url, quality="best", audio_only=False, output=None, cookies_file=None, proxy=None, timeout=30)
Download a video to a file.
from aytube import download
path = download("https://www.youtube.com/watch?v=dQw4w9WgXcQ", quality="1080p")
print(f"Saved to {path}")
Examples
Video Quality Selection
from aytube import get_stream_url
url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# Specific quality
r = get_stream_url(url, quality="1080p")
print(f"1080p: {r.url[:80]}... size={r.size:,}")
# Best available
r = get_stream_url(url)
print(f"best: {r.quality} size={r.size:,}")
Audio Only
from aytube import get_stream_url
r = get_stream_url("https://www.youtube.com/watch?v=dQw4w9WgXcQ", audio_only=True)
print(f"{r.quality} audio: {r.container} {r.audio_codec} {r.size:,} bytes")
With Cookies
from aytube import get_stream_url
# Place cookies_file next to your script, or in the package directory
result = get_stream_url(
"https://www.youtube.com/watch?v=VIDEO_ID",
cookies_file="/path/to/cookies_file",
quality="1080p",
)
Getting cookies_file:
- Install the Get cookies.txt Chrome extension
- Log into YouTube
- Click the extension → export cookies in Netscape format
Auto-discovery: If you don't pass cookies_file, aytube will automatically look for cookies_file in:
- The package installation directory
- Your current working directory
~/.config/aytube/cookies_file
With Proxy
from aytube import get_stream_url
result = get_stream_url(
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
proxy="http://127.0.0.1:8080",
quality="720p",
)
Different URL Formats
from aytube import get_stream_url
urls = [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"https://youtu.be/dQw4w9WgXcQ",
"https://www.youtube.com/shorts/dQw4w9WgXcQ",
"https://www.youtube.com/embed/dQw4w9WgXcQ",
]
for url in urls:
r = get_stream_url(url, verify=True)
print(f"{r.quality} {r.size:,} bytes {r.title[:40]}")
Batch Processing
from aytube import get_stream_url
urls = [
"https://www.youtube.com/watch?v=VIDEO_ID_1",
"https://www.youtube.com/watch?v=VIDEO_ID_2",
]
for url in urls:
try:
r = get_stream_url(url, quality="720p")
print(f"{r.title[:40]}: {r.size:,} bytes")
except Exception as e:
print(f"Failed: {e}")
How It Works
- URL Parsing — Extracts video ID from any YouTube URL format
- Page Fetch — Downloads the watch page HTML with cookie/proxy support. Auto-retries with cookies on HTTP 429/403/503
- Player Response — Parses
ytInitialPlayerResponseJSON from the HTML - Cipher Detection — Checks if formats have encrypted
signatureCipherfields - Key Extraction — Tries multiple strategies to extract the AES cipher key
- Signature Decryption — AES-128-CTR with zero counter (symmetric encrypt=decrypt)
- URL Construction — Builds adaptive format URLs with correct itag and signature parameters
- Quality Selection — Picks the best format matching your quality preference, preferring mp4 container and known sizes
- Verification — Uses
contentLengthfrom YouTube (most reliable), falls back to HTTP Range HEAD
Rate Limits
YouTube rate-limits unauthenticated requests. To avoid this:
- Provide a
cookies_file— authenticated sessions get higher rate limits - Auto-retry — aytube automatically retries rate-limited requests with cookies if a
cookies_fileis found - Backoff — exponential backoff between retries (1s → 2s → 4s)
# Recommended for public/production use:
result = get_stream_url(url, cookies_file="cookies_file")
Error Handling
| Error | Cause | Solution |
|---|---|---|
HTTP 429: Too Many Requests |
Rate limited | Provide cookies_file with authenticated session |
AGE_CHECK_REQUIRED |
Age-restricted video | Provide cookies_file with authenticated adult session |
LIVE_STREAM_OFFLINE |
Stream not live | Try again when the stream is live |
UNPLAYABLE |
Region/format restriction | Use a proxy from the target region |
Could not decipher signature |
YouTube changed obfuscation | Update player JS parsing; provide cookies |
Supported Itags
| Itag | Quality | Container | Codec | Type |
|---|---|---|---|---|
| 401 | 2160p | mp4 | av01 | video-only |
| 313 | 2160p | webm | vp9 | video-only |
| 137 | 1080p | mp4 | avc | video-only |
| 248 | 1080p | webm | vp9 | video-only |
| 136 | 720p | mp4 | avc | video-only |
| 247 | 720p | webm | vp9 | video-only |
| 135 | 480p | mp4 | avc | video-only |
| 18 | 360p | mp4 | avc+mp4a | muxed |
| 134 | 360p | mp4 | avc | video-only |
| 140 | audio | mp4 | mp4a.40.2 | audio-only |
| 251 | audio | webm | opus | audio-only |
| 250 | audio | webm | opus | audio-only |
| 249 | audio | webm | opus | audio-only |
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aytube-1.0.0.tar.gz.
File metadata
- Download URL: aytube-1.0.0.tar.gz
- Upload date:
- Size: 53.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d3cce1b60612c3b1c2d1a7c606cf607e4fe1340e75fb60e5fa13fa6d774bf56
|
|
| MD5 |
f622b010ce3a6f0163b7da3b2486ed2f
|
|
| BLAKE2b-256 |
a273907a7db809500d00b3b4b186feb67e33c99825997db27d33241634334680
|
File details
Details for the file aytube-1.0.0-py3-none-any.whl.
File metadata
- Download URL: aytube-1.0.0-py3-none-any.whl
- Upload date:
- Size: 58.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4255c6655a6f2ee53d5e9795c5d2c96ff65c1ad18504587955437c484c9140de
|
|
| MD5 |
4790c4a35ab469633830c744bfb36b85
|
|
| BLAKE2b-256 |
1e480fb3bda2e2ca15176ba21221cc604ef068e210c1d92ba3e8f725a1e19580
|