@mattebox/player-diagnostics 0.1.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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +24 -0
  3. package/README.md +45 -0
  4. package/dist/cdn/mattebox-player-diagnostics.min.js +124 -0
  5. package/dist/charts.d.ts +35 -0
  6. package/dist/charts.d.ts.map +1 -0
  7. package/dist/charts.js +401 -0
  8. package/dist/charts.js.map +1 -0
  9. package/dist/element.d.ts +62 -0
  10. package/dist/element.d.ts.map +1 -0
  11. package/dist/element.js +677 -0
  12. package/dist/element.js.map +1 -0
  13. package/dist/es2015/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/asyncToGenerator.js +27 -0
  14. package/dist/es2015/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/defineProperty.js +12 -0
  15. package/dist/es2015/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/objectSpread2.js +25 -0
  16. package/dist/es2015/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/toPrimitive.js +14 -0
  17. package/dist/es2015/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/toPropertyKey.js +9 -0
  18. package/dist/es2015/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/typeof.js +11 -0
  19. package/dist/es2015/charts.js +380 -0
  20. package/dist/es2015/element.js +651 -0
  21. package/dist/es2015/format.js +38 -0
  22. package/dist/es2015/host.js +34 -0
  23. package/dist/es2015/icon.js +46 -0
  24. package/dist/es2015/index.js +15 -0
  25. package/dist/es2015/report.js +145 -0
  26. package/dist/es2015/sampler.js +196 -0
  27. package/dist/es2015/style.js +135 -0
  28. package/dist/es2015/support.js +351 -0
  29. package/dist/es2015/trace.js +99 -0
  30. package/dist/format.d.ts +20 -0
  31. package/dist/format.d.ts.map +1 -0
  32. package/dist/format.js +45 -0
  33. package/dist/format.js.map +1 -0
  34. package/dist/host.d.ts +19 -0
  35. package/dist/host.d.ts.map +1 -0
  36. package/dist/host.js +38 -0
  37. package/dist/host.js.map +1 -0
  38. package/dist/icon.d.ts +31 -0
  39. package/dist/icon.d.ts.map +1 -0
  40. package/dist/icon.js +44 -0
  41. package/dist/icon.js.map +1 -0
  42. package/dist/index.d.ts +21 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +16 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/report.d.ts +140 -0
  47. package/dist/report.d.ts.map +1 -0
  48. package/dist/report.js +125 -0
  49. package/dist/report.js.map +1 -0
  50. package/dist/sampler.d.ts +68 -0
  51. package/dist/sampler.d.ts.map +1 -0
  52. package/dist/sampler.js +208 -0
  53. package/dist/sampler.js.map +1 -0
  54. package/dist/style.d.ts +10 -0
  55. package/dist/style.d.ts.map +1 -0
  56. package/dist/style.js +133 -0
  57. package/dist/style.js.map +1 -0
  58. package/dist/support.d.ts +46 -0
  59. package/dist/support.d.ts.map +1 -0
  60. package/dist/support.js +247 -0
  61. package/dist/support.js.map +1 -0
  62. package/dist/trace.d.ts +14 -0
  63. package/dist/trace.d.ts.map +1 -0
  64. package/dist/trace.js +100 -0
  65. package/dist/trace.js.map +1 -0
  66. package/package.json +59 -0
@@ -0,0 +1,351 @@
1
+ import _objectSpread2 from "./_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/objectSpread2.js";
2
+ import _asyncToGenerator from "./_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/asyncToGenerator.js";
3
+ //#region src/support.ts
4
+ const CODECS = [
5
+ {
6
+ label: "H.264 High 4.0",
7
+ codec: "avc1.640028",
8
+ kind: "video",
9
+ containers: ["mp4"]
10
+ },
11
+ {
12
+ label: "H.264 Baseline",
13
+ codec: "avc1.42e01e",
14
+ kind: "video",
15
+ containers: ["mp4"]
16
+ },
17
+ {
18
+ label: "H.265 / HEVC Main",
19
+ codec: "hvc1.1.6.L123.B0",
20
+ kind: "video",
21
+ containers: ["mp4"]
22
+ },
23
+ {
24
+ label: "VP9 Profile 0",
25
+ codec: "vp09.00.40.08",
26
+ kind: "video",
27
+ containers: ["mp4", "webm"]
28
+ },
29
+ {
30
+ label: "AV1 Main",
31
+ codec: "av01.0.08M.08",
32
+ kind: "video",
33
+ containers: ["mp4", "webm"]
34
+ },
35
+ {
36
+ label: "AAC-LC",
37
+ codec: "mp4a.40.2",
38
+ kind: "audio",
39
+ containers: ["mp4"]
40
+ },
41
+ {
42
+ label: "HE-AAC",
43
+ codec: "mp4a.40.5",
44
+ kind: "audio",
45
+ containers: ["mp4"]
46
+ },
47
+ {
48
+ label: "Opus",
49
+ codec: "opus",
50
+ kind: "audio",
51
+ containers: ["mp4", "webm"]
52
+ },
53
+ {
54
+ label: "FLAC",
55
+ codec: "flac",
56
+ kind: "audio",
57
+ containers: ["mp4"]
58
+ },
59
+ {
60
+ label: "AC-3",
61
+ codec: "ac-3",
62
+ kind: "audio",
63
+ containers: ["mp4"]
64
+ },
65
+ {
66
+ label: "E-AC-3",
67
+ codec: "ec-3",
68
+ kind: "audio",
69
+ containers: ["mp4"]
70
+ }
71
+ ];
72
+ const KEY_SYSTEMS = [
73
+ {
74
+ label: "Widevine",
75
+ keySystems: ["com.widevine.alpha"],
76
+ levels: [
77
+ ["HW_SECURE_ALL", "L1"],
78
+ ["HW_SECURE_DECODE", "L1"],
79
+ ["HW_SECURE_CRYPTO", "L2"],
80
+ ["SW_SECURE_DECODE", "L3"],
81
+ ["SW_SECURE_CRYPTO", "L3"]
82
+ ]
83
+ },
84
+ {
85
+ label: "PlayReady",
86
+ keySystems: ["com.microsoft.playready.recommendation", "com.microsoft.playready"],
87
+ levels: [
88
+ ["3000", "SL3000"],
89
+ ["2000", "SL2000"],
90
+ ["150", "SL150"]
91
+ ]
92
+ },
93
+ {
94
+ label: "FairPlay",
95
+ keySystems: ["com.apple.fps", "com.apple.fps.1_0"],
96
+ levels: []
97
+ },
98
+ {
99
+ label: "ClearKey",
100
+ keySystems: ["org.w3.clearkey"],
101
+ levels: []
102
+ }
103
+ ];
104
+ const HDCP_VERSIONS = [
105
+ "1.0",
106
+ "1.1",
107
+ "1.2",
108
+ "1.3",
109
+ "1.4",
110
+ "2.0",
111
+ "2.1",
112
+ "2.2",
113
+ "2.3"
114
+ ];
115
+ const VIDEO_TYPE = "video/mp4; codecs=\"avc1.42e01e\"";
116
+ const VIDEO_TYPE_ALT = "video/mp4; codecs=\"vp09.00.10.08\"";
117
+ const AUDIO_TYPE = "audio/mp4; codecs=\"mp4a.40.2\"";
118
+ const AUDIO_TYPE_ALT = "audio/mp4; codecs=\"opus\"";
119
+ /** A probe that never answers is a no: some CDMs hang instead of rejecting. */
120
+ function withTimeout(promise, fallback, ms = 4e3) {
121
+ return new Promise((resolve) => {
122
+ const timer = setTimeout(() => resolve(fallback), ms);
123
+ promise.then((value) => {
124
+ clearTimeout(timer);
125
+ resolve(value);
126
+ }, () => {
127
+ clearTimeout(timer);
128
+ resolve(fallback);
129
+ });
130
+ });
131
+ }
132
+ function has(name) {
133
+ return name in globalThis ? "yes" : "no";
134
+ }
135
+ function platform() {
136
+ let changeType = "no";
137
+ try {
138
+ if (typeof MediaSource !== "undefined" && "changeType" in SourceBuffer.prototype) changeType = "yes";
139
+ } catch (_unused) {
140
+ changeType = "no";
141
+ }
142
+ return [
143
+ {
144
+ label: "Secure context",
145
+ value: window.isSecureContext ? "yes" : "no"
146
+ },
147
+ {
148
+ label: "MediaSource",
149
+ value: has("MediaSource")
150
+ },
151
+ {
152
+ label: "ManagedMediaSource",
153
+ value: has("ManagedMediaSource")
154
+ },
155
+ {
156
+ label: "SourceBuffer.changeType",
157
+ value: changeType
158
+ },
159
+ {
160
+ label: "Encrypted Media (EME)",
161
+ value: has("MediaKeys")
162
+ },
163
+ {
164
+ label: "MediaCapabilities",
165
+ value: navigator.mediaCapabilities !== void 0 ? "yes" : "no"
166
+ },
167
+ {
168
+ label: "WebCodecs",
169
+ value: has("VideoDecoder")
170
+ }
171
+ ];
172
+ }
173
+ function mseSupports(type) {
174
+ try {
175
+ return typeof MediaSource !== "undefined" && MediaSource.isTypeSupported(type);
176
+ } catch (_unused2) {
177
+ return false;
178
+ }
179
+ }
180
+ function elementSupports(type) {
181
+ const answer = document.createElement("video").canPlayType(type);
182
+ return answer === "probably" ? "yes" : answer === "maybe" ? "maybe" : "no";
183
+ }
184
+ function decodingInfo(_x) {
185
+ return _decodingInfo.apply(this, arguments);
186
+ }
187
+ function _decodingInfo() {
188
+ _decodingInfo = _asyncToGenerator(function* (probe) {
189
+ const capabilities = navigator.mediaCapabilities;
190
+ if ((capabilities === null || capabilities === void 0 ? void 0 : capabilities.decodingInfo) === void 0) return {
191
+ smooth: "na",
192
+ efficient: "na"
193
+ };
194
+ const contentType = `${probe.kind}/${probe.containers[0]}; codecs="${probe.codec}"`;
195
+ const config = probe.kind === "video" ? {
196
+ type: "media-source",
197
+ video: {
198
+ contentType,
199
+ width: 1920,
200
+ height: 1080,
201
+ bitrate: 6e6,
202
+ framerate: 30
203
+ }
204
+ } : {
205
+ type: "media-source",
206
+ audio: {
207
+ contentType,
208
+ channels: "2",
209
+ bitrate: 128e3
210
+ }
211
+ };
212
+ const info = yield withTimeout(capabilities.decodingInfo(config), null);
213
+ if (info === null) return {
214
+ smooth: "na",
215
+ efficient: "na"
216
+ };
217
+ if (!info.supported) return {
218
+ smooth: "no",
219
+ efficient: "no"
220
+ };
221
+ return {
222
+ smooth: info.smooth ? "yes" : "no",
223
+ efficient: info.powerEfficient ? "yes" : "no"
224
+ };
225
+ });
226
+ return _decodingInfo.apply(this, arguments);
227
+ }
228
+ function codec(_x2) {
229
+ return _codec.apply(this, arguments);
230
+ }
231
+ function _codec() {
232
+ _codec = _asyncToGenerator(function* (probe) {
233
+ const cell = (container) => probe.containers.includes(container) ? mseSupports(`${probe.kind}/${container}; codecs="${probe.codec}"`) ? "yes" : "no" : "na";
234
+ const { smooth, efficient } = yield decodingInfo(probe);
235
+ return {
236
+ label: probe.label,
237
+ codec: probe.codec,
238
+ kind: probe.kind,
239
+ mse: cell("mp4"),
240
+ webm: cell("webm"),
241
+ element: elementSupports(`${probe.kind}/${probe.containers[0]}; codecs="${probe.codec}"`),
242
+ smooth,
243
+ efficient
244
+ };
245
+ });
246
+ return _codec.apply(this, arguments);
247
+ }
248
+ function videoAlternates(extra = {}) {
249
+ return [_objectSpread2({ contentType: VIDEO_TYPE }, extra), _objectSpread2({ contentType: VIDEO_TYPE_ALT }, extra)];
250
+ }
251
+ function baseConfig(extra = {}) {
252
+ return _objectSpread2({
253
+ initDataTypes: [
254
+ "cenc",
255
+ "keyids",
256
+ "sinf",
257
+ "skd"
258
+ ],
259
+ videoCapabilities: videoAlternates(),
260
+ audioCapabilities: [{ contentType: AUDIO_TYPE }, { contentType: AUDIO_TYPE_ALT }]
261
+ }, extra);
262
+ }
263
+ function requestAccess(keySystem, config) {
264
+ if (typeof navigator.requestMediaKeySystemAccess !== "function") return Promise.resolve(null);
265
+ return withTimeout(navigator.requestMediaKeySystemAccess(keySystem, [config]).then((access) => access, () => null), null);
266
+ }
267
+ const NONE = (label) => ({
268
+ label,
269
+ keySystem: null,
270
+ level: "na",
271
+ schemes: "na",
272
+ persistent: "na",
273
+ identifier: "na",
274
+ hdcp: "na"
275
+ });
276
+ function keySystem(_x3) {
277
+ return _keySystem.apply(this, arguments);
278
+ }
279
+ function _keySystem() {
280
+ _keySystem = _asyncToGenerator(function* (probe) {
281
+ let system = null;
282
+ let access = null;
283
+ for (const candidate of probe.keySystems) {
284
+ access = yield requestAccess(candidate, baseConfig());
285
+ if (access !== null) {
286
+ system = candidate;
287
+ break;
288
+ }
289
+ }
290
+ if (system === null || access === null) return NONE(probe.label);
291
+ let level = probe.levels.length === 0 ? "n/a for this system" : "none granted";
292
+ for (const [robustness, name] of probe.levels) if ((yield requestAccess(system, baseConfig({ videoCapabilities: videoAlternates({ robustness }) }))) !== null) {
293
+ level = `${name} (${robustness})`;
294
+ break;
295
+ }
296
+ const echoed = [];
297
+ let schemeApi = false;
298
+ for (const scheme of ["cenc", "cbcs"]) {
299
+ var _granted$getConfigura;
300
+ const granted = yield requestAccess(system, baseConfig({ videoCapabilities: videoAlternates({ encryptionScheme: scheme }) }));
301
+ const answer = granted === null || granted === void 0 || (_granted$getConfigura = granted.getConfiguration().videoCapabilities) === null || _granted$getConfigura === void 0 || (_granted$getConfigura = _granted$getConfigura.find((c) => c.contentType !== "")) === null || _granted$getConfigura === void 0 ? void 0 : _granted$getConfigura.encryptionScheme;
302
+ if (answer !== void 0 && answer !== null) schemeApi = true;
303
+ if (answer === scheme) echoed.push(scheme);
304
+ }
305
+ const schemes = !schemeApi ? "unknown (no API)" : echoed.length === 0 ? "none" : echoed.join(", ");
306
+ const persistent = yield requestAccess(system, baseConfig({
307
+ persistentState: "required",
308
+ sessionTypes: ["persistent-license"]
309
+ }));
310
+ const identifier = yield requestAccess(system, baseConfig({ distinctiveIdentifier: "required" }));
311
+ let hdcp = "na";
312
+ try {
313
+ const keys = yield withTimeout(access.createMediaKeys(), null);
314
+ if (keys !== null && typeof keys.getStatusForPolicy === "function") {
315
+ let best = null;
316
+ for (const version of HDCP_VERSIONS) {
317
+ if ((yield withTimeout(keys.getStatusForPolicy({ minHdcpVersion: version }), "unknown")) !== "usable") break;
318
+ best = version;
319
+ }
320
+ hdcp = best === null ? "no output protection" : `up to ${best}`;
321
+ }
322
+ } catch (_unused3) {
323
+ hdcp = "na";
324
+ }
325
+ return {
326
+ label: probe.label,
327
+ keySystem: system,
328
+ level,
329
+ schemes,
330
+ persistent: persistent !== null ? "yes" : "no",
331
+ identifier: identifier !== null ? "yes" : "no",
332
+ hdcp
333
+ };
334
+ });
335
+ return _keySystem.apply(this, arguments);
336
+ }
337
+ let cached = null;
338
+ /** Probes the browser once per page and answers from the cache after. */
339
+ function probeSupport() {
340
+ if (cached === null) cached = _asyncToGenerator(function* () {
341
+ return {
342
+ userAgent: navigator.userAgent,
343
+ platform: platform(),
344
+ codecs: yield Promise.all(CODECS.map(codec)),
345
+ drm: yield Promise.all(KEY_SYSTEMS.map(keySystem))
346
+ };
347
+ })();
348
+ return cached;
349
+ }
350
+ //#endregion
351
+ export { probeSupport };
@@ -0,0 +1,99 @@
1
+ import _objectSpread2 from "./_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/objectSpread2.js";
2
+ //#region src/trace.ts
3
+ /** Segments as a count, whatever their addressing. */
4
+ function segmentCount(segments) {
5
+ if (Array.isArray(segments)) return segments.length;
6
+ if (typeof segments === "object" && segments !== null && "kind" in segments) return String(segments.kind);
7
+ return 0;
8
+ }
9
+ /** A presentation as its shape: the periods, the tracks, the renditions, and how many segments each has. */
10
+ function slimPresentation(presentation) {
11
+ var _presentation$duratio, _presentation$live;
12
+ return {
13
+ id: presentation.id,
14
+ isLive: presentation.isLive,
15
+ duration: (_presentation$duratio = presentation.duration) !== null && _presentation$duratio !== void 0 ? _presentation$duratio : null,
16
+ live: (_presentation$live = presentation.live) !== null && _presentation$live !== void 0 ? _presentation$live : null,
17
+ periods: presentation.periods.map((period) => {
18
+ var _period$duration;
19
+ return {
20
+ id: period.id,
21
+ start: period.start,
22
+ duration: (_period$duration = period.duration) !== null && _period$duration !== void 0 ? _period$duration : null,
23
+ tracks: period.tracks.map((track) => {
24
+ var _track$lang, _track$role;
25
+ return {
26
+ id: track.id,
27
+ contentType: track.contentType,
28
+ mimeType: track.mimeType,
29
+ lang: (_track$lang = track.lang) !== null && _track$lang !== void 0 ? _track$lang : null,
30
+ role: (_track$role = track.role) !== null && _track$role !== void 0 ? _track$role : null,
31
+ protected: track.protection !== null && track.protection.schemes.length > 0,
32
+ renditions: track.renditions.map((r) => {
33
+ var _r$width, _r$height;
34
+ return {
35
+ id: r.id,
36
+ bitrate: r.bitrate,
37
+ width: (_r$width = r.width) !== null && _r$width !== void 0 ? _r$width : null,
38
+ height: (_r$height = r.height) !== null && _r$height !== void 0 ? _r$height : null,
39
+ codecs: r.codecs,
40
+ segments: segmentCount(r.segments)
41
+ };
42
+ })
43
+ };
44
+ })
45
+ };
46
+ })
47
+ };
48
+ }
49
+ function slimMessage(msg) {
50
+ switch (msg.type) {
51
+ case "MANIFEST_LOADED": return {
52
+ type: msg.type,
53
+ presentation: slimPresentation(msg.presentation)
54
+ };
55
+ case "PLAYLIST_REFRESHED": return _objectSpread2(_objectSpread2({}, msg), {}, { segments: segmentCount(msg.segments) });
56
+ case "SEGMENT_LOADED": return _objectSpread2(_objectSpread2({}, msg), {}, { bytes: length(msg.bytes) });
57
+ default: return msg;
58
+ }
59
+ }
60
+ /** A payload's length, whether it is still bytes or already the engine's `{ $bytes }` marker. */
61
+ function length(value) {
62
+ if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value.byteLength;
63
+ return value;
64
+ }
65
+ function slimEffect(effect) {
66
+ if (effect.kind === "emit" && effect.event === "tracks:changed") return {
67
+ kind: effect.kind,
68
+ event: effect.event
69
+ };
70
+ if (effect.kind === "schedule") return _objectSpread2(_objectSpread2({}, effect), {}, { then: slimMessage(effect.then) });
71
+ const out = {};
72
+ for (const [key, value] of Object.entries(effect)) out[key] = length(value);
73
+ return out;
74
+ }
75
+ /**
76
+ * JSON with the values a trace carries that JSON does not: byte buffers as
77
+ * their length, maps as objects, sets as arrays, functions and DOM nodes
78
+ * as their names.
79
+ */
80
+ function serializable(_key, value) {
81
+ if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return value.byteLength;
82
+ if (value instanceof Map) return Object.fromEntries(value);
83
+ if (value instanceof Set) return [...value];
84
+ if (typeof value === "function") return "[function]";
85
+ if (typeof Node !== "undefined" && value instanceof Node) return `[${value.nodeName}]`;
86
+ return value;
87
+ }
88
+ /** One entry, slimmed and plain. */
89
+ function slimEntry(entry) {
90
+ const slim = {
91
+ t: entry.t,
92
+ msg: slimMessage(entry.msg),
93
+ effects: entry.effects.map(slimEffect),
94
+ digest: entry.digest
95
+ };
96
+ return JSON.parse(JSON.stringify(slim, serializable));
97
+ }
98
+ //#endregion
99
+ export { slimEntry };
@@ -0,0 +1,20 @@
1
+ /** The numbers as the panel and the charts print them. Pure. */
2
+ /** Bits per second as "3.2 Mbps", "640 kbps" or "0 bps". */
3
+ export declare function bitrate(bps: number): string;
4
+ /** Seconds as "m:ss", or "h:mm:ss" from an hour up. Anything not finite reads as "–". */
5
+ export declare function clock(seconds: number): string;
6
+ /** A number with `digits` decimals, and "–" when it is not one. */
7
+ export declare function fixed(value: number | null | undefined, digits?: number): string;
8
+ /** A share as "1.23%", zero when there is no whole. */
9
+ export declare function share(part: number, whole: number): string;
10
+ /** Time ranges as "0.0–12.3, 40.0–52.1". */
11
+ export declare function ranges(list: ReadonlyArray<{
12
+ readonly start: number;
13
+ readonly end: number;
14
+ }>): string;
15
+ /** A rendition's name: its height, else its bitrate. */
16
+ export declare function rendition(r: {
17
+ readonly height?: number;
18
+ readonly bitrate: number;
19
+ } | null): string;
20
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,4DAA4D;AAC5D,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3C;AAED,yFAAyF;AACzF,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQ7C;AAED,mEAAmE;AACnE,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,SAAI,GAAG,MAAM,CAI1E;AAED,uDAAuD;AACvD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,4CAA4C;AAC5C,wBAAgB,MAAM,CACpB,IAAI,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GACpE,MAAM,CAIR;AAED,wDAAwD;AACxD,wBAAgB,SAAS,CACvB,CAAC,EAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAC/D,MAAM,CAGR"}
package/dist/format.js ADDED
@@ -0,0 +1,45 @@
1
+ /** The numbers as the panel and the charts print them. Pure. */
2
+ /** Bits per second as "3.2 Mbps", "640 kbps" or "0 bps". */
3
+ export function bitrate(bps) {
4
+ if (!Number.isFinite(bps) || bps <= 0)
5
+ return '0 bps';
6
+ if (bps >= 1_000_000)
7
+ return `${(bps / 1_000_000).toFixed(bps >= 10_000_000 ? 0 : 1)} Mbps`;
8
+ if (bps >= 1_000)
9
+ return `${Math.round(bps / 1_000)} kbps`;
10
+ return `${Math.round(bps)} bps`;
11
+ }
12
+ /** Seconds as "m:ss", or "h:mm:ss" from an hour up. Anything not finite reads as "–". */
13
+ export function clock(seconds) {
14
+ if (!Number.isFinite(seconds))
15
+ return '–';
16
+ const total = Math.max(0, Math.floor(seconds));
17
+ const hours = Math.floor(total / 3600);
18
+ const minutes = Math.floor((total % 3600) / 60);
19
+ const rest = total % 60;
20
+ const pad = (n) => (n < 10 ? `0${n}` : `${n}`);
21
+ return hours > 0 ? `${hours}:${pad(minutes)}:${pad(rest)}` : `${minutes}:${pad(rest)}`;
22
+ }
23
+ /** A number with `digits` decimals, and "–" when it is not one. */
24
+ export function fixed(value, digits = 1) {
25
+ return value === null || value === undefined || !Number.isFinite(value)
26
+ ? '–'
27
+ : value.toFixed(digits);
28
+ }
29
+ /** A share as "1.23%", zero when there is no whole. */
30
+ export function share(part, whole) {
31
+ return whole > 0 ? `${((part / whole) * 100).toFixed(2)}%` : '0%';
32
+ }
33
+ /** Time ranges as "0.0–12.3, 40.0–52.1". */
34
+ export function ranges(list) {
35
+ return list.length === 0
36
+ ? 'none'
37
+ : list.map((range) => `${range.start.toFixed(1)}–${range.end.toFixed(1)}`).join(', ');
38
+ }
39
+ /** A rendition's name: its height, else its bitrate. */
40
+ export function rendition(r) {
41
+ if (r === null)
42
+ return '–';
43
+ return r.height !== undefined ? `${r.height}p, ${bitrate(r.bitrate)}` : bitrate(r.bitrate);
44
+ }
45
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/host.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The contract of a control of the page's own, as guide chapter 03 of the
3
+ * player states it: the nearest <mattebox-player> above, through shadow
4
+ * hosts, awaited until defined and upgraded, then read for `video`,
5
+ * `engine`, `player` and `error`, with `sourcechange` and `error` heard on
6
+ * it. This package implements the contract from outside, on purpose: the
7
+ * player exports no base class, and a control that needs more than this
8
+ * surface has found a gap in the player's API.
9
+ */
10
+ import type { PlayerHost } from '@mattebox/player';
11
+ export type { PlayerHost };
12
+ /** The core's error shape, as the player exposes it: taken from the host, so the core is not a dependency. */
13
+ export type PlayerError = NonNullable<PlayerHost['error']>;
14
+ export declare const PLAYER = "mattebox-player";
15
+ /** The nearest player above `node`, or null outside one. It may not be upgraded yet. */
16
+ export declare function findPlayer(node: Node): HTMLElement | null;
17
+ /** Runs `fn` with the player once it is defined and upgraded, unless cancelled before. */
18
+ export declare function whenPlayer(found: HTMLElement, fn: (player: PlayerHost) => void): () => void;
19
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,8GAA8G;AAC9G,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAE3D,eAAO,MAAM,MAAM,oBAAoB,CAAC;AASxC,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,IAAI,CAOzD;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAa3F"}
package/dist/host.js ADDED
@@ -0,0 +1,38 @@
1
+ export const PLAYER = 'mattebox-player';
2
+ /** The parent, or the host of the shadow root `node` sits in, or null at the document. */
3
+ function above(node) {
4
+ const parent = node.parentNode;
5
+ if (parent !== null)
6
+ return parent;
7
+ return node instanceof ShadowRoot ? node.host : null;
8
+ }
9
+ /** The nearest player above `node`, or null outside one. It may not be upgraded yet. */
10
+ export function findPlayer(node) {
11
+ let current = node;
12
+ while (current !== null) {
13
+ if (current instanceof HTMLElement && current.localName === PLAYER)
14
+ return current;
15
+ current = above(current);
16
+ }
17
+ return null;
18
+ }
19
+ /** Runs `fn` with the player once it is defined and upgraded, unless cancelled before. */
20
+ export function whenPlayer(found, fn) {
21
+ let waiting = true;
22
+ const ready = () => {
23
+ if (!waiting)
24
+ return;
25
+ waiting = false;
26
+ customElements.upgrade(found);
27
+ if ('video' in found)
28
+ fn(found);
29
+ };
30
+ if ('video' in found)
31
+ ready();
32
+ else
33
+ void customElements.whenDefined(PLAYER).then(ready);
34
+ return () => {
35
+ waiting = false;
36
+ };
37
+ }
38
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,MAAM,MAAM,GAAG,iBAAiB,CAAC;AAExC,0FAA0F;AAC1F,SAAS,KAAK,CAAC,IAAU;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;IAC/B,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,IAAI,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,UAAU,CAAC,IAAU;IACnC,IAAI,OAAO,GAAgB,IAAI,CAAC;IAChC,OAAO,OAAO,KAAK,IAAI,EAAE,CAAC;QACxB,IAAI,OAAO,YAAY,WAAW,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM;YAAE,OAAO,OAAO,CAAC;QACnF,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,KAAkB,EAAE,EAAgC;IAC7E,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,OAAO,GAAG,KAAK,CAAC;QAChB,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,OAAO,IAAI,KAAK;YAAE,EAAE,CAAC,KAAmB,CAAC,CAAC;IAChD,CAAC,CAAC;IACF,IAAI,OAAO,IAAI,KAAK;QAAE,KAAK,EAAE,CAAC;;QACzB,KAAK,cAAc,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,GAAG,EAAE;QACV,OAAO,GAAG,KAAK,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC"}
package/dist/icon.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The glyph, copied from Vidstack's media-icons 0.10.0
3
+ * (https://github.com/vidstack/media-icons), the same set the player draws
4
+ * its own from: filled paths on a 32-unit viewBox. Copied, not depended
5
+ * on; the notice ships as NOTICE in the package.
6
+ *
7
+ * MIT License
8
+ *
9
+ * Copyright (c) 2023 Rahim Alwer
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ * of this software and associated documentation files (the "Software"), to deal
13
+ * in the Software without restriction, including without limitation the rights
14
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ * copies of the Software, and to permit persons to whom the Software is
16
+ * furnished to do so, subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included in all
19
+ * copies or substantial portions of the Software.
20
+ *
21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ * SOFTWARE.
28
+ */
29
+ /** The glyph, hidden from the accessibility tree: the button carries the name. */
30
+ export declare function icon(): SVGSVGElement;
31
+ //# sourceMappingURL=icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon.d.ts","sourceRoot":"","sources":["../src/icon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAQH,kFAAkF;AAClF,wBAAgB,IAAI,IAAI,aAAa,CAUpC"}
package/dist/icon.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The glyph, copied from Vidstack's media-icons 0.10.0
3
+ * (https://github.com/vidstack/media-icons), the same set the player draws
4
+ * its own from: filled paths on a 32-unit viewBox. Copied, not depended
5
+ * on; the notice ships as NOTICE in the package.
6
+ *
7
+ * MIT License
8
+ *
9
+ * Copyright (c) 2023 Rahim Alwer
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ * of this software and associated documentation files (the "Software"), to deal
13
+ * in the Software without restriction, including without limitation the rights
14
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ * copies of the Software, and to permit persons to whom the Software is
16
+ * furnished to do so, subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included in all
19
+ * copies or substantial portions of the Software.
20
+ *
21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ * SOFTWARE.
28
+ */
29
+ /** The "info" glyph: a ring with a dot and a bar, drawn even-odd so the ring is hollow. */
30
+ const INFO = 'M17.534 10.6674C17.534 11.5143 16.8475 12.2008 16.0006 12.2008C15.1538 12.2008 14.4673 11.5143 14.4673 10.6674C14.4673 9.82061 15.1538 9.13411 16.0006 9.13411C16.8475 9.13411 17.534 9.82061 17.534 10.6674Z M14.6678 14.2005C14.6678 13.8323 14.9663 13.5339 15.3345 13.5339H16.6678C17.036 13.5339 17.3345 13.8323 17.3345 14.2005V22.2005C17.3345 22.5687 17.036 22.8672 16.6678 22.8672H15.3345C14.9663 22.8672 14.6678 22.5687 14.6678 22.2005V14.2005Z M28 16C28 22.6274 22.6274 28 16 28C9.37258 28 4 22.6274 4 16C4 9.37258 9.37258 4 16 4C22.6274 4 28 9.37258 28 16ZM24.9333 16C24.9333 20.9337 20.9337 24.9333 16 24.9333C11.0663 24.9333 7.06667 20.9337 7.06667 16C7.06667 11.0663 11.0663 7.06667 16 7.06667C20.9337 7.06667 24.9333 11.0663 24.9333 16Z';
31
+ const SVG = 'http://www.w3.org/2000/svg';
32
+ /** The glyph, hidden from the accessibility tree: the button carries the name. */
33
+ export function icon() {
34
+ const svg = document.createElementNS(SVG, 'svg');
35
+ svg.setAttribute('viewBox', '0 0 32 32');
36
+ svg.setAttribute('aria-hidden', 'true');
37
+ svg.setAttribute('part', 'icon');
38
+ const path = document.createElementNS(SVG, 'path');
39
+ path.setAttribute('fill-rule', 'evenodd');
40
+ path.setAttribute('d', INFO);
41
+ svg.append(path);
42
+ return svg;
43
+ }
44
+ //# sourceMappingURL=icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon.js","sourceRoot":"","sources":["../src/icon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,2FAA2F;AAC3F,MAAM,IAAI,GACR,yuBAAyuB,CAAC;AAE5uB,MAAM,GAAG,GAAG,4BAA4B,CAAC;AAEzC,kFAAkF;AAClF,MAAM,UAAU,IAAI;IAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjD,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACzC,GAAG,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACxC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC"}