bccm-video-player
v3.1.0
Published
HLS video player built on Video.js v10. Custom skin with audio / subtitle / quality / playback-rate pickers, live mode, NPAW analytics, and Chromecast.
Keywords
Readme
bccm-video-player
HLS video player built on Video.js v10. Custom skin with audio / subtitle / quality / playback-rate pickers, live mode, NPAW analytics, and Chromecast.
Install
pnpm add bccm-video-playerimport { createPlayer } from "bccm-video-player"
import "bccm-video-player/css"Quick start
<div id="player"></div>const player = await createPlayer("player", {
src: { src: "https://example.com/stream.m3u8" },
autoplay: false,
languagePreferenceDefaults: { audio: "eng", subtitles: "eng" },
})Options
createPlayer(containerId, options)| Option | Type | Notes |
| -------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| src.src | string | HLS / DASH manifest URL. |
| autoplay | boolean | |
| live | boolean | Switches to the live skin: LIVE badge, no seek buttons / time displays / thumbnails. |
| language | string | UI language for tooltips, pickers, and error messages. Built-in: "en", "no", "nl", "de" (default "en"). Unsupported codes fall back to "en". Swap at runtime with player.setLanguage(...). See Adding a language. |
| languagePreferenceDefaults.audio | string | 3-letter code, e.g. "eng". |
| languagePreferenceDefaults.subtitles | string | 3-letter code, or omit to disable. |
| subtitles | Track[] | External <track> descriptors (src, srclang, label, kind). |
| videojs.poster | string | Poster image URL. |
| videojs.crossOrigin | string | Defaults to "anonymous". |
| npaw | NPAWOptions | See Analytics. |
| onProgress | (currentTime, duration, player) => void | Fires on timeupdate. |
Player API
interface Player {
element: HTMLElement // <video-player> root
mediaEl: HTMLVideoElement // underlying <hls-video> (use for play/pause/volume/events)
getAudioLanguages(): TrackOption[]
getSubtitleLanguages(): TrackOption[]
setAudioTrackToLanguage(language?: string): void
setSubtitleTrackToLanguage(language?: string): void
setVideoQuality(height: number): void // 0 / negative re-enables Auto (ABR)
setLanguage(lang: string): void // swaps UI strings live; unsupported codes fall back to "en"
dispose(): void
}For low-level control (play / pause / volume / events), use player.mediaEl:
player.mediaEl.play()
player.mediaEl.volume = 0.5
player.mediaEl.addEventListener("play", () => {
/* ... */
})Theming
The skin reads CSS variables from the player container.
| Variable | Default | Effect |
| ---------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| --bccm-color-primary | oklch(1 0 0) (white) | Text / icon color across the whole skin. Cascades via currentColor to slider fill, focus ring, hover backgrounds, live-badge accent. |
| --bccm-color-accent | oklch(1 0 0) (white) | Background of primary-action buttons (e.g. the OK on the error dialog). Foreground text auto-flips black/white based on lightness. |
Set on the container:
<div id="player" style="--bccm-color-accent: #6EB0E6"></div>Adding a language
Create
src/video-player/i18n/locales/<code>.ts:import type { LocaleTable } from "../strings" const de: LocaleTable = { seekBackward: "{seconds} Sekunden zurück", seekForward: "{seconds} Sekunden vor", // ... TypeScript will fail until every key in LocaleTable is filled in. } export default deRegister it in
src/video-player/i18n/strings.ts— three lines: animport, an entry inSUPPORTED_LANGS, and an entry inSTRINGS.Record<Lang, LocaleTable>makes it a compile error if any of the three is missing.
en.ts is the canonical reference for which keys exist and how interpolation placeholders (e.g. {seconds}, {height}, {label}) are spelled.
Keyboard
In picker menus (audio / subtitles / quality / playback rate):
↑ / ↓— roam wrappingHome / End— first / last itemEnter / Space— selectTab / Shift+Tab— leave the popover, continue along the control barEsc— close, restore focus to trigger
Analytics (NPAW)
createPlayer("player", {
src: { src: "..." },
npaw: {
enabled: true,
accountCode: "...",
appName: "web",
tracking: {
isLive: false,
userId: "...",
sessionId: "...",
metadata: {
contentId: "E385",
title: "...",
showTitle: "...",
},
},
},
})Adds ~800 KB to the bundle. Omit npaw (or set enabled: false) to skip.
BTV factory (internal)
For BCC apps that resolve streams from the BTV API:
import { PlayerFactory } from "bccm-video-player"
const factory = new PlayerFactory({
tokenFactory: null,
endpoint: "https://api.brunstad.tv/query",
})
await factory.create("player", { episodeId: "865" })Development
pnpm i
pnpm dev # demo at http://localhost:5173
pnpm test # vitest
pnpm build # tsc + vite + d.tsPublishing
Bump version in package.json, then:
pnpm publish