@kenzuya/mediabunny 1.26.0 → 1.28.6
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 +1 -1
- package/dist/bundles/{mediabunny.mjs → mediabunny.js} +21963 -21390
- package/dist/bundles/mediabunny.min.js +490 -0
- package/dist/modules/shared/mp3-misc.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-demuxer.d.ts +6 -6
- package/dist/modules/src/adts/adts-demuxer.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-muxer.d.ts +4 -4
- package/dist/modules/src/adts/adts-muxer.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-reader.d.ts +1 -1
- package/dist/modules/src/adts/adts-reader.d.ts.map +1 -1
- package/dist/modules/src/avi/avi-demuxer.d.ts +44 -0
- package/dist/modules/src/avi/avi-demuxer.d.ts.map +1 -0
- package/dist/modules/src/avi/avi-misc.d.ts +88 -0
- package/dist/modules/src/avi/avi-misc.d.ts.map +1 -0
- package/dist/modules/src/avi/avi-muxer.d.ts +45 -0
- package/dist/modules/src/avi/avi-muxer.d.ts.map +1 -0
- package/dist/modules/src/avi/riff-writer.d.ts +26 -0
- package/dist/modules/src/avi/riff-writer.d.ts.map +1 -0
- package/dist/modules/src/codec-data.d.ts +8 -3
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec.d.ts +10 -10
- package/dist/modules/src/codec.d.ts.map +1 -1
- package/dist/modules/src/conversion.d.ts +33 -16
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/custom-coder.d.ts +8 -8
- package/dist/modules/src/custom-coder.d.ts.map +1 -1
- package/dist/modules/src/demuxer.d.ts +3 -3
- package/dist/modules/src/demuxer.d.ts.map +1 -1
- package/dist/modules/src/encode.d.ts +8 -8
- package/dist/modules/src/encode.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-demuxer.d.ts +7 -7
- package/dist/modules/src/flac/flac-demuxer.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-misc.d.ts +3 -3
- package/dist/modules/src/flac/flac-misc.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-muxer.d.ts +5 -5
- package/dist/modules/src/flac/flac-muxer.d.ts.map +1 -1
- package/dist/modules/src/id3.d.ts +3 -3
- package/dist/modules/src/id3.d.ts.map +1 -1
- package/dist/modules/src/index.d.ts +20 -20
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/input-format.d.ts +22 -0
- package/dist/modules/src/input-format.d.ts.map +1 -1
- package/dist/modules/src/input-track.d.ts +8 -8
- package/dist/modules/src/input-track.d.ts.map +1 -1
- package/dist/modules/src/input.d.ts +12 -12
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts +2 -2
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts +12 -12
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-misc.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts +11 -11
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-reader.d.ts +2 -2
- package/dist/modules/src/isobmff/isobmff-reader.d.ts.map +1 -1
- package/dist/modules/src/matroska/ebml.d.ts +3 -3
- package/dist/modules/src/matroska/ebml.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-demuxer.d.ts +13 -13
- package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-input.d.ts +33 -0
- package/dist/modules/src/matroska/matroska-input.d.ts.map +1 -0
- package/dist/modules/src/matroska/matroska-misc.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-muxer.d.ts +5 -5
- package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
- package/dist/modules/src/media-sink.d.ts +5 -5
- package/dist/modules/src/media-sink.d.ts.map +1 -1
- package/dist/modules/src/media-source.d.ts +22 -4
- package/dist/modules/src/media-source.d.ts.map +1 -1
- package/dist/modules/src/metadata.d.ts +2 -2
- package/dist/modules/src/metadata.d.ts.map +1 -1
- package/dist/modules/src/misc.d.ts +5 -4
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-demuxer.d.ts +7 -7
- package/dist/modules/src/mp3/mp3-demuxer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-muxer.d.ts +4 -4
- package/dist/modules/src/mp3/mp3-muxer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-reader.d.ts +2 -2
- package/dist/modules/src/mp3/mp3-reader.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-writer.d.ts +1 -1
- package/dist/modules/src/mp3/mp3-writer.d.ts.map +1 -1
- package/dist/modules/src/muxer.d.ts +4 -4
- package/dist/modules/src/muxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-demuxer.d.ts +7 -7
- package/dist/modules/src/ogg/ogg-demuxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-misc.d.ts +1 -1
- package/dist/modules/src/ogg/ogg-misc.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-muxer.d.ts +5 -5
- package/dist/modules/src/ogg/ogg-muxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-reader.d.ts +1 -1
- package/dist/modules/src/ogg/ogg-reader.d.ts.map +1 -1
- package/dist/modules/src/output-format.d.ts +51 -6
- package/dist/modules/src/output-format.d.ts.map +1 -1
- package/dist/modules/src/output.d.ts +13 -13
- package/dist/modules/src/output.d.ts.map +1 -1
- package/dist/modules/src/packet.d.ts +1 -1
- package/dist/modules/src/packet.d.ts.map +1 -1
- package/dist/modules/src/pcm.d.ts.map +1 -1
- package/dist/modules/src/reader.d.ts +2 -2
- package/dist/modules/src/reader.d.ts.map +1 -1
- package/dist/modules/src/sample.d.ts +57 -15
- package/dist/modules/src/sample.d.ts.map +1 -1
- package/dist/modules/src/source.d.ts +3 -3
- package/dist/modules/src/source.d.ts.map +1 -1
- package/dist/modules/src/subtitles.d.ts +1 -1
- package/dist/modules/src/subtitles.d.ts.map +1 -1
- package/dist/modules/src/target.d.ts +2 -2
- package/dist/modules/src/target.d.ts.map +1 -1
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/dist/modules/src/wave/riff-writer.d.ts +1 -1
- package/dist/modules/src/wave/riff-writer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-demuxer.d.ts +6 -6
- package/dist/modules/src/wave/wave-demuxer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-muxer.d.ts +4 -4
- package/dist/modules/src/wave/wave-muxer.d.ts.map +1 -1
- package/dist/modules/src/writer.d.ts +1 -1
- package/dist/modules/src/writer.d.ts.map +1 -1
- package/dist/packages/eac3/eac3.wasm +0 -0
- package/dist/packages/eac3/mediabunny-eac3.js +1058 -0
- package/dist/packages/eac3/mediabunny-eac3.min.js +44 -0
- package/dist/packages/mp3-encoder/mediabunny-mp3-encoder.js +694 -0
- package/dist/packages/mp3-encoder/mediabunny-mp3-encoder.min.js +58 -0
- package/dist/packages/mpeg4/mediabunny-mpeg4.js +1198 -0
- package/dist/packages/mpeg4/mediabunny-mpeg4.min.js +44 -0
- package/dist/packages/mpeg4/xvid.wasm +0 -0
- package/package.json +18 -57
- package/dist/bundles/mediabunny.cjs +0 -26140
- package/dist/bundles/mediabunny.min.cjs +0 -147
- package/dist/bundles/mediabunny.min.mjs +0 -146
- package/dist/mediabunny.d.ts +0 -3319
- package/dist/modules/shared/mp3-misc.js +0 -147
- package/dist/modules/src/adts/adts-demuxer.js +0 -239
- package/dist/modules/src/adts/adts-muxer.js +0 -80
- package/dist/modules/src/adts/adts-reader.js +0 -63
- package/dist/modules/src/codec-data.js +0 -1730
- package/dist/modules/src/codec.js +0 -869
- package/dist/modules/src/conversion.js +0 -1459
- package/dist/modules/src/custom-coder.js +0 -117
- package/dist/modules/src/demuxer.js +0 -12
- package/dist/modules/src/encode.js +0 -442
- package/dist/modules/src/flac/flac-demuxer.js +0 -504
- package/dist/modules/src/flac/flac-misc.js +0 -135
- package/dist/modules/src/flac/flac-muxer.js +0 -222
- package/dist/modules/src/id3.js +0 -848
- package/dist/modules/src/index.js +0 -28
- package/dist/modules/src/input-format.js +0 -480
- package/dist/modules/src/input-track.js +0 -372
- package/dist/modules/src/input.js +0 -188
- package/dist/modules/src/isobmff/isobmff-boxes.js +0 -1480
- package/dist/modules/src/isobmff/isobmff-demuxer.js +0 -2618
- package/dist/modules/src/isobmff/isobmff-misc.js +0 -20
- package/dist/modules/src/isobmff/isobmff-muxer.js +0 -966
- package/dist/modules/src/isobmff/isobmff-reader.js +0 -72
- package/dist/modules/src/matroska/ebml.js +0 -653
- package/dist/modules/src/matroska/matroska-demuxer.js +0 -2133
- package/dist/modules/src/matroska/matroska-misc.js +0 -20
- package/dist/modules/src/matroska/matroska-muxer.js +0 -1017
- package/dist/modules/src/media-sink.js +0 -1736
- package/dist/modules/src/media-source.js +0 -1825
- package/dist/modules/src/metadata.js +0 -193
- package/dist/modules/src/misc.js +0 -623
- package/dist/modules/src/mp3/mp3-demuxer.js +0 -285
- package/dist/modules/src/mp3/mp3-muxer.js +0 -123
- package/dist/modules/src/mp3/mp3-reader.js +0 -26
- package/dist/modules/src/mp3/mp3-writer.js +0 -78
- package/dist/modules/src/muxer.js +0 -50
- package/dist/modules/src/node.d.ts +0 -9
- package/dist/modules/src/node.d.ts.map +0 -1
- package/dist/modules/src/node.js +0 -9
- package/dist/modules/src/ogg/ogg-demuxer.js +0 -763
- package/dist/modules/src/ogg/ogg-misc.js +0 -78
- package/dist/modules/src/ogg/ogg-muxer.js +0 -353
- package/dist/modules/src/ogg/ogg-reader.js +0 -65
- package/dist/modules/src/output-format.js +0 -527
- package/dist/modules/src/output.js +0 -300
- package/dist/modules/src/packet.js +0 -182
- package/dist/modules/src/pcm.js +0 -85
- package/dist/modules/src/reader.js +0 -236
- package/dist/modules/src/sample.js +0 -1056
- package/dist/modules/src/source.js +0 -1182
- package/dist/modules/src/subtitles.js +0 -575
- package/dist/modules/src/target.js +0 -140
- package/dist/modules/src/wave/riff-writer.js +0 -30
- package/dist/modules/src/wave/wave-demuxer.js +0 -447
- package/dist/modules/src/wave/wave-muxer.js +0 -318
- package/dist/modules/src/writer.js +0 -370
- package/src/adts/adts-demuxer.ts +0 -331
- package/src/adts/adts-muxer.ts +0 -111
- package/src/adts/adts-reader.ts +0 -85
- package/src/codec-data.ts +0 -2078
- package/src/codec.ts +0 -1092
- package/src/conversion.ts +0 -2112
- package/src/custom-coder.ts +0 -197
- package/src/demuxer.ts +0 -24
- package/src/encode.ts +0 -739
- package/src/flac/flac-demuxer.ts +0 -730
- package/src/flac/flac-misc.ts +0 -164
- package/src/flac/flac-muxer.ts +0 -320
- package/src/id3.ts +0 -925
- package/src/index.ts +0 -221
- package/src/input-format.ts +0 -541
- package/src/input-track.ts +0 -529
- package/src/input.ts +0 -235
- package/src/isobmff/isobmff-boxes.ts +0 -1719
- package/src/isobmff/isobmff-demuxer.ts +0 -3190
- package/src/isobmff/isobmff-misc.ts +0 -29
- package/src/isobmff/isobmff-muxer.ts +0 -1348
- package/src/isobmff/isobmff-reader.ts +0 -91
- package/src/matroska/ebml.ts +0 -730
- package/src/matroska/matroska-demuxer.ts +0 -2481
- package/src/matroska/matroska-misc.ts +0 -29
- package/src/matroska/matroska-muxer.ts +0 -1276
- package/src/media-sink.ts +0 -2179
- package/src/media-source.ts +0 -2243
- package/src/metadata.ts +0 -320
- package/src/misc.ts +0 -798
- package/src/mp3/mp3-demuxer.ts +0 -383
- package/src/mp3/mp3-muxer.ts +0 -166
- package/src/mp3/mp3-reader.ts +0 -34
- package/src/mp3/mp3-writer.ts +0 -120
- package/src/muxer.ts +0 -88
- package/src/node.ts +0 -11
- package/src/ogg/ogg-demuxer.ts +0 -1053
- package/src/ogg/ogg-misc.ts +0 -116
- package/src/ogg/ogg-muxer.ts +0 -497
- package/src/ogg/ogg-reader.ts +0 -93
- package/src/output-format.ts +0 -945
- package/src/output.ts +0 -488
- package/src/packet.ts +0 -263
- package/src/pcm.ts +0 -112
- package/src/reader.ts +0 -323
- package/src/sample.ts +0 -1461
- package/src/source.ts +0 -1688
- package/src/subtitles.ts +0 -711
- package/src/target.ts +0 -204
- package/src/tsconfig.json +0 -16
- package/src/wave/riff-writer.ts +0 -36
- package/src/wave/wave-demuxer.ts +0 -529
- package/src/wave/wave-muxer.ts +0 -371
- package/src/writer.ts +0 -490
package/src/misc.ts
DELETED
|
@@ -1,798 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2025-present, Vanilagy and contributors
|
|
3
|
-
*
|
|
4
|
-
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
-
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export function assert(x: unknown): asserts x {
|
|
10
|
-
if (!x) {
|
|
11
|
-
throw new Error('Assertion failed.');
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Represents a clockwise rotation in degrees.
|
|
17
|
-
* @group Miscellaneous
|
|
18
|
-
* @public
|
|
19
|
-
*/
|
|
20
|
-
export type Rotation = 0 | 90 | 180 | 270;
|
|
21
|
-
|
|
22
|
-
export const normalizeRotation = (rotation: number) => {
|
|
23
|
-
const mappedRotation = (rotation % 360 + 360) % 360;
|
|
24
|
-
|
|
25
|
-
if (mappedRotation === 0 || mappedRotation === 90 || mappedRotation === 180 || mappedRotation === 270) {
|
|
26
|
-
return mappedRotation as Rotation;
|
|
27
|
-
} else {
|
|
28
|
-
throw new Error(`Invalid rotation ${rotation}.`);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type TransformationMatrix = [number, number, number, number, number, number, number, number, number];
|
|
33
|
-
|
|
34
|
-
export const last = <T>(arr: T[]) => {
|
|
35
|
-
return arr && arr[arr.length - 1];
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const isU32 = (value: number) => {
|
|
39
|
-
return value >= 0 && value < 2 ** 32;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export class Bitstream {
|
|
43
|
-
/** Current offset in bits. */
|
|
44
|
-
pos = 0;
|
|
45
|
-
|
|
46
|
-
constructor(public bytes: Uint8Array) {}
|
|
47
|
-
|
|
48
|
-
seekToByte(byteOffset: number) {
|
|
49
|
-
this.pos = 8 * byteOffset;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private readBit() {
|
|
53
|
-
const byteIndex = Math.floor(this.pos / 8);
|
|
54
|
-
const byte = this.bytes[byteIndex] ?? 0;
|
|
55
|
-
const bitIndex = 0b111 - (this.pos & 0b111);
|
|
56
|
-
const bit = (byte & (1 << bitIndex)) >> bitIndex;
|
|
57
|
-
|
|
58
|
-
this.pos++;
|
|
59
|
-
return bit;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
readBits(n: number) {
|
|
63
|
-
if (n === 1) {
|
|
64
|
-
return this.readBit();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let result = 0;
|
|
68
|
-
|
|
69
|
-
for (let i = 0; i < n; i++) {
|
|
70
|
-
result <<= 1;
|
|
71
|
-
result |= this.readBit();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
writeBits(n: number, value: number) {
|
|
78
|
-
const end = this.pos + n;
|
|
79
|
-
|
|
80
|
-
for (let i = this.pos; i < end; i++) {
|
|
81
|
-
const byteIndex = Math.floor(i / 8);
|
|
82
|
-
let byte = this.bytes[byteIndex]!;
|
|
83
|
-
const bitIndex = 0b111 - (i & 0b111);
|
|
84
|
-
|
|
85
|
-
byte &= ~(1 << bitIndex);
|
|
86
|
-
byte |= ((value & (1 << (end - i - 1))) >> (end - i - 1)) << bitIndex;
|
|
87
|
-
this.bytes[byteIndex] = byte;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.pos = end;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
readAlignedByte() {
|
|
94
|
-
// Ensure we're byte-aligned
|
|
95
|
-
if (this.pos % 8 !== 0) {
|
|
96
|
-
throw new Error('Bitstream is not byte-aligned.');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const byteIndex = this.pos / 8;
|
|
100
|
-
const byte = this.bytes[byteIndex] ?? 0;
|
|
101
|
-
|
|
102
|
-
this.pos += 8;
|
|
103
|
-
return byte;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
skipBits(n: number) {
|
|
107
|
-
this.pos += n;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
getBitsLeft() {
|
|
111
|
-
return this.bytes.length * 8 - this.pos;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
clone() {
|
|
115
|
-
const clone = new Bitstream(this.bytes);
|
|
116
|
-
clone.pos = this.pos;
|
|
117
|
-
return clone;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** Reads an exponential-Golomb universal code from a Bitstream. */
|
|
122
|
-
export const readExpGolomb = (bitstream: Bitstream) => {
|
|
123
|
-
let leadingZeroBits = 0;
|
|
124
|
-
while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) {
|
|
125
|
-
leadingZeroBits++;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (leadingZeroBits >= 32) {
|
|
129
|
-
throw new Error('Invalid exponential-Golomb code.');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const result = (1 << leadingZeroBits) - 1 + bitstream.readBits(leadingZeroBits);
|
|
133
|
-
return result;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/** Reads a signed exponential-Golomb universal code from a Bitstream. */
|
|
137
|
-
export const readSignedExpGolomb = (bitstream: Bitstream) => {
|
|
138
|
-
const codeNum = readExpGolomb(bitstream);
|
|
139
|
-
|
|
140
|
-
return ((codeNum & 1) === 0)
|
|
141
|
-
? -(codeNum >> 1)
|
|
142
|
-
: ((codeNum + 1) >> 1);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
export const writeBits = (bytes: Uint8Array, start: number, end: number, value: number) => {
|
|
146
|
-
for (let i = start; i < end; i++) {
|
|
147
|
-
const byteIndex = Math.floor(i / 8);
|
|
148
|
-
let byte = bytes[byteIndex]!;
|
|
149
|
-
const bitIndex = 0b111 - (i & 0b111);
|
|
150
|
-
|
|
151
|
-
byte &= ~(1 << bitIndex);
|
|
152
|
-
byte |= ((value & (1 << (end - i - 1))) >> (end - i - 1)) << bitIndex;
|
|
153
|
-
bytes[byteIndex] = byte;
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
export const toUint8Array = (source: AllowSharedBufferSource): Uint8Array => {
|
|
158
|
-
if (source.constructor === Uint8Array) { // We want a true Uint8Array, not something that extends it like Buffer
|
|
159
|
-
return source;
|
|
160
|
-
} else if (source instanceof ArrayBuffer) {
|
|
161
|
-
return new Uint8Array(source);
|
|
162
|
-
} else {
|
|
163
|
-
return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
export const toDataView = (source: AllowSharedBufferSource) => {
|
|
168
|
-
if (source.constructor === DataView) {
|
|
169
|
-
return source;
|
|
170
|
-
} else if (source instanceof ArrayBuffer) {
|
|
171
|
-
return new DataView(source);
|
|
172
|
-
} else {
|
|
173
|
-
return new DataView(source.buffer, source.byteOffset, source.byteLength);
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export const textDecoder = /* #__PURE__ */ new TextDecoder();
|
|
178
|
-
export const textEncoder = /* #__PURE__ */ new TextEncoder();
|
|
179
|
-
|
|
180
|
-
export const isIso88591Compatible = (text: string) => {
|
|
181
|
-
for (let i = 0; i < text.length; i++) {
|
|
182
|
-
const code = text.charCodeAt(i);
|
|
183
|
-
if (code > 255) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return true;
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const invertObject = <K extends PropertyKey, V extends PropertyKey>(object: Record<K, V>) => {
|
|
192
|
-
return Object.fromEntries(Object.entries(object).map(([key, value]) => [value, key])) as Record<V, K>;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
// For the color space mappings, see Rec. ITU-T H.273.
|
|
196
|
-
|
|
197
|
-
export const COLOR_PRIMARIES_MAP = {
|
|
198
|
-
bt709: 1, // ITU-R BT.709
|
|
199
|
-
bt470bg: 5, // ITU-R BT.470BG
|
|
200
|
-
smpte170m: 6, // ITU-R BT.601 525 - SMPTE 170M
|
|
201
|
-
bt2020: 9, // ITU-R BT.202
|
|
202
|
-
smpte432: 12, // SMPTE EG 432-1
|
|
203
|
-
};
|
|
204
|
-
export const COLOR_PRIMARIES_MAP_INVERSE = /* #__PURE__ */ invertObject(COLOR_PRIMARIES_MAP);
|
|
205
|
-
|
|
206
|
-
export const TRANSFER_CHARACTERISTICS_MAP = {
|
|
207
|
-
'bt709': 1, // ITU-R BT.709
|
|
208
|
-
'smpte170m': 6, // SMPTE 170M
|
|
209
|
-
'linear': 8, // Linear transfer characteristics
|
|
210
|
-
'iec61966-2-1': 13, // IEC 61966-2-1
|
|
211
|
-
'pq': 16, // Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system
|
|
212
|
-
'hlg': 18, // Rec. ITU-R BT.2100-2 hybrid loggamma (HLG) system
|
|
213
|
-
};
|
|
214
|
-
export const TRANSFER_CHARACTERISTICS_MAP_INVERSE = /* #__PURE__ */ invertObject(TRANSFER_CHARACTERISTICS_MAP);
|
|
215
|
-
|
|
216
|
-
export const MATRIX_COEFFICIENTS_MAP = {
|
|
217
|
-
'rgb': 0, // Identity
|
|
218
|
-
'bt709': 1, // ITU-R BT.709
|
|
219
|
-
'bt470bg': 5, // ITU-R BT.470BG
|
|
220
|
-
'smpte170m': 6, // SMPTE 170M
|
|
221
|
-
'bt2020-ncl': 9, // ITU-R BT.2020-2 (non-constant luminance)
|
|
222
|
-
};
|
|
223
|
-
export const MATRIX_COEFFICIENTS_MAP_INVERSE = /* #__PURE__ */ invertObject(MATRIX_COEFFICIENTS_MAP);
|
|
224
|
-
|
|
225
|
-
export type RequiredNonNull<T> = {
|
|
226
|
-
[K in keyof T]-?: NonNullable<T[K]>;
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
export const colorSpaceIsComplete = (
|
|
230
|
-
colorSpace: VideoColorSpaceInit | undefined,
|
|
231
|
-
): colorSpace is RequiredNonNull<VideoColorSpaceInit> => {
|
|
232
|
-
return (
|
|
233
|
-
!!colorSpace
|
|
234
|
-
&& !!colorSpace.primaries
|
|
235
|
-
&& !!colorSpace.transfer
|
|
236
|
-
&& !!colorSpace.matrix
|
|
237
|
-
&& colorSpace.fullRange !== undefined
|
|
238
|
-
);
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
export const isAllowSharedBufferSource = (x: unknown) => {
|
|
242
|
-
return (
|
|
243
|
-
x instanceof ArrayBuffer
|
|
244
|
-
|| (typeof SharedArrayBuffer !== 'undefined' && x instanceof SharedArrayBuffer)
|
|
245
|
-
|| ArrayBuffer.isView(x)
|
|
246
|
-
);
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
export class AsyncMutex {
|
|
250
|
-
currentPromise = Promise.resolve();
|
|
251
|
-
|
|
252
|
-
async acquire() {
|
|
253
|
-
let resolver: () => void;
|
|
254
|
-
const nextPromise = new Promise<void>((resolve) => {
|
|
255
|
-
resolver = resolve;
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
const currentPromiseAlias = this.currentPromise;
|
|
259
|
-
this.currentPromise = nextPromise;
|
|
260
|
-
|
|
261
|
-
await currentPromiseAlias;
|
|
262
|
-
|
|
263
|
-
return resolver!;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
export const bytesToHexString = (bytes: Uint8Array) => {
|
|
268
|
-
return [...bytes].map(x => x.toString(16).padStart(2, '0')).join('');
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
export const reverseBitsU32 = (x: number): number => {
|
|
272
|
-
x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
|
|
273
|
-
x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
|
|
274
|
-
x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);
|
|
275
|
-
x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);
|
|
276
|
-
x = ((x >> 16) & 0x0000ffff) | ((x & 0x0000ffff) << 16);
|
|
277
|
-
return x >>> 0; // Ensure it's treated as an unsigned 32-bit integer
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
/** Returns the smallest index i such that val[i] === key, or -1 if no such index exists. */
|
|
281
|
-
export const binarySearchExact = <T>(arr: T[], key: number, valueGetter: (x: T) => number): number => {
|
|
282
|
-
let low = 0;
|
|
283
|
-
let high = arr.length - 1;
|
|
284
|
-
let ans = -1;
|
|
285
|
-
|
|
286
|
-
while (low <= high) {
|
|
287
|
-
const mid = (low + high) >> 1;
|
|
288
|
-
const midVal = valueGetter(arr[mid]!);
|
|
289
|
-
|
|
290
|
-
if (midVal === key) {
|
|
291
|
-
ans = mid;
|
|
292
|
-
high = mid - 1; // Continue searching left to find the lowest index
|
|
293
|
-
} else if (midVal < key) {
|
|
294
|
-
low = mid + 1;
|
|
295
|
-
} else {
|
|
296
|
-
high = mid - 1;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return ans;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
/** Returns the largest index i such that val[i] <= key, or -1 if no such index exists. */
|
|
304
|
-
export const binarySearchLessOrEqual = <T>(arr: T[], key: number, valueGetter: (x: T) => number) => {
|
|
305
|
-
let low = 0;
|
|
306
|
-
let high = arr.length - 1;
|
|
307
|
-
let ans = -1;
|
|
308
|
-
|
|
309
|
-
while (low <= high) {
|
|
310
|
-
const mid = (low + (high - low + 1) / 2) | 0;
|
|
311
|
-
const midVal = valueGetter(arr[mid]!);
|
|
312
|
-
|
|
313
|
-
if (midVal <= key) {
|
|
314
|
-
ans = mid;
|
|
315
|
-
low = mid + 1;
|
|
316
|
-
} else {
|
|
317
|
-
high = mid - 1;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return ans;
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
/** Assumes the array is already sorted. */
|
|
325
|
-
export const insertSorted = <T>(arr: T[], item: T, valueGetter: (x: T) => number) => {
|
|
326
|
-
const insertionIndex = binarySearchLessOrEqual(arr, valueGetter(item), valueGetter);
|
|
327
|
-
arr.splice(insertionIndex + 1, 0, item); // This even behaves correctly for the -1 case
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
export const promiseWithResolvers = <T = void>() => {
|
|
331
|
-
let resolve: (value: T) => void;
|
|
332
|
-
let reject: (reason: unknown) => void;
|
|
333
|
-
const promise = new Promise<T>((res, rej) => {
|
|
334
|
-
resolve = res;
|
|
335
|
-
reject = rej;
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
return { promise, resolve: resolve!, reject: reject! };
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
export const removeItem = <T>(arr: T[], item: T) => {
|
|
342
|
-
const index = arr.indexOf(item);
|
|
343
|
-
if (index !== -1) {
|
|
344
|
-
arr.splice(index, 1);
|
|
345
|
-
}
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
export const findLast = <T>(arr: T[], predicate: (x: T) => boolean) => {
|
|
349
|
-
for (let i = arr.length - 1; i >= 0; i--) {
|
|
350
|
-
if (predicate(arr[i]!)) {
|
|
351
|
-
return arr[i];
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return undefined;
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
export const findLastIndex = <T>(arr: T[], predicate: (x: T) => boolean) => {
|
|
359
|
-
for (let i = arr.length - 1; i >= 0; i--) {
|
|
360
|
-
if (predicate(arr[i]!)) {
|
|
361
|
-
return i;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
return -1;
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Sync or async iterable.
|
|
370
|
-
* @group Miscellaneous
|
|
371
|
-
* @public
|
|
372
|
-
*/
|
|
373
|
-
export type AnyIterable<T> =
|
|
374
|
-
| Iterable<T>
|
|
375
|
-
| AsyncIterable<T>;
|
|
376
|
-
|
|
377
|
-
export const toAsyncIterator = async function* <T>(source: AnyIterable<T>): AsyncGenerator<T, void, unknown> {
|
|
378
|
-
if (Symbol.iterator in source) {
|
|
379
|
-
// @ts-expect-error Trust me
|
|
380
|
-
yield* source[Symbol.iterator]();
|
|
381
|
-
} else {
|
|
382
|
-
// @ts-expect-error Trust me
|
|
383
|
-
yield* source[Symbol.asyncIterator]();
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
export const validateAnyIterable = (iterable: AnyIterable<unknown>) => {
|
|
388
|
-
if (!(Symbol.iterator in iterable) && !(Symbol.asyncIterator in iterable)) {
|
|
389
|
-
throw new TypeError('Argument must be an iterable or async iterable.');
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
export const assertNever = (x: never) => {
|
|
394
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
395
|
-
throw new Error(`Unexpected value: ${x}`);
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
export const getUint24 = (view: DataView, byteOffset: number, littleEndian: boolean) => {
|
|
399
|
-
const byte1 = view.getUint8(byteOffset);
|
|
400
|
-
const byte2 = view.getUint8(byteOffset + 1);
|
|
401
|
-
const byte3 = view.getUint8(byteOffset + 2);
|
|
402
|
-
|
|
403
|
-
if (littleEndian) {
|
|
404
|
-
return byte1 | (byte2 << 8) | (byte3 << 16);
|
|
405
|
-
} else {
|
|
406
|
-
return (byte1 << 16) | (byte2 << 8) | byte3;
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
export const getInt24 = (view: DataView, byteOffset: number, littleEndian: boolean) => {
|
|
411
|
-
// The left shift pushes the most significant bit into the sign bit region, and the subsequent right shift
|
|
412
|
-
// then correctly interprets the sign bit.
|
|
413
|
-
return getUint24(view, byteOffset, littleEndian) << 8 >> 8;
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
export const setUint24 = (view: DataView, byteOffset: number, value: number, littleEndian: boolean) => {
|
|
417
|
-
// Ensure the value is within 24-bit unsigned range (0 to 16777215)
|
|
418
|
-
value = value >>> 0; // Convert to unsigned 32-bit
|
|
419
|
-
value = value & 0xFFFFFF; // Mask to 24 bits
|
|
420
|
-
|
|
421
|
-
if (littleEndian) {
|
|
422
|
-
view.setUint8(byteOffset, value & 0xFF);
|
|
423
|
-
view.setUint8(byteOffset + 1, (value >>> 8) & 0xFF);
|
|
424
|
-
view.setUint8(byteOffset + 2, (value >>> 16) & 0xFF);
|
|
425
|
-
} else {
|
|
426
|
-
view.setUint8(byteOffset, (value >>> 16) & 0xFF);
|
|
427
|
-
view.setUint8(byteOffset + 1, (value >>> 8) & 0xFF);
|
|
428
|
-
view.setUint8(byteOffset + 2, value & 0xFF);
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
export const setInt24 = (view: DataView, byteOffset: number, value: number, littleEndian: boolean) => {
|
|
433
|
-
// Ensure the value is within 24-bit signed range (-8388608 to 8388607)
|
|
434
|
-
value = clamp(value, -8388608, 8388607);
|
|
435
|
-
|
|
436
|
-
// Convert negative values to their 24-bit representation
|
|
437
|
-
if (value < 0) {
|
|
438
|
-
value = (value + 0x1000000) & 0xFFFFFF;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
setUint24(view, byteOffset, value, littleEndian);
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
export const setInt64 = (view: DataView, byteOffset: number, value: number, littleEndian: boolean) => {
|
|
445
|
-
if (littleEndian) {
|
|
446
|
-
view.setUint32(byteOffset + 0, value, true);
|
|
447
|
-
view.setInt32(byteOffset + 4, Math.floor(value / 2 ** 32), true);
|
|
448
|
-
} else {
|
|
449
|
-
view.setInt32(byteOffset + 0, Math.floor(value / 2 ** 32), true);
|
|
450
|
-
view.setUint32(byteOffset + 4, value, true);
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Calls a function on each value spat out by an async generator. The reason for writing this manually instead of
|
|
456
|
-
* using a generator function is that the generator function queues return() calls - here, we forward them immediately.
|
|
457
|
-
*/
|
|
458
|
-
export const mapAsyncGenerator = <T, U>(
|
|
459
|
-
generator: AsyncGenerator<T, void, unknown>,
|
|
460
|
-
map: (t: T) => U,
|
|
461
|
-
): AsyncGenerator<U, void, unknown> => {
|
|
462
|
-
return {
|
|
463
|
-
async next() {
|
|
464
|
-
const result = await generator.next();
|
|
465
|
-
if (result.done) {
|
|
466
|
-
return { value: undefined, done: true };
|
|
467
|
-
} else {
|
|
468
|
-
return { value: map(result.value), done: false };
|
|
469
|
-
}
|
|
470
|
-
},
|
|
471
|
-
return() {
|
|
472
|
-
return generator.return() as ReturnType<AsyncGenerator<U, void, unknown>['return']>;
|
|
473
|
-
},
|
|
474
|
-
throw(error) {
|
|
475
|
-
return generator.throw(error) as ReturnType<AsyncGenerator<U, void, unknown>['throw']>;
|
|
476
|
-
},
|
|
477
|
-
[Symbol.asyncIterator]() {
|
|
478
|
-
return this;
|
|
479
|
-
},
|
|
480
|
-
};
|
|
481
|
-
};
|
|
482
|
-
|
|
483
|
-
export const clamp = (value: number, min: number, max: number) => {
|
|
484
|
-
return Math.max(min, Math.min(max, value));
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
export const UNDETERMINED_LANGUAGE = 'und';
|
|
488
|
-
|
|
489
|
-
export const roundIfAlmostInteger = (value: number) => {
|
|
490
|
-
const rounded = Math.round(value);
|
|
491
|
-
|
|
492
|
-
if (Math.abs(value / rounded - 1) < 10 * Number.EPSILON) {
|
|
493
|
-
return rounded;
|
|
494
|
-
} else {
|
|
495
|
-
return value;
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
export const roundToMultiple = (value: number, multiple: number) => {
|
|
500
|
-
return Math.round(value / multiple) * multiple;
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
export const ilog = (x: number) => {
|
|
504
|
-
let ret = 0;
|
|
505
|
-
while (x) {
|
|
506
|
-
ret++;
|
|
507
|
-
x >>= 1;
|
|
508
|
-
}
|
|
509
|
-
return ret;
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
const ISO_639_2_REGEX = /^[a-z]{3}$/;
|
|
513
|
-
export const isIso639Dash2LanguageCode = (x: string) => {
|
|
514
|
-
return ISO_639_2_REGEX.test(x);
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
// Since the result will be truncated, add a bit of eps to compensate for floating point errors
|
|
518
|
-
export const SECOND_TO_MICROSECOND_FACTOR = /* #__PURE__ */ 1e6 * (1 + Number.EPSILON);
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* Sets all keys K of T to be required.
|
|
522
|
-
* @group Miscellaneous
|
|
523
|
-
* @public
|
|
524
|
-
*/
|
|
525
|
-
export type SetRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Merges two RequestInit objects with special handling for headers.
|
|
529
|
-
* Headers are merged case-insensitively, but original casing is preserved.
|
|
530
|
-
* init2 headers take precedence and will override case-insensitive matches from init1.
|
|
531
|
-
*/
|
|
532
|
-
export const mergeRequestInit = (init1: RequestInit, init2: RequestInit): RequestInit => {
|
|
533
|
-
const merged: RequestInit = { ...init1, ...init2 };
|
|
534
|
-
|
|
535
|
-
// Special handling for headers
|
|
536
|
-
if (init1.headers || init2.headers) {
|
|
537
|
-
const headers1 = init1.headers ? normalizeHeaders(init1.headers) : {};
|
|
538
|
-
const headers2 = init2.headers ? normalizeHeaders(init2.headers) : {};
|
|
539
|
-
|
|
540
|
-
const mergedHeaders = { ...headers1 };
|
|
541
|
-
|
|
542
|
-
// For each header in headers2, check if a case-insensitive match exists in mergedHeaders
|
|
543
|
-
Object.entries(headers2).forEach(([key2, value2]) => {
|
|
544
|
-
const existingKey = Object.keys(mergedHeaders).find(
|
|
545
|
-
key1 => key1.toLowerCase() === key2.toLowerCase(),
|
|
546
|
-
);
|
|
547
|
-
|
|
548
|
-
if (existingKey) {
|
|
549
|
-
delete mergedHeaders[existingKey];
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
mergedHeaders[key2] = value2;
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
merged.headers = mergedHeaders;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return merged;
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
/** Normalizes HeadersInit to a Record<string, string> format. */
|
|
562
|
-
const normalizeHeaders = (headers: HeadersInit): Record<string, string> => {
|
|
563
|
-
if (headers instanceof Headers) {
|
|
564
|
-
const result: Record<string, string> = {};
|
|
565
|
-
headers.forEach((value, key) => {
|
|
566
|
-
result[key] = value;
|
|
567
|
-
});
|
|
568
|
-
return result;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (Array.isArray(headers)) {
|
|
572
|
-
const result: Record<string, string> = {};
|
|
573
|
-
headers.forEach(([key, value]) => {
|
|
574
|
-
result[key] = value;
|
|
575
|
-
});
|
|
576
|
-
return result;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
return headers;
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
export const retriedFetch = async (
|
|
583
|
-
fetchFn: typeof fetch,
|
|
584
|
-
url: string | URL | Request,
|
|
585
|
-
requestInit: RequestInit,
|
|
586
|
-
getRetryDelay: (previousAttempts: number, error: unknown, url: string | URL | Request) => number | null,
|
|
587
|
-
) => {
|
|
588
|
-
let attempts = 0;
|
|
589
|
-
|
|
590
|
-
while (true) {
|
|
591
|
-
try {
|
|
592
|
-
return await fetchFn(url, requestInit);
|
|
593
|
-
} catch (error) {
|
|
594
|
-
attempts++;
|
|
595
|
-
const retryDelayInSeconds = getRetryDelay(attempts, error, url);
|
|
596
|
-
|
|
597
|
-
if (retryDelayInSeconds === null) {
|
|
598
|
-
throw error;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
console.error('Retrying failed fetch. Error:', error);
|
|
602
|
-
|
|
603
|
-
if (!Number.isFinite(retryDelayInSeconds) || retryDelayInSeconds < 0) {
|
|
604
|
-
throw new TypeError('Retry delay must be a non-negative finite number.');
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (retryDelayInSeconds > 0) {
|
|
608
|
-
await new Promise(resolve => setTimeout(resolve, 1000 * retryDelayInSeconds));
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
export const computeRationalApproximation = (x: number, maxDenominator: number) => {
|
|
615
|
-
// Handle negative numbers
|
|
616
|
-
const sign = x < 0 ? -1 : 1;
|
|
617
|
-
x = Math.abs(x);
|
|
618
|
-
|
|
619
|
-
let prevNumerator = 0, prevDenominator = 1;
|
|
620
|
-
let currNumerator = 1, currDenominator = 0;
|
|
621
|
-
|
|
622
|
-
// Continued fraction algorithm
|
|
623
|
-
let remainder = x;
|
|
624
|
-
|
|
625
|
-
while (true) {
|
|
626
|
-
const integer = Math.floor(remainder);
|
|
627
|
-
|
|
628
|
-
// Calculate next convergent
|
|
629
|
-
const nextNumerator = integer * currNumerator + prevNumerator;
|
|
630
|
-
const nextDenominator = integer * currDenominator + prevDenominator;
|
|
631
|
-
|
|
632
|
-
if (nextDenominator > maxDenominator) {
|
|
633
|
-
return {
|
|
634
|
-
numerator: sign * currNumerator,
|
|
635
|
-
denominator: currDenominator,
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
prevNumerator = currNumerator;
|
|
640
|
-
prevDenominator = currDenominator;
|
|
641
|
-
currNumerator = nextNumerator;
|
|
642
|
-
currDenominator = nextDenominator;
|
|
643
|
-
|
|
644
|
-
remainder = 1 / (remainder - integer);
|
|
645
|
-
|
|
646
|
-
// Guard against precision issues
|
|
647
|
-
if (!isFinite(remainder)) {
|
|
648
|
-
break;
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
return {
|
|
653
|
-
numerator: sign * currNumerator,
|
|
654
|
-
denominator: currDenominator,
|
|
655
|
-
};
|
|
656
|
-
};
|
|
657
|
-
|
|
658
|
-
export class CallSerializer {
|
|
659
|
-
currentPromise = Promise.resolve();
|
|
660
|
-
|
|
661
|
-
call(fn: () => Promise<void> | void) {
|
|
662
|
-
return this.currentPromise = this.currentPromise.then(fn);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
let isWebKitCache: boolean | null = null;
|
|
667
|
-
export const isWebKit = () => {
|
|
668
|
-
if (isWebKitCache !== null) {
|
|
669
|
-
return isWebKitCache;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// This even returns true for WebKit-wrapping browsers such as Chrome on iOS
|
|
673
|
-
return isWebKitCache = !!(typeof navigator !== 'undefined' && navigator.vendor?.match(/apple/i));
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
let isFirefoxCache: boolean | null = null;
|
|
677
|
-
export const isFirefox = () => {
|
|
678
|
-
if (isFirefoxCache !== null) {
|
|
679
|
-
return isFirefoxCache;
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
return isFirefoxCache = typeof navigator !== 'undefined' && navigator.userAgent?.includes('Firefox');
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
let isChromiumCache: boolean | null = null;
|
|
686
|
-
export const isChromium = () => {
|
|
687
|
-
if (isChromiumCache !== null) {
|
|
688
|
-
return isChromiumCache;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
return isChromiumCache = !!(typeof navigator !== 'undefined' && navigator.vendor?.includes('Google Inc'));
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* T or a promise that resolves to T.
|
|
696
|
-
* @group Miscellaneous
|
|
697
|
-
* @public
|
|
698
|
-
*/
|
|
699
|
-
export type MaybePromise<T> = T | Promise<T>;
|
|
700
|
-
|
|
701
|
-
/** Acts like `??` except the condition is -1 and not null/undefined. */
|
|
702
|
-
export const coalesceIndex = (a: number, b: number) => {
|
|
703
|
-
return a !== -1 ? a : b;
|
|
704
|
-
};
|
|
705
|
-
|
|
706
|
-
export const closedIntervalsOverlap = (startA: number, endA: number, startB: number, endB: number) => {
|
|
707
|
-
return startA <= endB && startB <= endA;
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
type KeyValuePair<T extends Record<string, unknown>> = {
|
|
711
|
-
[K in keyof T]-?: {
|
|
712
|
-
key: K;
|
|
713
|
-
value: T[K] extends infer R | undefined ? R : T[K];
|
|
714
|
-
}
|
|
715
|
-
}[keyof T];
|
|
716
|
-
|
|
717
|
-
export const keyValueIterator = function* <T extends Record<string, unknown>>(object: T) {
|
|
718
|
-
for (const key in object) {
|
|
719
|
-
const value = object[key];
|
|
720
|
-
if (value === undefined) {
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
yield { key, value } as KeyValuePair<T>;
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
|
|
728
|
-
export const imageMimeTypeToExtension = (mimeType: string) => {
|
|
729
|
-
switch (mimeType.toLowerCase()) {
|
|
730
|
-
case 'image/jpeg':
|
|
731
|
-
case 'image/jpg':
|
|
732
|
-
return '.jpg';
|
|
733
|
-
case 'image/png':
|
|
734
|
-
return '.png';
|
|
735
|
-
case 'image/gif':
|
|
736
|
-
return '.gif';
|
|
737
|
-
case 'image/webp':
|
|
738
|
-
return '.webp';
|
|
739
|
-
case 'image/bmp':
|
|
740
|
-
return '.bmp';
|
|
741
|
-
case 'image/svg+xml':
|
|
742
|
-
return '.svg';
|
|
743
|
-
case 'image/tiff':
|
|
744
|
-
return '.tiff';
|
|
745
|
-
case 'image/avif':
|
|
746
|
-
return '.avif';
|
|
747
|
-
case 'image/x-icon':
|
|
748
|
-
case 'image/vnd.microsoft.icon':
|
|
749
|
-
return '.ico';
|
|
750
|
-
default:
|
|
751
|
-
return null;
|
|
752
|
-
}
|
|
753
|
-
};
|
|
754
|
-
|
|
755
|
-
export const base64ToBytes = (base64: string) => {
|
|
756
|
-
const decoded = atob(base64);
|
|
757
|
-
const bytes = new Uint8Array(decoded.length);
|
|
758
|
-
|
|
759
|
-
for (let i = 0; i < decoded.length; i++) {
|
|
760
|
-
bytes[i] = decoded.charCodeAt(i);
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
return bytes;
|
|
764
|
-
};
|
|
765
|
-
|
|
766
|
-
export const bytesToBase64 = (bytes: Uint8Array) => {
|
|
767
|
-
let string = '';
|
|
768
|
-
|
|
769
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
770
|
-
string += String.fromCharCode(bytes[i]!);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
return btoa(string);
|
|
774
|
-
};
|
|
775
|
-
|
|
776
|
-
export const uint8ArraysAreEqual = (a: Uint8Array, b: Uint8Array) => {
|
|
777
|
-
if (a.length !== b.length) {
|
|
778
|
-
return false;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
for (let i = 0; i < a.length; i++) {
|
|
782
|
-
if (a[i] !== b[i]) {
|
|
783
|
-
return false;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
return true;
|
|
788
|
-
};
|
|
789
|
-
|
|
790
|
-
export const polyfillSymbolDispose = () => {
|
|
791
|
-
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html
|
|
792
|
-
// @ts-expect-error Readonly
|
|
793
|
-
Symbol.dispose ??= Symbol('Symbol.dispose');
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
export const isNumber = (x: unknown) => {
|
|
797
|
-
return typeof x === 'number' && !Number.isNaN(x);
|
|
798
|
-
};
|