From 9b1c614815d4963e03dec41a155e58cb5eefb94f Mon Sep 17 00:00:00 2001 From: Tom Bloom Date: Thu, 9 Feb 2023 14:07:23 -0500 Subject: [PATCH] feat: Allow VTT files with erroneous linebreaks (#2394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bad linebreaks will now cause cues to be skipped (with a warning), rather than throwing an error. Closes #2358 Co-authored-by: Álvaro Velad Galván --- lib/text/vtt_text_parser.js | 8 ++-- lib/util/text_parser.js | 2 +- test/text/vtt_text_parser_unit.js | 69 ++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/lib/text/vtt_text_parser.js b/lib/text/vtt_text_parser.js index 7dea95d8f8..6e417e0742 100644 --- a/lib/text/vtt_text_parser.js +++ b/lib/text/vtt_text_parser.js @@ -380,11 +380,9 @@ shaka.text.VttTextParser = class { let end = VttTextParser.parseTime_(parser); if (start == null || expect == null || end == null) { - throw new shaka.util.Error( - shaka.util.Error.Severity.CRITICAL, - shaka.util.Error.Category.TEXT, - shaka.util.Error.Code.INVALID_TEXT_CUE, - 'Could not parse cue time range in WebVTT'); + shaka.log.alwaysWarn( + 'Failed to parse VTT time code. Cue skipped:', id, text); + return null; } start += timeOffset; diff --git a/lib/util/text_parser.js b/lib/util/text_parser.js index efc951ad3d..880ca7daea 100644 --- a/lib/util/text_parser.js +++ b/lib/util/text_parser.js @@ -21,7 +21,7 @@ shaka.util.TextParser = class { * @const * @private {string} */ - this.data_ = data; + this.data_ = data || ''; /** @private {number} */ this.position_ = 0; diff --git a/test/text/vtt_text_parser_unit.js b/test/text/vtt_text_parser_unit.js index bbc8d5455f..6f9fd9b9e8 100644 --- a/test/text/vtt_text_parser_unit.js +++ b/test/text/vtt_text_parser_unit.js @@ -8,7 +8,6 @@ describe('VttTextParser', () => { const Cue = shaka.text.Cue; const CueRegion = shaka.text.CueRegion; const originalLogWarning = shaka.log.warning; - const anyString = jasmine.any(String); /** @type {!jasmine.Spy} */ let logWarningSpy; @@ -161,38 +160,30 @@ describe('VttTextParser', () => { }); it('rejects invalid time values', () => { - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + verifyHelper([], 'WEBVTT\n\n00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n0:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n00:00.20 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n00:100.20 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n00:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n00:00:00:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n00:61.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); - errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + verifyHelper([], 'WEBVTT\n\n61:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, - anyString); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports vertical setting', () => { @@ -1223,6 +1214,34 @@ describe('VttTextParser', () => { {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); + it('supports an extra newline inside the cue body', () => { + verifyHelper( + [ + {startTime: 20, endTime: 40, payload: 'Test'}, + {startTime: 40, endTime: 50, payload: 'Test2'}, + ], + 'WEBVTT\n\n' + + '00:00:20.000 --> 00:00:40.000\n' + + 'Test\n\nExtra line\n\n' + + '00:00:40.000 --> 00:00:50.000\n' + + 'Test2', + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + }); + + it('supports an extra newline before the cue body', () => { + verifyHelper( + [ + {startTime: 20, endTime: 40, payload: ''}, + {startTime: 40, endTime: 50, payload: 'Test2'}, + ], + 'WEBVTT\n\n' + + '00:00:20.000 --> 00:00:40.000\n' + + '\nTest\n\n' + + '00:00:40.000 --> 00:00:50.000\n' + + 'Test2', + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); + }); + /** * @param {!Array} cues * @param {string} text