JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 40
  • Score
    100M100P100Q54675F
  • License MIT

YouTube search + download engine (audio/video) with optional caching.

Package Exports

  • @irithell-js/yt-play

Readme

@irithell-js/yt-play

High-performance YouTube audio/video download engine with intelligent caching, built-in yt-dlp and aria2c binaries for blazing fast downloads.

Features

  • βœ… Bundled Binaries - yt-dlp and aria2c included (no system dependencies)
  • Ultra Fast Downloads - aria2c acceleration (up to 5x faster)
  • Intelligent Caching - TTL-based cache with automatic cleanup
  • Smart Quality - Auto-reduces quality for long videos (>1h)
  • Container Ready - Works in Docker/isolated environments
  • Cross-Platform - Linux (x64/arm64), macOS, Windows
  • Zero Config - Auto-detects binaries and optimizes settings
  • TypeScript - Full type definitions included
  • Dual Format - ESM and CommonJS support

Installation

npm install @irithell-js/yt-play

Binaries (yt-dlp + aria2c) are automatically downloaded during installation (this may take a few seconds during the first use).

Quick Start

Basic Usage (ESM)

import { PlayEngine } from "@irithell-js/yt-play";

const engine = new PlayEngine();

// Search and download
const metadata = await engine.search("linkin park numb");
if (!metadata) throw new Error("Not found");

const requestId = engine.generateRequestId();
await engine.preload(metadata, requestId);

// Get audio file
const { file: audioFile } = await engine.getOrDownload(requestId, "audio");
console.log("Audio:", audioFile.path);

// Get video file
const { file: videoFile } = await engine.getOrDownload(requestId, "video");
console.log("Video:", videoFile.path);

// Cleanup cache
engine.cleanup(requestId);

Basic Usage (CommonJS)

const { PlayEngine } = require("@irithell-js/yt-play");

const engine = new PlayEngine();

async function download() {
  const metadata = await engine.search("song name");
  const requestId = engine.generateRequestId();
  await engine.preload(metadata, requestId);

  const { file } = await engine.getOrDownload(requestId, "audio");
  console.log("Downloaded:", file.path);

  engine.cleanup(requestId);
}

download();

Configuration

Constructor Options

const engine = new PlayEngine({
  // Cache settings
  cacheDir: "./cache", // Cache directory (default: OS temp)
  ttlMs: 5 * 60_000, // Cache TTL in ms (default: 3min)
  cleanupIntervalMs: 30_000, // Cleanup interval (default: 30s)
  preloadBuffer: true, // Load files into RAM (default: true)

  // Quality settings
  preferredAudioKbps: 128, // Audio quality: 320|256|192|128|96|64
  preferredVideoP: 720, // Video quality: 1080|720|480|360
  maxPreloadDurationSeconds: 1200, // Max duration for preload (default: 20min)

  // Performance settings (auto-optimized)
  useAria2c: true, // Use aria2c for downloads (default: auto)
  concurrentFragments: 8, // Parallel fragments (default: 5)
  ytdlpTimeoutMs: 300_000, // yt-dlp timeout (default: 5min)

  // Binary paths (optional - auto-detected)
  ytdlpBinaryPath: "./bin/yt-dlp",
  aria2cPath: "./bin/aria2c",
  ffmpegPath: "/usr/bin/ffmpeg", // Optional

  // Logging
  logger: console, // Logger instance (optional)

  // cookies (optional for VPS and dockers)
  cookiesPath: "./cookies.txt",
  // or
  cookiesFromBrowser: "firefox", // extract from browser
});

Quality Presets

// High quality (larger files)
const hq = new PlayEngine({
  preferredAudioKbps: 320,
  preferredVideoP: 1080,
});

// Balanced (recommended)
const balanced = new PlayEngine({
  preferredAudioKbps: 128,
  preferredVideoP: 720,
});

// Low quality (faster, smaller)
const lq = new PlayEngine({
  preferredAudioKbps: 96,
  preferredVideoP: 480,
});

API Reference

PlayEngine Methods

search(query: string): Promise<PlayMetadata | null>

Search for a video on YouTube.

const metadata = await engine.search("artist - song name");
// Returns: { title, author, duration, durationSeconds, thumb, videoId, url }

generateRequestId(prefix?: string): string

Generate unique request ID for caching.

const requestId = engine.generateRequestId("audio"); // "audio_1234567890_abc123"

preload(metadata: PlayMetadata, requestId: string): Promise<void>

Pre-download audio and video in parallel (cached for TTL duration).

await engine.preload(metadata, requestId);
// Downloads audio + video if <1h, only audio if >1h (96kbps)

getOrDownload(requestId: string, type: 'audio' | 'video'): Promise<Result>

Get file from cache or download directly.

const result = await engine.getOrDownload(requestId, "audio");
// Returns: { metadata, file: { path, size, info, buffer? }, direct: boolean }

console.log(result.file.path); // "/tmp/cache/audio_xxx.m4a"
console.log(result.file.size); // 8457234 (bytes)
console.log(result.file.info.quality); // "128kbps m4a"
console.log(result.direct); // false if from cache, true if direct download

waitCache(requestId: string, type: 'audio' | 'video', timeoutMs?: number, intervalMs?: number): Promise<CachedFile | null>

Wait for cache to be ready (useful for checking preload status).

const cached = await engine.waitCache(requestId, "audio", 8000, 500);
if (cached) {
  console.log("Cache ready:", cached.path);
} else {
  console.log("Timeout - falling back to direct download");
}

cleanup(requestId: string): void

Remove cached files for a request.

engine.cleanup(requestId); // Deletes audio + video from cache

getFromCache(requestId: string): CacheEntry | undefined

Get cache entry metadata (without downloading).

const entry = engine.getFromCache(requestId);
if (entry) {
  console.log(entry.metadata.title);
  console.log(entry.audio?.path);
  console.log(entry.loading); // true if preload in progress
}

Advanced Usage

Handle Long Videos (>1h)

const metadata = await engine.search("2h music mix");

// Automatically uses:
// - Audio: 96kbps (reduced quality)
// - Video: skipped (audio only)
await engine.preload(metadata, requestId);

const { file } = await engine.getOrDownload(requestId, "audio");
// Fast download with reduced quality

Custom Cache Directory

import path from "path";

const engine = new PlayEngine({
  cacheDir: path.join(process.cwd(), "downloads"),
  ttlMs: 10 * 60_000, // 10 minutes
});

Performance Monitoring

const startTime = Date.now();
await engine.preload(metadata, requestId);
const preloadTime = Date.now() - startTime;

console.log(`Preload took ${(preloadTime / 1000).toFixed(2)}s`);

Error Handling

try {
  const metadata = await engine.search("non-existent-video");
  if (!metadata) {
    console.error("Video not found");
    return;
  }

  await engine.preload(metadata, requestId);
  const { file } = await engine.getOrDownload(requestId, "audio");
  console.log("Success:", file.path);
} catch (error) {
  console.error("Download failed:", error.message);
}

Performance

With aria2c enabled (default):

Video Length Audio Download Video Download Total Time
5 min ~3-5s ~6-8s ~8s
1 hour ~15-20s Audio only ~20s
2 hours ~25-30s Audio only ~30s

Times may vary based on network speed and YouTube throttling

The values ​​are based on local tests with optimized caching, for downloading long videos use direct download

File Formats

  • Audio: M4A (native format, no conversion needed)
  • Video: MP4 (with audio merged)

M4A provides better quality-to-size ratio and downloads 10-20x faster (no re-encoding).

Requirements

  • Node.js >= 18.0.0
  • ~50MB disk space for binaries (auto-downloaded)
  • Optional: ffmpeg for advanced features

Binaries

The package automatically downloads:

  • yt-dlp v2025.12.08 (35 MB)
  • aria2c v1.37.0 (12 MB)

Binaries are platform-specific and downloaded on first npm install.

Supported Platforms

  • Linux x64 / arm64
  • macOS x64 / arm64 (Apple Silicon)
  • Windows x64

Manual Binary Paths

const engine = new PlayEngine({
  ytdlpBinaryPath: "/custom/path/yt-dlp",
  aria2cPath: "/custom/path/aria2c",
});

Troubleshooting

Slow Downloads

// Enable aria2c explicitly
const engine = new PlayEngine({
  useAria2c: true,
  concurrentFragments: 10, // Increase parallelism
});

Cache Issues

// Clear cache directory manually
import fs from "fs";
fs.rmSync("./cache", { recursive: true, force: true });

Binary Not Found

Binaries are auto-downloaded to node_modules/@irithell-js/yt-play/bin/. If missing:

npm rebuild @irithell-js/yt-play

License

MIT

Contributing

Issues and PRs welcome!

Changelog

Deprecated versions have been removed to prevent errors during use.

0.2.5

  • Added support to direct cookies extraction in pre built browsers

0.2.4

  • Added support to cookies.txt

0.2.3

  • Updated documentation
  • Improved error messages

0.2.2

  • Many syntax errors fixed

0.2.1

  • Added auto-detection for yt-dlp and aria2c binaries
  • Fixed CommonJS compatibility
  • Improved error handling for long videos

0.2.0

  • Initial release with bundled binaries
  • aria2c acceleration support
  • Intelligent caching system