diff --git a/src/components/TrimControl.tsx b/src/components/TrimControl.tsx index d48bdd69..bdc1f61e 100644 --- a/src/components/TrimControl.tsx +++ b/src/components/TrimControl.tsx @@ -25,7 +25,11 @@ export default function TrimControl({ recipe, onChange, duration, file }: Props) recipe.trimStart.toString() ); - const { waveform, isLoading: waveformLoading } = useAudioWaveform(file); + const { + waveform, + isLoading: waveformLoading, + waveformError, + } = useAudioWaveform(file); const hasAudio = waveform.length > 0; useEffect(() => { @@ -317,6 +321,11 @@ export default function TrimControl({ recipe, onChange, duration, file }: Props) {formatDuration(duration)}
)} + {waveformError && ( ++ {waveformError} +
+ )} {recipe.trimEnd !== null && recipe.trimEnd - recipe.trimStart < MIN_CLIP_DURATION && (
diff --git a/src/hooks/__tests__/useAudioWaveform.test.tsx b/src/hooks/__tests__/useAudioWaveform.test.tsx
new file mode 100644
index 00000000..5064a9cc
--- /dev/null
+++ b/src/hooks/__tests__/useAudioWaveform.test.tsx
@@ -0,0 +1,26 @@
+import { renderHook, waitFor } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import {
+ MAX_WAVEFORM_FILE_SIZE_BYTES,
+ useAudioWaveform,
+} from "../useAudioWaveform";
+
+describe("useAudioWaveform", () => {
+ it("skips waveform decoding for files that are too large", async () => {
+ const file = new File(["video"], "large-video.mp4", { type: "video/mp4" });
+ Object.defineProperty(file, "size", {
+ value: MAX_WAVEFORM_FILE_SIZE_BYTES + 1,
+ });
+ const arrayBufferSpy = vi.spyOn(file, "arrayBuffer");
+
+ const { result } = renderHook(() => useAudioWaveform(file));
+
+ await waitFor(() => {
+ expect(result.current.isLoading).toBe(false);
+ expect(result.current.waveformError).toMatch(/larger than 50 MB/i);
+ });
+
+ expect(result.current.waveform).toEqual([]);
+ expect(arrayBufferSpy).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/hooks/useAudioWaveform.ts b/src/hooks/useAudioWaveform.ts
index 25ed57d5..13e07889 100644
--- a/src/hooks/useAudioWaveform.ts
+++ b/src/hooks/useAudioWaveform.ts
@@ -3,6 +3,9 @@
import { useEffect, useState } from "react";
const DEFAULT_BAR_COUNT = 96;
+export const MAX_WAVEFORM_FILE_SIZE_BYTES = 50 * 1024 * 1024;
+const LARGE_FILE_WAVEFORM_MESSAGE =
+ "Waveform preview is disabled for files larger than 50 MB.";
type BrowserWindow = Window &
typeof globalThis & {
@@ -33,6 +36,7 @@ export function useAudioWaveform(
) {
const [waveform, setWaveform] = useState