FAQ
Do I need to install the core if I’m just using the video player?
No. nomercy-video-player and nomercy-music-player both re-export everything from nomercy-player-core.
Install only the package you need.
The core is a separate install only if you are writing plugins that work against the raw core interface without a library package.
Can I use both the video player and music player on the same page?
Yes. Each player instance is isolated by its id. The video player and music player share no global state beyond the internal instance registry.
const videoPlayer = nmplayer('video').setup({ ... });
const musicPlayer = nmMPlayer('music').setup({ ... });
They do not interfere. You can have both playing at the same time (subject to browser audio policy). If you need one to pause when the other plays, wire that coordination yourself in a consumer plugin or in your app code.
How do I write my own subtitle renderer?
Replace the built-in SubtitleOverlayPlugin (VTT text rendering) with your own plugin that implements the same interface.
Register your plugin with static readonly replaces = 'subtitle-overlay'.
For ASS/SSA subtitles with full typesetting, add OctopusPlugin, which loads @nomercy-entertainment/nomercy-subtitle-octopus dynamically and handles its own rendering.
Do not combine OctopusPlugin and a custom renderer for the same subtitle track.
See Video, Subtitle Overlay for the full API.
Does the player handle 401 / 403 differently?
Yes. The auth pipeline treats them differently by design:
- 401, token expired.
refreshOnUnauthenticatedis called once, the new token is applied, and the request is retried. If refresh fails, the request errors withcore:auth/refresh-failed(theauth:failedevent itself fires fromplayer.refreshAuth()). - 403, access denied. The error propagates immediately.
refreshOnUnauthenticatedis never called for 403s. The server has denied access even with valid credentials.
Never lump 401 and 403 in the same catch block. A 403 may signal an entitlement problem that no amount of token refreshing will fix.
How do I add auto-advance (play next track when the current one ends)?
On the video player it is built in and on by default — set autoAdvance: false in setup() to turn it off. On the music player, add AutoAdvancePlugin:
import { AutoAdvancePlugin } from '@nomercy-entertainment/nomercy-music-player/plugins';
player.addPlugin(AutoAdvancePlugin);
The music plugin listens to the ended event and calls player.next().
When crossfade is enabled, it triggers crossfadeTo() instead.
How do I pause all players at once?
There is no global play/pause. You control each instance by id:
const main = nmplayer('main');
const pip = nmplayer('pip');
main.pause();
pip.pause();
If you need coordinated playback across multiple players (group listening), use GroupListeningPlugin, planned for v2.1.
Can I use the player with TypeScript strict mode?
Yes. The packages ship full TypeScript types.
All public methods are typed.
The generic parameter T extends VideoPlaylistItem or T extends MusicPlaylistItem threads your playlist item type through current(), queue(), beforeLoad, and current events, no casts required.
How do I render the player without the built-in UI?
Do not add DesktopUiPlugin. The player itself renders nothing, all chrome is opt-in through plugins.
Build your own controls using the event API:
player.on('play', () => updatePlayButton('pause'));
player.on('pause', () => updatePlayButton('play'));
player.on('time', ({ time }) => updateSeekBar(time, player.duration()));
How do I restrict HLS quality to avoid high bitrate on slow networks?
OctopusPlugin is not related to quality.
Quality selection lives in the video player’s HLS adapter.
Set a maximum level via the config:
player.setup({
defaultQuality: 'auto', // ABR is active
});
To hard-cap to a specific quality level index at runtime:
player.quality(2); // lock to level index 2
player.quality('auto'); // back to auto (ABR)
HDR-aware ABR is automatic, so on SDR displays, the player filters out HDR levels from the ABR selection pool. No configuration needed. See Video, HLS for the full quality API.
How do I listen to events from a plugin I did not write?
Use the string form with the auto-namespaced event name on player.on():
player.on('plugin:equalizer:band:changed', ({ band }) => {
console.log(`Band at ${band.frequency} Hz set to ${band.gain} dB`);
});
Plugin events are always namespaced as plugin:<id>:<event>.
The class-form this.on(PluginClass, 'event', fn) is only available inside a Plugin subclass body, it is a protected method and does not exist on the external player.on() surface.
Is the player compatible with Capacitor, Tauri, or Electron?
Yes, via the platform adapter system. Override individual sub-ports without rebuilding the entire bundle:
import { browserPlatform } from '@nomercy-entertainment/nomercy-player-core';
player.setup({
platform: {
...browserPlatform,
wakeLock: myCapacitorWakeLock,
network: myCapacitorNetworkMonitor,
},
});
The player’s core logic only calls the interfaces, it does not import Capacitor or Tauri directly.
Where do I report bugs?
- nomercy-video-player: github.com/NoMercy-Entertainment/nomercy-video-player/issues
- nomercy-music-player: github.com/NoMercy-Entertainment/nomercy-music-player/issues
- nomercy-player-core: github.com/NoMercy-Entertainment/nomercy-player-core/issues