@remotion/media-parser 4.0.267 → 4.0.268
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/mp3/get-duration.js +4 -3
- package/dist/containers/mp3/parse-mpeg-header.js +57 -40
- package/dist/containers/webm/get-ready-tracks.d.ts +9 -2
- package/dist/containers/webm/get-ready-tracks.js +43 -8
- package/dist/containers/webm/get-sample-from-block.js +19 -0
- package/dist/containers/webm/make-track.d.ts +1 -0
- package/dist/containers/webm/make-track.js +9 -8
- package/dist/esm/fetch.mjs +31 -11
- package/dist/esm/index.mjs +533 -430
- package/dist/get-tracks.js +7 -14
- package/dist/has-all-info.js +7 -3
- package/dist/index.d.ts +4 -0
- package/dist/internal-parse-media.js +1 -1
- package/dist/readers/fetch/get-body-and-reader.d.ts +6 -1
- package/dist/readers/fetch/get-body-and-reader.js +7 -6
- package/dist/readers/from-fetch.js +16 -5
- package/dist/state/mp3.d.ts +5 -1
- package/dist/state/mp3.js +6 -0
- package/dist/state/parser-state.d.ts +4 -0
- package/dist/state/webm.d.ts +4 -0
- package/dist/state/webm.js +10 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -5,15 +5,16 @@ const get_frame_length_1 = require("./get-frame-length");
|
|
|
5
5
|
const samples_per_mpeg_file_1 = require("./samples-per-mpeg-file");
|
|
6
6
|
const getDurationFromMp3 = (state) => {
|
|
7
7
|
const mp3Info = state.mp3Info.getMp3Info();
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const mp3CbrInfo = state.mp3Info.getCbrMp3Info();
|
|
9
|
+
if (!mp3Info || !mp3CbrInfo) {
|
|
10
|
+
return null;
|
|
10
11
|
}
|
|
11
12
|
const samplesPerFrame = (0, samples_per_mpeg_file_1.getSamplesPerMpegFrame)({
|
|
12
13
|
layer: mp3Info.layer,
|
|
13
14
|
mpegVersion: mp3Info.mpegVersion,
|
|
14
15
|
});
|
|
15
16
|
const frameLengthInBytes = (0, get_frame_length_1.getMpegFrameLength)({
|
|
16
|
-
bitrateKbit:
|
|
17
|
+
bitrateKbit: mp3CbrInfo.bitrateKbit,
|
|
17
18
|
padding: false,
|
|
18
19
|
samplesPerFrame,
|
|
19
20
|
samplingFrequency: mp3Info.sampleRate,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// spec: http://www.mp3-tech.org/programmer/frame_header.html
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.parseMpegHeader = void 0;
|
|
5
|
+
const log_1 = require("../../log");
|
|
5
6
|
const register_track_1 = require("../../register-track");
|
|
6
7
|
const get_frame_length_1 = require("./get-frame-length");
|
|
7
8
|
const samples_per_mpeg_file_1 = require("./samples-per-mpeg-file");
|
|
@@ -219,35 +220,45 @@ const parseMpegHeader = async ({ state, }) => {
|
|
|
219
220
|
const offsetNow = iterator.counter.getOffset();
|
|
220
221
|
iterator.counter.decrement(offsetNow - initialOffset);
|
|
221
222
|
const data = iterator.getSlice(frameLength);
|
|
223
|
+
let isInfoTag = false;
|
|
222
224
|
if (state.callbacks.tracks.getTracks().length === 0) {
|
|
223
|
-
|
|
225
|
+
const info = {
|
|
224
226
|
layer,
|
|
225
227
|
mpegVersion,
|
|
226
228
|
sampleRate,
|
|
227
|
-
bitrateKbit,
|
|
228
229
|
startOfMpegStream: initialOffset,
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
230
|
+
};
|
|
231
|
+
const asText = new TextDecoder().decode(data);
|
|
232
|
+
const isVbr = asText.includes('Xing') || asText.includes('VBRI');
|
|
233
|
+
isInfoTag = isVbr || asText.includes('Info');
|
|
234
|
+
if (isVbr) {
|
|
235
|
+
log_1.Log.verbose(state.logLevel, 'MP3 has variable bit rate. Requiring whole file to be read');
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
state.mp3Info.setCbrMp3Info({
|
|
239
|
+
bitrateKbit,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (!isInfoTag) {
|
|
243
|
+
state.mp3Info.setMp3Info(info);
|
|
244
|
+
await (0, register_track_1.registerAudioTrack)({
|
|
245
|
+
container: 'mp3',
|
|
246
|
+
state,
|
|
247
|
+
track: {
|
|
248
|
+
type: 'audio',
|
|
249
|
+
codec: 'mp3',
|
|
250
|
+
codecPrivate: null,
|
|
251
|
+
codecWithoutConfig: 'mp3',
|
|
252
|
+
description: undefined,
|
|
253
|
+
numberOfChannels,
|
|
254
|
+
sampleRate,
|
|
255
|
+
timescale: 1000000,
|
|
256
|
+
trackId: 0,
|
|
257
|
+
trakBox: null,
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
261
|
+
}
|
|
251
262
|
}
|
|
252
263
|
const avgLength = (0, get_frame_length_1.getAverageMpegFrameLength)({
|
|
253
264
|
bitrateKbit,
|
|
@@ -255,21 +266,27 @@ const parseMpegHeader = async ({ state, }) => {
|
|
|
255
266
|
samplesPerFrame,
|
|
256
267
|
samplingFrequency: sampleRate,
|
|
257
268
|
});
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
duration
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
269
|
+
if (!isInfoTag) {
|
|
270
|
+
const mp3Info = state.mp3Info.getMp3Info();
|
|
271
|
+
if (!mp3Info) {
|
|
272
|
+
throw new Error('No MP3 info');
|
|
273
|
+
}
|
|
274
|
+
const nthFrame = Math.round((initialOffset - mp3Info.startOfMpegStream) / avgLength);
|
|
275
|
+
const durationInSeconds = samplesPerFrame / sampleRate;
|
|
276
|
+
const timeInSeconds = (nthFrame * samplesPerFrame) / sampleRate;
|
|
277
|
+
const timestamp = Math.round(timeInSeconds * 1000000);
|
|
278
|
+
const duration = Math.round(durationInSeconds * 1000000);
|
|
279
|
+
await state.callbacks.onAudioSample(0, {
|
|
280
|
+
data,
|
|
281
|
+
cts: timestamp,
|
|
282
|
+
dts: timestamp,
|
|
283
|
+
duration,
|
|
284
|
+
offset: initialOffset,
|
|
285
|
+
timescale: 1000000,
|
|
286
|
+
timestamp,
|
|
287
|
+
trackId: 0,
|
|
288
|
+
type: 'key',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
274
291
|
};
|
|
275
292
|
exports.parseMpegHeader = parseMpegHeader;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { Track } from '../../get-tracks';
|
|
2
|
-
import type {
|
|
3
|
-
export
|
|
2
|
+
import type { ParserState } from '../../state/parser-state';
|
|
3
|
+
export type ResolvedAndUnresolvedTracks = {
|
|
4
|
+
resolved: Track[];
|
|
5
|
+
missingInfo: Track[];
|
|
6
|
+
};
|
|
7
|
+
export declare const getTracksFromMatroska: ({ state, }: {
|
|
8
|
+
state: ParserState;
|
|
9
|
+
}) => ResolvedAndUnresolvedTracks;
|
|
10
|
+
export declare const matroskaHasTracks: (state: ParserState) => boolean;
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTracksFromMatroska = void 0;
|
|
3
|
+
exports.matroskaHasTracks = exports.getTracksFromMatroska = void 0;
|
|
4
|
+
const codec_string_1 = require("../avc/codec-string");
|
|
4
5
|
const make_track_1 = require("./make-track");
|
|
5
6
|
const traversal_1 = require("./traversal");
|
|
6
|
-
const getTracksFromMatroska = (
|
|
7
|
-
const
|
|
7
|
+
const getTracksFromMatroska = ({ state, }) => {
|
|
8
|
+
const webmState = state.webm;
|
|
9
|
+
const structure = state.getMatroskaStructure();
|
|
10
|
+
const mainSegment = (0, traversal_1.getMainSegment)(structure.boxes);
|
|
11
|
+
if (!mainSegment) {
|
|
12
|
+
throw new Error('No main segment');
|
|
13
|
+
}
|
|
14
|
+
const tracksSegment = (0, traversal_1.getTracksSegment)(mainSegment);
|
|
8
15
|
if (!tracksSegment) {
|
|
9
16
|
throw new Error('No tracks segment');
|
|
10
17
|
}
|
|
11
|
-
const
|
|
18
|
+
const resolvedTracks = [];
|
|
19
|
+
const missingInfo = [];
|
|
12
20
|
for (const trackEntrySegment of tracksSegment.value) {
|
|
13
21
|
if (trackEntrySegment.type === 'Crc32') {
|
|
14
22
|
continue;
|
|
@@ -18,12 +26,39 @@ const getTracksFromMatroska = (segment, timescale) => {
|
|
|
18
26
|
}
|
|
19
27
|
const track = (0, make_track_1.getTrack)({
|
|
20
28
|
track: trackEntrySegment,
|
|
21
|
-
timescale,
|
|
29
|
+
timescale: webmState.getTimescale(),
|
|
22
30
|
});
|
|
23
|
-
if (track) {
|
|
24
|
-
|
|
31
|
+
if (!track) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (track.codec === make_track_1.NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS) {
|
|
35
|
+
const avc = webmState.getAvcProfileForTrackNumber(track.trackId);
|
|
36
|
+
if (avc) {
|
|
37
|
+
resolvedTracks.push({
|
|
38
|
+
...track,
|
|
39
|
+
codec: (0, codec_string_1.getCodecStringFromSpsAndPps)(avc),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
missingInfo.push(track);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
resolvedTracks.push(track);
|
|
25
48
|
}
|
|
26
49
|
}
|
|
27
|
-
return
|
|
50
|
+
return { missingInfo, resolved: resolvedTracks };
|
|
28
51
|
};
|
|
29
52
|
exports.getTracksFromMatroska = getTracksFromMatroska;
|
|
53
|
+
const matroskaHasTracks = (state) => {
|
|
54
|
+
const structure = state.getMatroskaStructure();
|
|
55
|
+
const mainSegment = (0, traversal_1.getMainSegment)(structure.boxes);
|
|
56
|
+
if (!mainSegment) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return ((0, traversal_1.getTracksSegment)(mainSegment) !== null &&
|
|
60
|
+
(0, exports.getTracksFromMatroska)({
|
|
61
|
+
state,
|
|
62
|
+
}).missingInfo.length === 0);
|
|
63
|
+
};
|
|
64
|
+
exports.matroskaHasTracks = matroskaHasTracks;
|
|
@@ -2,8 +2,21 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getSampleFromBlock = void 0;
|
|
4
4
|
const buffer_iterator_1 = require("../../buffer-iterator");
|
|
5
|
+
const parse_avc_1 = require("../avc/parse-avc");
|
|
6
|
+
const get_ready_tracks_1 = require("./get-ready-tracks");
|
|
5
7
|
const all_segments_1 = require("./segments/all-segments");
|
|
6
8
|
const block_simple_block_flags_1 = require("./segments/block-simple-block-flags");
|
|
9
|
+
const addAvcToTrackIfNecessary = ({ partialVideoSample, codec, state, trackNumber, }) => {
|
|
10
|
+
if (codec === 'V_MPEG4/ISO/AVC' &&
|
|
11
|
+
(0, get_ready_tracks_1.getTracksFromMatroska)({ state }).missingInfo.length > 0) {
|
|
12
|
+
const parsed = (0, parse_avc_1.parseAvc)(partialVideoSample.data);
|
|
13
|
+
for (const parse of parsed) {
|
|
14
|
+
if (parse.type === 'avc-profile') {
|
|
15
|
+
state.webm.setAvcProfileForTrackNumber(trackNumber, parse);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
7
20
|
const getSampleFromBlock = (ebml, state, offset) => {
|
|
8
21
|
const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(ebml.value, ebml.value.length);
|
|
9
22
|
const trackNumber = iterator.getVint();
|
|
@@ -49,6 +62,12 @@ const getSampleFromBlock = (ebml, state, offset) => {
|
|
|
49
62
|
partialVideoSample,
|
|
50
63
|
};
|
|
51
64
|
}
|
|
65
|
+
addAvcToTrackIfNecessary({
|
|
66
|
+
codec,
|
|
67
|
+
partialVideoSample,
|
|
68
|
+
state,
|
|
69
|
+
trackNumber,
|
|
70
|
+
});
|
|
52
71
|
const sample = {
|
|
53
72
|
...partialVideoSample,
|
|
54
73
|
type: keyframe ? 'key' : 'delta',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AudioTrack, MediaParserAudioCodec, VideoTrack } from '../../get-tracks';
|
|
2
2
|
import type { TrackEntry } from './segments/all-segments';
|
|
3
|
+
export declare const NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS = "no-codec-private-should-be-derived-from-sps";
|
|
3
4
|
export declare const getMatroskaAudioCodecWithoutConfigString: ({ track, }: {
|
|
4
5
|
track: TrackEntry;
|
|
5
6
|
}) => MediaParserAudioCodec;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTrack = exports.getMatroskaAudioCodecWithoutConfigString = void 0;
|
|
3
|
+
exports.getTrack = exports.getMatroskaAudioCodecWithoutConfigString = exports.NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS = void 0;
|
|
4
4
|
const buffer_iterator_1 = require("../../buffer-iterator");
|
|
5
5
|
const make_hvc1_codec_strings_1 = require("../../make-hvc1-codec-strings");
|
|
6
6
|
const av1_codec_private_1 = require("./av1-codec-private");
|
|
@@ -8,6 +8,7 @@ const color_1 = require("./color");
|
|
|
8
8
|
const description_1 = require("./description");
|
|
9
9
|
const track_entry_1 = require("./segments/track-entry");
|
|
10
10
|
const traversal_1 = require("./traversal");
|
|
11
|
+
exports.NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS = 'no-codec-private-should-be-derived-from-sps';
|
|
11
12
|
const getDescription = (track) => {
|
|
12
13
|
const codec = (0, traversal_1.getCodecSegment)(track);
|
|
13
14
|
if (!codec) {
|
|
@@ -46,7 +47,7 @@ const getMatroskaVideoCodecString = ({ track, codecSegment: codec, }) => {
|
|
|
46
47
|
if (codec.value === 'V_VP9') {
|
|
47
48
|
const priv = (0, traversal_1.getPrivateData)(track);
|
|
48
49
|
if (priv) {
|
|
49
|
-
throw new Error('@remotion/media-parser cannot handle the private data for VP9. Do you have an example file you could send so we can implement it?');
|
|
50
|
+
throw new Error('@remotion/media-parser cannot handle the private data for VP9. Do you have an example file you could send so we can implement it? https://remotion.dev/report');
|
|
50
51
|
}
|
|
51
52
|
return 'vp09.00.10.08';
|
|
52
53
|
}
|
|
@@ -55,7 +56,12 @@ const getMatroskaVideoCodecString = ({ track, codecSegment: codec, }) => {
|
|
|
55
56
|
if (priv) {
|
|
56
57
|
return `avc1.${priv[1].toString(16).padStart(2, '0')}${priv[2].toString(16).padStart(2, '0')}${priv[3].toString(16).padStart(2, '0')}`;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
+
return exports.NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS;
|
|
60
|
+
}
|
|
61
|
+
if (codec.value === 'V_MPEGH/ISO/HEVC') {
|
|
62
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
63
|
+
const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(priv, priv.length);
|
|
64
|
+
return 'hvc1.' + (0, make_hvc1_codec_strings_1.getHvc1CodecString)(iterator);
|
|
59
65
|
}
|
|
60
66
|
if (codec.value === 'V_AV1') {
|
|
61
67
|
const priv = (0, traversal_1.getPrivateData)(track);
|
|
@@ -64,11 +70,6 @@ const getMatroskaVideoCodecString = ({ track, codecSegment: codec, }) => {
|
|
|
64
70
|
}
|
|
65
71
|
return (0, av1_codec_private_1.parseAv1PrivateData)(priv, null);
|
|
66
72
|
}
|
|
67
|
-
if (codec.value === 'V_MPEGH/ISO/HEVC') {
|
|
68
|
-
const priv = (0, traversal_1.getPrivateData)(track);
|
|
69
|
-
const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(priv, priv.length);
|
|
70
|
-
return 'hvc1.' + (0, make_hvc1_codec_strings_1.getHvc1CodecString)(iterator);
|
|
71
|
-
}
|
|
72
73
|
throw new Error(`Unknown codec: ${codec.value}`);
|
|
73
74
|
};
|
|
74
75
|
const getMatroskaAudioCodecWithoutConfigString = ({ track, }) => {
|
package/dist/esm/fetch.mjs
CHANGED
|
@@ -8,10 +8,17 @@ class MediaParserAbortError extends Error {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
// src/readers/fetch/get-body-and-reader.ts
|
|
11
|
-
var getLengthAndReader = async (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
var getLengthAndReader = async ({
|
|
12
|
+
canLiveWithoutContentLength,
|
|
13
|
+
res,
|
|
14
|
+
ownController,
|
|
15
|
+
requestedWithoutRange
|
|
16
|
+
}) => {
|
|
17
|
+
const length = res.headers.get("content-length");
|
|
18
|
+
const contentLength = length === null ? null : parseInt(length, 10);
|
|
19
|
+
if (requestedWithoutRange || canLiveWithoutContentLength && contentLength === null) {
|
|
20
|
+
const buffer = await res.arrayBuffer();
|
|
21
|
+
const encoded = new Uint8Array(buffer);
|
|
15
22
|
const stream = new ReadableStream({
|
|
16
23
|
start(controller) {
|
|
17
24
|
controller.enqueue(encoded);
|
|
@@ -29,8 +36,6 @@ var getLengthAndReader = async (endsWithM3u8, res, ownController) => {
|
|
|
29
36
|
needsContentRange: false
|
|
30
37
|
};
|
|
31
38
|
}
|
|
32
|
-
const length = res.headers.get("content-length");
|
|
33
|
-
const contentLength = length === null ? null : parseInt(length, 10);
|
|
34
39
|
if (!res.body) {
|
|
35
40
|
throw new Error("No body");
|
|
36
41
|
}
|
|
@@ -74,7 +79,11 @@ function parseContentRange(input) {
|
|
|
74
79
|
}
|
|
75
80
|
return range;
|
|
76
81
|
}
|
|
77
|
-
var validateContentRangeAndDetectIfSupported = (
|
|
82
|
+
var validateContentRangeAndDetectIfSupported = ({
|
|
83
|
+
actualRange,
|
|
84
|
+
parsedContentRange,
|
|
85
|
+
statusCode
|
|
86
|
+
}) => {
|
|
78
87
|
if (statusCode === 206) {
|
|
79
88
|
return { supportsContentRange: true };
|
|
80
89
|
}
|
|
@@ -102,8 +111,10 @@ var fetchReader = {
|
|
|
102
111
|
const ownController = new AbortController;
|
|
103
112
|
const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
|
|
104
113
|
const actualRange = range === null ? 0 : range;
|
|
105
|
-
const
|
|
106
|
-
const
|
|
114
|
+
const asString = typeof resolvedUrl === "string" ? resolvedUrl : resolvedUrl.pathname;
|
|
115
|
+
const requestWithoutRange = asString.endsWith(".m3u8");
|
|
116
|
+
const canLiveWithoutContentLength = asString.endsWith(".m3u8") || asString.endsWith(".ts");
|
|
117
|
+
const headers = actualRange === 0 && requestWithoutRange ? {} : typeof actualRange === "number" ? {
|
|
107
118
|
Range: `bytes=${actualRange}-`
|
|
108
119
|
} : {
|
|
109
120
|
Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`
|
|
@@ -115,7 +126,11 @@ var fetchReader = {
|
|
|
115
126
|
});
|
|
116
127
|
const contentRange = res.headers.get("content-range");
|
|
117
128
|
const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
|
|
118
|
-
const { supportsContentRange } = validateContentRangeAndDetectIfSupported(
|
|
129
|
+
const { supportsContentRange } = validateContentRangeAndDetectIfSupported({
|
|
130
|
+
actualRange,
|
|
131
|
+
parsedContentRange,
|
|
132
|
+
statusCode: res.status
|
|
133
|
+
});
|
|
119
134
|
controller._internals.signal.addEventListener("abort", () => {
|
|
120
135
|
ownController.abort(new MediaParserAbortError("Aborted by user"));
|
|
121
136
|
}, { once: true });
|
|
@@ -125,7 +140,12 @@ var fetchReader = {
|
|
|
125
140
|
const contentDisposition = res.headers.get("content-disposition");
|
|
126
141
|
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
|
|
127
142
|
const fallbackName = src.split("/").pop();
|
|
128
|
-
const { contentLength, needsContentRange, reader } = await getLengthAndReader(
|
|
143
|
+
const { contentLength, needsContentRange, reader } = await getLengthAndReader({
|
|
144
|
+
canLiveWithoutContentLength,
|
|
145
|
+
res,
|
|
146
|
+
ownController,
|
|
147
|
+
requestedWithoutRange: requestWithoutRange
|
|
148
|
+
});
|
|
129
149
|
if (controller) {
|
|
130
150
|
controller._internals.signal.addEventListener("abort", () => {
|
|
131
151
|
reader.reader.cancel().catch(() => {
|