timecode-converter
Version:
Modern TypeScript library for broadcast timecode conversions with full SMPTE drop-frame support
1 lines • 30.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/dropFrameHelpers.ts","../src/secondsToTimecode.ts","../src/timecodeToSeconds.ts","../src/padTimeToTimecode.ts","../src/validateTimecode.ts","../src/index.ts"],"names":["hours","minutes","secs","frames"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { FrameRate } from \"./types\"\n\n/**\n * Check if a timecode string is in drop-frame format\n * Drop-frame timecodes use semicolon before frames: hh:mm:ss;ff\n */\nexport const isDropFrameTimecode = (tc: string): boolean => {\n return tc.includes(\";\")\n}\n\n/**\n * Check if a frame rate supports drop-frame\n * Only 29.97 and 59.94 fps support drop-frame in SMPTE standard\n */\nexport const isDropFrameRate = (fps: FrameRate): boolean => {\n return Math.abs(fps - 29.97) < 0.01 || Math.abs(fps - 59.94) < 0.01\n}\n\n/**\n * Calculate the number of frames to drop for drop-frame timecode\n * SMPTE standard: Drop 2 frames per minute for 29.97, 4 frames for 59.94\n * Except every 10th minute (00, 10, 20, 30, 40, 50)\n */\nexport const calculateDroppedFrames = (hours: number, minutes: number, frameRate: FrameRate): number => {\n if (!isDropFrameRate(frameRate)) return 0\n\n const dropFramesPerMinute = Math.abs(frameRate - 29.97) < 0.01 ? 2 : 4\n const totalMinutes = hours * 60 + minutes\n\n // Calculate minutes where frames are dropped\n // Every minute drops frames except every 10th minute\n const droppedMinutes = totalMinutes - Math.floor(totalMinutes / 10)\n\n return droppedMinutes * dropFramesPerMinute\n}\n\n/**\n * Convert drop-frame timecode to total frames\n * Accounts for the dropped frame numbers in the calculation\n */\nexport const dropFrameTimecodeToFrames = (\n hours: number,\n minutes: number,\n seconds: number,\n frames: number,\n frameRate: FrameRate,\n): number => {\n // Calculate nominal frames (as if no frames were dropped)\n const nominalFps = Math.round(frameRate)\n let totalFrames = frames\n totalFrames += seconds * nominalFps\n totalFrames += minutes * nominalFps * 60\n totalFrames += hours * nominalFps * 60 * 60\n\n // Subtract the dropped frames\n const droppedFrames = calculateDroppedFrames(hours, minutes, frameRate)\n\n return totalFrames - droppedFrames\n}\n\n/**\n * Convert frame count to drop-frame timecode components\n * This reverses the drop-frame calculation\n */\nexport const framesToDropFrameTimecode = (\n frameCount: number,\n frameRate: FrameRate,\n): { hours: number; minutes: number; seconds: number; frames: number } => {\n const nominalFps = Math.round(frameRate)\n const dropFramesPerMinute = Math.abs(frameRate - 29.97) < 0.01 ? 2 : 4\n\n // Calculate how many frames per minute (accounting for drops)\n const actualFramesPerMinute = nominalFps * 60 - dropFramesPerMinute\n // Frames in a 10-minute segment (9 minutes with drops, 1 without)\n const framesPer10Minutes = actualFramesPerMinute * 9 + nominalFps * 60\n\n // Calculate which 10-minute segment we're in\n const tenMinuteSegments = Math.floor(frameCount / framesPer10Minutes)\n let remainingFrames = frameCount % framesPer10Minutes\n\n // Calculate additional minutes within the 10-minute segment\n let additionalMinutes = 0\n if (remainingFrames >= nominalFps * 60) {\n // We're past the first minute (which has no drops in each 10-min segment)\n remainingFrames -= nominalFps * 60\n additionalMinutes = 1 + Math.floor(remainingFrames / actualFramesPerMinute)\n remainingFrames = remainingFrames % actualFramesPerMinute\n }\n\n // Calculate total time components\n const totalMinutes = tenMinuteSegments * 10 + additionalMinutes\n const hours = Math.floor(totalMinutes / 60)\n const minutes = totalMinutes % 60\n\n // For display purposes, we need to add back the dropped frames\n // when we're in a minute that has drops\n let displayFrames = remainingFrames\n if (minutes % 10 !== 0 && additionalMinutes > 0) {\n // We're in a minute with drops, add them back for display\n displayFrames += dropFramesPerMinute\n }\n\n const seconds = Math.floor(displayFrames / nominalFps)\n const frames = displayFrames % nominalFps\n\n return { hours, minutes, seconds, frames }\n}\n","import type { Seconds, FrameRate, TimecodeFormat } from \"./types\"\nimport { isDropFrameRate, framesToDropFrameTimecode } from \"./dropFrameHelpers\"\n\n/**\n * Raised in this comment https://github.com/bbc/react-transcript-editor/pull/9\n * abstracted from https://github.com/bbc/newslabs-cdn/blob/master/js/20-bbcnpf.utils.js\n * In broadcast VIDEO, timecode is NOT hh:mm:ss:ms, it's hh:mm:ss:ff where ff is frames,\n * dependent on the framerate of the media concerned.\n * `hh:mm:ss:ff`\n */\n\n/**\n * Helper function\n * Rounds to frame boundaries with proper floating-point precision handling\n * Time in video can only \"exist in\" frame boundaries.\n * This makes it possible for the HTML5 player to be frame accurate.\n */\nconst normalisePlayerTime = (seconds: Seconds, fps: FrameRate): number => {\n // Use high precision calculation to avoid floating-point errors\n const totalFrames = Math.floor(Number((fps * seconds).toPrecision(12)))\n return Number((totalFrames / fps).toFixed(2))\n}\n\n/**\n * Prepends zero - example pads 3 to 03\n */\nconst padZero = (n: number): string => {\n if (n < 10) return `0${Math.floor(n)}`\n return String(Math.floor(n))\n}\n\n/**\n * Convert seconds to broadcast timecode format\n * @param seconds - Time in seconds\n * @param frameRate - Frames per second (required)\n * @param dropFrame - Generate drop-frame format. If not specified:\n * - For 29.97/59.94 fps: Uses drop-frame for durations ≥ 1 minute\n * - For other frame rates: Always non-drop frame\n * @returns Timecode in format:\n * - Non-drop: hh:mm:ss:ff (colons)\n * - Drop-frame: hh:mm:ss;ff (semicolon before frames)\n * @example\n * secondsToTimecode(3600, 29.97) // \"01:00:00;00\" (auto drop-frame)\n * secondsToTimecode(30, 29.97) // \"00:00:30:00\" (auto non-drop for short duration)\n * secondsToTimecode(3600, 29.97, false) // \"01:00:00:00\" (forced non-drop)\n * secondsToTimecode(3600, 25) // \"01:00:00:00\" (always non-drop for PAL)\n */\nconst secondsToTimecode = (seconds: Seconds, frameRate: FrameRate, dropFrame?: boolean): TimecodeFormat => {\n // Determine if we should use drop-frame\n let useDropFrame: boolean\n\n if (dropFrame !== undefined) {\n // Explicit preference from user\n useDropFrame = dropFrame\n } else if (isDropFrameRate(frameRate)) {\n // Auto-detect based on duration for drop-frame rates\n // Use drop-frame for durations >= 1 minute to maintain accuracy\n useDropFrame = seconds >= 60\n } else {\n // Non-drop frame rates never use drop-frame\n useDropFrame = false\n }\n\n // Only warn if user explicitly chose non-drop frame for long durations\n if (dropFrame === false && isDropFrameRate(frameRate) && seconds >= 3600) {\n console.warn(\n `Warning: Converting ${seconds} seconds at ${frameRate} fps without drop-frame. ` +\n `For durations over 1 hour, consider using drop-frame format for accurate broadcast timecode. ` +\n `After ${Math.floor(seconds / 3600)} hour(s), drift is approximately ${Math.round((seconds / 3600) * 3.6)} seconds.`,\n )\n }\n\n // Check if this is a valid drop-frame scenario\n if (useDropFrame && isDropFrameRate(frameRate)) {\n // Calculate total frames for drop-frame\n const totalFrames = Math.round(seconds * frameRate)\n const { hours, minutes, seconds: secs, frames } = framesToDropFrameTimecode(totalFrames, frameRate)\n\n // Format with semicolon for drop-frame\n return `${padZero(hours)}:${padZero(minutes)}:${padZero(secs)};${padZero(frames)}`\n }\n\n // Non-drop frame calculation (original logic)\n // handle edge case, trying to convert zero seconds\n if (seconds === 0) {\n return \"00:00:00:00\"\n }\n\n const fps = frameRate\n const normalisedSeconds = normalisePlayerTime(seconds, fps)\n const wholeSeconds = Math.floor(normalisedSeconds)\n\n // Calculate frames with precision handling to avoid floating-point errors\n const framesPrecise = (normalisedSeconds - wholeSeconds) * fps\n const frames = Math.round(framesPrecise * 100) / 100 // Round to 2 decimal places before flooring\n\n const hours = Math.floor(wholeSeconds / 3600)\n const minutes = Math.floor((wholeSeconds % 3600) / 60)\n const secs = wholeSeconds % 60\n\n return `${padZero(hours)}:${padZero(minutes)}:${padZero(secs)}:${padZero(frames)}`\n}\n\nexport default secondsToTimecode\n","import type { TimecodeFormat, FrameRate, Seconds } from \"./types\"\nimport { isDropFrameTimecode, isDropFrameRate, dropFrameTimecodeToFrames } from \"./dropFrameHelpers\"\n\n/**\n * Parse timecode string into components\n * Handles both drop-frame (semicolon) and non-drop (colon) formats\n */\nconst parseTimecode = (\n tc: TimecodeFormat,\n): { hours: number; minutes: number; seconds: number; frames: number; isDropFrame: boolean } => {\n const isDropFrame = isDropFrameTimecode(tc)\n // Normalize format for parsing (replace semicolon with colon)\n const normalized = tc.replace(\";\", \":\")\n const parts = normalized.split(\":\")\n\n return {\n hours: parseInt(parts[0]!, 10),\n minutes: parseInt(parts[1]!, 10),\n seconds: parseInt(parts[2]!, 10),\n frames: parseInt(parts[3]!, 10),\n isDropFrame,\n }\n}\n\n/**\n * Helper function for non-drop frame calculations\n * @param tc - Timecode string\n * @param fps - Frames per second\n * @returns Total number of frames\n */\nconst timecodeToFrames = (tc: TimecodeFormat, fps: FrameRate): number => {\n const { hours, minutes, seconds, frames, isDropFrame } = parseTimecode(tc)\n\n if (isDropFrame && isDropFrameRate(fps)) {\n // Use drop-frame calculation\n return dropFrameTimecodeToFrames(hours, minutes, seconds, frames, fps)\n }\n\n // Non-drop frame calculation\n let totalFrames = frames\n totalFrames += seconds * fps\n totalFrames += minutes * fps * 60\n totalFrames += hours * fps * 60 * 60\n\n return totalFrames\n}\n\n/**\n * Convert broadcast timecodes to seconds\n * @param tc - Timecode in format:\n * - Non-drop: `hh:mm:ss:ff` (colons)\n * - Drop-frame: `hh:mm:ss;ff` (semicolon before frames)\n * @param frameRate - Frames per second (required)\n * @returns Time in seconds\n *\n * Drop-frame is auto-detected from format:\n * - Semicolon (;) = drop-frame calculation\n * - Colon (:) = non-drop frame calculation\n */\nconst timecodeToSecondsHelper = (tc: TimecodeFormat, frameRate: FrameRate): Seconds => {\n const fps = frameRate\n\n // Warn if using drop-frame format with non-drop-frame rates\n if (isDropFrameTimecode(tc) && !isDropFrameRate(fps)) {\n console.warn(\n `Warning: Drop-frame timecode format (${tc}) used with non-drop-frame rate ${fps} fps. ` +\n `Drop-frame is only valid for 29.97 and 59.94 fps.`,\n )\n }\n\n const frames = timecodeToFrames(tc, fps)\n\n return Number((frames / fps).toFixed(2))\n}\n\nexport default timecodeToSecondsHelper\n","import type { TimecodeFormat } from \"./types\"\n\nconst countColon = (timecode: string): number => timecode.split(\":\").length\n\nconst includesFullStop = (timecode: string): boolean => timecode.includes(\".\")\n\nconst isOneDigit = (str: string): boolean => str.length === 1\n\n/**\n * Pads various time formats to standard timecode format\n * @param time - Time in various formats (hh:mm:ss:ff, mm:ss, m:ss, m.ss, s)\n * @returns Standard timecode format hh:mm:ss:ff\n */\nconst padTimeToTimecode = (time: string | number): TimecodeFormat | number => {\n if (typeof time === \"string\") {\n // Check if it's drop-frame format (contains semicolon)\n const isDropFrame = time.includes(\";\")\n\n // For drop-frame, count all separators (: and ;)\n const separatorCount = isDropFrame ? time.split(/[:;]/).length : countColon(time)\n\n switch (separatorCount) {\n case 4:\n // is already in timecode format\n // hh:mm:ss:ff or hh:mm:ss;ff\n return time\n case 2: {\n // m:ss or mm:ss\n const parts = time.split(\":\")\n if (isOneDigit(parts[0]!)) {\n return `00:0${time}:00`\n }\n return `00:${time}:00`\n }\n case 3:\n // hh:mm:ss\n return `${time}:00`\n default: {\n // mm.ss or m.ss\n if (includesFullStop(time)) {\n const parts = time.split(\".\")\n // m.ss\n if (isOneDigit(parts[0]!)) {\n return `00:0${parts[0]}:${parts[1]}:00`\n }\n return `00:${time.replace(\".\", \":\")}:00`\n }\n\n // if just int, then it's seconds\n // s or ss\n if (isOneDigit(time)) {\n return `00:00:0${time}:00`\n }\n return `00:00:${time}:00`\n }\n }\n }\n // edge case if it's number return a number coz cannot refactor\n // TODO: might need to refactor and move this elsewhere\n return time\n}\n\nexport default padTimeToTimecode\n","import type { TimecodeFormat, FrameRate } from \"./types\"\nimport { isDropFrameTimecode, isDropFrameRate } from \"./dropFrameHelpers\"\n\nexport interface TimecodeValidationResult {\n valid: boolean\n errors: string[]\n warnings: string[]\n format?: \"drop-frame\" | \"non-drop\"\n components?: {\n hours: number\n minutes: number\n seconds: number\n frames: number\n }\n}\n\n/**\n * Validate a timecode string and provide detailed feedback\n * @param timecode - Timecode string to validate\n * @param frameRate - Frame rate to validate against (optional)\n * @returns Validation result with errors, warnings, and parsed components\n * @example\n * validateTimecode(\"01:00:00;00\", 29.97)\n * // { valid: true, format: \"drop-frame\", components: {...} }\n *\n * validateTimecode(\"25:00:00:00\", 25)\n * // { valid: false, errors: [\"Hours cannot exceed 23\"] }\n *\n * validateTimecode(\"00:00:00;00\", 25)\n * // { valid: true, warnings: [\"Drop-frame format used with non-drop-frame rate 25 fps\"] }\n */\nexport function validateTimecode(timecode: TimecodeFormat, frameRate?: FrameRate): TimecodeValidationResult {\n const errors: string[] = []\n const warnings: string[] = []\n\n // Check basic format\n const dropFrameFormat = isDropFrameTimecode(timecode)\n const format = dropFrameFormat ? \"drop-frame\" : \"non-drop\"\n\n // Normalize semicolon to colon for parsing\n const normalized = timecode.replace(\";\", \":\")\n const parts = normalized.split(\":\")\n\n // Check part count\n if (parts.length !== 4) {\n errors.push(`Invalid timecode format. Expected hh:mm:ss:ff or hh:mm:ss;ff, got ${timecode}`)\n return { valid: false, errors, warnings }\n }\n\n // Parse components with null checks\n const hours = parts[0] ? parseInt(parts[0], 10) : NaN\n const minutes = parts[1] ? parseInt(parts[1], 10) : NaN\n const seconds = parts[2] ? parseInt(parts[2], 10) : NaN\n const frames = parts[3] ? parseInt(parts[3], 10) : NaN\n\n // Validate ranges\n if (isNaN(hours) || hours < 0) {\n errors.push(\"Hours must be a valid non-negative number\")\n } else if (hours > 23) {\n errors.push(\"Hours cannot exceed 23\")\n }\n\n if (isNaN(minutes) || minutes < 0) {\n errors.push(\"Minutes must be a valid non-negative number\")\n } else if (minutes > 59) {\n errors.push(\"Minutes cannot exceed 59\")\n }\n\n if (isNaN(seconds) || seconds < 0) {\n errors.push(\"Seconds must be a valid non-negative number\")\n } else if (seconds > 59) {\n errors.push(\"Seconds cannot exceed 59\")\n }\n\n if (isNaN(frames) || frames < 0) {\n errors.push(\"Frames must be a valid non-negative number\")\n }\n\n // Frame rate specific validation\n if (frameRate !== undefined) {\n const maxFrames = Math.round(frameRate) - 1\n if (frames > maxFrames) {\n errors.push(`Frames cannot exceed ${maxFrames} for ${frameRate} fps`)\n }\n\n // Drop-frame specific validation\n if (dropFrameFormat) {\n if (!isDropFrameRate(frameRate)) {\n warnings.push(\n `Drop-frame format used with non-drop-frame rate ${frameRate} fps. Drop-frame is only valid for 29.97 and 59.94 fps.`,\n )\n } else {\n // Check for invalid drop-frame timecodes\n // In drop-frame, frames 00 and 01 don't exist at minute boundaries (except every 10th minute)\n if (seconds === 0 && minutes % 10 !== 0 && frames < 2) {\n errors.push(`Invalid drop-frame timecode. Frames 00 and 01 don't exist at minute ${minutes}`)\n }\n }\n }\n }\n\n // Check for drop-frame format without frame rate\n if (dropFrameFormat && frameRate === undefined) {\n warnings.push(\"Drop-frame format detected but no frame rate provided for validation\")\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n format,\n components: errors.length === 0 ? { hours, minutes, seconds, frames } : undefined,\n }\n}\n","/**\n * Wrapping around \"time stamps\" and timecode conversion modules\n * To provide more support for variety of formats.\n */\nimport secondsToTimecode from \"./secondsToTimecode\"\nimport timecodeToSecondsHelper from \"./timecodeToSeconds\"\nimport padTimeToTimecode from \"./padTimeToTimecode\"\nimport type { Seconds } from \"./types\"\n\n/**\n * Convert various time formats to seconds\n * @param time - Can take as input timecodes in the following formats:\n * - hh:mm:ss:ff\n * - mm:ss\n * - m:ss\n * - ss - seconds --> if it's already in seconds then it just returns seconds\n * - hh:mm:ff\n * - m.ss\n * @param frameRate - Frames per second (must be specified for timecode strings)\n * @returns Time in seconds\n * @todo could be refactored with some helper functions for clarity\n */\nconst timecodeToSeconds = (time: string | number, frameRate?: number): Seconds => {\n if (typeof time === \"string\") {\n if (frameRate === undefined) {\n throw new Error(\"Frame rate must be specified when converting timecode strings to seconds\")\n }\n const resultPadded = padTimeToTimecode(time)\n if (typeof resultPadded === \"string\") {\n const resultConverted = timecodeToSecondsHelper(resultPadded, frameRate)\n return resultConverted\n }\n // This shouldn't happen based on current logic, but for type safety\n return resultPadded\n }\n\n // assuming it receives timecode as seconds as number\n return parseFloat(String(time))\n}\n\n/**\n * Get shortened timecode without frames\n * @param time - Time in seconds or timecode format\n * @param frameRate - Frames per second (required)\n * @param dropFrame - Generate drop-frame format (auto-detected from input format if string)\n * @returns Timecode in format hh:mm:ss\n */\nconst shortTimecode = (time: number | string, frameRate: number, dropFrame?: boolean): string => {\n // handle edge case if it's zero, then just return shorter timecode\n if (time === 0) {\n return \"00:00:00\"\n } else {\n // Auto-detect drop-frame from input format if not specified\n const useDropFrame = dropFrame !== undefined ? dropFrame : typeof time === \"string\" && time.includes(\";\")\n\n const seconds = typeof time === \"string\" ? timecodeToSeconds(time, frameRate) : time\n const timecode = secondsToTimecode(seconds, frameRate, useDropFrame)\n return timecode.slice(0, -3)\n }\n}\n\n// Export main functions\nexport { secondsToTimecode, timecodeToSeconds, shortTimecode }\n\n// Export validation function\nexport { validateTimecode } from \"./validateTimecode\"\nexport type { TimecodeValidationResult } from \"./validateTimecode\"\n\n// Export drop-frame helpers for advanced users\nexport { isDropFrameTimecode, isDropFrameRate } from \"./dropFrameHelpers\"\n\n// Export types\nexport type { Seconds, TimecodeFormat, FrameRate, TimecodeOptions } from \"./types\"\n"]}