Downloads HLS Playlist file and TS chunks. You can use it for content pre-fetching from CDN to Edge Server for your end viewers. A high-performance, tree-shaken HLS (HTTP Live Streaming) downloader engine. Built with modern ESM architecture, providing 100% type safety and zero-waste bundling.
NPM • Documentation • GitHub
⚠️ This package is native ESM and no longer provides a CommonJS export. If your project uses CommonJS, you will have to convert to ESM. Please don't open issues for questions regarding CommonJS / ESM.
⚠️ HLSDownloader
v2.x.xis no longer maintained and we will not accept any backport requests.
Features
- Event Based: Event based API
- Modern ESM: Optimized for Node.js 20+ environments using native modules.
- TypeScript Native: Built with strong typing for mission-critical applications.
- Resilient Networking and Retryable: Built-in resilience that automatically retries with exponential backoff of failed segment requests to ensure download completion.
- Promise Based: Fully asynchronous API designed for seamless integration with
async/awaitand modern control flows. - Support for HTTP/2: Leverages multiplexing to download multiple segments over a single connection for reduced overhead.
- Overwrite Protection: Safeguards your local data by preventing accidental overwriting of existing files unless explicitly enabled.
- Support for Custom HTTP Headers: Allows injection of custom headers for handling authentication, user-agents, or session tokens.
- Concurrent Downloads: Maximizes bandwidth by fetching multiple HLS segments simultaneously through parallel HTTP connections.
- Proxy and NoProxy Support: Proxy support and No Proxy support (undici integration).
- Professional Docs: Integrated JSDoc-to-HTML pipeline using TypeDoc and the Fresh theme.
Installation
npm install hlsdownloader
Note: This library requires undici as a peer dependency for proxy support.
Examples
Example 1: Basic Download with Event Monitoring
This is the standard implementation for saving a remote HLS stream to a local directory.
import { HLSDownloader } from 'hlsdownloader';
async function downloadStream() {
const downloader = new HLSDownloader({
playlistURL: 'https://example.com/video/master.m3u8',
destination: './downloads/my-video',
overwrite: true,
concurrency: 5, // Process 5 segments simultaneously
retry: { limit: 3, delay: 1000 },
timeout: 15000,
});
downloader.on('start', ({ total }) => console.log(`start downloading assets...`));
// Listen to progress updates
downloader.on('progress', data => {
const percent = ((data.total / data.total) * 100).toFixed(2); // Simple logic for example
console.log(`[Progress] Downloaded: ${data.url}`);
});
// Handle errors for specific segments
downloader.on('error', err => {
console.error(`[Segment Error] Failed to fetch ${err.url}: ${err.message}`);
});
// Final summary
const summary = await downloader.startDownload();
console.log(`Finished! Total items: ${summary.total}. Errors: ${summary.errors.length}`);
}
downloadStream();
Example 2: "Dry-Run" / CDN Priming (No File Writing)
If the destination is omitted, the library fetches streams but doesn't write to disk. This is excellent for CDN Priming or validating manifest health.
import { HLSDownloader } from 'hlsdownloader';
async function primeCDN() {
const downloader = new HLSDownloader({
playlistURL: 'https://cdn.provider.com/live/stream.m3u8',
// destination is omitted -> results in memory-only stream fetch
concurrency: 10,
headers: {
Authorization: 'Bearer internal-token-123',
'X-Custom-Source': 'Prewarm-Service',
},
});
downloader.on('start', ({ total }) => console.log(`Priming ${total} assets...`));
const result = await downloader.startDownload();
if (result.errors.length === 0) {
console.log('CDN Cache successfully warmed.');
} else {
console.error('Priming failed for some chunks', result.errors);
}
}
primeCDN();
Example 3: Corporate Proxy & Advanced Networking
If you are using behind corporate proxy, pass the proxy and no proxy configuration as follows
import { HLSDownloader } from 'hlsdownloader';
const downloader = new HLSDownloader({
playlistURL: 'https://secure-stream.corp.internal/index.m3u8',
destination: '/mnt/storage/archive',
proxy: 'http://proxy.corporate.net:8080',
noProxy: '.internal.com,localhost', // Bypass proxy for internal domains
headers: {
Cookie: 'session_id=abc123',
'User-Agent': 'MediaArchiver/1.0',
},
});
downloader.on('start', ({ total }) => console.log(`Priming ${total} assets...`));
// Listen to progress updates
downloader.on('progress', data => {
const percent = ((data.total / data.total) * 100).toFixed(2); // Simple logic for example
console.log(`[Progress] Downloaded: ${data.url}`);
});
// Handle errors for specific segments
downloader.on('error', err => {
console.error(`[Segment Error] Failed to fetch ${err.url}: ${err.message}`);
});
const summary = await downloader.startDownload();
Example 4: Simple progress bar
This example demostrate a simple download progressbar. You can bring your own progress bar implementation
import { HLSDownloader } from 'hlsdownloader';
const downloader = new HLSDownloader({
playlistURL: 'https://stream.example.com/playlist/master.m3u8',
concurrency: 5,
retry: { limit: 3, delay: 1000 },
headers: { 'User-Agent': 'MyHeader' },
timeout: 15000,
});
downloader.on('start', ({ total }) => {
console.log(`Starting download of ${total} segments...`);
});
downloader.on('progress', ({ processed, total, url }) => {
const percentage = Math.round((processed / total) * 100);
const progressBar = '='.repeat(Math.floor(percentage / 5)).padEnd(20, ' ');
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
process.stdout.write(`[${progressBar}] ${percentage}% | Processing: ${processed}/${total}`);
});
downloader.on('end', () => {
process.stdout.write('\nDownload Complete!\n');
});
await downloader.startDownload();
API Documentation
The library is organized under the HLSDownloader module. For full interactive documentation, visit our Documentation site.
HLSDownloader (Class)
The main service orchestrator for fetching HLS content.
| Method | Returns | Description |
|---|---|---|
| startDownload() | Promise<DownloadSummary> | Begins parsing and fetching segments. |
DownloaderOptions (Interface)
| Option | Type | Default | Description |
|---|---|---|---|
| playlistURL | string | Required | The source .m3u8 URL. |
| destination | string | undefined | Local path to save files. Omit for "dry-run" mode. |
| concurrency | number | os.cpus().length | Simultaneous segment downloads. |
| overwrite | boolean | false | Overwrite existing files in the destination. |
| headers | object | {} | Custom headers to pass |
| timeout | number | 10000 | Network request timeout in ms. |
| retry | object | { limit: 1, delay: 500 } | Exponential backoff settings. |
| proxy | string | undefined | Corporate proxy URL. Also reads URLs for HTTP_PROXY, HTTPS_PROXY environment variables |
| noProxy | string | undefined | Corporate No Proxy Urls. Also reads urls from NO_PROXY environment vriable |
DownloaderEvents (Interface)
| Event Name | Description |
|---|---|
| start | emits when download started |
| progress | emits for each segement downloded |
| error | emits when a segement downlod error occurred |
| end | emits when download ended |
DownloadSummary (Interface)
| Property | Type | Description |
|---|---|---|
| total | number | Count of successfully saved segments. |
| message | string | User friendly message. |
| errors | DownloadError[] | Array of detailed failure objects. |
SegmentDownloadedData (Interface) - emits on progress events
| Property | Type | Description |
|---|---|---|
| url | string | Original segment URL as referenced in the HLS playlist (.m3u8). |
| path | string | Local file system path where the segment was saved. Empty if not provided. |
| processed | number | Total number of segments downloaded so far. |
| total | number | Total number of segments downloaded to download, including this one. |
SegmentDownloadErrorData (Interface) - emits on error events
| Property | Type | Description |
|---|---|---|
| url | string | Original segment URL that failed to download. |
| name | string | Error name or type (e.g., NetworkError, TimeoutError). |
| message | string | Human-readable error description. |
Development & Contributing
Contributions are welcome! This project enforces strict quality standards to maintain 100% coverage.
Prerequisites
Workflow
Fork & Clone: Get the repo locally.
Install:npm installTest:npm run test(Must pass without warnings)Lint:npm run lint(Must pass without warnings)Build:npm run build(Generates./distand bundled types)Docs:npm run docs(Generates TypeDoc HTML)Test with Coverage Report:npm run test:coverage(Must maintain 100% coverage)
Guidelines
- Follow the JSDoc hierarchy: Use
@module HLSDownloaderand@category Services/Types. - All new features must include unit tests.
- Maintain ESM compatibility (always use file extensions in imports).
Contributions, issues and feature requests are welcome!
Feel free to check issues page. You can also take a look at the contributing guide.
Show your support
Give a ⭐️ if this project helped you!. I will be grateful if you all help me to improve this package by giving your suggestions, feature request and pull requests. I am all ears!!
License
Copyright © 2026 Nur Rony.

