JAVASCRIPT   7

time.js

Guest on 20th July 2021 03:32:53 PM

  1. 'use strict';
  2.  
  3. import mejs from '../core/mejs';
  4.  
  5. /**
  6.  * Indicate if FPS is dropFrame (typically non-integer frame rates: 29.976)
  7.  *
  8.  * @param {Number} fps - Frames per second
  9.  * @return {Boolean}
  10.  */
  11. export function isDropFrame(fps = 25) {
  12.         return !(fps % 1 === 0);
  13. }
  14. /**
  15.  * Format a numeric time in format '00:00:00'
  16.  *
  17.  * @param {Number} time - Ideally a number, but if not or less than zero, is defaulted to zero
  18.  * @param {Boolean} forceHours
  19.  * @param {Boolean} showFrameCount
  20.  * @param {Number} fps - Frames per second
  21.  * @param {Number} secondsDecimalLength - Number of decimals to display if any
  22.  * @param {String} timeFormat
  23.  * @return {String}
  24.  */
  25. export function secondsToTimeCode(time, forceHours = false, showFrameCount = false, fps = 25, secondsDecimalLength = 0, timeFormat = 'hh:mm:ss') {
  26.  
  27.         time = !time || typeof time !== 'number' || time < 0 ? 0 : time;
  28.  
  29.         let
  30.                 dropFrames = Math.round(fps * 0.066666), // Number of drop frames to drop on the minute marks (6%)
  31.                 timeBase = Math.round(fps),
  32.                 framesPer24Hours = Math.round(fps * 3600) * 24,
  33.                 framesPer10Minutes = Math.round(fps * 600),
  34.                 frameSep = isDropFrame(fps) ? ';' : ':',
  35.                 hours,
  36.                 minutes,
  37.                 seconds,
  38.                 frames,
  39.                 f = Math.round(time * fps)
  40.         ;
  41.  
  42.         if (isDropFrame(fps)) {
  43.  
  44.                 if (f < 0) {
  45.                         f = framesPer24Hours + f;
  46.                 }
  47.  
  48.                 f = f % framesPer24Hours;
  49.  
  50.                 const d = Math.floor(f / framesPer10Minutes);
  51.                 const m = f % framesPer10Minutes;
  52.                 f = f + dropFrames * 9 * d;
  53.                 if (m > dropFrames) {
  54.                         f = f + dropFrames * (Math.floor((m - dropFrames) / (Math.round(timeBase * 60 - dropFrames))));
  55.                 }
  56.  
  57.                 const timeBaseDivision = Math.floor(f / timeBase);
  58.  
  59.                 hours = Math.floor(Math.floor(timeBaseDivision / 60) / 60);
  60.                 minutes = Math.floor(timeBaseDivision / 60) % 60;
  61.  
  62.                 if (showFrameCount) {
  63.                         seconds = timeBaseDivision % 60;
  64.                 } else {
  65.                         seconds = Math.floor((f / timeBase) % 60).toFixed(secondsDecimalLength);
  66.                 }
  67.         }
  68.         else {
  69.                 hours = Math.floor(time / 3600) % 24;
  70.                 minutes = Math.floor(time / 60) % 60;
  71.                 if (showFrameCount) {
  72.                         seconds = Math.floor(time % 60);
  73.                 } else {
  74.                         seconds = Math.floor(time % 60).toFixed(secondsDecimalLength);
  75.                 }
  76.         }
  77.         hours = hours <= 0 ? 0 : hours;
  78.         minutes = minutes <= 0 ? 0 : minutes;
  79.         seconds = seconds <= 0 ? 0 : seconds;
  80.  
  81.         seconds = seconds === 60 ? 0 : seconds;
  82.         minutes = minutes === 60 ? 0 : minutes;
  83.  
  84.         const timeFormatFrags = timeFormat.split(':');
  85.         const timeFormatSettings = {};
  86.         for (let i = 0, total = timeFormatFrags.length; i < total; ++i) {
  87.                 let unique = '';
  88.                 for (let j = 0, t = timeFormatFrags[i].length; j < t; j++) {
  89.                         if (unique.indexOf(timeFormatFrags[i][j]) < 0) {
  90.                                 unique += timeFormatFrags[i][j];
  91.                         }
  92.                 }
  93.                 if (~['f', 's', 'm', 'h'].indexOf(unique)) {
  94.                         timeFormatSettings[unique] = timeFormatFrags[i].length;
  95.                 }
  96.         }
  97.  
  98.         let result = (forceHours || hours > 0) ? `${(hours < 10 && timeFormatSettings.h > 1 ? `0${hours}` : hours)}:` : '';
  99.         result += `${(minutes < 10 && timeFormatSettings.m > 1 ? `0${minutes}` : minutes)}:`;
  100.         result += `${(seconds < 10 && timeFormatSettings.s > 1 ? `0${seconds}` : seconds)}`;
  101.  
  102.         if (showFrameCount) {
  103.                 frames = (f % timeBase).toFixed(0);
  104.                 frames = frames <= 0 ? 0 : frames;
  105.                 result += (frames < 10 && timeFormatSettings.f) ? `${frameSep}0${frames}` : `${frameSep}${frames}`;
  106.         }
  107.  
  108.         return result;
  109. }
  110.  
  111. /**
  112.  * Convert a '00:00:00' time string into seconds
  113.  *
  114.  * @param {String} time
  115.  * @param {Number} fps - Frames per second
  116.  * @return {Number}
  117.  */
  118. export function timeCodeToSeconds (time, fps = 25) {
  119.  
  120.         if (typeof time !== 'string') {
  121.                 throw new TypeError('Time must be a string');
  122.         }
  123.  
  124.         if (time.indexOf(';') > 0) {
  125.                 time = time.replace(';', ':');
  126.         }
  127.  
  128.         if (!/\d{2}(\:\d{2}){0,3}/i.test(time)) {
  129.                 throw new TypeError('Time code must have the format `00:00:00`');
  130.         }
  131.  
  132.         const parts = time.split(':');
  133.  
  134.         let
  135.                 output,
  136.                 hours = 0,
  137.                 minutes = 0,
  138.                 seconds = 0,
  139.                 frames = 0,
  140.                 totalMinutes = 0,
  141.                 dropFrames = Math.round(fps * 0.066666), // Number of drop frames to drop on the minute marks (6%)
  142.                 timeBase = Math.round(fps),
  143.                 hFrames = timeBase * 3600,
  144.                 mFrames = timeBase * 60
  145.         ;
  146.  
  147.         switch (parts.length) {
  148.                 default:
  149.                 case 1:
  150.                         seconds = parseInt(parts[0], 10);
  151.                         break;
  152.                 case 2:
  153.                         minutes = parseInt(parts[0], 10);
  154.                         seconds = parseInt(parts[1], 10);
  155.                         break;
  156.                 case 3:
  157.                         hours = parseInt(parts[0], 10);
  158.                         minutes = parseInt(parts[1], 10);
  159.                         seconds = parseInt(parts[2], 10);
  160.                         break;
  161.                 case 4:
  162.                         hours = parseInt(parts[0], 10);
  163.                         minutes = parseInt(parts[1], 10);
  164.                         seconds = parseInt(parts[2], 10);
  165.                         frames = parseInt(parts[3], 10);
  166.                         break;
  167.         }
  168.  
  169.         if (isDropFrame(fps)) {
  170.                 totalMinutes = (60 * hours) + minutes;
  171.                 output = ((hFrames * hours) + (mFrames * minutes) + (timeBase * seconds) + frames) - (dropFrames * (totalMinutes - (Math.floor(totalMinutes / 10))));
  172.         } else {
  173.                 output = (( hFrames * hours ) + ( mFrames * minutes  ) + fps * seconds + frames) / fps;
  174.         }
  175.  
  176.         return parseFloat(output.toFixed(3));
  177. }
  178.  
  179. /**
  180.  * Calculate the time format to use
  181.  *
  182.  * There is a default format set in the options but it can be incomplete, so it is adjusted according to the media
  183.  * duration. Format: 'hh:mm:ss:ff'
  184.  * @param {*} time - Ideally a number, but if not or less than zero, is defaulted to zero
  185.  * @param {Object} options
  186.  * @param {Number} fps - Frames per second
  187.  */
  188. export function calculateTimeFormat (time, options, fps = 25) {
  189.  
  190.         time = !time || typeof time !== 'number' || time < 0 ? 0 : time;
  191.  
  192.         const
  193.                 hours = Math.floor(time / 3600) % 24,
  194.                 minutes = Math.floor(time / 60) % 60,
  195.                 seconds = Math.floor(time % 60),
  196.                 frames = Math.floor(((time % 1) * fps).toFixed(3)),
  197.                 lis = [
  198.                         [frames, 'f'],
  199.                         [seconds, 's'],
  200.                         [minutes, 'm'],
  201.                         [hours, 'h']
  202.                 ]
  203.         ;
  204.  
  205.         let
  206.                 format = options.timeFormat,
  207.                 firstTwoPlaces = (format[1] === format[0]),
  208.                 separatorIndex = firstTwoPlaces ? 2 : 1,
  209.                 separator = format.length < separatorIndex ? format[separatorIndex] : ':',
  210.                 firstChar = format[0],
  211.                 required = false
  212.         ;
  213.  
  214.         for (let i = 0, len = lis.length; i < len; i++) {
  215.                 if (~format.indexOf(lis[i][1])) {
  216.                         required = true;
  217.                 }
  218.                 else if (required) {
  219.                         let hasNextValue = false;
  220.                         for (let j = i; j < len; j++) {
  221.                                 if (lis[j][0] > 0) {
  222.                                         hasNextValue = true;
  223.                                         break;
  224.                                 }
  225.                         }
  226.  
  227.                         if (!hasNextValue) {
  228.                                 break;
  229.                         }
  230.  
  231.                         if (!firstTwoPlaces) {
  232.                                 format = firstChar + format;
  233.                         }
  234.                         format = lis[i][1] + separator + format;
  235.                         if (firstTwoPlaces) {
  236.                                 format = lis[i][1] + format;
  237.                         }
  238.                         firstChar = lis[i][1];
  239.                 }
  240.         }
  241.  
  242.         options.timeFormat = format;
  243. }
  244.  
  245. /**
  246.  * Convert Society of Motion Picture and Television Engineers (SMTPE) time code into seconds
  247.  *
  248.  * @param {String} SMPTE
  249.  * @return {Number}
  250.  */
  251. export function convertSMPTEtoSeconds (SMPTE) {
  252.  
  253.         if (typeof SMPTE !== 'string') {
  254.                 throw new TypeError('Argument must be a string value');
  255.         }
  256.  
  257.         SMPTE = SMPTE.replace(',', '.');
  258.  
  259.         const decimalLen = ~SMPTE.indexOf('.') ? SMPTE.split('.')[1].length : 0;
  260.  
  261.         let
  262.                 secs = 0,
  263.                 multiplier = 1
  264.         ;
  265.  
  266.         SMPTE = SMPTE.split(':').reverse();
  267.  
  268.         for (let i = 0, total = SMPTE.length; i < total; i++) {
  269.                 multiplier = 1;
  270.                 if (i > 0) {
  271.                         multiplier = Math.pow(60, i);
  272.                 }
  273.                 secs += Number(SMPTE[i]) * multiplier;
  274.         }
  275.         return Number(secs.toFixed(decimalLen));
  276. }
  277.  
  278. mejs.Utils = mejs.Utils || {};
  279. mejs.Utils.secondsToTimeCode = secondsToTimeCode;
  280. mejs.Utils.timeCodeToSeconds = timeCodeToSeconds;
  281. mejs.Utils.calculateTimeFormat = calculateTimeFormat;
  282. mejs.Utils.convertSMPTEtoSeconds = convertSMPTEtoSeconds;

Raw Paste


Login or Register to edit or fork this paste. It's free.