An http api wrapper for yt-dlp/ejs.
The absolute easiest way to use this with Lavalink is to just add this to the youtube plugin config
plugins:
youtube:
remoteCipher:
url: "https://cipher.kikkia.dev/"
userAgent: "your_service_name" # OptionalYou can use the public instance without a password at https://cipher.kikkia.dev/.
I do my best to keep it up and running and decently fast, but I don't guaruntee 100% uptime. Feel free to host it yourself or use the public API.
WARNING: Ratelimit of 10 requests/sec (should be fine up to 1000+ active players). If you have more than 1k players you probably want to host it yourself.
The easiest way to host this service is with Docker (NOTE: Default password in the docker-compose.yml is "test")
git clone https://github.com/kikkia/yt-cipher.git
cd yt-cipherBuild container and run:
docker compose upIf you have Bun installed, you can run the service directly.
Clone this repository:
git clone https://github.com/kikkia/yt-cipher.git
cd yt-cipherInstall dependencies and run:
bun install
bun startIn your flake.nix:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
yt-cipher.url = "github:kikkia/yt-cipher";
};
outputs = { self, nixpkgs, yt-cipher }:
{
nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
yt-cipher.nixosModules.default
{
nixpkgs = {
overlays = [yt-cipher.overlays.default];
config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) ["yt-cipher"];
};
}
./configuration.nix
];
};
};
}In your configuration.nix:
{
services.yt-cipher = {
enable = true;
openFirewall = true;
# apiToken = "your-secret-token";
};
}You can optionally set the API_TOKEN environment variable in your docker-compose.yml file to require a password to access the service.
Requests without a valid Authorization: <your_token> header will be rejected if you have a token set.
Environment Variables:
MAX_THREADS- max # of workers that can handle requests. Default is 1 per thread on the machine or 1 if it can't determine that for some reasonAPI_TOKEN- A required password to access this servicePORT- Port to run the api on, default:8001HOST- Sets the hostname for the deno server, default:0.0.0.0PREPROCESSED_CACHE_SIZE- Max size of processed player script cache. Lower to consume less memory, default:150SOLVER_CACHE_SIZE- Max size of solver function cache. Lower to consume less memory, default:50STS_CACHE_SIZE- Max size of signature timestamp cache. Lower to consume less memory, default:150DISABLE_METRICS- Disables the metrics made for prometheus
To run the server with IPv6, you need to configure the HOST environment variable.
- Set
HOSTto[::]to bind to all available IPv6 and IPv4 addresses on most modern operating systems.
When accessing the service over IPv6, make sure to use the correct address format. For example, to access the service running on localhost, you would use http://[::1]:8001/.
If you are using this with the youtube-source plugin, please reference the setup steps.
If you ever have issues with read timeout errors, you can try upping the http timeouts in your lavalink config
lavalink:
server:
timeouts:
connectTimeoutMs: 10000
connectionRequestTimeoutMs: 10000
socketTimeoutMs: 10000Request Body:
{
"encrypted_signature": "...",
"n_param": "...",
"player_url": "..."
}encrypted_signature(string): The encrypted signature from the video stream.n_param(string): Thenparameter value.player_url(string): The URL to the JavaScript player file that contains the decryption logic.
Successful Response:
{
"decrypted_signature": "...",
"decrypted_n_sig": "..."
}Example curl request:
curl -X POST http://localhost:8001/decrypt_signature \
-H "Content-Type: application/json" \
-H "Authorization: your_secret_token" \
-d '{
"encrypted_signature": "...",
"n_param": "...",
"player_url": "https://..."
}'Extracts the signature timestamp (sts) from a player script.
Request Body:
{
"player_url": "..."
}player_url(string): The URL to the JavaScript player file.
Successful Response:
{
"sts": "some_timestamp"
}Example curl request:
curl -X POST http://localhost:8001/get_sts \
-H "Content-Type: application/json" \
-H "Authorization: your_secret_token" \
-d '{
"player_url": "https://..."
}'Resolves a raw stream URL by handling the signature and n-parameter decryption, returning a fully constructed and ready-to-use playback URL.
Request Body:
{
"stream_url": "...",
"player_url": "...",
"encrypted_signature": "...",
"signature_key": "...",
"n_param": "..."
}stream_url(string): The initial stream URL (not video url).player_url(string): The URL to the JavaScript player file.encrypted_signature(string): The encrypted signature value.signature_key(string, optional): The query parameter key to use for the decrypted signature in the final URL. Defaults tosig.n_param(string, optional): Thenparameter value. If not provided, it will be extracted from thestream_url.
Successful Response:
{
"resolved_url": "..."
}