@nikelroot/video-player
v0.4.1
Published
Standalone React video player with HLS support.
Readme
@nikelroot/video-player
Standalone React video player with HLS support, retry/recovery behavior, fullscreen, seek controls, and overridable error messages.
Install
npm install @nikelroot/video-playerGitLab CI and automatic npm releases
The repository is hosted at https://gitlab.nikelroot.ru/home/nvideoplayer.
Every push to the default branch runs validation and publishes a new public
version of @nikelroot/video-player to npmjs.com. Merge requests and other
branches only run validation. Tag pipelines are disabled.
The release chooses the highest stable version from package.json and npm,
then increases its patch number (for example, 0.3.2 → 0.3.3) inside the
CI workspace, builds the package, and publishes it directly to npm. The source
repository is not modified: CI does not push commits or create Git tags.
The published version is visible on npmjs.com; package.json in Git remains
the starting version. Releases are serialized to avoid version collisions.
The npm package records the source commit as gitHead; retrying a job for an
already-published commit skips publication. If publishing failed before the
version reached npm, retry the failed publish job to calculate the next
available version and publish again.
One-time setup in GitLab:
- Configure a Docker-compatible runner capable of using
node:24-bookworm. - Protect the default branch (usually
main). - In Settings → CI/CD → Variables, add this Masked and Protected
variable with variable expansion disabled:
NPM_TOKEN: an npm granular access token with read/write permission for@nikelroot/video-playerand Bypass two-factor authentication enabled. The package publishing settings must permit token publishing. Renew the token before its expiration.
- Push the repository and CI configuration to GitLab. Do not add secrets to Git.
Only NPM_TOKEN is required. No GitLab push token or job-token push permission
is needed.
This self-hosted GitLab uses token authentication because npm trusted publishing currently supports GitLab.com shared runners only. See the npm CI token guide and trusted publishing documentation.
Peer dependencies:
npm install react react-dom styled-componentsUsage
import { useRef } from 'react';
import VideoPlayer from '@nikelroot/video-player';
export function Example() {
const videoRef = useRef<HTMLVideoElement | null>(null);
return (
<VideoPlayer
videoSrc="https://example.com/stream.m3u8"
videoRef={videoRef}
active={true}
live={false}
autoPlay={false}
onTimeChange={(time) => console.log(time)}
/>
);
}Only videoSrc is required. controlsVariant defaults to "none"; set it to "full", "fullscreen-only", or "tiny" to render built-in controls.
When active is true, pressing F toggles fullscreen.
Multiple MP4 players
Use active when rendering several video players on the same page and only one of them should be ready for playback.
<VideoPlayer
videoSrc="https://cdn.example.com/video-a.mp4"
sourceType="native"
active={isSelected}
preload="metadata"
/>This solves a switching problem where previous MP4 players can keep large browser media requests open after another player starts. In Chrome DevTools this often appears as new video requests staying in a long Pending state, even when CDN, disk, and network throughput are healthy.
For native MP4 sources:
active={true}allows playback and fullscreen.active={false}releases playback loading so inactive players do not keep competing media requests open.preload="metadata"still loads metadata for inactive native videos, so duration and basic media information can be available without starting playback loading.
By default exclusivePlayback is enabled. When a player starts playback, the previous active native MP4 player is paused and its media source is released, freeing the browser media request before the next video loads.
Public CDN requests use hlsCredentials="same-origin" and crossOrigin="anonymous" by default. For streams that require cross-origin cookies, explicitly set hlsCredentials="include" and crossOrigin="use-credentials" and configure credentialed CORS on the CDN:
<VideoPlayer
videoSrc="https://cdn.example.com/stream.m3u8"
hlsCredentials="include"
crossOrigin="use-credentials"
/>If you use hlsCredentials="include" or crossOrigin="use-credentials", the CDN must allow credentialed CORS and should not forward Cookie into the cache key for public media.
For hlsCredentials="omit", the player selects the hls.js fetch loader when the browser supports it and no custom loader or XHR setup is configured. XHR cannot suppress same-origin cookies; use a fetch-based loader when omitting all credentials is required in other configurations. Custom loaders are responsible for their own credential handling. Native HLS requests are controlled by crossOrigin and the browser.
HLS buffer targets default to 30–60 seconds ahead for VOD and 20–30 seconds for live, with 15 and 10 seconds of back buffer respectively. Segment boundaries, browser buffering and decoding also affect memory usage; these values are not hard memory limits. Override them using hlsConfig, vodHlsConfig or liveHlsConfig.
HLS downloads stop when playback is paused and resume when playback continues. Set active={false} to release HLS resources for an inactive player. Live seek controls use the browser's current seekable window; as the playlist advances, expired portions are no longer seekable.
Playback error data includes a compact diagnostic summary instead of loader objects and segment payloads.
Build before publishing:
npm run buildSeparate audio and video recordings
Provide the HLS master as videoSrc, the video media playlist as videoOnlySrc,
and available audio intervals in seconds on the same recording timeline:
<VideoPlayer
videoSrc="https://cdn.example.com/record/master.m3u8"
videoOnlySrc="https://cdn.example.com/record/video.m3u8"
audioRanges={[{ start: 0, end: 120 }, { start: 135, end: 240 }]}
onAudioFallbackChange={(videoOnly) => console.log({ videoOnly })}
/>Missing audio switches playback to the video playlist while retaining position,
playing or paused state, speed, volume, and mute. Playback returns to the master
when the current position has at least four seconds of available audio. Audio
request failures impose a 15-second retry cooldown. Update audioRanges as a
live recording grows; callbacks and metadata updates do not reload the source.
The player displays a nonblocking status while playing without audio.
Both media playlists and their fragment timestamps must use the same timeline.
