Skip to content

Commit

Permalink
feat(text): Creates style tags for underline/italics/bold in WebVttGe…
Browse files Browse the repository at this point in the history
…nerator (shaka-project#3266)
  • Loading branch information
Álvaro Velad Galván authored Mar 30, 2021
1 parent 38c5081 commit 658790a
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 4 deletions.
65 changes: 63 additions & 2 deletions lib/text/web_vtt_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,80 @@

goog.provide('shaka.text.WebVttGenerator');

goog.require('shaka.Deprecate');
goog.require('shaka.text.Cue');


/**
* @summary Manage the conversion to WebVTT.
* @export
*/
shaka.text.WebVttGenerator = class {
/**
* @param {!Array.<!shaka.extern.Cue>} cues
* @param {!Array.<!shaka.text.Cue>} cues
* @return {string}
*/
static convert(cues) {
// Flatten nested cue payloads recursively. If a cue has nested cues,
// their contents should be combined and replace the payload of the parent.
const flattenPayload = (cue) => {
// Handle styles (currently bold/italics/underline).
// TODO: add support for color rendering.
const openStyleTags = [];
const bold = cue.fontWeight >= shaka.text.Cue.fontWeight.BOLD;
const italics = cue.fontStyle == shaka.text.Cue.fontStyle.ITALIC;
const underline = cue.textDecoration.includes(
shaka.text.Cue.textDecoration.UNDERLINE);
if (bold) {
openStyleTags.push('b');
}
if (italics) {
openStyleTags.push('i');
}
if (underline) {
openStyleTags.push('u');
}

// Prefix opens tags, suffix closes tags in reverse order of opening.
const prefixStyleTags = openStyleTags.reduce((acc, tag) => {
return `${acc}<${tag}>`;
}, '');
const suffixStyleTags = openStyleTags.reduceRight((acc, tag) => {
return `${acc}</${tag}>`;
}, '');

if (cue.lineBreak || cue.spacer) {
if (cue.spacer) {
shaka.Deprecate.deprecateFeature(4,
'shaka.text.Cue',
'Please use lineBreak instead of spacer.');
}
// This is a vertical lineBreak, so insert a newline.
return '\n';
} else if (cue.nestedCues.length) {
return cue.nestedCues.map(flattenPayload).join('');
} else {
// This is a real cue.
return prefixStyleTags + cue.payload + suffixStyleTags;
}
};

// We don't want to modify the array or objects passed in, since we don't
// technically own them. So we build a new array and replace certain items
// in it if they need to be flattened.
const flattenedCues = cues.map((cue) => {
if (cue.nestedCues.length) {
const flatCue = cue.clone();
flatCue.nestedCues = [];
flatCue.payload = flattenPayload(cue);
return flatCue;
} else {
return cue;
}
});

let webvttString = 'WEBVTT\n\n';
for (const cue of cues) {
for (const cue of flattenedCues) {
const webvttTimeString = (time) => {
const hours = Math.floor(time / 3600);
const minutes = Math.floor(time / 60 % 60);
Expand Down
36 changes: 34 additions & 2 deletions test/text/web_vtt_generator_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

goog.require('shaka.text.Cue');
goog.require('shaka.text.WebVttGenerator');

describe('WebVttGenerator', () => {
Expand All @@ -12,10 +13,13 @@ describe('WebVttGenerator', () => {
});

it('convert cues to WebVTT', () => {
const shakaCue1 = new shaka.text.Cue(20, 40, 'Test');
const shakaCue2 = new shaka.text.Cue(40, 50, 'Test2');

verifyHelper(
[
{startTime: 20, endTime: 40, payload: 'Test'},
{startTime: 40, endTime: 50, payload: 'Test2'},
shakaCue1,
shakaCue2,
],
'WEBVTT\n\n' +
'00:00:20.000 --> 00:00:40.000\n' +
Expand All @@ -24,6 +28,34 @@ describe('WebVttGenerator', () => {
'Test2\n\n');
});

it('creates style tags for cues with underline/italics/bold', () => {
const shakaCue = new shaka.text.Cue(10, 20, '');

// First cue is underlined and italicized.
const nestedCue1 = new shaka.text.Cue(10, 20, 'Test1');
nestedCue1.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
nestedCue1.textDecoration.push(shaka.text.Cue.textDecoration.UNDERLINE);

// Second cue is italicized and bolded.
const nestedCue2 = new shaka.text.Cue(10, 20, 'Test2');
nestedCue2.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
nestedCue2.fontWeight = shaka.text.Cue.fontWeight.BOLD;

// Third cue has no bold, italics, or underline.
const nestedCue3 = new shaka.text.Cue(10, 20, 'Test3');

// Fourth cue is only underlined.
const nestedCue4 = new shaka.text.Cue(10, 20, 'Test4');
nestedCue4.textDecoration.push(shaka.text.Cue.textDecoration.UNDERLINE);

shakaCue.nestedCues = [nestedCue1, nestedCue2, nestedCue3, nestedCue4];
verifyHelper(
[shakaCue],
'WEBVTT\n\n' +
'00:00:10.000 --> 00:00:20.000\n' +
'<i><u>Test1</u></i><b><i>Test2</i></b>Test3<u>Test4</u>\n\n');
});

/**
* @param {!Array} cues
* @param {string} text
Expand Down

0 comments on commit 658790a

Please sign in to comment.