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

zerorate-player

v1.3.5

Published

Custom ZeroRate HLS media player SDK with quality switching and live stream support. Specificially designed for FreePass Merchants.

Readme

ZeroratePlayer Web SDK

[BEFORE YOU INSTALL: IMPORTANT NOTICE]: This SDK is customly built to be use by merchants on the freepass.africa platform.

ZeroratePlayer Demo

A robust web HLS video player SDK with built-in quality switching, live stream support, and automatic browser policy handling.

Features ✨

  • 📺 HLS & MP4 video playback
  • ⚡ Adaptive bitrate streaming
  • 🔴 Live stream support with DVR
  • 🛡️ Automatic browser policy handling
  • 🎨 Customizable UI components
  • 📱 Mobile-first design
  • 🔄 Dynamic source switching
  • 📊 Quality metrics monitoring

Installation 💻

npm install zerorate-player

Quick Start 🚀

HTML Implementation

ES Module (Recommended)

<div id="player-container"></div>

<script type="module">
  import ZeroratePlayer from "zerorate-player";
  import "zerorate-player/dist/zeroratePlayer.bundle.css";

  const player = new ZeroratePlayer({
    src: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
    type: "video",
    mediaType: "on-demand",
    autoplay: true,
    videoContainerId: "player-container",
    poster: "poster.jpg",
  });
</script>

Traditional Script Tag (UMD)

<!-- Dependencies -->
<link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.1.5/hls.min.js"></script>
<script src="https://cdn.plyr.io/3.7.8/plyr.js"></script>

<!-- ZeroratePlayer -->
<div id="player-container"></div>
<script src="path/to/zerorateplayer.min.js"></script>
<link rel="stylesheet" href="path/to/zeroratePlayer.bundle.css" />

<script>
  document.addEventListener("DOMContentLoaded", () => {
    const player = new ZeroRatePlayer({
      src: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
      videoContainerId: "player-container",
      mediaType: "on-demand",
      autoplay: true,
    });
  });
</script>

React/NextJs Implementation

import { useEffect, useRef } from "react";
import ZeroratePlayer from "zerorate-player";
import "zerorate-player/dist/zeroratePlayer.bundle.css";

export default function VideoPlayer() {
  const playerRef = (useRef < ZeroratePlayer) | (null > null);

  useEffect(() => {
    // Initialize after component mounts
    playerRef.current = new ZeroratePlayer({
      appId: "your-app-id",
      region: "ke-01",
      src: "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
      type: "video",
      mediaType: "on-demand",
      videoContainerId: "player-container",
      autoplay: true,
    });

    // Cleanup on unmount
    return () => {
      if (playerRef.current) {
        playerRef.current.destroy();
      }
    };
  }, []);

  return <div id="player-container" />;
}

Configuration ⚙️

Constructor Options

| Option | Type | Default | Description | | ------------------ | ------- | ------------------- | ------------------------------------------------------------- | | appId | string | Required | Application identifier for authentication | | region | string | Required | Service region code | | grantType | string | "web" | Authentication grant type | | subscriberId | string | "" | Unique subscriber identifier | | authUrl | string | "" | Endpoint to authenticate subscriber | | type | string | "video" | Media type ("video" or "audio") | | src | string | Required | HLS manifest URL | | autoplay | boolean | true | Auto-start playback | | mediaType | string | "on-demand" | "on-demand" or "live" stream type | | videoContainerId | string | "video-container" | DOM element ID for player container | | poster | string | "" | Preview image URL | | clickToPlay | boolean | false | Click overlay to start playback (auto-set based on mediaType) | | muted | boolean | true | Initial muted state |

Key points about configuration:

  • clickToPlay is automatically set to true for "on-demand" media type
  • mediaType affects available player controls
  • Authentication headers (appId, region, grantType, subcriberId) are automatically added to all HLS requests
  • Mobile devices get playsinline attribute automatically

Example with authentication:

const player = new ZeroratePlayer({
  appId: "your-app-id",
  region: "ke-01",
  subcriberId: "user-12345",
  src: "https://secure-stream.m3u8",
  mediaType: "live",
});

API Reference 📚

Available Events

| Event Name | Trigger Condition | Event Details | Fatal? | | -------------------- | ------------------------ | --------------------------------------------------------------------------------- | ------ | | zerorate-sdk-error | HLS network error occurs | { status: number, message: string, url: string, fatal: boolean, response: any } | Yes | | media-play | Playback starts/resumes | { currentTime: number, duration: number, isLive: boolean, timestamp: number } | No | | media-pause | Playback is paused | Same as media-play | No | | media-ended | Playback completes | Same as media-play | No | | volume-changed | Video quality is changed | newVolumne: number | No | | enter-fullscreen | Enters fullscreen mode | { fullscreen: true } | No | | exit-fullscreen | Exits fullscreen mode | { fullscreen: false } | No |

Key Notes:

  • media-ended event does not fire if autoplay is true
  • fatal in zerorate-sdk-error: When true, player cannot recover automatically
  • response in zerorate-sdk-error: Contains parsed server response (if available)
  • isLive in media events: Indicates if current stream is live content
  • All times are in seconds

Core Methods

// Start/resume playback
player.play();

// Pause playback
player.pause();

// Destroy player instance
player.destroy();

// Change video source
player.setSource("https://new-source.m3u8");

// Update poster image
player.setPoster("new-poster.jpg");

// Get available qualities
const qualities = player.getQualities();

// Change quality (360, 480, 720, 1080)
player.changeQuality(720);

// Toggle fullscreen
player.toggleFullscreen();

Event Handling

player.on("ready", () => {
  console.log("Player initialized");
});

player.on("play", () => {
  console.log("Playback started");
});

player.on("qualitychange", (newQuality) => {
  console.log("Quality changed to:", newQuality);
});

player.on("error", (error) => {
  console.error("Player error:", error);
});

// Traditional Script Tag
document
  .getElementById("player-container")
  .addEventListener("zerorate-sdk-error", (e) => {
    console.error("Stream Error:", e.detail);
    // e.detail contains: { status: number, message: string, url: string, fatal: boolean }
  });

// React/Next.js
useEffect(() => {
  const videoElement = containerRef.current?.querySelector("video");
  const handler = (e) => {
    // Handle error state
    setErrorState(e.detail);
  };

  videoElement?.addEventListener("zerorate-sdk-error", handler);
  return () => videoElement?.removeEventListener("zerorate-sdk-error", handler);
}, []);

Customization 🎨

CSS Variables

:root {
  --plyr-color-main: #6a0dad;
  --plyr-control-radius: 8px;
  --plyr-control-spacing: 10px;
  --plyr-font-family: "Inter", sans-serif;
}

Quality Selector UI

const qualitySelect = document.createElement("select");
qualitySelect.className = "quality-selector";

player.on("ready", () => {
  player.getQualities().forEach((quality) => {
    const option = document.createElement("option");
    option.value = quality;
    option.text = `${quality}p`;
    qualitySelect.appendChild(option);
  });

  qualitySelect.addEventListener("change", (e) => {
    player.changeQuality(Number(e.target.value));
  });

  document.querySelector(".plyr__controls").appendChild(qualitySelect);
});

Browser Support 🌐

| Browser | HLS | MP4 | Autoplay | Fullscreen | | ------- | --- | --- | -------- | ---------- | | Chrome | ✅ | ✅ | ✅ | ✅ | | Safari | ✅ | ✅ | ⚠️ | ✅ | | Firefox | ✅ | ✅ | ✅ | ✅ | | Edge | ✅ | ✅ | ✅ | ✅ | | Mobile | ✅ | ✅ | ⚠️ | ✅ |

Troubleshooting 🔧

Common Issues

Next.js Server-Side Rendering Error
Error: "ReferenceError: document is not defined"

Solution:

  1. Use dynamic import with SSR disabled:
// pages/index.js
import dynamic from "next/dynamic";

const VideoPlayer = dynamic(() => import("@/components/VideoPlayer"), {
  ssr: false,
});

export default function Home() {
  return <VideoPlayer />;
}
  1. Add browser checks in your component:
// components/VideoPlayer.js
"use client"; // Required for Next.js App Router

import { useEffect, useRef } from "react";
import ZeroratePlayer from "zerorate-player";

export default function VideoPlayer() {
  // ... component implementation ...
}

Why this happens:
Next.js attempts server-side rendering by default, but the player requires browser APIs like document. The SDK includes built-in browser environment checks, but you still need to:

  • Disable SSR for player components
  • Use React's useEffect for initialization
  • Ensure client-side only execution

Other Common Issues

"Container Not Found" Error

// ❌ Wrong: Initializing before DOM ready
new ZeroratePlayer({ videoContainerId: "container" });

// ✅ Correct: Initialize in DOMContentLoaded
document.addEventListener("DOMContentLoaded", () => {
  new ZeroratePlayer({ videoContainerId: "container" });
});

Autoplay Blocked

  • Add muted: true to constructor options
  • Initialize after user interaction:
document.addEventListener(
  "click",
  () => {
    new ZeroratePlayer({
      /* options */
    });
  },
  { once: true }
);

Missing Styles

// Add these imports to your main JS file
import "zerorate-player/dist/zeroratePlayer.bundle.css";

Common Error Handling

Handling Errors

// UMD Implementation
document
  .getElementById("player-container")
  .addEventListener("zerorate-sdk-error", (e) => {
    console.error("Stream Error:", e.detail);
    alert(`Stream Error ${e.detail.status}: ${e.detail.message}`);
  });

// React Implementation
useEffect(() => {
  const containerRef = (useRef < HTMLDivElement) | (null > null);
  const videoElement = containerRef.current?.querySelector("video");

  const errorHandler = (e: any) => {
    if (e.detail.status === 403) {
      alert("Stream Error " + e.detail.status + " " + e.detail.message);
    }
  };

  containerRef.current?.addEventListener("zerorate-sdk-error", errorHandler);

  return () =>
    videoElement?.removeEventListener("zerorate-sdk-error", errorHandler);
}, [refreshAuth]);

Contributing 🤝

  1. Fork the repository
  2. Create feature branch: git checkout -b feature/new-component
  3. Commit changes: git commit -m 'Add new feature'
  4. Push to branch: git push origin feature/new-component
  5. Submit pull request

License 📄

MIT License © 2023 Zerorate Team. See LICENSE for full text.

Event Handling

// Traditional HTML
const container = document.getElementById("player-container");

container.addEventListener("media-play", (e) => {
  console.log("Playback started at", e.detail.currentTime);
});

container.addEventListener("media-pause", (e) => {
  console.log("Paused at", e.detail.currentTime);
});

container.addEventListener("media-ended", () => {
  console.log("Playback completed");
});

// React/Next.js
useEffect(() => {
  const container = containerRef.current;

  const playHandler = (e) => {
    analytics.track("play", { time: e.detail.currentTime });
  };

  container?.addEventListener("media-play", playHandler);
  container?.addEventListener("media-pause", handlePause);
  container?.addEventListener("media-ended", handleEnd);

  return () => {
    container?.removeEventListener("media-play", playHandler);
    container?.removeEventListener("media-pause", handlePause);
    container?.removeEventListener("media-ended", handleEnd);
  };
}, []);