npm package: @interactify-live/media-display
Description: Pure JavaScript library for displaying videos and images
Author: Interactify
Latest version: 1.0.10

# @interactify-live/media-display

A pure JavaScript library for displaying videos and images with a simple, lightweight API. Supports HLS streams, camera streams, and provides comprehensive media playback controls.

## Features

- **Pure JavaScript**: Minimal dependencies, works in any modern browser
- **Image Support**: Display images with various object-fit options
- **Video Support**: Full video player functionality with controls
- **HLS Support**: Native HLS stream playback using HLS.js
- **Camera Streams**: Support for live camera/media streams
- **TypeScript**: Complete TypeScript support with type definitions
- **Lightweight**: Optimized bundle size for performance
- **Flexible**: Customizable styling and behavior options
- **Event-driven**: Rich event system for media interactions
- **SSR Safe**: Dynamic imports prevent server-side rendering issues

## Installation

```bash
npm install @interactify-live/media-display
```

## Quick Start

### Basic Usage

````javascript
import { MediaDisplay } from "@interactify-live/media-display";

// Create a media display instance
const mediaDisplay = new MediaDisplay({
  width: 400,
  height: 300,
  objectFit: "contain",
});

// Add to DOM
document.body.appendChild(mediaDisplay.element);

// Load an image
mediaDisplay.load({
  id: "image1",
  type: "image",
  url: "https://example.com/image.jpg",
  alt: "Sample image",
});

// Load a video
mediaDisplay.load({
  id: "video1",
  type: "video",
  url: "https://example.com/video.mp4",
});

// Load an HLS stream
mediaDisplay.load({
  id: "hls-stream",
  type: "video",
  url: "https://example.com/stream.m3u8",
});

// Play the video
await mediaDisplay.play();

### With TypeScript

```typescript
import {
  MediaDisplay,
  MediaItem,
  MediaDisplayOptions,
} from "@interactify-live/media-display";

const options: MediaDisplayOptions = {
  width: 400,
  height: 300,
  autoplay: true,
  muted: true,
  loop: true,
  controls: true,
  objectFit: "contain",
  backgroundColor: "#000000",
  onLoad: (media: MediaItem) => console.log("Media loaded:", media),
  onError: (media: MediaItem, error: Error) => console.error("Error:", error),
  onPlay: (media: MediaItem) => console.log("Started playing:", media),
  onPause: (media: MediaItem) => console.log("Paused:", media),
  onEnded: (media: MediaItem) => console.log("Ended:", media),
};

const mediaDisplay = new MediaDisplay(options);
````

### Camera Stream Support

```javascript
// Get camera stream
navigator.mediaDevices
  .getUserMedia({ video: true })
  .then((stream) => {
    // Load camera stream
    mediaDisplay.loadStream(stream);
  })
  .catch((error) => {
    console.error("Failed to get camera stream:", error);
  });
```

## API Reference

### MediaDisplay Constructor

```typescript
new MediaDisplay(options?: MediaDisplayOptions)
```

#### Options

- `width?: number | string` - Width of the container
- `height?: number | string` - Height of the container
- `autoplay?: boolean` - Auto-play videos (default: false)
- `muted?: boolean` - Start videos muted (default: false)
- `loop?: boolean` - Loop videos (default: false)
- `controls?: boolean` - Show video controls (default: false)
- `objectFit?: "contain" | "cover" | "fill" | "none" | "scale-down"` - CSS object-fit property (default: "contain")
- `backgroundColor?: string` - Background color of the container
- `onLoad?: (media: MediaItem) => void` - Called when media loads successfully
- `onError?: (media: MediaItem, error: Error) => void` - Called when media fails to load
- `onPlay?: (media: MediaItem) => void` - Called when video starts playing
- `onPause?: (media: MediaItem) => void` - Called when video is paused
- `onEnded?: (media: MediaItem) => void` - Called when video ends
- `onVideoReady?: (videoElement: HTMLVideoElement) => void` - Called when video element is ready

### MediaDisplay Methods

#### `load(media: MediaItem): void`

Loads a new media item (image or video). Automatically handles HLS streams (.m3u8 files).

#### `loadStream(stream: MediaStream): void`

Loads a camera or media stream. Automatically creates a video element and starts playback.

#### `play(): Promise<void>`

Plays the current video. Throws error if current media is not a video.

#### `pause(): void`

Pauses the current video. No effect if current media is not a video.

#### `destroy(): void`

Destroys the current media element and cleans up resources (including HLS instances).

#### `getCurrentTime(): number`

Returns the current playback time of the video (0 for images).

#### `getDuration(): number`

Returns the total duration of the video (0 for images).

#### `setCurrentTime(time: number): void`

Sets the current playback time of the video.

#### `setVolume(volume: number): void`

Sets the volume of the video (0-1).

#### `getVolume(): number`

Returns the current volume of the video (0-1).

#### `mute(): void`

Mutes the video.

#### `unmute(): void`

Unmutes the video.

#### `isMuted(): boolean`

Returns true if the video is muted.

#### `isPlaying(): boolean`

Returns true if the video is currently playing.

#### `getCurrentMedia(): MediaItem | null`

Returns the currently loaded media item.

#### `updateOptions(newOptions: Partial<MediaDisplayOptions>): void`

Updates the display options dynamically.

### MediaItem Interface

```typescript
interface MediaItem {
  id: string; // Unique identifier
  type: "image" | "video"; // Media type
  url: string; // Media URL (supports .m3u8 for HLS)
  thumbnail?: string; // Optional thumbnail URL
  alt?: string; // Optional alt text for images
}
```

### Utility Functions

The library also exports utility functions for advanced use cases:

```typescript
import {
  isValidUrl,
  validateMediaItem,
  createContainer,
  createImageElement,
  createVideoElement,
  addMediaEventListeners,
} from "@interactify-live/media-display";
```

## Examples

### Image Gallery

```javascript
const gallery = new MediaDisplay({
  width: 600,
  height: 400,
  objectFit: "cover",
});

const images = [
  { id: "1", type: "image", url: "image1.jpg" },
  { id: "2", type: "image", url: "image2.jpg" },
  { id: "3", type: "image", url: "image3.jpg" },
];

let currentIndex = 0;

function showNext() {
  currentIndex = (currentIndex + 1) % images.length;
  gallery.load(images[currentIndex]);
}

function showPrevious() {
  currentIndex = (currentIndex - 1 + images.length) % images.length;
  gallery.load(images[currentIndex]);
}
```

### HLS Stream Player

```javascript
const hlsPlayer = new MediaDisplay({
  width: 800,
  height: 450,
  controls: true,
  autoplay: false,
  muted: false,
  onLoad: (media) => console.log("HLS stream loaded:", media),
  onError: (media, error) => console.error("HLS error:", error),
});

// Load HLS stream
hlsPlayer.load({
  id: "live-stream",
  type: "video",
  url: "https://example.com/live/stream.m3u8",
});
```

### Camera Stream with Controls

```javascript
const cameraDisplay = new MediaDisplay({
  width: 640,
  height: 480,
  objectFit: "cover",
  onVideoReady: (videoElement) => {
    console.log("Camera stream ready");
    // Custom video element setup
  },
});

// Start camera
async function startCamera() {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      video: { width: 640, height: 480 },
      audio: false,
    });

    cameraDisplay.loadStream(stream);
  } catch (error) {
    console.error("Failed to start camera:", error);
  }
}

// Stop camera
function stopCamera() {
  cameraDisplay.destroy();
}
```

### Video Player with Controls

```javascript
const videoPlayer = new MediaDisplay({
  width: 800,
  height: 450,
  controls: true,
  autoplay: false,
  muted: false,
  onPlay: (media) => console.log("Video started playing"),
  onPause: (media) => console.log("Video paused"),
  onEnded: (media) => console.log("Video ended"),
});

// Custom controls
const playButton = document.getElementById("play-btn");
const pauseButton = document.getElementById("pause-btn");
const muteButton = document.getElementById("mute-btn");
const progressBar = document.getElementById("progress");

playButton.addEventListener("click", () => videoPlayer.play());
pauseButton.addEventListener("click", () => videoPlayer.pause());
muteButton.addEventListener("click", () => {
  if (videoPlayer.isMuted()) {
    videoPlayer.unmute();
    muteButton.textContent = "Mute";
  } else {
    videoPlayer.mute();
    muteButton.textContent = "Unmute";
  }
});

// Update progress bar
setInterval(() => {
  const current = videoPlayer.getCurrentTime();
  const duration = videoPlayer.getDuration();
  const progress = (current / duration) * 100;
  progressBar.style.width = `${progress}%`;
}, 100);
```

### Responsive Media Display

```javascript
const responsiveDisplay = new MediaDisplay({
  width: "100%",
  height: "100vh",
  objectFit: "contain",
  backgroundColor: "#f0f0f0",
});

// Update options on window resize
window.addEventListener("resize", () => {
  responsiveDisplay.updateOptions({
    width: window.innerWidth,
    height: window.innerHeight,
  });
});
```

## Dependencies

- **hls.js**: For HLS stream playback (automatically imported when needed)
- **tslib**: TypeScript runtime helpers

## Browser Support

- Chrome 60+
- Firefox 55+
- Safari 12+
- Edge 79+

## License

MIT