React Logoreact-player

`react-player` is a versatile and universal React component designed for playing a wide range of media URLs within your React applications. It acts as an abstraction layer over various media services and file types, providing a consistent API to embed and control media players from sources like YouTube, Vimeo, Facebook, Twitch, SoundCloud, Wistia, DailyMotion, Vidyard, Streamable, and direct file paths (MP4, WebM, OGG, etc.).

Key Features:
* Broad Compatibility: Supports an extensive list of popular media services and direct media file URLs, simplifying integration regardless of the content source.
* Customization: Offers granular control over player behavior through props such as `playing`, `volume`, `muted`, `loop`, `controls`, and `playbackRate`.
* Event Handling: Provides a comprehensive set of callbacks for various player events, including `onReady`, `onStart`, `onPlay`, `onPause`, `onBuffer`, `onBufferEnd`, `onEnded`, `onError`, `onProgress`, `onDuration`, and `onSeek`, allowing for dynamic interaction and UI updates.
* Responsive Design: Can be easily configured to be responsive, adapting to the dimensions of its parent container.
* Lightweight: It intelligently loads only the necessary player SDKs (e.g., YouTube's IFrame API) when a URL from a particular service is provided, minimizing bundle size and improving performance.

Installation:
To integrate `react-player` into your project, use npm or yarn:
```bash
npm install react-player
# or
yarn add react-player
```

Basic Usage:
After installation, you can import `ReactPlayer` and pass the media URL to its `url` prop. You can then customize its behavior using various props.

Common Props:
* `url` (String | Array): The media URL to play. Can be a single URL or an array of URLs for a playlist.
* `playing` (Boolean): If `true`, the media will play automatically.
* `loop` (Boolean): If `true`, the media will loop once it ends.
* `controls` (Boolean): If `true`, native player controls will be displayed.
* `volume` (Number): A value between 0 and 1 for the player's volume.
* `muted` (Boolean): If `true`, the player will be muted.
* `width` (String | Number): Sets the width of the player (e.g., `'640px'`, `'100%'`, or `640`).
* `height` (String | Number): Sets the height of the player.
* `playbackRate` (Number): Controls the playback speed (e.g., `0.5`, `1`, `1.5`, `2`).
* `onReady` (Function): Callback fired when the player is ready to begin playing.
* `onPlay` (Function): Callback fired when the player starts playing.
* `onPause` (Function): Callback fired when the player is paused.
* `onEnded` (Function): Callback fired when the media finishes playing.
* `onProgress` (Function): Callback fired at a specified `interval` (defaulting to 1000ms) with a `ProgressState` object containing `played` (0-1), `playedSeconds`, `loaded` (0-1), and `loadedSeconds`.
* `onError` (Function): Callback fired when an error occurs during media loading or playback.

`react-player` significantly streamlines the process of embedding and managing media content in React applications, abstracting away the complexities of different media APIs into a single, cohesive component.

Example Code

```jsx
import React, { useState, useRef, useCallback, useEffect } from 'react';
import ReactPlayer from 'react-player';

function VideoPlayer() {
  const [playing, setPlaying] = useState(false);
  const [volume, setVolume] = useState(0.8);
  const [muted, setMuted] = useState(false);
  const [playbackRate, setPlaybackRate] = useState(1);
  const [progress, setProgress] = useState({ played: 0, playedSeconds: 0 });
  const [duration, setDuration] = useState(0);
  const playerRef = useRef(null);

  const videoUrl = 'https://www.youtube.com/watch?v=LXb3EKWsInQ'; // Example YouTube URL

  const handlePlayPause = useCallback(() => {
    setPlaying((prev) => !prev);
  }, []);

  const handleVolumeChange = useCallback((e) => {
    setVolume(parseFloat(e.target.value));
  }, []);

  const handleMute = useCallback(() => {
    setMuted((prev) => !prev);
  }, []);

  const handlePlaybackRateChange = useCallback((e) => {
    setPlaybackRate(parseFloat(e.target.value));
  }, []);

  const handleProgress = useCallback((state) => {
    // We only want to update time slider if we are not currently seeking
    setProgress(state);
  }, []);

  const handleDuration = useCallback((duration) => {
    setDuration(duration);
  }, []);

  const handleSeekChange = useCallback((e) => {
    const newPlayed = parseFloat(e.target.value);
    setProgress((prev) => ({ ...prev, played: newPlayed }));
    playerRef.current.seekTo(newPlayed, 'fraction');
  }, []);

  const formatTime = (seconds) => {
    const date = new Date(null);
    date.setSeconds(seconds);
    return date.toISOString().slice(11, 19);
  };

  return (
    <div style={{ maxWidth: '800px', margin: '20px auto', padding: '20px', border: '1px solid #ddd', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }}>
      <h2 style={{ textAlign: 'center', marginBottom: '20px', color: '#333' }}>ReactPlayer with Custom Controls</h2>
      <div style={{ position: 'relative', paddingTop: '56.25%', marginBottom: '20px' }}>
        <ReactPlayer
          ref={playerRef}
          className='react-player'
          url={videoUrl}
          playing={playing}
          controls={false} // We are building custom controls
          volume={volume}
          muted={muted}
          playbackRate={playbackRate}
          width='100%'
          height='100%'
          style={{ position: 'absolute', top: 0, left: 0 }}
          onReady={() => console.log('Player is ready!')}
          onStart={() => console.log('Video started!')}
          onPlay={() => console.log('Video playing...')}
          onPause={() => console.log('Video paused.')}
          onBuffer={() => console.log('Buffering...')}
          onBufferEnd={() => console.log('Buffer ended.')}
          onEnded={() => {
            console.log('Video ended!');
            setPlaying(false);
          }}
          onError={(error) => console.error('Player error:', error)}
          onProgress={handleProgress}
          onDuration={handleDuration}
        />
      </div>

      <div style={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
        {/* Play/Pause & Mute Buttons */}
        <div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
          <button onClick={handlePlayPause} style={buttonStyle}>
            {playing ? '⏸️ Pause' : '▶️ Play'}
          </button>
          <button onClick={handleMute} style={buttonStyle}>
            {muted ? '🔊 Unmute' : '🔇 Mute'}
          </button>
          <span style={{ marginLeft: '10px' }}>
            {formatTime(progress.playedSeconds)} / {formatTime(duration)}
          </span>
        </div>

        {/* Progress Bar */}
        <input
          type='range'
          min={0}
          max={0.999999}
          step='any'
          value={progress.played}
          onChange={handleSeekChange}
          style={{ width: '100%' }}
        />

        {/* Volume & Playback Rate Controls */}
        <div style={{ display: 'flex', gap: '20px', alignItems: 'center' }}>
          <label style={{ display: 'flex', alignItems: 'center' }}>
            Volume:
            <input
              type='range'
              min={0}
              max={1}
              step='any'
              value={volume}
              onChange={handleVolumeChange}
              style={{ marginLeft: '5px', width: '100px' }}
            />
            {(volume * 100).toFixed(0)}%
          </label>

          <label style={{ display: 'flex', alignItems: 'center' }}>
            Speed:
            <select value={playbackRate} onChange={handlePlaybackRateChange} style={{ marginLeft: '5px', padding: '5px' }}>
              <option value={0.5}>0.5x</option>
              <option value={0.75}>0.75x</option>
              <option value={1}>1x</option>
              <option value={1.25}>1.25x</option>
              <option value={1.5}>1.5x</option>
              <option value={2}>2x</option>
            </select>
          </label>
        </div>
      </div>

      <p style={{ fontSize: '0.8em', color: '#666', marginTop: '20px', textAlign: 'center' }}>
        This example showcases `react-player` with custom UI controls. For simpler usage, set the `controls` prop to `true` to use the native player controls.
      </p>
    </div>
  );
}

const buttonStyle = {
  padding: '8px 15px',
  fontSize: '1em',
  cursor: 'pointer',
  borderRadius: '5px',
  border: '1px solid #007bff',
  backgroundColor: '#007bff',
  color: 'white',
  transition: 'background-color 0.2s ease',
};

export default VideoPlayer;
```