shaka-player 3.2.1 → 3.3.1

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 (213) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/.github/ISSUE_TEMPLATE/question.md +1 -1
  4. package/AUTHORS +9 -5
  5. package/CHANGELOG.md +358 -0
  6. package/CONTRIBUTORS +7 -2
  7. package/build/conformance.textproto +183 -169
  8. package/build/generateExterns.js +1 -1
  9. package/build/types/core +3 -0
  10. package/build/types/offline +1 -0
  11. package/build/types/polyfill +1 -0
  12. package/build/types/ui +2 -0
  13. package/demo/common/assets.js +19 -1
  14. package/demo/common/message_ids.js +13 -1
  15. package/demo/config.js +31 -1
  16. package/demo/index.html +1 -1
  17. package/demo/locales/en.json +12 -0
  18. package/demo/locales/source.json +48 -0
  19. package/dist/controls.css +26 -2
  20. package/dist/controls.css.map +1 -1
  21. package/dist/demo.compiled.debug.js +20 -17
  22. package/dist/demo.compiled.debug.map +3 -3
  23. package/dist/demo.compiled.js +20 -17
  24. package/dist/demo.compiled.map +3 -3
  25. package/dist/deps.js +19 -12
  26. package/dist/locales.js +39 -37
  27. package/dist/receiver.compiled.debug.js +12 -10
  28. package/dist/receiver.compiled.debug.map +3 -3
  29. package/dist/receiver.compiled.js +12 -10
  30. package/dist/receiver.compiled.map +3 -3
  31. package/dist/shaka-player.compiled.d.ts +231 -18
  32. package/dist/shaka-player.compiled.debug.d.ts +231 -18
  33. package/dist/shaka-player.compiled.debug.externs.js +279 -8
  34. package/dist/shaka-player.compiled.debug.js +512 -449
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +279 -8
  37. package/dist/shaka-player.compiled.js +854 -821
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +247 -19
  40. package/dist/shaka-player.ui.debug.d.ts +247 -19
  41. package/dist/shaka-player.ui.debug.externs.js +307 -9
  42. package/dist/shaka-player.ui.debug.js +662 -580
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +307 -9
  45. package/dist/shaka-player.ui.js +1047 -1000
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/bg-fetch-after.gv +29 -0
  48. package/docs/design/bg-fetch-after.gv.png +0 -0
  49. package/docs/design/bg-fetch-before.gv +18 -0
  50. package/docs/design/bg-fetch-before.gv.png +0 -0
  51. package/docs/design/bg-fetch.md +134 -0
  52. package/docs/tutorials/blob-url.md +15 -0
  53. package/docs/tutorials/fairplay.md +1 -1
  54. package/docs/tutorials/index.json +1 -0
  55. package/docs/tutorials/ui-customization.md +66 -0
  56. package/docs/tutorials/ui.md +5 -5
  57. package/externs/cmcd.js +186 -0
  58. package/externs/ima.js +3 -0
  59. package/externs/shaka/ads.js +5 -0
  60. package/externs/shaka/manifest.js +12 -1
  61. package/externs/shaka/manifest_parser.js +10 -1
  62. package/externs/shaka/net.js +20 -4
  63. package/externs/shaka/offline.js +31 -2
  64. package/externs/shaka/player.js +138 -5
  65. package/externs/shaka/text.js +24 -0
  66. package/externs/webcrypto.js +18 -0
  67. package/karma.conf.js +1 -0
  68. package/lib/abr/ewma.js +14 -0
  69. package/lib/abr/ewma_bandwidth_estimator.js +16 -2
  70. package/lib/abr/simple_abr_manager.js +6 -0
  71. package/lib/ads/client_side_ad.js +8 -0
  72. package/lib/ads/client_side_ad_manager.js +54 -90
  73. package/lib/ads/server_side_ad.js +7 -0
  74. package/lib/ads/server_side_ad_manager.js +7 -10
  75. package/lib/cast/cast_proxy.js +3 -2
  76. package/lib/cast/cast_receiver.js +2 -1
  77. package/lib/cast/cast_sender.js +2 -2
  78. package/lib/cast/cast_utils.js +1 -0
  79. package/lib/dash/dash_parser.js +141 -16
  80. package/lib/dash/segment_base.js +25 -1
  81. package/lib/dash/segment_list.js +19 -10
  82. package/lib/dash/segment_template.js +24 -11
  83. package/lib/hls/hls_parser.js +146 -40
  84. package/lib/media/drm_engine.js +7 -0
  85. package/lib/media/gap_jumping_controller.js +4 -2
  86. package/lib/media/media_source_engine.js +1 -2
  87. package/lib/media/quality_observer.js +291 -0
  88. package/lib/media/segment_index.js +8 -1
  89. package/lib/media/segment_reference.js +37 -4
  90. package/lib/media/streaming_engine.js +49 -7
  91. package/lib/net/http_fetch_plugin.js +31 -11
  92. package/lib/net/http_plugin_utils.js +1 -0
  93. package/lib/net/http_xhr_plugin.js +40 -14
  94. package/lib/net/networking_engine.js +83 -19
  95. package/lib/offline/download_info.js +68 -0
  96. package/lib/offline/download_manager.js +13 -5
  97. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  98. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  99. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  100. package/lib/offline/storage.js +393 -284
  101. package/lib/offline/stored_content_utils.js +2 -0
  102. package/lib/player.js +249 -43
  103. package/lib/polyfill/media_capabilities.js +36 -15
  104. package/lib/polyfill/mediasource.js +6 -0
  105. package/lib/polyfill/orientation.js +1 -1
  106. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  107. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  108. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  109. package/lib/polyfill/random_uuid.js +52 -0
  110. package/lib/text/cue.js +18 -0
  111. package/lib/text/mp4_ttml_parser.js +3 -0
  112. package/lib/text/text_engine.js +14 -2
  113. package/lib/text/ttml_text_parser.js +114 -60
  114. package/lib/text/ui_text_displayer.js +95 -41
  115. package/lib/util/cmcd_manager.js +672 -0
  116. package/lib/util/error.js +6 -0
  117. package/lib/util/fake_event.js +53 -7
  118. package/lib/util/language_utils.js +12 -0
  119. package/lib/util/mutex.js +52 -0
  120. package/lib/util/periods.js +102 -65
  121. package/lib/util/platform.js +13 -1
  122. package/lib/util/player_configuration.js +18 -0
  123. package/lib/util/stream_utils.js +99 -10
  124. package/lib/util/xml_utils.js +19 -0
  125. package/package.json +2 -2
  126. package/shaka-player.uncompiled.js +3 -0
  127. package/test/cast/cast_proxy_unit.js +12 -6
  128. package/test/cast/cast_utils_unit.js +1 -1
  129. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  130. package/test/dash/dash_parser_live_unit.js +101 -1
  131. package/test/dash/dash_parser_manifest_unit.js +222 -2
  132. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  133. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  134. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  135. package/test/hls/hls_live_unit.js +2 -0
  136. package/test/hls/hls_parser_unit.js +7 -1
  137. package/test/media/closed_caption_parser_unit.js +6 -1
  138. package/test/media/drm_engine_unit.js +47 -3
  139. package/test/media/quality_observer_unit.js +139 -0
  140. package/test/media/segment_reference_unit.js +16 -1
  141. package/test/media/streaming_engine_integration.js +4 -2
  142. package/test/media/streaming_engine_unit.js +147 -0
  143. package/test/net/http_plugin_unit.js +20 -15
  144. package/test/offline/storage_integration.js +108 -4
  145. package/test/player_integration.js +178 -8
  146. package/test/player_src_equals_integration.js +41 -8
  147. package/test/player_unit.js +19 -9
  148. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  149. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  150. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  151. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  152. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  153. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  154. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  155. package/test/test/assets/3675/dash_0.mpd +30 -0
  156. package/test/test/assets/3675/dash_1.mpd +30 -0
  157. package/test/test/assets/3675/dash_2.mpd +30 -0
  158. package/test/test/assets/3675/dash_3.mpd +30 -0
  159. package/test/test/assets/3675/dash_4.mpd +30 -0
  160. package/test/test/assets/3675/dash_5.mpd +26 -0
  161. package/test/test/assets/3675/init-stream0.m4s +0 -0
  162. package/test/test/assets/chapters.vtt +2 -2
  163. package/test/test/assets/chapters2.vtt +10 -0
  164. package/test/test/util/dash_parser_util.js +4 -0
  165. package/test/test/util/fake_ad.js +7 -0
  166. package/test/test/util/fake_ad_manager.js +1 -1
  167. package/test/test/util/fake_drm_engine.js +9 -2
  168. package/test/test/util/manifest_generator.js +3 -2
  169. package/test/test/util/test_scheme.js +14 -1
  170. package/test/test/util/ttml_utils.js +81 -0
  171. package/test/text/mp4_ttml_parser_unit.js +11 -18
  172. package/test/text/ttml_text_parser_unit.js +552 -227
  173. package/test/text/ui_text_displayer_unit.js +29 -17
  174. package/test/ui/localization_unit.js +15 -14
  175. package/test/ui/text_displayer_layout_unit.js +13 -1
  176. package/test/ui/ui_unit.js +250 -0
  177. package/test/util/cmcd_manager_unit.js +291 -0
  178. package/test/util/stream_utils_unit.js +45 -4
  179. package/third_party/closure-uri/uri.js +21 -0
  180. package/ui/airplay_button.js +1 -0
  181. package/ui/audio_language_selection.js +7 -0
  182. package/ui/cast_button.js +3 -3
  183. package/ui/context_menu.js +109 -0
  184. package/ui/controls.js +45 -13
  185. package/ui/controls.less +1 -0
  186. package/ui/enums.js +4 -0
  187. package/ui/externs/ui.js +28 -1
  188. package/ui/fast_forward_button.js +14 -5
  189. package/ui/fullscreen_button.js +1 -0
  190. package/ui/less/buttons.less +0 -4
  191. package/ui/less/containers.less +77 -7
  192. package/ui/less/overflow_menu.less +0 -10
  193. package/ui/less/tooltip.less +97 -0
  194. package/ui/locales/en.json +1 -0
  195. package/ui/locales/ru.json +6 -6
  196. package/ui/locales/source.json +4 -0
  197. package/ui/localization.js +28 -51
  198. package/ui/loop_button.js +5 -0
  199. package/ui/mute_button.js +2 -1
  200. package/ui/overflow_menu.js +5 -25
  201. package/ui/pip_button.js +7 -3
  202. package/ui/play_button.js +2 -2
  203. package/ui/playback_rate_selection.js +8 -9
  204. package/ui/resolution_selection.js +7 -0
  205. package/ui/rewind_button.js +15 -6
  206. package/ui/seek_bar.js +4 -2
  207. package/ui/settings_menu.js +36 -4
  208. package/ui/small_play_button.js +1 -0
  209. package/ui/statistics_button.js +253 -0
  210. package/ui/text_selection.js +12 -4
  211. package/ui/ui.js +30 -0
  212. package/ui/volume_bar.js +1 -1
  213. package/externs/media_capabilities.js +0 -16
package/ui/controls.js CHANGED
@@ -16,6 +16,7 @@ goog.require('shaka.log');
16
16
  goog.require('shaka.ui.AdCounter');
17
17
  goog.require('shaka.ui.AdPosition');
18
18
  goog.require('shaka.ui.BigPlayButton');
19
+ goog.require('shaka.ui.ContextMenu');
19
20
  goog.require('shaka.ui.Locales');
20
21
  goog.require('shaka.ui.Localization');
21
22
  goog.require('shaka.ui.SeekBar');
@@ -323,6 +324,10 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
323
324
  this.playButton_ = null;
324
325
  }
325
326
 
327
+ if (this.contextMenu_) {
328
+ this.contextMenu_ = null;
329
+ }
330
+
326
331
  if (this.controlsContainer_) {
327
332
  shaka.util.Dom.removeAllChildren(this.controlsContainer_);
328
333
  this.releaseChildElements_();
@@ -573,9 +578,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
573
578
  }
574
579
  }
575
580
  } catch (error) {
576
- this.dispatchEvent(new shaka.util.FakeEvent('error', {
577
- detail: error,
578
- }));
581
+ this.dispatchEvent(new shaka.util.FakeEvent(
582
+ 'error', (new Map()).set('detail', error)));
579
583
  }
580
584
  }
581
585
  }
@@ -651,6 +655,10 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
651
655
  this.addPlayButton_();
652
656
  }
653
657
 
658
+ if (this.config_.customContextMenu) {
659
+ this.addContextMenu_();
660
+ }
661
+
654
662
  if (!this.spinnerContainer_) {
655
663
  this.addBufferingSpinner_();
656
664
  }
@@ -709,6 +717,14 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
709
717
  this.elements_.push(this.playButton_);
710
718
  }
711
719
 
720
+ /** @private */
721
+ addContextMenu_() {
722
+ /** @private {shaka.ui.ContextMenu} */
723
+ this.contextMenu_ =
724
+ new shaka.ui.ContextMenu(this.controlsButtonPanel_, this);
725
+ this.elements_.push(this.contextMenu_);
726
+ }
727
+
712
728
  /** @private */
713
729
  addScrimContainer_() {
714
730
  // This is the container that gets styled by CSS to have the
@@ -723,7 +739,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
723
739
  /** @private {!HTMLElement} */
724
740
  this.adPanel_ = shaka.util.Dom.createHTMLElement('div');
725
741
  this.adPanel_.classList.add('shaka-ad-controls');
726
- shaka.ui.Utils.setDisplay(this.adPanel_, this.ad_ != null);
742
+ const showAdPanel = this.ad_ != null && this.ad_.isLinear();
743
+ shaka.ui.Utils.setDisplay(this.adPanel_, showAdPanel);
727
744
  this.bottomControls_.appendChild(this.adPanel_);
728
745
 
729
746
  const adPosition = new shaka.ui.AdPosition(this.adPanel_, this);
@@ -780,8 +797,12 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
780
797
  // on the page. The click event listener on window ensures that.
781
798
  // However, clicks on the bottom controls don't propagate to the container,
782
799
  // so we have to explicitly hide the menus onclick here.
783
- this.eventManager_.listen(this.bottomControls_, 'click', () => {
784
- this.hideSettingsMenus();
800
+ this.eventManager_.listen(this.bottomControls_, 'click', (e) => {
801
+ // We explicitly deny this measure when clicking on buttons that
802
+ // open submenus in the control panel.
803
+ if (!e.target['closest']('.shaka-overflow-button')) {
804
+ this.hideSettingsMenus();
805
+ }
785
806
  });
786
807
 
787
808
  this.addAdControls_();
@@ -791,6 +812,9 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
791
812
  this.controlsButtonPanel_.classList.add('shaka-controls-button-panel');
792
813
  this.controlsButtonPanel_.classList.add(
793
814
  'shaka-show-controls-on-mouse-over');
815
+ if (this.config_.enableTooltips) {
816
+ this.controlsButtonPanel_.classList.add('shaka-tooltips-on');
817
+ }
794
818
  this.bottomControls_.appendChild(this.controlsButtonPanel_);
795
819
 
796
820
  // Create the elements specified by controlPanelElements
@@ -860,7 +884,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
860
884
 
861
885
 
862
886
  /**
863
- * Adds a container for server side ad UI with IMA SDK.
887
+ * Adds a container for client side ad UI with IMA SDK.
864
888
  *
865
889
  * @private
866
890
  */
@@ -869,6 +893,9 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
869
893
  this.clientAdContainer_ = shaka.util.Dom.createHTMLElement('div');
870
894
  this.clientAdContainer_.classList.add('shaka-client-side-ad-container');
871
895
  shaka.ui.Utils.setDisplay(this.clientAdContainer_, false);
896
+ this.eventManager_.listen(this.clientAdContainer_, 'click', () => {
897
+ this.onContainerClick_();
898
+ });
872
899
  this.videoContainer_.appendChild(this.clientAdContainer_);
873
900
  }
874
901
 
@@ -895,6 +922,12 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
895
922
  // Listen for click events to dismiss the settings menus.
896
923
  this.eventManager_.listen(window, 'click', () => this.hideSettingsMenus());
897
924
 
925
+ // Avoid having multiple submenus open at the same time.
926
+ this.eventManager_.listen(
927
+ this, 'submenuopen', () => {
928
+ this.hideSettingsMenus();
929
+ });
930
+
898
931
  this.eventManager_.listen(this.video_, 'play', () => {
899
932
  this.onPlayStateChange_();
900
933
  });
@@ -1101,7 +1134,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1101
1134
  // recent mouse movement, we're in keyboard navigation, or one of a special
1102
1135
  // class of elements is hovered.
1103
1136
  if (adIsPaused ||
1104
- (!this.ad_ && videoIsPaused) ||
1137
+ ((!this.ad_ || !this.ad_.isLinear()) && videoIsPaused) ||
1105
1138
  this.recentMouseMovement_ ||
1106
1139
  keyboardNavigationMode ||
1107
1140
  this.isHovered_()) {
@@ -1145,14 +1178,14 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1145
1178
 
1146
1179
  if (this.anySettingsMenusAreOpen()) {
1147
1180
  this.hideSettingsMenusTimer_.tickNow();
1148
- } else {
1181
+ } else if (this.config_.singleClickForPlayAndPause) {
1149
1182
  this.onPlayPauseClick_();
1150
1183
  }
1151
1184
  }
1152
1185
 
1153
1186
  /** @private */
1154
1187
  onPlayPauseClick_() {
1155
- if (this.ad_) {
1188
+ if (this.ad_ && this.ad_.isLinear()) {
1156
1189
  this.playPauseAd();
1157
1190
  } else {
1158
1191
  this.playPausePresentation();
@@ -1162,9 +1195,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1162
1195
  /** @private */
1163
1196
  onCastStatusChange_() {
1164
1197
  const isCasting = this.castProxy_.isCasting();
1165
- this.dispatchEvent(new shaka.util.FakeEvent('caststatuschanged', {
1166
- newStatus: isCasting,
1167
- }));
1198
+ this.dispatchEvent(new shaka.util.FakeEvent(
1199
+ 'caststatuschanged', (new Map()).set('newStatus', isCasting)));
1168
1200
 
1169
1201
  if (isCasting) {
1170
1202
  this.controlsContainer_.setAttribute('casting', 'true');
package/ui/controls.less CHANGED
@@ -12,6 +12,7 @@
12
12
  @import "less/other_elements.less";
13
13
  @import "less/overflow_menu.less";
14
14
  @import "less/ad_controls.less";
15
+ @import "less/tooltip.less";
15
16
  @import (css, inline) "https://fonts.googleapis.com/css?family=Roboto";
16
17
  // NOTE: Working around google/material-design-icons#958
17
18
  @import (css, inline) "https://fonts.googleapis.com/icon?family=Material+Icons+Round";
package/ui/enums.js CHANGED
@@ -16,7 +16,9 @@ goog.provide('shaka.ui.Enums');
16
16
  shaka.ui.Enums.MaterialDesignIcons = {
17
17
  'FULLSCREEN': 'fullscreen',
18
18
  'EXIT_FULLSCREEN': 'fullscreen_exit',
19
+ 'CLOSE': 'close',
19
20
  'CLOSED_CAPTIONS': 'closed_caption',
21
+ 'CLOSED_CAPTIONS_OFF': 'closed_caption_disabled',
20
22
  'CHECKMARK': 'done',
21
23
  'LANGUAGE': 'language',
22
24
  'PIP': 'picture_in_picture_alt',
@@ -40,4 +42,6 @@ shaka.ui.Enums.MaterialDesignIcons = {
40
42
  'UNLOOP': 'repeat_on',
41
43
  'AIRPLAY': 'airplay',
42
44
  'REPLAY': 'replay',
45
+ 'STATISTICS_ON': 'insert_chart_outlined',
46
+ 'STATISTICS_OFF': 'insert_chart',
43
47
  };
package/ui/externs/ui.js CHANGED
@@ -63,8 +63,14 @@ shaka.extern.UIVolumeBarColors;
63
63
  * @typedef {{
64
64
  * controlPanelElements: !Array.<string>,
65
65
  * overflowMenuButtons: !Array.<string>,
66
+ * contextMenuElements: !Array.<string>,
67
+ * statisticsList: !Array.<string>,
68
+ * playbackRates: !Array.<number>,
69
+ * fastForwardRates: !Array.<number>,
70
+ * rewindRates: !Array.<number>,
66
71
  * addSeekBar: boolean,
67
72
  * addBigPlayButton: boolean,
73
+ * customContextMenu: boolean,
68
74
  * castReceiverAppId: string,
69
75
  * clearBufferOnQualityChange: boolean,
70
76
  * showUnbufferedStart: boolean,
@@ -73,20 +79,34 @@ shaka.extern.UIVolumeBarColors;
73
79
  * trackLabelFormat: shaka.ui.Overlay.TrackLabelFormat,
74
80
  * fadeDelay: number,
75
81
  * doubleClickForFullscreen: boolean,
82
+ * singleClickForPlayAndPause: boolean,
76
83
  * enableKeyboardPlaybackControls: boolean,
77
84
  * enableFullscreenOnRotation: boolean,
78
- * forceLandscapeOnFullscreen: boolean
85
+ * forceLandscapeOnFullscreen: boolean,
86
+ * enableTooltips: boolean
79
87
  * }}
80
88
  *
81
89
  * @property {!Array.<string>} controlPanelElements
82
90
  * The ordered list of control panel elements of the UI.
83
91
  * @property {!Array.<string>} overflowMenuButtons
84
92
  * The ordered list of the overflow menu buttons.
93
+ * @property {!Array.<string>} contextMenuElements
94
+ * The ordered list of buttons in the context menu.
95
+ * @property {!Array.<string>} statisticsList
96
+ * The ordered list of statistics present in the statistics container.
97
+ * @property {!Array.<number>} playbackRates
98
+ * The ordered list of rates for playback selection.
99
+ * @property {!Array.<number>} fastForwardRates
100
+ * The ordered list of rates for fast forward selection.
101
+ * @property {!Array.<number>} rewindRates
102
+ * The ordered list of rates for rewind selection.
85
103
  * @property {boolean} addSeekBar
86
104
  * Whether or not a seek bar should be part of the UI.
87
105
  * @property {boolean} addBigPlayButton
88
106
  * Whether or not a big play button in the center of the video
89
107
  * should be part of the UI.
108
+ * @property {boolean} customContextMenu
109
+ * Whether or not a custom context menu replaces the default.
90
110
  * @property {string} castReceiverAppId
91
111
  * Receiver app id to use for the Chromecast support.
92
112
  * @property {boolean} clearBufferOnQualityChange
@@ -135,6 +155,9 @@ shaka.extern.UIVolumeBarColors;
135
155
  * Whether or not double-clicking on the UI should cause it to enter
136
156
  * fullscreen.
137
157
  * Defaults to true.
158
+ * @property {boolean} singleClickForPlayAndPause
159
+ * Whether or not clicking on the video should cause it to play or pause.
160
+ * Defaults to true.
138
161
  * @property {boolean} enableKeyboardPlaybackControls
139
162
  * Whether or not playback controls via keyboard is enabled, such as seek
140
163
  * forward, seek backward, jump to the beginning/end of the video.
@@ -147,6 +170,10 @@ shaka.extern.UIVolumeBarColors;
147
170
  * enters fullscreen. Note that this behavior is based on an experimental
148
171
  * browser API, and may not work on all platforms.
149
172
  * Defaults to true.
173
+ * @property {boolean} enableTooltips
174
+ * Whether or not buttons in the control panel display tooltips that contain
175
+ * information about their function.
176
+ * Defaults to false.
150
177
  * @exportDoc
151
178
  */
152
179
  shaka.extern.UIConfiguration;
@@ -32,11 +32,16 @@ shaka.ui.FastForwardButton = class extends shaka.ui.Element {
32
32
  this.button_ = shaka.util.Dom.createButton();
33
33
  this.button_.classList.add('material-icons-round');
34
34
  this.button_.classList.add('shaka-fast-forward-button');
35
+ this.button_.classList.add('shaka-tooltip-status');
36
+ this.button_.setAttribute('shaka-status', '1x');
35
37
  this.button_.textContent =
36
38
  shaka.ui.Enums.MaterialDesignIcons.FAST_FORWARD;
37
39
  this.parent.appendChild(this.button_);
38
40
  this.updateAriaLabel_();
39
41
 
42
+ /** @private {!Array.<number>} */
43
+ this.fastForwardRates_ = this.controls.getConfig().fastForwardRates;
44
+
40
45
  this.eventManager.listen(
41
46
  this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
42
47
  this.updateAriaLabel_();
@@ -61,7 +66,7 @@ shaka.ui.FastForwardButton = class extends shaka.ui.Element {
61
66
  }
62
67
 
63
68
  /**
64
- * Cycles trick play rate between 1, 2, 4, and 8.
69
+ * Cycles trick play rate between the selected fast forward rates.
65
70
  * @private
66
71
  */
67
72
  fastForward_() {
@@ -70,11 +75,15 @@ shaka.ui.FastForwardButton = class extends shaka.ui.Element {
70
75
  }
71
76
 
72
77
  const trickPlayRate = this.player.getPlaybackRate();
73
- // Every time the button is clicked, the rate is multiplied by 2,
74
- // unless the rate is at max (8), in which case it is dropped back to 1.
75
- const newRate = (trickPlayRate < 0 || trickPlayRate > 4) ?
76
- 1 : trickPlayRate * 2;
78
+ const newRateIndex = this.fastForwardRates_.indexOf(trickPlayRate) + 1;
79
+
80
+ // When the button is clicked, the next rate in this.fastForwardRates_ is
81
+ // selected. If no more rates are available, the first one is set.
82
+ const newRate = (newRateIndex != this.fastForwardRates_.length) ?
83
+ this.fastForwardRates_[newRateIndex] : this.fastForwardRates_[0];
77
84
  this.player.trickPlay(newRate);
85
+
86
+ this.button_.setAttribute('shaka-status', newRate + 'x');
78
87
  }
79
88
  };
80
89
 
@@ -32,6 +32,7 @@ shaka.ui.FullscreenButton = class extends shaka.ui.Element {
32
32
  this.button_ = shaka.util.Dom.createButton();
33
33
  this.button_.classList.add('shaka-fullscreen-button');
34
34
  this.button_.classList.add('material-icons-round');
35
+ this.button_.classList.add('shaka-tooltip');
35
36
 
36
37
  // Don't show the button if fullscreen is not supported
37
38
  if (!document.fullscreenEnabled) {
@@ -75,10 +75,6 @@
75
75
  .shaka-current-time {
76
76
  font-size: 14px;
77
77
  color: rgb(255, 255, 255);
78
-
79
- /* Make the time element the right size for the text, instead of defaulting
80
- * to the same size as the rest of the controls. */
81
- height: auto;
82
78
  cursor: pointer;
83
79
 
84
80
  &[disabled] {
@@ -195,6 +195,80 @@
195
195
  align-items: center;
196
196
  }
197
197
 
198
+ .shaka-statistics-container {
199
+ overflow-x: hidden;
200
+ overflow-y: auto;
201
+
202
+ min-width: 300px;
203
+
204
+ color: white;
205
+ background-color: rgba(35, 35, 35, 0.9);
206
+
207
+ font-size: 14px;
208
+
209
+ padding: 5px 10px;
210
+ border-radius: 2px;
211
+
212
+ position: absolute;
213
+ z-index: 2;
214
+ left: 15px;
215
+ top: 15px;
216
+
217
+ /* Fades out with the other controls. */
218
+ .show-when-controls-shown();
219
+
220
+ div {
221
+ display: flex;
222
+ justify-content: space-between;
223
+ }
224
+
225
+ span {
226
+ color: rgb(150, 150, 150);
227
+ }
228
+ }
229
+
230
+ .shaka-context-menu {
231
+ background-color: rgba(35, 35, 35, 0.9);
232
+
233
+ border-radius: 2px;
234
+
235
+ position: absolute;
236
+ z-index: 3;
237
+
238
+ button {
239
+ padding: 5px 10px;
240
+
241
+ width: 100%;
242
+ display: flex;
243
+ align-items: center;
244
+
245
+ color: white;
246
+ background: transparent;
247
+ border: 0;
248
+ cursor: pointer;
249
+
250
+ &:hover {
251
+ background-color: rgba(50, 50, 50, 0.9);
252
+ }
253
+ }
254
+
255
+ label {
256
+ padding: 0 20px;
257
+
258
+ align-items: flex-start;
259
+
260
+ color: white;
261
+ cursor: pointer;
262
+ }
263
+
264
+ .shaka-current-selection-span {
265
+ align-items: flex-start;
266
+
267
+ color: white;
268
+ cursor: pointer;
269
+ }
270
+ }
271
+
198
272
  .shaka-scrim-container {
199
273
  margin: 0;
200
274
  .fill-container();
@@ -229,13 +303,9 @@
229
303
  transition-delay: 500ms;
230
304
 
231
305
  /* These are defaults which are overridden by JS or cue styles. */
232
- span:not(.shaka-text-wrapper) {
233
- display: inline;
234
- font-size: 20px;
235
- line-height: 1.4; // relative to font size.
236
- background-color: rgba(0, 0, 0, 0.8);
237
- color: rgb(255, 255, 255);
238
- }
306
+ font-size: 20px;
307
+ line-height: 1.4; // relative to font size.
308
+ color: rgb(255, 255, 255);
239
309
 
240
310
  span.shaka-text-wrapper {
241
311
  display: inline;
@@ -141,13 +141,3 @@
141
141
  /* TODO(b/116651454): eliminate hard-coded offsets */
142
142
  left: 17px;
143
143
  }
144
-
145
- /* The captions button, when captions are on. */
146
- .shaka-captions-on {
147
- color: black;
148
- }
149
-
150
- /* The captions button, when captions are off. */
151
- .shaka-captions-off {
152
- color: grey;
153
- }
@@ -0,0 +1,97 @@
1
+ /*!
2
+ * @license
3
+ * The tooltip is based on https://github.com/felipefialho/css-components/
4
+ * Local modifications have been performed.
5
+ *
6
+ * Copyright (c) 2017 Felipe Fialho
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ */
26
+
27
+ @material-icons-width: 32px;
28
+
29
+ .translateX(@percent) {
30
+ -webkit-transform: translateX(percentage(@percent));
31
+ -moz-transform: translateX(percentage(@percent));
32
+ -ms-transform: translateX(percentage(@percent));
33
+ -o-transform: translateX(percentage(@percent));
34
+ transform: translateX(percentage(@percent));
35
+ }
36
+
37
+ /* .shaka-tooltips-on enables the tooltips and is only added to the
38
+ * control panel when the 'enableTooltips' option is set to true */
39
+ .shaka-tooltips-on {
40
+ overflow: visible;
41
+
42
+ & > [class*="shaka-tooltip"] {
43
+ position: relative;
44
+
45
+ /* The :after pseudo-element contains the tooltip */
46
+ &:hover:after, &:focus-visible:after, &:active:after {
47
+ content: attr(aria-label);
48
+
49
+ /* Override .material-icons-round text styling */
50
+ font-family: Roboto-Regular, Roboto, sans-serif;
51
+ line-height: @material-icons-width / 2;
52
+ white-space: nowrap;
53
+ font-size: 13px;
54
+
55
+ /* Styling */
56
+ background: rgba(35, 35, 35, 0.9);
57
+ color: white;
58
+ border-radius: 3px;
59
+ padding: 5px 10px;
60
+
61
+ /* Positioning */
62
+ position: absolute;
63
+ bottom: @material-icons-width + 5px;
64
+
65
+ /* Left attribute is set to half of the width of the parent button */
66
+ left: @material-icons-width / 2;
67
+
68
+ /* The tooltip is also translated 50% to appear centered */
69
+ .translateX(-0.5);
70
+ }
71
+ }
72
+
73
+ /* Adds an additional attribute for the status in .shaka-tooltip-status */
74
+ & > .shaka-tooltip-status {
75
+ &:hover:after, &:focus-visible:after, &:active:after {
76
+ content: attr(aria-label) " (" attr(shaka-status) ")";
77
+ }
78
+ }
79
+
80
+ /* The first tooltip of the panel is not centered on top of the button
81
+ * but rather aligned with the left border of the control panel */
82
+ button:first-child {
83
+ &:hover:after, &:focus-visible:after, &:active:after {
84
+ left: 0;
85
+ .translateX(0);
86
+ }
87
+ }
88
+
89
+ /* The last tooltip of the panel is not centered on top of the button
90
+ * but rather aligned with the right border of the control panel */
91
+ button:last-child {
92
+ &:hover:after, &:focus-visible:after,&:active:after {
93
+ left: @material-icons-width;
94
+ .translateX(-1);
95
+ }
96
+ }
97
+ }
@@ -33,6 +33,7 @@
33
33
  "SEEK": "Seek",
34
34
  "SKIP_AD": "Skip Ad",
35
35
  "SKIP_TO_LIVE": "Skip ahead to live",
36
+ "STATISTICS": "Statistics",
36
37
  "SUBTITLE_FORCED": "Forced",
37
38
  "UNDETERMINED_LANGUAGE": "Undetermined",
38
39
  "UNMUTE": "Unmute",
@@ -1,10 +1,10 @@
1
1
  {
2
- "AD_DURATION": "Продолжительность объявления",
3
- "AD_PROGRESS": "Объявление [AD_ON] из [NUM_ADS]",
4
- "AD_TIME": "Объявление: [AD_TIME]",
2
+ "AD_DURATION": "Продолжительность рекламы",
3
+ "AD_PROGRESS": "Реклама [AD_ON] из [NUM_ADS]",
4
+ "AD_TIME": "Реклама: [AD_TIME]",
5
5
  "AUTO_QUALITY": "Авто",
6
6
  "BACK": "Назад",
7
- "CAPTIONS": "Титры",
7
+ "CAPTIONS": "Субтитры",
8
8
  "CAST": "Транслировать...",
9
9
  "ENTER_LOOP_MODE": "Зациклить текущее видео",
10
10
  "ENTER_PICTURE_IN_PICTURE": "Перейти в режим \"Картинка в картинке\"",
@@ -20,8 +20,8 @@
20
20
  "MULTIPLE_LANGUAGES": "Несколько языков",
21
21
  "MUTE": "Отключить звук",
22
22
  "NOT_APPLICABLE": "Неприменимо",
23
- "OFF": "Включить",
24
- "ON": "Отключить",
23
+ "OFF": "Выкл.",
24
+ "ON": "Вкл.",
25
25
  "PAUSE": "Пауза",
26
26
  "PICTURE_IN_PICTURE": "Картинка в картинке",
27
27
  "PLAY": "Воспроизвести",
@@ -138,6 +138,10 @@
138
138
  "description": "Label for a button used to skip ahead to the live broadcast.",
139
139
  "message": "Skip ahead to live"
140
140
  },
141
+ "STATISTICS": {
142
+ "description": "Label for a button that displays statistics of the video.",
143
+ "message": "Statistics"
144
+ },
141
145
  "SUBTITLE_FORCED": {
142
146
  "description": "Label used to identify a subtitle track that is forced to be shown.",
143
147
  "message": "Forced"