@remotion/media-parser 4.0.209 → 4.0.211

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 (290) hide show
  1. package/buffer.js +2 -0
  2. package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +1 -1
  3. package/dist/boxes/iso-base-media/make-track.js +14 -2
  4. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +13 -4
  5. package/dist/boxes/iso-base-media/mdat/mdat.js +20 -5
  6. package/dist/boxes/iso-base-media/moov/moov.d.ts +2 -1
  7. package/dist/boxes/iso-base-media/moov/moov.js +2 -1
  8. package/dist/boxes/iso-base-media/process-box.d.ts +6 -3
  9. package/dist/boxes/iso-base-media/process-box.js +66 -12
  10. package/dist/boxes/iso-base-media/stsd/avcc.d.ts +1 -1
  11. package/dist/boxes/iso-base-media/stsd/avcc.js +2 -2
  12. package/dist/boxes/iso-base-media/stsd/ctts.js +2 -5
  13. package/dist/boxes/iso-base-media/stsd/hvcc.d.ts +1 -1
  14. package/dist/boxes/iso-base-media/stsd/hvcc.js +2 -2
  15. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
  16. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
  17. package/dist/boxes/iso-base-media/stsd/samples.d.ts +4 -2
  18. package/dist/boxes/iso-base-media/stsd/samples.js +69 -11
  19. package/dist/boxes/iso-base-media/stsd/stsd.d.ts +2 -1
  20. package/dist/boxes/iso-base-media/stsd/stsd.js +2 -1
  21. package/dist/boxes/iso-base-media/trak/trak.d.ts +2 -1
  22. package/dist/boxes/iso-base-media/trak/trak.js +2 -1
  23. package/dist/boxes/iso-base-media/traversal.d.ts +39 -0
  24. package/dist/boxes/iso-base-media/traversal.js +201 -0
  25. package/dist/boxes/webm/color.d.ts +4 -0
  26. package/dist/boxes/webm/color.js +127 -0
  27. package/dist/boxes/webm/description.js +1 -1
  28. package/dist/boxes/webm/ebml.d.ts +1 -1
  29. package/dist/boxes/webm/get-ready-tracks.js +3 -3
  30. package/dist/boxes/webm/get-sample-from-block.js +1 -1
  31. package/dist/boxes/webm/make-track.d.ts +9 -0
  32. package/dist/boxes/webm/make-track.js +260 -0
  33. package/dist/boxes/webm/parse-ebml.js +2 -2
  34. package/dist/boxes/webm/segments/all-segments.d.ts +36 -3
  35. package/dist/boxes/webm/segments/all-segments.js +34 -6
  36. package/dist/boxes/webm/segments/parse-children.js +6 -0
  37. package/dist/boxes/webm/traversal.d.ts +26 -1
  38. package/dist/boxes/webm/traversal.js +214 -1
  39. package/dist/buffer-iterator.d.ts +4 -1
  40. package/dist/buffer-iterator.js +31 -5
  41. package/dist/create/cluster-segment.js +0 -2
  42. package/dist/create/cluster.d.ts +16 -2
  43. package/dist/create/cluster.js +17 -10
  44. package/dist/create/create-media.d.ts +4 -2
  45. package/dist/create/create-media.js +101 -22
  46. package/dist/create/make-duration-with-padding.d.ts +1 -1
  47. package/dist/create/make-duration-with-padding.js +3 -3
  48. package/dist/create/matroska-cues.d.ts +6 -0
  49. package/dist/create/matroska-cues.js +49 -0
  50. package/dist/create/matroska-info.js +1 -1
  51. package/dist/create/matroska-seek.d.ts +6 -0
  52. package/dist/create/matroska-seek.js +32 -0
  53. package/dist/create/matroska-segment.d.ts +1 -0
  54. package/dist/create/matroska-segment.js +3 -2
  55. package/dist/create/matroska-trackentry.d.ts +9 -14
  56. package/dist/create/matroska-trackentry.js +79 -102
  57. package/dist/emit-available-info.d.ts +12 -0
  58. package/dist/emit-available-info.js +133 -0
  59. package/dist/esm/buffer.mjs +57 -0
  60. package/dist/esm/from-fetch.mjs +107 -0
  61. package/dist/esm/from-node.mjs +49 -0
  62. package/dist/esm/from-web-file.mjs +49 -0
  63. package/dist/esm/index.mjs +6822 -0
  64. package/dist/esm/web-fs.mjs +67 -0
  65. package/dist/get-audio-codec.d.ts +5 -5
  66. package/dist/get-audio-codec.js +44 -57
  67. package/dist/get-container.d.ts +4 -0
  68. package/dist/get-container.js +26 -0
  69. package/dist/get-duration.js +1 -1
  70. package/dist/get-fps.js +1 -1
  71. package/dist/get-sample-aspect-ratio.d.ts +1 -1
  72. package/dist/get-sample-aspect-ratio.js +19 -19
  73. package/dist/get-tracks.d.ts +13 -0
  74. package/dist/get-tracks.js +8 -8
  75. package/dist/get-video-codec.d.ts +5 -2
  76. package/dist/get-video-codec.js +111 -21
  77. package/dist/has-all-info.d.ts +2 -2
  78. package/dist/has-all-info.js +23 -9
  79. package/dist/index.d.ts +4 -1
  80. package/dist/options.d.ts +97 -30
  81. package/dist/parse-media.js +59 -69
  82. package/dist/parse-video.d.ts +2 -1
  83. package/dist/parse-video.js +3 -1
  84. package/dist/parser-context.d.ts +1 -0
  85. package/dist/parser-state.js +1 -2
  86. package/dist/readers/from-fetch.d.ts +12 -0
  87. package/dist/readers/from-fetch.js +83 -17
  88. package/dist/readers/from-node.js +14 -3
  89. package/dist/readers/from-web-file.js +15 -2
  90. package/dist/readers/reader.d.ts +7 -1
  91. package/dist/samples-from-moof.js +1 -1
  92. package/dist/truthy.d.ts +3 -0
  93. package/dist/truthy.js +7 -0
  94. package/dist/writers/buffer.d.ts +2 -0
  95. package/dist/writers/buffer.js +58 -0
  96. package/dist/writers/web-fs.d.ts +1 -0
  97. package/dist/writers/web-fs.js +42 -18
  98. package/dist/writers/writer.d.ts +4 -2
  99. package/fetch.js +2 -0
  100. package/node.js +2 -0
  101. package/package.json +43 -8
  102. package/web-file.js +2 -0
  103. package/web-fs.js +2 -0
  104. package/.eslintrc +0 -8
  105. package/dist/av1-codec-string.d.ts +0 -3
  106. package/dist/av1-codec-string.js +0 -91
  107. package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
  108. package/dist/boxes/iso-base-media/ftype.js +0 -31
  109. package/dist/boxes/iso-base-media/stsd/avcc-hvcc.d.ts +0 -20
  110. package/dist/boxes/iso-base-media/stsd/avcc-hvcc.js +0 -73
  111. package/dist/boxes/iso-base-media/stts/stts.d.ts +0 -15
  112. package/dist/boxes/iso-base-media/stts/stts.js +0 -35
  113. package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.d.ts +0 -14
  114. package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.js +0 -67
  115. package/dist/boxes/webm/bitstream/av1/bitstream-frame.d.ts +0 -11
  116. package/dist/boxes/webm/bitstream/av1/bitstream-frame.js +0 -14
  117. package/dist/boxes/webm/bitstream/av1/chroma-sample-position.d.ts +0 -6
  118. package/dist/boxes/webm/bitstream/av1/chroma-sample-position.js +0 -9
  119. package/dist/boxes/webm/bitstream/av1/color-config.d.ts +0 -16
  120. package/dist/boxes/webm/bitstream/av1/color-config.js +0 -103
  121. package/dist/boxes/webm/bitstream/av1/color-primaries.d.ts +0 -14
  122. package/dist/boxes/webm/bitstream/av1/color-primaries.js +0 -17
  123. package/dist/boxes/webm/bitstream/av1/decoder-model-info.d.ts +0 -9
  124. package/dist/boxes/webm/bitstream/av1/decoder-model-info.js +0 -17
  125. package/dist/boxes/webm/bitstream/av1/frame.d.ts +0 -0
  126. package/dist/boxes/webm/bitstream/av1/frame.js +0 -1
  127. package/dist/boxes/webm/bitstream/av1/header-segment.d.ts +0 -51
  128. package/dist/boxes/webm/bitstream/av1/header-segment.js +0 -183
  129. package/dist/boxes/webm/bitstream/av1/matrix-coefficients.d.ts +0 -17
  130. package/dist/boxes/webm/bitstream/av1/matrix-coefficients.js +0 -20
  131. package/dist/boxes/webm/bitstream/av1/operating-parameters-info.d.ts +0 -10
  132. package/dist/boxes/webm/bitstream/av1/operating-parameters-info.js +0 -15
  133. package/dist/boxes/webm/bitstream/av1/temporal-point-info.d.ts +0 -5
  134. package/dist/boxes/webm/bitstream/av1/temporal-point-info.js +0 -8
  135. package/dist/boxes/webm/bitstream/av1/timing-info.d.ts +0 -8
  136. package/dist/boxes/webm/bitstream/av1/timing-info.js +0 -20
  137. package/dist/boxes/webm/bitstream/av1/transfer-characteristics.d.ts +0 -21
  138. package/dist/boxes/webm/bitstream/av1/transfer-characteristics.js +0 -24
  139. package/dist/boxes/webm/bitstream/av1/uvlc.d.ts +0 -2
  140. package/dist/boxes/webm/bitstream/av1/uvlc.js +0 -20
  141. package/dist/boxes/webm/bitstream/av1.d.ts +0 -20
  142. package/dist/boxes/webm/bitstream/av1.js +0 -118
  143. package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.d.ts +0 -0
  144. package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.js +0 -1
  145. package/dist/boxes/webm/segments/duration.d.ts +0 -6
  146. package/dist/boxes/webm/segments/duration.js +0 -19
  147. package/dist/boxes/webm/segments/info.d.ts +0 -9
  148. package/dist/boxes/webm/segments/info.js +0 -22
  149. package/dist/boxes/webm/segments/main.d.ts +0 -5
  150. package/dist/boxes/webm/segments/main.js +0 -2
  151. package/dist/boxes/webm/segments/muxing.d.ts +0 -6
  152. package/dist/boxes/webm/segments/muxing.js +0 -11
  153. package/dist/boxes/webm/segments/seek-head.d.ts +0 -9
  154. package/dist/boxes/webm/segments/seek-head.js +0 -22
  155. package/dist/boxes/webm/segments/seek-position.d.ts +0 -6
  156. package/dist/boxes/webm/segments/seek-position.js +0 -11
  157. package/dist/boxes/webm/segments/seek.d.ts +0 -13
  158. package/dist/boxes/webm/segments/seek.js +0 -35
  159. package/dist/boxes/webm/segments/timestamp-scale.d.ts +0 -6
  160. package/dist/boxes/webm/segments/timestamp-scale.js +0 -11
  161. package/dist/boxes/webm/segments/tracks.d.ts +0 -8
  162. package/dist/boxes/webm/segments/tracks.js +0 -21
  163. package/dist/boxes/webm/segments/unknown.d.ts +0 -6
  164. package/dist/boxes/webm/segments/unknown.js +0 -11
  165. package/dist/boxes/webm/segments/void.d.ts +0 -6
  166. package/dist/boxes/webm/segments/void.js +0 -11
  167. package/dist/boxes/webm/segments/writing.d.ts +0 -6
  168. package/dist/boxes/webm/segments/writing.js +0 -11
  169. package/dist/boxes/webm/tracks.d.ts +0 -8
  170. package/dist/boxes/webm/tracks.js +0 -21
  171. package/dist/combine-uint8array.d.ts +0 -1
  172. package/dist/combine-uint8array.js +0 -13
  173. package/dist/from-web.d.ts +0 -2
  174. package/dist/from-web.js +0 -45
  175. package/dist/get-video-metadata.d.ts +0 -2
  176. package/dist/get-video-metadata.js +0 -44
  177. package/dist/read-and-increment-offset.d.ts +0 -28
  178. package/dist/read-and-increment-offset.js +0 -177
  179. package/dist/understand-vorbis.d.ts +0 -1
  180. package/dist/understand-vorbis.js +0 -12
  181. package/input.webm +0 -0
  182. package/src/add-new-matroska-tracks.ts +0 -23
  183. package/src/boxes/iso-base-media/base-type.ts +0 -4
  184. package/src/boxes/iso-base-media/esds/decoder-specific-config.ts +0 -68
  185. package/src/boxes/iso-base-media/esds/esds-descriptors.ts +0 -135
  186. package/src/boxes/iso-base-media/esds/esds.ts +0 -49
  187. package/src/boxes/iso-base-media/ftyp.ts +0 -39
  188. package/src/boxes/iso-base-media/get-sample-positions-from-track.ts +0 -69
  189. package/src/boxes/iso-base-media/make-track.ts +0 -116
  190. package/src/boxes/iso-base-media/mdat/mdat.ts +0 -140
  191. package/src/boxes/iso-base-media/mdhd.ts +0 -59
  192. package/src/boxes/iso-base-media/moov/moov.ts +0 -43
  193. package/src/boxes/iso-base-media/mvhd.ts +0 -114
  194. package/src/boxes/iso-base-media/process-box.ts +0 -748
  195. package/src/boxes/iso-base-media/stsd/av1c.ts +0 -19
  196. package/src/boxes/iso-base-media/stsd/avcc.ts +0 -36
  197. package/src/boxes/iso-base-media/stsd/colr.ts +0 -49
  198. package/src/boxes/iso-base-media/stsd/ctts.ts +0 -64
  199. package/src/boxes/iso-base-media/stsd/hvcc.ts +0 -32
  200. package/src/boxes/iso-base-media/stsd/keys.ts +0 -27
  201. package/src/boxes/iso-base-media/stsd/mebx.ts +0 -54
  202. package/src/boxes/iso-base-media/stsd/pasp.ts +0 -32
  203. package/src/boxes/iso-base-media/stsd/samples.ts +0 -359
  204. package/src/boxes/iso-base-media/stsd/stco.ts +0 -52
  205. package/src/boxes/iso-base-media/stsd/stsc.ts +0 -61
  206. package/src/boxes/iso-base-media/stsd/stsd.ts +0 -55
  207. package/src/boxes/iso-base-media/stsd/stss.ts +0 -47
  208. package/src/boxes/iso-base-media/stsd/stsz.ts +0 -75
  209. package/src/boxes/iso-base-media/stsd/stts.ts +0 -62
  210. package/src/boxes/iso-base-media/tfdt.ts +0 -37
  211. package/src/boxes/iso-base-media/tfhd.ts +0 -66
  212. package/src/boxes/iso-base-media/tkhd.ts +0 -150
  213. package/src/boxes/iso-base-media/to-date.ts +0 -9
  214. package/src/boxes/iso-base-media/trak/trak.ts +0 -43
  215. package/src/boxes/iso-base-media/trun.ts +0 -74
  216. package/src/boxes/iso-base-media/void-box.ts +0 -4
  217. package/src/boxes/webm/allowed-partial-segments.ts +0 -1
  218. package/src/boxes/webm/av1-codec-private.ts +0 -113
  219. package/src/boxes/webm/description.ts +0 -104
  220. package/src/boxes/webm/ebml.ts +0 -98
  221. package/src/boxes/webm/get-ready-tracks.ts +0 -36
  222. package/src/boxes/webm/get-sample-from-block.ts +0 -125
  223. package/src/boxes/webm/get-track.ts +0 -257
  224. package/src/boxes/webm/make-header.ts +0 -253
  225. package/src/boxes/webm/parse-ebml.ts +0 -259
  226. package/src/boxes/webm/parse-webm-header.ts +0 -18
  227. package/src/boxes/webm/segments/all-segments.ts +0 -888
  228. package/src/boxes/webm/segments/block-simple-block-flags.ts +0 -52
  229. package/src/boxes/webm/segments/parse-children.ts +0 -144
  230. package/src/boxes/webm/segments/track-entry.ts +0 -38
  231. package/src/boxes/webm/segments.ts +0 -147
  232. package/src/boxes/webm/traversal.ts +0 -45
  233. package/src/buffer-iterator.ts +0 -555
  234. package/src/create/cluster-segment.ts +0 -62
  235. package/src/create/cluster.ts +0 -64
  236. package/src/create/create-media.ts +0 -136
  237. package/src/create/make-duration-with-padding.ts +0 -15
  238. package/src/create/matroska-header.ts +0 -63
  239. package/src/create/matroska-info.ts +0 -30
  240. package/src/create/matroska-segment.ts +0 -10
  241. package/src/create/matroska-trackentry.ts +0 -325
  242. package/src/create/timescale.ts +0 -1
  243. package/src/get-audio-codec.ts +0 -270
  244. package/src/get-dimensions.ts +0 -47
  245. package/src/get-duration.ts +0 -103
  246. package/src/get-fps.ts +0 -113
  247. package/src/get-sample-aspect-ratio.ts +0 -204
  248. package/src/get-sample-positions.ts +0 -93
  249. package/src/get-tracks.ts +0 -147
  250. package/src/get-video-codec.ts +0 -117
  251. package/src/has-all-info.ts +0 -81
  252. package/src/index.ts +0 -18
  253. package/src/make-hvc1-codec-strings.ts +0 -55
  254. package/src/options.ts +0 -118
  255. package/src/parse-media.ts +0 -183
  256. package/src/parse-result.ts +0 -79
  257. package/src/parse-video.ts +0 -83
  258. package/src/parser-context.ts +0 -10
  259. package/src/parser-state.ts +0 -178
  260. package/src/readers/from-fetch.ts +0 -90
  261. package/src/readers/from-node.ts +0 -51
  262. package/src/readers/from-web-file.ts +0 -49
  263. package/src/readers/reader.ts +0 -15
  264. package/src/samples-from-moof.ts +0 -102
  265. package/src/test/aspect-ratio.test.ts +0 -42
  266. package/src/test/av1.test.ts +0 -108
  267. package/src/test/create-matroska.test.ts +0 -287
  268. package/src/test/duration.test.ts +0 -18
  269. package/src/test/keys.test.ts +0 -47
  270. package/src/test/matroska.test.ts +0 -463
  271. package/src/test/mvhd.test.ts +0 -94
  272. package/src/test/parse-esds.test.ts +0 -98
  273. package/src/test/parse-stco.test.ts +0 -61
  274. package/src/test/parse-stsc.test.ts +0 -104
  275. package/src/test/parse-stsz.test.ts +0 -57
  276. package/src/test/parse-stts.test.ts +0 -38
  277. package/src/test/parse-video.test.ts +0 -101
  278. package/src/test/parse-webm.test.ts +0 -17
  279. package/src/test/samples-from-moof.test.ts +0 -2496
  280. package/src/test/stream-local.test.ts +0 -743
  281. package/src/test/stream-remote.test.ts +0 -59
  282. package/src/test/stream-samples.test.ts +0 -181
  283. package/src/test/stsd.test.ts +0 -265
  284. package/src/test/tkhd.test.ts +0 -87
  285. package/src/traversal.ts +0 -528
  286. package/src/webcodec-sample-types.ts +0 -29
  287. package/src/writers/web-fs.ts +0 -50
  288. package/src/writers/writer.ts +0 -12
  289. package/tsconfig.json +0 -14
  290. package/tsconfig.tsbuildinfo +0 -1
@@ -1,17 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasAllInfo = void 0;
3
+ exports.getAvailableInfo = void 0;
4
4
  const get_audio_codec_1 = require("./get-audio-codec");
5
+ const get_container_1 = require("./get-container");
5
6
  const get_dimensions_1 = require("./get-dimensions");
6
7
  const get_duration_1 = require("./get-duration");
7
8
  const get_fps_1 = require("./get-fps");
8
9
  const get_tracks_1 = require("./get-tracks");
9
10
  const get_video_codec_1 = require("./get-video-codec");
10
- const hasAllInfo = (options, parseResult, state) => {
11
- const keys = Object.entries(options)
12
- .filter(([, value]) => value)
13
- .map(([key]) => key);
14
- return keys.every((key) => {
11
+ const getAvailableInfo = (options, parseResult, state) => {
12
+ const keys = Object.entries(options).filter(([, value]) => value);
13
+ const infos = keys.map(([key]) => {
15
14
  if (key === 'boxes') {
16
15
  return parseResult.status === 'done';
17
16
  }
@@ -24,13 +23,13 @@ const hasAllInfo = (options, parseResult, state) => {
24
23
  return (0, get_dimensions_1.hasDimensions)(parseResult.segments, state);
25
24
  }
26
25
  if (key === 'fps') {
27
- return (0, get_fps_1.hasFps)(parseResult.segments) !== null;
26
+ return (0, get_fps_1.hasFps)(parseResult.segments);
28
27
  }
29
28
  if (key === 'videoCodec') {
30
29
  return (0, get_video_codec_1.hasVideoCodec)(parseResult.segments);
31
30
  }
32
31
  if (key === 'audioCodec') {
33
- return (0, get_audio_codec_1.hasAudioCodec)(parseResult.segments);
32
+ return (0, get_audio_codec_1.hasAudioCodec)(parseResult.segments, state);
34
33
  }
35
34
  if (key === 'tracks') {
36
35
  return (0, get_tracks_1.hasTracks)(parseResult.segments);
@@ -38,7 +37,22 @@ const hasAllInfo = (options, parseResult, state) => {
38
37
  if (key === 'internalStats') {
39
38
  return false;
40
39
  }
40
+ if (key === 'size') {
41
+ return true;
42
+ }
43
+ if (key === 'name') {
44
+ return true;
45
+ }
46
+ if (key === 'container') {
47
+ return (0, get_container_1.hasContainer)(parseResult.segments);
48
+ }
41
49
  throw new Error(`Unknown key: ${key}`);
42
50
  });
51
+ const entries = [];
52
+ let i = 0;
53
+ for (const [key] of keys) {
54
+ entries.push([key, infos[i++]]);
55
+ }
56
+ return Object.fromEntries(entries);
43
57
  };
44
- exports.hasAllInfo = hasAllInfo;
58
+ exports.getAvailableInfo = getAvailableInfo;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- export { AudioTrack, OtherTrack, Track, VideoTrack } from './get-tracks';
1
+ export { AudioTrack, MediaParserAudioCodec, MediaParserVideoCodec, OtherTrack, Track, VideoTrack, VideoTrackColorParams, } from './get-tracks';
2
+ export type { Options, ParseMediaContainer, ParseMediaFields, ParseMediaResult, TracksField, } from './options';
2
3
  export { parseMedia } from './parse-media';
3
4
  export { AudioSample, OnAudioSample, OnAudioTrack, OnVideoSample, OnVideoTrack, VideoSample, } from './webcodec-sample-types';
4
5
  export type { MediaFn } from './create/create-media';
6
+ export { Dimensions } from './get-dimensions';
7
+ export type { ReaderInterface } from './readers/reader';
5
8
  export declare const MediaParserInternals: {
6
9
  createMedia: (writer: import("./writers/writer").WriterInterface) => Promise<import("./create/create-media").MediaFn>;
7
10
  };
package/dist/options.d.ts CHANGED
@@ -1,50 +1,117 @@
1
1
  import type { Dimensions } from './get-dimensions';
2
- import type { AudioTrack, VideoTrack } from './get-tracks';
2
+ import type { AudioTrack, MediaParserAudioCodec, MediaParserVideoCodec, VideoTrack } from './get-tracks';
3
3
  import type { AnySegment } from './parse-result';
4
4
  import type { InternalStats } from './parser-state';
5
5
  import type { ReaderInterface } from './readers/reader';
6
6
  import type { OnAudioTrack, OnVideoTrack } from './webcodec-sample-types';
7
- export type KnownVideoCodecs = 'h264' | 'h265' | 'vp8' | 'vp9' | 'av1' | 'prores';
8
7
  export type KnownAudioCodecs = 'aac' | 'mp3' | 'aiff' | 'opus' | 'pcm' | 'vorbis' | 'unknown';
9
- export type Options<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean, EnableTracks extends boolean, EnableRotation extends boolean, EnableUnrotatedDimensions extends boolean, EnableInternalStats extends boolean> = {
10
- dimensions?: EnableDimensions;
11
- durationInSeconds?: EnableDuration;
12
- boxes?: EnableBoxes;
13
- fps?: EnableFps;
14
- videoCodec?: EnableVideoCodec;
15
- audioCodec?: EnableAudioCodec;
16
- tracks?: EnableTracks;
17
- rotation?: EnableRotation;
18
- unrotatedDimensions?: EnableUnrotatedDimensions;
19
- internalStats?: EnableInternalStats;
8
+ export type ParseMediaFields = {
9
+ dimensions: boolean;
10
+ durationInSeconds: boolean;
11
+ boxes: boolean;
12
+ fps: boolean;
13
+ videoCodec: boolean;
14
+ audioCodec: boolean;
15
+ tracks: boolean;
16
+ rotation: boolean;
17
+ unrotatedDimensions: boolean;
18
+ internalStats: boolean;
19
+ size: boolean;
20
+ name: boolean;
21
+ container: boolean;
20
22
  };
21
- export type Metadata<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean, EnableTracks extends boolean, EnableRotation extends boolean, EnableUnrotatedDimensions extends boolean, EnableInternalStats extends boolean> = (EnableDimensions extends true ? {
23
+ export type AllParseMediaFields = {
24
+ dimensions: true;
25
+ durationInSeconds: true;
26
+ boxes: true;
27
+ fps: true;
28
+ videoCodec: true;
29
+ audioCodec: true;
30
+ tracks: true;
31
+ rotation: true;
32
+ unrotatedDimensions: true;
33
+ internalStats: true;
34
+ size: true;
35
+ name: true;
36
+ container: true;
37
+ };
38
+ export type Options<Fields extends ParseMediaFields> = {
39
+ dimensions?: Fields['dimensions'];
40
+ durationInSeconds?: Fields['durationInSeconds'];
41
+ boxes?: Fields['boxes'];
42
+ fps?: Fields['fps'];
43
+ videoCodec?: Fields['videoCodec'];
44
+ audioCodec?: Fields['audioCodec'];
45
+ tracks?: Fields['tracks'];
46
+ rotation?: Fields['rotation'];
47
+ unrotatedDimensions?: Fields['unrotatedDimensions'];
48
+ internalStats?: Fields['internalStats'];
49
+ size?: Fields['size'];
50
+ name?: Fields['name'];
51
+ container?: Fields['container'];
52
+ };
53
+ export type TracksField = {
54
+ videoTracks: VideoTrack[];
55
+ audioTracks: AudioTrack[];
56
+ };
57
+ export type ParseMediaContainer = 'mp4' | 'webm';
58
+ export type ParseMediaCallbacks<Fields extends Options<ParseMediaFields>> = (Fields['dimensions'] extends true ? {
59
+ onDimensions?: (dimensions: Dimensions) => void;
60
+ } : {}) & (Fields['durationInSeconds'] extends true ? {
61
+ onDurationInSeconds?: (durationInSeconds: number | null) => void;
62
+ } : {}) & (Fields['boxes'] extends true ? {
63
+ onBoxes?: (boxes: AnySegment[]) => void;
64
+ } : {}) & (Fields['fps'] extends true ? {
65
+ onFps?: (fps: number | null) => void;
66
+ } : {}) & (Fields['videoCodec'] extends true ? {
67
+ onVideoCodec?: (codec: MediaParserVideoCodec | null) => void;
68
+ } : {}) & (Fields['audioCodec'] extends true ? {
69
+ onAudioCodec?: (codec: MediaParserAudioCodec | null) => void;
70
+ } : {}) & (Fields['tracks'] extends true ? {
71
+ onTracks?: (tracks: TracksField) => void;
72
+ } : {}) & (Fields['rotation'] extends true ? {
73
+ onRotation?: (rotation: number | null) => void;
74
+ } : {}) & (Fields['unrotatedDimensions'] extends true ? {
75
+ onUnrotatedDimensions?: (dimensions: Dimensions) => void;
76
+ } : {}) & (Fields['internalStats'] extends true ? {
77
+ onInternalStats?: (stats: InternalStats) => void;
78
+ } : {}) & (Fields['size'] extends true ? {
79
+ onSize?: (size: number | null) => void;
80
+ } : {}) & (Fields['name'] extends true ? {
81
+ onName?: (name: string) => void;
82
+ } : {}) & (Fields['container'] extends true ? {
83
+ onContainer?: (container: ParseMediaContainer | null) => void;
84
+ } : {});
85
+ export type ParseMediaResult<Fields extends Options<ParseMediaFields>> = (Fields['dimensions'] extends true ? {
22
86
  dimensions: Dimensions;
23
- } : {}) & (EnableDuration extends true ? {
87
+ } : {}) & (Fields['durationInSeconds'] extends true ? {
24
88
  durationInSeconds: number | null;
25
- } : {}) & (EnableBoxes extends true ? {
89
+ } : {}) & (Fields['boxes'] extends true ? {
26
90
  boxes: AnySegment[];
27
- } : {}) & (EnableFps extends true ? {
91
+ } : {}) & (Fields['fps'] extends true ? {
28
92
  fps: number | null;
29
- } : {}) & (EnableVideoCodec extends true ? {
30
- videoCodec: KnownVideoCodecs | null;
31
- } : {}) & (EnableAudioCodec extends true ? {
32
- audioCodec: KnownAudioCodecs | null;
33
- } : {}) & (EnableTracks extends true ? {
34
- videoTracks: VideoTrack[];
35
- audioTracks: AudioTrack[];
36
- } : {}) & (EnableRotation extends true ? {
93
+ } : {}) & (Fields['videoCodec'] extends true ? {
94
+ videoCodec: MediaParserVideoCodec | null;
95
+ } : {}) & (Fields['audioCodec'] extends true ? {
96
+ audioCodec: MediaParserAudioCodec | null;
97
+ } : {}) & (Fields['tracks'] extends true ? TracksField : {}) & (Fields['rotation'] extends true ? {
37
98
  rotation: number | null;
38
- } : {}) & (EnableUnrotatedDimensions extends true ? {
99
+ } : {}) & (Fields['unrotatedDimensions'] extends true ? {
39
100
  unrotatedDimensions: Dimensions;
40
- } : {}) & (EnableInternalStats extends true ? {
101
+ } : {}) & (Fields['internalStats'] extends true ? {
41
102
  internalStats: InternalStats;
103
+ } : {}) & (Fields['size'] extends true ? {
104
+ size: number | null;
105
+ } : {}) & (Fields['name'] extends true ? {
106
+ name: string;
107
+ } : {}) & (Fields['container'] extends true ? {
108
+ container: ParseMediaContainer | null;
42
109
  } : {});
43
- export type ParseMedia = <EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean, EnableTracks extends boolean, EnableRotation extends boolean, EnableUnrotatedDimensions extends boolean, EnableInternalStats extends boolean>(options: {
110
+ export type ParseMedia = <F extends Options<ParseMediaFields>>(options: {
44
111
  src: string | File;
45
- fields?: Options<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec, EnableAudioCodec, EnableTracks, EnableRotation, EnableUnrotatedDimensions, EnableInternalStats>;
112
+ fields?: F;
46
113
  reader?: ReaderInterface;
47
114
  onAudioTrack?: OnAudioTrack;
48
115
  onVideoTrack?: OnVideoTrack;
49
116
  signal?: AbortSignal;
50
- }) => Promise<Metadata<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec, EnableAudioCodec, EnableTracks, EnableRotation, EnableUnrotatedDimensions, EnableInternalStats>>;
117
+ } & ParseMediaCallbacks<F>) => Promise<ParseMediaResult<F>>;
@@ -2,25 +2,25 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMedia = void 0;
4
4
  const buffer_iterator_1 = require("./buffer-iterator");
5
- const get_audio_codec_1 = require("./get-audio-codec");
6
- const get_dimensions_1 = require("./get-dimensions");
7
- const get_duration_1 = require("./get-duration");
8
- const get_fps_1 = require("./get-fps");
9
- const get_tracks_1 = require("./get-tracks");
10
- const get_video_codec_1 = require("./get-video-codec");
5
+ const emit_available_info_1 = require("./emit-available-info");
11
6
  const has_all_info_1 = require("./has-all-info");
12
7
  const parse_video_1 = require("./parse-video");
13
8
  const parser_state_1 = require("./parser-state");
14
9
  const from_fetch_1 = require("./readers/from-fetch");
15
- const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, signal, }) => {
10
+ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, signal, ...more }) => {
16
11
  const state = (0, parser_state_1.makeParserState)({
17
12
  hasAudioCallbacks: onAudioTrack !== null,
18
13
  hasVideoCallbacks: onVideoTrack !== null,
19
14
  signal,
20
15
  });
21
- const { reader, contentLength } = await readerInterface.read(src, null, signal);
16
+ const { reader, contentLength, name, supportsContentRange: readerSupportsContentRange, } = await readerInterface.read(src, null, signal);
22
17
  let currentReader = reader;
18
+ const supportsContentRange = readerSupportsContentRange &&
19
+ !(typeof process !== 'undefined' &&
20
+ typeof process.env !== 'undefined' &&
21
+ process.env.DISABLE_CONTENT_RANGE === 'true');
23
22
  const returnValue = {};
23
+ const moreFields = more;
24
24
  let iterator = null;
25
25
  let parseResult = null;
26
26
  const options = {
@@ -31,22 +31,35 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
31
31
  nullifySamples: !(typeof process !== 'undefined' &&
32
32
  typeof process.env !== 'undefined' &&
33
33
  process.env.KEEP_SAMPLES === 'true'),
34
+ supportsContentRange,
34
35
  };
35
36
  while (parseResult === null || parseResult.status === 'incomplete') {
36
37
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
37
38
  throw new Error('Aborted');
38
39
  }
39
- const result = await currentReader.read();
40
- if (iterator) {
41
- if (!result.done) {
42
- iterator.addData(result.value);
40
+ // eslint-disable-next-line no-constant-condition
41
+ while (true) {
42
+ const result = await currentReader.reader.read();
43
+ if (iterator) {
44
+ if (!result.done) {
45
+ iterator.addData(result.value);
46
+ }
47
+ }
48
+ else {
49
+ if (result.done) {
50
+ throw new Error('Unexpectedly reached EOF');
51
+ }
52
+ iterator = (0, buffer_iterator_1.getArrayBufferIterator)(result.value, contentLength !== null && contentLength !== void 0 ? contentLength : 1000000000);
53
+ }
54
+ if (iterator.bytesRemaining() >= 0) {
55
+ break;
43
56
  }
44
- }
45
- else {
46
57
  if (result.done) {
47
- throw new Error('Unexpectedly reached EOF');
58
+ break;
48
59
  }
49
- iterator = (0, buffer_iterator_1.getArrayBufferIterator)(result.value, contentLength !== null && contentLength !== void 0 ? contentLength : 1000000000);
60
+ }
61
+ if (!iterator) {
62
+ throw new Error('Unexpected null');
50
63
  }
51
64
  if (parseResult && parseResult.status === 'incomplete') {
52
65
  parseResult = await parseResult.continueParsing();
@@ -55,73 +68,50 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
55
68
  parseResult = await (0, parse_video_1.parseVideo)({
56
69
  iterator,
57
70
  options,
71
+ signal: signal !== null && signal !== void 0 ? signal : null,
58
72
  });
59
73
  }
74
+ const availableInfo = (0, has_all_info_1.getAvailableInfo)(fields !== null && fields !== void 0 ? fields : {}, parseResult, state);
75
+ const hasAllInfo = Object.values(availableInfo).every(Boolean);
76
+ (0, emit_available_info_1.emitAvailableInfo)({
77
+ hasInfo: availableInfo,
78
+ moreFields,
79
+ parseResult,
80
+ state,
81
+ returnValue,
82
+ contentLength,
83
+ name,
84
+ });
60
85
  // TODO Better: Check if no active listeners are registered
61
86
  // Also maybe check for canSkipVideoData
62
- if ((0, has_all_info_1.hasAllInfo)(fields !== null && fields !== void 0 ? fields : {}, parseResult, state) &&
63
- !onVideoTrack &&
64
- !onAudioTrack) {
65
- if (!currentReader.closed) {
66
- currentReader.cancel(new Error('has all information'));
67
- }
87
+ if (hasAllInfo && !onVideoTrack && !onAudioTrack) {
68
88
  break;
69
89
  }
70
90
  if (parseResult &&
71
91
  parseResult.status === 'incomplete' &&
72
92
  parseResult.skipTo !== null) {
73
- if (!currentReader.closed) {
74
- currentReader.cancel(new Error('skipped ahead'));
93
+ if (!supportsContentRange) {
94
+ throw new Error('Content-Range header is not supported by the reader, but was asked to seek');
75
95
  }
76
96
  const { reader: newReader } = await readerInterface.read(src, parseResult.skipTo, signal);
77
97
  currentReader = newReader;
78
- iterator.skipTo(parseResult.skipTo);
98
+ iterator.skipTo(parseResult.skipTo, true);
79
99
  }
80
100
  }
81
- if (!parseResult) {
82
- throw new Error('Could not parse video');
83
- }
84
- if (fields === null || fields === void 0 ? void 0 : fields.dimensions) {
85
- const dimensions = (0, get_dimensions_1.getDimensions)(parseResult.segments, state);
86
- returnValue.dimensions = {
87
- width: dimensions.width,
88
- height: dimensions.height,
89
- };
90
- }
91
- if (fields === null || fields === void 0 ? void 0 : fields.unrotatedDimensions) {
92
- const dimensions = (0, get_dimensions_1.getDimensions)(parseResult.segments, state);
93
- returnValue.unrotatedDimensions = {
94
- width: dimensions.unrotatedWidth,
95
- height: dimensions.unrotatedHeight,
96
- };
97
- }
98
- if (fields === null || fields === void 0 ? void 0 : fields.rotation) {
99
- const dimensions = (0, get_dimensions_1.getDimensions)(parseResult.segments, state);
100
- returnValue.rotation = dimensions.rotation;
101
- }
102
- if (fields === null || fields === void 0 ? void 0 : fields.durationInSeconds) {
103
- returnValue.durationInSeconds = (0, get_duration_1.getDuration)(parseResult.segments, state);
104
- }
105
- if (fields === null || fields === void 0 ? void 0 : fields.fps) {
106
- returnValue.fps = (0, get_fps_1.getFps)(parseResult.segments);
107
- }
108
- if (fields === null || fields === void 0 ? void 0 : fields.videoCodec) {
109
- returnValue.videoCodec = (0, get_video_codec_1.getVideoCodec)(parseResult.segments);
110
- }
111
- if (fields === null || fields === void 0 ? void 0 : fields.audioCodec) {
112
- returnValue.audioCodec = (0, get_audio_codec_1.getAudioCodec)(parseResult.segments);
113
- }
114
- if (fields === null || fields === void 0 ? void 0 : fields.tracks) {
115
- const { audioTracks, videoTracks } = (0, get_tracks_1.getTracks)(parseResult.segments, state);
116
- returnValue.audioTracks = audioTracks;
117
- returnValue.videoTracks = videoTracks;
118
- }
119
- if (fields === null || fields === void 0 ? void 0 : fields.boxes) {
120
- returnValue.boxes = parseResult.segments;
121
- }
122
- if (fields === null || fields === void 0 ? void 0 : fields.internalStats) {
123
- returnValue.internalStats = state.getInternalStats();
124
- }
101
+ // Force assign
102
+ (0, emit_available_info_1.emitAvailableInfo)({
103
+ hasInfo: Object.keys(fields !== null && fields !== void 0 ? fields : {}).reduce((acc, key) => {
104
+ acc[key] = true;
105
+ return acc;
106
+ }, {}),
107
+ moreFields,
108
+ parseResult,
109
+ state,
110
+ returnValue,
111
+ contentLength,
112
+ name,
113
+ });
114
+ currentReader.abort();
125
115
  iterator === null || iterator === void 0 ? void 0 : iterator.destroy();
126
116
  return returnValue;
127
117
  };
@@ -14,7 +14,8 @@ export type BoxAndNext = {
14
14
  } | {
15
15
  type: 'incomplete';
16
16
  } | PartialMdatBox;
17
- export declare const parseVideo: ({ iterator, options, }: {
17
+ export declare const parseVideo: ({ iterator, options, signal, }: {
18
18
  iterator: BufferIterator;
19
19
  options: ParserContext;
20
+ signal: AbortSignal | null;
20
21
  }) => Promise<ParseResult>;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseVideo = void 0;
4
4
  const process_box_1 = require("./boxes/iso-base-media/process-box");
5
5
  const parse_webm_header_1 = require("./boxes/webm/parse-webm-header");
6
- const parseVideo = ({ iterator, options, }) => {
6
+ const parseVideo = ({ iterator, options, signal, }) => {
7
7
  if (iterator.bytesRemaining() === 0) {
8
8
  return Promise.resolve({
9
9
  status: 'incomplete',
@@ -12,6 +12,7 @@ const parseVideo = ({ iterator, options, }) => {
12
12
  return (0, exports.parseVideo)({
13
13
  iterator,
14
14
  options,
15
+ signal,
15
16
  });
16
17
  },
17
18
  skipTo: null,
@@ -41,6 +42,7 @@ const parseVideo = ({ iterator, options, }) => {
41
42
  options,
42
43
  continueMdat: false,
43
44
  littleEndian: false,
45
+ signal,
44
46
  });
45
47
  }
46
48
  if (iterator.isWebm()) {
@@ -6,4 +6,5 @@ export type ParserContext = {
6
6
  canSkipVideoData: boolean;
7
7
  parserState: ParserState;
8
8
  nullifySamples: boolean;
9
+ supportsContentRange: boolean;
9
10
  };
@@ -2,12 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeParserState = void 0;
4
4
  const traversal_1 = require("./boxes/webm/traversal");
5
- const traversal_2 = require("./traversal");
6
5
  const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, signal, }) => {
7
6
  const trackEntries = {};
8
7
  const onTrackEntrySegment = (trackEntry) => {
9
8
  var _a;
10
- const trackId = (0, traversal_2.getTrackId)(trackEntry);
9
+ const trackId = (0, traversal_1.getTrackId)(trackEntry);
11
10
  if (!trackId) {
12
11
  throw new Error('Expected track id');
13
12
  }
@@ -1,2 +1,14 @@
1
1
  import type { ReaderInterface } from './reader';
2
+ interface ParsedContentRange {
3
+ unit: string;
4
+ start?: number | null;
5
+ end?: number | null;
6
+ size?: number | null;
7
+ }
8
+ /**
9
+ * Parse Content-Range header.
10
+ * From: https://github.com/gregberge/content-range/blob/main/src/index.ts
11
+ */
12
+ export declare function parseContentRange(input: string): ParsedContentRange | null;
2
13
  export declare const fetchReader: ReaderInterface;
14
+ export {};
@@ -1,8 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchReader = void 0;
3
+ exports.fetchReader = exports.parseContentRange = void 0;
4
+ /**
5
+ * Parse Content-Range header.
6
+ * From: https://github.com/gregberge/content-range/blob/main/src/index.ts
7
+ */
8
+ function parseContentRange(input) {
9
+ const matches = input.match(/^(\w+) ((\d+)-(\d+)|\*)\/(\d+|\*)$/);
10
+ if (!matches)
11
+ return null;
12
+ const [, unit, , start, end, size] = matches;
13
+ const range = {
14
+ unit,
15
+ start: start != null ? Number(start) : null,
16
+ end: end != null ? Number(end) : null,
17
+ size: size === '*' ? null : Number(size),
18
+ };
19
+ if (range.start === null && range.end === null && range.size === null) {
20
+ return null;
21
+ }
22
+ return range;
23
+ }
24
+ exports.parseContentRange = parseContentRange;
25
+ const validateContentRangeAndDetectIfSupported = (actualRange, parsedContentRange) => {
26
+ if (typeof actualRange === 'number' &&
27
+ (parsedContentRange === null || parsedContentRange === void 0 ? void 0 : parsedContentRange.start) !== actualRange) {
28
+ if (actualRange === 0) {
29
+ return { supportsContentRange: false };
30
+ }
31
+ throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange === null || parsedContentRange === void 0 ? void 0 : parsedContentRange.start})`);
32
+ }
33
+ if (actualRange !== null &&
34
+ typeof actualRange !== 'number' &&
35
+ ((parsedContentRange === null || parsedContentRange === void 0 ? void 0 : parsedContentRange.start) !== actualRange[0] ||
36
+ (parsedContentRange === null || parsedContentRange === void 0 ? void 0 : parsedContentRange.end) !== actualRange[1])) {
37
+ throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange === null || parsedContentRange === void 0 ? void 0 : parsedContentRange.start})`);
38
+ }
39
+ return { supportsContentRange: true };
40
+ };
4
41
  exports.fetchReader = {
5
42
  read: async (src, range, signal) => {
43
+ var _a;
6
44
  if (typeof src !== 'string') {
7
45
  throw new Error('src must be a string when using `fetchReader`');
8
46
  }
@@ -10,40 +48,68 @@ exports.fetchReader = {
10
48
  ? new URL(src, window.location.origin).toString()
11
49
  : src;
12
50
  if (!resolvedUrl.startsWith('https://') &&
51
+ !resolvedUrl.startsWith('blob:') &&
13
52
  !resolvedUrl.startsWith('http://')) {
14
53
  return Promise.reject(new Error(resolvedUrl +
15
- ' is not a URL - needs to start with http:// or https://. If you want to read a local file, pass `reader: nodeReader` to parseMedia().'));
54
+ ' 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().'));
16
55
  }
56
+ const controller = new AbortController();
57
+ const cache = typeof navigator !== 'undefined' &&
58
+ navigator.userAgent.includes('Cloudflare-Workers')
59
+ ? undefined
60
+ : // Disable Next.js caching
61
+ 'no-store';
62
+ const actualRange = range === null ? 0 : range;
17
63
  const res = await fetch(resolvedUrl, {
18
- headers: range === null
19
- ? {}
20
- : typeof range === 'number'
21
- ? {
22
- Range: `bytes=${range}`,
23
- }
24
- : {
25
- Range: `bytes=${`${range[0]}-${range[1]}`}`,
26
- },
27
- signal,
28
- // Disable Next.js caching
29
- cache: 'no-store',
64
+ headers: typeof actualRange === 'number'
65
+ ? {
66
+ Range: `bytes=${actualRange}-`,
67
+ }
68
+ : {
69
+ Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`,
70
+ },
71
+ signal: controller.signal,
72
+ cache,
30
73
  });
74
+ const contentRange = res.headers.get('content-range');
75
+ const parsedContentRange = contentRange
76
+ ? parseContentRange(contentRange)
77
+ : null;
78
+ const { supportsContentRange } = validateContentRangeAndDetectIfSupported(actualRange, parsedContentRange);
79
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', () => {
80
+ controller.abort();
81
+ }, { once: true });
31
82
  if (res.status.toString().startsWith('4') ||
32
83
  res.status.toString().startsWith('5')) {
33
- throw new Error(`Server returned status code ${res.status} for ${src}`);
84
+ throw new Error(`Server returned status code ${res.status} for ${src} and range ${actualRange}`);
34
85
  }
35
86
  if (!res.body) {
36
87
  throw new Error('No body');
37
88
  }
38
89
  const length = res.headers.get('content-length');
39
90
  const contentLength = length === null ? null : parseInt(length, 10);
91
+ const contentDisposition = res.headers.get('content-disposition');
92
+ const name = (_a = contentDisposition === null || contentDisposition === void 0 ? void 0 : contentDisposition.match(/filename="([^"]+)"/)) === null || _a === void 0 ? void 0 : _a[1];
93
+ const fallbackName = src.split('/').pop();
40
94
  const reader = res.body.getReader();
41
95
  if (signal) {
42
96
  signal.addEventListener('abort', () => {
43
- reader.cancel();
97
+ reader.cancel().catch(() => {
98
+ // Prevent unhandled rejection in Firefox
99
+ });
44
100
  }, { once: true });
45
101
  }
46
- return { reader, contentLength };
102
+ return {
103
+ reader: {
104
+ reader,
105
+ abort: () => {
106
+ controller.abort();
107
+ },
108
+ },
109
+ contentLength,
110
+ name: name !== null && name !== void 0 ? name : fallbackName,
111
+ supportsContentRange,
112
+ };
47
113
  },
48
114
  getLength: async (src) => {
49
115
  if (typeof src !== 'string') {
@@ -9,6 +9,7 @@ exports.nodeReader = {
9
9
  if (typeof src !== 'string') {
10
10
  throw new Error('src must be a string when using `nodeReader`');
11
11
  }
12
+ const controller = new AbortController();
12
13
  const stream = (0, fs_1.createReadStream)(src, {
13
14
  start: range === null ? 0 : typeof range === 'number' ? range : range[0],
14
15
  end: range === null
@@ -16,18 +17,28 @@ exports.nodeReader = {
16
17
  : typeof range === 'number'
17
18
  ? Infinity
18
19
  : range[1],
19
- signal,
20
+ signal: controller.signal,
20
21
  });
22
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', () => {
23
+ controller.abort();
24
+ }, { once: true });
21
25
  const stats = await (0, promises_1.stat)(src);
22
26
  const reader = stream_1.Readable.toWeb(stream).getReader();
23
27
  if (signal) {
24
28
  signal.addEventListener('abort', () => {
25
- reader.cancel();
29
+ reader.cancel().catch(() => { });
26
30
  }, { once: true });
27
31
  }
28
32
  return {
29
- reader,
33
+ reader: {
34
+ reader,
35
+ abort: () => {
36
+ controller.abort();
37
+ },
38
+ },
30
39
  contentLength: stats.size,
40
+ name: src.split('/').pop(),
41
+ supportsContentRange: true,
31
42
  };
32
43
  },
33
44
  getLength: async (src) => {