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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hiudyy/ytdl

v0.2.6

Published

Universal Audio and Video Downloader: Download content effortlessly from YouTube, TikTok, Instagram, Pinterest, social media platforms, and various streaming sites.

Readme

@hiudyy/ytdl

Universal audio and video downloader with multi-provider fallback system. Supports YouTube, TikTok, Instagram, and Pinterest.

Features

  • YouTube with a pool of 7 providers (automatic fallback, retry, and cooldown)
  • TikTok videos & slideshows, with search
  • Instagram posts, reels & IGTV (video/image detection)
  • Pinterest pins & search
  • downloadToTemp — stream any media URL to a temp file with size limits & cleanup
  • Zero runtime dependencies — dual CJS/ESM exports
  • Abort support (AbortSignal) and injectable fetch implementation

Installation

npm install @hiudyy/ytdl
yarn add @hiudyy/ytdl

How to use

Importing the module

const { downloadYouTube, resolveYouTubeTarget } = require("@hiudyy/ytdl");
// or ESM:
// import { downloadYouTube, resolveYouTubeTarget } from '@hiudyy/ytdl';

API

downloadYouTube(videoURL, format, options?)

Downloads a YouTube video or audio using a pool of providers with automatic fallback.

Parameters:

  • videoURL (string) — YouTube video URL
  • format (string) — "mp3" for audio or "mp4" for video
  • options (object, optional):
    • signal (AbortSignal) — abort signal to cancel the download
    • fetchImpl (function) — custom fetch implementation
    • pool (YouTubeProviderPool) — custom provider pool instance

Returns: Promise<YtDownloadResult>

const { downloadYouTube } = require("@hiudyy/ytdl");

(async () => {
  const result = await downloadYouTube("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "mp3");
  if (result.success) {
    console.log("Downloaded:", result.filePath);
    console.log("Title:", result.title);
    console.log("Size:", result.size);
    console.log("Source provider:", result.source);
  } else {
    console.error("Failed:", result.error);
  }
})();

YtDownloadResult:

{
  success: boolean;
  filePath?: string;      // Path to the downloaded file
  title?: string;         // Video title
  thumbnail?: string;     // Thumbnail URL
  quality?: string;       // Quality label
  duration?: string;      // Duration string
  author?: string;        // Channel/author name
  ext?: string;           // File extension
  size?: number;          // File size in bytes
  source?: string;        // Provider name used
  error?: string;         // Error message if failed
}

resolveYouTubeTarget(query, signal?, fetchImpl?)

Resolves a YouTube URL to a canonical watch URL.

const { resolveYouTubeTarget } = require("@hiudyy/ytdl");

(async () => {
  const { url } = await resolveYouTubeTarget("https://youtu.be/dQw4w9WgXcQ");
  console.log(url); // https://www.youtube.com/watch?v=dQw4w9WgXcQ
})();

Provider System

The library uses a pool of 7 providers with automatic fallback, retry, and cooldown:

| Provider | Formats | Strategy | |----------|---------|----------| | nayan | mp3, mp4 | Direct API | | flvto | mp3, mp4 | POST + format selection | | ytconvert | mp3, mp4 | POST + polling (30 attempts, backoff) | | nevercap | mp3, mp4 | POST + polling (15 attempts, backoff) | | oceansaver | mp3, mp4 | POST + polling (20 attempts, backoff) | | savetube | mp3, mp4 | CDN + AES decrypt | | luka | mp3, mp4 | Direct API |

Pool behavior:

  • Providers are tried sequentially (one at a time, never fired in parallel)
  • Max 3 failures before cooldown (5 hours)
  • 2 retries per provider with 2s delay
  • Successful providers are promoted to the front
  • Failed providers are demoted to the back

Custom Pool Configuration

You can tune the pool behavior (failure threshold, cooldown, retries) and/or provide your own provider list.

const { configureDefaultYouTubePool } = require("@hiudyy/ytdl");

// Adjust only the options:
configureDefaultYouTubePool({
  maxFailures: 5,
  cooldownMs: 60 * 60_000, // 1 hour
  retries: 3,
  retryDelayMs: 3_000,
});

// Or pass a custom provider list + options:
configureDefaultYouTubePool([myProviderA, myProviderB], {
  retries: 1,
  cooldownMs: 30 * 60_000,
});

Pool options:

| Option | Default | Description | |--------|---------|-------------| | maxFailures | 3 | Failures before the provider enters cooldown | | cooldownMs | 5h | How long a provider stays in cooldown | | retries | 2 | Retry attempts per provider | | retryDelayMs | 2000 | Delay between retries | | mode | "sequential" | "sequential" (one at a time) or "race" (parallel) |

You can also build your own pool with new YouTubeProviderPool(providers, options) and pass it directly to downloadYouTube(url, format, { pool }).


Abort Support

const { downloadYouTube } = require("@hiudyy/ytdl");

const controller = new AbortController();
setTimeout(() => controller.abort(), 30_000); // 30s timeout

const result = await downloadYouTube(url, "mp4", { signal: controller.signal });

TikTok

downloadTiktok(url, options?)

Downloads a TikTok video or slideshow via tikwm.com.

Parameters:

  • url (string) — TikTok video URL
  • options (object, optional):
    • signal (AbortSignal) — abort signal to cancel the request
    • fetchImpl (function) — custom fetch implementation

Returns: Promise<TiktokDownloadResult>

const { downloadTiktok, isValidTiktokURL } = require("@hiudyy/ytdl");

(async () => {
  const url = "https://www.tiktok.com/@user/video/1234567890";
  if (isValidTiktokURL(url)) {
    const result = await downloadTiktok(url);
    console.log("Type:", result.type);   // "video" or "image"
    console.log("URLs:", result.urls);   // array of media URLs
    console.log("Title:", result.title);
    console.log("Audio:", result.audio);
  }
})();

TiktokDownloadResult:

{
  urls: string[];     // Media URLs (video or images)
  type: "video" | "image";
  title: string;      // Video title
  audio: string;      // Audio/music URL
}

searchTiktok(query, options?)

Searches TikTok and returns a random result.

const { searchTiktok } = require("@hiudyy/ytdl");

(async () => {
  const result = await searchTiktok("funny cats");
  console.log("URL:", result.url);
  console.log("Title:", result.title);
})();

isValidTiktokURL(url)

Validates if a URL is a valid TikTok URL.

const { isValidTiktokURL } = require("@hiudyy/ytdl");
console.log(isValidTiktokURL("https://www.tiktok.com/@user/video/123")); // true

Instagram

downloadInstagram(url, options?)

Downloads media from an Instagram post, reel, or IGTV.

Parameters:

  • url (string) — Instagram post/reel/IGTV URL
  • options (object, optional):
    • signal (AbortSignal) — abort signal to cancel the request
    • fetchImpl (function) — custom fetch implementation

Returns: Promise<InstagramDownloadResult>

const { downloadInstagram, isValidInstagramURL } = require("@hiudyy/ytdl");

(async () => {
  const url = "https://www.instagram.com/reel/ABC123/";
  if (isValidInstagramURL(url)) {
    const result = await downloadInstagram(url);
    console.log("Count:", result.count);
    for (const media of result.medias) {
      console.log(media.type, media.url);
    }
  }
})();

InstagramDownloadResult:

{
  medias: Array<{
    type: "video" | "image";
    url: string;
  }>;
  count: number;
}

isValidInstagramURL(url)

Validates if a URL is a valid Instagram URL (supports /p/, /reel/, /reels/, /tv/).

const { isValidInstagramURL } = require("@hiudyy/ytdl");
console.log(isValidInstagramURL("https://www.instagram.com/p/ABC123/")); // true

Pinterest

downloadPinterest(url, options?)

Downloads a specific Pinterest pin (image or video).

Parameters:

  • url (string) — Pinterest pin URL (supports pin.it short URLs)
  • options (object, optional):
    • signal (AbortSignal) — abort signal to cancel the request
    • fetchImpl (function) — custom fetch implementation

Returns: Promise<PinterestDownloadResult>

const { downloadPinterest, isValidPinterestURL } = require("@hiudyy/ytdl");

(async () => {
  const url = "https://br.pinterest.com/pin/123456789/";
  if (isValidPinterestURL(url)) {
    const result = await downloadPinterest(url);
    console.log("Type:", result.type);  // "image" or "video"
    console.log("URL:", result.url);
  }
})();

PinterestDownloadResult:

{
  url: string;
  type: "image" | "video";
}

searchPinterest(query, options?)

Searches Pinterest for images and returns up to 50 image URLs.

const { searchPinterest } = require("@hiudyy/ytdl");

(async () => {
  const images = await searchPinterest("nature landscape");
  console.log(`Found ${images.length} images`);
  images.forEach(url => console.log(url));
})();

isValidPinterestURL(url)

Validates if a URL is a valid Pinterest URL.

const { isValidPinterestURL } = require("@hiudyy/ytdl");
console.log(isValidPinterestURL("https://br.pinterest.com/pin/123456/")); // true
console.log(isValidPinterestURL("https://pin.it/abc123")); // true

Download to Temp

downloadToTemp(options)

Downloads any media URL to a temporary file with size limits and automatic cleanup.

Parameters:

  • options (object):
    • url (string) — Media URL to download
    • kind (string) — Media kind: "image", "audio", "video", "document", "sticker"
    • headers (object, optional) — Custom HTTP headers
    • signal (AbortSignal, optional) — Abort signal
    • fetchImpl (function, optional) — Custom fetch implementation
    • tempDir (string, optional) — Custom temp directory (defaults to os.tmpdir())

Returns: Promise<TempMedia>

Size limits: image=20MB, audio=40MB, video=80MB, document=80MB, sticker=20MB

const { downloadToTemp } = require("@hiudyy/ytdl");

(async () => {
  const media = await downloadToTemp({
    url: "https://example.com/video.mp4",
    kind: "video",
  });

  console.log("Path:", media.path);
  console.log("Size:", media.size);
  console.log("Content-Type:", media.contentType);

  // Use the file...

  // Clean up when done
  await media.cleanup();
})();

TempMedia:

{
  path: string;         // Path to the temp file
  size: number;         // File size in bytes
  contentType: string;  // MIME type
  kind: string;         // Media kind
  cleanup: () => Promise<void>;  // Remove the temp file (idempotent)
}

Transcode

transcodeYouTubeMedia(inputPath, outputPath, options?)

Re-encodes an audio/video file using FFmpeg (requires FFmpeg in PATH).

Parameters:

  • inputPath (string) — source file path
  • outputPath (string) — destination file path
  • options (object, optional):
    • videoCodec (string) — default "libx264"
    • audioCodec (string) — default "aac"
    • preset (string) — default "fast"
    • crf (number) — default 23
    • audioBitrate (string) — default "128k"
const { transcodeYouTubeMedia } = require("@hiudyy/ytdl");

await transcodeYouTubeMedia("/tmp/in.webm", "/tmp/out.mp4", {
  videoCodec: "libx264",
  audioBitrate: "192k",
});

Requirements

  • Node.js >= 18.0.0 (bundles fetch, AbortSignal, etc.)
  • FFmpeg is only required if you use transcodeYouTubeMedia — it must be available in your PATH

Contribution

Feel free to open issues or submit pull requests to improve the module.

GitHub repository: 🔗 Click here


License

This project is licensed under the MIT License.