Quick start
import { EvePlayer } from '@admmedia/eveplayer';
import '@admmedia/eveplayer/style.css';
const container = document.getElementById('player-container')!;
const player = new EvePlayer(container, {
widescreen: true,
autoplay: false,
muted: false,
});
player.setSource({
sources: [{ src: 'https://example.com/video.mp4', type: 'video/mp4' }],
poster: 'https://example.com/poster.jpg',
});
player.on('play', () => console.log('Playing'));
player.on('timeupdate', ({ currentTime }) => console.log('Time:', currentTime));
player.on('error', (err) => console.error('Error:', err.category, err.code, err.message));
// When done (e.g. navigating away)
player.dispose();
widescreen: true gives the player a fixed 16:9 frame. Leave it out to let
the box follow the video's own aspect ratio: Player sizing
explains both.
What you get
- One class,
EvePlayer, wrapping a single Video.js 8Player. Consumers never touch Video.js directly (the public surface is the class plus the types re-exported from the package entry point). - A typed event bus:
on/off/onceoverPlayerEventMap. - HLS / DASH / CMAF via
@videojs/http-streamingwith a custom "Auto" quality selector.
Loading streams
// HLS
player.setSource({
sources: [{ src: 'https://example.com/master.m3u8', type: 'application/x-mpegURL' }],
});
// MPEG-DASH
player.setSource({
sources: [{ src: 'https://example.com/manifest.mpd', type: 'application/dash+xml' }],
});
// Poster-only / no video yet
player.setSource({ sources: [], poster: 'https://example.com/poster.jpg' });
setSource() is safe to call at any time; an empty sources array skips
.src() entirely instead of raising a "source not supported" error.
Swapping to a different source
Reloading a variant of what is already playing is just another setSource().
When the new source is a genuinely different stream, though (a pre-live
placeholder handing over to the live stream, say, or a switch from progressive
MP4 to HLS), call reset() first:
player.reset();
player.setSource({
sources: [{ src: 'https://example.com/live.m3u8', type: 'application/x-mpegURL' }],
});
Safari keeps a single playback engine across an in-place swap, and its
native-to-VHS hand-off can race the segment loaders, leaving the player frozen
on the last frame of the previous source. reset() clears the engine back to a
sourceless state (without disposing the player) so the next setSource() loads
from scratch. The viewer's volume and mute state are carried across.
MPEG-DASH on Safari (macOS): known to be unreliable, see Format support before relying on DASH there. Prefer an HLS source for Safari when both are available.
See Text tracks & captions for side-loading WebVTT subtitle or chapter files that are not embedded in the manifest.
Autoplay and muting
Browsers only allow unattended playback when the video starts muted, so the
usual pairing is autoplay: true with muted: true plus an unmute control of
your own:
const player = new EvePlayer(container, { autoplay: true, muted: true });
// Your own "tap for sound" button
unmuteButton.addEventListener('click', () => {
player.muted = false;
});
muted is the initial state, not a standing instruction. Once the player is
unmuted (through your control, through the control bar's own mute toggle, or by
setting player.muted = false), it stays unmuted: loading another source,
swapping a pre-live placeholder for the live stream, or otherwise rebuilding the
underlying playback engine never silently restores the muted option the player
was constructed with. The volume is preserved the same way as long as engine
rebuilds go through reset().
Listen for volumechange to keep your own UI in step with either route:
player.on('volumechange', ({ volume, muted }) => updateUnmuteButton(muted, volume));
Cleanup
Always call dispose() when the player leaves the page. It tears down Video.js,
removes the DOM nodes it created, and clears every listener. It is safe to call
more than once.