Utility Functions
MediaFox provides several utility functions for common media-related operations.
Time Utilities
formatTime(seconds, showMilliseconds?)
Formats seconds into a human-readable time string.
formatTime(seconds: number, showMilliseconds?: boolean): stringParameters:
seconds: Time in secondsshowMilliseconds: Whether to show milliseconds (default:false)
Returns: Formatted time string
Examples:
import { formatTime } from '@mediafox/core';
formatTime(65); // "1:05"
formatTime(3665); // "1:01:05"
formatTime(65.5, true); // "1:05.500"
formatTime(-30); // "-0:30"parseTime(timeString)
Parses a time string into seconds.
parseTime(timeString: string): numberParameters:
timeString: Time string in format "HH:MM:SS", "MM:SS", or "SS"
Returns: Time in seconds
Examples:
import { parseTime } from '@mediafox/core';
parseTime("1:30"); // 90
parseTime("1:01:30"); // 3690
parseTime("45"); // 45
parseTime("2:30:45"); // 9045timeToFrame(time, frameRate)
Converts time to frame number.
timeToFrame(time: number, frameRate: number): numberParameters:
time: Time in secondsframeRate: Frame rate in Hz
Returns: Frame number
Example:
import { timeToFrame } from '@mediafox/core';
timeToFrame(1.5, 30); // 45 (1.5 seconds at 30fps)
timeToFrame(2, 24); // 48 (2 seconds at 24fps)frameToTime(frame, frameRate)
Converts frame number to time.
frameToTime(frame: number, frameRate: number): numberParameters:
frame: Frame numberframeRate: Frame rate in Hz
Returns: Time in seconds
Example:
import { frameToTime } from '@mediafox/core';
frameToTime(45, 30); // 1.5 (45 frames at 30fps)
frameToTime(48, 24); // 2 (48 frames at 24fps)Range Utilities
clamp(value, min, max)
Clamps a value between minimum and maximum bounds.
clamp(value: number, min: number, max: number): numberParameters:
value: Value to clampmin: Minimum valuemax: Maximum value
Returns: Clamped value
Example:
import { clamp } from '@mediafox/core';
clamp(5, 0, 10); // 5
clamp(-5, 0, 10); // 0
clamp(15, 0, 10); // 10timeRangesOverlap(range1, range2)
Checks if two time ranges overlap.
timeRangesOverlap(
range1: { start: number; end: number },
range2: { start: number; end: number }
): booleanParameters:
range1: First time rangerange2: Second time range
Returns: true if ranges overlap
Example:
import { timeRangesOverlap } from '@mediafox/core';
const range1 = { start: 0, end: 10 };
const range2 = { start: 5, end: 15 };
const range3 = { start: 15, end: 20 };
timeRangesOverlap(range1, range2); // true
timeRangesOverlap(range1, range3); // falsemergeTimeRanges(ranges)
Merges overlapping time ranges into continuous segments.
mergeTimeRanges(
ranges: Array<{ start: number; end: number }>
): Array<{ start: number; end: number }>Parameters:
ranges: Array of time ranges to merge
Returns: Array of merged time ranges
Example:
import { mergeTimeRanges } from '@mediafox/core';
const ranges = [
{ start: 0, end: 10 },
{ start: 5, end: 15 },
{ start: 20, end: 30 }
];
const merged = mergeTimeRanges(ranges);
// [{ start: 0, end: 15 }, { start: 20, end: 30 }]totalBufferedDuration(ranges)
Calculates the total duration of buffered ranges.
totalBufferedDuration(
ranges: Array<{ start: number; end: number }>
): numberParameters:
ranges: Array of time ranges
Returns: Total duration in seconds
Example:
import { totalBufferedDuration } from '@mediafox/core';
const buffered = [
{ start: 0, end: 10 },
{ start: 15, end: 25 },
{ start: 30, end: 35 }
];
totalBufferedDuration(buffered); // 25 seconds totalfindBufferedRange(ranges, time)
Finds the buffered range containing a specific time.
findBufferedRange(
ranges: Array<{ start: number; end: number }>,
time: number
): { start: number; end: number } | nullParameters:
ranges: Array of time rangestime: Time to search for
Returns: The containing range or null
Example:
import { findBufferedRange } from '@mediafox/core';
const buffered = [
{ start: 0, end: 10 },
{ start: 15, end: 25 }
];
findBufferedRange(buffered, 5); // { start: 0, end: 10 }
findBufferedRange(buffered, 20); // { start: 15, end: 25 }
findBufferedRange(buffered, 12); // nullError Handling
MediaFoxError
Custom error class for player errors.
class MediaFoxError extends Error {
code: ErrorCode;
details?: any;
constructor(code: ErrorCode, message: string, details?: any)
}Static Factory Methods:
// Create specific error types
MediaFoxError.mediaNotSupported(message?, details?);
MediaFoxError.mediaLoadFailed(message?, details?);
MediaFoxError.decodeError(message?, details?);
MediaFoxError.networkError(message?, details?);
MediaFoxError.permissionDenied(message?, details?);
MediaFoxError.playbackError(message?, details?);
MediaFoxError.trackNotFound(message?, details?);
MediaFoxError.invalidState(message?, details?);
MediaFoxError.unknownError(message?, details?);Example:
import { MediaFoxError, ErrorCode } from '@mediafox/core';
// Handle player errors
player.on('error', (error) => {
switch (error.code) {
case ErrorCode.MEDIA_NOT_SUPPORTED:
console.error('Format not supported');
break;
case ErrorCode.NETWORK_ERROR:
console.error('Network issue:', error.details);
break;
default:
console.error('Player error:', error.message);
}
});
// Create custom errors
throw MediaFoxError.mediaNotSupported(
'WebM format not supported in this browser'
);ErrorCode
Enumeration of error codes.
enum ErrorCode {
MEDIA_NOT_SUPPORTED = 'MEDIA_NOT_SUPPORTED',
MEDIA_LOAD_FAILED = 'MEDIA_LOAD_FAILED',
DECODE_ERROR = 'DECODE_ERROR',
NETWORK_ERROR = 'NETWORK_ERROR',
PERMISSION_DENIED = 'PERMISSION_DENIED',
PLAYBACK_ERROR = 'PLAYBACK_ERROR',
TRACK_NOT_FOUND = 'TRACK_NOT_FOUND',
INVALID_STATE = 'INVALID_STATE',
UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}wrapError(error, context)
Wraps any error with additional context.
wrapError(error: unknown, context: string): MediaFoxErrorParameters:
error: Original errorcontext: Context string for the error
Returns: MediaFoxError instance
Example:
import { wrapError } from '@mediafox/core';
try {
await loadMedia();
} catch (error) {
throw wrapError(error, 'Failed to load media file');
}Component Classes
EventEmitter
Type-safe event emitter implementation.
class EventEmitter<EventMap extends Record<string, any>> {
on<K extends keyof EventMap>(
event: K,
listener: (data: EventMap[K]) => void
): UnsubscribeFn
once<K extends keyof EventMap>(
event: K,
listener: (data: EventMap[K]) => void
): UnsubscribeFn
off<K extends keyof EventMap>(
event: K,
listener?: (data: EventMap[K]) => void
): void
emit<K extends keyof EventMap>(
event: K,
data: EventMap[K]
): void
}Example:
import { EventEmitter } from '@mediafox/core';
// Define event map
type MyEvents = {
connect: { id: string };
disconnect: void;
message: { text: string };
};
// Create emitter
const emitter = new EventEmitter<MyEvents>();
// Listen to events
emitter.on('connect', ({ id }) => {
console.log(`Connected: ${id}`);
});
// Emit events
emitter.emit('connect', { id: '123' });Store
Reactive state store with subscriptions.
class Store<T> {
constructor(initialState: T)
subscribe(listener: (state: T) => void): StateUnsubscribe
getState(): T
setState(updater: Partial<T> | ((state: T) => Partial<T>)): void
}Example:
import { Store } from '@mediafox/core';
// Create store
const store = new Store({
count: 0,
message: 'Hello'
});
// Subscribe to changes
const unsub = store.subscribe(state => {
console.log(`Count: ${state.count}`);
});
// Update state
store.setState({ count: 1 });
store.setState(state => ({ count: state.count + 1 }));
// Get current state
const current = store.getState();
// Unsubscribe
unsub();Constants
Quality Levels
Pre-defined quality constants from Mediabunny:
import {
QUALITY_VERY_LOW,
QUALITY_LOW,
QUALITY_MEDIUM,
QUALITY_HIGH,
QUALITY_VERY_HIGH
} from 'mediabunny';
// Use for screenshot quality
player.screenshot({
format: 'jpeg',
quality: QUALITY_HIGH
});TIP
These quality constants are exported directly from mediabunny. Since mediabunny is a peer dependency, import them from 'mediabunny' rather than '@mediafox/core'.
Version
Library version string:
import { VERSION } from '@mediafox/core';
console.log(`MediaFox version: ${VERSION}`);Usage Examples
Progress Bar Implementation
import { formatTime, clamp } from '@mediafox/core';
// Update progress bar
player.subscribe(state => {
const percent = (state.currentTime / state.duration) * 100;
progressBar.style.width = `${percent}%`;
timeDisplay.textContent = formatTime(state.currentTime);
});
// Handle seeking
progressBar.addEventListener('click', (e) => {
const rect = progressBar.getBoundingClientRect();
const percent = clamp((e.clientX - rect.left) / rect.width, 0, 1);
const time = percent * player.duration;
player.seek(time);
});Buffering Display
import { totalBufferedDuration, mergeTimeRanges } from '@mediafox/core';
player.subscribe(state => {
const buffered = mergeTimeRanges(state.buffered);
const totalBuffered = totalBufferedDuration(buffered);
bufferedDisplay.textContent = `Buffered: ${formatTime(totalBuffered)}`;
// Show buffered segments
buffered.forEach(range => {
const startPercent = (range.start / state.duration) * 100;
const widthPercent = ((range.end - range.start) / state.duration) * 100;
createBufferedSegment(startPercent, widthPercent);
});
});Frame-Accurate Navigation
import { timeToFrame, frameToTime } from '@mediafox/core';
const frameRate = 24; // Get from video track
// Navigate by frames
function nextFrame() {
const currentFrame = timeToFrame(player.currentTime, frameRate);
const nextTime = frameToTime(currentFrame + 1, frameRate);
player.seek(nextTime, { accurate: true });
}
function previousFrame() {
const currentFrame = timeToFrame(player.currentTime, frameRate);
const prevTime = frameToTime(Math.max(0, currentFrame - 1), frameRate);
player.seek(prevTime, { accurate: true });
}