# mstf-kit

English | [简体中文](./README.md)

A modern JavaScript/TypeScript utility library providing a rich set of commonly used utility functions.

## ✨ Features

- 📦 Tree Shaking Support
- 🔧 TypeScript Support
- 📚 Complete Type Definitions
- 🎯 Modular Design
- 💪 Comprehensive Test Coverage
- 📝 Detailed Documentation
- 🔒 Code Obfuscation Protection

## 📦 Installation

```bash
npm install mstf-kit
# or
yarn add mstf-kit
# or
pnpm add mstf-kit
```

## 🚀 Usage

```typescript
// Import the utility functions you need
import { formatDate, isEmail } from 'mstf-kit';

// Use date formatting
const date = formatDate(new Date(), 'YYYY-MM-DD');
console.log(date); // 2024-03-10

// Validate email
const isValidEmail = isEmail('example@email.com');
console.log(isValidEmail); // true
```

### Importing on Demand

To reduce bundle size, it is recommended to use tree-shaking and import only the specific functions you need:

```typescript
// Only import the functions you need
import { capitalize, truncate } from 'mstf-kit';
import { formatDate } from 'mstf-kit';
import { createLottiePlayer } from 'mstf-kit';

// Don't import the entire library like this
// import * as mstfKit from 'mstf-kit'; // ❌ Not recommended
```

Modern bundlers (like webpack, rollup, and vite) will automatically perform tree-shaking, only including the code you actually use.

## 📚 API Documentation

### 🔤 String Utils

Utility functions for string manipulation.

- `capitalize(str: string): string` - Capitalize first letter
- `camelCase(str: string): string` - Convert to camelCase
- `truncate(str: string, length: number): string` - Truncate string

### 🔢 Number Utils

Utility functions for number handling and calculations.

- `formatNumber(num: number, locale?: string): string` - Format number
- `round(num: number, decimals?: number): number` - Round number
- `clamp(num: number, min: number, max: number): number` - Clamp number
- `random(min: number, max: number, isInteger?: boolean): number` - Generate random number
- `percentage(value: number, total: number, decimals?: number): number` - Calculate percentage

### 📋 Array Utils

Utility functions for array operations and manipulation.

- `unique<T>(arr: T[]): T[]` - Remove duplicates
- `groupBy<T>(arr: T[], key: string | ((item: T) => string)): Record<string, T[]>` - Group array
- `flatten<T>(arr: any[], depth?: number): T[]` - Flatten array
- `sample<T>(arr: T[], count?: number): T | T[]` - Random sampling
- `shuffle<T>(arr: T[]): T[]` - Shuffle array
- `closest(arr: number[], target: number): number` - Find closest value

### 📦 Object Utils

Utility functions for object operations and manipulation.

- `deepClone<T>(obj: T): T` - Deep clone
- `get(obj: any, path: string | string[], defaultValue?: any): any` - Get nested property
- `set(obj: any, path: string | string[], value: any): void` - Set nested property
- `pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>` - Pick properties
- `omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>` - Omit properties
- `merge<T>(...objects: T[]): T` - Merge objects

### 📅 Date Utils

Utility functions for date and time handling.

- `formatDate(date: Date | number | string, format?: string): string` - Format date
- `getRelativeTime(date: Date | number | string, now?: Date): string` - Get relative time
- `getDateRange(start: Date | number | string, end: Date | number | string): Date[]` - Get date range
- `addTime(date: Date | number | string, amount: number, unit: string): Date` - Add time
- `isSameDay(date1: Date | number | string, date2: Date | number | string): boolean` - Check same day

### ✅ Validation Utils

Utility functions for data validation.

- `isEmail(email: string): boolean` - Validate email
- `isChinesePhone(phone: string): boolean` - Validate Chinese phone number
- `isChineseIdCard(idCard: string): boolean` - Validate Chinese ID card
- `isUrl(url: string): boolean` - Validate URL
- `isIPv4(ip: string): boolean` - Validate IPv4 address
- `validatePassword(password: string, options?: object): boolean` - Validate password strength
- `isSafeString(str: string): boolean` - Validate XSS safety

### 🎵 Audio Utils

#### Audio Stream Handler (audioStream)

Audio stream processing tool for handling audio data streams, supporting ArrayBuffer and streaming data formats with auto-play capability.

```typescript
import { 
  createAudioStreamHandler, 
  handleAudioBuffer, 
  createAudioHandlers 
} from 'mstf-kit';

// Example 1: Handling ArrayBuffer response
const response = await axios.post('/api/voice/synthesize', {
  voice_id: 'my-voice',
  text: 'Hello, world!'
}, {
  responseType: 'arraybuffer',
  headers: { Accept: 'audio/mp3' }
});

// Method 1: Direct processing
const { blob, url, handler } = await handleAudioBuffer(response, {
  mimeType: 'audio/mp3',
  autoPlay: true,
  logLevel: 'debug'
});

// Example 2: Handling streaming data
// Create a handler
const audioHandler = createAudioStreamHandler({
  mimeType: 'audio/mp3',
  logLevel: 'debug'
});

// Example 3: Simplest approach (all-in-one)
const { config, handler } = createAudioHandlers(
  {
    responseType: 'arraybuffer',
    headers: { Accept: 'audio/mp3' }
  },
  {
    mimeType: 'audio/mp3',
    autoPlayOnComplete: true,
    logLevel: 'debug'
  }
);

// Use the enhanced config to send the request
const response = await axios.post('/api/voice/synthesize', data, config);
```

#### Lightweight Audio Request Handler (audioRequest)

A lightweight audio processing utility focused on handling streaming and non-streaming audio data without additional dependencies, supporting various response formats.

```typescript
import { 
  processStreamResponse, 
  processArrayBuffer, 
  processBlob,
  processBase64Audio,
  createBase64StreamProcessor 
} from 'mstf-kit';

// Example 1: Using fetch and getReader to process streaming response
const response = await fetch('https://api.example.com/audio/stream', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ text: 'Text to synthesize' })
});

// Get the reader from response stream
const reader = response.body.getReader();
// Process streaming audio data
const { pause, resume, abort, isPlaying, finalBlob } = await processStreamResponse(reader, {
  autoPlay: true,             // Auto-play audio
  returnBlob: true,           // Return complete blob
  audioField: 'data.audio',   // Audio data path in the response
  onStart: () => {            // Audio playback start callback
    console.log('Audio playback started');
    playButton.classList.add('playing');
  },
  onEnded: () => {            // Audio playback end callback
    console.log('Audio playback ended');
    playButton.classList.remove('playing');
    statusElement.textContent = 'Playback completed';
  },
  onAudioData: (blob) => {    // Callback when receiving new audio chunks
    console.log('Audio chunk received:', blob.size);
  },
  onComplete: (blob) => {     // Processing complete callback
    if (blob) {
      console.log('Complete audio size:', blob.size);
    }
  }
});

// Playback control
pauseButton.addEventListener('click', () => {
  pause();
  playButton.classList.remove('playing');
});

playButton.addEventListener('click', () => {
  resume();
  playButton.classList.add('playing');
});

// Monitor playback status
setInterval(() => {
  const playing = isPlaying();
  statusElement.textContent = playing ? 'Playing' : 'Paused';
}, 100);

// Abort processing
cancelButton.addEventListener('click', () => {
  abort();
});

// Get complete audio
if (finalBlob) {
  const blob = await finalBlob;
  const url = URL.createObjectURL(blob);
  audio.src = url;
}
```

Supported options:

```typescript
// Audio processing options
{
  autoPlay?: boolean;         // Whether to auto-play
  returnBlob?: boolean;       // Whether to return complete blob
  mimeType?: string;          // MIME type, defaults to 'audio/wav'
  audioField?: string;        // Audio data field path, e.g., 'data.audio'
  onAudioData?: (audioBlob: Blob) => void;      // Callback when audio data is received
  onError?: (error: Error) => void;             // Error callback
  onComplete?: (blob?: Blob) => void;           // Completion callback
  onStart?: () => void;                 // Audio playback start callback
  onEnded?: () => void;                 // Audio playback end callback
}
```

##### Axios Support

Using Axios for streaming and non-streaming audio requests:

```typescript
import axios from 'axios';
import { createAxiosAudioOptions } from 'mstf-kit';

// Streaming audio request - create configuration
const { axiosConfig, pause, resume, abort, isPlaying, finalBlob } = createAxiosAudioOptions({
  autoPlay: true,              // Auto-play audio
  returnBlob: true,            // Return complete blob
  audioField: 'data.audio',    // Path to audio data in response JSON
  mimeType: 'audio/wav',       // Audio MIME type
  onStart: () => {
    console.log('Audio playback started');
    playButton.disabled = false;
  },
  onAudioData: (blob) => {     // Callback when receiving audio chunks
    console.log('Audio chunk received:', blob.size);
  }
});

// Send request
const response = await axios.post(
  'https://api.example.com/audio/stream',
  { text: 'Text to synthesize' },
  axiosConfig
);

// Control playback
const togglePlay = () => {
  if (isPlaying()) {
    pause();
    playButton.textContent = 'Play';
  } else {
    resume();
    playButton.textContent = 'Pause';
  }
};

playButton.addEventListener('click', togglePlay);
```

##### Custom Data Formats

Handles multiple server response data formats:

1. **Standard format**: `data: {"audio":"base64data","is_last":false}`
2. **Custom paths**: Specify path to audio data using `audioField`

```typescript
// Standard format processing
const { pause, resume, abort } = await processStreamResponse(reader, {
  autoPlay: true
});

// Custom path processing
const { pause, resume, abort } = await processStreamResponse(reader, {
  autoPlay: true,
  audioField: 'result.data.audioContent' // Specify custom path
});

// Axios with custom format
const { axiosConfig } = createAxiosAudioOptions({
  autoPlay: true,
  audioField: 'response.voice.content'
});
```

Intelligent data extraction: If `audioField` is not specified, it will automatically attempt to extract audio data from:
- Data provided directly as a string
- The `audio` property of the object
- Data nested in `data.audio`

##### Stopping/Aborting Processing

Supports aborting the processing using AbortController:

```typescript
// Create an AbortController
const controller = new AbortController();
const signal = controller.signal;

// Method 1: Pass through config
const { config, handler } = createAudioHandlers(
  { /* axios config */ },
  { 
    abortSignal: signal,
    // other options...
  }
);

// Method 2: Set directly
audioHandler.setAbortSignal(signal);

// Method 3: Call abort method directly
audioHandler.abort();

// When you need to abort:
controller.abort(); // This will trigger the abort processing
```

##### Playback Control

```typescript
// Pause playback
handler.pause();

// Resume playback
handler.resume();

// Stop playback
handler.stop();

// Set volume (0-1)
handler.setVolume(0.5);

// Release resources
handler.release();
```

##### Configuration Options

`AudioStreamOptions` supports these options:

```typescript
{
  // Log level: 'none' | 'error' | 'warn' | 'info' | 'debug'
  logLevel?: LogLevel;
  
  // Whether to autoplay
  autoPlay?: boolean;
  
  // Custom MIME type
  mimeType?: string;
  
  // Whether to loop playback
  loop?: boolean;
  
  // Initial volume (0-1)
  volume?: number;
  
  // Callback when playback ends
  onEnded?: () => void;
  
  // Callback on error
  onError?: (error: Error) => void;
  
  // Callback when playback starts
  onPlay?: () => void;
  
  // Callback for playback progress
  onProgress?: (currentTime: number, duration: number) => void;
  
  // Callback when data is loaded
  onDataLoaded?: (blob: Blob) => void;
  
  // Callback when processing is aborted
  onAborted?: () => void;
}
```

`DownloadProgressConfig` supports these options:

```typescript
{
  // Whether parsing is required
  needParse?: boolean;
  
  // Audio data path, e.g. "audio.b"
  audioPath?: string;
  
  // MIME type
  mimeType?: string;
  
  // Whether to autoplay on first chunk
  autoPlayOnFirstChunk?: boolean;
  
  // Whether to autoplay when download completes
  autoPlayOnComplete?: boolean;
  
  // AbortSignal for stopping processing
  abortSignal?: AbortSignal;
}
```


**Question 5: How do I determine which responseType to use?**

- Use `responseType: 'arraybuffer'` when API returns binary audio data directly
- Use `responseType: 'json'` when API returns a JSON structure containing audio data, and specify `audioDataField`
- Use `responseType: 'text'` when API returns text-formatted audio data (like Base64 encoded)

Combine server API documentation and actual testing to determine the most suitable type.

### 🔊 Audio Player

`mstf-kit` provides powerful audio playback tools supporting both background playback and UI rendering modes:

#### Background Playback Mode

```typescript
import { createAudioPlayer, playAudio } from 'mstf-kit';

// Simple playback method
const audioBlob = new Blob([...]); // Audio data
const player = await playAudio(audioBlob, {
  volume: 0.8,
  loop: true
});

// Or use the complete API
const backgroundPlayer = createAudioPlayer();
await backgroundPlayer.load('https://example.com/audio.mp3');
await backgroundPlayer.play();

// Playback controls
backgroundPlayer.pause();
backgroundPlayer.setVolume(0.5);
backgroundPlayer.seek(30); // Jump to 30 seconds position
```

#### UI Rendering Mode

```typescript
import { createAudioPlayer, AUDIO_FORMATS } from 'mstf-kit';

// Create a player with UI interface
const uiPlayer = createAudioPlayer({
  renderUI: true,           // Enable UI rendering
  container: '#player-box', // Specify container element
  theme: 'dark',            // Use dark theme
  showVisualization: true,  // Show audio visualization
  visualizationType: 'bars' // Use bar spectrum visualization
});

// Load audio
await uiPlayer.load(audioBlob);
await uiPlayer.play();

// Callback when playback ends
uiPlayer.onEnded = () => {
  console.log('Playback completed');
};

// Release resources when not needed
uiPlayer.destroy();
```

#### Vue Integration

Seamlessly integrates with Vue3 framework, supporting the use of ref as container:

```typescript
import { ref, onMounted, onUnmounted } from 'vue';
import { createAudioPlayer } from 'mstf-kit';

export default {
  setup() {
    // Create container reference
    const playerContainer = ref(null);
    let audioPlayer = null;
    
    onMounted(async () => {
      // Create player and use ref as container
      audioPlayer = createAudioPlayer({
        renderUI: true,
        container: playerContainer, // Pass ref directly
        theme: 'dark',
        showVisualization: true
      });
      
      // Load and play audio
      await audioPlayer.load('/audio/example.mp3');
      await audioPlayer.play();
    });
    
    // Clean up resources when component is unmounted
    onUnmounted(() => {
      if (audioPlayer) {
        audioPlayer.destroy();
      }
    });
    
    return { playerContainer };
  }
}
```

#### Visualization Types

The player supports three visualization types:

- `waveform`: Waveform display
- `bars`: Spectrum bar chart
- `circle`: Circular spectrum visualization

#### Supported Themes

- `default`: Default theme (light)
- `dark`: Dark theme
- `minimal`: Minimal theme (transparent background)

### 🎭 Lottie Animation

`mstf-kit` supports loading, rendering, and controlling Lottie animations, making it easy to showcase high-quality vector animations in your application.

#### Basic Usage

```typescript
import { createLottiePlayer, playLottie } from 'mstf-kit';

// Quickly load and play a Lottie animation
const player = await playLottie(
  'https://assets.lottiefiles.com/packages/lf20_UJNc2t.json',
  '#animation-container',
  { loop: true, speed: 1.5 }
);

// Or use the complete API
const lottiePlayer = await createLottiePlayer({
  container: '#animation-container',
  renderer: 'canvas', // dotlottie-web uses canvas rendering
  loop: true,
  autoplay: true
});

// Load animation
await lottiePlayer.load('https://assets.lottiefiles.com/packages/lf20_UJNc2t.json');

// Control animation
lottiePlayer.pause();
lottiePlayer.setSpeed(2.0);
lottiePlayer.play();
```

#### Vue Integration

Seamlessly integrates with Vue3 framework, supporting the use of refs as containers:

```typescript
import { ref } from 'vue';
import { playLottie } from 'mstf-kit';

export default {
  setup() {
    // Create container reference
    const animationContainer = ref(null);
    
    // Load animation (in onMounted)
    onMounted(async () => {
      const player = await playLottie(
        'https://assets.lottiefiles.com/packages/lf20_UJNc2t.json',
        animationContainer,
        { loop: true }
      );
    });
    
    return { animationContainer };
  }
}
```

#### Multiple Library Loading Modes

Supports various loading methods:

```typescript
// Use the built-in dotlottie-web library (default)
const player1 = await createLottiePlayer({
  container: '#animation-container',
  loop: true
});

// Use a custom external library
import customLottieLib from 'custom-lottie-lib';
const player2 = await createLottiePlayer({
  container: '#animation-container',
  libOptions: {
    source: 'external',
    externalLib: customLottieLib
  }
});

// Load from CDN
const player3 = await createLottiePlayer({
  container: '#animation-container',
  libOptions: {
    source: 'cdn',
    cdnURL: 'https://cdn.jsdelivr.net/npm/@lottiefiles/dotlottie-web/+esm'
  }
});
```

#### Rendering Modes

The Lottie player uses Canvas rendering by default, providing high-performance animation playback.

#### Animation Controls

The player supports a rich set of control methods:

```typescript
// Playback controls
player.play();
player.pause();
player.stop();

// Speed and direction
player.setSpeed(1.5);  // 1.5x speed
player.setDirection(-1); // Play in reverse

// Navigation controls
player.goToFrame(24);  // Jump to frame 24
player.goToAndPlay(24); // Jump to frame and play
player.setSegment(10, 50); // Only play frames 10-50

// Loop controls
player.setLoop(true);  // Infinite loop
player.setLoop(3);     // Loop 3 times

// Animation information
console.log(`Total frames: ${player.getTotalFrames()}`);
console.log(`Current frame: ${player.getCurrentFrame()}`);
console.log(`Duration: ${player.getDuration()}ms`);
console.log(`Is playing: ${player.isPlaying()}`);

// Resource cleanup
player.destroy();
```

#### Advanced Features

- **Lightweight and Efficient**: Uses dotlottie-web library for smaller size and better performance
- **Multiple Library Sources**: Supports built-in library (default), CDN loading, or externally provided custom libraries
- **Vue Framework Support**: Seamlessly supports Vue3 refs as container references
- **Multiple Sources**: Supports loading animations from URLs, JSON strings, or objects
- **Animation Events**: Provides rich callback functions to monitor animation state changes
- **Responsiveness**: Supports adaptive container sizing through the `resize()` method

### 🎬 Plyr Player (plyrPlayer)

Provides a wrapper for the Plyr media player, supporting both video and audio playback, with rich features and an easy-to-use API.

```typescript
import { createPlyrPlayer, playWithPlyr, createPlaylist } from 'mstf-kit';

// Quickly create a simple player
const player = await playWithPlyr(
  'https://example.com/video.mp4',
  '#player-container',
  { autoplay: true, muted: true }
);

// Use the complete API
const advancedPlayer = await createPlyrPlayer({
  container: '#player-container',
  source: {
    type: 'video',
    title: 'Example Video',
    sources: [
      {
        src: 'https://example.com/video.mp4',
        type: 'video/mp4'
      }
    ],
    poster: 'https://example.com/poster.jpg'
  },
  controls: ['play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'fullscreen'],
  i18n: {
    play: 'Play',
    pause: 'Pause',
    mute: 'Mute',
    volume: 'Volume'
  }
});

// Access enhanced features
await advancedPlayer.play();
advancedPlayer.addMarker(30, 'Important moment');
const screenshot = advancedPlayer.getCaptureImage();
advancedPlayer.downloadMedia('video.mp4');
```

#### Vue Integration

Seamlessly supports Vue3 refs as container references:

```typescript
import { ref, onMounted } from 'vue';
import { createPlyrPlayer } from 'mstf-kit';

export default {
  setup() {
    const playerRef = ref(null);
    let player = null;
    
    onMounted(async () => {
      player = await createPlyrPlayer({
        container: () => playerRef.value, // Use function to return the ref element
        source: { /* media source config */ }
      });
    });
    
    return { playerRef };
  }
}
```

#### Playlist Support

```typescript
// Create a playlist
const { player, next, previous, playIndex } = await createPlaylist(
  [
    'https://example.com/video1.mp4',
    'https://example.com/audio1.mp3',
    {
      type: 'video',
      sources: [{ src: 'https://example.com/video2.mp4', type: 'video/mp4' }]
    }
  ],
  '#playlist-container',
  { loop: { active: true } }
);

// Playback controls
next();       // Play next item
previous();   // Play previous item
playIndex(2); // Play item at specific index
```

#### Key Features

- **Multiple Loading Modes**: Supports CDN, npm, or externally provided Plyr library
- **Enhanced Functionality**: Screenshot capture, aspect ratio control, markers, picture-in-picture, etc.
- **Vue Integration**: Direct support for Vue refs as containers
- **Playlist**: Support for mixed media type playlists
- **Internationalization**: Built-in support for multiple languages
- **Rich Events**: Complete event callback system
- **TypeScript**: Full type definitions

#### Supported Configuration Options

- **Custom Controls**: Customizable control bar buttons
- **Video Ratio**: Support for various aspect ratios
- **Playback Speed**: Adjustable playback rate
- **Captions**: Support for multilingual subtitle tracks
- **Quality Switching**: Support for video quality selection

##### Powerful Enhanced Features

```typescript
// Change aspect ratio
player.changeAspectRatio('16:9');

// Enter picture-in-picture mode
await player.enterPictureInPicture();

// Add timeline markers
player.addMarker(45, 'Highlight', 'red');

// Capture current frame
const imageDataUrl = player.getCaptureImage();

// Download media file
player.downloadMedia('downloaded-video.mp4');

// Custom shortcuts
player.addShortcut('m', () => player.toggleMute());
```

#### Configuration Options in Detail

##### Control Buttons (controls)

Available control button options:

```typescript
controls: [
  'play-large',  // Large play button in the center
  'play',        // Play/pause button
  'progress',    // Progress bar
  'current-time', // Current time display
  'duration',    // Total duration display
  'mute',        // Mute button
  'volume',      // Volume control
  'captions',    // Captions button
  'settings',    // Settings button
  'pip',         // Picture-in-picture button
  'airplay',     // AirPlay button
  'fullscreen',  // Fullscreen button
  'restart',     // Restart button
  'fast-forward', // Fast-forward button
  'rewind'       // Rewind button
]
```

##### Complete Configuration Options

```typescript
// Complete player configuration options
{
  // Basic configuration
  container: '#player', // Player container (string selector, DOM element, or function returning DOM element)
  source: {             // Media source configuration
    type: 'video',      // 'video' or 'audio'
    title: 'Video Title', // Media title
    sources: [          // Media source list
      {
        src: 'https://example.com/video.mp4',
        type: 'video/mp4',
        size: 720       // Quality indicator (pixel height)
      }
    ],
    poster: 'https://example.com/poster.jpg', // Video poster image URL
    tracks: [           // Subtitle/chapter tracks
      {
        kind: 'captions',
        label: 'English',
        src: 'https://example.com/captions.en.vtt',
        srclang: 'en',
        default: true
      }
    ]
  },
  autoplay: false,      // Whether to autoplay
  muted: false,         // Whether to mute
  loop: { active: false }, // Whether to loop
  volume: 1.0,          // Default volume (0-1)
  
  // UI configuration
  controls: ['play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'fullscreen'],
  hideControls: true,   // Whether to auto-hide controls
  resetOnEnd: false,    // Whether to reset after playback ends
  fullscreen: {         // Fullscreen settings
    enabled: true,      // Whether to enable fullscreen
    fallback: true,     // Whether to use fallback if browser doesn't support native fullscreen
    iosNative: true     // Use native fullscreen on iOS
  },
  ratio: '16:9',        // Video aspect ratio
  storage: {            // Local storage
    enabled: true,      // Whether to enable storage
    key: 'plyr-volume'  // Storage key name
  },
  speed: {              // Playback speed settings
    selected: 1,        // Default speed
    options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2] // Available speed options
  },
  quality: {            // Video quality settings
    default: '720',     // Default quality
    options: ['1080', '720', '480', '360'] // Available quality options (corresponds to size in sources)
  },
  invertTime: false,    // Whether to invert time display (show remaining time)
  displayDuration: true, // Whether to display total duration
  markers: {            // Timeline markers
    enabled: true,      // Whether to enable markers
    points: [           // Marker list
      {
        time: 15,       // Marker time (seconds)
        label: 'Highlight', // Marker label
        color: 'red'    // Marker color
      }
    ]
  },
  
  // Localization text
  i18n: {
    restart: 'Restart',
    play: 'Play',
    pause: 'Pause',
    volume: 'Volume',
    mute: 'Mute',
    unmute: 'Unmute',
    pip: 'PIP',
    normal: 'Normal',
    settings: 'Settings',
    speed: 'Speed',
    quality: 'Quality',
    loop: 'Loop',
    start: 'Start',
    end: 'End',
    all: 'All',
    reset: 'Reset',
    disabled: 'Disabled',
    enabled: 'Enabled',
    advertisement: 'Ad',
    qualityLabel: {
      1080: '1080p',
      720: '720p',
      480: '480p',
      360: '360p'
    },
    captions: 'Captions',
    download: 'Download',
    enterFullscreen: 'Enter fullscreen',
    exitFullscreen: 'Exit fullscreen'
  },
  
  // Debug settings
  debug: false,         // Whether to enable debug mode
  loadSprite: true      // Whether to load SVG sprite
}
```

##### createPlyrPlayer Specific Options

```typescript
// Additional options for creating Plyr player
{
  // Plyr library loading options
  plyrLibOptions: {
    source: 'npm', // Where to load Plyr library from: 'cdn'(default), 'npm', 'local', 'external'
    cdnUrl: 'https://unpkg.com/plyr@3.7.8/dist/plyr.min.js', // Custom CDN URL
    cssUrl: 'https://unpkg.com/plyr@3.7.8/dist/plyr.css',    // Custom CSS URL
    externalLib: null // Externally provided Plyr library instance (used when source is 'external')
  },
  initOnLoad: true,     // Whether to initialize immediately on load
  autoCreateCss: true   // Whether to automatically include CSS
}
```

#### Enhanced Player API

The created enhanced Plyr player provides the following API:

```typescript
// Basic playback controls
player.play();            // Play
player.pause();           // Pause
player.stop();            // Stop
player.restart();         // Restart
player.rewind(10);        // Rewind 10 seconds
player.forward(10);       // Forward 10 seconds
player.increaseVolume(0.1); // Increase volume by 10%
player.decreaseVolume(0.1); // Decrease volume by 10%
player.togglePlay();      // Toggle play/pause
player.toggleMute();      // Toggle mute/unmute

// Status retrieval
player.isPlaying();       // Whether playing
player.isPaused();        // Whether paused
player.playing;           // Playing state
player.paused;            // Paused state
player.stopped;           // Stopped state

// Media properties
player.volume = 0.8;      // Set volume (0-1)
player.muted = true;      // Set mute
player.currentTime = 30;  // Set current playback position (seconds)
player.speed = 1.5;       // Set playback speed

// Enhanced features
player.getContainer();    // Get container element
player.getDefaultOptions(); // Get default options
player.setSource(newSource); // Set new media source
player.changeAspectRatio('4:3'); // Change video aspect ratio
player.addShortcut('m', () => player.toggleMute()); // Add shortcut
player.getCaptureImage(); // Capture current frame
player.downloadMedia('video.mp4'); // Download media
player.setPoster('https://example.com/poster.jpg'); // Set video poster
player.isFullscreen();    // Whether in fullscreen
player.enterPictureInPicture(); // Enter picture-in-picture mode
player.exitPictureInPicture();  // Exit picture-in-picture mode
player.togglePictureInPicture(); // Toggle picture-in-picture mode
player.reload();          // Reload media
player.getQualityOptions(); // Get available quality options
player.setQuality('720'); // Set video quality
player.getSpeedOptions(); // Get available speed options
player.setCustomControls(['play', 'volume']); // Set custom controls
player.addMarker(45, 'Highlight'); // Add timeline marker
player.removeMarker(45);  // Remove marker
player.clearMarkers();    // Clear all markers

// Event listeners
player.on('play', () => console.log('Started playing'));
player.once('ended', () => console.log('Playback ended'));
player.off('play', callback); // Remove event listener
```

#### Playlist API

```typescript
// Playlist controller
const { 
  player,                   // Player instance
  next,                     // Play next function
  previous,                 // Play previous function
  playIndex,                // Play specific index function
  currentIndex,             // Current playing index
  sources                   // Media source list
} = await createPlaylist(sources, container, options);

// Usage examples
next();                     // Play next
previous();                 // Play previous
playIndex(2);               // Play media at index 2
const currentPlaying = sources[currentIndex]; // Get current playing media info
```

#### Use Cases

- **Video Learning Platforms**: Create video players with support for markers, screenshots, and advanced controls
- **Online Video Streaming**: Build professional players with multi-quality, subtitles, and custom UI
- **Audio Applications**: Create audio players with playlist functionality
- **Mixed Media Presentation**: Support seamless switching between video and audio in the same player
- **Vue Integration**: Easily integrate advanced media playback features in Vue applications

### 🔌 WebSocket Utils

Provides efficient and reliable WebSocket connection management and communication tools.

- `createWebSocketClient(options: WebSocketOptions): WebSocketClient` - Create a WebSocket client
- `isWebSocketSupported(): boolean` - Check if the current environment supports WebSocket

#### WebSocket Client API

The WebSocket client (`WebSocketClient`) provides the following core features:

- **Automatic Reconnection** - Automatically attempts to reconnect when the network is disrupted
- **Heartbeat Detection** - Keeps the connection active and detects disconnections
- **Message Queue** - Automatically caches messages when offline and sends them when the connection is restored
- **Message Priority** - Supports high, medium, and low priority message handling
- **Event System** - Provides a rich set of event listening interfaces
- **Batch Sending** - Supports message batching to optimize network transmission
- **Timeout Handling** - Automatically handles message timeouts and retries
- **Complete Metrics** - Provides detailed connection and performance statistics

#### Basic Usage Example

```typescript
import { WebSocketClient, WebSocketState, MessagePriority } from 'mstf-kit';

// Create WebSocket client
const ws = new WebSocketClient({
  url: 'wss://example.com/socket',
  protocols: ['v1'],
  debug: true,               // Enable debug logging
  connectionTimeout: 8000,   // Connection timeout (ms)
  
  // Heartbeat configuration
  heartbeat: {
    enabled: true,
    interval: 30000,         // Send heartbeat every 30 seconds
    message: { type: 'ping' },
    timeout: 5000            // Consider timeout if no response after 5 seconds
  },
  
  // Automatic reconnection configuration
  reconnect: {
    enabled: true,
    maxRetries: 10,          // Maximum 10 retry attempts
    initialDelay: 1000,      // Initial retry delay of 1 second
    maxDelay: 30000,         // Maximum retry delay of 30 seconds
    factor: 1.5,             // Exponential backoff factor
    jitter: 0.5              // Random jitter coefficient
  }
});

// Connect to server
ws.connect()
  .then(() => {
    console.log('Connection successful');
    
    // Send message
    return ws.send({ type: 'hello', data: 'world' });
  })
  .catch(error => {
    console.error('Connection error:', error);
  });

// Listen for messages
ws.on('message', data => {
  console.log('Message received:', data);
});

// Listen for connection state changes
ws.on('close', event => {
  console.log('Connection closed:', event.code);
});

ws.on('reconnect', attempt => {
  console.log(`Reconnection successful (attempt ${attempt})`);
});

// Send messages with different priorities
ws.send(criticalData, { priority: MessagePriority.HIGH });
ws.send(normalData, { priority: MessagePriority.NORMAL });
ws.send(statsData, { priority: MessagePriority.LOW });

// Message expecting a server response
ws.send({ type: 'query', id: 'user-123' }, {
  expectResponse: true,      // Wait for response
  timeout: 5000,             // Response timeout
  retries: 2,                // Number of retries on timeout
  retryDelay: 1000           // Retry interval
}).then(response => {
  console.log('Response received:', response);
}).catch(error => {
  console.error('Request failed:', error);
});

// Get connection status and statistics
console.log('Current state:', ws.getState());
console.log('Connection latency:', ws.getLatency());
console.log('Statistics:', ws.getConnectionStats());

// Destroy resources when no longer used
ws.destroy();
```

#### Advanced Features

- **Batch Messages**: Suitable for scenarios requiring sending many small messages, automatically merges them into batch messages to reduce network overhead
- **Dynamic Configuration**: Adjust heartbeat, reconnection, and message handling configurations at runtime
- **Complete Lifecycle Management**: Automatically handles resource release to prevent memory leaks
- **Compatibility**: Supports various browser environments and Node.js

See the API documentation for more advanced usage.

## 📄 License

[MIT](./LICENSE) © [mustafa]