diff --git a/src/components/video-editor/exportStatusModel.test.ts b/src/components/video-editor/exportStatusModel.test.ts index 878daddf..9cb3158a 100644 --- a/src/components/video-editor/exportStatusModel.test.ts +++ b/src/components/video-editor/exportStatusModel.test.ts @@ -58,6 +58,43 @@ describe("resolveExportStatusModel", () => { expect(status.isExportFinalSaveIndeterminate).toBe(true); }); + it("sanitizes invalid finalizing progress before rounding", () => { + const negativeStatus = resolveExportStatusModel({ + isExporting: true, + exportProgress: progress({ + phase: "finalizing", + renderProgress: -12.4, + }), + exportFormat: "mp4", + exportPipelineModel: "modern", + }); + const infiniteStatus = resolveExportStatusModel({ + isExporting: true, + exportProgress: progress({ + phase: "finalizing", + renderProgress: Number.POSITIVE_INFINITY, + }), + exportFormat: "mp4", + exportPipelineModel: "modern", + }); + const nanStatus = resolveExportStatusModel({ + isExporting: true, + exportProgress: progress({ + phase: "finalizing", + renderProgress: Number.NaN, + }), + exportFormat: "mp4", + exportPipelineModel: "modern", + }); + + expect(negativeStatus.exportFinalizingProgress).toBe(0); + expect(negativeStatus.exportFinalizingPercent).toBe(0); + expect(infiniteStatus.exportFinalizingProgress).toBe(0); + expect(infiniteStatus.exportFinalizingPercent).toBe(0); + expect(nanStatus.exportFinalizingProgress).toBe(0); + expect(nanStatus.exportFinalizingPercent).toBe(0); + }); + it("keeps audio finalization out of the muxing-and-saving state", () => { const status = resolveExportStatusModel({ isExporting: true, diff --git a/src/components/video-editor/exportStatusModel.ts b/src/components/video-editor/exportStatusModel.ts index 631df27b..7641717a 100644 --- a/src/components/video-editor/exportStatusModel.ts +++ b/src/components/video-editor/exportStatusModel.ts @@ -35,12 +35,14 @@ export function resolveExportStatusModel({ const isExportFinalizing = exportProgress?.phase === "finalizing"; const isRenderingAudio = isExportFinalizing && typeof exportProgress?.audioProgress === "number"; + const rawFinalizingProgress = + typeof exportProgress?.renderProgress === "number" + ? exportProgress.renderProgress + : (exportProgress?.percentage ?? 100); const exportFinalizingProgress = isExportFinalizing - ? Math.min( - typeof exportProgress?.renderProgress === "number" - ? exportProgress.renderProgress - : (exportProgress?.percentage ?? 100), - 100, + ? Math.max( + 0, + Math.min(100, Number.isFinite(rawFinalizingProgress) ? rawFinalizingProgress : 0), ) : null; const exportFinalizingPercent = isExportFinalizing