youtube-unthrottle
implements a small subset of tools like
yt-dlp,
rusty_ytdl,
and of course, youtube-dl.
Specifically, youtube-unthrottle
extracts the video and audio stream URLs
from a YouTube link passed via argv[1]
. A program like mpv
can act on
this output like:
uri="$(xclip -o)"
x="/tmp/streams.txt"
youtube-unthrottle "$uri" > "$x"
audio="$(head -1 $x)"
video="$(tail -1 $x)"
mpv --title="$uri" --audio-file="$audio" "$video"
Our main challenge: YouTube obfuscates its stream URLs and pairs them with dynamic JavaScript-based deobfuscation logic. To get usable URLs, we must apply the latter to the former.
Why solve this problem anew, when tools like yt-dlp
already exist? I have
mainly learning in mind:
- embed a scripting language within another program
- use the C APIs of libcurl and pcre2, without relying on a higher-level language wrapper
- test-drive the -fanalyzer gcc option
- see whether ASan, LSan, and UBSan catch problems caused by changing server-side state
- try out sandboxing APIs like libseccomp, Landlock, pledge(), and unveil()
I also want to watch YouTube without:
- crashing my desktop PC due to CPU/GPU thermals
- needing the OOM killer to save me from swap death
- seeing jank, tearing, and other visual glitches
I like to avoid python3 as well, which e.g. yt-dlp
requires.
I've tested on 64-bit Arch Linux and 64-bit OpenBSD 7.6.
ada
cmake
curl
duktape
jansson
libseccomp
pcre2
I developed with the following versions of these libraries (though I assume many other versions would work as well):
$ pacman -Q ada cmake curl duktape jansson libseccomp pcre2
ada 2.9.2-1
cmake 3.31.5-1
curl 8.11.1-3
duktape 2.7.0-7
jansson 2.14-4
libseccomp 2.5.5-4
pcre2 10.44-1
Optionally, for code coverage and fuzzing:
clang
llvm
To build and run:
cmake --preset default
cmake --build --preset default
./build/youtube-unthrottle --help
To build and run tests:
cmake --preset default
cmake --build --preset default
ctest --preset default
To rebuild from scratch:
cmake --preset default --fresh
cmake --build --preset default --clean-first
To build with clang instead of gcc:
cmake --preset clang --fresh
cmake --build --preset default --clean-first
To create a code coverage report:
cmake --preset coverage --fresh
cmake --build --preset default --clean-first
COVERAGE_PROFILE_DIR=coverage.profraw ctest --preset default
./scripts/coverage.sh coverage.profraw ./build/coverage.xml
llvm-cov show -instr-profile=./build/coverage.profdata -object ./build/youtube-unthrottle
To build and fuzz:
cmake --preset fuzzer --fresh
cmake --build --preset default --clean-first
cd ./build/tests/fuzzer/
cp -pr ../../../tests/fuzzer/samples/find_js_deobfuscator corpus
./find_js_deobfuscator -max_len=3000000 corpus > fuzz.log 2>&1 &