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

@irithell-js/yt-play

v0.2.5

Published

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

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