'use strict'; var xml2js = require('xml2js'); /** * Converts an input buffer to a SubRip subtitle. * @param {Buffer|string} input * @param {function(Error, string=)} done */ module.exports = function(input, done) { if (typeof buffer !== 'string') input = input.toString(); xml2js.parseString(input, { explicitArray: false, explicitRoot: false }, function(err, xml) { try { if (err) return done(err); done(undefined, xml.events.event.map(_event).join('\n')); } catch(err) { done(err); } }); }; /** * Converts an event. * @private * @param {Object} event * @param {number} index * @returns {string} */ function _event(event, index) { var attributes = event.$; return (index + 1) + '\n' + _time(attributes.start) + ' --> ' + _time(attributes.end) + '\n' + _text(attributes.text) + '\n'; } /** * Prefixes a value. * @private * @param {string} value * @param {number} length * @returns {string} */ function _prefix(value, length) { while (value.length < length) value = '0' + value; return value; } /** * Suffixes a value. * @private * @param {string} value * @param {number} length * @returns {string} */ function _suffix(value, length) { while (value.length < length) value = value + '0'; return value; } /** * Formats a text value. * @private * @param {string} text * @returns {string} */ function _text(text) { return text .replace(/{\\i1}/g, '').replace(/{\\i0}/g, '') .replace(/{\\b1}/g, '').replace(/{\\b0}/g, '') .replace(/{\\u1}/g, '').replace(/{\\u0}/g, '') .replace(/{[^}]+}/g, '') .replace(/(\s+)?\\n(\s+)?/ig, '\n') .trim(); } /** * Formats a time stamp. * @private * @param {string} time * @returns {string} */ function _time(time) { var all = time.match(/^([0-9]+):([0-9]+):([0-9]+)\.([0-9]+)$/); if (!all) throw new Error('Invalid time.'); var hours = _prefix(all[1], 2); var minutes = _prefix(all[2], 2); var seconds = _prefix(all[3], 2); var milliseconds = _suffix(all[4], 3); return hours + ':' + minutes + ':' + seconds + ',' + milliseconds; }