@elacity-js/media-player
v0.12.5
Published
Main entrypoint for player module
Readme
@elacity-js/media-player
DASH-MPEG media player with Web3 DRM support. Plays NFT-gated streams protected by the Chipotle (cenc:lit-aes-gcm-v3) and legacy (cenc:web3-drm-v1) license protocols.
Full documentation: https://elacitylabs.gitbook.io/docs/docs/media-player/summary
Installation
npm install @elacity-js/media-playerQuick start
import { MediaPlayer } from "@elacity-js/media-player";
// 1. One-time setup (call before creating any player instance)
await MediaPlayer.setup({
provider: window.ethereum,
session: {
expiresAt: Math.floor(Date.now() / 1000) + 24 * 3600, // 24 h
},
drmSystem: {
"cenc:lit-aes-gcm-v3": { priority: 0 },
"cenc:web3-drm-v1": { priority: 9 },
},
});
// 2. Create a player and attach it to a <video> element
const videoEl = document.getElementById("video");
const player = await MediaPlayer.create(
"0x0EBaC909D31EF0074495e752C0cF4EA49ba13C41", // NFT contract address
"96862553258370885849903076...", // NFT token ID
videoEl,
"https://ipfs.ela.city/ipfs/<CID>/stream.mpd",
);
player.addEventListener("statechanged", (e) => {
console.log(e.detail.prevState, "->", e.detail.state);
});MediaPlayer.setup(options)
Called once before any player is created. Initialises the WASM runtime, loads the Web3 crypto module, and configures global defaults.
| Option | Type | Description |
|---|---|---|
| provider | EIP-1193 | Wallet provider (window.ethereum, WalletConnect, etc.) |
| session | object | Session persistence config (see Session persistence) |
| drmSystem | object | Map of DRM variant → { priority, disabled }. Lower priority number = preferred. |
| "go.glueCode" | boolean | Load wasm_exec.js from the same origin. Set to true when serving the player locally. |
| remote | boolean | Fetch WASM assets from the CDN instead of the local bundle. |
| cryptoVersion | string | Pin a specific @elacity-js/crypto-protocol version. |
DRM variants
| Variant | Description |
|---|---|
| cenc:lit-aes-gcm-v3 | Current Chipotle protocol (recommended) |
| cenc:web3-drm-v1 | Legacy Go-based protocol |
| cenc:lit-drm-v1 | Deprecated Lit protocol |
MediaPlayer.create(tokenAddress, tokenId, videoElement, src, options?)
Creates and starts a player instance. Returns a promise that resolves once the player is initialised (not necessarily when playback starts — listen for statechanged).
| Parameter | Type | Description |
|---|---|---|
| tokenAddress | string | NFT contract address that gates the content |
| tokenId | string | NFT token ID |
| videoElement | HTMLVideoElement | <video> or <audio> element to render into |
| src | string | URL to the DASH manifest (.mpd) |
| options | object | See below |
options
| Option | Type | Description |
|---|---|---|
| fromts | number | Start playback at this timestamp (seconds) |
| logLevel | number | Internal log verbosity |
| thumbnail | string | Poster image URL shown before playback |
| handlebars | object | Metadata injected into the player UI (title, author, …) |
| drmSystem | object | Per-instance DRM priority override |
| onBeforePlay | async () => void | Async hook invoked before the player starts. Playback is held until the promise resolves. |
const player = await MediaPlayer.create(
tokenAddress,
tokenId,
document.getElementById("video"),
streamUrl,
{
fromts: 30,
logLevel: 46,
thumbnail: "/poster.png",
handlebars: { title: "My Film", author: "Studio" },
drmSystem: { "cenc:lit-aes-gcm-v3": { priority: 0 } },
onBeforePlay: async () => {
await showSplashScreen();
},
}
);Events
Listen with player.addEventListener(type, handler).
| Event | e.detail shape | Description |
|---|---|---|
| statechanged | { state, prevState } | Player state machine transition. States: idle, loading, loaded, playing, paused, ended, error. |
| display | metadata object | Fired when display/chapter metadata is updated |
player.addEventListener("statechanged", (e) => {
if (e.detail.state === "loaded") {
player.play({ fromts: 0 });
}
});Session persistence
When session.expiresAt is set, the player persists the session keypair and the wallet-signed delegation to the browser's Origin Private File System (OPFS). On subsequent page loads the delegation is reused — no MetaMask prompt — as long as:
- the session has not expired (
expiresAt) - the delegation is less than 1 hour old
await MediaPlayer.setup({
provider: window.ethereum,
session: {
expiresAt: Math.floor(Date.now() / 1000) + 30 * 24 * 3600, // 30 days
// signerAddress: "0x..." // optional: skip the eth_accounts call
},
});Without session.expiresAt the wallet will prompt for a signature on every page load.
Stopping and restarting
player.stop();
// Create a new instance to restart
const newPlayer = await MediaPlayer.create(...);Switching the wallet provider at runtime
import { setProvider } from "@elacity-js/media-player";
setProvider(window.ethereum, "0xYourAddress");HTML example
<video id="video" autoplay width="1280" height="720" crossorigin="anonymous"></video>
<script type="module">
import { MediaPlayer } from "@elacity-js/media-player";
await MediaPlayer.setup({
provider: window.ethereum,
session: {
expiresAt: Math.floor(Date.now() / 1000) + 24 * 3600,
},
drmSystem: {
"cenc:lit-aes-gcm-v3": { priority: 0 },
},
});
const player = await MediaPlayer.create(
"0x<contract>",
"<tokenId>",
document.getElementById("video"),
"https://ipfs.ela.city/ipfs/<CID>/stream.mpd",
);
player.addEventListener("statechanged", (e) =>
console.log(e.detail.prevState, "->", e.detail.state)
);
</script>