yt-dlp External JavaScript Solver
yt-dlp-ejs is a specialized Python library that provides external JavaScript execution capabilities for yt-dlp, the popular video downloader. It solves YouTube's signature and n-parameter challenges by bundling JavaScript solvers that work across multiple runtimes such as Deno, Bun, Node.js, and QuickJS. Currently at version 0.8.0, it maintains a frequent release cadence to adapt to YouTube's player code changes.
Warnings
- breaking yt-dlp is often pinned to a specific compatible version of yt-dlp-ejs. Using mismatched versions can lead to 'No suitable player found' or 'Signature/n-parameter decryption failed' errors, especially for YouTube videos.
- gotcha yt-dlp-ejs *requires* an external JavaScript runtime (e.g., Deno, Node.js, Bun, or QuickJS) to be installed on your system. Without one, yt-dlp-ejs cannot function, and YouTube support in yt-dlp will be limited or broken.
- gotcha YouTube frequently updates its player code, which can break yt-dlp-ejs's decryption logic. This necessitates frequent updates to yt-dlp-ejs.
- gotcha If building from source or performing advanced integrations, be aware that internal changes (like exposing `window` as `self` in 0.8.0 or making `window` a local in 0.2.0) might affect custom JavaScript code relying on these globals.
Install
-
pip install yt-dlp-ejs -
pip install "yt-dlp[default]"
Imports
- yt_dlp_ejs.yt.solver
import yt_dlp_ejs.yt.solver
Quickstart
import os
from yt_dlp import YoutubeDL
# yt-dlp-ejs is automatically detected by yt-dlp if installed.
# Ensure a JS runtime (Deno, Node.js, Bun) is available in your PATH
# or specified via yt-dlp options (e.g., --js-runtimes deno:/path/to/deno)
# Example: Download a YouTube video that requires signature/n-parameter decryption
# For this to work, yt-dlp-ejs and a JS runtime must be correctly set up.
url = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' # Example URL
with YoutubeDL({'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'}) as ydl:
info = ydl.extract_info(url, download=False)
print(f"Title: {info.get('title')}")
print(f"Uploader: {info.get('uploader')}")
print(f"Duration: {info.get('duration_string')}")
print("yt-dlp-ejs (and a JS runtime) was implicitly used for decryption.")
# To explicitly verify the presence of EJS solvers (for advanced debugging)
try:
from yt_dlp_ejs.yt.solver import core, lib
print("yt_dlp_ejs solvers (core, lib) are importable.")
# Example of accessing a solver, though not typically done by end-users:
# core_js = core()
# print(f"Core solver JS size: {len(core_js)} bytes")
except ImportError:
print("yt_dlp_ejs solvers are not directly importable or installed.")