@remotion/media-parser 4.0.266 → 4.0.267
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/dist/containers/flac/get-channel-count.d.ts +1 -1
- package/dist/containers/m3u/get-streams.d.ts +10 -0
- package/dist/containers/m3u/get-streams.js +20 -0
- package/dist/containers/m3u/parse-directive.js +8 -0
- package/dist/containers/m3u/parse-m3u-media-directive.d.ts +2 -0
- package/dist/containers/m3u/parse-m3u-media-directive.js +31 -0
- package/dist/containers/m3u/parse-stream-inf.js +1 -0
- package/dist/containers/m3u/types.d.ts +15 -1
- package/dist/esm/{from-fetch.mjs → fetch.mjs} +3 -119
- package/dist/esm/index.mjs +322 -269
- package/dist/esm/node-writer.mjs +113 -0
- package/dist/esm/node.mjs +37 -106
- package/dist/fetch.d.ts +1 -0
- package/dist/fetch.js +17 -0
- package/dist/make-hvc1-codec-strings.js +3 -3
- package/dist/node-writer.d.ts +1 -0
- package/dist/node-writer.js +17 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +17 -0
- package/dist/readers/fetch/get-body-and-reader.js +3 -2
- package/dist/state/parser-state.d.ts +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-file.d.ts +1 -0
- package/dist/web-file.js +17 -0
- package/package.json +32 -32
- package/dist/containers/flac/m3u/after-manifest-fetch.d.ts +0 -14
- package/dist/containers/flac/m3u/after-manifest-fetch.js +0 -53
- package/dist/containers/flac/m3u/fetch-m3u8-stream.d.ts +0 -3
- package/dist/containers/flac/m3u/fetch-m3u8-stream.js +0 -15
- package/dist/containers/flac/m3u/get-chunks.d.ts +0 -6
- package/dist/containers/flac/m3u/get-chunks.js +0 -20
- package/dist/containers/flac/m3u/get-duration-from-m3u.d.ts +0 -2
- package/dist/containers/flac/m3u/get-duration-from-m3u.js +0 -9
- package/dist/containers/flac/m3u/get-playlist.d.ts +0 -3
- package/dist/containers/flac/m3u/get-playlist.js +0 -19
- package/dist/containers/flac/m3u/get-streams.d.ts +0 -13
- package/dist/containers/flac/m3u/get-streams.js +0 -41
- package/dist/containers/flac/m3u/parse-directive.d.ts +0 -2
- package/dist/containers/flac/m3u/parse-directive.js +0 -64
- package/dist/containers/flac/m3u/parse-m3u-manifest.d.ts +0 -8
- package/dist/containers/flac/m3u/parse-m3u-manifest.js +0 -18
- package/dist/containers/flac/m3u/parse-m3u.d.ts +0 -4
- package/dist/containers/flac/m3u/parse-m3u.js +0 -35
- package/dist/containers/flac/m3u/parse-m3u8-text.d.ts +0 -2
- package/dist/containers/flac/m3u/parse-m3u8-text.js +0 -23
- package/dist/containers/flac/m3u/parse-stream-inf.d.ts +0 -3
- package/dist/containers/flac/m3u/parse-stream-inf.js +0 -61
- package/dist/containers/flac/m3u/return-packets.d.ts +0 -14
- package/dist/containers/flac/m3u/return-packets.js +0 -63
- package/dist/containers/flac/m3u/select-stream.d.ts +0 -10
- package/dist/containers/flac/m3u/select-stream.js +0 -15
- package/dist/containers/flac/m3u/types.d.ts +0 -48
- package/dist/containers/flac/m3u/types.js +0 -2
- package/dist/containers/mp3/get-tracks-from-mp3.d.ts +0 -4
- package/dist/containers/mp3/get-tracks-from-mp3.js +0 -25
- package/dist/does-need-contentlength-contentrange.d.ts +0 -2
- package/dist/does-need-contentlength-contentrange.js +0 -10
- package/dist/esm/from-node.mjs +0 -44
- package/dist/readers/from-uintarray.d.ts +0 -2
- package/dist/readers/from-uintarray.js +0 -27
- /package/dist/esm/{from-web-file.mjs → web-file.mjs} +0 -0
package/dist/esm/index.mjs
CHANGED
|
@@ -1,264 +1,3 @@
|
|
|
1
|
-
// src/errors.ts
|
|
2
|
-
class IsAGifError extends Error {
|
|
3
|
-
mimeType;
|
|
4
|
-
sizeInBytes;
|
|
5
|
-
fileName;
|
|
6
|
-
constructor({
|
|
7
|
-
message,
|
|
8
|
-
mimeType,
|
|
9
|
-
sizeInBytes,
|
|
10
|
-
fileName
|
|
11
|
-
}) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.fileName = "IsAGifError";
|
|
14
|
-
this.mimeType = mimeType;
|
|
15
|
-
this.sizeInBytes = sizeInBytes;
|
|
16
|
-
this.fileName = fileName;
|
|
17
|
-
if (Error.captureStackTrace) {
|
|
18
|
-
Error.captureStackTrace(this, IsAGifError);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
class IsAnImageError extends Error {
|
|
24
|
-
imageType;
|
|
25
|
-
dimensions;
|
|
26
|
-
mimeType;
|
|
27
|
-
sizeInBytes;
|
|
28
|
-
fileName;
|
|
29
|
-
constructor({
|
|
30
|
-
dimensions,
|
|
31
|
-
imageType,
|
|
32
|
-
message,
|
|
33
|
-
mimeType,
|
|
34
|
-
sizeInBytes,
|
|
35
|
-
fileName
|
|
36
|
-
}) {
|
|
37
|
-
super(message);
|
|
38
|
-
this.name = "IsAnImageError";
|
|
39
|
-
this.imageType = imageType;
|
|
40
|
-
this.dimensions = dimensions;
|
|
41
|
-
this.mimeType = mimeType;
|
|
42
|
-
this.sizeInBytes = sizeInBytes;
|
|
43
|
-
this.fileName = fileName;
|
|
44
|
-
if (Error.captureStackTrace) {
|
|
45
|
-
Error.captureStackTrace(this, IsAnImageError);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
class IsAPdfError extends Error {
|
|
51
|
-
mimeType;
|
|
52
|
-
sizeInBytes;
|
|
53
|
-
fileName;
|
|
54
|
-
constructor({
|
|
55
|
-
message,
|
|
56
|
-
mimeType,
|
|
57
|
-
sizeInBytes,
|
|
58
|
-
fileName
|
|
59
|
-
}) {
|
|
60
|
-
super(message);
|
|
61
|
-
this.name = "IsAPdfError";
|
|
62
|
-
this.mimeType = mimeType;
|
|
63
|
-
this.sizeInBytes = sizeInBytes;
|
|
64
|
-
this.fileName = fileName;
|
|
65
|
-
if (Error.captureStackTrace) {
|
|
66
|
-
Error.captureStackTrace(this, IsAPdfError);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
class IsAnUnsupportedFileTypeError extends Error {
|
|
72
|
-
mimeType;
|
|
73
|
-
sizeInBytes;
|
|
74
|
-
fileName;
|
|
75
|
-
constructor({
|
|
76
|
-
message,
|
|
77
|
-
mimeType,
|
|
78
|
-
sizeInBytes,
|
|
79
|
-
fileName
|
|
80
|
-
}) {
|
|
81
|
-
super(message);
|
|
82
|
-
this.name = "IsAnUnsupportedFileTypeError";
|
|
83
|
-
this.mimeType = mimeType;
|
|
84
|
-
this.sizeInBytes = sizeInBytes;
|
|
85
|
-
this.fileName = fileName;
|
|
86
|
-
if (Error.captureStackTrace) {
|
|
87
|
-
Error.captureStackTrace(this, IsAnUnsupportedFileTypeError);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
class IsAnUnsupportedAudioTypeError extends Error {
|
|
93
|
-
mimeType;
|
|
94
|
-
sizeInBytes;
|
|
95
|
-
fileName;
|
|
96
|
-
audioType;
|
|
97
|
-
constructor({
|
|
98
|
-
message,
|
|
99
|
-
mimeType,
|
|
100
|
-
sizeInBytes,
|
|
101
|
-
fileName,
|
|
102
|
-
audioType
|
|
103
|
-
}) {
|
|
104
|
-
super(message);
|
|
105
|
-
this.name = "IsAnUnsupportedAudioTypeError";
|
|
106
|
-
this.mimeType = mimeType;
|
|
107
|
-
this.sizeInBytes = sizeInBytes;
|
|
108
|
-
this.fileName = fileName;
|
|
109
|
-
this.audioType = audioType;
|
|
110
|
-
if (Error.captureStackTrace) {
|
|
111
|
-
Error.captureStackTrace(this, IsAnUnsupportedAudioTypeError);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
class MediaParserAbortError extends Error {
|
|
117
|
-
constructor(message) {
|
|
118
|
-
super(message);
|
|
119
|
-
this.name = "MediaParserAbortError";
|
|
120
|
-
this.cause = undefined;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
var hasBeenAborted = (error) => {
|
|
124
|
-
return error instanceof MediaParserAbortError;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
// src/readers/fetch/get-body-and-reader.ts
|
|
128
|
-
var getLengthAndReader = async (endsWithM3u8, res, ownController) => {
|
|
129
|
-
if (endsWithM3u8) {
|
|
130
|
-
const text = await res.text();
|
|
131
|
-
const stream = new ReadableStream({
|
|
132
|
-
start(controller) {
|
|
133
|
-
controller.enqueue(new TextEncoder().encode(text));
|
|
134
|
-
controller.close();
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
return {
|
|
138
|
-
contentLength: text.length,
|
|
139
|
-
reader: {
|
|
140
|
-
reader: stream.getReader(),
|
|
141
|
-
abort() {
|
|
142
|
-
ownController.abort();
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
needsContentRange: false
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
const length = res.headers.get("content-length");
|
|
149
|
-
const contentLength = length === null ? null : parseInt(length, 10);
|
|
150
|
-
if (!res.body) {
|
|
151
|
-
throw new Error("No body");
|
|
152
|
-
}
|
|
153
|
-
const reader = res.body.getReader();
|
|
154
|
-
return {
|
|
155
|
-
reader: {
|
|
156
|
-
reader,
|
|
157
|
-
abort: () => {
|
|
158
|
-
ownController.abort();
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
contentLength,
|
|
162
|
-
needsContentRange: true
|
|
163
|
-
};
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
// src/readers/fetch/resolve-url.ts
|
|
167
|
-
var resolveUrl = (src) => {
|
|
168
|
-
try {
|
|
169
|
-
const resolvedUrl = typeof window !== "undefined" && typeof window.location !== "undefined" ? new URL(src, window.location.origin) : new URL(src);
|
|
170
|
-
return resolvedUrl;
|
|
171
|
-
} catch {
|
|
172
|
-
return src;
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// src/readers/from-fetch.ts
|
|
177
|
-
function parseContentRange(input) {
|
|
178
|
-
const matches = input.match(/^(\w+) ((\d+)-(\d+)|\*)\/(\d+|\*)$/);
|
|
179
|
-
if (!matches)
|
|
180
|
-
return null;
|
|
181
|
-
const [, unit, , start, end, size] = matches;
|
|
182
|
-
const range = {
|
|
183
|
-
unit,
|
|
184
|
-
start: start != null ? Number(start) : null,
|
|
185
|
-
end: end != null ? Number(end) : null,
|
|
186
|
-
size: size === "*" ? null : Number(size)
|
|
187
|
-
};
|
|
188
|
-
if (range.start === null && range.end === null && range.size === null) {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
return range;
|
|
192
|
-
}
|
|
193
|
-
var validateContentRangeAndDetectIfSupported = (actualRange, parsedContentRange, statusCode) => {
|
|
194
|
-
if (statusCode === 206) {
|
|
195
|
-
return { supportsContentRange: true };
|
|
196
|
-
}
|
|
197
|
-
if (typeof actualRange === "number" && parsedContentRange?.start !== actualRange) {
|
|
198
|
-
if (actualRange === 0) {
|
|
199
|
-
return { supportsContentRange: false };
|
|
200
|
-
}
|
|
201
|
-
throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
|
|
202
|
-
}
|
|
203
|
-
if (actualRange !== null && typeof actualRange !== "number" && (parsedContentRange?.start !== actualRange[0] || parsedContentRange?.end !== actualRange[1])) {
|
|
204
|
-
throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
|
|
205
|
-
}
|
|
206
|
-
return { supportsContentRange: true };
|
|
207
|
-
};
|
|
208
|
-
var fetchReader = {
|
|
209
|
-
read: async ({ src, range, controller }) => {
|
|
210
|
-
if (typeof src !== "string") {
|
|
211
|
-
throw new Error("src must be a string when using `fetchReader`");
|
|
212
|
-
}
|
|
213
|
-
const resolvedUrl = resolveUrl(src);
|
|
214
|
-
const resolvedUrlString = resolvedUrl.toString();
|
|
215
|
-
if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
|
|
216
|
-
return Promise.reject(new Error(`${resolvedUrlString} is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass \`reader: nodeReader\` to parseMedia().`));
|
|
217
|
-
}
|
|
218
|
-
const ownController = new AbortController;
|
|
219
|
-
const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
|
|
220
|
-
const actualRange = range === null ? 0 : range;
|
|
221
|
-
const endsWithM3u8 = (typeof resolvedUrl === "string" ? resolvedUrl : resolvedUrl.pathname).endsWith(".m3u8");
|
|
222
|
-
const headers = actualRange === 0 && endsWithM3u8 ? {} : typeof actualRange === "number" ? {
|
|
223
|
-
Range: `bytes=${actualRange}-`
|
|
224
|
-
} : {
|
|
225
|
-
Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`
|
|
226
|
-
};
|
|
227
|
-
const res = await fetch(resolvedUrl, {
|
|
228
|
-
headers,
|
|
229
|
-
signal: ownController.signal,
|
|
230
|
-
cache
|
|
231
|
-
});
|
|
232
|
-
const contentRange = res.headers.get("content-range");
|
|
233
|
-
const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
|
|
234
|
-
const { supportsContentRange } = validateContentRangeAndDetectIfSupported(actualRange, parsedContentRange, res.status);
|
|
235
|
-
controller._internals.signal.addEventListener("abort", () => {
|
|
236
|
-
ownController.abort(new MediaParserAbortError("Aborted by user"));
|
|
237
|
-
}, { once: true });
|
|
238
|
-
if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
|
|
239
|
-
throw new Error(`Server returned status code ${res.status} for ${src} and range ${actualRange}`);
|
|
240
|
-
}
|
|
241
|
-
const contentDisposition = res.headers.get("content-disposition");
|
|
242
|
-
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
|
|
243
|
-
const fallbackName = src.split("/").pop();
|
|
244
|
-
const { contentLength, needsContentRange, reader } = await getLengthAndReader(endsWithM3u8, res, ownController);
|
|
245
|
-
if (controller) {
|
|
246
|
-
controller._internals.signal.addEventListener("abort", () => {
|
|
247
|
-
reader.reader.cancel().catch(() => {
|
|
248
|
-
});
|
|
249
|
-
}, { once: true });
|
|
250
|
-
}
|
|
251
|
-
return {
|
|
252
|
-
reader,
|
|
253
|
-
contentLength,
|
|
254
|
-
contentType: res.headers.get("content-type"),
|
|
255
|
-
name: name ?? fallbackName,
|
|
256
|
-
supportsContentRange,
|
|
257
|
-
needsContentRange
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
|
|
262
1
|
// src/aac-codecprivate.ts
|
|
263
2
|
var getSampleRateFromSampleFrequencyIndex = (samplingFrequencyIndex) => {
|
|
264
3
|
switch (samplingFrequencyIndex) {
|
|
@@ -2766,8 +2505,8 @@ var getHvc1CodecString = (data) => {
|
|
|
2766
2505
|
const generalProfileSpaceTierFlagAndIdc = data.getUint8();
|
|
2767
2506
|
let generalProfileCompatibility = data.getUint32();
|
|
2768
2507
|
const generalProfileSpace = generalProfileSpaceTierFlagAndIdc >> 6;
|
|
2769
|
-
const generalTierFlag = generalProfileSpaceTierFlagAndIdc >> 5;
|
|
2770
|
-
const generalProfileIdc = generalProfileSpaceTierFlagAndIdc
|
|
2508
|
+
const generalTierFlag = (generalProfileSpaceTierFlagAndIdc & 32) >> 5;
|
|
2509
|
+
const generalProfileIdc = generalProfileSpaceTierFlagAndIdc & 31;
|
|
2771
2510
|
const generalConstraintIndicator = data.getSlice(6);
|
|
2772
2511
|
const generalLevelIdc = data.getUint8();
|
|
2773
2512
|
let profileId = 0;
|
|
@@ -2788,7 +2527,7 @@ var getHvc1CodecString = (data) => {
|
|
|
2788
2527
|
hasByte = true;
|
|
2789
2528
|
}
|
|
2790
2529
|
}
|
|
2791
|
-
return `${profileSpaceChar}${generalProfileIdc.toString(16)}.${profileId.toString(16)}.${generalTierChar}${generalLevelIdc}
|
|
2530
|
+
return `${profileSpaceChar}${generalProfileIdc.toString(16)}.${profileId.toString(16)}.${generalTierChar}${generalLevelIdc}${generalConstraintString ? "." : ""}${generalConstraintString}`;
|
|
2792
2531
|
};
|
|
2793
2532
|
|
|
2794
2533
|
// src/containers/webm/av1-codec-private.ts
|
|
@@ -5808,12 +5547,30 @@ var getM3uStreams = (structure, originalSrc) => {
|
|
|
5808
5547
|
if (next.type !== "m3u-text-value") {
|
|
5809
5548
|
throw new Error("Expected m3u-text-value");
|
|
5810
5549
|
}
|
|
5811
|
-
|
|
5812
|
-
|
|
5550
|
+
const dedicatedAudioTracks = [];
|
|
5551
|
+
if (str.audio) {
|
|
5552
|
+
const match = structure.boxes.filter((box) => {
|
|
5553
|
+
return box.type === "m3u-media-info" && box.groupId === str.audio;
|
|
5554
|
+
});
|
|
5555
|
+
for (const audioTrack of match) {
|
|
5556
|
+
dedicatedAudioTracks.push({
|
|
5557
|
+
autoselect: audioTrack.autoselect,
|
|
5558
|
+
channels: audioTrack.channels,
|
|
5559
|
+
default: audioTrack.default,
|
|
5560
|
+
groupId: audioTrack.groupId,
|
|
5561
|
+
language: audioTrack.language,
|
|
5562
|
+
name: audioTrack.name,
|
|
5563
|
+
url: originalSrc && originalSrc.startsWith("http") ? new URL(audioTrack.uri, originalSrc).href : audioTrack.uri
|
|
5564
|
+
});
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
5567
|
+
boxes.push({
|
|
5568
|
+
url: originalSrc && originalSrc.startsWith("http") ? new URL(next.value, originalSrc).href : next.value,
|
|
5813
5569
|
averageBandwidth: str.averageBandwidth,
|
|
5814
5570
|
bandwidth: str.bandwidth,
|
|
5815
5571
|
codecs: str.codecs,
|
|
5816
|
-
resolution: str.resolution
|
|
5572
|
+
resolution: str.resolution,
|
|
5573
|
+
dedicatedAudioTracks
|
|
5817
5574
|
});
|
|
5818
5575
|
}
|
|
5819
5576
|
}
|
|
@@ -7344,6 +7101,132 @@ class MediaParserEmitter {
|
|
|
7344
7101
|
};
|
|
7345
7102
|
}
|
|
7346
7103
|
|
|
7104
|
+
// src/errors.ts
|
|
7105
|
+
class IsAGifError extends Error {
|
|
7106
|
+
mimeType;
|
|
7107
|
+
sizeInBytes;
|
|
7108
|
+
fileName;
|
|
7109
|
+
constructor({
|
|
7110
|
+
message,
|
|
7111
|
+
mimeType,
|
|
7112
|
+
sizeInBytes,
|
|
7113
|
+
fileName
|
|
7114
|
+
}) {
|
|
7115
|
+
super(message);
|
|
7116
|
+
this.fileName = "IsAGifError";
|
|
7117
|
+
this.mimeType = mimeType;
|
|
7118
|
+
this.sizeInBytes = sizeInBytes;
|
|
7119
|
+
this.fileName = fileName;
|
|
7120
|
+
if (Error.captureStackTrace) {
|
|
7121
|
+
Error.captureStackTrace(this, IsAGifError);
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
|
|
7126
|
+
class IsAnImageError extends Error {
|
|
7127
|
+
imageType;
|
|
7128
|
+
dimensions;
|
|
7129
|
+
mimeType;
|
|
7130
|
+
sizeInBytes;
|
|
7131
|
+
fileName;
|
|
7132
|
+
constructor({
|
|
7133
|
+
dimensions,
|
|
7134
|
+
imageType,
|
|
7135
|
+
message,
|
|
7136
|
+
mimeType,
|
|
7137
|
+
sizeInBytes,
|
|
7138
|
+
fileName
|
|
7139
|
+
}) {
|
|
7140
|
+
super(message);
|
|
7141
|
+
this.name = "IsAnImageError";
|
|
7142
|
+
this.imageType = imageType;
|
|
7143
|
+
this.dimensions = dimensions;
|
|
7144
|
+
this.mimeType = mimeType;
|
|
7145
|
+
this.sizeInBytes = sizeInBytes;
|
|
7146
|
+
this.fileName = fileName;
|
|
7147
|
+
if (Error.captureStackTrace) {
|
|
7148
|
+
Error.captureStackTrace(this, IsAnImageError);
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
|
|
7153
|
+
class IsAPdfError extends Error {
|
|
7154
|
+
mimeType;
|
|
7155
|
+
sizeInBytes;
|
|
7156
|
+
fileName;
|
|
7157
|
+
constructor({
|
|
7158
|
+
message,
|
|
7159
|
+
mimeType,
|
|
7160
|
+
sizeInBytes,
|
|
7161
|
+
fileName
|
|
7162
|
+
}) {
|
|
7163
|
+
super(message);
|
|
7164
|
+
this.name = "IsAPdfError";
|
|
7165
|
+
this.mimeType = mimeType;
|
|
7166
|
+
this.sizeInBytes = sizeInBytes;
|
|
7167
|
+
this.fileName = fileName;
|
|
7168
|
+
if (Error.captureStackTrace) {
|
|
7169
|
+
Error.captureStackTrace(this, IsAPdfError);
|
|
7170
|
+
}
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
7173
|
+
|
|
7174
|
+
class IsAnUnsupportedFileTypeError extends Error {
|
|
7175
|
+
mimeType;
|
|
7176
|
+
sizeInBytes;
|
|
7177
|
+
fileName;
|
|
7178
|
+
constructor({
|
|
7179
|
+
message,
|
|
7180
|
+
mimeType,
|
|
7181
|
+
sizeInBytes,
|
|
7182
|
+
fileName
|
|
7183
|
+
}) {
|
|
7184
|
+
super(message);
|
|
7185
|
+
this.name = "IsAnUnsupportedFileTypeError";
|
|
7186
|
+
this.mimeType = mimeType;
|
|
7187
|
+
this.sizeInBytes = sizeInBytes;
|
|
7188
|
+
this.fileName = fileName;
|
|
7189
|
+
if (Error.captureStackTrace) {
|
|
7190
|
+
Error.captureStackTrace(this, IsAnUnsupportedFileTypeError);
|
|
7191
|
+
}
|
|
7192
|
+
}
|
|
7193
|
+
}
|
|
7194
|
+
|
|
7195
|
+
class IsAnUnsupportedAudioTypeError extends Error {
|
|
7196
|
+
mimeType;
|
|
7197
|
+
sizeInBytes;
|
|
7198
|
+
fileName;
|
|
7199
|
+
audioType;
|
|
7200
|
+
constructor({
|
|
7201
|
+
message,
|
|
7202
|
+
mimeType,
|
|
7203
|
+
sizeInBytes,
|
|
7204
|
+
fileName,
|
|
7205
|
+
audioType
|
|
7206
|
+
}) {
|
|
7207
|
+
super(message);
|
|
7208
|
+
this.name = "IsAnUnsupportedAudioTypeError";
|
|
7209
|
+
this.mimeType = mimeType;
|
|
7210
|
+
this.sizeInBytes = sizeInBytes;
|
|
7211
|
+
this.fileName = fileName;
|
|
7212
|
+
this.audioType = audioType;
|
|
7213
|
+
if (Error.captureStackTrace) {
|
|
7214
|
+
Error.captureStackTrace(this, IsAnUnsupportedAudioTypeError);
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
|
|
7219
|
+
class MediaParserAbortError extends Error {
|
|
7220
|
+
constructor(message) {
|
|
7221
|
+
super(message);
|
|
7222
|
+
this.name = "MediaParserAbortError";
|
|
7223
|
+
this.cause = undefined;
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7226
|
+
var hasBeenAborted = (error) => {
|
|
7227
|
+
return error instanceof MediaParserAbortError;
|
|
7228
|
+
};
|
|
7229
|
+
|
|
7347
7230
|
// src/pause-signal.ts
|
|
7348
7231
|
var makePauseSignal = (emitter) => {
|
|
7349
7232
|
const waiterFns = [];
|
|
@@ -8975,7 +8858,34 @@ var parseStreamInf = (str) => {
|
|
|
8975
8858
|
resolution: map.RESOLUTION ? {
|
|
8976
8859
|
width: parseInt(map.RESOLUTION.split("x")[0], 10),
|
|
8977
8860
|
height: parseInt(map.RESOLUTION.split("x")[1], 10)
|
|
8978
|
-
} : null
|
|
8861
|
+
} : null,
|
|
8862
|
+
audio: map.AUDIO || null
|
|
8863
|
+
};
|
|
8864
|
+
};
|
|
8865
|
+
|
|
8866
|
+
// src/containers/m3u/parse-m3u-media-directive.ts
|
|
8867
|
+
var parseM3uMediaDirective = (str) => {
|
|
8868
|
+
const quotes = splitRespectingQuotes(str);
|
|
8869
|
+
const map = {};
|
|
8870
|
+
for (const quote of quotes) {
|
|
8871
|
+
const firstColon = quote.indexOf("=");
|
|
8872
|
+
const key = firstColon === -1 ? quote : quote.slice(0, firstColon);
|
|
8873
|
+
const value = firstColon === -1 ? null : quote.slice(firstColon + 1);
|
|
8874
|
+
if (value === null) {
|
|
8875
|
+
throw new Error("Value is null");
|
|
8876
|
+
}
|
|
8877
|
+
const actualValue = value?.startsWith('"') && value?.endsWith('"') ? value.slice(1, -1) : value;
|
|
8878
|
+
map[key] = actualValue;
|
|
8879
|
+
}
|
|
8880
|
+
return {
|
|
8881
|
+
type: "m3u-media-info",
|
|
8882
|
+
autoselect: map.AUTOSELECT === "YES",
|
|
8883
|
+
channels: map.CHANNELS ? parseInt(map.CHANNELS, 10) : null,
|
|
8884
|
+
default: map.DEFAULT === "YES",
|
|
8885
|
+
groupId: map["GROUP-ID"],
|
|
8886
|
+
language: map.LANGUAGE || null,
|
|
8887
|
+
name: map.NAME || null,
|
|
8888
|
+
uri: map.URI
|
|
8979
8889
|
};
|
|
8980
8890
|
};
|
|
8981
8891
|
|
|
@@ -8998,6 +8908,13 @@ var parseM3uDirective = (str) => {
|
|
|
8998
8908
|
type: "m3u-independent-segments"
|
|
8999
8909
|
};
|
|
9000
8910
|
}
|
|
8911
|
+
if (directive === "#EXT-X-MEDIA") {
|
|
8912
|
+
if (!value) {
|
|
8913
|
+
throw new Error("EXT-X-MEDIA directive must have a value");
|
|
8914
|
+
}
|
|
8915
|
+
const parsed = parseM3uMediaDirective(value);
|
|
8916
|
+
return parsed;
|
|
8917
|
+
}
|
|
9001
8918
|
if (directive === "#EXT-X-TARGETDURATION") {
|
|
9002
8919
|
if (!value) {
|
|
9003
8920
|
throw new Error("EXT-X-TARGETDURATION directive must have a value");
|
|
@@ -9121,6 +9038,142 @@ var defaultSelectM3uStreamFn = ({ streams }) => {
|
|
|
9121
9038
|
return Promise.resolve(streams[0].id);
|
|
9122
9039
|
};
|
|
9123
9040
|
|
|
9041
|
+
// src/readers/fetch/get-body-and-reader.ts
|
|
9042
|
+
var getLengthAndReader = async (endsWithM3u8, res, ownController) => {
|
|
9043
|
+
if (endsWithM3u8) {
|
|
9044
|
+
const text = await res.text();
|
|
9045
|
+
const encoded = new TextEncoder().encode(text);
|
|
9046
|
+
const stream = new ReadableStream({
|
|
9047
|
+
start(controller) {
|
|
9048
|
+
controller.enqueue(encoded);
|
|
9049
|
+
controller.close();
|
|
9050
|
+
}
|
|
9051
|
+
});
|
|
9052
|
+
return {
|
|
9053
|
+
contentLength: encoded.byteLength,
|
|
9054
|
+
reader: {
|
|
9055
|
+
reader: stream.getReader(),
|
|
9056
|
+
abort() {
|
|
9057
|
+
ownController.abort();
|
|
9058
|
+
}
|
|
9059
|
+
},
|
|
9060
|
+
needsContentRange: false
|
|
9061
|
+
};
|
|
9062
|
+
}
|
|
9063
|
+
const length = res.headers.get("content-length");
|
|
9064
|
+
const contentLength = length === null ? null : parseInt(length, 10);
|
|
9065
|
+
if (!res.body) {
|
|
9066
|
+
throw new Error("No body");
|
|
9067
|
+
}
|
|
9068
|
+
const reader = res.body.getReader();
|
|
9069
|
+
return {
|
|
9070
|
+
reader: {
|
|
9071
|
+
reader,
|
|
9072
|
+
abort: () => {
|
|
9073
|
+
ownController.abort();
|
|
9074
|
+
}
|
|
9075
|
+
},
|
|
9076
|
+
contentLength,
|
|
9077
|
+
needsContentRange: true
|
|
9078
|
+
};
|
|
9079
|
+
};
|
|
9080
|
+
|
|
9081
|
+
// src/readers/fetch/resolve-url.ts
|
|
9082
|
+
var resolveUrl = (src) => {
|
|
9083
|
+
try {
|
|
9084
|
+
const resolvedUrl = typeof window !== "undefined" && typeof window.location !== "undefined" ? new URL(src, window.location.origin) : new URL(src);
|
|
9085
|
+
return resolvedUrl;
|
|
9086
|
+
} catch {
|
|
9087
|
+
return src;
|
|
9088
|
+
}
|
|
9089
|
+
};
|
|
9090
|
+
|
|
9091
|
+
// src/readers/from-fetch.ts
|
|
9092
|
+
function parseContentRange(input) {
|
|
9093
|
+
const matches = input.match(/^(\w+) ((\d+)-(\d+)|\*)\/(\d+|\*)$/);
|
|
9094
|
+
if (!matches)
|
|
9095
|
+
return null;
|
|
9096
|
+
const [, unit, , start, end, size] = matches;
|
|
9097
|
+
const range2 = {
|
|
9098
|
+
unit,
|
|
9099
|
+
start: start != null ? Number(start) : null,
|
|
9100
|
+
end: end != null ? Number(end) : null,
|
|
9101
|
+
size: size === "*" ? null : Number(size)
|
|
9102
|
+
};
|
|
9103
|
+
if (range2.start === null && range2.end === null && range2.size === null) {
|
|
9104
|
+
return null;
|
|
9105
|
+
}
|
|
9106
|
+
return range2;
|
|
9107
|
+
}
|
|
9108
|
+
var validateContentRangeAndDetectIfSupported = (actualRange, parsedContentRange, statusCode) => {
|
|
9109
|
+
if (statusCode === 206) {
|
|
9110
|
+
return { supportsContentRange: true };
|
|
9111
|
+
}
|
|
9112
|
+
if (typeof actualRange === "number" && parsedContentRange?.start !== actualRange) {
|
|
9113
|
+
if (actualRange === 0) {
|
|
9114
|
+
return { supportsContentRange: false };
|
|
9115
|
+
}
|
|
9116
|
+
throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
|
|
9117
|
+
}
|
|
9118
|
+
if (actualRange !== null && typeof actualRange !== "number" && (parsedContentRange?.start !== actualRange[0] || parsedContentRange?.end !== actualRange[1])) {
|
|
9119
|
+
throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
|
|
9120
|
+
}
|
|
9121
|
+
return { supportsContentRange: true };
|
|
9122
|
+
};
|
|
9123
|
+
var fetchReader = {
|
|
9124
|
+
read: async ({ src, range: range2, controller }) => {
|
|
9125
|
+
if (typeof src !== "string") {
|
|
9126
|
+
throw new Error("src must be a string when using `fetchReader`");
|
|
9127
|
+
}
|
|
9128
|
+
const resolvedUrl = resolveUrl(src);
|
|
9129
|
+
const resolvedUrlString = resolvedUrl.toString();
|
|
9130
|
+
if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
|
|
9131
|
+
return Promise.reject(new Error(`${resolvedUrlString} is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass \`reader: nodeReader\` to parseMedia().`));
|
|
9132
|
+
}
|
|
9133
|
+
const ownController = new AbortController;
|
|
9134
|
+
const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
|
|
9135
|
+
const actualRange = range2 === null ? 0 : range2;
|
|
9136
|
+
const endsWithM3u8 = (typeof resolvedUrl === "string" ? resolvedUrl : resolvedUrl.pathname).endsWith(".m3u8");
|
|
9137
|
+
const headers = actualRange === 0 && endsWithM3u8 ? {} : typeof actualRange === "number" ? {
|
|
9138
|
+
Range: `bytes=${actualRange}-`
|
|
9139
|
+
} : {
|
|
9140
|
+
Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`
|
|
9141
|
+
};
|
|
9142
|
+
const res = await fetch(resolvedUrl, {
|
|
9143
|
+
headers,
|
|
9144
|
+
signal: ownController.signal,
|
|
9145
|
+
cache
|
|
9146
|
+
});
|
|
9147
|
+
const contentRange = res.headers.get("content-range");
|
|
9148
|
+
const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
|
|
9149
|
+
const { supportsContentRange } = validateContentRangeAndDetectIfSupported(actualRange, parsedContentRange, res.status);
|
|
9150
|
+
controller._internals.signal.addEventListener("abort", () => {
|
|
9151
|
+
ownController.abort(new MediaParserAbortError("Aborted by user"));
|
|
9152
|
+
}, { once: true });
|
|
9153
|
+
if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
|
|
9154
|
+
throw new Error(`Server returned status code ${res.status} for ${src} and range ${actualRange}`);
|
|
9155
|
+
}
|
|
9156
|
+
const contentDisposition = res.headers.get("content-disposition");
|
|
9157
|
+
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
|
|
9158
|
+
const fallbackName = src.split("/").pop();
|
|
9159
|
+
const { contentLength, needsContentRange, reader } = await getLengthAndReader(endsWithM3u8, res, ownController);
|
|
9160
|
+
if (controller) {
|
|
9161
|
+
controller._internals.signal.addEventListener("abort", () => {
|
|
9162
|
+
reader.reader.cancel().catch(() => {
|
|
9163
|
+
});
|
|
9164
|
+
}, { once: true });
|
|
9165
|
+
}
|
|
9166
|
+
return {
|
|
9167
|
+
reader,
|
|
9168
|
+
contentLength,
|
|
9169
|
+
contentType: res.headers.get("content-type"),
|
|
9170
|
+
name: name ?? fallbackName,
|
|
9171
|
+
supportsContentRange,
|
|
9172
|
+
needsContentRange
|
|
9173
|
+
};
|
|
9174
|
+
}
|
|
9175
|
+
};
|
|
9176
|
+
|
|
9124
9177
|
// src/parse-media.ts
|
|
9125
9178
|
var parseMedia = (options) => {
|
|
9126
9179
|
return internalParseMedia({
|
|
@@ -11969,7 +12022,7 @@ var downloadAndParseMedia = async (options) => {
|
|
|
11969
12022
|
return returnValue;
|
|
11970
12023
|
};
|
|
11971
12024
|
// src/version.ts
|
|
11972
|
-
var VERSION = "4.0.
|
|
12025
|
+
var VERSION = "4.0.267";
|
|
11973
12026
|
|
|
11974
12027
|
// src/index.ts
|
|
11975
12028
|
var MediaParserInternals = {
|