Source: lib/text/sbv_text_parser.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.text.SbvTextParser');
  7. goog.require('goog.asserts');
  8. goog.require('shaka.text.Cue');
  9. goog.require('shaka.text.TextEngine');
  10. goog.require('shaka.util.Error');
  11. goog.require('shaka.util.StringUtils');
  12. goog.require('shaka.util.TextParser');
  13. /**
  14. * @implements {shaka.extern.TextParser}
  15. * @export
  16. */
  17. shaka.text.SbvTextParser = class {
  18. /**
  19. * @override
  20. * @export
  21. */
  22. parseInit(data) {
  23. goog.asserts.assert(false, 'SubViewer does not have init segments');
  24. }
  25. /**
  26. * @override
  27. * @export
  28. */
  29. setSequenceMode(sequenceMode) {
  30. // Unused.
  31. }
  32. /**
  33. * @override
  34. * @export
  35. */
  36. setManifestType(manifestType) {
  37. // Unused.
  38. }
  39. /**
  40. * @override
  41. * @export
  42. */
  43. parseMedia(data, time) {
  44. const SbvTextParser = shaka.text.SbvTextParser;
  45. const StringUtils = shaka.util.StringUtils;
  46. // Get the input as a string.
  47. const strFromData = StringUtils.fromUTF8(data);
  48. // remove dos newlines
  49. let str = strFromData.replace(/\r+/g, '');
  50. // trim white space start and end
  51. str = str.trim();
  52. /** @type {!Array.<!shaka.text.Cue>} */
  53. const cues = [];
  54. // Supports no cues
  55. if (str == '') {
  56. return cues;
  57. }
  58. // get cues
  59. const blocklist = str.split('\n\n');
  60. for (const block of blocklist) {
  61. const lines = block.split('\n');
  62. // Parse the times.
  63. const parser = new shaka.util.TextParser(lines[0]);
  64. const start = SbvTextParser.parseTime_(parser);
  65. const expect = parser.readRegex(/,/g);
  66. const end = SbvTextParser.parseTime_(parser);
  67. if (start == null || expect == null || end == null) {
  68. throw new shaka.util.Error(
  69. shaka.util.Error.Severity.CRITICAL,
  70. shaka.util.Error.Category.TEXT,
  71. shaka.util.Error.Code.INVALID_TEXT_CUE,
  72. 'Could not parse cue time range in SubViewer');
  73. }
  74. // Get the payload.
  75. const payload = lines.slice(1).join('\n').trim();
  76. const cue = new shaka.text.Cue(start, end, payload);
  77. cues.push(cue);
  78. }
  79. return cues;
  80. }
  81. /**
  82. * Parses a SubViewer time from the given parser.
  83. *
  84. * @param {!shaka.util.TextParser} parser
  85. * @return {?number}
  86. * @private
  87. */
  88. static parseTime_(parser) {
  89. // 00:00.000 or 00:00:00.000 or 0:00:00.000 or
  90. // 00:00.00 or 00:00:00.00 or 0:00:00.00
  91. const regexExpresion = /(?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{2,3})/g;
  92. const results = parser.readRegex(regexExpresion);
  93. if (results == null) {
  94. return null;
  95. }
  96. // This capture is optional, but will still be in the array as undefined,
  97. // in which case it is 0.
  98. const hours = Number(results[1]) || 0;
  99. const minutes = Number(results[2]);
  100. const seconds = Number(results[3]);
  101. const milliseconds = Number(results[4]);
  102. if (minutes > 59 || seconds > 59) {
  103. return null;
  104. }
  105. return (milliseconds / 1000) + seconds + (minutes * 60) + (hours * 3600);
  106. }
  107. };
  108. shaka.text.TextEngine.registerParser(
  109. 'text/x-subviewer', () => new shaka.text.SbvTextParser());