shaka-player 3.2.9 → 3.2.12
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/.github/workflows/build-and-test.yaml +67 -15
- package/.github/workflows/compute-incremental-coverage.py +251 -0
- package/.github/workflows/report-incremental-coverage.yaml +39 -0
- package/.github/workflows/selenium-lab-tests.yaml +179 -31
- package/CHANGELOG.md +34 -0
- package/CONTRIBUTORS +2 -0
- package/README.md +20 -6
- package/demo/index.html +0 -2
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +2 -2
- package/dist/locales.js +29 -29
- package/dist/shaka-player.compiled.d.ts +12 -1
- package/dist/shaka-player.compiled.debug.d.ts +12 -1
- package/dist/shaka-player.compiled.debug.externs.js +49 -38
- package/dist/shaka-player.compiled.debug.js +105 -96
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +49 -38
- package/dist/shaka-player.compiled.js +759 -755
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +12 -1
- package/dist/shaka-player.ui.debug.d.ts +12 -1
- package/dist/shaka-player.ui.debug.externs.js +49 -38
- package/dist/shaka-player.ui.debug.js +119 -110
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +49 -38
- package/dist/shaka-player.ui.js +866 -863
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/welcome.md +6 -3
- package/karma.conf.js +3 -11
- package/lib/dash/dash_parser.js +5 -0
- package/lib/hls/hls_parser.js +6 -2
- package/lib/media/drm_engine.js +1 -1
- package/lib/media/presentation_timeline.js +24 -1
- package/lib/media/streaming_engine.js +1 -0
- package/lib/player.js +7 -6
- package/lib/polyfill/media_capabilities.js +3 -0
- package/lib/polyfill/videoplaybackquality.js +3 -1
- package/lib/text/cue.js +0 -5
- package/lib/text/simple_text_displayer.js +21 -9
- package/lib/text/ui_text_displayer.js +91 -19
- package/lib/util/buffer_utils.js +3 -0
- package/lib/util/object_utils.js +1 -0
- package/lib/util/platform.js +41 -1
- package/lib/util/stream_utils.js +23 -3
- package/lib/util/string_utils.js +102 -13
- package/maintained-branches.md +15 -0
- package/package.json +3 -5
- package/test/player_src_equals_integration.js +2 -0
- package/test/test/assets/small.mp4 +0 -0
- package/test/text/simple_text_displayer_unit.js +27 -0
- package/test/text/ui_text_displayer_unit.js +65 -0
- package/test/util/string_utils_unit.js +46 -8
- package/ui/less/ad_controls.less +4 -0
- package/app-engine/README.md +0 -9
- package/app-engine/demo-version-index/README.md +0 -14
- package/app-engine/demo-version-index/app.yaml +0 -2
- package/app-engine/demo-version-index/main.py +0 -162
- package/app-engine/demo-version-index/requirements.txt +0 -6
- package/app-engine/demo-version-index/templates/index.html +0 -114
- package/app-engine/shaka-player-demo/README.md +0 -18
- package/app-engine/shaka-player-demo/app.yaml +0 -61
- package/app-engine/shaka-player-demo/main.py +0 -95
- package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
- package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
- package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
- package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
- package/app-engine/shaka-player-demo/posters/sources.txt +0 -46
- package/app-engine/shaka-player-demo/posters/standard.png +0 -0
- package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
- package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
- package/app-engine/shaka-player-demo/posters.py +0 -110
- package/app-engine/shaka-player-demo/requirements.txt +0 -5
- package/app-engine/shaka-player-demo/time.txt +0 -1
- package/build/README.md +0 -127
- package/build/__init__.py +0 -0
- package/build/all.py +0 -150
- package/build/apps.py +0 -186
- package/build/build.py +0 -392
- package/build/check.py +0 -354
- package/build/checkversion.py +0 -84
- package/build/compiler.py +0 -513
- package/build/conformance.textproto +0 -321
- package/build/docker/Dockerfile +0 -20
- package/build/docker/docker-compose.yml +0 -10
- package/build/docs.py +0 -54
- package/build/eslint-plugin-shaka-rules/arg-comment-spacing.js +0 -72
- package/build/eslint-plugin-shaka-rules/index.js +0 -24
- package/build/eslint-plugin-shaka-rules/package.json +0 -7
- package/build/eslint-plugin-shaka-rules/private.js +0 -109
- package/build/gendeps.py +0 -71
- package/build/generateExterns.js +0 -867
- package/build/generateLocalizations.py +0 -262
- package/build/generateTsDefs.py +0 -137
- package/build/install-linux-prereqs.sh +0 -136
- package/build/license-header +0 -5
- package/build/misspellings.txt +0 -38
- package/build/pixelsChanged.js +0 -35
- package/build/shaka-lab.yaml +0 -163
- package/build/shakaBuildHelpers.py +0 -356
- package/build/stats.py +0 -816
- package/build/subprocessWindowsPatch.py +0 -103
- package/build/test.py +0 -541
- package/build/types/ads +0 -8
- package/build/types/cast +0 -6
- package/build/types/cea +0 -13
- package/build/types/complete +0 -9
- package/build/types/core +0 -106
- package/build/types/dash +0 -8
- package/build/types/hls +0 -9
- package/build/types/manifests +0 -5
- package/build/types/networking +0 -6
- package/build/types/offline +0 -21
- package/build/types/polyfill +0 -19
- package/build/types/text +0 -11
- package/build/types/ui +0 -37
- package/build/updateScreenshots.py +0 -85
- package/build/wrapper.template.js +0 -52
package/lib/util/string_utils.js
CHANGED
|
@@ -11,6 +11,7 @@ goog.require('shaka.log');
|
|
|
11
11
|
goog.require('shaka.util.BufferUtils');
|
|
12
12
|
goog.require('shaka.util.Error');
|
|
13
13
|
goog.require('shaka.util.Lazy');
|
|
14
|
+
goog.require('shaka.util.Platform');
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -37,18 +38,84 @@ shaka.util.StringUtils = class {
|
|
|
37
38
|
uint8 = uint8.subarray(3);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
if (window.TextDecoder && !shaka.util.Platform.isPS4()) {
|
|
42
|
+
// Use the TextDecoder interface to decode the text. This has the
|
|
43
|
+
// advantage compared to the previously-standard decodeUriComponent that
|
|
44
|
+
// it will continue parsing even if it finds an invalid UTF8 character,
|
|
45
|
+
// rather than stop and throw an error.
|
|
46
|
+
const utf8decoder = new TextDecoder();
|
|
47
|
+
const decoded = utf8decoder.decode(uint8);
|
|
48
|
+
if (decoded.includes('\uFFFD')) {
|
|
49
|
+
shaka.log.alwaysError('Decoded string contains an "unknown character' +
|
|
50
|
+
'" codepoint. That probably means the UTF8 ' +
|
|
51
|
+
'encoding was incorrect!');
|
|
52
|
+
}
|
|
53
|
+
return decoded;
|
|
54
|
+
} else {
|
|
55
|
+
// Homebrewed UTF-8 decoder based on
|
|
56
|
+
// https://en.wikipedia.org/wiki/UTF-8#Encoding
|
|
57
|
+
// Unlike decodeURIComponent, won't throw on bad encoding.
|
|
58
|
+
// In this way, it is similar to TextDecoder.
|
|
59
|
+
|
|
60
|
+
let decoded = '';
|
|
61
|
+
for (let i = 0; i < uint8.length; ++i) {
|
|
62
|
+
// By default, the "replacement character" codepoint.
|
|
63
|
+
let codePoint = 0xFFFD;
|
|
64
|
+
|
|
65
|
+
// Top bit is 0, 1-byte encoding.
|
|
66
|
+
if ((uint8[i] & 0x80) == 0) {
|
|
67
|
+
codePoint = uint8[i];
|
|
68
|
+
|
|
69
|
+
// Top 3 bits of byte 0 are 110, top 2 bits of byte 1 are 10,
|
|
70
|
+
// 2-byte encoding.
|
|
71
|
+
} else if (uint8.length >= i + 2 &&
|
|
72
|
+
(uint8[i] & 0xe0) == 0xc0 &&
|
|
73
|
+
(uint8[i + 1] & 0xc0) == 0x80) {
|
|
74
|
+
codePoint = ((uint8[i] & 0x1f) << 6) |
|
|
75
|
+
((uint8[i + 1] & 0x3f));
|
|
76
|
+
i += 1; // Consume one extra byte.
|
|
77
|
+
|
|
78
|
+
// Top 4 bits of byte 0 are 1110, top 2 bits of byte 1 and 2 are 10,
|
|
79
|
+
// 3-byte encoding.
|
|
80
|
+
} else if (uint8.length >= i + 3 &&
|
|
81
|
+
(uint8[i] & 0xf0) == 0xe0 &&
|
|
82
|
+
(uint8[i + 1] & 0xc0) == 0x80 &&
|
|
83
|
+
(uint8[i + 2] & 0xc0) == 0x80) {
|
|
84
|
+
codePoint = ((uint8[i] & 0x0f) << 12) |
|
|
85
|
+
((uint8[i + 1] & 0x3f) << 6) |
|
|
86
|
+
((uint8[i + 2] & 0x3f));
|
|
87
|
+
i += 2; // Consume two extra bytes.
|
|
88
|
+
|
|
89
|
+
// Top 5 bits of byte 0 are 11110, top 2 bits of byte 1, 2 and 3 are 10,
|
|
90
|
+
// 4-byte encoding.
|
|
91
|
+
} else if (uint8.length >= i + 4 &&
|
|
92
|
+
(uint8[i] & 0xf1) == 0xf0 &&
|
|
93
|
+
(uint8[i + 1] & 0xc0) == 0x80 &&
|
|
94
|
+
(uint8[i + 2] & 0xc0) == 0x80 &&
|
|
95
|
+
(uint8[i + 3] & 0xc0) == 0x80) {
|
|
96
|
+
codePoint = ((uint8[i] & 0x07) << 18) |
|
|
97
|
+
((uint8[i + 1] & 0x3f) << 12) |
|
|
98
|
+
((uint8[i + 2] & 0x3f) << 6) |
|
|
99
|
+
((uint8[i + 3] & 0x3f));
|
|
100
|
+
i += 3; // Consume three extra bytes.
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// JavaScript strings are a series of UTF-16 characters.
|
|
104
|
+
if (codePoint <= 0xffff) {
|
|
105
|
+
decoded += String.fromCharCode(codePoint);
|
|
106
|
+
} else {
|
|
107
|
+
// UTF-16 surrogate-pair encoding, based on
|
|
108
|
+
// https://en.wikipedia.org/wiki/UTF-16#Description
|
|
109
|
+
const baseCodePoint = codePoint - 0x10000;
|
|
110
|
+
const highPart = baseCodePoint >> 10;
|
|
111
|
+
const lowPart = baseCodePoint & 0x3ff;
|
|
112
|
+
decoded += String.fromCharCode(0xd800 + highPart);
|
|
113
|
+
decoded += String.fromCharCode(0xdc00 + lowPart);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return decoded;
|
|
50
118
|
}
|
|
51
|
-
return decoded;
|
|
52
119
|
}
|
|
53
120
|
|
|
54
121
|
|
|
@@ -141,8 +208,30 @@ shaka.util.StringUtils = class {
|
|
|
141
208
|
* @export
|
|
142
209
|
*/
|
|
143
210
|
static toUTF8(str) {
|
|
144
|
-
|
|
145
|
-
|
|
211
|
+
if (window.TextEncoder && !shaka.util.Platform.isPS4()) {
|
|
212
|
+
const utf8Encoder = new TextEncoder();
|
|
213
|
+
return shaka.util.BufferUtils.toArrayBuffer(utf8Encoder.encode(str));
|
|
214
|
+
} else {
|
|
215
|
+
// http://stackoverflow.com/a/13691499
|
|
216
|
+
// Converts the given string to a URI encoded string. If a character
|
|
217
|
+
// falls in the ASCII range, it is not converted; otherwise it will be
|
|
218
|
+
// converted to a series of URI escape sequences according to UTF-8.
|
|
219
|
+
// Example: 'g#€' -> 'g#%E3%82%AC'
|
|
220
|
+
const encoded = encodeURIComponent(str);
|
|
221
|
+
// Convert each escape sequence individually into a character. Each
|
|
222
|
+
// escape sequence is interpreted as a code-point, so if an escape
|
|
223
|
+
// sequence happens to be part of a multi-byte sequence, each byte will
|
|
224
|
+
// be converted to a single character.
|
|
225
|
+
// Example: 'g#%E3%82%AC' -> '\x67\x35\xe3\x82\xac'
|
|
226
|
+
const utf8 = unescape(encoded);
|
|
227
|
+
|
|
228
|
+
const result = new Uint8Array(utf8.length);
|
|
229
|
+
for (let i = 0; i < utf8.length; i++) {
|
|
230
|
+
const item = utf8[i];
|
|
231
|
+
result[i] = item.charCodeAt(0);
|
|
232
|
+
}
|
|
233
|
+
return shaka.util.BufferUtils.toArrayBuffer(result);
|
|
234
|
+
}
|
|
146
235
|
}
|
|
147
236
|
|
|
148
237
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Maintained Shaka Player Branches
|
|
2
|
+
|
|
3
|
+
We are currently maintaining the following branches of Shaka Player:
|
|
4
|
+
|
|
5
|
+
- v4.1 (latest)
|
|
6
|
+
- v4.0 (previous)
|
|
7
|
+
- v3.3 (LTS until April 30, 2023)
|
|
8
|
+
- v3.2 (in use by the Cast Application Framework)
|
|
9
|
+
|
|
10
|
+
Other branches are no longer receiving bug fixes, and we recommend you upgrade
|
|
11
|
+
to a maintained branch. For details on upgrading, please see our
|
|
12
|
+
[upgrade guide](https://shaka-player-demo.appspot.com/docs/api/tutorial-upgrade.html).
|
|
13
|
+
|
|
14
|
+
For more information on how these branches are chosen, please refer to our
|
|
15
|
+
[Branch Maintenance Policy](https://shaka-project.github.io/maintenance/shaka-player.html#branch-maintenance-policy).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shaka-player",
|
|
3
3
|
"description": "DASH/EME video player library",
|
|
4
|
-
"version": "3.2.
|
|
4
|
+
"version": "3.2.12",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"eslint-config-google": "^0.14.0",
|
|
28
28
|
"eslint-plugin-shaka-rules": "file:./build/eslint-plugin-shaka-rules",
|
|
29
29
|
"esprima": "^4.0.1",
|
|
30
|
-
"fastestsmallesttextencoderdecoder": "^1.0.22",
|
|
31
30
|
"fontfaceonload": "^1.0.2",
|
|
32
31
|
"google-closure-compiler-java": "^20220301.0.0",
|
|
33
32
|
"google-closure-deps": "https://gitpkg.now.sh/google/closure-library/closure-deps?d7736da6",
|
|
@@ -50,7 +49,7 @@
|
|
|
50
49
|
"less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43",
|
|
51
50
|
"less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf",
|
|
52
51
|
"material-design-lite": "^1.3.0",
|
|
53
|
-
"mux.js": "^6.
|
|
52
|
+
"mux.js": "^6.2.0",
|
|
54
53
|
"open-sans-fonts": "^1.6.2",
|
|
55
54
|
"postcss-less": "^6.0.0",
|
|
56
55
|
"pwacompat": "^2.0.17",
|
|
@@ -71,7 +70,6 @@
|
|
|
71
70
|
"dialog-polyfill/dist/dialog-polyfill.js",
|
|
72
71
|
"eme-encryption-scheme-polyfill/index.js",
|
|
73
72
|
"es6-promise-polyfill/promise.min.js",
|
|
74
|
-
"fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js",
|
|
75
73
|
"google-closure-library/closure/goog/base.js",
|
|
76
74
|
"less/dist/less.js",
|
|
77
75
|
"material-design-lite/dist/material.indigo-blue.min.css",
|
|
@@ -96,7 +94,7 @@
|
|
|
96
94
|
"prepublishOnly": "python build/checkversion.py && python build/all.py --force"
|
|
97
95
|
},
|
|
98
96
|
"dependencies": {
|
|
99
|
-
"eme-encryption-scheme-polyfill": "^2.
|
|
97
|
+
"eme-encryption-scheme-polyfill": "^2.1.1"
|
|
100
98
|
},
|
|
101
99
|
"engines": {
|
|
102
100
|
"node": ">=14"
|
|
@@ -305,6 +305,8 @@ describe('Player Src Equals', () => {
|
|
|
305
305
|
expect(stats.loadLatency).toBeGreaterThan(0);
|
|
306
306
|
expect(stats.manifestTimeSeconds).toBeNaN(); // There's no manifest.
|
|
307
307
|
expect(stats.drmTimeSeconds).toBeNaN(); // There's no DRM.
|
|
308
|
+
expect(stats.height).toBe(110);
|
|
309
|
+
expect(stats.width).toBe(256);
|
|
308
310
|
});
|
|
309
311
|
|
|
310
312
|
it('plays with external text tracks', async () => {
|
|
Binary file
|
|
@@ -127,6 +127,33 @@ describe('SimpleTextDisplayer', () => {
|
|
|
127
127
|
[shakaCue]);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
+
it('flattens nested cue payloads correctly', () => {
|
|
131
|
+
const level0ContainerCue = new shaka.text.Cue(10, 30, '');
|
|
132
|
+
level0ContainerCue.isContainer = true;
|
|
133
|
+
|
|
134
|
+
const level1NonContainerCueA = new shaka.text.Cue(10, 20, '');
|
|
135
|
+
const level1NonContainerCueB = new shaka.text.Cue(20, 30, '');
|
|
136
|
+
|
|
137
|
+
// Add a trailing whitespace character to get a space-delimited expected
|
|
138
|
+
// result.
|
|
139
|
+
const cueANestedCue0 = new shaka.text.Cue(10, 20, 'Cue A Test0 ');
|
|
140
|
+
const cueANestedCue1 = new shaka.text.Cue(10, 20, 'Cue A Test1');
|
|
141
|
+
const cueBNestedCue0 = new shaka.text.Cue(20, 30, 'Cue B Test0 ');
|
|
142
|
+
const cueBNestedCue1 = new shaka.text.Cue(20, 30, 'Cue B Test1');
|
|
143
|
+
|
|
144
|
+
level1NonContainerCueA.nestedCues = [cueANestedCue0, cueANestedCue1];
|
|
145
|
+
level1NonContainerCueB.nestedCues = [cueBNestedCue0, cueBNestedCue1];
|
|
146
|
+
level0ContainerCue.nestedCues =
|
|
147
|
+
[level1NonContainerCueA, level1NonContainerCueB];
|
|
148
|
+
|
|
149
|
+
verifyHelper(
|
|
150
|
+
[
|
|
151
|
+
{startTime: 10, endTime: 20, text: 'Cue A Test0 Cue A Test1'},
|
|
152
|
+
{startTime: 20, endTime: 30, text: 'Cue B Test0 Cue B Test1'},
|
|
153
|
+
],
|
|
154
|
+
[level0ContainerCue]);
|
|
155
|
+
});
|
|
156
|
+
|
|
130
157
|
// Regression test for b/159050711
|
|
131
158
|
it('maintains the styles of the parent cue', () => {
|
|
132
159
|
const shakaCue = new shaka.text.Cue(10, 20, '');
|
|
@@ -50,6 +50,7 @@ describe('UITextDisplayer', () => {
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
beforeEach(() => {
|
|
53
|
+
video.currentTime = 0;
|
|
53
54
|
textDisplayer = new shaka.text.UITextDisplayer(video, videoContainer);
|
|
54
55
|
});
|
|
55
56
|
|
|
@@ -396,4 +397,68 @@ describe('UITextDisplayer', () => {
|
|
|
396
397
|
expect(parentCueElements.length).toBe(1);
|
|
397
398
|
expect(parentCueElements[0].textContent).toBe('');
|
|
398
399
|
});
|
|
400
|
+
|
|
401
|
+
it('creates separate elements for cue regions', () => {
|
|
402
|
+
const cueRegion = new shaka.text.CueRegion();
|
|
403
|
+
cueRegion.id = 'regionId';
|
|
404
|
+
cueRegion.height = 80;
|
|
405
|
+
cueRegion.heightUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
406
|
+
cueRegion.width = 80;
|
|
407
|
+
cueRegion.widthUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
408
|
+
cueRegion.viewportAnchorX = 10;
|
|
409
|
+
cueRegion.viewportAnchorY = 10;
|
|
410
|
+
cueRegion.viewportAnchorUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
411
|
+
|
|
412
|
+
// These all attach to the same region, but only one region element should
|
|
413
|
+
// be created.
|
|
414
|
+
const cues = [
|
|
415
|
+
new shaka.text.Cue(0, 100, ''),
|
|
416
|
+
new shaka.text.Cue(0, 100, ''),
|
|
417
|
+
new shaka.text.Cue(0, 100, ''),
|
|
418
|
+
];
|
|
419
|
+
for (const cue of cues) {
|
|
420
|
+
cue.displayAlign = shaka.text.Cue.displayAlign.CENTER;
|
|
421
|
+
cue.region = cueRegion;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
textDisplayer.setTextVisibility(true);
|
|
425
|
+
textDisplayer.append(cues);
|
|
426
|
+
updateCaptions();
|
|
427
|
+
|
|
428
|
+
const textContainer = videoContainer.querySelector('.shaka-text-container');
|
|
429
|
+
const allRegionElements = textContainer.querySelectorAll(
|
|
430
|
+
'.shaka-text-region');
|
|
431
|
+
|
|
432
|
+
// Verify that the nested cues are all attached to a single region element.
|
|
433
|
+
expect(allRegionElements.length).toBe(1);
|
|
434
|
+
const regionElement = allRegionElements[0];
|
|
435
|
+
const children = Array.from(regionElement.childNodes).filter(
|
|
436
|
+
(e) => e.nodeType == Node.ELEMENT_NODE);
|
|
437
|
+
expect(children.length).toBe(3);
|
|
438
|
+
|
|
439
|
+
// Verify styles applied to the region element.
|
|
440
|
+
const regionCssObj = parseCssText(regionElement.style.cssText);
|
|
441
|
+
const expectRegionCssObj = {
|
|
442
|
+
'position': 'absolute',
|
|
443
|
+
'height': '80%',
|
|
444
|
+
'width': '80%',
|
|
445
|
+
'top': '10%',
|
|
446
|
+
'left': '10%',
|
|
447
|
+
'display': 'flex',
|
|
448
|
+
'flex-direction': 'column',
|
|
449
|
+
'align-items': 'center',
|
|
450
|
+
'justify-content': 'center',
|
|
451
|
+
};
|
|
452
|
+
expect(regionCssObj).toEqual(jasmine.objectContaining(expectRegionCssObj));
|
|
453
|
+
|
|
454
|
+
for (const caption of children) {
|
|
455
|
+
// Verify that styles applied to the nested cues _DO NOT_ include region
|
|
456
|
+
// placement.
|
|
457
|
+
const cueCssObj = parseCssText(caption.style.cssText);
|
|
458
|
+
expect(Object.keys(cueCssObj)).not.toContain('height');
|
|
459
|
+
expect(Object.keys(cueCssObj)).not.toContain('width');
|
|
460
|
+
expect(Object.keys(cueCssObj)).not.toContain('top');
|
|
461
|
+
expect(Object.keys(cueCssObj)).not.toContain('left');
|
|
462
|
+
}
|
|
463
|
+
});
|
|
399
464
|
});
|
|
@@ -5,6 +5,29 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
describe('StringUtils', () => {
|
|
8
|
+
describe('with TextDecoder', () => {
|
|
9
|
+
if (window.TextDecoder) {
|
|
10
|
+
defineStringUtilTests();
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('without TextDecoder', () => {
|
|
15
|
+
let originalTextDecoder;
|
|
16
|
+
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
originalTextDecoder = window.TextDecoder;
|
|
19
|
+
window['TextDecoder'] = null;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterAll(() => {
|
|
23
|
+
window.TextDecoder = originalTextDecoder;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
defineStringUtilTests();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function defineStringUtilTests() {
|
|
8
31
|
const StringUtils = shaka.util.StringUtils;
|
|
9
32
|
|
|
10
33
|
it('parses fromUTF8', () => {
|
|
@@ -16,19 +39,34 @@ describe('StringUtils', () => {
|
|
|
16
39
|
});
|
|
17
40
|
|
|
18
41
|
it('won\'t break if given cut-off UTF8 character', () => {
|
|
19
|
-
|
|
20
|
-
// at the very end of the string.
|
|
21
|
-
const arr1 = [0x53, 0x61, 0x6e, 0x20, 0x4a, 0x6f, 0x73, 0x81];
|
|
42
|
+
const arr1 = [0x53, 0x61, 0x6e, 0x20, 0x4a, 0x6f, 0x73, 0xc3, 0xa9];
|
|
22
43
|
expect(StringUtils.fromUTF8(new Uint8Array(arr1)))
|
|
44
|
+
.toBe('San Jos\u00E9');
|
|
45
|
+
|
|
46
|
+
// This array contains the first half of a 2-byte UTF8 character
|
|
47
|
+
// (0xc3 0xa9 = é). The half-character is stranded at the very end of the
|
|
48
|
+
// string.
|
|
49
|
+
const arr = [0x53, 0x61, 0x6e, 0x20, 0x4a, 0x6f, 0x73, 0xc3];
|
|
50
|
+
expect(StringUtils.fromUTF8(new Uint8Array(arr)))
|
|
23
51
|
.toBe('San Jos\uFFFD');
|
|
52
|
+
});
|
|
24
53
|
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
const
|
|
28
|
-
expect(StringUtils.fromUTF8(new Uint8Array(
|
|
54
|
+
it('won\'t break if given an invalid UTF-8 sequence', () => {
|
|
55
|
+
// 0xe9 0x33 0x33 is an invalid UTF-8 sequence.
|
|
56
|
+
const arr = [0x4a, 0x6f, 0x73, 0xE9, 0x33, 0x33, 0x20, 0x53, 0x61, 0x6e];
|
|
57
|
+
expect(StringUtils.fromUTF8(new Uint8Array(arr)))
|
|
29
58
|
.toBe('Jos\uFFFD33 San');
|
|
30
59
|
});
|
|
31
60
|
|
|
61
|
+
it('can handle an 8-byte character', () => {
|
|
62
|
+
// This is the UTF-8 encoding of the US flag emoji.
|
|
63
|
+
// It decodes into two Unicode codepoints, which becomes 4 JavaScript
|
|
64
|
+
// UTF-16 characters.
|
|
65
|
+
const arr = [0xf0, 0x9f, 0x87, 0xba, 0xf0, 0x9f, 0x87, 0xb8];
|
|
66
|
+
expect(StringUtils.fromUTF8(new Uint8Array(arr)))
|
|
67
|
+
.toBe('\uD83C\uDDFA\uD83C\uDDF8');
|
|
68
|
+
});
|
|
69
|
+
|
|
32
70
|
it('strips the BOM in fromUTF8', () => {
|
|
33
71
|
// This is 4 Unicode characters, the last will be split into a surrogate
|
|
34
72
|
// pair.
|
|
@@ -125,4 +163,4 @@ describe('StringUtils', () => {
|
|
|
125
163
|
expect(StringUtils.fromUTF16(buffer, true).length)
|
|
126
164
|
.toBe(buffer.byteLength / 2);
|
|
127
165
|
});
|
|
128
|
-
}
|
|
166
|
+
}
|
package/ui/less/ad_controls.less
CHANGED
|
@@ -71,6 +71,10 @@
|
|
|
71
71
|
.ad-text-shadow();
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
.shaka-ad-controls .shaka-ad-position:not(.shaka-hidden) + .shaka-ad-counter {
|
|
75
|
+
margin-left: 0.75em;
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
.shaka-skip-ad-container {
|
|
75
79
|
/* Skip button is positioned at the very right edge of the
|
|
76
80
|
* video container unlike the rest of the bottom controls. */
|
package/app-engine/README.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Google App Engine Code
|
|
2
|
-
|
|
3
|
-
This folder contains source code for the services we run on Google App Engine
|
|
4
|
-
(appspot.com).
|
|
5
|
-
|
|
6
|
-
- shaka-player-demo: Our hosted demo on https://shaka-player-demo.appspot.com/
|
|
7
|
-
|
|
8
|
-
- demo-version-index: An index of Shaka Player releases and demos, hosted at
|
|
9
|
-
https://index-dot-shaka-player-demo.appspot.com/
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Google App Engine Version Index
|
|
2
|
-
|
|
3
|
-
This folder contains everything necessary to host an index of Shaka Player
|
|
4
|
-
releases and demos at https://index-dot-shaka-player-demo.appspot.com/
|
|
5
|
-
|
|
6
|
-
- app.yaml: App Engine config file. Defines the runtime (Python 3).
|
|
7
|
-
|
|
8
|
-
- main.py: A python service that queries available versions and generates the
|
|
9
|
-
index from a template.
|
|
10
|
-
|
|
11
|
-
- requirements.txt: Used by App Engine to install the necessary Python server
|
|
12
|
-
requirements (Flask, App Engine API).
|
|
13
|
-
|
|
14
|
-
- templates/index.html: A Jinja2 template used to generate the index HTML.
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
# Shaka Player Version Index - Appspot Entrypoint
|
|
2
|
-
# Copyright 2022 Google LLC
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
# Generate an index of Shaka Player versions on appspot.
|
|
6
|
-
|
|
7
|
-
import collections
|
|
8
|
-
import google.appengine.api.modules
|
|
9
|
-
import jinja2
|
|
10
|
-
import os
|
|
11
|
-
import random
|
|
12
|
-
import re
|
|
13
|
-
|
|
14
|
-
from flask import Flask, render_template
|
|
15
|
-
|
|
16
|
-
DEMO_URL_TEMPLATE = 'https://{0}-dot-shaka-player-demo.appspot.com/'
|
|
17
|
-
|
|
18
|
-
# In Google Hosted Libraries
|
|
19
|
-
HOSTED_URL_TEMPLATE = 'https://ajax.googleapis.com/ajax/libs/shaka-player/{0}/shaka-player.{1}'
|
|
20
|
-
|
|
21
|
-
# Before Google Hosted Libraries, v1 appspot URLs
|
|
22
|
-
V1_URL_TEMPLATE = 'https://{0}-dot-shaka-player-demo.appspot.com/shaka-player.{1}'
|
|
23
|
-
# Before Google Hosted Libraries, v2 appspot URLs
|
|
24
|
-
V2_URL_TEMPLATE = 'https://{0}-dot-shaka-player-demo.appspot.com/dist/shaka-player.{1}'
|
|
25
|
-
|
|
26
|
-
def version_to_demo_url(v):
|
|
27
|
-
return DEMO_URL_TEMPLATE.format(v.replace('.', '-'))
|
|
28
|
-
|
|
29
|
-
def version_to_lib_url(v):
|
|
30
|
-
if v == 'nightly':
|
|
31
|
-
return V2_URL_TEMPLATE.format(v, 'compiled.js')
|
|
32
|
-
elif (version_key(v) == version_key('v1.6.5') or
|
|
33
|
-
version_key(v) >= version_key('v2.0.6')):
|
|
34
|
-
return HOSTED_URL_TEMPLATE.format(v.replace('v', ''), 'compiled.js')
|
|
35
|
-
elif version_key(v) >= version_key('v2.0.0-beta'):
|
|
36
|
-
return V2_URL_TEMPLATE.format(v.replace('.', '-'), 'compiled.js')
|
|
37
|
-
else:
|
|
38
|
-
return V1_URL_TEMPLATE.format(v.replace('.', '-'), 'compiled.js')
|
|
39
|
-
|
|
40
|
-
def version_to_ui_lib_url(v):
|
|
41
|
-
if v == 'nightly':
|
|
42
|
-
return V2_URL_TEMPLATE.format(v, 'ui.js')
|
|
43
|
-
elif version_key(v) >= version_key('v2.5.0'):
|
|
44
|
-
return HOSTED_URL_TEMPLATE.format(v.replace('v', ''), 'ui.js')
|
|
45
|
-
else:
|
|
46
|
-
return None
|
|
47
|
-
|
|
48
|
-
def version_to_lib_externs_url(v):
|
|
49
|
-
if v == 'nightly':
|
|
50
|
-
return V2_URL_TEMPLATE.format(v, 'compiled.externs.js')
|
|
51
|
-
elif version_key(v) >= version_key('v2.0.6'):
|
|
52
|
-
return HOSTED_URL_TEMPLATE.format(v.replace('v', ''), 'compiled.externs.js')
|
|
53
|
-
else:
|
|
54
|
-
return None
|
|
55
|
-
|
|
56
|
-
def version_to_ui_lib_externs_url(v):
|
|
57
|
-
if v == 'nightly':
|
|
58
|
-
return V2_URL_TEMPLATE.format(v, 'ui.externs.js')
|
|
59
|
-
elif version_key(v) >= version_key('v2.5.0'):
|
|
60
|
-
return HOSTED_URL_TEMPLATE.format(v.replace('v', ''), 'ui.externs.js')
|
|
61
|
-
else:
|
|
62
|
-
return None
|
|
63
|
-
|
|
64
|
-
def version_to_lib_defs_url(v):
|
|
65
|
-
if v == 'nightly':
|
|
66
|
-
return V2_URL_TEMPLATE.format(v, 'compiled.d.ts')
|
|
67
|
-
elif version_key(v) >= version_key('v3.0.6'):
|
|
68
|
-
return HOSTED_URL_TEMPLATE.format(v.replace('v', ''), 'compiled.d.ts')
|
|
69
|
-
else:
|
|
70
|
-
return None
|
|
71
|
-
|
|
72
|
-
def version_to_ui_lib_defs_url(v):
|
|
73
|
-
if v == 'nightly':
|
|
74
|
-
return V2_URL_TEMPLATE.format(v, 'ui.d.ts')
|
|
75
|
-
elif version_key(v) >= version_key('v3.0.6'):
|
|
76
|
-
return HOSTED_URL_TEMPLATE.format(v.replace('v', ''), 'ui.d.ts')
|
|
77
|
-
else:
|
|
78
|
-
return None
|
|
79
|
-
|
|
80
|
-
def version_to_metadata(v):
|
|
81
|
-
return {
|
|
82
|
-
'version': v,
|
|
83
|
-
'best': False, # Corrected later in another loop
|
|
84
|
-
'demo': version_to_demo_url(v),
|
|
85
|
-
'lib': version_to_lib_url(v),
|
|
86
|
-
'ui_lib': version_to_ui_lib_url(v),
|
|
87
|
-
'lib_externs': version_to_lib_externs_url(v),
|
|
88
|
-
'ui_lib_externs': version_to_ui_lib_externs_url(v),
|
|
89
|
-
'lib_defs': version_to_lib_defs_url(v),
|
|
90
|
-
'ui_lib_defs': version_to_ui_lib_defs_url(v),
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
def is_release_version(name):
|
|
94
|
-
return re.match(r'v\d+-\d+-\d+(?:-.+)?', name)
|
|
95
|
-
|
|
96
|
-
def appengine_version_to_package_version(version):
|
|
97
|
-
# Replace the first two dashes with dots. More dashes indicate a prerelease
|
|
98
|
-
# version, as seen in "v2.0.0-beta3".
|
|
99
|
-
return version.replace('-', '.', 2)
|
|
100
|
-
|
|
101
|
-
def version_key(version):
|
|
102
|
-
if version == 'nightly':
|
|
103
|
-
# A false version number for nightly, greater than any actual release
|
|
104
|
-
# version.
|
|
105
|
-
return [float('inf')]
|
|
106
|
-
|
|
107
|
-
assert version[0] == 'v'
|
|
108
|
-
main_version, _, suffix = version[1:].partition('-')
|
|
109
|
-
if not suffix:
|
|
110
|
-
suffix = '}}}' # this puts main releases after prerelease versions
|
|
111
|
-
version_tuple = [int(x) for x in main_version.split('.')]
|
|
112
|
-
return version_tuple + [suffix]
|
|
113
|
-
|
|
114
|
-
def get_appengine_versions():
|
|
115
|
-
if os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine/'):
|
|
116
|
-
# NOTE: this doesn't return anything useful in a local dev server.
|
|
117
|
-
return google.appengine.api.modules.modules.get_versions()
|
|
118
|
-
|
|
119
|
-
# For a local dev server, fake it so we can test sorting.
|
|
120
|
-
fake_versions = [
|
|
121
|
-
'v1-6-0', 'v1-6-1', 'v1-6-2', 'v1-6-3', 'v1-6-4', 'v1-6-5',
|
|
122
|
-
'v2-0-0-beta', 'v2-0-0-beta2', 'v2-0-0-beta3', 'v2-0-0',
|
|
123
|
-
'v2-1-0', 'v2-1-1', 'v2-1-2',
|
|
124
|
-
'v2-2-1', 'v2-2-2-beta', 'v2-2-2-beta2', 'v2-2-2', 'v2-2-9', 'v2-2-10',
|
|
125
|
-
]
|
|
126
|
-
random.shuffle(fake_versions) # in-place shuffle
|
|
127
|
-
return fake_versions
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
app = Flask(__name__)
|
|
131
|
-
|
|
132
|
-
@app.route('/')
|
|
133
|
-
def root():
|
|
134
|
-
appengine_versions = get_appengine_versions()
|
|
135
|
-
# Filter for release versions only.
|
|
136
|
-
appengine_versions = filter(is_release_version, appengine_versions)
|
|
137
|
-
|
|
138
|
-
# Now convert from appengine versions (v2-0-0) to package versions (v2.0.0).
|
|
139
|
-
versions = list(map(appengine_version_to_package_version, appengine_versions))
|
|
140
|
-
# Now sort, putting prerelease versions ahead of the corresponding release.
|
|
141
|
-
versions.sort(key=version_key)
|
|
142
|
-
|
|
143
|
-
version_metadata = collections.OrderedDict()
|
|
144
|
-
latest_by_branch = {}
|
|
145
|
-
for v in versions:
|
|
146
|
-
version_metadata[v] = version_to_metadata(v)
|
|
147
|
-
|
|
148
|
-
# Because |versions| is already sorted, we can just overwrite the entry
|
|
149
|
-
# in the latest_by_branch dictionary.
|
|
150
|
-
branch_key = tuple(version_key(v)[0:2])
|
|
151
|
-
latest_by_branch[branch_key] = v
|
|
152
|
-
|
|
153
|
-
for v in latest_by_branch.values():
|
|
154
|
-
version_metadata[v]['best'] = True
|
|
155
|
-
|
|
156
|
-
# Append nightly rather than filter for it, so that it always appears at the
|
|
157
|
-
# end of the list.
|
|
158
|
-
version_metadata['nightly'] = version_to_metadata('nightly')
|
|
159
|
-
version_metadata['nightly']['best'] = True
|
|
160
|
-
|
|
161
|
-
for i in version_metadata.values(): print(i)
|
|
162
|
-
return render_template('index.html', versions=version_metadata.values())
|