npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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-player
import { 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

  1. 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 de
  2. Register it in src/video-player/i18n/strings.ts — three lines: an import, an entry in SUPPORTED_LANGS, and an entry in STRINGS. 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 wrapping
  • Home / End — first / last item
  • Enter / Space — select
  • Tab / Shift+Tab — leave the popover, continue along the control bar
  • Esc — 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.ts

Publishing

Bump version in package.json, then:

pnpm publish