Skip to content

Commit

Permalink
chore: Add text_utils.js (#4941)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad authored Jan 30, 2023
1 parent 056588b commit ff80ae6
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 128 deletions.
1 change: 1 addition & 0 deletions build/types/core
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
+../../lib/text/cue.js
+../../lib/text/simple_text_displayer.js
+../../lib/text/text_engine.js
+../../lib/text/text_utils.js
+../../lib/text/ui_text_displayer.js
+../../lib/text/web_vtt_generator.js

Expand Down
66 changes: 2 additions & 64 deletions lib/text/simple_text_displayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ goog.provide('shaka.text.SimpleTextDisplayer');
goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.text.Cue');
goog.require('shaka.text.Utils');


/**
Expand Down Expand Up @@ -79,70 +80,7 @@ shaka.text.SimpleTextDisplayer = class {
* @export
*/
append(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) {
// 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.
// We also don't want to flatten the text payloads starting at a container
// element; otherwise, for containers encapsulating multiple caption lines,
// the lines would merge into a single cue. This is undesirable when a
// subset of the captions are outside of the append time window. To fix
// this, we only call flattenPayload() starting at elements marked as
// isContainer = false.
const getCuesToFlatten = (cues, result) => {
for (const cue of cues) {
if (cue.isContainer) {
// Recurse to find the actual text payload cues.
getCuesToFlatten(cue.nestedCues, result);
} else {
// Flatten the payload.
const flatCue = cue.clone();
flatCue.nestedCues = [];
flatCue.payload = flattenPayload(cue);
result.push(flatCue);
}
}
return result;
};
const flattenedCues = getCuesToFlatten(cues, []);
const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues, []);

// Convert cues.
const textTrackCues = [];
Expand Down
88 changes: 88 additions & 0 deletions lib/text/text_utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

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

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


shaka.text.Utils = class {
/**
* Flatten nested cue payloads recursively. If a cue has nested cues,
* their contents should be combined and replace the payload of the parent.
*
* @param {!shaka.text.Cue} cue
* @return {string}
* @private
*/
static 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) {
// This is a vertical lineBreak, so insert a newline.
return '\n';
} else if (cue.nestedCues.length) {
return cue.nestedCues.map(shaka.text.Utils.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.
* We also don't want to flatten the text payloads starting at a container
* element; otherwise, for containers encapsulating multiple caption lines,
* the lines would merge into a single cue. This is undesirable when a
* subset of the captions are outside of the append time window. To fix
* this, we only call flattenPayload() starting at elements marked as
* isContainer = false.
*
* @param {!Array.<!shaka.text.Cue>} cues
* @param {!Array.<!shaka.text.Cue>} result
* @return {!Array.<!shaka.text.Cue>}
*/
static getCuesToFlatten(cues, result) {
for (const cue of cues) {
if (cue.isContainer) {
// Recurse to find the actual text payload cues.
shaka.text.Utils.getCuesToFlatten(cue.nestedCues, result);
} else {
// Flatten the payload.
const flatCue = cue.clone();
flatCue.nestedCues = [];
flatCue.payload = shaka.text.Utils.flattenPayload_(cue);
result.push(flatCue);
}
}
return result;
}
};
66 changes: 2 additions & 64 deletions lib/text/web_vtt_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
goog.provide('shaka.text.WebVttGenerator');

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


/**
Expand All @@ -20,45 +21,6 @@ shaka.text.WebVttGenerator = class {
* @return {string}
*/
static convert(cues, adCuePoints) {
// 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) {
// 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;
}
};

const webvttTimeString = (time) => {
let newTime = time;
for (const adCuePoint of adCuePoints) {
Expand All @@ -78,31 +40,7 @@ shaka.text.WebVttGenerator = class {
milliseconds;
};

// 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.
// We also don't want to flatten the text payloads starting at a container
// element; otherwise, for containers encapsulating multiple caption lines,
// the lines would merge into a single cue. This is undesirable when a
// subset of the captions are outside of the append time window. To fix
// this, we only call flattenPayload() starting at elements marked as
// isContainer = false.
const getCuesToFlatten = (cues, result) => {
for (const cue of cues) {
if (cue.isContainer) {
// Recurse to find the actual text payload cues.
getCuesToFlatten(cue.nestedCues, result);
} else {
// Flatten the payload.
const flatCue = cue.clone();
flatCue.nestedCues = [];
flatCue.payload = flattenPayload(cue);
result.push(flatCue);
}
}
return result;
};
const flattenedCues = getCuesToFlatten(cues, []);
const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues, []);

let webvttString = 'WEBVTT\n\n';
for (const cue of flattenedCues) {
Expand Down

0 comments on commit ff80ae6

Please sign in to comment.