remotion 3.3.81 → 3.3.82

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/cjs/Img.d.ts CHANGED
@@ -3,4 +3,6 @@ import React from 'react';
3
3
  * @description Works just like a regular HTML img tag. When you use the <Img> tag, Remotion will ensure that the image is loaded before rendering the frame.
4
4
  * @see [Documentation](https://www.remotion.dev/docs/img)
5
5
  */
6
- export declare const Img: React.ForwardRefExoticComponent<Pick<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "key" | keyof React.ImgHTMLAttributes<HTMLImageElement>> & React.RefAttributes<HTMLImageElement>>;
6
+ export declare const Img: React.ForwardRefExoticComponent<Pick<React.ClassAttributes<HTMLImageElement> & React.ImgHTMLAttributes<HTMLImageElement> & {
7
+ maxRetries?: number | undefined;
8
+ }, "key" | "maxRetries" | keyof React.ImgHTMLAttributes<HTMLImageElement>> & React.RefAttributes<HTMLImageElement>>;
package/dist/cjs/Img.js CHANGED
@@ -4,49 +4,86 @@ exports.Img = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const delay_render_js_1 = require("./delay-render.js");
7
- const get_environment_js_1 = require("./get-environment.js");
8
7
  const prefetch_js_1 = require("./prefetch.js");
9
- const ImgRefForwarding = ({ onError, src, ...props }, ref) => {
8
+ function exponentialBackoff(errorCount) {
9
+ return 1000 * 2 ** (errorCount - 1);
10
+ }
11
+ const ImgRefForwarding = ({ onError, maxRetries = 2, src, ...props }, ref) => {
10
12
  const imageRef = (0, react_1.useRef)(null);
11
- const environment = (0, get_environment_js_1.useRemotionEnvironment)();
13
+ const errors = (0, react_1.useRef)({});
12
14
  (0, react_1.useImperativeHandle)(ref, () => {
13
15
  return imageRef.current;
14
16
  }, []);
15
17
  const actualSrc = (0, prefetch_js_1.usePreload)(src);
16
- const didGetError = (0, react_1.useCallback)((e) => {
17
- var _a;
18
- if (onError) {
19
- onError(e);
20
- }
21
- else {
22
- console.error('Error loading image with src:', (_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src, e, 'Handle the event using the onError() prop to make this message disappear.');
18
+ const retryIn = (0, react_1.useCallback)((timeout) => {
19
+ if (!imageRef.current) {
20
+ return;
23
21
  }
24
- }, [onError]);
25
- // If image source switches, make new handle
26
- if (environment === 'rendering') {
27
- // eslint-disable-next-line react-hooks/rules-of-hooks
28
- (0, react_1.useLayoutEffect)(() => {
29
- if (process.env.NODE_ENV === 'test') {
22
+ const currentSrc = imageRef.current.src;
23
+ setTimeout(() => {
24
+ var _a;
25
+ if (!imageRef.current) {
26
+ // Component has been unmounted, do not retry
30
27
  return;
31
28
  }
32
- const newHandle = (0, delay_render_js_1.delayRender)('Loading <Img> with src=' + src);
33
- const { current } = imageRef;
34
- const didLoad = () => {
35
- (0, delay_render_js_1.continueRender)(newHandle);
36
- };
37
- if (current === null || current === void 0 ? void 0 : current.complete) {
38
- (0, delay_render_js_1.continueRender)(newHandle);
29
+ const newSrc = (_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src;
30
+ if (newSrc !== currentSrc) {
31
+ // src has changed, do not retry
32
+ return;
39
33
  }
40
- else {
41
- current === null || current === void 0 ? void 0 : current.addEventListener('load', didLoad, { once: true });
34
+ imageRef.current.removeAttribute('src');
35
+ imageRef.current.setAttribute('src', newSrc);
36
+ }, timeout);
37
+ }, []);
38
+ const didGetError = (0, react_1.useCallback)((e) => {
39
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
40
+ if (!errors.current) {
41
+ return;
42
+ }
43
+ errors.current[(_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src] =
44
+ ((_c = errors.current[(_b = imageRef.current) === null || _b === void 0 ? void 0 : _b.src]) !== null && _c !== void 0 ? _c : 0) + 1;
45
+ if (onError &&
46
+ ((_e = errors.current[(_d = imageRef.current) === null || _d === void 0 ? void 0 : _d.src]) !== null && _e !== void 0 ? _e : 0) > maxRetries) {
47
+ onError(e);
48
+ return;
49
+ }
50
+ if (((_g = errors.current[(_f = imageRef.current) === null || _f === void 0 ? void 0 : _f.src]) !== null && _g !== void 0 ? _g : 0) <= maxRetries) {
51
+ const backoff = exponentialBackoff((_j = errors.current[(_h = imageRef.current) === null || _h === void 0 ? void 0 : _h.src]) !== null && _j !== void 0 ? _j : 0);
52
+ console.warn(`Could not load image with source ${(_k = imageRef.current) === null || _k === void 0 ? void 0 : _k.src}, retrying again in ${backoff}ms`);
53
+ retryIn(backoff);
54
+ return;
55
+ }
56
+ console.error('Error loading image with src:', (_l = imageRef.current) === null || _l === void 0 ? void 0 : _l.src, e, 'Handle the event using the onError() prop to make this message disappear.');
57
+ }, [maxRetries, onError, retryIn]);
58
+ (0, react_1.useLayoutEffect)(() => {
59
+ if (process.env.NODE_ENV === 'test') {
60
+ return;
61
+ }
62
+ const newHandle = (0, delay_render_js_1.delayRender)('Loading <Img> with src=' + src);
63
+ const { current } = imageRef;
64
+ const onComplete = () => {
65
+ var _a, _b, _c, _d;
66
+ if (((_b = errors.current[(_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src]) !== null && _b !== void 0 ? _b : 0) > 0) {
67
+ delete errors.current[(_c = imageRef.current) === null || _c === void 0 ? void 0 : _c.src];
68
+ console.info(`Retry successful - ${(_d = imageRef.current) === null || _d === void 0 ? void 0 : _d.src} is now loaded`);
42
69
  }
43
- // If tag gets unmounted, clear pending handles because image is not going to load
44
- return () => {
45
- current === null || current === void 0 ? void 0 : current.removeEventListener('load', didLoad);
46
- (0, delay_render_js_1.continueRender)(newHandle);
47
- };
48
- }, [src]);
49
- }
70
+ (0, delay_render_js_1.continueRender)(newHandle);
71
+ };
72
+ const didLoad = () => {
73
+ onComplete();
74
+ };
75
+ if (current === null || current === void 0 ? void 0 : current.complete) {
76
+ onComplete();
77
+ }
78
+ else {
79
+ current === null || current === void 0 ? void 0 : current.addEventListener('load', didLoad, { once: true });
80
+ }
81
+ // If tag gets unmounted, clear pending handles because image is not going to load
82
+ return () => {
83
+ current === null || current === void 0 ? void 0 : current.removeEventListener('load', didLoad);
84
+ (0, delay_render_js_1.continueRender)(newHandle);
85
+ };
86
+ }, [src]);
50
87
  return ((0, jsx_runtime_1.jsx)("img", { ...props, ref: imageRef, src: actualSrc, onError: didGetError }));
51
88
  };
52
89
  /**
@@ -42,7 +42,7 @@ const useMediaInTimeline = ({ volume, mediaVolume, mediaRef, src, mediaType, pla
42
42
  if (typeof volume === 'number') {
43
43
  return volume;
44
44
  }
45
- return new Array(Math.max(0, duration + startsAt))
45
+ return new Array(Math.floor(Math.max(0, duration + startsAt)))
46
46
  .fill(true)
47
47
  .map((_, i) => {
48
48
  return (0, volume_prop_js_1.evaluateVolume)({
@@ -1 +1 @@
1
- export declare const VERSION = "3.3.81";
1
+ export declare const VERSION = "3.3.82";
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // Automatically generated on publish
5
- exports.VERSION = '3.3.81';
5
+ exports.VERSION = '3.3.82';
@@ -58,7 +58,7 @@ function truthy(value) {
58
58
  }
59
59
 
60
60
  // Automatically generated on publish
61
- const VERSION = '3.3.81';
61
+ const VERSION = '3.3.82';
62
62
 
63
63
  const checkMultipleRemotionVersions = () => {
64
64
  if (typeof globalThis === 'undefined') {
@@ -988,7 +988,7 @@ const useMediaInTimeline = ({ volume, mediaVolume, mediaRef, src, mediaType, pla
988
988
  if (typeof volume === 'number') {
989
989
  return volume;
990
990
  }
991
- return new Array(Math.max(0, duration + startsAt))
991
+ return new Array(Math.floor(Math.max(0, duration + startsAt)))
992
992
  .fill(true)
993
993
  .map((_, i) => {
994
994
  return evaluateVolume({
@@ -2790,47 +2790,85 @@ const IFrameRefForwarding = ({ onLoad, onError, ...props }, ref) => {
2790
2790
  */
2791
2791
  const IFrame = forwardRef(IFrameRefForwarding);
2792
2792
 
2793
- const ImgRefForwarding = ({ onError, src, ...props }, ref) => {
2793
+ function exponentialBackoff(errorCount) {
2794
+ return 1000 * 2 ** (errorCount - 1);
2795
+ }
2796
+ const ImgRefForwarding = ({ onError, maxRetries = 2, src, ...props }, ref) => {
2794
2797
  const imageRef = useRef(null);
2795
- const environment = useRemotionEnvironment();
2798
+ const errors = useRef({});
2796
2799
  useImperativeHandle(ref, () => {
2797
2800
  return imageRef.current;
2798
2801
  }, []);
2799
2802
  const actualSrc = usePreload(src);
2800
- const didGetError = useCallback((e) => {
2801
- var _a;
2802
- if (onError) {
2803
- onError(e);
2804
- }
2805
- else {
2806
- console.error('Error loading image with src:', (_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src, e, 'Handle the event using the onError() prop to make this message disappear.');
2803
+ const retryIn = useCallback((timeout) => {
2804
+ if (!imageRef.current) {
2805
+ return;
2807
2806
  }
2808
- }, [onError]);
2809
- // If image source switches, make new handle
2810
- if (environment === 'rendering') {
2811
- // eslint-disable-next-line react-hooks/rules-of-hooks
2812
- useLayoutEffect(() => {
2813
- if (process.env.NODE_ENV === 'test') {
2807
+ const currentSrc = imageRef.current.src;
2808
+ setTimeout(() => {
2809
+ var _a;
2810
+ if (!imageRef.current) {
2811
+ // Component has been unmounted, do not retry
2814
2812
  return;
2815
2813
  }
2816
- const newHandle = delayRender('Loading <Img> with src=' + src);
2817
- const { current } = imageRef;
2818
- const didLoad = () => {
2819
- continueRender(newHandle);
2820
- };
2821
- if (current === null || current === void 0 ? void 0 : current.complete) {
2822
- continueRender(newHandle);
2814
+ const newSrc = (_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src;
2815
+ if (newSrc !== currentSrc) {
2816
+ // src has changed, do not retry
2817
+ return;
2823
2818
  }
2824
- else {
2825
- current === null || current === void 0 ? void 0 : current.addEventListener('load', didLoad, { once: true });
2819
+ imageRef.current.removeAttribute('src');
2820
+ imageRef.current.setAttribute('src', newSrc);
2821
+ }, timeout);
2822
+ }, []);
2823
+ const didGetError = useCallback((e) => {
2824
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2825
+ if (!errors.current) {
2826
+ return;
2827
+ }
2828
+ errors.current[(_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src] =
2829
+ ((_c = errors.current[(_b = imageRef.current) === null || _b === void 0 ? void 0 : _b.src]) !== null && _c !== void 0 ? _c : 0) + 1;
2830
+ if (onError &&
2831
+ ((_e = errors.current[(_d = imageRef.current) === null || _d === void 0 ? void 0 : _d.src]) !== null && _e !== void 0 ? _e : 0) > maxRetries) {
2832
+ onError(e);
2833
+ return;
2834
+ }
2835
+ if (((_g = errors.current[(_f = imageRef.current) === null || _f === void 0 ? void 0 : _f.src]) !== null && _g !== void 0 ? _g : 0) <= maxRetries) {
2836
+ const backoff = exponentialBackoff((_j = errors.current[(_h = imageRef.current) === null || _h === void 0 ? void 0 : _h.src]) !== null && _j !== void 0 ? _j : 0);
2837
+ console.warn(`Could not load image with source ${(_k = imageRef.current) === null || _k === void 0 ? void 0 : _k.src}, retrying again in ${backoff}ms`);
2838
+ retryIn(backoff);
2839
+ return;
2840
+ }
2841
+ console.error('Error loading image with src:', (_l = imageRef.current) === null || _l === void 0 ? void 0 : _l.src, e, 'Handle the event using the onError() prop to make this message disappear.');
2842
+ }, [maxRetries, onError, retryIn]);
2843
+ useLayoutEffect(() => {
2844
+ if (process.env.NODE_ENV === 'test') {
2845
+ return;
2846
+ }
2847
+ const newHandle = delayRender('Loading <Img> with src=' + src);
2848
+ const { current } = imageRef;
2849
+ const onComplete = () => {
2850
+ var _a, _b, _c, _d;
2851
+ if (((_b = errors.current[(_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.src]) !== null && _b !== void 0 ? _b : 0) > 0) {
2852
+ delete errors.current[(_c = imageRef.current) === null || _c === void 0 ? void 0 : _c.src];
2853
+ console.info(`Retry successful - ${(_d = imageRef.current) === null || _d === void 0 ? void 0 : _d.src} is now loaded`);
2826
2854
  }
2827
- // If tag gets unmounted, clear pending handles because image is not going to load
2828
- return () => {
2829
- current === null || current === void 0 ? void 0 : current.removeEventListener('load', didLoad);
2830
- continueRender(newHandle);
2831
- };
2832
- }, [src]);
2833
- }
2855
+ continueRender(newHandle);
2856
+ };
2857
+ const didLoad = () => {
2858
+ onComplete();
2859
+ };
2860
+ if (current === null || current === void 0 ? void 0 : current.complete) {
2861
+ onComplete();
2862
+ }
2863
+ else {
2864
+ current === null || current === void 0 ? void 0 : current.addEventListener('load', didLoad, { once: true });
2865
+ }
2866
+ // If tag gets unmounted, clear pending handles because image is not going to load
2867
+ return () => {
2868
+ current === null || current === void 0 ? void 0 : current.removeEventListener('load', didLoad);
2869
+ continueRender(newHandle);
2870
+ };
2871
+ }, [src]);
2834
2872
  return (jsx("img", { ...props, ref: imageRef, src: actualSrc, onError: didGetError }));
2835
2873
  };
2836
2874
  /**
@@ -1,4 +1,4 @@
1
1
  // Automatically generated on publish
2
- const VERSION = '3.3.81';
2
+ const VERSION = '3.3.82';
3
3
 
4
4
  export { VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remotion",
3
- "version": "3.3.81",
3
+ "version": "3.3.82",
4
4
  "description": "Render videos in React",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/cjs/index.d.ts",