import { NoReactInternals } from 'remotion/no-react'; export const onlyArtifact = async ({ assets, frameBuffer, }) => { const artifacts = assets.filter((asset) => asset.type === 'artifact'); let frameBufferUint8 = null; const result = []; for (const artifact of artifacts) { if (artifact.contentType === 'binary' || artifact.contentType === 'text') { result.push({ frame: artifact.frame, content: artifact.content, filename: artifact.filename, downloadBehavior: artifact.downloadBehavior, }); continue; } if (artifact.contentType === 'thumbnail') { if (frameBuffer === null) { // A thumbnail artifact was defined to be emitted, but the output was not a video. // Also, in Lambda, there are extra frames which are not video frames. // This could happen if a thumbnail is unconditionally emitted. continue; } const ab = frameBuffer instanceof Blob ? await frameBuffer.arrayBuffer() : new Uint8Array(await (await frameBuffer.convertToBlob({ type: 'image/png' })).arrayBuffer()); frameBufferUint8 = new Uint8Array(ab); result.push({ frame: artifact.frame, content: frameBufferUint8, filename: artifact.filename, downloadBehavior: artifact.downloadBehavior, }); continue; } throw new Error('Unknown artifact type: ' + artifact); } return result.filter(NoReactInternals.truthy); }; export const handleArtifacts = () => { const previousArtifacts = []; const handle = async ({ imageData, frame, assets: artifactAssets, onArtifact, }) => { const artifacts = await onlyArtifact({ assets: artifactAssets, frameBuffer: imageData, }); for (const artifact of artifacts) { const previousArtifact = previousArtifacts.find((a) => a.filename === artifact.filename); if (previousArtifact) { throw new Error(`An artifact with output "${artifact.filename}" was already registered at frame ${previousArtifact.frame}, but now registered again at frame ${frame}. Artifacts must have unique names. https://remotion.dev/docs/artifacts`); } onArtifact(artifact); previousArtifacts.push({ frame, filename: artifact.filename }); } }; return { handle }; };