From ebbb8ddb8b77234a9800ea5ab92bdd3a208ac7bb Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Wed, 13 Mar 2019 06:55:57 -0700 Subject: [PATCH] Support parsing metadata from input --- README.md | 42 ++++++++++++++++++++++++++ lib/parser.js | 27 +++++++++++++++-- test/parser.test.js | 73 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1052c2e..6c645b8 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,48 @@ For the above example we'd get: } ``` +### Metadata + +Some WebVTT strings may also contain lines of metadata after the initial `WEBVTT` line, for example: + +``` +WEBVTT +Kind: captions +Language: en + +00:00:00.000 --> 00:00:01.000 +Hello world! +``` + +By passing `{ meta: true }` to the `parse` method, these metadata will be returned as an object called `meta`. For example, parsing the above example: + +```js +parse(webvtt, { meta: true }); +``` + +would return the following: + +```json +{ + "valid":true, + "meta":{ + "Kind": "captions", + "Language": "en" + }, + "cues":[ + { + "identifier":"", + "start":0, + "end":1, + "text":"Hello world!", + "styles":"" + } + ] +} +``` + +If no metadata is available, `meta` will be set to `null` in the result if the option is specified. + ### Compiling Compiles JSON from the above format back into a WebVTT string. diff --git a/lib/parser.js b/lib/parser.js index 4370094..defa214 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -13,7 +13,12 @@ ParserError.prototype = Object.create(Error.prototype); const TIMESTAMP_REGEXP = /([0-9]{1,2})?:?([0-9]{2}):([0-9]{2}\.[0-9]{3})/; -function parse (input) { +function parse (input, options) { + if (!options) options = {}; + + options = { + meta: options.meta === true + }; if (typeof input !== 'string') { throw new ParserError('Input must be a string'); @@ -46,13 +51,29 @@ function parse (input) { return { valid: true }; } - if (headerParts.length > 1 && headerParts[1] !== '') { + if (!options.meta && headerParts.length > 1 && headerParts[1] !== '') { throw new ParserError('Missing blank line after signature'); } const cues = parseCues(parts); + const meta = options.meta ? parseMeta(headerParts) : null; + + const result = { valid: true, cues }; + + if (options.meta) { + result.meta = meta; + } + + return result; +} - return { valid: true, cues }; +function parseMeta (headerParts) { + const meta = {}; + headerParts.slice(1).forEach(header => { + const [key, value] = header.split(':').map(t => t.trim()); + meta[key] = value; + }); + return Object.keys(meta).length > 0 ? meta : null; } function parseCues (cues) { diff --git a/test/parser.test.js b/test/parser.test.js index da81bcf..ad5d307 100644 --- a/test/parser.test.js +++ b/test/parser.test.js @@ -220,4 +220,77 @@ Chapter 17`; parse(input).cues.should.have.length(3); }); + + it('should not return meta by default', () => { + const input = `WEBVTT + +1 +00:00.000 --> 00:00.001`; + + parse(input).should.have.property('valid').be.true; + parse(input).should.not.have.property('meta'); + }); + + it('should accept an options object', () => { + const input = `WEBVTT + +1 +00:00.000 --> 00:00.001`; + const options = { meta: true }; + + parse(input, options).cues[0].start.should.equal(0); + parse(input, options).cues[0].end.should.equal(0.001); + }); + + it('should fail if metadata exists but the meta option is not set', () => { + const input = `WEBVTT +Kind: captions +Language: en + +1 +00:00.000 --> 00:00.001`; + const options = { }; + + (() => { parse(input, options); }) + .should.throw(parserError, /Missing blank line after signature/); + }); + + it('should fail if metadata exists but the meta option is false', () => { + const input = `WEBVTT +Kind: captions +Language: en + +1 +00:00.000 --> 00:00.001`; + const options = { meta: false }; + + (() => { parse(input, options); }) + .should.throw(parserError, /Missing blank line after signature/); + }); + + it('should return meta if meta option is true', () => { + const input = `WEBVTT +Kind: captions +Language: en + +1 +00:00.000 --> 00:00.001`; + const options = { meta: true }; + + parse(input, options).should.have.property('valid').be.true; + parse(input, options).should.have.property('meta').be.deep.equal( + { Kind: 'captions', Language: 'en' } + ); + }); + + it('should return null if meta option is true but no meta', () => { + const input = `WEBVTT + +1 +00:00.000 --> 00:00.001`; + const options = { meta: true }; + + parse(input, options).should.have.property('valid').be.true; + parse(input, options).should.have.property('meta').be.equal(null); + }); });