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

pappy-media-api

v0.9.1

Published

Universal media engine & downloader — search, resolve, grab, and download music, categorized movies, videos, galleries, and 200+ batch items from 520+ platforms with parallel download acceleration, audio/video stream muxing, ID3 album art tagging, target-

Readme

pappy-media-api

The standalone media engine — search, resolve and download, entirely on YOUR machine.

No hosted API. No API keys. No rate limits. No server bill.

YouTube · TikTok · Pinterest · SoundCloud · Dailymotion · Vimeo · Streamable · Twitch · Bluesky · Instagram · Reddit · X · Facebook · Threads · Snapchat · Rumble · Tumblr · Movies (legal) · Subtitles · iTunes · 1800+ sites (via the optional yt-dlp tier)

npm version node license


💸 Why this exists

Hosted media APIs cost money every month — per request, per user, per server. pappy-media-api flips the model: the engine runs inside your app. Your users' machines do the work, so your costs are… zero. Install it, call it, ship.

npm install pappy-media-api
import { UMedia } from "pappy-media-api";

const media = new UMedia();

// 1) Search — music leads with REAL 30-second previews
const { data } = await media.search({ q: "afrobeats", type: "music", limit: 3 });
for (const item of data.items) console.log(item.title, "—", item.previewKind, "→", item.previewUrl);

// 2) Resolve a post → ALL media, in order
const { data: post } = await media.resolve("https://www.tiktok.com/@user/photo/7690630628697459990");
console.log(post.itemCount, post.counts);   // 30 { images: 30, … } — never truncated silently

// 3) Download everything to disk
const { data: job } = await media.download({ url: post.sourceUrl, quality: "best", dir: "./out" });
console.log(job.requestedQuality, "→", job.selectedQuality);  // "best" → "720p" — real, never invented

That's the whole model: your code, your machine, your files.


🎯 The contract that keeps your app honest

🏷️ Quality is never manufactured

requestedQuality vs selectedQuality on every download. A 240p source never arrives wearing a 1080p sticker. fallback: true tells you exactly when reality differed from the request.

🖼️ Galleries arrive complete

100 photos → 100 files, in order (001 - …, 002 - …). Anything that failed is named in failedItems[] with the reason — never silent, never partial-by-accident.

🎧 Previews drop first

Music search leads with real 30s iTunes clips (previewKind: "clip30s"), movies with YouTube trailers, social posts with official embeds. previewKind: "none" beats a fake preview.

🧯 Typed failures, always

UMediaError with a stable code (RATE_LIMITED, MEDIA_NOT_FOUND, PROVIDER_UNAVAILABLE, SSRF_BLOCKED, …), plus engine.attempts[] — the real trail of which providers were tried and why.


🗺️ What runs where (honest edition)

| Platform | Search | Resolve | Download | How | |---|---|---|---|---| | YouTube | ✅ | ✅ | ✅ * | InnerTube — search & metadata always; stream URLs depend on your network (see below) | | TikTok | — | ✅ | ✅ | video posts = direct CDN mp4; photo galleries = every slide the platform publicly exposes, truncated: true when it degrades galleries | | Pinterest | — | ✅ | ✅ | image pins, video pins (direct mp4 + HLS variants), idea/story pins, pin.it short links | | SoundCloud | — | ✅ | ✅ | full tracks as direct progressive MP3 (+ HLS) with real titles/artists | | Dailymotion | — | ✅ | ✅ | public player metadata — HLS/progressive renditions (HLS saved as .ts) | | Vimeo | — | ✅ | ✅ | player config — progressive mp4 when served, HLS otherwise | | Streamable | — | ✅ | ✅ | direct mp4 renditions | | Twitch | — | ✅ | ✅ | clips = direct CloudFront mp4s; VODs/livestreams via the yt-dlp tier | | Bluesky | — | ✅ | ✅ | public AppView API — full-size images + video playlists | | Instagram | — | ✅ | ✅ | oEmbed→mobile info API: photos, videos, full carousels | | Reddit | — | ✅ | ✅ | posts + galleries + video with its audio sidecar (DC IPs may 403 — typed honest error) | | X | — | ✅ | ✅ | syndication token + guest GraphQL: photos/videos/gifs at real bitrates | | Facebook | — | ✅ | ✅ | reels/watch/videos/shares/fb.watch via the web player JSON | | Threads | — | ✅ | ✅ | post SSR state + og media (Meta gates some networks — typed honest error) | | Snapchat | — | ✅ | ✅ | spotlight videos (direct sc-cdn mp4) + public stories/highlights — ALL snaps in order | | Rumble | — | ✅ best-effort | ✅ best-effort | embed API direct mp4s (site blocks datacenter IPs) | | Tumblr | — | ✅ | ✅ | mobile API: video/audio/photo posts + reblog trails, all in order | | iTunes | ✅ | — | ✅ previews | real 30s clips, rock solid | | 1800+ sites | — | ✅ | ✅ | optional tier: pip install yt-dlp — also used automatically as a fallback when a platform is bot-gating your network; labeled source: "yt-dlp (auto-fallback)" | | Movies (legal) | ✅ | ✅ metadata | ✅ trailers/free films | Wikipedia metadata (keyless) + Archive.org full movies + YouTube trailers; categorized cinema | | Music Engine | ✅ | ✅ | ✅ | Multi-source (iTunes 30s clips, SoundCloud full progressive MP3s, Archive.org) | | Mass Grabber | — | ✅ | ✅ | Universal page & gallery extractor: scrapes 200+ photos, videos, audios, and files into disk or ZIP | | Subtitles | — | ✅ | ✅ | YouTube caption tracks (keyless) + OpenSubtitles (your own free key); .srt/.vtt output |


🎵 Universal Music Engine

Search, resolve, and download music across iTunes, SoundCloud, Internet Archive, and YouTube with rich metadata, album art, 30-second previews, and direct progressive audio streams.

import { UMedia } from "pappy-media-api";
const media = new UMedia();

// Multi-source music search with audio stream and preview URLs
const res = await media.searchMusic({ q: "Daft Punk", limit: 5 });

for (const track of res.data.items) {
  console.log(`${track.artist} - ${track.title} (${track.source})`);
  console.log(`  Preview: ${track.previewUrl}`);
  console.log(`  Direct Stream: ${track.streamUrl || track.downloadUrl}`);
}

CLI:

# Search across all sources with audio preview links
npx pappy-media-api music "Starboy" --limit 5

# Search specifically on SoundCloud for full tracks
npx pappy-media-api music "lofi beats" --source soundcloud --limit 10

🎬 Categorized Movies & Cinema

Browse and discover cinema categorized across 16 global industries and genres:

  • Regional Industries: hollywood, bollywood, nollywood, korean (K-Drama), chinese (Wuxia), donghua (Chinese Animation), japanese, anime
  • Genres: action, comedy, horror, scifi, documentary, classics (Public Domain)
  • Mature & Adult (Strict Opt-in): 18+_movies, 18+_anime (adult: true required)

Direct MP4 downloads are provided for full feature films via Internet Archive, alongside legal official trailers on YouTube.

// 1) List available movie categories
const categories = media.movieCategories();

// 2) Search public domain classic movies (with direct MP4 downloadUrl)
const classics = await media.searchMovies({
  q: "Charade",
  category: "classics",
  source: "archive",
});
console.log(classics.data.items[0].downloadUrl);
// → https://archive.org/download/Charade/Charade.mp4

// 3) Search action cinema
const actionFilms = await media.searchMovies({
  q: "martial arts",
  category: "action",
  limit: 5,
});

// 4) Access adult-themed cinema (strictly gated opt-in)
const mature = await media.searchMovies({
  q: "uncut",
  category: "18+_movies",
  adult: true,
});

CLI:

# List all movie categories
npx pappy-media-api movie-categories

# Search classic movies
npx pappy-media-api movies "night of the living dead" --category classics

# Include adult categories (opt-in)
npx pappy-media-api movie-categories --adult

🌐 Universal Mass Media Grabber (200+ Media Items)

Extract and download every photo, video, audio file, and document embedded inside any webpage or gallery URL. Perfect for scraping 50, 100, or 200+ assets at once with automatic batch downloading and optional .zip bundle generation.

// 1) Grab all media metadata from any webpage
const grabResult = await media.grab("https://example.com/gallery", {
  limit: 200,     // Extract up to 200 items
  type: "all",    // "all" | "image" | "video" | "audio" | "document"
});

console.log(`Found ${grabResult.data.itemCount} items!`);

// 2) Download all extracted items into a folder or zip
const downloadResult = await media.downloadGrab(grabResult, {
  dir: "./downloads",
  zip: true,      // Package all downloaded files into a .zip archive
  concurrency: 5, // Concurrent download workers
  onProgress: (done, total) => console.log(`Downloaded ${done}/${total}...`),
});

CLI:

# Grab and inspect all media on a webpage
npx pappy-media-api grab "https://example.com/page" --limit 100

# Grab, download all media, and zip them into an archive
npx pappy-media-api grab "https://example.com/gallery" --limit 200 -o ./downloads --zip

🏛️ 520 Platform Registry & Spec

pappy-media-api includes an exhaustive registry of 520 digital media platforms across 12 distinct industry categories:

  • Major Social Networks (youtube, tiktok, instagram, facebook, x, threads, snapchat, reddit, …)
  • Music & Audio Platforms (soundcloud, audiomack, bandcamp, mixcloud, spotify, …)
  • Chinese & Regional Platforms (douyin, kuaishou, bilibili, weibo, iqiyi, youku, …)
  • Video & Streaming Hubs (twitch, vimeo, dailymotion, kick, rumble, …)
  • Anime & Animation (crunchyroll, hidive, donghua, iqiyi, …)
  • Image & Art Boards (pinterest, deviantart, pixiv, artstation, imgur, …)
  • News, Podcasts, E-Learning, Sports, Cloud Drives, and Adult Streaming.
import { getPlatform, queryPlatforms, detectPlatform } from "pappy-media-api";

// Identify platform from URL
const detected = detectPlatform("https://www.tiktok.com/@user/video/123");

// Query platforms in the registry
const musicPlatforms = queryPlatforms({ category: "music_audio", tier: "A" });

🎬 Movies & subtitles (legal)

Discovery + metadata — real, keyless, no piracy:

const media = new UMedia();

// metadata for any film: title, year, plot, poster, rating
const { data } = await media.movie({ q: "Inception" });
// → { title: "Inception", year: 2010, poster: "https://…", description: "2010 film by…" }

// optional: richer metadata + ratings via your own free TMDB key
await media.movie({ q: "Inception", tmdbKey: process.env.PAPPY_TMDB_KEY });

// legal playback sources: official trailers + officially free full movies on YouTube
const films = await media.searchMovies({ q: "inception", limit: 10 });

Subtitles — two legal engines, real .srt/.vtt files:

// 1) a YouTube video's own captions (keyless; same network caveat as streams)
await media.youtubeSubtitles({ url: "https://youtu.be/…", lang: "en", format: "srt" });
const langs = await media.captionLanguages("https://youtu.be/…"); // what's available

// 2) any movie or TV episode via OpenSubtitles (bring your own free key)
//    get one at opensubtitles.com/consumers, then:
const subs = media.subtitles({ apiKey: process.env.PAPPY_OPENSUBTITLES_KEY });
const found = await subs.search({ imdbId: "tt1375666", languages: ["en", "fr"] });
await subs.download({ fileId: found.data.results[0].files[0].fileId, dir: "./subs" });

Converters are exported too: vttToSrt, youtubeXmlToSrt, srtToVtt.

CLI: pappy-media-api movie "Inception" · pappy-media-api movies "inception" · pappy-media-api subtitles <youtube-url> --lang en --format srt

18+ content is strictly gated. No adult provider ships in this engine (adult_enabled: false, adultProviders: []), and no DRM or paywall is ever circumvented.

* About YouTube stream URLs: YouTube bot-gates datacenter IPs and serves formats without URLs. On typical home connections download() just works; on hard networks you'll get a typed PROVIDER_UNAVAILABLE with the real reason — or run download({ … }) via downloadWithYtdlp() / pappy-media-api download <url> --ytdlp which handles PO tokens, cookies and muxing. We'd rather tell you the truth than fake a download.

Direct media URLs always work: give resolve()/download() any direct .mp4/.m4a/.jpg/… link and it goes straight to disk — no platform needed.

// the power tier — one function, 1800+ sites, hard networks
await media.downloadWithYtdlp({ url: "https://example.com/anything", quality: "720p", dir: "./out" });

📚 API

| Call | What it does | |---|---| | media.searchMusic({q, limit, source, adult}) | Music engine across iTunes, SoundCloud, Archive.org with audio streams & previews | | media.searchMovies({q, category, limit, source, adult}) | Categorized cinema (Hollywood, Bollywood, Nollywood, Korean, Anime, Action, 18+ opt-in) | | media.movieCategories({adult}) | Registry of 16 movie categories & genres | | media.grab(url, {limit, type, dir}) | Mass media grabber extracting 200+ images/videos/audio from any page | | media.downloadGrab(grabRes, {dir, zip}) | Batch downloader for grabbed items with progress and optional ZIP packaging | | media.acceleratedDownload({url, dest, concurrency}) | Parallel multi-segment chunk downloader with HTTP Range support | | media.mux({video, audio, output}) | Lossless video and audio stream merger (MP4/MKV) via ffmpeg | | media.extractAudio({input, output, format, bitrate}) | High quality audio extraction from video or stream URLs | | media.tagAudio({filePath, metadata, cover}) | ID3v2 metadata & album artwork thumbnail tagger | | media.downloadMusic(track, {dir, tag}) | Download track from music search, embed ID3 tags & artwork | | media.compress({input, output, targetSizeMb}) | Target-size video compressor (optimizes for Discord, WhatsApp, social limits) | | media.embedSubtitles({video, subtitles, output, mode}) | Subtitle track embedder (soft timed text tracks or burned hardsubs) | | media.createPreviewGif({input, output, duration}) | Animated GIF/WebP preview clip generator with 2-pass palette optimization | | media.createStoryboard({input, output, rows, cols}) | Keyframe storyboard contact sheet image generator | | media.record({url, output, durationSeconds}) | Live stream and HLS/DASH broadcast recorder | | media.inspect(url) | Deep media inspector — streams, codecs, resolutions, subtitles, formats | | media.serve({port, host}) | Embedded zero-dependency HTTP streaming proxy & REST microservice | | media.search({q, type, limit, adult}) | Multi-source search — type: video | music | movie | short_video | | media.resolve(url) | Every media item of a post, in order + honest engine.attempts | | media.download({url, quality, dir, accelerate, zip, onProgress}) | Saves files to disk — quality: original | best | 2160p … 144p | audio | | media.downloadWithYtdlp({url, quality, dir}) | yt-dlp tier (requires yt-dlp on PATH) | | media.capabilities() | What THIS machine can actually do — never overstated | | media.status() | Real adapter status |

Error codes — INVALID_REQUEST · INVALID_URL · SSRF_BLOCKED · AUTH_REQUIRED · AUTH_INVALID · RATE_LIMITED · MEDIA_NOT_FOUND · CONTENT_PRIVATE · ACCESS_RESTRICTED · QUALITY_UNAVAILABLE · PROVIDER_ERROR · PROVIDER_UNAVAILABLE · TIMEOUT · NOT_FOUND · INTERNAL


🖥️ CLI

# 1. Embedded Streaming Proxy & Microservice Server
npx pappy-media-api serve --port 3333                     # boots HTTP server + HTML5 dashboard

# 2. Deep Media Stream Inspector
npx pappy-media-api inspect "https://example.com/video"   # codecs, formats, bitrates, subtitles

# 3. High-Speed Segmented Parallel Download
npx pappy-media-api download "https://example.com/movie.mp4" --accelerate --concurrency 4
npx pappy-media-api download "https://example.com/video" --cookies cookies.txt   # session bypass

# 4. Target-Size Video Compressor & Subtitle Embedder
npx pappy-media-api compress video.mp4 -o discord.mp4 --target 25mb             # fits under 25MB
npx pappy-media-api embed-subs --video movie.mp4 --subs movie.srt -o subbed.mp4 # soft or --burn

# 5. Visual Storyboards & Animated GIF Previews
npx pappy-media-api preview video.mp4 --gif -o preview.gif                      # animated preview
npx pappy-media-api preview video.mp4 --storyboard -o contact_sheet.jpg         # 3x3 keyframes

# 6. Live Broadcast & HLS Stream Recorder
npx pappy-media-api record "https://live.example.com/stream.m3u8" --duration 60s -o live.mp4

# 7. In-Process Stream Muxer & Audio Extractor
npx pappy-media-api mux --video video.mp4 --audio audio.m4a -o synced.mp4
npx pappy-media-api extract-audio video.mp4 -o song.mp3 --bitrate 320k

# 8. Music Engine with ID3 & Album Art Injection
npx pappy-media-api music "Starboy" --limit 5
npx pappy-media-api music "lofi study" --source soundcloud --download --tag

# 9. Categorized Movies & Public Domain Features
npx pappy-media-api movie-categories
npx pappy-media-api movies "night of the living dead" --category classics
npx pappy-media-api movies "kung fu" --category chinese

# 10. Mass Media Grabber (200+ items)
npx pappy-media-api grab "https://example.com/gallery" --limit 200 -o ./downloads --zip

# 11. Social & Video Resolvers
npx pappy-media-api search "lofi beats" --type music --limit 5
npx pappy-media-api resolve "https://www.tiktok.com/@user/photo/7690630628697459990"
npx pappy-media-api download "https://youtu.be/jNQXAC9IVRw" --quality best -o ./out
npx pappy-media-api download "https://example.com/video" --ytdlp      # power tier
npx pappy-media-api status
npx pappy-media-api doctor                                             # start here if a download fails

Downloads on a bot-gated network

YouTube (and some platforms) withhold stream URLs from datacenter networks — the native tier honestly reports that, then falls back automatically:

# 1. check what you have and what's missing
npx pappy-media-api doctor

# 2. if yt-dlp is missing, install it — that's the whole fix
pip install yt-dlp        # or: pipx install yt-dlp / brew install yt-dlp

# 3. the same command now just works
npx pappy-media-api download "https://youtu.be/jNQXAC9IVRw" -o ./out
const media = new UMedia();
const r = await media.download({ url, dir: "./out" });
r.data.source;   // "youtube" (native) | "yt-dlp (auto-fallback)" | "tiktok"
r.data.files;    // [{ name, path, size }]

With yt-dlp installed, download() uses it only when the native tier couldn't get a URL — everything else stays on the fast native path. Force it with noYtdlpFallback: true to require the native tier only.


🧯 Safety, built in

  • SSRF hygiene — private, loopback and internal hosts are refused (SSRF_BLOCKED).
  • No secrets to manage — there are none. No keys, no tokens, no dashboards.
  • Zero telemetry. Your users' requests never touch anyone's server — because there isn't one.

🤖 Production Showcase: Pappy / Omega (Telegram Media OS)

pappy-media-api powers Pappy / Omega — a production-grade Telegram-native Media Operating System:

  • 🎵 Universal Music Search & DJ Streaming: iTunes 30s previews, SoundCloud full tracks, ID3 album art tagging, and group voice-call DJ streaming.
  • 🎬 16 Categorized Movie Industries: Hollywood, Bollywood, Nollywood, Korean, Chinese, Japanese, Anime, Donghua, Action, and Classics with legal public-domain MP4s and trailers.
  • 🌐 Mass Web Media Grabber: Scrapes and bundles up to 200+ images/videos from any page into direct ZIP downloads.
  • 🗜️ Target-Size Video Compression: Dynamically compresses high-res video down to 48MB to seamlessly fit under Telegram's 50MB Bot API upload ceiling.
  • ⚡ Multi-Segment Range Accelerator: 3–5x faster downloads with parallel chunk reconstruction.
  • 🖼️ Complete Social Galleries: Downloads every item in TikTok, Instagram, Reddit, X, and Pinterest posts with zero silent truncation.

Built to save you the hosting bill. Ship the engine, not the infrastructure.

MIT © 2026 · part of the Unified Media API project