npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@wvlen/tydle

v0.1.12

Published

YouTube video extractor written in Rust that can be used anywhere in web or native environments, based on an extremely small subset of yt-dlp.

Readme

tydle

Crates.io

tydle is an extremely small subset of yt-dlp, written entirely in Rust. Unlike yt-dlp and all the video-downloaders based around or on it, tydle is meant to be minimal and provide a developer-facing API. It provides a heavily modular approach to extract video metadata, streams or the raw manifest from YouTube and a separate module for deciphering signatures.

The purpose of tydle is not to be used just as a CLI application or as a Rust library, but to be ran on any platform, focused primarily on the client. It can be used in web-based projects through WebAssembly running on serverless functions (Or elsewhere compatible) and in various other environments.

Usage

Require the crate in your Cargo.toml file:

tydle = "0.1.0"

Then use the crate in your Rust code:

use anyhow::Result;
// `Tydle` is the public interface to interact with YouTube.
use tydle::{Tydle, TydleOptions, Extract};

async fn main() -> Result<()> {
  // Initialize `tydle`
  let ty = Tydle::new(TydleOptions { ..Default::default() })?;

  // Now you can fetch depending on what you need.
  let manifest = ty.get_manifest(...).await?;
  let streams = ty.get_streams(...).await?;
  let video_info = ty.get_video_info(...).await?;

  Ok(())
}

Managing Streams, Metadata and Manifests

tydle, with its Extract trait, provides two fetch functions, those being get_streams and get_video_info.

use anyhow::Result;
use tydle::{Tydle, TydleOptions, Extract};

#[tokio::main]
async fn main() -> Result<()> {
  let ty = Tydle::new(TydleOptions { ..Default::default() })?;

  let streams = ty.get_streams(...).await?;
  let video_info = ty.get_video_info(...).await?;

  Ok(())
}

These two functions need to fetch from YouTube's API to get the JSON object (termed the "manifest") which contains data about the video and streams. When you call these two functions specifically, they fetch the manifest themselves individually and return the parsed response directly.

This works great if you are only dealing with singular types of data, like only streams or only video metadata. However, You should avoid using these functions if you need to fetch both the streams as well as the video metadata of the same video, because they each fetch the manifest individually, so you'd be getting and parsing the manifest twice for the same video, which is just a waste of CPU cycles.

Instead, you should use the get_manifest method to fetch the manifest once, then you can pass it to one of the x_from_manifest functions to parse them as structs you can actually work with.

use anyhow::Result;
use tydle::{Tydle, TydleOptions, VideoId, Extract};

#[tokio::main]
async fn main() -> Result<()> {
  let ty = Tydle::new(TydleOptions { ..Default::default() })?;

  let video_id = VideoId::new("XDjB9E3YtUE")?;
  // Now that you have this manifest fetched once, simply pass it to the `x_from_manifest` functions.
  let manifest = ty.get_manifest(&video_id).await?;

  let video_info = ty.get_video_info_from_manifest(&manifest).await?;
  let streams = ty.get_streams_from_manifest(&manifest).await?;

  Ok(())
}

Using The TypeScript API For The WASM Build

Since tydle also compiles to WebAssembly, you can easily use it from TypeScript as well. Here's a simple example using TypeScript:

import { Tydle } from "@wvlen/tydle";

const tydle = new Tydle();

const { streams } = await tydle.fetchStreams("xITJ35Kwpv4");

console.log(streams);

Pitfalls Of Using WASM For Browsers

Since this library is focused for execution on client environments, you might be tempted to use the WebAssembly build for running it in the browser directly. However, even though you can get this tydle to run in the browser correctly, you won't be able to do anything useful other than signature deciphering. This happens because in the browser, CORS restrictions are imposed, preventing any fetches to YouTube's API from being possible.

The library can't work around this issue, even with a proxy option because then the streams fetched won't even be useful to you, as they are only available to the client that fetched it, which in the case of a proxy would be the proxy server and not the browser that's running tydle. Considering that extracted streams on the client being directly accessible from the client is a core focus of the library, it's useless if the browser imposes a restriction.

However, to make up for this, you can probably create a serverless function with the help of the WASM build. Since serverless functions (like on Vercel) can run WebAssembly and produce a reasonable response time, you could probably do something similar as shown below: (This example is using SvelteKit.)

import { error } from "@sveltejs/kit";
import { Tydle } from "@wvlen/tydle";

export async function GET({ params: { videoId } }) {
  try {
    const tydle = new Tydle();
    const streams = await tydle.fetchStreams(videoId);
    const urlStreams = streams.filter((stream) => "url" in stream.source);

    // Since the streams are only accessible here,
    // you need to fetch the source URL here and send that video response back.
    return fetch("url" in urlStreams[0].source && urlStreams[0].source.url);
  } catch (err) {
    console.error(err);
    return error(500, { message: "Failed to get video" });
  }
}

Though this is slower than if the ability to directly call on the client was possible, it at least makes it usable on web environments.

Signature Deciphering

Signature deciphering requires executing JavaScript somehow, as we need to execute YouTube's player.js file which contains the actual logic to decipher signatures. tydle uses the Deno JavaScript Runtime to decipher YouTube URL signatures on native platforms. In WebAssembly builds, it uses the eval() function from the JavaScript context to perform the action instead.

To actually use signature deciphering, enable the cipher feature in your Cargo.toml, then import the Cipher trait to call decipher_signature on ty.

use anyhow::Result;
use tydle::{Tydle, TydleOptions, Cipher};

#[tokio::main]
async fn main() -> Result<()> {
  let ty = Tydle::new(TydleOptions { ..Default::default() })?;

  let deciphered = ty.decipher_signature(...).await?;

  Ok(())
}

Developing Locally

Clone the repository.

$ git clone https://github.com/Dev-Siri/tydle

You need to have Rust installed obviously.

Compile for native builds:

$ cargo build --release

Install wasm-pack if you are compiling for WebAssembly:

$ cargo install wasm-pack

After which, you can build with wasm-pack for target wasm32-unknown-unknown with an environment:

$ wasm-pack build --target nodejs --out-name tydle --scope wvlen --out-dir pkg --release --no-default-features --features cipher

Credits

  • yt-dlp for documentation of the YouTube APIs and providing the EJS modules.
  • youtube_explode_dart for the implementation example of the Deno runtime for signature deciphering.

License

This project is MIT licensed.