Skip to main content

Configuration

Global Config

nametypedefaultdescription
updateFrequencyMSnumber1000How often to update the download progress
maxParallelDownloadsnumber5How many files to download in parallel

To update global config, you can use setConfig function.

import {
setConfig,
Config,
getConfig,
} from "@TheWidlarzGroup/react-native-video-stream-downloader";

setConfig({ updateFrequencyMS: 1000, maxParallelDownloads: 5 });

const config: Config = getConfig();

Download Config

nametypedefaultdescription
includeAllTracksbooleanfalseInclude all (audio and text) tracks from stream in the download
tracksobjectundefinedExplicitly select track IDs to include (see Track Selection)
expiresAtnumber0Date when the download will expire. Once download is expired, it will be deleted from the device.
drmobjectundefinedDRM configuration for protected content (see DRM Config)
metadataobjectundefinedCustom metadata to store with the download (see Metadata)
import { DownloadOptions } from "@TheWidlarzGroup/react-native-video-stream-downloader";

const downloadOptions: DownloadOptions = {
includeAllTracks: true, // or use `tracks` for precise selection
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30), // 30 days
};

// download stream with download options
const downloadStatus = await downloadStream(
"https://example.com/stream.m3u8",
downloadOptions
);

Track Selection

To precisely control which tracks are downloaded, pass tracks with arrays of track IDs obtained from getAvailableTracks(url).

import {
getAvailableTracks,
downloadStream,
} from "@TheWidlarzGroup/react-native-video-stream-downloader";

const tracks = await getAvailableTracks("https://example.com/manifest.m3u8");
const selectedVideo = tracks.video?.find((v) => v.height === 720);

await downloadStream("https://example.com/manifest.m3u8", {
tracks: {
video: selectedVideo ? [selectedVideo.id] : [],
audio: tracks.audio?.map((a) => a.id),
text: tracks.text?.map((t) => t.id),
},
});

Metadata

The metadata field allows you to store custom data with your download. You can add any key-value pairs, and they will be preserved and returned in the DownloadedAsset object.

Reserved Keys

Some metadata keys are used by the plugin:

  • title: Used to name the downloaded file on the device

Example Metadata Usage

const downloadOptions: DownloadOptions = {
metadata: {
title: "My Video Title", // Used by plugin for file naming
category: "movies",
genre: "action",
year: 2024,
rating: 4.5,
tags: ["action", "adventure"],
customData: {
userId: "12345",
playlistId: "playlist_1",
isFavorite: true,
},
},
};

const downloadStatus = await downloadStream(
"https://example.com/video.m3u8",
downloadOptions
);

Accessing Metadata in Downloaded Assets

import { getDownloadedAssets } from "@TheWidlarzGroup/react-native-video-stream-downloader";

const assets = getDownloadedAssets();
const asset = assets[0];

console.log(asset.metadata?.title); // "My Video Title"
console.log(asset.metadata?.category); // "movies"
console.log(asset.metadata?.customData?.userId); // "12345"

Metadata Type

The metadata field uses the Metadata type which allows any string key with any value:

interface Metadata {
title?: string; // Used by plugin for file naming
[key: string]: unknown; // Any other key-value pairs
}

DRM Config

When downloading DRM-protected content, you need to provide DRM configuration. You can either use licenseServer for automatic license acquisition or getLicense for custom license handling (iOS only).

drm?: {
/**
* The license server URL.
* @Platform Android - Widevine License Server URL
* @Platform iOS - FairPlay License Server URL
* @Note Either licenseServer or getLicense must be provided
*/
licenseServer?: string;

/**
* Optional URL to the DRM certificate.
* @Platform iOS - *required* FairPlay Certificate URL
* @Platform Android - not required for Widevine
*/
certificateUrl?: string;

/**
* Additional headers to include in the DRM request.
*/
headers?: { [key: string]: string };

/**
* Custom license acquisition function (iOS only).
* Instead of using licenseServer, you can manually acquire the license in JavaScript.
* @Platform iOS - FairPlay only
*/
getLicense?: (
spcString: string,
contentId: string,
licenseUrl: string,
loadedLicenseUrl: string
) => Promise<string> | string;
}

Example DRM Configuration

import { Platform } from "react-native";

const drmConfig = {
licenseServer:
Platform.OS === "ios"
? "https://your-fairplay-license-server.com/license"
: "https://your-widevine-license-server.com/license",
certificateUrl:
Platform.OS === "ios"
? "https://your-fairplay-certificate.com/certificate"
: undefined,
headers: {
"x-drm-usertoken": "your-drm-token",
},
};

const downloadOptions: DownloadOptions = {
drm: drmConfig,
};

const downloadStatus = await downloadStream(
"https://example.com/drm-video.m3u8",
downloadOptions
);

Custom License Acquisition (iOS Only)

Instead of using licenseServer, you can manually acquire the license using the getLicense function:

import { Platform } from "react-native";

const drmConfig = {
certificateUrl: "https://your-fairplay-certificate.com/certificate",
getLicense: (spcString, contentId, licenseUrl, loadedLicenseUrl) => {
const base64spc = Base64.encode(spcString);
const formData = new FormData();
formData.append("spc", base64spc);

return fetch(`https://license.pallycon.com/ri/licenseManager.do`, {
method: "POST",
headers: {
"pallycon-customdata-v2": "your-custom-header",
"Content-Type": "application/x-www-form-urlencoded",
},
body: formData,
})
.then((response) => response.text())
.then((response) => response)
.catch((error) => console.error("Error", error));
},
};

const downloadOptions: DownloadOptions = {
drm: drmConfig,
};

const downloadStatus = await downloadStream(
"https://example.com/drm-video.m3u8",
downloadOptions
);

getLicense Parameters

The getLicense function receives the following parameters:

  • spcString: The SPC (Server Playback Context) used for DRM validation
  • contentId: The content ID from the DRM object or loadingRequest.request.url?.host
  • licenseUrl: The URL passed in the DRM object
  • loadedLicenseUrl: The URL retrieved from loadingRequest.request.URL.absoluteString, starting with skd:// or clearkey://

You should return a Base64-encoded CKC response, either directly or as a Promise.