@remotion/studio 4.0.466 → 4.0.468

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 (31) hide show
  1. package/dist/components/CurrentAsset.js +8 -54
  2. package/dist/components/NewComposition/ValidationMessage.d.ts +1 -0
  3. package/dist/components/NewComposition/ValidationMessage.js +3 -3
  4. package/dist/components/RenderModal/DataEditor.js +8 -2
  5. package/dist/components/RenderModal/get-render-modal-warnings.d.ts +7 -1
  6. package/dist/components/RenderModal/get-render-modal-warnings.js +21 -7
  7. package/dist/components/Timeline/TimelineExpandedSection.js +9 -2
  8. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.d.ts +1 -0
  9. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +12 -5
  10. package/dist/components/Timeline/TimelineListItem.js +21 -3
  11. package/dist/components/Timeline/TimelineMediaInfo.d.ts +5 -0
  12. package/dist/components/Timeline/TimelineMediaInfo.js +173 -0
  13. package/dist/components/Timeline/TimelineTracks.js +1 -1
  14. package/dist/components/Timeline/TimelineVideoInfo.js +2 -2
  15. package/dist/components/Timeline/get-timeline-keyframes.d.ts +1 -1
  16. package/dist/components/Timeline/get-timeline-keyframes.js +9 -2
  17. package/dist/esm/{chunk-sa3dm85y.js → chunk-8q828zk7.js} +2461 -2130
  18. package/dist/esm/internals.mjs +2461 -2130
  19. package/dist/esm/previewEntry.mjs +2469 -2138
  20. package/dist/esm/renderEntry.mjs +1 -1
  21. package/dist/helpers/calculate-timeline.js +4 -0
  22. package/dist/helpers/format-media-duration.d.ts +1 -0
  23. package/dist/helpers/format-media-duration.js +14 -0
  24. package/dist/helpers/get-timeline-sequence-layout.js +4 -3
  25. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +1 -0
  26. package/dist/helpers/timeline-layout.d.ts +10 -6
  27. package/dist/helpers/timeline-layout.js +22 -7
  28. package/dist/helpers/use-max-media-duration.js +25 -28
  29. package/dist/helpers/use-media-metadata.d.ts +10 -0
  30. package/dist/helpers/use-media-metadata.js +135 -0
  31. package/package.json +10 -10
@@ -207,7 +207,7 @@ var renderContent = (Root) => {
207
207
  renderToDOM(/* @__PURE__ */ jsx("div", {
208
208
  children: /* @__PURE__ */ jsx(DelayedSpinner, {})
209
209
  }));
210
- import("./chunk-sa3dm85y.js").then(({ StudioInternals }) => {
210
+ import("./chunk-8q828zk7.js").then(({ StudioInternals }) => {
211
211
  window.remotion_isStudio = true;
212
212
  window.remotion_isReadOnlyStudio = true;
213
213
  window.remotion_inputProps = "{}";
@@ -46,6 +46,7 @@ const calculateTimeline = ({ sequences, overrideIdsToNodePaths, }) => {
46
46
  const visibleDuration = (0, get_sequence_visible_range_1.getTimelineVisibleDuration)(sequence, sortedSequences);
47
47
  const overrideId = (_b = (_a = sequence.controls) === null || _a === void 0 ? void 0 : _a.overrideId) !== null && _b !== void 0 ? _b : null;
48
48
  const nodePath = overrideId ? overrideIdsToNodePaths[overrideId] : null;
49
+ const hasKeyframeRows = sequence.controls !== null || sequence.effects.length > 0;
49
50
  tracks.push({
50
51
  sequence: {
51
52
  ...sequence,
@@ -59,6 +60,9 @@ const calculateTimeline = ({ sequences, overrideIdsToNodePaths, }) => {
59
60
  hash: actualHash,
60
61
  cascadedStart,
61
62
  cascadedDuration: sequence.duration,
63
+ keyframeDisplayOffset: hasKeyframeRows
64
+ ? cascadedStart - sequence.from
65
+ : 0,
62
66
  nodePathInfo: nodePath
63
67
  ? {
64
68
  sequenceSubscriptionKey: nodePath,
@@ -0,0 +1 @@
1
+ export declare const formatMediaDuration: (seconds: number) => string;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatMediaDuration = void 0;
4
+ const formatMediaDuration = (seconds) => {
5
+ const h = Math.floor(seconds / 3600);
6
+ const m = Math.floor((seconds % 3600) / 60);
7
+ const s = seconds % 60;
8
+ const sFixed = s.toFixed(2).padStart(5, '0');
9
+ if (h > 0) {
10
+ return `${h}:${String(m).padStart(2, '0')}:${sFixed}`;
11
+ }
12
+ return `${String(m).padStart(2, '0')}:${sFixed}`;
13
+ };
14
+ exports.formatMediaDuration = formatMediaDuration;
@@ -13,10 +13,11 @@ const getWidthOfTrack = ({ durationInFrames, lastFrame, windowWidth, spatialDura
13
13
  const getTimelineSequenceLayout = ({ durationInFrames, startFrom, maxMediaDuration, startFromMedia, video, windowWidth, premountDisplay, postmountDisplay, }) => {
14
14
  var _a;
15
15
  const maxMediaSequenceDuration = (maxMediaDuration !== null && maxMediaDuration !== void 0 ? maxMediaDuration : Infinity) - startFromMedia;
16
- const lastFrame = ((_a = video.durationInFrames) !== null && _a !== void 0 ? _a : 1) - 1;
17
- const spatialDuration = Math.max(0, Math.min(maxMediaSequenceDuration, durationInFrames - 1, lastFrame - startFrom));
16
+ const timelineDuration = (_a = video.durationInFrames) !== null && _a !== void 0 ? _a : 1;
17
+ const lastFrame = timelineDuration - 1;
18
+ const spatialDuration = Math.max(0, Math.min(maxMediaSequenceDuration, durationInFrames, timelineDuration - startFrom));
18
19
  // Unclipped spatial duration: without the lastFrame - startFrom constraint
19
- const naturalSpatialDuration = Math.max(0, Math.min(maxMediaSequenceDuration, durationInFrames - 1));
20
+ const naturalSpatialDuration = Math.max(0, Math.min(maxMediaSequenceDuration, durationInFrames));
20
21
  const marginLeft = lastFrame === 0
21
22
  ? 0
22
23
  : (startFrom / lastFrame) * (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2);
@@ -9,6 +9,7 @@ type Track = {
9
9
  sequence: TSequence;
10
10
  depth: number;
11
11
  nodePathInfo: SequenceNodePathInfo | null;
12
+ keyframeDisplayOffset: number;
12
13
  };
13
14
  export type TrackWithHash = Track & {
14
15
  hash: string;
@@ -1,9 +1,9 @@
1
1
  import { type AnySchemaFieldInfo, type CodeValues, type DragOverrides, type EffectSchemaFieldInfo, type SchemaFieldInfo, type SequenceControls, type SequenceSchemaFieldInfo } from '@remotion/studio-shared';
2
- import type { GetDragOverrides, SequenceSchema as SequenceSchemaShape, TSequence } from 'remotion';
2
+ import type { GetDragOverrides, GetEffectDragOverrides, SequenceSchema as SequenceSchemaShape, TSequence } from 'remotion';
3
3
  import type { GetIsExpanded } from '../components/ExpandedTracksProvider';
4
4
  import type { SequenceNodePathInfo } from './get-timeline-sequence-sort-key';
5
+ export { getEffectFieldsToShow, getFieldsToShow, SCHEMA_FIELD_ROW_HEIGHT, } from '@remotion/studio-shared';
5
6
  export type { AnySchemaFieldInfo, CodeValues, DragOverrides, EffectSchemaFieldInfo, SchemaFieldInfo, SequenceControls, SequenceSchemaFieldInfo, };
6
- export { SCHEMA_FIELD_ROW_HEIGHT, getEffectFieldsToShow, getFieldsToShow, } from '@remotion/studio-shared';
7
7
  export declare const TIMELINE_PADDING = 16;
8
8
  export declare const TIMELINE_BORDER = 1;
9
9
  export declare const TIMELINE_ITEM_BORDER_BOTTOM = 1;
@@ -29,10 +29,11 @@ export type TimelineTreeNode = {
29
29
  readonly label: string;
30
30
  readonly field: AnySchemaFieldInfo | null;
31
31
  };
32
- export declare const buildTimelineTree: ({ sequence, nodePathInfo, getDragOverrides, codeValues, }: {
32
+ export declare const buildTimelineTree: ({ sequence, nodePathInfo, getDragOverrides, getEffectDragOverrides, codeValues, }: {
33
33
  sequence: TSequence;
34
34
  nodePathInfo: SequenceNodePathInfo;
35
35
  getDragOverrides: GetDragOverrides;
36
+ getEffectDragOverrides: GetEffectDragOverrides;
36
37
  codeValues: CodeValues;
37
38
  }) => TimelineTreeNode[];
38
39
  export type FlatTreeRow = {
@@ -52,6 +53,9 @@ export declare const getExpandedTrackHeight: ({ sequence, nodePathInfo, getIsExp
52
53
  codeValues: CodeValues;
53
54
  }) => number;
54
55
  export declare const TIMELINE_LAYER_HEIGHT_VIDEO = 75;
55
- export declare const TIMELINE_LAYER_HEIGHT_IMAGE = 50;
56
- export declare const TIMELINE_LAYER_HEIGHT_AUDIO = 25;
57
- export declare const getTimelineLayerHeight: (type: "audio" | "image" | "other" | "sequence" | "video") => 25 | 50 | 75;
56
+ export declare const TIMELINE_LAYER_HEIGHT_IMAGE = 58;
57
+ export declare const TIMELINE_LAYER_HEIGHT_AUDIO = 58;
58
+ export declare const TIMELINE_LAYER_HEIGHT_DEFAULT = 25;
59
+ export declare const TIMELINE_LIST_ITEM_ROW_HEIGHT = 25;
60
+ export declare const TIMELINE_VIDEO_INFO_WAVEFORM_HEIGHT = 25;
61
+ export declare const getTimelineLayerHeight: (type: "audio" | "image" | "other" | "sequence" | "video") => 25 | 58 | 75;
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTimelineLayerHeight = exports.TIMELINE_LAYER_HEIGHT_AUDIO = exports.TIMELINE_LAYER_HEIGHT_IMAGE = exports.TIMELINE_LAYER_HEIGHT_VIDEO = exports.getExpandedTrackHeight = exports.getTreeRowHeight = exports.flattenVisibleTreeNodes = exports.buildTimelineTree = exports.EXPANDED_SECTION_PADDING_RIGHT = exports.TREE_GROUP_ROW_HEIGHT = exports.TIMELINE_TRACK_EXPANDED_HEIGHT = exports.TIMELINE_ITEM_BORDER_BOTTOM = exports.TIMELINE_BORDER = exports.TIMELINE_PADDING = exports.getFieldsToShow = exports.getEffectFieldsToShow = exports.SCHEMA_FIELD_ROW_HEIGHT = void 0;
3
+ exports.getTimelineLayerHeight = exports.TIMELINE_VIDEO_INFO_WAVEFORM_HEIGHT = exports.TIMELINE_LIST_ITEM_ROW_HEIGHT = exports.TIMELINE_LAYER_HEIGHT_DEFAULT = exports.TIMELINE_LAYER_HEIGHT_AUDIO = exports.TIMELINE_LAYER_HEIGHT_IMAGE = exports.TIMELINE_LAYER_HEIGHT_VIDEO = exports.getExpandedTrackHeight = exports.getTreeRowHeight = exports.flattenVisibleTreeNodes = exports.buildTimelineTree = exports.EXPANDED_SECTION_PADDING_RIGHT = exports.TREE_GROUP_ROW_HEIGHT = exports.TIMELINE_TRACK_EXPANDED_HEIGHT = exports.TIMELINE_ITEM_BORDER_BOTTOM = exports.TIMELINE_BORDER = exports.TIMELINE_PADDING = exports.SCHEMA_FIELD_ROW_HEIGHT = exports.getFieldsToShow = exports.getEffectFieldsToShow = void 0;
4
4
  const studio_shared_1 = require("@remotion/studio-shared");
5
5
  const studio_shared_2 = require("@remotion/studio-shared");
6
- Object.defineProperty(exports, "SCHEMA_FIELD_ROW_HEIGHT", { enumerable: true, get: function () { return studio_shared_2.SCHEMA_FIELD_ROW_HEIGHT; } });
7
6
  Object.defineProperty(exports, "getEffectFieldsToShow", { enumerable: true, get: function () { return studio_shared_2.getEffectFieldsToShow; } });
8
7
  Object.defineProperty(exports, "getFieldsToShow", { enumerable: true, get: function () { return studio_shared_2.getFieldsToShow; } });
8
+ Object.defineProperty(exports, "SCHEMA_FIELD_ROW_HEIGHT", { enumerable: true, get: function () { return studio_shared_2.SCHEMA_FIELD_ROW_HEIGHT; } });
9
9
  exports.TIMELINE_PADDING = 16;
10
10
  exports.TIMELINE_BORDER = 1;
11
11
  exports.TIMELINE_ITEM_BORDER_BOTTOM = 1;
12
12
  exports.TIMELINE_TRACK_EXPANDED_HEIGHT = 100;
13
13
  exports.TREE_GROUP_ROW_HEIGHT = 22;
14
14
  exports.EXPANDED_SECTION_PADDING_RIGHT = 10;
15
- const buildTimelineTree = ({ sequence, nodePathInfo, getDragOverrides, codeValues, }) => {
15
+ const buildTimelineTree = ({ sequence, nodePathInfo, getDragOverrides, getEffectDragOverrides, codeValues, }) => {
16
16
  var _a;
17
17
  const roots = [];
18
18
  const { sequenceSubscriptionKey, index, auxiliaryKeys } = nodePathInfo;
@@ -51,7 +51,13 @@ const buildTimelineTree = ({ sequence, nodePathInfo, getDragOverrides, codeValue
51
51
  effectInfo: null,
52
52
  children: sequence.effects.map((effect, i) => {
53
53
  var _a;
54
- const effectFields = (0, studio_shared_1.getEffectFieldsToShow)(effect, i);
54
+ const effectFields = (0, studio_shared_1.getEffectFieldsToShow)({
55
+ effect,
56
+ effectIndex: i,
57
+ nodePath: sequenceSubscriptionKey,
58
+ codeValues,
59
+ getEffectDragOverrides,
60
+ });
55
61
  return {
56
62
  kind: 'group',
57
63
  nodePathInfo: {
@@ -120,6 +126,7 @@ const getExpandedTrackHeight = ({ sequence, nodePathInfo, getIsExpanded, codeVal
120
126
  nodePathInfo,
121
127
  // We assume that no drag overrides can change the timeline layout
122
128
  getDragOverrides: () => ({}),
129
+ getEffectDragOverrides: () => ({}),
123
130
  codeValues,
124
131
  });
125
132
  const flat = (0, exports.flattenVisibleTreeNodes)({ nodes: tree, getIsExpanded });
@@ -132,8 +139,13 @@ const getExpandedTrackHeight = ({ sequence, nodePathInfo, getIsExpanded, codeVal
132
139
  };
133
140
  exports.getExpandedTrackHeight = getExpandedTrackHeight;
134
141
  exports.TIMELINE_LAYER_HEIGHT_VIDEO = 75;
135
- exports.TIMELINE_LAYER_HEIGHT_IMAGE = 50;
136
- exports.TIMELINE_LAYER_HEIGHT_AUDIO = 25;
142
+ exports.TIMELINE_LAYER_HEIGHT_IMAGE = 58;
143
+ exports.TIMELINE_LAYER_HEIGHT_AUDIO = 58;
144
+ exports.TIMELINE_LAYER_HEIGHT_DEFAULT = 25;
145
+ // The horizontal row inside a timeline list item (eye + arrow + label).
146
+ exports.TIMELINE_LIST_ITEM_ROW_HEIGHT = 25;
147
+ // The waveform stripe rendered underneath the filmstrip in TimelineVideoInfo.
148
+ exports.TIMELINE_VIDEO_INFO_WAVEFORM_HEIGHT = 25;
137
149
  const getTimelineLayerHeight = (type) => {
138
150
  if (type === 'video') {
139
151
  return exports.TIMELINE_LAYER_HEIGHT_VIDEO;
@@ -141,6 +153,9 @@ const getTimelineLayerHeight = (type) => {
141
153
  if (type === 'image') {
142
154
  return exports.TIMELINE_LAYER_HEIGHT_IMAGE;
143
155
  }
144
- return exports.TIMELINE_LAYER_HEIGHT_AUDIO;
156
+ if (type === 'audio') {
157
+ return exports.TIMELINE_LAYER_HEIGHT_AUDIO;
158
+ }
159
+ return exports.TIMELINE_LAYER_HEIGHT_DEFAULT;
145
160
  };
146
161
  exports.getTimelineLayerHeight = getTimelineLayerHeight;
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useMaxMediaDuration = void 0;
4
- const media_utils_1 = require("@remotion/media-utils");
5
- const mediabunny_1 = require("mediabunny");
6
4
  const react_1 = require("react");
7
- const get_duration_or_compute_1 = require("./get-duration-or-compute");
5
+ const use_media_metadata_1 = require("./use-media-metadata");
8
6
  const cache = new Map();
7
+ const getCacheKey = (src, fps) => JSON.stringify([src, fps]);
9
8
  const getSrc = (s) => {
10
9
  if (s.type === 'video') {
11
10
  return s.src;
@@ -18,40 +17,38 @@ const getSrc = (s) => {
18
17
  const useMaxMediaDuration = (s, fps) => {
19
18
  var _a;
20
19
  const src = getSrc(s);
21
- const [maxMediaDuration, setMaxMediaDuration] = (0, react_1.useState)(src ? ((_a = cache.get(src)) !== null && _a !== void 0 ? _a : null) : Infinity);
20
+ const cacheKey = src ? getCacheKey(src, fps) : null;
21
+ const [maxMediaDuration, setMaxMediaDuration] = (0, react_1.useState)(cacheKey ? ((_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : null) : Infinity);
22
22
  (0, react_1.useEffect)(() => {
23
- if (!src) {
23
+ var _a;
24
+ if (!src || !cacheKey) {
24
25
  return;
25
26
  }
26
- const input = new mediabunny_1.Input({
27
- formats: mediabunny_1.ALL_FORMATS,
28
- source: new mediabunny_1.UrlSource(src),
29
- });
30
- (0, get_duration_or_compute_1.getDurationOrCompute)(input)
31
- .then((duration) => {
32
- cache.set(src, Math.floor(duration * fps));
33
- setMaxMediaDuration(Math.floor(duration * fps));
27
+ const cached = (_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : null;
28
+ setMaxMediaDuration(cached);
29
+ if (cached !== null) {
30
+ return;
31
+ }
32
+ let cancelled = false;
33
+ (0, use_media_metadata_1.getMediaMetadata)(src)
34
+ .then((metadata) => {
35
+ if (cancelled || !metadata) {
36
+ return;
37
+ }
38
+ const duration = Math.floor(metadata.duration * fps);
39
+ cache.set(cacheKey, duration);
40
+ setMaxMediaDuration(duration);
34
41
  })
35
- .catch((e) => {
36
- if (e instanceof mediabunny_1.InputDisposedError) {
42
+ .catch(() => {
43
+ if (cancelled) {
37
44
  return;
38
45
  }
39
- // In case of CORS errors, fall back to getVideoMetadata
40
- return (0, media_utils_1.getVideoMetadata)(src)
41
- .then((metadata) => {
42
- var _a;
43
- const durationOrInfinity = (_a = metadata.durationInSeconds) !== null && _a !== void 0 ? _a : Infinity;
44
- cache.set(src, Math.floor(durationOrInfinity * fps));
45
- setMaxMediaDuration(Math.floor(durationOrInfinity * fps));
46
- })
47
- .catch(() => {
48
- // Silently handle getVideoMetadata failures to prevent unhandled rejections
49
- });
46
+ setMaxMediaDuration(null);
50
47
  });
51
48
  return () => {
52
- input.dispose();
49
+ cancelled = true;
53
50
  };
54
- }, [src, fps]);
51
+ }, [cacheKey, fps, src]);
55
52
  if (maxMediaDuration !== null && (s.type === 'audio' || s.type === 'video')) {
56
53
  return maxMediaDuration;
57
54
  }
@@ -0,0 +1,10 @@
1
+ export type MediaMetadata = {
2
+ duration: number;
3
+ format: string | null;
4
+ width: number | null;
5
+ height: number | null;
6
+ videoCodec: string | null;
7
+ audioCodec: string | null;
8
+ };
9
+ export declare const getMediaMetadata: (src: string) => Promise<MediaMetadata | null>;
10
+ export declare const useMediaMetadata: (src: string | null) => MediaMetadata | null;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMediaMetadata = exports.getMediaMetadata = void 0;
4
+ const media_utils_1 = require("@remotion/media-utils");
5
+ const mediabunny_1 = require("mediabunny");
6
+ const react_1 = require("react");
7
+ const get_duration_or_compute_1 = require("./get-duration-or-compute");
8
+ const cache = new Map();
9
+ const pendingRequests = new Map();
10
+ const safeCall = async (fn) => {
11
+ try {
12
+ return await fn();
13
+ }
14
+ catch (_a) {
15
+ return null;
16
+ }
17
+ };
18
+ const getMediabunnyMetadata = async (src) => {
19
+ var _a;
20
+ let input;
21
+ try {
22
+ input = new mediabunny_1.Input({
23
+ formats: mediabunny_1.ALL_FORMATS,
24
+ source: new mediabunny_1.UrlSource(src),
25
+ });
26
+ }
27
+ catch (_b) {
28
+ return null;
29
+ }
30
+ try {
31
+ const [duration, format, videoTrack, audioTrack] = await Promise.all([
32
+ safeCall(() => (0, get_duration_or_compute_1.getDurationOrCompute)(input)),
33
+ safeCall(() => input.getFormat()),
34
+ safeCall(() => input.getPrimaryVideoTrack()),
35
+ safeCall(() => input.getPrimaryAudioTrack()),
36
+ ]);
37
+ if (duration === null) {
38
+ return null;
39
+ }
40
+ const [width, height, videoCodec, audioCodec] = await Promise.all([
41
+ videoTrack ? safeCall(() => videoTrack.getDisplayWidth()) : null,
42
+ videoTrack ? safeCall(() => videoTrack.getDisplayHeight()) : null,
43
+ videoTrack ? safeCall(() => videoTrack.getCodec()) : null,
44
+ audioTrack ? safeCall(() => audioTrack.getCodec()) : null,
45
+ ]);
46
+ return {
47
+ duration,
48
+ format: (_a = format === null || format === void 0 ? void 0 : format.name) !== null && _a !== void 0 ? _a : null,
49
+ width,
50
+ height,
51
+ videoCodec,
52
+ audioCodec,
53
+ };
54
+ }
55
+ finally {
56
+ try {
57
+ input.dispose();
58
+ }
59
+ catch (_c) {
60
+ // ignore
61
+ }
62
+ }
63
+ };
64
+ const getFallbackVideoMetadata = async (src) => {
65
+ try {
66
+ const metadata = await (0, media_utils_1.getVideoMetadata)(src);
67
+ return {
68
+ duration: metadata.durationInSeconds,
69
+ format: null,
70
+ width: metadata.width,
71
+ height: metadata.height,
72
+ videoCodec: null,
73
+ audioCodec: null,
74
+ };
75
+ }
76
+ catch (_a) {
77
+ return null;
78
+ }
79
+ };
80
+ const getMediaMetadata = (src) => {
81
+ const cached = cache.get(src);
82
+ if (cached) {
83
+ return Promise.resolve(cached);
84
+ }
85
+ const pendingRequest = pendingRequests.get(src);
86
+ if (pendingRequest) {
87
+ return pendingRequest;
88
+ }
89
+ const request = getMediabunnyMetadata(src)
90
+ .catch(() => null)
91
+ .then((metadata) => metadata !== null && metadata !== void 0 ? metadata : getFallbackVideoMetadata(src))
92
+ .then((metadata) => {
93
+ if (metadata) {
94
+ cache.set(src, metadata);
95
+ }
96
+ return metadata;
97
+ })
98
+ .finally(() => {
99
+ pendingRequests.delete(src);
100
+ });
101
+ pendingRequests.set(src, request);
102
+ return request;
103
+ };
104
+ exports.getMediaMetadata = getMediaMetadata;
105
+ const useMediaMetadata = (src) => {
106
+ var _a;
107
+ const [mediaMetadata, setMediaMetadata] = (0, react_1.useState)(src ? ((_a = cache.get(src)) !== null && _a !== void 0 ? _a : null) : null);
108
+ (0, react_1.useEffect)(() => {
109
+ var _a;
110
+ const cached = src ? ((_a = cache.get(src)) !== null && _a !== void 0 ? _a : null) : null;
111
+ setMediaMetadata(cached);
112
+ if (!src || cached) {
113
+ return;
114
+ }
115
+ let cancelled = false;
116
+ (0, exports.getMediaMetadata)(src)
117
+ .then((metadata) => {
118
+ if (cancelled) {
119
+ return;
120
+ }
121
+ setMediaMetadata(metadata);
122
+ })
123
+ .catch(() => {
124
+ if (cancelled) {
125
+ return;
126
+ }
127
+ setMediaMetadata(null);
128
+ });
129
+ return () => {
130
+ cancelled = true;
131
+ };
132
+ }, [src]);
133
+ return mediaMetadata;
134
+ };
135
+ exports.useMediaMetadata = useMediaMetadata;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio"
4
4
  },
5
5
  "name": "@remotion/studio",
6
- "version": "4.0.466",
6
+ "version": "4.0.468",
7
7
  "description": "APIs for interacting with the Remotion Studio",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -25,14 +25,14 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "semver": "7.5.3",
28
- "remotion": "4.0.466",
29
- "@remotion/player": "4.0.466",
30
- "@remotion/media-utils": "4.0.466",
31
- "@remotion/renderer": "4.0.466",
32
- "@remotion/web-renderer": "4.0.466",
33
- "@remotion/studio-shared": "4.0.466",
34
- "@remotion/timeline-utils": "4.0.466",
35
- "@remotion/zod-types": "4.0.466",
28
+ "remotion": "4.0.468",
29
+ "@remotion/player": "4.0.468",
30
+ "@remotion/media-utils": "4.0.468",
31
+ "@remotion/renderer": "4.0.468",
32
+ "@remotion/web-renderer": "4.0.468",
33
+ "@remotion/studio-shared": "4.0.468",
34
+ "@remotion/timeline-utils": "4.0.468",
35
+ "@remotion/zod-types": "4.0.468",
36
36
  "@jridgewell/trace-mapping": "0.3.31",
37
37
  "mediabunny": "1.45.0",
38
38
  "memfs": "3.4.3",
@@ -43,7 +43,7 @@
43
43
  "react": "19.2.3",
44
44
  "react-dom": "19.2.3",
45
45
  "@types/semver": "7.5.3",
46
- "@remotion/eslint-config-internal": "4.0.466",
46
+ "@remotion/eslint-config-internal": "4.0.468",
47
47
  "eslint": "9.19.0",
48
48
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
49
49
  },