PlexPlayer

Installation

Install the package via npm or yarn:

Terminalbash
npm install @frameset/plex-player

or with yarn:

yarn add @frameset/plex-player

Quick Start

Import the component and styles, then use it in your React application:

App.tsxtsx
import { PlexVideoPlayer } from '@frameset/plex-player';
import '@frameset/plex-player/styles.css';

function App() {
  return (
    <PlexVideoPlayer
      src="https://example.com/video.mp4"
      poster="https://example.com/poster.jpg"
      autoPlay={false}
      accentColor="#e5a00d"
      theme="dark"
    />
  );
}

Basic Usage

Here's a live example of the player with common props:

Example.tsxtsx
<PlexVideoPlayer
  src="https://example.com/video.mp4"
  poster="https://example.com/poster.jpg"
  autoPlay={false}
  muted={false}
  pip={true}
  fullscreen={true}
  playbackSpeed={true}
  accentColor="#e5a00d"
  theme="dark"
  onPlay={() => console.log('Video started')}
  onEnded={() => console.log('Video ended')}
/>

Video Props

Core props for video source and behavior:

PropTypeDescription
srcstring | VideoSource[]Video source URL or array of sources with quality options
posterstringPoster image URL shown before playback
autoPlaybooleanAuto-start playback when ready
mutedbooleanStart with muted audio
loopbooleanLoop video playback
preload'none' | 'metadata' | 'auto'Video preload behavior
widthnumber | stringPlayer width
heightnumber | stringPlayer height

Control Props

Props for enabling/disabling player controls:

PropTypeDescription
controlsbooleanShow player controls
pipbooleanEnable Picture-in-Picture button
fullscreenbooleanEnable fullscreen button
playbackSpeedbooleanEnable playback speed control
playbackSpeedsnumber[]Available playback speeds
volumebooleanEnable volume control
initialVolumenumberInitial volume (0-1)
qualitySelectorbooleanEnable quality selector (requires multiple sources)
keyboardbooleanEnable keyboard shortcuts
clickToPlaybooleanClick on video to play/pause
doubleClickFullscreenbooleanDouble-click to toggle fullscreen

Style Props

Props for customizing the player appearance:

PropTypeDescription
accentColorstringAccent color for progress bar and buttons
theme'dark' | 'light' | 'auto'Control bar color theme
classNamestringCustom CSS class for the container
styleReact.CSSPropertiesInline styles for the container
controlsTimeoutnumberTimeout before hiding controls (ms)

💡 Tip: Custom Accent Colors

The accentColor prop accepts any valid CSS color value. Use your brand color to match the player with your site design.

Event Callbacks

Callbacks for handling player events:

PropTypeDescription
onPlay() => voidCalled when playback starts
onPause() => voidCalled when playback pauses
onEnded() => voidCalled when video ends
onTimeUpdate(time: number) => voidCalled on time update with current time
onProgress(buffered: number) => voidCalled on buffer progress
onVolumeChange(volume: number, muted: boolean) => voidCalled when volume changes
onFullscreenChange(isFullscreen: boolean) => voidCalled on fullscreen toggle
onPipChange(isPip: boolean) => voidCalled on PiP toggle
onQualityChange(quality: string) => voidCalled when quality changes
onError(error: MediaError | null) => voidCalled on playback error
onReady() => voidCalled when player is ready
EventsExample.tsxtsx
<PlexVideoPlayer
  src="https://example.com/video.mp4"
  onPlay={() => analytics.track('video_play')}
  onPause={() => analytics.track('video_pause')}
  onEnded={() => showNextVideo()}
  onTimeUpdate={(time) => saveProgress(time)}
  onError={(error) => console.error('Video error:', error)}
/>

Playlist

Create a playlist with multiple videos. The player will automatically play the next video when the current one ends.

PlaylistExample.tsxtsx
import { PlexVideoPlayer } from '@frameset/plex-player';
import '@frameset/plex-player/styles.css';

const playlist = [
  {
    id: '1',
    src: 'https://example.com/video1.mp4',
    title: 'Episode 1',
    poster: 'https://example.com/poster1.jpg',
  },
  {
    id: '2',
    src: 'https://example.com/video2.mp4',
    title: 'Episode 2',
    poster: 'https://example.com/poster2.jpg',
  },
  {
    id: '3',
    src: 'https://example.com/video3.mp4',
    title: 'Episode 3',
    poster: 'https://example.com/poster3.jpg',
  },
];

function App() {
  return (
    <PlexVideoPlayer
      src=""
      playlist={playlist}
      onPlaylistItemChange={(index, item) => {
        console.log(`Now playing: ${item.title}`);
      }}
    />
  );
}

PlaylistItem Type

interface PlaylistItem {
  id: string;        // Unique identifier
  src: string;       // Video source URL
  title: string;     // Video title
  poster?: string;   // Poster image URL (optional)
  duration?: number; // Duration in seconds (optional)
}

Quality Selector

Provide multiple video sources with different quality options:

QualityExample.tsxtsx
<PlexVideoPlayer
  src={[
    { src: 'video-1080p.mp4', quality: '1080p', label: 'Full HD' },
    { src: 'video-720p.mp4', quality: '720p', label: 'HD' },
    { src: 'video-480p.mp4', quality: '480p', label: 'SD' },
    { src: 'video-360p.mp4', quality: '360p', label: 'Low' },
  ]}
  qualitySelector={true}
  onQualityChange={(quality) => console.log(`Quality: ${quality}`)}
/>

Subtitles

Add subtitle tracks using the textTracks prop:

SubtitlesExample.tsxtsx
<PlexVideoPlayer
  src="https://example.com/video.mp4"
  textTracks={[
    {
      src: '/subtitles/en.vtt',
      kind: 'subtitles',
      srclang: 'en',
      label: 'English',
      default: true,
    },
    {
      src: '/subtitles/es.vtt',
      kind: 'subtitles',
      srclang: 'es',
      label: 'Español',
    },
    {
      src: '/subtitles/uk.vtt',
      kind: 'subtitles',
      srclang: 'uk',
      label: 'Українська',
    },
  ]}
/>

VAST Ads

Integrate video ads using VAST 2.0/3.0/4.0:

AdsExample.tsxtsx
<PlexVideoPlayer
  src="https://example.com/video.mp4"
  vast={{
    url: 'https://example.com/vast.xml',
    position: 'preroll',
    skipDelay: 5, // Skip button after 5 seconds
  }}
  onAdStart={(ad) => console.log('Ad started:', ad.title)}
  onAdEnd={() => console.log('Ad ended')}
  onAdSkip={() => console.log('Ad skipped')}
/>

// Multiple ads
<PlexVideoPlayer
  src="https://example.com/video.mp4"
  vast={[
    { url: 'preroll.xml', position: 'preroll' },
    { url: 'midroll.xml', position: 'midroll', midrollTime: 60 },
    { url: 'postroll.xml', position: 'postroll' },
  ]}
/>

Keyboard Shortcuts

Built-in keyboard shortcuts for better accessibility:

KeyAction
Space / KToggle play/pause
Rewind 10 seconds
Forward 10 seconds
Shift + ←Rewind 30 seconds
Shift + →Forward 30 seconds
Volume up
Volume down
MToggle mute
FToggle fullscreen
PToggle Picture-in-Picture
0-9Seek to 0%-90% of video

Custom Hotkeys

<PlexVideoPlayer
  src="https://example.com/video.mp4"
  keyboard={true}
  hotkeys={{
    play: 'Space',
    mute: 'm',
    fullscreen: 'f',
    pip: 'p',
    seekForward: 'ArrowRight',
    seekBackward: 'ArrowLeft',
    volumeUp: 'ArrowUp',
    volumeDown: 'ArrowDown',
  }}
/>

Ref Methods

Access player methods via ref for programmatic control:

RefExample.tsxtsx
import { useRef } from 'react';
import { PlexVideoPlayer, PlexVideoPlayerRef } from '@frameset/plex-player';

function App() {
  const playerRef = useRef<PlexVideoPlayerRef>(null);

  const handleCustomPlay = () => {
    playerRef.current?.play();
  };

  const handleSeekTo = (time: number) => {
    playerRef.current?.seek(time);
  };

  const handleSkipIntro = () => {
    playerRef.current?.seek(30); // Skip to 30 seconds
  };

  return (
    <>
      <PlexVideoPlayer
        ref={playerRef}
        src="https://example.com/video.mp4"
      />
      <button onClick={handleCustomPlay}>Play</button>
      <button onClick={handleSkipIntro}>Skip Intro</button>
    </>
  );
}

Available Methods

PropTypeDescription
play()Promise<void>Start playback
pause()voidPause playback
stop()voidStop and reset playback
seek(time)voidSeek to specific time (seconds)
setVolume(volume)voidSet volume (0-1)
mute() / unmute()voidMute/unmute audio
toggleMute()voidToggle mute state
enterFullscreen()Promise<void>Enter fullscreen mode
exitFullscreen()Promise<void>Exit fullscreen mode
toggleFullscreen()Promise<void>Toggle fullscreen
enterPip() / exitPip()Promise<void>Enter/exit PiP mode
setPlaybackRate(rate)voidSet playback speed
getCurrentTime()numberGet current time
getDuration()numberGet video duration
getVideoElement()HTMLVideoElement | nullGet underlying video element

Hooks

Custom hooks for building your own player UI:

usePlayer

Hook for managing video player state:

import { usePlayer } from '@frameset/plex-player';

function CustomPlayer() {
  const {
    state,
    videoRef,
    containerRef,
    play,
    pause,
    togglePlay,
    seek,
    setVolume,
    toggleMute,
    toggleFullscreen,
    togglePip,
  } = usePlayer({
    autoPlay: false,
    muted: false,
    volume: 1,
  });

  return (
    <div ref={containerRef}>
      <video ref={videoRef} src="video.mp4" />
      <button onClick={togglePlay}>
        {state.isPlaying ? 'Pause' : 'Play'}
      </button>
      <span>{state.currentTime} / {state.duration}</span>
    </div>
  );
}

useKeyboard

Hook for keyboard shortcuts:

import { useKeyboard } from '@frameset/plex-player';

useKeyboard({
  enabled: true,
  containerRef: containerRef,
  onPlay: togglePlay,
  onMute: toggleMute,
  onFullscreen: toggleFullscreen,
  onPip: togglePip,
  onSeek: (delta) => seek(currentTime + delta),
  onVolume: (delta) => setVolume(volume + delta),
});

Utilities

Helper functions exported from the package:

import {
  formatTime,        // (seconds) => "1:23:45"
  parseTime,         // ("1:23:45") => seconds
  percentage,        // (value, total) => percentage
  clamp,             // (value, min, max) => clamped value
  throttle,          // Throttle function execution
  debounce,          // Debounce function execution
  isFullscreenSupported,
  isPipSupported,
  isMobile,
  isTouchDevice,
  detectVideoType,   // Detect MIME type from URL
  canPlayType,       // Check browser support for format
} from '@frameset/plex-player';

// Example
const time = formatTime(3723); // "1:02:03"
const seconds = parseTime("1:02:03"); // 3723

TypeScript Types

All types are exported for TypeScript users:

import type {
  PlexVideoPlayerProps,
  PlexVideoPlayerRef,
  PlayerState,
  VideoSource,
  TextTrack,
  VastConfig,
  VastAdInfo,
  PlaylistItem,
  HotkeyConfig,
  UsePlayerOptions,
  UsePlayerReturn,
} from '@frameset/plex-player';