Skip to content

Player Core Quick Start

For library authors and plugin developers working directly against nomercy-player-core, the base library beneath the video and music players. If you are building a video or music player, use the Video Quick Start or Music Quick Start instead, as both library packages include everything from the core.

Install

Code
npm install @nomercy-entertainment/nomercy-player-core@beta

Writing a core-level plugin

A core-level plugin works with any player built on the player core, whether video, music, or a custom library you write. Type the P generic broadly:

TypeScript
import { Plugin } from '@nomercy-entertainment/nomercy-player-core';
import type { IPlayer, BaseEventMap } from '@nomercy-entertainment/nomercy-player-core';

interface AnalyticsOptions {
endpoint: string;
sampleRateMs?: number;
}

interface AnalyticsEvents {
'session:reported': { duration: number; rebufferRatio: number };
}

export class AnalyticsPlugin extends Plugin<
IPlayer<BaseEventMap>,
AnalyticsOptions,
AnalyticsEvents
> {
static readonly id = 'nomercy:analytics';
static readonly version = '1.0.0';
static readonly description = 'Reports session metrics to an analytics endpoint';

use(): void {
this.on('dispose', () => this.report());
}

dispose(): void {}

private async report(): Promise<void> {
const metrics = this.player.metrics();
await this.fetch(this.opts.endpoint, {
method: 'POST',
responseType: 'json',
body: JSON.stringify({
duration: metrics.sessionDurationMs,
rebufferRatio: metrics.rebufferRatio,
}),
});
this.emit('session:reported', {
duration: metrics.sessionDurationMs,
rebufferRatio: metrics.rebufferRatio,
});
}
}

The AnalyticsPlugin above is typed against plain IPlayer<BaseEventMap> and calls this.player.metrics() directly — no cast, no extra constraint needed. Plugins that don’t read the active item omit & WithCurrentItem<...>; metrics(), getPlugin(), and transport methods are on IPlayer directly.

Register it on any player:

TypeScript
import { nmplayer } from '@nomercy-entertainment/nomercy-video-player';
import { nmMPlayer } from '@nomercy-entertainment/nomercy-music-player';

nmplayer('video')
.addPlugin(AnalyticsPlugin, {
endpoint: '/api/v1/analytics',
})
.setup({ ... });

nmMPlayer('music')
.addPlugin(AnalyticsPlugin, {
endpoint: '/api/v1/analytics',
})
.setup({ ... });

Accessing adapter ports

Core adapters are available from the player core’s subpath exports:

TypeScript
import {
LocalStorageBackend,
MemoryStorageBackend,
DEFAULT_RETRY_POLICY,
browserPlatform,
} from '@nomercy-entertainment/nomercy-player-core';
import type { IRetryPolicy } from '@nomercy-entertainment/nomercy-player-core';

See Core: Adapters for the full catalog.

Testing core-level plugins

TypeScript
import { describePlugin } from '@nomercy-entertainment/nomercy-player-core/testing';

describePlugin(AnalyticsPlugin, ({ player, plugin }) => {
test('emits session:reported', () => {
const events: unknown[] = [];
player.on('plugin:nomercy:analytics:session:reported', (event) => events.push(event));

player.emit('ended', undefined);

expect(events).toHaveLength(1);
});
});

describePlugin provides a fresh player with the plugin registered, auto-disposes in afterEach, and automatically asserts no listener leak after each test. No separate leak test is needed.

What success looks like

A core-level plugin registers without errors, use() is called during setup(), and the automatic leak harness in describePlugin passes after dispose. The plugin emits its typed events, and player.on('plugin:nomercy:analytics:session:reported', ...) receives them (the event name is plugin:<id>:<event>, and this plugin’s id is nomercy:analytics).