YouTube's only muxed mp4 is format 18 (360p), so the muxed-first selector
was posting 360p even when 1080p was available. Split streams are now
preferred for YouTube and merged locally; every other host keeps the
muxed-first chain unchanged (verified identical selection for Instagram,
X and Reddit).
Three things the obvious version got wrong:
- A height<=1080 cap excludes portrait video: a 1080p Short or reel is
1080x1920. Resolution is capped with -S res:1080 instead, which keys
off the smaller dimension.
- h264 is a hard first preference, not an -S sort key. At equal
resolution YouTube's VP9/AV1 renditions are smaller and win on size,
but neither reliably plays in an mp4 container on older Signal
clients. Dropping a resolution rung to stay on h264 is the better
trade, and is usually smaller too: a 10-min video takes 480p h264
(37 MB) over 720p AV1 (78 MB).
- The audio cap matters. YouTube's 388k track is 29 MB by itself on a
10-min video, enough to push an otherwise-fine merge past the 100 MB
Signal limit; abr<=160 takes the 129k track instead.
The 88 MB video cap makes yt-dlp step down automatically on long videos,
so a 3-min video lands at 1080p (80 MB) and a 10-min one at 480p.
Clips get the same treatment — they're YouTube-only, and 60s at 1080p is
only ~29 MB. /force is deliberately left muxed-first: it exists for the
biggest, slowest videos, where 1080p would risk the rsync timeout.
Measured, old -> new: 3-min 360p/11 MB -> 1080p/80 MB; 10-min 360p/27 MB
-> 480p/37 MB; portrait Short 360x640/6 MB -> 1080x1920/23 MB. Verified
end to end: real downloads decode as h264+aac, clip lands at exactly
60.000s.
Reddit links now download and post like the other platforms.
Two changes were needed, not just the URL pattern:
- Regex: yt-dlp's Reddit extractor only matches /comments/ permalinks, so
the app's /r/<sub>/s/<code> share links and redd.it / v.redd.it
shortlinks are listed explicitly — they redirect to the canonical URL,
which yt-dlp follows. Without them the link is silently dropped.
- Format selector: Reddit publishes video and audio as separate DASH/HLS
streams with no muxed rendition, so every `best...` term failed and
yt-dlp aborted with "Requested format is not available". Added a
bv*+ba merge tail (and a bare bv* for silent videos) to the normal and
/force selectors. Muxed hosts still resolve at the earlier terms, so
YouTube/IG/TikTok/X selection is unchanged.
Posts with no video report "No media found", already in the silent list,
so ordinary Reddit links shared in chat draw no reply.
Two YouTube regressions stacked up:
- yt-dlp 2026.3.17 hit "HTTP Error 403: Forbidden" on the actual media
download. Bumping to 2026.6.9 fixes the data-download 403, but its EJS
n-sig challenge solver now requires Node >= 22, and Debian 13 only ships
Node 20 ("node-20.x (unsupported)" -> only image formats resolve). bot.py
now points --js-runtimes at a standalone /opt/node22 via the new
JS_RUNTIME constant.
- With a cookies.txt present, yt-dlp skips the cookieless android_vr/android
clients (whose URLs work) and falls back to the `tv` client, whose media
URLs 403. New _cookie_args(url) withholds cookies for YouTube hosts only,
while still sending them to Instagram/TikTok/X.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Group-chat bot that downloads videos from X/Instagram/YouTube/TikTok links
via yt-dlp and posts them back, plus /speed and /rev video toys.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>