murmuraba
Version:
Real-time audio noise reduction with advanced chunked processing for web applications
122 lines (121 loc) • 4.17 kB
JavaScript
/**
* Unified time formatting utilities for consistent duration handling across the application.
* All durations are stored internally as milliseconds for precision.
*/
/**
* Convert time between different units
*/
export const convertTime = {
msToSeconds: (ms) => ms / 1000,
secondsToMs: (seconds) => seconds * 1000,
msToMinutes: (ms) => ms / (1000 * 60),
minutesToMs: (minutes) => minutes * 1000 * 60,
};
/**
* Validate and normalize time values
*/
export const normalizeTime = (time) => {
if (!isFinite(time) || time < 0)
return 0;
return time;
};
/**
* Core time formatting function that accepts milliseconds
* This is the single source of truth for time formatting
*/
export const formatDuration = (milliseconds, options = {}) => {
const { format = 'mm:ss', showHours = false, precision = 'seconds' } = options;
const normalizedMs = normalizeTime(milliseconds);
if (normalizedMs === 0)
return format === 'compact' ? '0s' : '0:00';
const totalSeconds = precision === 'milliseconds'
? normalizedMs / 1000
: Math.floor(normalizedMs / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = Math.floor(totalSeconds % 60);
const ms = Math.floor(normalizedMs % 1000);
switch (format) {
case 'compact':
if (hours > 0)
return `${hours}h ${minutes}m`;
if (minutes > 0)
return `${minutes}m ${seconds}s`;
return `${seconds}s`;
case 'hh:mm:ss':
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
case 'mm:ss':
default: {
if (showHours && hours > 0) {
return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
const totalMinutes = Math.floor(totalSeconds / 60);
const remainingSeconds = Math.floor(totalSeconds % 60);
if (precision === 'milliseconds' && ms > 0) {
return `${totalMinutes}:${remainingSeconds.toString().padStart(2, '0')}.${Math.floor(ms / 100)}`;
}
return `${totalMinutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}
}
};
/**
* Legacy compatibility - formats seconds to mm:ss
* @deprecated Use formatDuration with convertTime.secondsToMs() instead
*/
export const formatTime = (seconds) => {
return formatDuration(convertTime.secondsToMs(seconds));
};
/**
* Format duration with automatic unit detection and user-friendly labels
*/
export const formatDurationWithLabel = (milliseconds) => {
const ms = normalizeTime(milliseconds);
if (ms < 1000)
return `${ms}ms`;
if (ms < 60000)
return `${(ms / 1000).toFixed(1)}s`;
if (ms < 3600000)
return formatDuration(ms, { format: 'mm:ss' });
return formatDuration(ms, { format: 'hh:mm:ss' });
};
/**
* Create a time formatter with consistent options
*/
export const createTimeFormatter = (options = {}) => {
return (milliseconds) => formatDuration(milliseconds, options);
};
/**
* Utility for chunk duration statistics
*/
export const calculateDurationStats = (durations) => {
if (durations.length === 0) {
return {
total: 0,
average: 0,
min: 0,
max: 0,
totalFormatted: '0:00',
averageFormatted: '0:00',
};
}
const total = durations.reduce((sum, duration) => sum + duration, 0);
const average = total / durations.length;
const min = Math.min(...durations);
const max = Math.max(...durations);
return {
total,
average,
min,
max,
totalFormatted: formatDuration(total),
averageFormatted: formatDuration(average),
minFormatted: formatDuration(min),
maxFormatted: formatDuration(max),
};
};
/**
* Type guard for time values
*/
export const isValidTime = (value) => {
return typeof value === 'number' && isFinite(value) && value >= 0;
};