@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.
Maintainers
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 injectablefetchimplementation
Installation
npm install @hiudyy/ytdlyarn add @hiudyy/ytdlHow 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 URLformat(string) —"mp3"for audio or"mp4"for videooptions(object, optional):signal(AbortSignal) — abort signal to cancel the downloadfetchImpl(function) — custom fetch implementationpool(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 URLoptions(object, optional):signal(AbortSignal) — abort signal to cancel the requestfetchImpl(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")); // truedownloadInstagram(url, options?)
Downloads media from an Instagram post, reel, or IGTV.
Parameters:
url(string) — Instagram post/reel/IGTV URLoptions(object, optional):signal(AbortSignal) — abort signal to cancel the requestfetchImpl(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/")); // truedownloadPinterest(url, options?)
Downloads a specific Pinterest pin (image or video).
Parameters:
url(string) — Pinterest pin URL (supportspin.itshort URLs)options(object, optional):signal(AbortSignal) — abort signal to cancel the requestfetchImpl(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")); // trueDownload 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 downloadkind(string) — Media kind:"image","audio","video","document","sticker"headers(object, optional) — Custom HTTP headerssignal(AbortSignal, optional) — Abort signalfetchImpl(function, optional) — Custom fetch implementationtempDir(string, optional) — Custom temp directory (defaults toos.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 pathoutputPath(string) — destination file pathoptions(object, optional):videoCodec(string) — default"libx264"audioCodec(string) — default"aac"preset(string) — default"fast"crf(number) — default23audioBitrate(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 yourPATH
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.
