shaka-player 4.9.13 → 4.10.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.
- package/README.md +4 -0
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +24 -19
- package/dist/locales.js +46 -35
- package/dist/shaka-player.compiled.d.ts +291 -12
- package/dist/shaka-player.compiled.debug.d.ts +291 -12
- package/dist/shaka-player.compiled.debug.externs.js +443 -6
- package/dist/shaka-player.compiled.debug.js +651 -556
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +443 -6
- package/dist/shaka-player.compiled.js +1325 -1270
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +306 -13
- package/dist/shaka-player.ui.debug.d.ts +306 -13
- package/dist/shaka-player.ui.debug.externs.js +477 -18
- package/dist/shaka-player.ui.debug.js +799 -681
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +477 -18
- package/dist/shaka-player.ui.js +1600 -1533
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/ads.js +21 -1
- package/externs/shaka/manifest.js +20 -1
- package/externs/shaka/manifest_parser.js +18 -1
- package/externs/shaka/player.js +164 -50
- package/lib/ads/ad_manager.js +225 -10
- package/lib/ads/ad_utils.js +323 -0
- package/lib/ads/ads_stats.js +24 -0
- package/lib/ads/client_side_ad_manager.js +42 -34
- package/lib/ads/interstitial_ad.js +292 -0
- package/lib/ads/interstitial_ad_manager.js +772 -0
- package/lib/ads/media_tailor_ad_manager.js +19 -22
- package/lib/ads/server_side_ad_manager.js +12 -15
- package/lib/cast/cast_utils.js +1 -0
- package/lib/cea/cea_utils.js +12 -0
- package/lib/cea/mp4_cea_parser.js +17 -0
- package/lib/dash/dash_parser.js +81 -28
- package/lib/dash/segment_base.js +3 -0
- package/lib/hls/hls_parser.js +429 -121
- package/lib/hls/manifest_text_parser.js +1 -0
- package/lib/media/adaptation_set_criteria.js +31 -1
- package/lib/media/drm_engine.js +16 -2
- package/lib/media/manifest_filterer.js +7 -5
- package/lib/media/preload_manager.js +8 -10
- package/lib/media/presentation_timeline.js +37 -5
- package/lib/media/quality_observer.js +68 -2
- package/lib/media/segment_reference.js +1 -1
- package/lib/media/segment_utils.js +33 -1
- package/lib/media/streaming_engine.js +120 -43
- package/lib/mss/mss_parser.js +13 -2
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/manifest_converter.js +3 -0
- package/lib/offline/offline_manifest_parser.js +5 -0
- package/lib/offline/storage.js +2 -0
- package/lib/player.js +498 -165
- package/lib/util/fake_event.js +1 -0
- package/lib/util/manifest_parser_utils.js +9 -2
- package/lib/util/mp4_box_parsers.js +32 -0
- package/lib/util/player_configuration.js +21 -9
- package/lib/util/stats.js +43 -0
- package/package.json +1 -1
- package/shaka-player.uncompiled.js +2 -0
- package/ui/ad_counter.js +3 -3
- package/ui/ad_position.js +3 -3
- package/ui/ad_statistics_button.js +237 -0
- package/ui/audio_language_selection.js +8 -4
- package/ui/controls.js +6 -3
- package/ui/element.js +3 -3
- package/ui/enums.js +1 -0
- package/ui/externs/ui.js +3 -0
- package/ui/language_utils.js +48 -3
- package/ui/less/containers.less +32 -0
- package/ui/less/thumbnails.less +13 -0
- package/ui/locales/en.json +2 -0
- package/ui/locales/es-419.json +2 -0
- package/ui/locales/es.json +3 -0
- package/ui/locales/fr.json +1 -0
- package/ui/locales/pl.json +1 -0
- package/ui/locales/pt-BR.json +1 -0
- package/ui/locales/pt-PT.json +1 -0
- package/ui/locales/source.json +8 -0
- package/ui/mute_button.js +4 -4
- package/ui/overflow_menu.js +3 -3
- package/ui/play_button.js +5 -7
- package/ui/presentation_time.js +3 -3
- package/ui/save_video_frame_button.js +196 -0
- package/ui/seek_bar.js +75 -20
- package/ui/skip_ad_button.js +4 -4
- package/ui/statistics_button.js +14 -2
- package/ui/ui.js +15 -0
- package/ui/volume_bar.js +4 -4
package/ui/language_utils.js
CHANGED
|
@@ -39,6 +39,20 @@ shaka.ui.LanguageUtils = class {
|
|
|
39
39
|
return track.active == true;
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
/** @type {!Map<string, !Set<string>>} */
|
|
43
|
+
const codecsByLanguage = new Map();
|
|
44
|
+
for (const track of tracks) {
|
|
45
|
+
if (!track.audioCodec) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!codecsByLanguage.has(track.language)) {
|
|
49
|
+
codecsByLanguage.set(track.language, new Set());
|
|
50
|
+
}
|
|
51
|
+
codecsByLanguage.get(track.language).add(track.audioCodec);
|
|
52
|
+
}
|
|
53
|
+
const hasDifferentAudioCodecs = (language) =>
|
|
54
|
+
codecsByLanguage.has(language) && codecsByLanguage.get(language).size > 1;
|
|
55
|
+
|
|
42
56
|
// Remove old tracks
|
|
43
57
|
// 1. Save the back to menu button
|
|
44
58
|
const backButton = shaka.ui.Utils.getFirstDescendantWithClassName(
|
|
@@ -59,7 +73,8 @@ shaka.ui.LanguageUtils = class {
|
|
|
59
73
|
}
|
|
60
74
|
};
|
|
61
75
|
|
|
62
|
-
const getCombination = (language, rolesString, label, channelsCount
|
|
76
|
+
const getCombination = (language, rolesString, label, channelsCount,
|
|
77
|
+
audioCodec) => {
|
|
63
78
|
const keys = [
|
|
64
79
|
language,
|
|
65
80
|
rolesString,
|
|
@@ -67,6 +82,9 @@ shaka.ui.LanguageUtils = class {
|
|
|
67
82
|
if (showAudioChannelCountVariants && channelsCount != null) {
|
|
68
83
|
keys.push(channelsCount);
|
|
69
84
|
}
|
|
85
|
+
if (hasDifferentAudioCodecs(language) && audioCodec) {
|
|
86
|
+
keys.push(audioCodec);
|
|
87
|
+
}
|
|
70
88
|
if (label &&
|
|
71
89
|
trackLabelFormat == shaka.ui.Overlay.TrackLabelFormat.LABEL) {
|
|
72
90
|
keys.push(label);
|
|
@@ -82,6 +100,21 @@ shaka.ui.LanguageUtils = class {
|
|
|
82
100
|
return name;
|
|
83
101
|
};
|
|
84
102
|
|
|
103
|
+
const getAudioCodecName = (audioCodec) => {
|
|
104
|
+
let name = '';
|
|
105
|
+
audioCodec = audioCodec.toLowerCase();
|
|
106
|
+
if (audioCodec.startsWith('mp4a')) {
|
|
107
|
+
name = 'AAC';
|
|
108
|
+
} else if (audioCodec === 'ec-3' || audioCodec === 'ac-3') {
|
|
109
|
+
name = 'Dolby';
|
|
110
|
+
} else if (audioCodec === 'opus') {
|
|
111
|
+
name = 'Opus';
|
|
112
|
+
} else if (audioCodec === 'flac') {
|
|
113
|
+
name = 'fLaC';
|
|
114
|
+
}
|
|
115
|
+
return name ? ' ' + name : name;
|
|
116
|
+
};
|
|
117
|
+
|
|
85
118
|
/** @type {!Map.<string, !Set.<string>>} */
|
|
86
119
|
const rolesByLanguage = new Map();
|
|
87
120
|
for (const track of tracks) {
|
|
@@ -96,7 +129,8 @@ shaka.ui.LanguageUtils = class {
|
|
|
96
129
|
const combinationsMade = new Set();
|
|
97
130
|
const selectedCombination = selectedTrack ? getCombination(
|
|
98
131
|
selectedTrack.language, getRolesString(selectedTrack),
|
|
99
|
-
selectedTrack.label, selectedTrack.channelsCount
|
|
132
|
+
selectedTrack.label, selectedTrack.channelsCount,
|
|
133
|
+
selectedTrack.audioCodec) : '';
|
|
100
134
|
|
|
101
135
|
for (const track of tracks) {
|
|
102
136
|
const language = track.language;
|
|
@@ -105,8 +139,10 @@ shaka.ui.LanguageUtils = class {
|
|
|
105
139
|
const rolesString = getRolesString(track);
|
|
106
140
|
const label = track.label;
|
|
107
141
|
const channelsCount = track.channelsCount;
|
|
142
|
+
const audioCodec = track.audioCodec;
|
|
108
143
|
const combinationName =
|
|
109
|
-
getCombination(language, rolesString, label, channelsCount
|
|
144
|
+
getCombination(language, rolesString, label, channelsCount,
|
|
145
|
+
audioCodec);
|
|
110
146
|
if (combinationsMade.has(combinationName)) {
|
|
111
147
|
continue;
|
|
112
148
|
}
|
|
@@ -124,6 +160,9 @@ shaka.ui.LanguageUtils = class {
|
|
|
124
160
|
shaka.ui.LanguageUtils.getLanguageName(language, localization);
|
|
125
161
|
switch (trackLabelFormat) {
|
|
126
162
|
case shaka.ui.Overlay.TrackLabelFormat.LANGUAGE:
|
|
163
|
+
if (hasDifferentAudioCodecs(language)) {
|
|
164
|
+
span.textContent += getAudioCodecName(audioCodec);
|
|
165
|
+
}
|
|
127
166
|
if (showAudioChannelCountVariants) {
|
|
128
167
|
span.textContent += getChannelsCountName(channelsCount);
|
|
129
168
|
}
|
|
@@ -132,6 +171,9 @@ shaka.ui.LanguageUtils = class {
|
|
|
132
171
|
}
|
|
133
172
|
break;
|
|
134
173
|
case shaka.ui.Overlay.TrackLabelFormat.ROLE:
|
|
174
|
+
if (hasDifferentAudioCodecs(language)) {
|
|
175
|
+
span.textContent += getAudioCodecName(audioCodec);
|
|
176
|
+
}
|
|
135
177
|
if (showAudioChannelCountVariants) {
|
|
136
178
|
span.textContent += getChannelsCountName(channelsCount);
|
|
137
179
|
}
|
|
@@ -148,6 +190,9 @@ shaka.ui.LanguageUtils = class {
|
|
|
148
190
|
}
|
|
149
191
|
break;
|
|
150
192
|
case shaka.ui.Overlay.TrackLabelFormat.LANGUAGE_ROLE:
|
|
193
|
+
if (hasDifferentAudioCodecs(language)) {
|
|
194
|
+
span.textContent += getAudioCodecName(audioCodec);
|
|
195
|
+
}
|
|
151
196
|
if (showAudioChannelCountVariants) {
|
|
152
197
|
span.textContent += getChannelsCountName(channelsCount);
|
|
153
198
|
}
|
package/ui/less/containers.less
CHANGED
|
@@ -248,6 +248,38 @@
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
.shaka-ad-statistics-container {
|
|
252
|
+
overflow-x: hidden;
|
|
253
|
+
overflow-y: auto;
|
|
254
|
+
|
|
255
|
+
min-width: 150px;
|
|
256
|
+
|
|
257
|
+
color: white;
|
|
258
|
+
background-color: rgba(35 35 35 / 90%);
|
|
259
|
+
|
|
260
|
+
font-size: 14px;
|
|
261
|
+
|
|
262
|
+
padding: 5px 10px;
|
|
263
|
+
border-radius: 2px;
|
|
264
|
+
|
|
265
|
+
position: absolute;
|
|
266
|
+
z-index: 2;
|
|
267
|
+
right: 15px;
|
|
268
|
+
top: 15px;
|
|
269
|
+
|
|
270
|
+
/* Fades out with the other controls. */
|
|
271
|
+
.show-when-controls-shown();
|
|
272
|
+
|
|
273
|
+
div {
|
|
274
|
+
display: flex;
|
|
275
|
+
justify-content: space-between;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
span {
|
|
279
|
+
color: rgb(150 150 150);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
251
283
|
.shaka-context-menu {
|
|
252
284
|
background-color: rgba(35 35 35 / 90%);
|
|
253
285
|
|
package/ui/less/thumbnails.less
CHANGED
|
@@ -24,3 +24,16 @@
|
|
|
24
24
|
text-align: center;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
#shaka-player-ui-time-container {
|
|
29
|
+
background-color: white;
|
|
30
|
+
border: 1px solid black;
|
|
31
|
+
border-radius: 10px;
|
|
32
|
+
box-shadow: 0 8px 8px 0 rgb(0 0 0 / 50%);
|
|
33
|
+
color: black;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
padding: 1px 7px;
|
|
36
|
+
position: absolute;
|
|
37
|
+
visibility: hidden;
|
|
38
|
+
z-index: 1;
|
|
39
|
+
}
|
package/ui/locales/en.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"AD_DURATION": "Ad duration",
|
|
3
3
|
"AD_PROGRESS": "Ad [AD_ON] of [NUM_ADS]",
|
|
4
|
+
"AD_STATISTICS": "Ad statistics",
|
|
4
5
|
"AD_TIME": "Ad: [AD_TIME]",
|
|
5
6
|
"AIRPLAY": "AirPlay",
|
|
6
7
|
"AUTO_QUALITY": "Auto",
|
|
7
8
|
"BACK": "Back",
|
|
8
9
|
"CAPTIONS": "Captions",
|
|
9
10
|
"CAST": "Cast...",
|
|
11
|
+
"DOWNLOAD_VIDEO_FRAME": "Save video frame",
|
|
10
12
|
"ENTER_LOOP_MODE": "Loop the current video",
|
|
11
13
|
"ENTER_PICTURE_IN_PICTURE": "Enter Picture-in-Picture",
|
|
12
14
|
"EXIT_FULL_SCREEN": "Exit full screen",
|
package/ui/locales/es-419.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"AD_DURATION": "Duración del anuncio",
|
|
3
3
|
"AD_PROGRESS": "Anuncio [AD_ON] de [NUM_ADS]",
|
|
4
|
+
"AD_STATISTICS": "Estadísticas de anuncios",
|
|
4
5
|
"AD_TIME": "Anuncio: [AD_TIME]",
|
|
5
6
|
"AUTO_QUALITY": "Automático",
|
|
6
7
|
"BACK": "Atrás",
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"SEEK": "Buscar",
|
|
33
34
|
"SKIP_AD": "Omitir anuncio",
|
|
34
35
|
"SKIP_TO_LIVE": "Adelantar hasta la transmisión en vivo",
|
|
36
|
+
"STATISTICS": "Estadísticas",
|
|
35
37
|
"SUBTITLE_FORCED": "Forzado",
|
|
36
38
|
"SURROUND": "Envolvente",
|
|
37
39
|
"TOGGLE_STEREOSCOPIC": "Alternar estereoscópico",
|
package/ui/locales/es.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"AD_DURATION": "Duración del anuncio",
|
|
3
3
|
"AD_PROGRESS": "Anuncio [AD_ON] de [NUM_ADS]",
|
|
4
|
+
"AD_STATISTICS": "Estadísticas de anuncios",
|
|
4
5
|
"AD_TIME": "Anuncio: [AD_TIME]",
|
|
5
6
|
"AIRPLAY": "AirPlay",
|
|
6
7
|
"AUTO_QUALITY": "Automático",
|
|
7
8
|
"BACK": "Atrás",
|
|
8
9
|
"CAPTIONS": "Subtítulos",
|
|
9
10
|
"CAST": "Enviar...",
|
|
11
|
+
"DOWNLOAD_VIDEO_FRAME": "Guardar fotograma",
|
|
10
12
|
"ENTER_LOOP_MODE": "Reproducir en bucle el vídeo actual",
|
|
11
13
|
"ENTER_PICTURE_IN_PICTURE": "Activar el modo imagen en imagen",
|
|
12
14
|
"EXIT_FULL_SCREEN": "Salir del modo de pantalla completa",
|
|
@@ -34,6 +36,7 @@
|
|
|
34
36
|
"SEEK": "Buscar",
|
|
35
37
|
"SKIP_AD": "Saltar anuncio",
|
|
36
38
|
"SKIP_TO_LIVE": "Ir al vídeo en directo",
|
|
39
|
+
"STATISTICS": "Estadísticas",
|
|
37
40
|
"SUBTITLE_FORCED": "Forzado",
|
|
38
41
|
"SURROUND": "Envolvente",
|
|
39
42
|
"TOGGLE_STEREOSCOPIC": "Alternar estereoscópico",
|
package/ui/locales/fr.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"BACK": "Retour",
|
|
9
9
|
"CAPTIONS": "Sous-titres",
|
|
10
10
|
"CAST": "Caster…",
|
|
11
|
+
"DOWNLOAD_VIDEO_FRAME": "Enregistrer l'image vidéo",
|
|
11
12
|
"ENTER_LOOP_MODE": "Lire en boucle la vidéo en cours",
|
|
12
13
|
"ENTER_PICTURE_IN_PICTURE": "Utiliser le mode Picture-in-Picture",
|
|
13
14
|
"EXIT_FULL_SCREEN": "Quitter le mode plein écran",
|
package/ui/locales/pl.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"BACK": "Wstecz",
|
|
9
9
|
"CAPTIONS": "Napisy",
|
|
10
10
|
"CAST": "Przesyłaj...",
|
|
11
|
+
"DOWNLOAD_VIDEO_FRAME": "Zapisz klatkę wideo",
|
|
11
12
|
"ENTER_LOOP_MODE": "Odtwarzaj bieżący film w pętli",
|
|
12
13
|
"ENTER_PICTURE_IN_PICTURE": "Włącz tryb obrazu w obrazie",
|
|
13
14
|
"EXIT_FULL_SCREEN": "Zamknij pełny ekran",
|
package/ui/locales/pt-BR.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"BACK": "Voltar",
|
|
9
9
|
"CAPTIONS": "Legendas",
|
|
10
10
|
"CAST": "Transmitir...",
|
|
11
|
+
"DOWNLOAD_VIDEO_FRAME": "Salvar quadro de vídeo",
|
|
11
12
|
"ENTER_LOOP_MODE": "Repetir o vídeo atual",
|
|
12
13
|
"ENTER_PICTURE_IN_PICTURE": "Entrar no modo picture-in-picture",
|
|
13
14
|
"EXIT_FULL_SCREEN": "Sair do modo tela cheia",
|
package/ui/locales/pt-PT.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"BACK": "Anterior",
|
|
9
9
|
"CAPTIONS": "Legendas",
|
|
10
10
|
"CAST": "Transmitir...",
|
|
11
|
+
"DOWNLOAD_VIDEO_FRAME": "Salvar quadro de vídeo",
|
|
11
12
|
"ENTER_LOOP_MODE": "Repetir o vídeo atual",
|
|
12
13
|
"ENTER_PICTURE_IN_PICTURE": "Entrar no modo ecrã no ecrã",
|
|
13
14
|
"EXIT_FULL_SCREEN": "Sair do modo de ecrã inteiro",
|
package/ui/locales/source.json
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
"description": "The contents of the ad countdown element, describing what ad you are on in a sequence of ads.",
|
|
8
8
|
"message": "Ad [AD_ON:1] of [NUM_ADS:6]"
|
|
9
9
|
},
|
|
10
|
+
"AD_STATISTICS": {
|
|
11
|
+
"description": "Label for a button that displays ad statistics.",
|
|
12
|
+
"message": "Ad statistics"
|
|
13
|
+
},
|
|
10
14
|
"AD_TIME": {
|
|
11
15
|
"description": "The text content of a label that shows how much time is left in the current ad.",
|
|
12
16
|
"message": "Ad: [AD_TIME:0:05/0:10]"
|
|
@@ -33,6 +37,10 @@
|
|
|
33
37
|
"description": "Label for a button used to open the native Cast dialog in the browser and select a destination to Cast to.",
|
|
34
38
|
"message": "Cast..."
|
|
35
39
|
},
|
|
40
|
+
"DOWNLOAD_VIDEO_FRAME": {
|
|
41
|
+
"description": "Label for a button used to download the current video frame.",
|
|
42
|
+
"message": "Save video frame"
|
|
43
|
+
},
|
|
36
44
|
"ENTER_LOOP_MODE": {
|
|
37
45
|
"description": "Label for a button that controls the loop mode of a video player. This mode will loop (play over and over) currently selected video.",
|
|
38
46
|
"message": "Loop the current video"
|
package/ui/mute_button.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
goog.provide('shaka.ui.MuteButton');
|
|
9
9
|
|
|
10
|
-
goog.require('shaka.ads.
|
|
10
|
+
goog.require('shaka.ads.Utils');
|
|
11
11
|
goog.require('shaka.ui.Controls');
|
|
12
12
|
goog.require('shaka.ui.Element');
|
|
13
13
|
goog.require('shaka.ui.Enums');
|
|
@@ -62,19 +62,19 @@ shaka.ui.MuteButton = class extends shaka.ui.Element {
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
this.eventManager.listen(this.adManager,
|
|
65
|
-
shaka.ads.
|
|
65
|
+
shaka.ads.Utils.AD_VOLUME_CHANGED, () => {
|
|
66
66
|
this.updateAriaLabel_();
|
|
67
67
|
this.updateIcon_();
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
this.eventManager.listen(this.adManager,
|
|
71
|
-
shaka.ads.
|
|
71
|
+
shaka.ads.Utils.AD_MUTED, () => {
|
|
72
72
|
this.updateAriaLabel_();
|
|
73
73
|
this.updateIcon_();
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
this.eventManager.listen(this.adManager,
|
|
77
|
-
shaka.ads.
|
|
77
|
+
shaka.ads.Utils.AD_STOPPED, () => {
|
|
78
78
|
// The base class also listens for this event and sets this.ad
|
|
79
79
|
// to null. This is a safeguard in case of a race condition as
|
|
80
80
|
// the label and icon code depends on this.ad being correctly
|
package/ui/overflow_menu.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
goog.provide('shaka.ui.OverflowMenu');
|
|
9
9
|
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
|
-
goog.require('shaka.ads.
|
|
11
|
+
goog.require('shaka.ads.Utils');
|
|
12
12
|
goog.require('shaka.log');
|
|
13
13
|
goog.require('shaka.ui.Controls');
|
|
14
14
|
goog.require('shaka.ui.Element');
|
|
@@ -59,14 +59,14 @@ shaka.ui.OverflowMenu = class extends shaka.ui.Element {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
this.eventManager.listen(
|
|
62
|
-
this.adManager, shaka.ads.
|
|
62
|
+
this.adManager, shaka.ads.Utils.AD_STARTED, () => {
|
|
63
63
|
if (this.ad && this.ad.isLinear()) {
|
|
64
64
|
shaka.ui.Utils.setDisplay(this.overflowMenuButton_, false);
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
this.eventManager.listen(
|
|
69
|
-
this.adManager, shaka.ads.
|
|
69
|
+
this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
|
|
70
70
|
shaka.ui.Utils.setDisplay(this.overflowMenuButton_, true);
|
|
71
71
|
});
|
|
72
72
|
|
package/ui/play_button.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
goog.provide('shaka.ui.PlayButton');
|
|
9
9
|
|
|
10
|
-
goog.require('shaka.ads.
|
|
10
|
+
goog.require('shaka.ads.Utils');
|
|
11
11
|
goog.require('shaka.ui.Element');
|
|
12
12
|
goog.require('shaka.ui.Localization');
|
|
13
13
|
goog.require('shaka.util.Dom');
|
|
@@ -27,8 +27,6 @@ shaka.ui.PlayButton = class extends shaka.ui.Element {
|
|
|
27
27
|
constructor(parent, controls) {
|
|
28
28
|
super(parent, controls);
|
|
29
29
|
|
|
30
|
-
const AdManager = shaka.ads.AdManager;
|
|
31
|
-
|
|
32
30
|
/** @protected {!HTMLButtonElement} */
|
|
33
31
|
this.button = shaka.util.Dom.createButton();
|
|
34
32
|
this.parent.appendChild(this.button);
|
|
@@ -58,22 +56,22 @@ shaka.ui.PlayButton = class extends shaka.ui.Element {
|
|
|
58
56
|
this.updateIcon();
|
|
59
57
|
});
|
|
60
58
|
|
|
61
|
-
this.eventManager.listen(this.adManager,
|
|
59
|
+
this.eventManager.listen(this.adManager, shaka.ads.Utils.AD_PAUSED, () => {
|
|
62
60
|
this.updateAriaLabel();
|
|
63
61
|
this.updateIcon();
|
|
64
62
|
});
|
|
65
63
|
|
|
66
|
-
this.eventManager.listen(this.adManager,
|
|
64
|
+
this.eventManager.listen(this.adManager, shaka.ads.Utils.AD_RESUMED, () => {
|
|
67
65
|
this.updateAriaLabel();
|
|
68
66
|
this.updateIcon();
|
|
69
67
|
});
|
|
70
68
|
|
|
71
|
-
this.eventManager.listen(this.adManager,
|
|
69
|
+
this.eventManager.listen(this.adManager, shaka.ads.Utils.AD_STARTED, () => {
|
|
72
70
|
this.updateAriaLabel();
|
|
73
71
|
this.updateIcon();
|
|
74
72
|
});
|
|
75
73
|
|
|
76
|
-
this.eventManager.listen(this.adManager,
|
|
74
|
+
this.eventManager.listen(this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
|
|
77
75
|
this.updateAriaLabel();
|
|
78
76
|
this.updateIcon();
|
|
79
77
|
});
|
package/ui/presentation_time.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
goog.provide('shaka.ui.PresentationTimeTracker');
|
|
9
9
|
|
|
10
|
-
goog.require('shaka.ads.
|
|
10
|
+
goog.require('shaka.ads.Utils');
|
|
11
11
|
goog.require('shaka.ui.Controls');
|
|
12
12
|
goog.require('shaka.ui.Element');
|
|
13
13
|
goog.require('shaka.ui.Locales');
|
|
@@ -54,12 +54,12 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
this.eventManager.listen(
|
|
57
|
-
this.adManager, shaka.ads.
|
|
57
|
+
this.adManager, shaka.ads.Utils.AD_STARTED, () => {
|
|
58
58
|
shaka.ui.Utils.setDisplay(this.currentTime_, false);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
this.eventManager.listen(
|
|
62
|
-
this.adManager, shaka.ads.
|
|
62
|
+
this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
|
|
63
63
|
shaka.ui.Utils.setDisplay(this.currentTime_, true);
|
|
64
64
|
});
|
|
65
65
|
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
goog.provide('shaka.ui.SaveVideoFrameButton');
|
|
9
|
+
|
|
10
|
+
goog.require('shaka.ads.Utils');
|
|
11
|
+
goog.require('shaka.ui.ContextMenu');
|
|
12
|
+
goog.require('shaka.ui.Controls');
|
|
13
|
+
goog.require('shaka.ui.Element');
|
|
14
|
+
goog.require('shaka.ui.Enums');
|
|
15
|
+
goog.require('shaka.ui.Locales');
|
|
16
|
+
goog.require('shaka.ui.Localization');
|
|
17
|
+
goog.require('shaka.ui.OverflowMenu');
|
|
18
|
+
goog.require('shaka.ui.Utils');
|
|
19
|
+
goog.require('shaka.util.Dom');
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @extends {shaka.ui.Element}
|
|
24
|
+
* @final
|
|
25
|
+
* @export
|
|
26
|
+
*/
|
|
27
|
+
shaka.ui.SaveVideoFrameButton = class extends shaka.ui.Element {
|
|
28
|
+
/**
|
|
29
|
+
* @param {!HTMLElement} parent
|
|
30
|
+
* @param {!shaka.ui.Controls} controls
|
|
31
|
+
*/
|
|
32
|
+
constructor(parent, controls) {
|
|
33
|
+
super(parent, controls);
|
|
34
|
+
|
|
35
|
+
const LocIds = shaka.ui.Locales.Ids;
|
|
36
|
+
/** @private {!HTMLButtonElement} */
|
|
37
|
+
this.button_ = shaka.util.Dom.createButton();
|
|
38
|
+
this.button_.classList.add('shaka-save.video-frame-button');
|
|
39
|
+
this.button_.classList.add('shaka-tooltip');
|
|
40
|
+
|
|
41
|
+
/** @private {!HTMLElement} */
|
|
42
|
+
this.icon_ = shaka.util.Dom.createHTMLElement('i');
|
|
43
|
+
this.icon_.classList.add('material-icons-round');
|
|
44
|
+
this.icon_.textContent = shaka.ui.Enums.MaterialDesignIcons.DOWNLOAD;
|
|
45
|
+
this.button_.appendChild(this.icon_);
|
|
46
|
+
|
|
47
|
+
const label = shaka.util.Dom.createHTMLElement('label');
|
|
48
|
+
label.classList.add('shaka-overflow-button-label');
|
|
49
|
+
label.classList.add('shaka-overflow-menu-only');
|
|
50
|
+
this.nameSpan_ = shaka.util.Dom.createHTMLElement('span');
|
|
51
|
+
this.nameSpan_.textContent =
|
|
52
|
+
this.localization.resolve(LocIds.DOWNLOAD_VIDEO_FRAME);
|
|
53
|
+
label.appendChild(this.nameSpan_);
|
|
54
|
+
|
|
55
|
+
/** @private {!HTMLElement} */
|
|
56
|
+
this.currentState_ = shaka.util.Dom.createHTMLElement('span');
|
|
57
|
+
this.currentState_.classList.add('shaka-current-selection-span');
|
|
58
|
+
label.appendChild(this.currentState_);
|
|
59
|
+
|
|
60
|
+
this.button_.appendChild(label);
|
|
61
|
+
|
|
62
|
+
this.updateLocalizedStrings_();
|
|
63
|
+
|
|
64
|
+
this.parent.appendChild(this.button_);
|
|
65
|
+
|
|
66
|
+
this.eventManager.listen(
|
|
67
|
+
this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
|
|
68
|
+
this.updateLocalizedStrings_();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
this.eventManager.listen(
|
|
72
|
+
this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
|
|
73
|
+
this.updateLocalizedStrings_();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.eventManager.listen(this.button_, 'click', () => {
|
|
77
|
+
this.onClick_();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const vr = this.controls.getVR();
|
|
81
|
+
this.eventManager.listen(vr, 'vrstatuschanged', () => {
|
|
82
|
+
this.checkAvailability_();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
this.eventManager.listen(
|
|
86
|
+
this.adManager, shaka.ads.Utils.AD_STARTED, () => {
|
|
87
|
+
this.checkAvailability_();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
this.eventManager.listen(
|
|
91
|
+
this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
|
|
92
|
+
this.checkAvailability_();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
this.eventManager.listen(this.player, 'unloading', () => {
|
|
96
|
+
this.checkAvailability_();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.eventManager.listen(this.player, 'loaded', () => {
|
|
100
|
+
this.checkAvailability_();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
this.eventManager.listen(this.player, 'loaded', () => {
|
|
104
|
+
this.checkAvailability_();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this.eventManager.listen(this.video, 'play', () => {
|
|
108
|
+
this.checkAvailability_();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
this.eventManager.listen(this.video, 'pause', () => {
|
|
112
|
+
this.checkAvailability_();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
this.eventManager.listen(this.video, 'seeking', () => {
|
|
116
|
+
this.checkAvailability_();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
this.checkAvailability_();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
/** @private */
|
|
124
|
+
onClick_() {
|
|
125
|
+
const canvas = /** @type {!HTMLCanvasElement}*/ (
|
|
126
|
+
document.createElement('canvas'));
|
|
127
|
+
const context = /** @type {CanvasRenderingContext2D} */ (
|
|
128
|
+
canvas.getContext('2d'));
|
|
129
|
+
|
|
130
|
+
const video = /** @type {!HTMLVideoElement} */ (
|
|
131
|
+
this.controls.getLocalVideo());
|
|
132
|
+
|
|
133
|
+
canvas.width = video.videoWidth;
|
|
134
|
+
canvas.height = video.videoHeight;
|
|
135
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
136
|
+
|
|
137
|
+
const dataURL = canvas.toDataURL('image/png');
|
|
138
|
+
|
|
139
|
+
const downloadLink = /** @type {!HTMLAnchorElement}*/ (
|
|
140
|
+
document.createElement('a'));
|
|
141
|
+
downloadLink.href = dataURL;
|
|
142
|
+
downloadLink.download =
|
|
143
|
+
'videoframe_' + video.currentTime.toFixed(3) + '.png';
|
|
144
|
+
downloadLink.click();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @private
|
|
150
|
+
*/
|
|
151
|
+
checkAvailability_() {
|
|
152
|
+
let available = true;
|
|
153
|
+
if (this.controls.isPlayingVR()) {
|
|
154
|
+
available = false;
|
|
155
|
+
}
|
|
156
|
+
if (this.player.drmInfo() || this.player.isAudioOnly()) {
|
|
157
|
+
available = false;
|
|
158
|
+
}
|
|
159
|
+
if (this.ad) {
|
|
160
|
+
available = false;
|
|
161
|
+
}
|
|
162
|
+
shaka.ui.Utils.setDisplay(this.button_, available);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
updateLocalizedStrings_() {
|
|
170
|
+
const LocIds = shaka.ui.Locales.Ids;
|
|
171
|
+
|
|
172
|
+
this.button_.ariaLabel =
|
|
173
|
+
this.localization.resolve(LocIds.DOWNLOAD_VIDEO_FRAME);
|
|
174
|
+
this.nameSpan_.textContent =
|
|
175
|
+
this.localization.resolve(LocIds.DOWNLOAD_VIDEO_FRAME);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @implements {shaka.extern.IUIElement.Factory}
|
|
182
|
+
* @final
|
|
183
|
+
*/
|
|
184
|
+
shaka.ui.SaveVideoFrameButton.Factory = class {
|
|
185
|
+
/** @override */
|
|
186
|
+
create(rootElement, controls) {
|
|
187
|
+
return new shaka.ui.SaveVideoFrameButton(rootElement, controls);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
shaka.ui.OverflowMenu.registerElement(
|
|
193
|
+
'save_video_frame', new shaka.ui.SaveVideoFrameButton.Factory());
|
|
194
|
+
|
|
195
|
+
shaka.ui.ContextMenu.registerElement(
|
|
196
|
+
'save_video_frame', new shaka.ui.SaveVideoFrameButton.Factory());
|