### listeners example Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Shows how to use the `listeners` method to get a copy of the array of listeners for a given event. The example registers a listener for 'connection' and then inspects the listeners array. ```javascript server.on('connection', (stream) => { console.log('someone connected!'); }); console.log(util.inspect(server.listeners('connection'))); // Prints: [ [Function] ] ``` -------------------------------- ### Install hlsdownloader with npm Source: https://nurrony.github.io/hlsdownloader Install the hlsdownloader package via npm. Requires undici as a peer dependency for proxy support. ```bash npm install hlsdownloader ``` -------------------------------- ### EventEmitter constructor example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Creates an EventEmitter instance. This is the setup for the subsequent example that demonstrates adding listeners. ```javascript import { EventEmitter } from 'node:events'; const myEE = new EventEmitter(); ``` -------------------------------- ### eventNames example Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Demonstrates the `eventNames()` method of EventEmitter, which returns an array of event names for which listeners are registered. The example registers listeners for 'foo', 'bar', and a symbol, then prints the array. ```javascript import { EventEmitter } from 'node:events'; const myEE = new EventEmitter(); myEE.on('foo', () => {}); myEE.on('bar', () => {}); const sym = Symbol('symbol'); myEE.on(sym, () => {}); console.log(myEE.eventNames()); // Prints: [ 'foo', 'bar', Symbol(symbol) ] ``` -------------------------------- ### EventEmitter rawListeners example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Shows how to use rawListeners to get the wrapper function created by once. The wrapper has a `listener` property containing the original listener, and calling it logs 'log once' without unbinding the event. ```js import { EventEmitter } from 'node:events'; const emitter = new EventEmitter(); emitter.once('log', () => console.log('log once')); // Returns a new Array with a function `onceWrapper` which has a property // `listener` which contains the original listener bound above const listeners = emitter.rawListeners('log'); const logFnWrapper = listeners[0]; // Logs "log once" to the console and does not unbind the `once` event ``` -------------------------------- ### Simple Progress Bar with HLSDownloader Source: https://nurrony.github.io/hlsdownloader Simple progress bar example. Demonstrates a custom progress bar implementation using the progress event's processed and total values. You can bring your own progress bar implementation. ```javascript 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(); ``` -------------------------------- ### captureRejectionSymbol example Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Shows how to use the `captureRejectionSymbol` method to handle promise rejections when `captureRejections` is enabled on an EventEmitter. The example defines a class extending EventEmitter and overrides the symbol method to log rejection details and call a destroy method. ```javascript import { EventEmitter, captureRejectionSymbol } from 'node:events'; class MyClass extends EventEmitter { constructor() { super({ captureRejections: true }); } [captureRejectionSymbol](err, event, ...args) { console.log('rejection happened for', event, 'with', err, ...args); this.destroy(err); } destroy(err) { // Tear the resource down here. } } ``` -------------------------------- ### Dry-Run / CDN Priming with HLSDownloader (No File Writing) Source: https://nurrony.github.io/hlsdownloader Dry-run / CDN priming example that omits the destination option, causing the library to fetch streams without writing to disk. Useful for CDN priming or validating manifest health. Includes custom headers for authentication and source identification. ```javascript 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(); ``` -------------------------------- ### Uint8Array interface start Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Begins the Uint8Array interface definition, including the BYTES_PER_ELEMENT, buffer, byteLength, and byteOffset properties. ```TypeScript interface Uint8Array { /** * The size in bytes of each element in the array. */ readonly BYTES_PER_ELEMENT: number; /** * The ArrayBuffer instance referenced by the array. */ readonly buffer: TArrayBuffer; /** * The length in bytes of the array. */ readonly byteLength: number; /** * The offset in bytes of the array. */ readonly byteOffset: number; } ``` -------------------------------- ### EventEmitter prependListener order example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Shows the order of listener invocation when using prependListener. The listener added with prependListener is called first, printing 'b' before 'a'. ```js myEE.on('foo', () => console.log('a')); myEE.prependListener('foo', () => console.log('b')); myEE.emit('foo'); // Prints: // b // a ``` -------------------------------- ### Basic Download with Event Monitoring using HLSDownloader Source: https://nurrony.github.io/hlsdownloader Standard implementation for saving a remote HLS stream to a local directory. Configures playlistURL, destination, overwrite, concurrency, retry, and timeout. Listens to start, progress, and error events, then logs a final summary with total items and error count. ```javascript 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(); ``` -------------------------------- ### EventEmitter prependListener example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Adds a listener to the beginning of the listeners array for the 'connection' event. The listener is called before any other listeners for that event. ```js server.prependListener('connection', (stream) => { console.log('someone connected!'); }); ``` -------------------------------- ### Corporate Proxy & Advanced Networking with HLSDownloader Source: https://nurrony.github.io/hlsdownloader Corporate proxy and advanced networking example. Passes proxy and noProxy configuration to bypass proxy for internal domains, and includes custom headers for authentication and user-agent. Suitable for environments behind a corporate proxy. ```javascript 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(); ``` -------------------------------- ### rawListeners() example Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Shows how `rawListeners()` returns an array of wrappers, including those created by `.once()`. The wrapper has a `listener` property that can be called to invoke the original listener without removing it, while calling the wrapper itself removes the listener. ```javascript import { EventEmitter } from 'node:events'; const emitter = new EventEmitter(); emitter.once('log', () => console.log('log once')); // Returns a new Array with a function `onceWrapper` which has a property // `listener` which contains the original listener bound above const listeners = emitter.rawListeners('log'); const logFnWrapper = listeners[0]; // Logs "log once" to the console and does not unbind the `once` event logFnWrapper.listener(); // Logs "log once" to the console and removes the listener logFnWrapper(); emitter.on('log', () => console.log('log persistently')); // Will return a new Array with a single function bound by `.on()` above const newListeners = emitter.rawListeners('log'); // Logs "log persistently" twice newListeners[0](); emitter.emit('log'); ``` -------------------------------- ### Uint8Array sort example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Shows the expected usage of the sort method on a Uint8Array, where the compare function returns a negative value if the first argument is less than the second, zero if equal, and a positive value otherwise. The example sorts an array of numbers in ascending order. ```ts [11,2,22,1].sort((a, b) => a - b) ``` -------------------------------- ### EventEmitterAsyncResource Usage Example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Demonstrates how to use EventEmitterAsyncResource to ensure event listeners run within a specific async context, compared to a standard EventEmitter. ```javascript import { EventEmitterAsyncResource, EventEmitter } from 'node:events'; import { notStrictEqual, strictEqual } from 'node:assert'; import { executionAsyncId, triggerAsyncId } from 'node:async_hooks'; // Async tracking tooling will identify this as 'Q'. const ee1 = new EventEmitterAsyncResource({ name: 'Q' }); // 'foo' listeners will run in the EventEmitters async context. ee1.on('foo', () => { strictEqual(executionAsyncId(), ee1.asyncId); strictEqual(triggerAsyncId(), ee1.triggerAsyncId); }); const ee2 = new EventEmitter(); // 'foo' listeners on ordinary EventEmitters that do not track async // context, however, run in the same async context as the emit(). ee2.on('foo', () => { notStrictEqual(executionAsyncId(), ee2.asyncId); notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId); }); Promise.resolve().then(() => { ee1.emit('foo'); ee2.emit('foo'); }); ``` -------------------------------- ### Int8Array sort method signature with example Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Defines the sort method for Int8Array. The compareFn determines order; if omitted, elements are sorted in ascending order. Includes an example usage in the documentation comment. ```TypeScript sort(compareFn?: (a: number, b: number) => number): this; ``` ```TypeScript [11,2,22,1].sort((a, b) => a - b) ``` -------------------------------- ### isValidPlaylist Source: https://nurrony.github.io/hlsdownloader/module/hlsutils/hlsutils Checks if the content starts with the mandatory HLS #EXTM3U tag. ```APIDOC ## `isValidPlaylist(content: string): boolean` ### Description Checks if the content starts with the mandatory HLS #EXTM3U tag. ### Method Static method ### Signature `isValidPlaylist(content: string): boolean` ### Parameters - `content` (string) - Required - The raw manifest string. ### Returns - `boolean` - `true` if it contains the HLS header. ``` -------------------------------- ### getTargetPath(url: string): Promise Source: https://nurrony.github.io/hlsdownloader/module/services-filewriter/default Get the target directory path for a given URL. ```APIDOC ## Method: getTargetPath(url: string): Promise ### Description Get the target directory path for a given URL. ### Parameters - **url** (string) - Required - The URL to transform. ### Returns - **Promise** - The localized file path. ``` -------------------------------- ### Error.captureStackTrace() with constructorOpt Source: https://nurrony.github.io/hlsdownloader/module/exceptions-unsupportedprotocol/default Shows how to use the optional `constructorOpt` argument to omit frames above a given function from the generated stack trace. The example hides implementation details of error generation by temporarily setting `Error.stackTraceLimit` to 0. ```javascript function a() { b(); } function b() { c(); } function c() { // Create an error without stack trace to avoid calculating the stack trace twice. const { stackTraceLimit } = Error; Error.stackTraceLimit = 0; const error = new Error(); Error.stackTraceLimit = stackTraceLimit; // Capture the stack trace above function b Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace throw error; } a(); ``` -------------------------------- ### HLSDownloader.startDownload() Source: https://nurrony.github.io/hlsdownloader Begins parsing and fetching HLS segments. Returns a Promise that resolves to a DownloadSummary object containing the download results. ```APIDOC ## HLSDownloader.startDownload() ### Description Begins parsing and fetching segments from the HLS playlist. Returns a Promise that resolves to a DownloadSummary object. ### Method startDownload() ### Returns Promise ### Parameters None ### Response #### Success Response (Promise) - **total** (number) - Count of successfully saved segments. - **message** (string) - User friendly message. - **errors** (DownloadError[]) - Array of detailed failure objects. #### Response Example { "total": 10, "message": "Download completed", "errors": [] } ``` -------------------------------- ### prepareDirectory(url: string): Promise Source: https://nurrony.github.io/hlsdownloader/module/services-filewriter/default Ensures the destination directory exists for a specific URL. ```APIDOC ## Method: prepareDirectory(url: string): Promise ### Description Ensures the destination directory exists for a specific URL. ### Parameters - **url** (string) - Required - The URL of the file to be saved. ### Returns - **Promise** - The prepared absolute target path. ``` -------------------------------- ### getMaxListeners and setMaxListeners for EventEmitter and EventTarget Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Use this snippet to get and set the maximum number of listeners for both `EventEmitter` and `EventTarget`. For `EventTarget`s, this is the only way to get the max listeners; exceeding the max triggers a warning. ```js import { getMaxListeners, setMaxListeners, EventEmitter } from 'node:events'; { const ee = new EventEmitter(); console.log(getMaxListeners(ee)); // 10 setMaxListeners(11, ee); console.log(getMaxListeners(ee)); // 11 } { const et = new EventTarget(); console.log(getMaxListeners(et)); // 10 setMaxListeners(11, et); console.log(getMaxListeners(et)); // 11 } ``` -------------------------------- ### Instantiate HttpClient with custom options Source: https://nurrony.github.io/hlsdownloader/module/services-httpclient/default Creates an HttpClient instance with custom options for HLS streaming. Configure timeout, retry policy, proxy, noProxy bypass, and custom headers. The retry strategy uses exponential backoff for transient 5xx/429 errors. ```javascript const client = new HttpClient({ timeout: 5000, retry: { limit: 3, delay: 1000 }, proxy: 'http://proxy.corp.com:8080', noProxy: 'localhost,127.0.0.1,.internal.com', headers: { 'x-custom-header': 'my-custom-header' } }); ``` -------------------------------- ### removeListener() during emit example Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Demonstrates that `removeListener()` called during an emit does not remove the listener from the current emit, but it will be removed for subsequent emits. The example shows that callbackB is still called on the first emit even though callbackA removes it, and is not called on the second emit. ```javascript import { EventEmitter } from 'node:events'; class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); const callbackA = () => { console.log('A'); myEmitter.removeListener('event', callbackB); }; const callbackB = () => { console.log('B'); }; myEmitter.on('event', callbackA); myEmitter.on('event', callbackB); // callbackA removes listener callbackB but it will still be called. // Internal listener array at time of emit [callbackA, callbackB] myEmitter.emit('event'); // Prints: // A // B // callbackB is now removed. // Internal listener array [callbackA] myEmitter.emit('event'); // Prints: // A ``` -------------------------------- ### new default(customOptions: HttpClientOptions): default Source: https://nurrony.github.io/hlsdownloader/module/services-httpclient/default Creates a new HttpClient instance with the provided configuration options. ```APIDOC ## new default(customOptions: HttpClientOptions): default ### Description Creates a new HttpClient instance with the provided configuration options. ### Method Constructor ### Parameters - **customOptions** (HttpClientOptions) - Optional - Configuration object. Defaults to `{}`. ### Returns - `default` - The newly created HttpClient instance. ### Request Example ```typescript const client = new HttpClient({ timeout: 5000, retry: { limit: 3, delay: 1000 }, proxy: 'http://proxy.corp.com:8080', noProxy: 'localhost,127.0.0.1,.internal.com', headers: { 'x-custom-header': 'my-custom-header' } }); ``` ``` -------------------------------- ### Using once with AbortSignal Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Demonstrates how to use an AbortSignal to cancel waiting for an event when using the once utility. ```javascript import { EventEmitter, once } from 'node:events'; const ee = new EventEmitter(); const ac = new AbortController(); async function foo(emitter, event, signal) { try { await once(emitter, event, { signal }); console.log('event emitted!'); } catch (error) { if (error.name === 'AbortError') { console.error('Waiting for the event was canceled!'); } else { console.error('There was an error', error.message); } } } foo(ee, 'foo', ac.signal); ac.abort(); // Prints: Waiting for the event was canceled! ``` -------------------------------- ### removeListener() with duplicate listeners example Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Shows that when the same function is added multiple times for an event, `removeListener()` removes the most recently added instance. In this example, the `once('ping')` listener is removed, so the first `emit('ping')` triggers the remaining `on('ping')` listener, and the second emit does nothing. ```javascript import { EventEmitter } from 'node:events'; const ee = new EventEmitter(); function pong() { console.log('pong'); } ee.on('ping', pong); ee.once('ping', pong); ee.removeListener('ping', pong); ee.emit('ping'); ee.emit('ping'); ``` -------------------------------- ### getEventListeners for EventEmitter and EventTarget Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Use this snippet to retrieve the listeners of an `EventEmitter` or an `EventTarget`. For `EventTarget`s, this is the only way to get the event listeners, which is useful for debugging. ```js import { getEventListeners, EventEmitter } from 'node:events'; { const ee = new EventEmitter(); const listener = () => console.log('Events are fun'); ee.on('foo', listener); console.log(getEventListeners(ee, 'foo')); // [ [Function: listener] ] } { const et = new EventTarget(); const listener = () => console.log('Events are fun'); et.addEventListener('foo', listener); console.log(getEventListeners(et, 'foo')); // [ [Function: listener] ] } ``` -------------------------------- ### create(o: object | null, properties: PropertyDescriptorMap & ThisType): any Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Creates an object with a specified prototype and optional additional properties. ```APIDOC ## method ### Description Creates an object that has the specified prototype, and that optionally contains specified properties. ### Signature ```typescript create(o: object | null, properties: PropertyDescriptorMap & ThisType): any ``` ### Parameters - **o** (object | null) - Object to use as a prototype. May be null. - **properties** (PropertyDescriptorMap & ThisType) - JavaScript object that contains one or more property descriptors. ### Response - `any` - The newly created object. ``` -------------------------------- ### getOwnPropertyDescriptor(o: any, p: PropertyKey): PropertyDescriptor | undefined Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Gets the own property descriptor of a specified object. An own property descriptor is defined directly on the object, not inherited from its prototype. ```APIDOC ## method ### Description Gets the own property descriptor of the specified object. ### Signature ```typescript getOwnPropertyDescriptor(o: any, p: PropertyKey): PropertyDescriptor | undefined ``` ### Parameters - **o** (any) - Object that contains the property. - **p** (PropertyKey) - Name of the property. ### Response - `PropertyDescriptor | undefined` - The property descriptor, or undefined if the property is not found. ``` -------------------------------- ### new default(options: DownloaderOptions): default Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Creates a new instance of the default class, which is the main orchestrator for HLS stream acquisition. The options parameter configures the downloader. ```APIDOC ## new default(options: DownloaderOptions): default ### Description Creates a new instance of the default class, which is the main orchestrator for HLS stream acquisition. The options parameter configures the downloader. ### Method Constructor ### Parameters - `options` (DownloaderOptions) - Required - Configuration object. ### Returns `default` ### Hierarchy - `EventEmitter` - `default` ``` -------------------------------- ### Int8Array slice method signature Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Defines the slice method for Int8Array, returning a section of the array. Parameters start and end are optional, with end exclusive. ```TypeScript slice(start?: number, end?: number): Int8Array; ``` -------------------------------- ### Uint8Array copyWithin method signature Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Defines the copyWithin method for Uint8Array, copying a section of the array to the same array starting at target. Negative indices are treated as length+index. ```TypeScript copyWithin(target: number, start: number, end?: number): this; ``` -------------------------------- ### new default(destination: string, overwrite: boolean): default Source: https://nurrony.github.io/hlsdownloader/module/services-filewriter/default Creates a new FileWriter instance with a destination directory and overwrite flag. ```APIDOC ## Constructor: new default(destination: string, overwrite: boolean): default ### Description Creates a new FileWriter instance with the specified destination directory and overwrite behavior. ### Parameters - **destination** (string) - Required - The root directory for downloads. - **overwrite** (boolean, default: "false") - Required - Whether to overwrite existing files. ### Returns - **default** - The new FileWriter instance. ``` -------------------------------- ### new default(message?: string): default Source: https://nurrony.github.io/hlsdownloader/module/exceptions-invalidplaylist/default Creates a new InvalidPlaylist exception instance with an optional error message. ```APIDOC ## new default(message?: string): default ### Description Creates a new InvalidPlaylist exception instance. This exception is thrown when an HLS playlist is invalid. ### Constructor `new default(message?: string): default` ### Parameters - `message` (string, optional) - Optional error message. ### Returns - `default` - The new InvalidPlaylist exception instance. ### Hierarchy - `Error` - `default` ``` -------------------------------- ### DownloaderOptions (Interface) Source: https://nurrony.github.io/hlsdownloader Configuration options for the HLSDownloader. These options control the source playlist URL, destination path, concurrency, overwrite behavior, headers, timeout, retry settings, and proxy configuration. ```APIDOC ## DownloaderOptions (Interface) ### Description Options for configuring the HLSDownloader instance. ### Properties - **playlistURL** (string) - Required - The source .m3u8 URL. - **destination** (string) - Optional - Local path to save files. Omit for "dry-run" mode. - **concurrency** (number) - Optional - Simultaneous segment downloads. Default: os.cpus().length. - **overwrite** (boolean) - Optional - Overwrite existing files in the destination. Default: false. - **headers** (object) - Optional - Custom headers to pass. Default: {}. - **timeout** (number) - Optional - Network request timeout in ms. Default: 10000. - **retry** (object) - Optional - Exponential backoff settings. Default: { limit: 1, delay: 500 }. - **proxy** (string) - Optional - Corporate proxy URL. Also reads URLs for `HTTP_PROXY`, `HTTPS_PROXY` environment variables. - **noProxy** (string) - Optional - Corporate No Proxy Urls. Also reads urls from `NO_PROXY` environment variable. ``` -------------------------------- ### create(o: object | null): any Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Creates an object with a specified prototype or with null prototype. ```APIDOC ## method ### Description Creates an object that has the specified prototype or that has null prototype. ### Signature ```typescript create(o: object | null): any ``` ### Parameters - **o** (object | null) - Object to use as a prototype. May be null. ### Response - `any` - The newly created object. ``` -------------------------------- ### prependOnceListener() - One-time listener at beginning Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Adds a one-time listener to the beginning of the listeners array for the 'connection' event. The listener is removed after the first invocation. Returns a reference to the EventEmitter for chaining. ```javascript server.prependOnceListener('connection', (stream) => { console.log('Ah, we have our first user!'); }); ``` -------------------------------- ### fetchText(url: string): Promise Source: https://nurrony.github.io/hlsdownloader/module/services-httpclient/default Fetches a playlist and validates its HLS structure. ```APIDOC ## fetchText(url: string): Promise ### Description Fetches a playlist and validates its HLS structure. ### Method async ### Parameters - **url** (string) - Required - The M3U8 playlist URL. ### Returns - `Promise` - The raw string content of the playlist. ### Throws - If the response body is not a valid HLS manifest. ``` -------------------------------- ### on() and prependListener() - Listener order Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Demonstrates the order of listener invocation: by default listeners are called in the order added, but prependListener adds the listener to the beginning. The output shows 'b' before 'a'. ```javascript import { EventEmitter } from 'node:events'; const myEE = new EventEmitter(); myEE.on('foo', () => console.log('a')); myEE.prependListener('foo', () => console.log('b')); myEE.emit('foo'); // Prints: // b // a ``` -------------------------------- ### once() and prependOnceListener() - One-time listener order Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Shows the behavior of once() and prependOnceListener(): both are one-time listeners, but prependOnceListener adds the listener to the beginning of the array. The output shows 'b' before 'a'. ```javascript import { EventEmitter } from 'node:events'; const myEE = new EventEmitter(); myEE.once('foo', () => console.log('a')); myEE.prependOnceListener('foo', () => console.log('b')); myEE.emit('foo'); // Prints: // b // a ``` -------------------------------- ### EventEmitter listener management with on, once, removeListener, and emit Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Shows how to attach, once-attach, and remove a listener for the 'ping' event, then emit the event twice. The second emit will not trigger the listener because it was removed before the first emit. ```javascript function pong() { console.log('pong'); } const ee = new EventEmitter(); ee.on('ping', pong); ee.once('ping', pong); ee.removeListener('ping', pong); ee.emit('ping'); ee.emit('ping'); ``` -------------------------------- ### FileService class for file system operations Source: https://nurrony.github.io/hlsdownloader/source/src/services/filewriter-ts Defines the FileService class for managing file system operations in an HLS downloader. It handles directory creation, path resolution, overwrite checks, and stream persistence. Use it to prepare directories, check write permissions, and save web streams to disk. ```typescript import { constants, createWriteStream } from 'node:fs'; import * as fsPromises from 'node:fs/promises'; import path from 'node:path'; import { Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; import { HlsUtils } from '../HLSUtils.js'; /** * Manages file system operations including directory creation, path resolution, and stream persistence. * @category Services * @author Nur Rony */ class FileService { private destination: string; private overwrite: boolean; /** * Constructor of FileService * @param destination - The root directory for downloads. * @param overwrite - Whether to overwrite existing files. */ constructor(destination: string, overwrite: boolean = false) { this.destination = destination; this.overwrite = overwrite; } /** * Get the target directory path * @param url - The URL to transform. * @returns The localized file path. */ async getTargetPath(url: string): Promise { const { pathname } = HlsUtils.parseUrl(url); return path.join(this.destination, HlsUtils.stripFirstSlash(pathname)); } /** * Ensures the destination directory exists for a specific URL. * @param url - The URL of the file to be saved. * @returns The prepared absolute target path. */ async prepareDirectory(url: string): Promise { const targetPath = await this.getTargetPath(url); const destDirectory = path.dirname(targetPath); await fsPromises.mkdir(destDirectory, { recursive: true }); return targetPath; } /** * Verifies if writing is permitted based on the overwrite flag and existing files. * @param url - The URL to check against the file system. * @returns Returns true if writing should proceed. */ async canWrite(url: string): Promise { try { const targetPath = await this.getTargetPath(url); await fsPromises.access(targetPath, constants.F_OK); return this.overwrite; } catch (error: any) { if (error.code === 'ENOENT') return true; throw error; } } /** * Pipes a web-standard ReadableStream to the local file system using stream/promises. * @param webStream - The source stream from the network. * @param filePath - The destination path. * @returns Resolves when the stream finishes writing. */ async saveStream(webStream: ReadableStream, filePath: string): Promise { const readStream = Readable.fromWeb(webStream as any); const writeStream = createWriteStream(filePath); try { await pipeline(readStream, writeStream); } catch (err) { // Cleanup the file if the download/write fails await fsPromises.unlink(filePath).catch(() => {}); throw err; } } } export default FileService; ``` -------------------------------- ### canWrite(url: string): Promise Source: https://nurrony.github.io/hlsdownloader/module/services-filewriter/default Verifies if writing is permitted based on the overwrite flag and existing files. ```APIDOC ## Method: canWrite(url: string): Promise ### Description Verifies if writing is permitted based on the overwrite flag and existing files. ### Parameters - **url** (string) - Required - The URL to check against the file system. ### Returns - **Promise** - Returns true if writing should proceed. ``` -------------------------------- ### keys(o: object): string[] Source: https://nurrony.github.io/hlsdownloader/source/node-modules/typescript/lib/lib-es5-d-ts Returns the names of enumerable string properties and methods of an object. ```APIDOC ## method ### Description Returns the names of the enumerable string properties and methods of an object. ### Signature ```typescript keys(o: object): string[] ``` ### Parameters - **`o`** (object) - Object that contains the properties and methods. This can be an object that you created or an existing DOM object. ### Response - `string[]` - An array of enumerable property and method names. ``` -------------------------------- ### fetchText method Source: https://nurrony.github.io/hlsdownloader/source/src/services/httpclient-ts Fetches a playlist and validates its HLS structure. Throws InvalidPlayList if the response body is not a valid HLS manifest. ```typescript /** * Fetches a playlist and validates its HLS structure. * @param url {string} - The M3U8 playlist URL * @returns The raw string content of the playlist * @throws {InvalidPlayList} If the response body is not a valid HLS manifest */ async fetchText(url: string): Promise { const response = await this.requestWithRetry(url); const body = await response.text(); if (!HlsUtils.isValidPlaylist(body)) throw new InvalidPlayList('Invalid playlist'); return body; } ``` -------------------------------- ### DownloadSummary (Interface) Source: https://nurrony.github.io/hlsdownloader Represents the result of a download operation, including the count of successfully saved segments, a user-friendly message, and detailed error information. ```APIDOC ## DownloadSummary (Interface) ### Description Represents the result of a download operation. ### Properties - **total** (number) - Count of successfully saved segments. - **message** (string) - User friendly message. - **errors** (DownloadError[]) - Array of detailed failure objects. ``` -------------------------------- ### setPrimaryOrigin(url: string): void Source: https://nurrony.github.io/hlsdownloader/module/services-httpclient/default Sets the primary origin based on the initial playlist URL. ```APIDOC ## setPrimaryOrigin(url: string): void ### Description Sets the primary origin based on the initial playlist URL. ### Method void ### Parameters - **url** (string) - Required - URL to set primary origin from. ### Returns - `void` ``` -------------------------------- ### HttpClient.ts - Full TypeScript Implementation Source: https://nurrony.github.io/hlsdownloader/source/src/services/httpclient-ts The complete implementation of the HttpClient class. The constructor supports configuration options for timeout, retry, proxy, noProxy, and custom headers. It initializes a ProxyAgent when a proxy URL is provided, and normalizes headers to lowercase. The setPrimaryOrigin method extracts the origin from a URL, and getRequestHeaders removes sensitive headers when the target is a different origin. ```TypeScript import { ProxyAgent } from 'undici'; import { HlsUtils } from '../HLSUtils.js'; import InvalidPlayList from './../exceptions/InvalidPlaylist.js'; /** * Configuration for the internal HTTP Client. * @category Types */ interface HttpClientOptions { /** Request timeout in milliseconds (Default: 10000) */ timeout?: number; /** Retry strategy for transient network failures */ retry?: { /** Maximum number of retry attempts */ limit: number; /** Base delay in milliseconds for exponential backoff */ delay: number; }; /** Corporate proxy URL (e.g., http://proxy.corp.com:8080) */ proxy?: string; /** List of hostnames that should bypass the proxy */ noProxy?: string[]; /** * Custom HTTP headers to be sent with every request. * Useful for Auth tokens, Cookies, or custom User-Agents. */ headers?: Record; } /** * * A resilient HTTP Client specifically designed for HLS streaming workloads. * Features include: * - Native fetch implementation (Node 20+) * - Exponential backoff retry strategy for transient 5xx/429 errors * - Corporate Proxy support via ProxyAgent * - Domain-based Proxy bypass (NO_PROXY) * - Automatic AbortController management for request timeouts * @example * const client = new HttpClient({ * timeout: 5000, * retry: { limit: 3, delay: 1000 }, * proxy: 'http://proxy.corp.com:8080', * noProxy: 'localhost,127.0.0.1,.internal.com', * headers: { 'x-custom-header': 'my-custom-header' } * }); */ class HttpClient { /** Initialized request options (headers, etc.) */ private options: RequestInit; private primaryOrigin: string | null = null; /** List of sensitive headers */ private sensitiveHeaders: string[] = ['authorization', 'cookie', 'x-auth-token']; /** Max time in milliseconds before a request is aborted */ private timeout: number; /** Retry configuration for transient failures */ private retryOptions: { limit: number; delay: number }; /** The proxy agent used for network requests, if configured */ private dispatcher?: ProxyAgent; /** List of hostnames that should bypass the corporate proxy */ private noProxy: string[] = []; /** * Creates a new HttpClient instance. * @param customOptions - Configuration object * @param customOptions.timeout - Request timeout in ms (Default: 10000) * @param customOptions.retry - Retry strategy settings * @param customOptions.proxy - Corporate proxy URL * @param customOptions.noProxy - Array of domains to bypass proxy */ constructor(customOptions: HttpClientOptions = {}) { this.options = { method: 'GET', headers: { 'User-Agent': 'HLSDownloader' } }; // Normalize headers to lowercase for safer matching if (customOptions.headers) { const normalized: Record = {}; for (const [key, value] of Object.entries(customOptions.headers)) { normalized[key.toLowerCase()] = value; } this.options.headers = { 'User-Agent': 'HLSDownloader', ...this.options.headers, ...normalized }; } this.timeout = customOptions.timeout ?? 5000; this.retryOptions = customOptions.retry ?? { limit: 1, delay: 500 }; // Parse bypass list (e.g., 'localhost,127.0.0.1,.internal.com') const noProxyEnv = process.env.NO_PROXY || process.env.no_proxy || ''; this.noProxy = customOptions.noProxy ?? noProxyEnv .split(',') .map(s => s.trim()) .filter(Boolean); const proxyUrl = customOptions.proxy || process.env.HTTPS_PROXY || process.env.HTTP_PROXY; if (proxyUrl) { this.dispatcher = new ProxyAgent({ uri: proxyUrl }); } } /** * Sets the primary origin based on the initial playlist URL. * @param url {string} url to set primary origin from */ public setPrimaryOrigin(url: string): void { try { this.primaryOrigin = new URL(url).origin; } catch { this.primaryOrigin = null; } } /** * Get Request headers * @param targetUrl {string} target url to get the request for * @returns request headers */ private getRequestHeaders(targetUrl: string): Record { const currentHeaders = { ...(this.options.headers as Record) }; try { const targetOrigin = new URL(targetUrl).origin; // If the target is NOT the primary origin, strip sensitive headers if (this.primaryOrigin && targetOrigin !== this.primaryOrigin) { this.sensitiveHeaders.forEach(header => { delete currentHeaders[header]; }); } } catch { // If URL is invalid/relative, we keep headers as it's likely the same host } return currentHeaders; } } ``` -------------------------------- ### handleRetry method Source: https://nurrony.github.io/hlsdownloader/source/src/services/httpclient-ts Calculates exponential backoff and waits before retrying. Uses HlsUtils.sleep to delay the retry attempt. ```typescript /** * Calculates exponential backoff and waits before retrying. * @param url {string} - url to handle retry for * @param attempt {number} - attempt to calculate backoff * @returns Fetch API Response * @internal */ private async handleRetry(url: string, attempt: number): Promise { const backoff = this.retryOptions.delay * Math.pow(2, attempt); await HlsUtils.sleep(backoff); return this.requestWithRetry(url, attempt + 1); } ``` -------------------------------- ### saveStream(webStream: ReadableStream, filePath: string): Promise Source: https://nurrony.github.io/hlsdownloader/module/services-filewriter/default Pipes a web-standard ReadableStream to the local file system using stream/promises. ```APIDOC ## Method: saveStream(webStream: ReadableStream, filePath: string): Promise ### Description Pipes a web-standard ReadableStream to the local file system using stream/promises. ### Parameters - **webStream** (ReadableStream) - Required - The source stream from the network. - **filePath** (string) - Required - The destination path. ### Returns - **Promise** - Resolves when the stream finishes writing. ``` -------------------------------- ### prependListener Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Adds the `listener` function to the beginning of the listeners array for the event named `eventName`. No checks are made to see if the `listener` has already been added. Multiple calls passing the same combination of `eventName` and `listener` will result in the `listener` being added, and called, multiple times. Returns a reference to the `EventEmitter`, so that calls can be chained. ```APIDOC ## prependListener ### Description Adds the `listener` function to the beginning of the listeners array for the event named `eventName`. No checks are made to see if the `listener` has already been added. Multiple calls passing the same combination of `eventName` and `listener` will result in the `listener` being added, and called, multiple times. Returns a reference to the `EventEmitter`, so that calls can be chained. ### Method prependListener ### Parameters - **eventName** (string | symbol) - Required - The name of the event. - **listener** (Function) - Required - The listener function to add. ### Returns - **EventEmitter** - Returns a reference to the `EventEmitter`, so calls can be chained. ### Example ```js myEmitter.prependListener('event', () => { console.log('prepend'); }); ``` ``` -------------------------------- ### listeners(eventName: string | symbol): ((args: any[]) => void)[] Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Inherited from EventEmitter. Returns a copy of the array of listeners for the event named eventName. ```APIDOC ## listeners(eventName: string | symbol): ((args: any[]) => void)[] ### Description Inherited from EventEmitter. Returns a copy of the array of listeners for the event named eventName. ### Method listeners ### Type Parameters - `E` extends `string | symbol` ### Parameters - `eventName` (string | symbol) - Required - The event name. ### Returns - `((args: any[]) => void)[]` - Array of listener functions. ``` -------------------------------- ### addAbortListener with using keyword Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Use this snippet to safely listen to an abort signal without risking resource leaks. The `using` keyword automatically removes the listener when the scope exits, preventing `stopImmediatePropagation` from blocking the listener. ```js import { addAbortListener } from 'node:events'; function example(signal) { signal.addEventListener('abort', (e) => e.stopImmediatePropagation()); // addAbortListener() returns a disposable, so the `using` keyword ensures // the abort listener is automatically removed when this scope exits. using _ = addAbortListener(signal, (e) => { // Do something when signal is aborted. }); } ``` -------------------------------- ### addListener(eventName: string | symbol, listener: (args: any[]) => void): this Source: https://nurrony.github.io/hlsdownloader/module/downloader/default Inherited from EventEmitter. Alias for emitter.on(eventName, listener). Adds a listener for the specified event. ```APIDOC ## addListener(eventName: string | symbol, listener: (args: any[]) => void): this ### Description Inherited from EventEmitter. Alias for emitter.on(eventName, listener). Adds a listener for the specified event. ### Method addListener ### Type Parameters - `E` extends `string | symbol` ### Parameters - `eventName` (string | symbol) - Required - The event name. - `listener` ((args: any[]) => void) - Required - The event handler function. ### Returns - `this` ``` -------------------------------- ### prependOnceListener Source: https://nurrony.github.io/hlsdownloader/source/node-modules/types/node/events-d-ts Adds a one-time `listener` function for the event named `eventName` to the beginning of the listeners array. The next time `eventName` is triggered, this listener is removed and then invoked. Returns a reference to the `EventEmitter`, so that calls can be chained. ```APIDOC ## prependOnceListener ### Description Adds a one-time `listener` function for the event named `eventName` to the beginning of the listeners array. The next time `eventName` is triggered, this listener is removed and then invoked. Returns a reference to the `EventEmitter`, so that calls can be chained. ### Method prependOnceListener ### Parameters - **eventName** (string | symbol) - Required - The name of the event. - **listener** (Function) - Required - The listener function to add. ### Returns - **EventEmitter** - Returns a reference to the `EventEmitter`, so calls can be chained. ### Example ```js myEmitter.prependOnceListener('event', () => { console.log('prepend once'); }); ``` ```