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

react-native-hls-cache

v1.4.0

Published

HSL

Readme

react-native-hls-cache

HLS segment caching for React Native via a local TCP proxy server.

| Platform | Support | |----------|---------| | iOS | Full proxy — manifests + segments cached to disk | | Android | No-op — ExoPlayer/Media3 handles caching natively |

Powered by Nitro Modules for zero-overhead FFI.


Installation

npm install react-native-hls-cache react-native-nitro-modules

Bare React Native

cd ios && pod install

Expo

expo prebuild regenerates ios/Podfile from scratch, wiping manual edits. Use the config plugin to inject the Cache pod automatically:

// app.json
{
  "expo": {
    "plugins": ["react-native-hls-cache"]
  }
}

How it works

AVPlayer
  → http://127.0.0.1:9000/proxy?url=<encoded>
  → Local proxy (NWListener)
      ├── Cache hit  → serve from disk instantly
      └── Cache miss → fetch from origin, stream to player + write to disk

All HLS manifest URLs are rewritten to route through the proxy. Subsequent plays of the same video are served entirely from disk — zero network traffic.


Quick start

import { useEffect } from 'react';
import { startServer, convertUrl, precacheBatch, cancelPrecache } from 'react-native-hls-cache';
import Video from 'react-native-video';

// 1. Start the proxy once on app mount
useEffect(() => {
  startServer(9000, 1_073_741_824, false, (e) => {
    if (e.type === 'ready') console.log('Proxy ready on port 9000');
  });
}, []);

// 2. Warm upcoming videos before the user scrolls to them
useEffect(() => {
  const sessionId = precacheBatch(upcomingUrls, 3);
  return () => cancelPrecache(sessionId);
}, [upcomingUrls]);

// 3. Route playback through the proxy
const url = convertUrl('https://cdn.example.com/video.m3u8');
<Video source={{ uri: url }} />;

API

startServer(port?, maxCacheSize?, headOnlyCache?, onCacheEvent?)

Starts the local proxy server. Call once on app mount.

startServer(
  9000,            // port (default: 9000)
  1_073_741_824,   // max disk cache in bytes (default: 1 GB)
  false,           // headOnlyCache: only cache the first 3 segments (default: false)
  (event) => {
    // event.type: 'ready' | 'hit' | 'miss' | 'download' | 'error'
    // event.url:   origin URL (empty when not applicable)
    // event.bytes: bytes transferred (0 when not applicable)
    // event.error: error message (empty when not applicable)
    console.log(event);
  }
);

headOnlyCache is optimised for vertical video feeds — it caches just enough to ensure the first play is fast without filling disk on content the user might never finish watching.


convertUrl(url, isCacheable?)

Rewrites a remote HLS URL to route through the proxy. Returns the original URL unchanged on Android or when the server is not running.

const proxyUrl = convertUrl('https://cdn.example.com/video.m3u8');
// → "http://127.0.0.1:9000/proxy?url=https%3A%2F%2Fcdn..."

// Bypass the proxy for a specific video:
const directUrl = convertUrl(url, false);

Pass proxyUrl to your video player instead of the original URL.


clearCache()

Deletes all cached files from disk.

await clearCache();

precache(url, segmentCount?)

Downloads the manifest and first N segments of a stream to disk before the user presses play. Subsequent playback will be instant cache hits.

// Cache the first 5 segments (≈ first 30s at 6s/segment)
await precache('https://cdn.example.com/video.m3u8', 5);

// Cache the entire stream:
await precache('https://cdn.example.com/video.m3u8', 0);

precacheBatch(urls, segmentCount?)

Concurrently precaches multiple streams. Returns a session ID for cancellation.

const sessionId = precacheBatch(
  ['https://cdn.example.com/v1.m3u8', 'https://cdn.example.com/v2.m3u8'],
  3 // segments per stream (default: 3)
);

// Cancel all in-flight downloads (e.g. user navigates away):
cancelPrecache(sessionId);

cancelPrecache(sessionId)

Cancels all in-flight downloads for a session returned by precacheBatch.

cancelPrecache(sessionId);

getVariants(url)

Fetches an HLS master playlist and returns all variant renditions sorted by bandwidth (lowest → highest). Useful for picking which quality to precache.

const variants = await getVariants('https://cdn.example.com/master.m3u8');
// [
//   { url, bandwidth: 365811,  resolution: '270x480',  codecs: '...', frameRate: 30 },
//   { url, bandwidth: 613626,  resolution: '480x854',  ... },
//   { url, bandwidth: 1096138, resolution: '720x1280', ... },
// ]

// Precache only the lowest quality:
await precache(variants[0]!.url, 5);

Returns [] if the URL is a media playlist (no #EXT-X-STREAM-INF) or if the fetch fails.


Cache behaviour

| Detail | Value | |--------|-------| | Storage location | ~/Library/Caches/HLSVideoCache/ | | Cache key | SHA-256 of URL (+ byte range for fMP4 segments) | | Eviction | LRU — oldest files pruned on each write until under maxCacheSize | | Manifest rewriting | EXT-X-MAP, EXT-X-MEDIA, EXT-X-PART, EXT-X-PRELOAD-HINT URIs all rewritten to proxy URLs | | Range requests | Supported — fMP4 byte-range requests cached per range, with fallback slice from full cached file |


License

MIT