shaka-player 4.3.10 → 4.4.0

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 (316) hide show
  1. package/.github/workflows/release-please.yaml +7 -0
  2. package/AUTHORS +9 -0
  3. package/CHANGELOG.md +295 -200
  4. package/CONTRIBUTORS +8 -0
  5. package/LICENSE +32 -0
  6. package/README.md +63 -10
  7. package/demo/autoTemplate.txt +40 -5
  8. package/demo/close_button.js +11 -0
  9. package/demo/common/asset.js +13 -1
  10. package/demo/common/assets.js +53 -3
  11. package/demo/common/message_ids.js +25 -1
  12. package/demo/config.js +69 -10
  13. package/demo/customWarning.txt +2 -2
  14. package/demo/index.html +3 -1
  15. package/demo/locales/en.json +26 -2
  16. package/demo/locales/source.json +105 -9
  17. package/demo/main.js +52 -9
  18. package/demo/search.js +3 -1
  19. package/demo/service_worker.js +3 -0
  20. package/dist/controls.css +1 -1
  21. package/dist/controls.css.map +1 -1
  22. package/dist/demo.compiled.debug.js +124 -112
  23. package/dist/demo.compiled.debug.map +3 -3
  24. package/dist/demo.compiled.js +124 -112
  25. package/dist/demo.compiled.map +3 -3
  26. package/dist/deps.js +46 -28
  27. package/dist/locales.js +28 -28
  28. package/dist/receiver.compiled.debug.js +52 -46
  29. package/dist/receiver.compiled.debug.map +3 -3
  30. package/dist/receiver.compiled.js +52 -46
  31. package/dist/receiver.compiled.map +3 -3
  32. package/dist/shaka-player.compiled.d.ts +676 -391
  33. package/dist/shaka-player.compiled.debug.d.ts +676 -391
  34. package/dist/shaka-player.compiled.debug.externs.js +1188 -616
  35. package/dist/shaka-player.compiled.debug.js +1045 -700
  36. package/dist/shaka-player.compiled.debug.map +4 -4
  37. package/dist/shaka-player.compiled.externs.js +1188 -616
  38. package/dist/shaka-player.compiled.js +1094 -933
  39. package/dist/shaka-player.compiled.map +4 -4
  40. package/dist/shaka-player.ui.d.ts +677 -392
  41. package/dist/shaka-player.ui.debug.d.ts +677 -392
  42. package/dist/shaka-player.ui.debug.externs.js +1023 -451
  43. package/dist/shaka-player.ui.debug.js +1100 -739
  44. package/dist/shaka-player.ui.debug.map +4 -4
  45. package/dist/shaka-player.ui.externs.js +1023 -451
  46. package/dist/shaka-player.ui.js +1244 -1071
  47. package/dist/shaka-player.ui.map +4 -4
  48. package/docs/tutorials/ad_monetization.md +15 -1
  49. package/docs/tutorials/application-level-redirects.md +1 -1
  50. package/docs/tutorials/config.md +9 -5
  51. package/docs/tutorials/drm-config.md +61 -0
  52. package/docs/tutorials/fairplay.md +19 -4
  53. package/docs/tutorials/license-server-auth.md +4 -4
  54. package/docs/tutorials/license-wrapping.md +2 -2
  55. package/docs/tutorials/ui-customization.md +7 -3
  56. package/docs/tutorials/ui.md +7 -7
  57. package/docs/tutorials/upgrade.md +3 -0
  58. package/externs/ima.js +123 -2
  59. package/externs/isoboxer.js +217 -0
  60. package/externs/mediakeys.js +18 -0
  61. package/externs/mux.js +1 -105
  62. package/externs/pictureinpicture.js +48 -0
  63. package/externs/shaka/ads.js +61 -1
  64. package/externs/shaka/cea.js +110 -0
  65. package/externs/shaka/codecs.js +32 -0
  66. package/externs/shaka/manifest.js +101 -1
  67. package/externs/shaka/manifest_parser.js +0 -10
  68. package/externs/shaka/net.js +36 -7
  69. package/externs/shaka/offline.js +8 -1
  70. package/externs/shaka/player.js +220 -21
  71. package/externs/shaka/text.js +1 -382
  72. package/externs/shaka/transmuxer.js +59 -0
  73. package/karma.conf.js +13 -0
  74. package/lib/abr/simple_abr_manager.js +6 -3
  75. package/lib/ads/ad_manager.js +60 -2
  76. package/lib/ads/client_side_ad.js +86 -0
  77. package/lib/ads/client_side_ad_manager.js +79 -3
  78. package/lib/ads/server_side_ad.js +86 -0
  79. package/lib/ads/server_side_ad_manager.js +13 -0
  80. package/lib/cast/cast_utils.js +1 -0
  81. package/lib/cea/cea608_data_channel.js +24 -14
  82. package/lib/cea/cea608_memory.js +5 -2
  83. package/lib/cea/cea708_service.js +8 -9
  84. package/lib/cea/cea708_window.js +1 -2
  85. package/lib/cea/cea_decoder.js +23 -6
  86. package/lib/cea/cea_utils.js +25 -2
  87. package/lib/cea/dummy_caption_decoder.js +21 -0
  88. package/lib/cea/dummy_cea_parser.js +1 -3
  89. package/lib/cea/mp4_cea_parser.js +15 -10
  90. package/lib/cea/ts_cea_parser.js +69 -0
  91. package/lib/dash/content_protection.js +32 -2
  92. package/lib/dash/dash_parser.js +93 -31
  93. package/lib/dash/mpd_utils.js +6 -25
  94. package/lib/dash/segment_base.js +12 -14
  95. package/lib/dash/segment_list.js +10 -6
  96. package/lib/dash/segment_template.js +349 -32
  97. package/lib/dependencies/all.js +8 -0
  98. package/lib/hls/hls_classes.js +33 -8
  99. package/lib/hls/hls_parser.js +805 -191
  100. package/lib/hls/manifest_text_parser.js +4 -14
  101. package/lib/media/adaptation_set_criteria.js +43 -3
  102. package/lib/media/closed_caption_parser.js +74 -12
  103. package/lib/media/drm_engine.js +189 -49
  104. package/lib/media/gap_jumping_controller.js +1 -1
  105. package/lib/media/manifest_parser.js +34 -0
  106. package/lib/media/media_source_capabilities.js +10 -0
  107. package/lib/media/media_source_engine.js +475 -231
  108. package/lib/media/playhead.js +1 -1
  109. package/lib/media/presentation_timeline.js +62 -0
  110. package/lib/media/segment_index.js +50 -14
  111. package/lib/media/segment_prefetch.js +277 -0
  112. package/lib/media/segment_reference.js +70 -4
  113. package/lib/media/streaming_engine.js +258 -81
  114. package/lib/media/video_wrapper.js +15 -7
  115. package/lib/mss/content_protection.js +353 -0
  116. package/lib/mss/mss_parser.js +1081 -0
  117. package/lib/net/networking_engine.js +60 -10
  118. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  119. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  120. package/lib/offline/manifest_converter.js +6 -0
  121. package/lib/offline/storage.js +2 -4
  122. package/lib/player.js +309 -105
  123. package/lib/polyfill/media_capabilities.js +43 -3
  124. package/lib/polyfill/patchedmediakeys_apple.js +5 -0
  125. package/lib/polyfill/patchedmediakeys_nop.js +5 -0
  126. package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
  127. package/lib/text/cue.js +208 -130
  128. package/lib/text/lrc_text_parser.js +2 -2
  129. package/lib/text/mp4_vtt_parser.js +2 -2
  130. package/lib/text/sbv_text_parser.js +1 -1
  131. package/lib/text/simple_text_displayer.js +2 -1
  132. package/lib/text/srt_text_parser.js +9 -1
  133. package/lib/text/ssa_text_parser.js +2 -2
  134. package/lib/text/text_engine.js +3 -21
  135. package/lib/text/text_utils.js +71 -20
  136. package/lib/text/ui_text_displayer.js +14 -14
  137. package/lib/text/vtt_text_parser.js +22 -14
  138. package/lib/transmuxer/aac_transmuxer.js +224 -0
  139. package/lib/transmuxer/ac3.js +142 -0
  140. package/lib/transmuxer/ac3_transmuxer.js +212 -0
  141. package/lib/transmuxer/adts.js +232 -0
  142. package/lib/transmuxer/ec3.js +103 -0
  143. package/lib/transmuxer/ec3_transmuxer.js +212 -0
  144. package/lib/transmuxer/h264.js +324 -0
  145. package/lib/transmuxer/mp3_transmuxer.js +204 -0
  146. package/lib/transmuxer/mpeg_audio.js +196 -0
  147. package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
  148. package/lib/transmuxer/mss_transmuxer.js +389 -0
  149. package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
  150. package/lib/transmuxer/transmuxer_engine.js +161 -0
  151. package/lib/transmuxer/ts_transmuxer.js +738 -0
  152. package/lib/util/cmcd_manager.js +131 -71
  153. package/lib/util/error.js +62 -26
  154. package/lib/util/exp_golomb.js +220 -0
  155. package/lib/util/fairplay_utils.js +64 -13
  156. package/lib/util/id3_utils.js +56 -3
  157. package/lib/util/language_utils.js +11 -8
  158. package/lib/util/manifest_parser_utils.js +3 -0
  159. package/lib/util/mime_utils.js +44 -7
  160. package/lib/util/mp4_box_parsers.js +233 -5
  161. package/lib/util/mp4_generator.js +1381 -0
  162. package/lib/util/periods.js +40 -34
  163. package/lib/util/platform.js +17 -3
  164. package/lib/util/player_configuration.js +38 -1
  165. package/lib/util/stream_utils.js +138 -27
  166. package/lib/util/text_parser.js +1 -1
  167. package/lib/util/ts_parser.js +470 -47
  168. package/lib/util/xml_utils.js +16 -3
  169. package/maintained-branches.md +2 -2
  170. package/package.json +3 -1
  171. package/roadmap.md +21 -6
  172. package/shaka-player.uncompiled.js +18 -0
  173. package/test/abr/simple_abr_manager_unit.js +32 -4
  174. package/test/ads/ad_manager_unit.js +18 -2
  175. package/test/cast/cast_utils_unit.js +7 -2
  176. package/test/cea/cea608_memory_unit.js +24 -0
  177. package/test/cea/cea_decoder_unit.js +33 -0
  178. package/test/dash/dash_parser_content_protection_unit.js +93 -3
  179. package/test/dash/dash_parser_live_unit.js +56 -13
  180. package/test/dash/dash_parser_manifest_unit.js +70 -2
  181. package/test/dash/dash_parser_segment_base_unit.js +14 -9
  182. package/test/dash/dash_parser_segment_template_unit.js +286 -6
  183. package/test/demo/demo_unit.js +5 -1
  184. package/test/hls/hls_live_unit.js +188 -28
  185. package/test/hls/hls_parser_unit.js +250 -109
  186. package/test/hls/manifest_text_parser_unit.js +18 -13
  187. package/test/media/adaptation_set_criteria_unit.js +46 -14
  188. package/test/media/adaptation_set_unit.js +2 -0
  189. package/test/media/drm_engine_integration.js +11 -8
  190. package/test/media/drm_engine_unit.js +220 -7
  191. package/test/media/media_source_engine_integration.js +122 -38
  192. package/test/media/media_source_engine_unit.js +133 -153
  193. package/test/media/playhead_unit.js +3 -0
  194. package/test/media/presentation_timeline_unit.js +51 -0
  195. package/test/media/segment_index_unit.js +52 -0
  196. package/test/media/segment_prefetch_unit.js +243 -0
  197. package/test/media/streaming_engine_integration.js +9 -3
  198. package/test/media/streaming_engine_unit.js +440 -59
  199. package/test/mss/mss_parser_content_protection_unit.js +49 -0
  200. package/test/mss/mss_parser_unit.js +472 -0
  201. package/test/mss/mss_player_integration.js +123 -0
  202. package/test/offline/manifest_convert_unit.js +9 -0
  203. package/test/offline/storage_integration.js +6 -1
  204. package/test/player_unit.js +386 -133
  205. package/test/polyfill/media_capabilities_unit.js +18 -0
  206. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  207. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  208. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  209. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  210. package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
  211. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
  212. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  213. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  214. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  215. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  216. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  217. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  218. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  219. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  220. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
  221. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  222. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  223. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  224. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  225. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  226. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  227. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  228. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  229. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
  230. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
  231. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  232. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  233. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  234. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  235. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
  236. package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
  237. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  238. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  239. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  240. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  241. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  242. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  243. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  244. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  245. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  246. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  247. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  248. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  249. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  250. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  251. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
  252. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  253. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  254. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  255. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  256. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  257. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  258. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
  259. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  260. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  261. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  262. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  263. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  264. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  265. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
  266. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
  267. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  268. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  269. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  270. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  271. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
  272. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  273. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  274. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  275. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  276. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  277. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  278. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
  279. package/test/test/boot.js +7 -2
  280. package/test/test/util/fake_ad.js +99 -0
  281. package/test/test/util/fake_ad_manager.js +7 -1
  282. package/test/test/util/fake_networking_engine.js +41 -14
  283. package/test/test/util/fake_segment_prefetch.js +81 -0
  284. package/test/test/util/manifest_generator.js +19 -5
  285. package/test/test/util/mss_parser_util.js +115 -0
  286. package/test/test/util/offline_utils.js +1 -0
  287. package/test/test/util/simple_fakes.js +12 -3
  288. package/test/test/util/streaming_engine_util.js +14 -4
  289. package/test/test/util/ttml_utils.js +2 -2
  290. package/test/text/cue_integration.js +1 -1
  291. package/test/text/srt_text_parser_unit.js +78 -0
  292. package/test/text/text_engine_unit.js +17 -8
  293. package/test/text/ui_text_displayer_unit.js +4 -4
  294. package/test/text/vtt_text_parser_unit.js +59 -40
  295. package/test/text/web_vtt_generator_unit.js +9 -3
  296. package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
  297. package/test/transmuxer/transmuxer_engine_integration.js +60 -0
  298. package/test/transmuxer/transmuxer_integration.js +296 -0
  299. package/test/util/cmcd_manager_unit.js +162 -13
  300. package/test/util/language_utils_unit.js +9 -2
  301. package/test/util/mp4_box_parsers_unit.js +39 -4
  302. package/test/util/periods_unit.js +34 -26
  303. package/test/util/stream_utils_unit.js +60 -107
  304. package/ui/controls.js +19 -1
  305. package/ui/controls.less +1 -0
  306. package/ui/externs/ui.js +11 -1
  307. package/ui/language_utils.js +15 -0
  308. package/ui/less/thumbnails.less +26 -0
  309. package/ui/locales/oc.json +42 -0
  310. package/ui/pip_button.js +83 -2
  311. package/ui/range_element.js +15 -0
  312. package/ui/resolution_selection.js +9 -2
  313. package/ui/seek_bar.js +223 -0
  314. package/ui/ui.js +5 -0
  315. package/lib/cea/i_caption_decoder.js +0 -51
  316. package/lib/cea/i_cea_parser.js +0 -68
@@ -29,7 +29,7 @@ describe('PeriodCombiner', () => {
29
29
  });
30
30
 
31
31
  it('Ad insertion - join during main content', async () => {
32
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
32
+ /** @type {!Array.<shaka.extern.Period>} */
33
33
  const periods = [
34
34
  {
35
35
  id: 'main',
@@ -112,7 +112,7 @@ describe('PeriodCombiner', () => {
112
112
  });
113
113
 
114
114
  it('Ad insertion - join during ad', async () => {
115
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
115
+ /** @type {!Array.<shaka.extern.Period>} */
116
116
  const periods = [
117
117
  {
118
118
  id: 'ad',
@@ -190,7 +190,7 @@ describe('PeriodCombiner', () => {
190
190
  });
191
191
 
192
192
  it('Ad insertion - smaller ad, res not found in main content', async () => {
193
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
193
+ /** @type {!Array.<shaka.extern.Period>} */
194
194
  const periods = [
195
195
  {
196
196
  id: '1',
@@ -240,7 +240,7 @@ describe('PeriodCombiner', () => {
240
240
  });
241
241
 
242
242
  it('Ad insertion - larger ad, res not found in main content', async () => {
243
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
243
+ /** @type {!Array.<shaka.extern.Period>} */
244
244
  const periods = [
245
245
  {
246
246
  id: '1',
@@ -288,7 +288,7 @@ describe('PeriodCombiner', () => {
288
288
  });
289
289
 
290
290
  it('Language changes during and after an ad', async () => {
291
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
291
+ /** @type {!Array.<shaka.extern.Period>} */
292
292
  const periods = [
293
293
  {
294
294
  id: 'show1',
@@ -347,6 +347,7 @@ describe('PeriodCombiner', () => {
347
347
  const spanish = variants.find(
348
348
  (v) => v.video.height == 1080 && v.language == 'es');
349
349
  expect(spanish.audio.originalId).toBe('es*,en,es');
350
+ expect(spanish.audio.originalLanguage).toBe('es');
350
351
  expect(spanish.video.originalId).toBe('1080,480,1080');
351
352
 
352
353
  // The French track is primary in the last period and has English 480p in
@@ -354,6 +355,7 @@ describe('PeriodCombiner', () => {
354
355
  const french = variants.find(
355
356
  (v) => v.video.height == 1080 && v.language == 'fr');
356
357
  expect(french.audio.originalId).toBe('fr,en,fr*');
358
+ expect(french.audio.originalLanguage).toBe('fr');
357
359
  expect(french.video.originalId).toBe('1080,480,1080');
358
360
 
359
361
  // Because there's no English in the first or last periods, the English
@@ -361,11 +363,12 @@ describe('PeriodCombiner', () => {
361
363
  const english = variants.find(
362
364
  (v) => v.video.height == 1080 && v.language == 'en');
363
365
  expect(english.audio.originalId).toBe('es*,en,fr*');
366
+ expect(english.audio.originalLanguage).toBe('en');
364
367
  expect(english.video.originalId).toBe('1080,480,1080');
365
368
  });
366
369
 
367
370
  it('VOD playlist of completely unrelated periods', async () => {
368
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
371
+ /** @type {!Array.<shaka.extern.Period>} */
369
372
  const periods = [
370
373
  {
371
374
  id: 'show1',
@@ -406,7 +409,9 @@ describe('PeriodCombiner', () => {
406
409
  const english = variants.find(
407
410
  (v) => v.video.height == 1080 && v.language == 'en');
408
411
  expect(spanish.audio.originalId).toBe('es,en');
412
+ expect(spanish.audio.originalLanguage).toBe('es');
409
413
  expect(english.audio.originalId).toBe('es,en');
414
+ expect(english.audio.originalLanguage).toBe('en');
410
415
  });
411
416
 
412
417
  it('Multiple representations of the same resolution', async () => {
@@ -416,7 +421,7 @@ describe('PeriodCombiner', () => {
416
421
  /** @type {shaka.extern.Stream} */
417
422
  const video2 = makeVideoStream(480);
418
423
  video2.bandwidth = 2;
419
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
424
+ /** @type {!Array.<shaka.extern.Period>} */
420
425
  const periods = [
421
426
  {
422
427
  id: '1',
@@ -533,7 +538,7 @@ describe('PeriodCombiner', () => {
533
538
  const i3 = makeImageStream(240);
534
539
  i3.originalId = 'i3';
535
540
 
536
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
541
+ /** @type {!Array.<shaka.extern.Period>} */
537
542
  const periods = [
538
543
  {
539
544
  id: '1',
@@ -601,7 +606,7 @@ describe('PeriodCombiner', () => {
601
606
  // Regression test for #3383, where we failed on multi-period content with
602
607
  // multiple image streams per period.
603
608
  it('Can handle multiple image streams', async () => {
604
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
609
+ /** @type {!Array.<shaka.extern.Period>} */
605
610
  const periods = [
606
611
  {
607
612
  id: '1',
@@ -642,7 +647,7 @@ describe('PeriodCombiner', () => {
642
647
  });
643
648
 
644
649
  it('handles text track gaps', async () => {
645
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
650
+ /** @type {!Array.<shaka.extern.Period>} */
646
651
  const periods = [
647
652
  {
648
653
  id: '1',
@@ -680,7 +685,7 @@ describe('PeriodCombiner', () => {
680
685
  ],
681
686
  textStreams: [
682
687
  makeTextStream('en'),
683
- makeTextStream('es'),
688
+ makeTextStream('spa'),
684
689
  ],
685
690
  imageStreams: [],
686
691
  },
@@ -703,11 +708,13 @@ describe('PeriodCombiner', () => {
703
708
  const spanish = textStreams.find((s) => s.language == 'es');
704
709
  const english = textStreams.find((s) => s.language == 'en');
705
710
  expect(spanish.originalId).toBe(',,es');
711
+ expect(spanish.originalLanguage).toBe('spa');
706
712
  expect(english.originalId).toBe('en,,en');
713
+ expect(english.originalLanguage).toBe('en');
707
714
  });
708
715
 
709
716
  it('handles image track gaps', async () => {
710
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
717
+ /** @type {!Array.<shaka.extern.Period>} */
711
718
  const periods = [
712
719
  {
713
720
  id: '1',
@@ -771,7 +778,7 @@ describe('PeriodCombiner', () => {
771
778
  });
772
779
 
773
780
  it('Disjoint audio channels', async () => {
774
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
781
+ /** @type {!Array.<shaka.extern.Period>} */
775
782
  const periods = [
776
783
  {
777
784
  id: '1',
@@ -819,7 +826,7 @@ describe('PeriodCombiner', () => {
819
826
  return stream;
820
827
  };
821
828
 
822
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
829
+ /** @type {!Array.<shaka.extern.Period>} */
823
830
  const periods = [
824
831
  {
825
832
  id: '1',
@@ -867,7 +874,7 @@ describe('PeriodCombiner', () => {
867
874
  return stream;
868
875
  };
869
876
 
870
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
877
+ /** @type {!Array.<shaka.extern.Period>} */
871
878
  const periods = [
872
879
  {
873
880
  id: '1',
@@ -911,7 +918,7 @@ describe('PeriodCombiner', () => {
911
918
  const newCodec = makeVideoStream(720);
912
919
  newCodec.codecs = 'foo.abcd';
913
920
 
914
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
921
+ /** @type {!Array.<shaka.extern.Period>} */
915
922
  const periods = [
916
923
  {
917
924
  id: '1',
@@ -963,7 +970,7 @@ describe('PeriodCombiner', () => {
963
970
  stream4.codecs = 'mp4a.40.2';
964
971
  stream4.roles = ['description'];
965
972
 
966
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
973
+ /** @type {!Array.<shaka.extern.Period>} */
967
974
  const periods = [
968
975
  {
969
976
  id: '0',
@@ -1045,7 +1052,7 @@ describe('PeriodCombiner', () => {
1045
1052
  stream8.bandwidth = 120000;
1046
1053
  stream8.codecs = 'vp09.01.20.08.01';
1047
1054
 
1048
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
1055
+ /** @type {!Array.<shaka.extern.Period>} */
1049
1056
  const periods = [
1050
1057
  {
1051
1058
  id: '0',
@@ -1103,7 +1110,7 @@ describe('PeriodCombiner', () => {
1103
1110
  const stream4 = makeAudioStreamWithRoles(['role1']);
1104
1111
  stream4.originalId = 'stream4';
1105
1112
 
1106
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
1113
+ /** @type {!Array.<shaka.extern.Period>} */
1107
1114
  const periods = [
1108
1115
  {
1109
1116
  id: '1',
@@ -1145,7 +1152,7 @@ describe('PeriodCombiner', () => {
1145
1152
  });
1146
1153
 
1147
1154
  it('Matches streams with roles in common', async () => {
1148
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
1155
+ /** @type {!Array.<shaka.extern.Period>} */
1149
1156
  const periods = [
1150
1157
  {
1151
1158
  id: '1',
@@ -1197,7 +1204,7 @@ describe('PeriodCombiner', () => {
1197
1204
  });
1198
1205
 
1199
1206
  it('Matches streams with mismatched roles', async () => {
1200
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
1207
+ /** @type {!Array.<shaka.extern.Period>} */
1201
1208
  const periods = [
1202
1209
  {
1203
1210
  id: '0',
@@ -1374,7 +1381,7 @@ describe('PeriodCombiner', () => {
1374
1381
  v20.frameRate = 24000/1001;
1375
1382
  v20.bandwidth = 570005990000;
1376
1383
 
1377
- /** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
1384
+ /** @type {!Array.<shaka.extern.Period>} */
1378
1385
  const periods = [
1379
1386
  {
1380
1387
  id: '1',
@@ -1547,7 +1554,8 @@ describe('PeriodCombiner', () => {
1547
1554
  language);
1548
1555
  streamGenerator.primary = primary;
1549
1556
  streamGenerator.channelsCount = channels;
1550
- streamGenerator.originalId = primary ? language + '*' : language;
1557
+ streamGenerator.originalId = primary ?
1558
+ streamGenerator.language + '*' : streamGenerator.language;
1551
1559
  if (channels != 2) {
1552
1560
  streamGenerator.originalId += `-${channels}c`;
1553
1561
  }
@@ -1568,7 +1576,8 @@ describe('PeriodCombiner', () => {
1568
1576
  /* type= */ shaka.util.ManifestParserUtils.ContentType.TEXT,
1569
1577
  language);
1570
1578
  streamGenerator.primary = primary;
1571
- streamGenerator.originalId = primary ? language + '*' : language;
1579
+ streamGenerator.originalId = primary ?
1580
+ streamGenerator.language + '*' : streamGenerator.language;
1572
1581
  return streamGenerator.build_();
1573
1582
  }
1574
1583
 
@@ -1583,8 +1592,7 @@ describe('PeriodCombiner', () => {
1583
1592
  /* manifest= */ null,
1584
1593
  /* isPartial= */ false,
1585
1594
  /* id= */ nextId++,
1586
- /* type= */ shaka.util.ManifestParserUtils.ContentType.IMAGE,
1587
- /* lang= */ 'und');
1595
+ /* type= */ shaka.util.ManifestParserUtils.ContentType.IMAGE);
1588
1596
  streamGenerator.size(width, height);
1589
1597
  streamGenerator.originalId = height.toString();
1590
1598
  streamGenerator.mime('image/jpeg');
@@ -483,7 +483,8 @@ describe('StreamUtils', () => {
483
483
  });
484
484
 
485
485
  await StreamUtils.getDecodingInfosForVariants(manifest.variants,
486
- /* usePersistentLicenses= */false, /* srcEquals= */ false);
486
+ /* usePersistentLicenses= */false, /* srcEquals= */ false,
487
+ /* preferredKeySystems= */ []);
487
488
  expect(manifest.variants.length).toBeTruthy();
488
489
  expect(manifest.variants[0].decodingInfos.length).toBe(1);
489
490
  expect(manifest.variants[0].decodingInfos[0].supported).toBeTruthy();
@@ -499,7 +500,8 @@ describe('StreamUtils', () => {
499
500
  });
500
501
 
501
502
  await StreamUtils.getDecodingInfosForVariants(manifest.variants,
502
- /* usePersistentLicenses= */false, /* srcEquals= */ true);
503
+ /* usePersistentLicenses= */false, /* srcEquals= */ true,
504
+ /* preferredKeySystems= */ []);
503
505
  expect(manifest.variants.length).toBeTruthy();
504
506
  expect(manifest.variants[0].decodingInfos.length).toBe(1);
505
507
  expect(manifest.variants[0].decodingInfos[0].supported).toBeTruthy();
@@ -528,7 +530,8 @@ describe('StreamUtils', () => {
528
530
  });
529
531
 
530
532
  await StreamUtils.getDecodingInfosForVariants(manifest.variants,
531
- /* usePersistentLicenses= */false, /* srcEquals= */ false);
533
+ /* usePersistentLicenses= */false, /* srcEquals= */ false,
534
+ /* preferredKeySystems= */ []);
532
535
  expect(manifest.variants.length).toBe(1);
533
536
  expect(manifest.variants[0].decodingInfos.length).toBe(0);
534
537
  });
@@ -562,7 +565,8 @@ describe('StreamUtils', () => {
562
565
  });
563
566
 
564
567
  await StreamUtils.getDecodingInfosForVariants(manifest.variants,
565
- /* usePersistentLicenses= */ false, /* srcEquals= */ false);
568
+ /* usePersistentLicenses= */ false, /* srcEquals= */ false,
569
+ /* preferredKeySystems= */ []);
566
570
  expect(decodingInfoSpy.calls.argsFor(0)[0].video.transferFunction)
567
571
  .toBe('srgb');
568
572
  expect(decodingInfoSpy.calls.argsFor(1)[0].video.transferFunction)
@@ -573,6 +577,38 @@ describe('StreamUtils', () => {
573
577
  navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
574
578
  }
575
579
  });
580
+
581
+ it('includes streams only with preferred key system', async () => {
582
+ const originalDecodingInfo = navigator.mediaCapabilities.decodingInfo;
583
+
584
+ try {
585
+ navigator.mediaCapabilities.decodingInfo =
586
+ shaka.test.Util.spyFunc(decodingInfoSpy);
587
+
588
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
589
+ manifest.addVariant(0, (variant) => {
590
+ variant.addVideo(1, (stream) => {
591
+ stream.mime('video/mp4', 'avc1.4d400d');
592
+ stream.encrypted = true;
593
+ stream.addDrmInfo('com.widevine.alpha');
594
+ stream.addDrmInfo('com.microsoft.playready');
595
+ });
596
+ });
597
+ });
598
+
599
+ await StreamUtils.getDecodingInfosForVariants(manifest.variants,
600
+ /* usePersistentLicenses= */ false, /* srcEquals= */ false,
601
+ /* preferredKeySystems= */ ['com.microsoft.playready']);
602
+
603
+ // if preferred key system satisfies us, we shouldn't check other ones.
604
+ expect(decodingInfoSpy).toHaveBeenCalledTimes(1);
605
+ expect(decodingInfoSpy.calls.argsFor(0)[0].keySystemConfiguration
606
+ .keySystem)
607
+ .toBe('com.microsoft.playready');
608
+ } finally {
609
+ navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
610
+ }
611
+ });
576
612
  });
577
613
 
578
614
  describe('filterManifest', () => {
@@ -952,7 +988,8 @@ describe('StreamUtils', () => {
952
988
  });
953
989
 
954
990
  await StreamUtils.getDecodingInfosForVariants(manifest.variants,
955
- /* usePersistentLicenses= */false, /* srcEquals= */ false);
991
+ /* usePersistentLicenses= */false, /* srcEquals= */ false,
992
+ /* preferredKeySystems= */ []);
956
993
 
957
994
  shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
958
995
  /* preferredVideoCodecs= */[],
@@ -967,111 +1004,27 @@ describe('StreamUtils', () => {
967
1004
  });
968
1005
  });
969
1006
 
970
- describe('meetsRestrictions', () => {
971
- const oldDateNow = Date.now;
972
- /* @param {shaka.extern.Restrictions} */
973
- const restrictions = {
974
- minWidth: 10,
975
- maxWidth: 20,
976
- minHeight: 10,
977
- maxHeight: 20,
978
- minPixels: 10,
979
- maxPixels: 20,
980
- minFrameRate: 21,
981
- maxFrameRate: 25,
982
- minBandwidth: 1000,
983
- maxBandwidth: 3000,
1007
+ describe('isPlayable', () => {
1008
+ /** @type {shaka.extern.Variant} */
1009
+ const variant = {
1010
+ id: 1,
1011
+ language: 'es',
1012
+ disabledUntilTime: 0,
1013
+ video: null,
1014
+ audio: null,
1015
+ primary: false,
1016
+ bandwidth: 2000,
1017
+ allowedByApplication: true,
1018
+ allowedByKeySystem: true,
1019
+ decodingInfos: [],
984
1020
  };
985
- /* @param {{width: number, height: number}} */
986
- const maxHwRes = {width: 123, height: 456};
987
- /* @param {shaka.extern.Variant} */
988
- let variant;
989
- /* @param {boolean} */
990
- let meetsRestrictionsResult;
991
-
992
- beforeEach(() => {
993
- Date.now = () => 123 * 1000;
994
- });
995
-
996
- afterEach(() => {
997
- Date.now = oldDateNow;
998
- });
999
1021
 
1000
- /*
1001
- * @param {number} disabledUntilTime
1002
- */
1003
- const checkRestrictions = ({disabledUntilTime = 0}) => {
1004
- /* @param {shaka.extern.Variant} */
1005
- variant = {
1006
- id: 1,
1007
- language: 'es',
1008
- disabledUntilTime,
1009
- video: null,
1010
- audio: null,
1011
- primary: false,
1012
- bandwidth: 2000,
1013
- allowedByApplication: true,
1014
- allowedByKeySystem: true,
1015
- decodingInfos: [],
1016
- };
1017
- meetsRestrictionsResult = StreamUtils.meetsRestrictions(variant,
1018
- restrictions, maxHwRes);
1019
- };
1020
-
1021
- describe('when disabledUntilTime > now', () => {
1022
- beforeEach(() => {
1023
- checkRestrictions({disabledUntilTime: 124});
1024
- });
1022
+ it('returns false if variant is disabled', () => {
1023
+ variant.allowedByApplication = true;
1024
+ variant.allowedByKeySystem = true;
1025
+ variant.disabledUntilTime = 1234;
1025
1026
 
1026
- it('does not meet the restrictions', () => {
1027
- expect(meetsRestrictionsResult).toBeFalsy();
1028
- });
1029
-
1030
- it('does not reset disabledUntilTime', () => {
1031
- expect(variant.disabledUntilTime).toBe(124);
1032
- });
1033
- });
1034
-
1035
- describe('when disabledUntilTime == now', () => {
1036
- beforeEach(() => {
1037
- checkRestrictions({disabledUntilTime: 123});
1038
- });
1039
-
1040
- it('meets the restrictions', () => {
1041
- expect(meetsRestrictionsResult).toBeTruthy();
1042
- });
1043
-
1044
- it('resets disabledUntilTime', () => {
1045
- expect(variant.disabledUntilTime).toBe(0);
1046
- });
1047
- });
1048
-
1049
- describe('when disabledUntilTime == now', () => {
1050
- beforeEach(() => {
1051
- checkRestrictions({disabledUntilTime: 122});
1052
- });
1053
-
1054
- it('meets the restrictions', () => {
1055
- expect(meetsRestrictionsResult).toBeTruthy();
1056
- });
1057
-
1058
- it('resets disabledUntilTime', () => {
1059
- expect(variant.disabledUntilTime).toBe(0);
1060
- });
1061
- });
1062
-
1063
- describe('when disabledUntilTime == 0', () => {
1064
- beforeEach(() => {
1065
- checkRestrictions({disabledUntilTime: 0});
1066
- });
1067
-
1068
- it('meets the restrictions', () => {
1069
- expect(meetsRestrictionsResult).toBeTruthy();
1070
- });
1071
-
1072
- it('leaves disabledUntilTime = 0', () => {
1073
- expect(variant.disabledUntilTime).toBe(0);
1074
- });
1027
+ expect(shaka.util.StreamUtils.isPlayable(variant)).toBe(false);
1075
1028
  });
1076
1029
  });
1077
1030
  });
package/ui/controls.js CHANGED
@@ -594,7 +594,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
594
594
  if (document.pictureInPictureElement) {
595
595
  await document.exitPictureInPicture();
596
596
  }
597
- await this.videoContainer_.requestFullscreen({navigationUI: 'hide'});
597
+ const fullScreenElement = this.config_.fullScreenElement;
598
+ await fullScreenElement.requestFullscreen({navigationUI: 'hide'});
598
599
 
599
600
  if (this.config_.forceLandscapeOnFullscreen && screen.orientation) {
600
601
  // Locking to 'landscape' should let it be either
@@ -1270,6 +1271,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1270
1271
  }
1271
1272
 
1272
1273
  const keyboardSeekDistance = this.config_.keyboardSeekDistance;
1274
+ const keyboardLargeSeekDistance = this.config_.keyboardLargeSeekDistance;
1273
1275
 
1274
1276
  switch (event.key) {
1275
1277
  case 'ArrowLeft':
@@ -1288,6 +1290,22 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1288
1290
  this.seek_(this.seekBar_.getValue() + keyboardSeekDistance);
1289
1291
  }
1290
1292
  break;
1293
+ case 'PageDown':
1294
+ // PageDown is like ArrowLeft, but has a larger jump distance, and does
1295
+ // nothing to volume.
1296
+ if (this.seekBar_ && isSeekBar && keyboardSeekDistance > 0) {
1297
+ event.preventDefault();
1298
+ this.seek_(this.seekBar_.getValue() - keyboardLargeSeekDistance);
1299
+ }
1300
+ break;
1301
+ case 'PageUp':
1302
+ // PageDown is like ArrowRight, but has a larger jump distance, and does
1303
+ // nothing to volume.
1304
+ if (this.seekBar_ && isSeekBar && keyboardSeekDistance > 0) {
1305
+ event.preventDefault();
1306
+ this.seek_(this.seekBar_.getValue() + keyboardLargeSeekDistance);
1307
+ }
1308
+ break;
1291
1309
  // Jump to the beginning of the video's seek range.
1292
1310
  case 'Home':
1293
1311
  if (this.seekBar_) {
package/ui/controls.less CHANGED
@@ -13,6 +13,7 @@
13
13
  @import "less/overflow_menu.less";
14
14
  @import "less/ad_controls.less";
15
15
  @import "less/tooltip.less";
16
+ @import "less/thumbnails.less";
16
17
  @import (css, inline) "https://fonts.googleapis.com/css?family=Roboto";
17
18
  // NOTE: Working around google/material-design-icons#958
18
19
  @import (css, inline) "https://fonts.googleapis.com/icon?family=Material+Icons+Round";
package/ui/externs/ui.js CHANGED
@@ -85,7 +85,9 @@ shaka.extern.UIVolumeBarColors;
85
85
  * enableFullscreenOnRotation: boolean,
86
86
  * forceLandscapeOnFullscreen: boolean,
87
87
  * enableTooltips: boolean,
88
- * keyboardSeekDistance: number
88
+ * keyboardSeekDistance: number,
89
+ * keyboardLargeSeekDistance: number,
90
+ * fullScreenElement: HTMLElement
89
91
  * }}
90
92
  *
91
93
  * @property {!Array.<string>} controlPanelElements
@@ -183,6 +185,14 @@ shaka.extern.UIVolumeBarColors;
183
185
  * right keyboard keys when the video is selected. If less than or equal to 0,
184
186
  * no seeking will occur.
185
187
  * Defaults to 5 seconds.
188
+ * @property {number} keyboardLargeSeekDistance
189
+ * The time interval, in seconds, to seek when the user presses the page up or
190
+ * page down keyboard keys when the video is selected. If less than or equal
191
+ * to 0, no seeking will occur.
192
+ * Defaults to 60 seconds.
193
+ * @property {HTMLElement} fullScreenElement
194
+ * DOM element on which fullscreen will be done.
195
+ * Defaults to Shaka Player Container.
186
196
  * @exportDoc
187
197
  */
188
198
  shaka.extern.UIConfiguration;
@@ -193,6 +193,21 @@ shaka.ui.LanguageUtils = class {
193
193
  // Extract the base language from the locale as a fallback step.
194
194
  const language = shaka.util.LanguageUtils.getBase(locale);
195
195
 
196
+ // If Intl.DisplayNames is supported we prefer it, because the list of
197
+ // languages is up to date.
198
+ if (window.Intl && 'DisplayNames' in Intl) {
199
+ try {
200
+ if (Intl.DisplayNames.supportedLocalesOf([locale]).length) {
201
+ const languageNames =
202
+ new Intl.DisplayNames([locale], {type: 'language'});
203
+ const language = languageNames.of(locale);
204
+ return language.charAt(0).toUpperCase() + language.slice(1);
205
+ }
206
+ } catch (e) {
207
+ // Ignore errors and try the fallback
208
+ }
209
+ }
210
+
196
211
  // First try to resolve the full language name.
197
212
  // If that fails, try the base.
198
213
  // Finally, report "unknown".
@@ -0,0 +1,26 @@
1
+ #shaka-player-ui-thumbnail-container {
2
+ background-color: black;
3
+ border: 1px solid black;
4
+ box-shadow: 0 8px 8px 0 rgb(0 0 0 / 50%);
5
+ min-width: 150px;
6
+ overflow: hidden;
7
+ position: absolute;
8
+ visibility: hidden;
9
+ width: 15%;
10
+ z-index: 1;
11
+
12
+ #shaka-player-ui-thumbnail-image {
13
+ position: absolute;
14
+ }
15
+
16
+ #shaka-player-ui-thumbnail-time {
17
+ background-color: rgb(0 0 0 / 50%);
18
+ bottom: 0;
19
+ color: white;
20
+ font-size: 16px;
21
+ left: 0;
22
+ position: absolute;
23
+ right: 0;
24
+ text-align: center;
25
+ }
26
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "AD_DURATION": "Durada publicitat",
3
+ "AD_PROGRESS": "Publicitat [AD_ON:1] de [NUM_ADS:6]",
4
+ "AD_TIME": "Publicitat : [AD_TIME:0:05/0:10]",
5
+ "AIRPLAY": "AirPlay",
6
+ "AUTO_QUALITY": "Auto",
7
+ "BACK": "Tornar",
8
+ "CAPTIONS": "Sostítols",
9
+ "CAST": "Difusar...",
10
+ "ENTER_LOOP_MODE": "Repetir en bocla aquesta vidèo",
11
+ "ENTER_PICTURE_IN_PICTURE": "Passar en mòde vidèo incrustada",
12
+ "EXIT_FULL_SCREEN": "Sortir del plen ecran",
13
+ "EXIT_LOOP_MODE": "Quitar de repetir aquesta vidèo",
14
+ "EXIT_PICTURE_IN_PICTURE": "Quitar lo mòde vidèo incrustada",
15
+ "FAST_FORWARD": "Avança rapida",
16
+ "FULL_SCREEN": "Plen ecran",
17
+ "LANGUAGE": "Lenga",
18
+ "LIVE": "Dirècte",
19
+ "LOOP": "Bocla",
20
+ "MORE_SETTINGS": "Mai de paramètres",
21
+ "MULTIPLE_LANGUAGES": "Multiplas lengas",
22
+ "MUTE": "Amudir",
23
+ "NOT_APPLICABLE": "S’aplica pas",
24
+ "OFF": "Desactivat",
25
+ "ON": "Activat",
26
+ "PAUSE": "Pausa",
27
+ "PICTURE_IN_PICTURE": "Vidèo incrustada",
28
+ "PLAY": "Lectura",
29
+ "PLAYBACK_RATE": "Velocitat de lectura",
30
+ "REPLAY": "Tornar legir",
31
+ "RESOLUTION": "Resolucion",
32
+ "REWIND": "Recular",
33
+ "SEEK": "Cercar",
34
+ "SKIP_AD": "Sautar publicitat",
35
+ "SKIP_TO_LIVE": "Anar al dirècte",
36
+ "STATISTICS": "Estatisticas",
37
+ "SUBTITLE_FORCED": "Forçat",
38
+ "UNDETERMINED_LANGUAGE": "Lenga indeterminada",
39
+ "UNMUTE": "Desamudir",
40
+ "UNRECOGNIZED_LANGUAGE": "Non reconeguda",
41
+ "VOLUME": "Volum",
42
+ }