shaka-player 4.3.3 → 4.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.github/workflows/build-and-test.yaml +4 -4
  2. package/.github/workflows/demo-version-index.yaml +6 -0
  3. package/.github/workflows/selenium-lab-tests.yaml +72 -11
  4. package/.github/workflows/update-screenshots.yaml +142 -0
  5. package/CHANGELOG.md +41 -0
  6. package/demo/common/asset.js +15 -0
  7. package/demo/common/assets.js +4 -2
  8. package/demo/common/message_ids.js +1 -0
  9. package/demo/custom.js +19 -0
  10. package/demo/locales/en.json +1 -0
  11. package/demo/locales/source.json +4 -0
  12. package/demo/main.js +14 -0
  13. package/dist/demo.compiled.debug.js +30 -28
  14. package/dist/demo.compiled.debug.map +3 -3
  15. package/dist/demo.compiled.js +30 -28
  16. package/dist/demo.compiled.map +3 -3
  17. package/dist/deps.js +4 -3
  18. package/dist/locales.js +30 -30
  19. package/dist/receiver.compiled.debug.js +22 -22
  20. package/dist/receiver.compiled.debug.map +2 -2
  21. package/dist/receiver.compiled.js +22 -22
  22. package/dist/receiver.compiled.map +2 -2
  23. package/dist/shaka-player.compiled.d.ts +7 -0
  24. package/dist/shaka-player.compiled.debug.d.ts +7 -0
  25. package/dist/shaka-player.compiled.debug.js +116 -109
  26. package/dist/shaka-player.compiled.debug.map +4 -4
  27. package/dist/shaka-player.compiled.js +825 -821
  28. package/dist/shaka-player.compiled.map +4 -4
  29. package/dist/shaka-player.ui.d.ts +7 -0
  30. package/dist/shaka-player.ui.debug.d.ts +7 -0
  31. package/dist/shaka-player.ui.debug.js +128 -121
  32. package/dist/shaka-player.ui.debug.map +4 -4
  33. package/dist/shaka-player.ui.js +937 -932
  34. package/dist/shaka-player.ui.map +4 -4
  35. package/docs/tutorials/errors.md +94 -0
  36. package/docs/tutorials/fairplay.md +2 -2
  37. package/docs/tutorials/index.json +2 -0
  38. package/docs/tutorials/widevine-service-certs.md +45 -0
  39. package/externs/ima.js +9 -0
  40. package/lib/ads/client_side_ad_manager.js +6 -3
  41. package/lib/dash/segment_template.js +17 -5
  42. package/lib/hls/hls_parser.js +12 -2
  43. package/lib/media/drm_engine.js +4 -2
  44. package/lib/media/transmuxer.js +13 -7
  45. package/lib/media/video_wrapper.js +3 -3
  46. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  47. package/lib/player.js +3 -1
  48. package/lib/polyfill/media_capabilities.js +6 -9
  49. package/lib/polyfill/mediasource.js +24 -2
  50. package/lib/text/simple_text_displayer.js +2 -64
  51. package/lib/text/text_utils.js +88 -0
  52. package/lib/text/ui_text_displayer.js +1 -5
  53. package/lib/text/vtt_text_parser.js +228 -102
  54. package/lib/text/web_vtt_generator.js +2 -64
  55. package/lib/util/mime_utils.js +1 -1
  56. package/lib/util/platform.js +8 -0
  57. package/lib/util/stream_utils.js +26 -14
  58. package/package.json +1 -1
  59. package/support.html +1 -0
  60. package/test/dash/dash_parser_manifest_unit.js +0 -36
  61. package/test/polyfill/media_capabilities_unit.js +21 -22
  62. package/test/test/util/layout_tests.js +433 -0
  63. package/test/test/util/util.js +0 -120
  64. package/test/{ui → text}/text_displayer_layout_unit.js +59 -235
  65. package/test/text/ui_text_displayer_unit.js +2 -4
  66. package/test/text/vtt_text_parser_unit.js +138 -8
  67. package/test/text/web_vtt_layout_integration.js +525 -0
@@ -474,6 +474,7 @@ shaka.text.UITextDisplayer = class {
474
474
  wrapper = shaka.util.Dom.createHTMLElement('span');
475
475
  wrapper.classList.add('shaka-text-wrapper');
476
476
  wrapper.style.backgroundColor = cue.backgroundColor;
477
+ wrapper.style.lineHeight = 'normal';
477
478
  cueElement.appendChild(wrapper);
478
479
  }
479
480
 
@@ -617,12 +618,7 @@ shaka.text.UITextDisplayer = class {
617
618
  // TODO: Implement lineAlignment of 'CENTER'.
618
619
  if (cue.line != null) {
619
620
  if (cue.lineInterpretation == Cue.lineInterpretation.PERCENTAGE) {
620
- // When setting absolute positioning, you need to set x/y/width/height
621
- // so the element is positioned correctly. Set these as default and
622
- // other settings will override them.
623
621
  style.position = 'absolute';
624
- style.left = '0';
625
- style.top = '0';
626
622
  if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
627
623
  style.width = '100%';
628
624
  if (cue.lineAlign == Cue.lineAlign.START) {
@@ -154,14 +154,14 @@ shaka.text.VttTextParser = class {
154
154
  for (const [key, value] of Object.entries(textColor)) {
155
155
  const cue = new shaka.text.Cue(0, 0, '');
156
156
  cue.color = value;
157
- styles.set(key, cue);
157
+ styles.set('.' + key, cue);
158
158
  }
159
159
 
160
160
  const bgColor = shaka.text.Cue.defaultTextBackgroundColor;
161
161
  for (const [key, value] of Object.entries(bgColor)) {
162
162
  const cue = new shaka.text.Cue(0, 0, '');
163
163
  cue.backgroundColor = value;
164
- styles.set(key, cue);
164
+ styles.set('.' + key, cue);
165
165
  }
166
166
  }
167
167
 
@@ -221,96 +221,121 @@ shaka.text.VttTextParser = class {
221
221
  return;
222
222
  }
223
223
 
224
- if (!text[1].includes('::cue')) {
225
- return;
226
- }
227
- let styleSelector = 'global';
228
- // Look for what is within parentisesis. For example:
229
- // <code>:: cue (b) {</code>, what we are looking for is <code>b</code>
230
- const selector = text[1].match(/\((.*)\)/);
231
- if (selector) {
232
- styleSelector = selector.pop();
224
+ /** @type {!Array.<!Array.<string>>} */
225
+ const styleBlocks = [];
226
+ let lastBlockIndex = -1;
227
+ for (let i = 1; i < text.length; i++) {
228
+ if (text[i].includes('::cue')) {
229
+ styleBlocks.push([]);
230
+ lastBlockIndex = styleBlocks.length - 1;
231
+ }
232
+ if (lastBlockIndex == -1) {
233
+ continue;
234
+ }
235
+ styleBlocks[lastBlockIndex].push(text[i]);
236
+ if (text[i].includes('}')) {
237
+ lastBlockIndex = -1;
238
+ }
233
239
  }
234
240
 
235
- // We start at 2 to avoid '::cue' and end earlier to avoid '}'
236
- let propertyLines = text.slice(2, -1);
237
- if (text[1].includes('}')) {
238
- const payload = /\{(.*?)\}/.exec(text[1]);
239
- if (payload) {
240
- propertyLines = payload[1].split(';');
241
+ for (const styleBlock of styleBlocks) {
242
+ let styleSelector = 'global';
243
+ // Look for what is within parentheses. For example:
244
+ // <code>:: cue (b) {</code>, what we are looking for is <code>b</code>
245
+ const selector = styleBlock[0].match(/\((.*)\)/);
246
+ if (selector) {
247
+ styleSelector = selector.pop();
241
248
  }
242
- }
243
249
 
244
- const cue = new shaka.text.Cue(0, 0, '');
245
- let validStyle = false;
246
- for (let i = 0; i < propertyLines.length; i++) {
247
- // We look for CSS properties. As a general rule they are separated by
248
- // <code>:</code>. Eg: <code>color: red;</code>
249
- const lineParts = /^\s*([^:]+):\s*(.*)/.exec(propertyLines[i]);
250
- if (lineParts) {
251
- const name = lineParts[1].trim();
252
- const value = lineParts[2].trim().replace(';', '');
253
- switch (name) {
254
- case 'background-color':
255
- validStyle = true;
256
- cue.backgroundColor = value;
257
- break;
258
- case 'color':
259
- validStyle = true;
260
- cue.color = value;
261
- break;
262
- case 'font-family':
263
- validStyle = true;
264
- cue.fontFamily = value;
265
- break;
266
- case 'font-size':
267
- validStyle = true;
268
- cue.fontSize = value;
269
- break;
270
- case 'font-weight':
271
- if (parseInt(value, 10) >= 700) {
250
+ // We start at 1 to avoid '::cue' and end earlier to avoid '}'
251
+ let propertyLines = styleBlock.slice(1, -1);
252
+ if (styleBlock[0].includes('}')) {
253
+ const payload = /\{(.*?)\}/.exec(styleBlock[0]);
254
+ if (payload) {
255
+ propertyLines = payload[1].split(';');
256
+ }
257
+ }
258
+
259
+ // Continue styles over multiple selectors if necessary.
260
+ // For example,
261
+ // ::cue(b) { background: white; } ::cue(b) { color: blue; }
262
+ // should set both the background and foreground of bold tags.
263
+ let cue = styles.get(styleSelector);
264
+ if (!cue) {
265
+ cue = new shaka.text.Cue(0, 0, '');
266
+ }
267
+
268
+ let validStyle = false;
269
+ for (let i = 0; i < propertyLines.length; i++) {
270
+ // We look for CSS properties. As a general rule they are separated by
271
+ // <code>:</code>. Eg: <code>color: red;</code>
272
+ const lineParts = /^\s*([^:]+):\s*(.*)/.exec(propertyLines[i]);
273
+ if (lineParts) {
274
+ const name = lineParts[1].trim();
275
+ const value = lineParts[2].trim().replace(';', '');
276
+ switch (name) {
277
+ case 'background-color':
278
+ case 'background':
272
279
  validStyle = true;
273
- cue.fontWeight = shaka.text.Cue.fontWeight.BOLD;
274
- }
275
- break;
276
- case 'font-style':
277
- switch (value) {
278
- case 'normal':
279
- validStyle = true;
280
- cue.fontStyle = shaka.text.Cue.fontStyle.NORMAL;
281
- break;
282
- case 'italic':
283
- validStyle = true;
284
- cue.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
285
- break;
286
- case 'oblique':
280
+ cue.backgroundColor = value;
281
+ break;
282
+ case 'color':
283
+ validStyle = true;
284
+ cue.color = value;
285
+ break;
286
+ case 'font-family':
287
+ validStyle = true;
288
+ cue.fontFamily = value;
289
+ break;
290
+ case 'font-size':
291
+ validStyle = true;
292
+ cue.fontSize = value;
293
+ break;
294
+ case 'font-weight':
295
+ if (parseInt(value, 10) >= 700 || value == 'bold') {
287
296
  validStyle = true;
288
- cue.fontStyle = shaka.text.Cue.fontStyle.OBLIQUE;
289
- break;
290
- }
291
- break;
292
- case 'opacity':
293
- validStyle = true;
294
- cue.opacity = parseFloat(value);
295
- break;
296
- case 'text-shadow':
297
- validStyle = true;
298
- cue.textShadow = value;
299
- break;
300
- case 'white-space':
301
- validStyle = true;
302
- cue.wrapLine = value != 'noWrap';
303
- break;
304
- default:
305
- shaka.log.warning('VTT parser encountered an unsupported style: ',
306
- lineParts);
307
- break;
297
+ cue.fontWeight = shaka.text.Cue.fontWeight.BOLD;
298
+ }
299
+ break;
300
+ case 'font-style':
301
+ switch (value) {
302
+ case 'normal':
303
+ validStyle = true;
304
+ cue.fontStyle = shaka.text.Cue.fontStyle.NORMAL;
305
+ break;
306
+ case 'italic':
307
+ validStyle = true;
308
+ cue.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
309
+ break;
310
+ case 'oblique':
311
+ validStyle = true;
312
+ cue.fontStyle = shaka.text.Cue.fontStyle.OBLIQUE;
313
+ break;
314
+ }
315
+ break;
316
+ case 'opacity':
317
+ validStyle = true;
318
+ cue.opacity = parseFloat(value);
319
+ break;
320
+ case 'text-shadow':
321
+ validStyle = true;
322
+ cue.textShadow = value;
323
+ break;
324
+ case 'white-space':
325
+ validStyle = true;
326
+ cue.wrapLine = value != 'noWrap';
327
+ break;
328
+ default:
329
+ shaka.log.warning('VTT parser encountered an unsupported style: ',
330
+ lineParts);
331
+ break;
332
+ }
308
333
  }
309
334
  }
310
- }
311
335
 
312
- if (validStyle) {
313
- styles.set(styleSelector, cue);
336
+ if (validStyle) {
337
+ styles.set(styleSelector, cue);
338
+ }
314
339
  }
315
340
  }
316
341
 
@@ -337,8 +362,8 @@ shaka.text.VttTextParser = class {
337
362
  return null;
338
363
  }
339
364
 
340
- // Skip style blocks.
341
- if (text[0] == 'STYLE') {
365
+ // Skip style and region blocks.
366
+ if (text[0] == 'STYLE' || text[0] == 'REGION') {
342
367
  return null;
343
368
  }
344
369
 
@@ -366,8 +391,7 @@ shaka.text.VttTextParser = class {
366
391
  end += timeOffset;
367
392
 
368
393
  // Get the payload.
369
- const payload = VttTextParser.htmlUnescape_(
370
- text.slice(1).join('\n').trim());
394
+ const payload = text.slice(1).join('\n').trim();
371
395
 
372
396
  let cue = null;
373
397
  if (styles.has('global')) {
@@ -414,6 +438,7 @@ shaka.text.VttTextParser = class {
414
438
  }
415
439
  payload = VttTextParser.replaceColorPayload_(payload);
416
440
  payload = VttTextParser.replaceKaraokeStylePayload_(payload);
441
+ payload = VttTextParser.replaceVoiceStylePayload_(payload);
417
442
  const xmlPayload = '<span>' + payload + '</span>';
418
443
  const element = shaka.util.XmlUtils.parseXmlString(xmlPayload, 'span');
419
444
  if (element) {
@@ -424,7 +449,7 @@ shaka.text.VttTextParser = class {
424
449
  const childNode = childNodes[0];
425
450
  if (childNode.nodeType == Node.TEXT_NODE ||
426
451
  childNode.nodeType == Node.CDATA_SECTION_NODE) {
427
- rootCue.payload = payload;
452
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
428
453
  return;
429
454
  }
430
455
  }
@@ -435,8 +460,81 @@ shaka.text.VttTextParser = class {
435
460
  rootCue.nestedCues = cues;
436
461
  } else {
437
462
  shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
438
- rootCue.payload = payload;
463
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Converts voice style tag to be valid for xml parsing
469
+ * For example,
470
+ * input: <v Shaka>Test
471
+ * output: <v.voice-Shaka>Test</v.voice-Shaka>
472
+ *
473
+ * @param {string} payload
474
+ * @return {string} processed payload
475
+ * @private
476
+ */
477
+ static replaceVoiceStylePayload_(payload) {
478
+ const voiceTag = 'v';
479
+ const names = [];
480
+ let nameStart = -1;
481
+ let newPayload = '';
482
+ let hasVoiceEndTag = false;
483
+ for (let i = 0; i < payload.length; i++) {
484
+ // This condition is used to manage tags that have end tags.
485
+ if (payload[i] === '/') {
486
+ const end = payload.indexOf('>', i);
487
+ if (end === -1) {
488
+ return payload;
489
+ }
490
+ const tagEnd = payload.substring(i + 1, end);
491
+ if (!tagEnd || tagEnd != voiceTag) {
492
+ newPayload += payload[i];
493
+ continue;
494
+ }
495
+ hasVoiceEndTag = true;
496
+ let tagStart = null;
497
+ if (names.length) {
498
+ tagStart = names[names.length -1];
499
+ }
500
+ if (!tagStart) {
501
+ newPayload += payload[i];
502
+ } else if (tagStart === tagEnd) {
503
+ newPayload += '/' + tagEnd + '>';
504
+ i += tagEnd.length + 1;
505
+ } else {
506
+ if (!tagStart.startsWith(voiceTag)) {
507
+ newPayload += payload[i];
508
+ continue;
509
+ }
510
+ newPayload += '/' + tagStart + '>';
511
+ i += tagEnd.length + 1;
512
+ }
513
+ } else {
514
+ // Here we only want the tag name, not any other payload.
515
+ if (payload[i] === '<') {
516
+ nameStart = i + 1;
517
+ if (payload[nameStart] != voiceTag) {
518
+ nameStart = -1;
519
+ }
520
+ } else if (payload[i] === '>') {
521
+ if (nameStart > 0) {
522
+ names.push(payload.substr(nameStart, i - nameStart));
523
+ nameStart = -1;
524
+ }
525
+ }
526
+ newPayload += payload[i];
527
+ }
528
+ }
529
+ for (const name of names) {
530
+ const newName = name.replace(' ', '.voice-');
531
+ newPayload = newPayload.replace(`<${name}>`, `<${newName}>`);
532
+ newPayload = newPayload.replace(`</${name}>`, `</${newName}>`);
533
+ if (!hasVoiceEndTag) {
534
+ newPayload += `</${newName}>`;
535
+ }
439
536
  }
537
+ return newPayload;
440
538
  }
441
539
 
442
540
  /**
@@ -495,28 +593,36 @@ shaka.text.VttTextParser = class {
495
593
  let nameStart = -1;
496
594
  let newPayload = '';
497
595
  for (let i = 0; i < payload.length; i++) {
498
- if (payload[i] === '/') {
596
+ if (payload[i] === '/' && i > 0 && payload[i - 1] === '<') {
499
597
  const end = payload.indexOf('>', i);
500
598
  if (end <= i) {
501
599
  return payload;
502
600
  }
503
601
  const tagEnd = payload.substring(i + 1, end);
602
+ if (!tagEnd || tagEnd !== 'c') {
603
+ newPayload += payload[i];
604
+ continue;
605
+ }
504
606
  const tagStart = names.pop();
505
- if (!tagEnd || !tagStart) {
506
- return payload;
607
+ if (!tagStart) {
608
+ newPayload += payload[i];
507
609
  } else if (tagStart === tagEnd) {
508
610
  newPayload += '/' + tagEnd + '>';
509
611
  i += tagEnd.length + 1;
510
612
  } else {
511
- if (!tagStart.startsWith('c.') || tagEnd !== 'c') {
512
- return payload;
613
+ if (!tagStart.startsWith('c.')) {
614
+ newPayload += payload[i];
615
+ continue;
513
616
  }
514
- newPayload += '/' + tagStart + '>';
515
617
  i += tagEnd.length + 1;
618
+ newPayload += '/' + tagStart + '>';
516
619
  }
517
620
  } else {
518
621
  if (payload[i] === '<') {
519
622
  nameStart = i + 1;
623
+ if (payload[nameStart] != 'c') {
624
+ nameStart = -1;
625
+ }
520
626
  } else if (payload[i] === '>') {
521
627
  if (nameStart > 0) {
522
628
  names.push(payload.substr(nameStart, i - nameStart));
@@ -585,12 +691,29 @@ shaka.text.VttTextParser = class {
585
691
  const bold = shaka.text.Cue.fontWeight.BOLD;
586
692
  const italic = shaka.text.Cue.fontStyle.ITALIC;
587
693
  const underline = shaka.text.Cue.textDecoration.UNDERLINE;
588
- const tags = element.nodeName.split(/[ .]+/);
694
+ const tags = element.nodeName.split(/(?=[ .])+/g);
589
695
  for (const tag of tags) {
590
- if (styles.has(tag)) {
591
- VttTextParser.mergeStyle_(nestedCue, styles.get(tag));
696
+ let styleTag = tag;
697
+ // White blanks at start indicate that the style is a voice
698
+ if (styleTag.startsWith('.voice-')) {
699
+ const voice = styleTag.split('-').pop();
700
+ styleTag = `v[voice="${voice}"]`;
701
+ // The specification allows to have quotes and not, so we check to
702
+ // see which one is being used.
703
+ if (!styles.has(styleTag)) {
704
+ styleTag = `v[voice=${voice}]`;
705
+ }
706
+ }
707
+ if (styles.has(styleTag)) {
708
+ VttTextParser.mergeStyle_(nestedCue, styles.get(styleTag));
592
709
  }
593
710
  switch (tag) {
711
+ case 'br': {
712
+ const lineBreakCue = rootCue.clone();
713
+ lineBreakCue.lineBreak = true;
714
+ cues.push(lineBreakCue);
715
+ break;
716
+ }
594
717
  case 'b':
595
718
  nestedCue.fontWeight = bold;
596
719
  break;
@@ -631,7 +754,7 @@ shaka.text.VttTextParser = class {
631
754
  }
632
755
  if (text.length > 0) {
633
756
  const textCue = nestedCue.clone();
634
- textCue.payload = text;
757
+ textCue.payload = VttTextParser.htmlUnescape_(text);
635
758
  cues.push(textCue);
636
759
  }
637
760
  isFirst = false;
@@ -846,8 +969,8 @@ shaka.text.VttTextParser = class {
846
969
  }
847
970
 
848
971
  /**
849
- * This method converts the HTML entities &amp;, &lt;, &gt;, &quot;, and
850
- * &#39; in string to their corresponding characters.
972
+ * This method converts the HTML entities &amp;, &lt;, &gt;, &quot;, &#39;,
973
+ * &nbsp;, &lrm; and &rlm; in string to their corresponding characters.
851
974
  *
852
975
  * @param {!string} input
853
976
  * @return {string}
@@ -861,10 +984,13 @@ shaka.text.VttTextParser = class {
861
984
  '&gt;': '>',
862
985
  '&quot;': '"',
863
986
  '&#39;': '\'',
987
+ '&nbsp;': '\u{a0}',
988
+ '&lrm;': '\u{200e}',
989
+ '&rlm;': '\u{200f}',
864
990
  };
865
991
 
866
992
  // Used to match HTML entities and HTML characters.
867
- const reEscapedHtml = /&(?:amp|lt|gt|quot|#(0+)?39);/g;
993
+ const reEscapedHtml = /&(?:amp|lt|gt|quot|#(0+)?39|nbsp|lrm|rlm);/g;
868
994
  const reHasEscapedHtml = RegExp(reEscapedHtml.source);
869
995
  // This check is an optimization, since replace always makes a copy
870
996
  if (input && reHasEscapedHtml.test(input)) {
@@ -7,6 +7,7 @@
7
7
  goog.provide('shaka.text.WebVttGenerator');
8
8
 
9
9
  goog.require('shaka.text.Cue');
10
+ goog.require('shaka.text.Utils');
10
11
 
11
12
 
12
13
  /**
@@ -20,45 +21,6 @@ shaka.text.WebVttGenerator = class {
20
21
  * @return {string}
21
22
  */
22
23
  static convert(cues, adCuePoints) {
23
- // Flatten nested cue payloads recursively. If a cue has nested cues,
24
- // their contents should be combined and replace the payload of the parent.
25
- const flattenPayload = (cue) => {
26
- // Handle styles (currently bold/italics/underline).
27
- // TODO: add support for color rendering.
28
- const openStyleTags = [];
29
- const bold = cue.fontWeight >= shaka.text.Cue.fontWeight.BOLD;
30
- const italics = cue.fontStyle == shaka.text.Cue.fontStyle.ITALIC;
31
- const underline = cue.textDecoration.includes(
32
- shaka.text.Cue.textDecoration.UNDERLINE);
33
- if (bold) {
34
- openStyleTags.push('b');
35
- }
36
- if (italics) {
37
- openStyleTags.push('i');
38
- }
39
- if (underline) {
40
- openStyleTags.push('u');
41
- }
42
-
43
- // Prefix opens tags, suffix closes tags in reverse order of opening.
44
- const prefixStyleTags = openStyleTags.reduce((acc, tag) => {
45
- return `${acc}<${tag}>`;
46
- }, '');
47
- const suffixStyleTags = openStyleTags.reduceRight((acc, tag) => {
48
- return `${acc}</${tag}>`;
49
- }, '');
50
-
51
- if (cue.lineBreak) {
52
- // This is a vertical lineBreak, so insert a newline.
53
- return '\n';
54
- } else if (cue.nestedCues.length) {
55
- return cue.nestedCues.map(flattenPayload).join('');
56
- } else {
57
- // This is a real cue.
58
- return prefixStyleTags + cue.payload + suffixStyleTags;
59
- }
60
- };
61
-
62
24
  const webvttTimeString = (time) => {
63
25
  let newTime = time;
64
26
  for (const adCuePoint of adCuePoints) {
@@ -78,31 +40,7 @@ shaka.text.WebVttGenerator = class {
78
40
  milliseconds;
79
41
  };
80
42
 
81
- // We don't want to modify the array or objects passed in, since we don't
82
- // technically own them. So we build a new array and replace certain items
83
- // in it if they need to be flattened.
84
- // We also don't want to flatten the text payloads starting at a container
85
- // element; otherwise, for containers encapsulating multiple caption lines,
86
- // the lines would merge into a single cue. This is undesirable when a
87
- // subset of the captions are outside of the append time window. To fix
88
- // this, we only call flattenPayload() starting at elements marked as
89
- // isContainer = false.
90
- const getCuesToFlatten = (cues, result) => {
91
- for (const cue of cues) {
92
- if (cue.isContainer) {
93
- // Recurse to find the actual text payload cues.
94
- getCuesToFlatten(cue.nestedCues, result);
95
- } else {
96
- // Flatten the payload.
97
- const flatCue = cue.clone();
98
- flatCue.nestedCues = [];
99
- flatCue.payload = flattenPayload(cue);
100
- result.push(flatCue);
101
- }
102
- }
103
- return result;
104
- };
105
- const flattenedCues = getCuesToFlatten(cues, []);
43
+ const flattenedCues = shaka.text.Utils.getCuesToFlatten(cues, []);
106
44
 
107
45
  let webvttString = 'WEBVTT\n\n';
108
46
  for (const cue of flattenedCues) {
@@ -49,7 +49,7 @@ shaka.util.MimeUtils = class {
49
49
 
50
50
  if (Transmuxer.isSupported(fullMimeType, contentType)) {
51
51
  return shaka.media.Transmuxer.convertCodecs(contentType, fullMimeType);
52
- } else if (contentType == ContentType.AUDIO) {
52
+ } else if (mimeType != 'video/mp2t' && contentType == ContentType.AUDIO) {
53
53
  // video/mp2t is the correct mime type for TS audio, so only replace the
54
54
  // word "video" with "audio" for non-TS audio content.
55
55
  return fullMimeType.replace('video', 'audio');
@@ -238,6 +238,14 @@ shaka.util.Platform = class {
238
238
  return shaka.util.Platform.userAgentContains_('PlayStation 4');
239
239
  }
240
240
 
241
+ /**
242
+ * Check if the current platform is Hisense.
243
+ */
244
+ static isHisense() {
245
+ return shaka.util.Platform.userAgentContains_('Hisense') ||
246
+ shaka.util.Platform.userAgentContains_('VIDAA');
247
+ }
248
+
241
249
  /**
242
250
  * Check if the current platform is Virgin Media device.
243
251
  */
@@ -712,26 +712,38 @@ shaka.util.StreamUtils = class {
712
712
  }
713
713
 
714
714
  if (audio) {
715
- if (!keySystemConfig.audio) {
715
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
716
+ if (info.audioRobustness != '') {
717
+ if (!keySystemConfig.audio) {
718
+ // KeySystemTrackConfiguration
719
+ keySystemConfig.audio = {
720
+ robustness: info.audioRobustness,
721
+ };
722
+ } else {
723
+ keySystemConfig.audio.robustness =
724
+ keySystemConfig.audio.robustness || info.audioRobustness;
725
+ }
726
+ } else if (!keySystemConfig.audio) {
716
727
  // KeySystemTrackConfiguration
717
- keySystemConfig.audio = {
718
- robustness: info.audioRobustness,
719
- };
720
- } else {
721
- keySystemConfig.audio.robustness =
722
- keySystemConfig.audio.robustness || info.audioRobustness;
728
+ keySystemConfig.audio = {};
723
729
  }
724
730
  }
725
731
 
726
732
  if (video) {
727
- if (!keySystemConfig.video) {
733
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
734
+ if (info.videoRobustness != '') {
735
+ if (!keySystemConfig.video) {
736
+ // KeySystemTrackConfiguration
737
+ keySystemConfig.video = {
738
+ robustness: info.videoRobustness,
739
+ };
740
+ } else {
741
+ keySystemConfig.video.robustness =
742
+ keySystemConfig.video.robustness || info.videoRobustness;
743
+ }
744
+ } else if (!keySystemConfig.video) {
728
745
  // KeySystemTrackConfiguration
729
- keySystemConfig.video = {
730
- robustness: info.videoRobustness,
731
- };
732
- } else {
733
- keySystemConfig.video.robustness =
734
- keySystemConfig.video.robustness || info.videoRobustness;
746
+ keySystemConfig.video = {};
735
747
  }
736
748
  }
737
749
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.3.3",
4
+ "version": "4.3.5",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
package/support.html CHANGED
@@ -38,6 +38,7 @@
38
38
  }
39
39
 
40
40
  </style>
41
+ <script defer src="node_modules/mux.js/dist/mux.min.js"></script>
41
42
  <script src="dist/shaka-player.compiled.js"></script>
42
43
  <script>
43
44
  function whenLoaded(fn) {