From b5e2066fc112c59218e3211758351ce6126b8319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Mon, 30 Jan 2023 18:22:57 +0100 Subject: [PATCH] chore: Add text_utils.js (#4941) --- build/types/core | 1 + lib/text/simple_text_displayer.js | 66 +---------------------- lib/text/text_utils.js | 88 +++++++++++++++++++++++++++++++ lib/text/web_vtt_generator.js | 66 +---------------------- 4 files changed, 93 insertions(+), 128 deletions(-) create mode 100644 lib/text/text_utils.js diff --git a/build/types/core b/build/types/core index f9f4554860..bc4d4e4b61 100644 --- a/build/types/core +++ b/build/types/core @@ -57,6 +57,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 diff --git a/lib/text/simple_text_displayer.js b/lib/text/simple_text_displayer.js index e2343caa3f..6d0c916f8e 100644 --- a/lib/text/simple_text_displayer.js +++ b/lib/text/simple_text_displayer.js @@ -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'); /** @@ -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}`; - }, ''); - - 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 = []; diff --git a/lib/text/text_utils.js b/lib/text/text_utils.js new file mode 100644 index 0000000000..feb5a1e79b --- /dev/null +++ b/lib/text/text_utils.js @@ -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}`; + }, ''); + + 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.} cues + * @param {!Array.} result + * @return {!Array.} + */ + 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; + } +}; diff --git a/lib/text/web_vtt_generator.js b/lib/text/web_vtt_generator.js index cfa9fbc554..5cf9f231bb 100644 --- a/lib/text/web_vtt_generator.js +++ b/lib/text/web_vtt_generator.js @@ -7,6 +7,7 @@ goog.provide('shaka.text.WebVttGenerator'); goog.require('shaka.text.Cue'); +goog.require('shaka.text.Utils'); /** @@ -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}`; - }, ''); - - 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) { @@ -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) {