diff options
| author | Maze <167211895+mazeincoding@users.noreply.github.com> | 2026-01-31 00:20:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-31 00:20:04 +0100 |
| commit | 7bf0984698e43b9aa2dd879f65951318ed410390 (patch) | |
| tree | ccf2cd590a47d550152afc07129cb55c71a9ec35 /apps/web/src/components/editor/audio-waveform.tsx | |
| parent | 0173db99448d1c4c6415dcf15272e17551b48b04 (diff) | |
| download | opencut-7bf0984698e43b9aa2dd879f65951318ed410390.tar.gz | |
codebase overhaul (#697)
Diffstat (limited to 'apps/web/src/components/editor/audio-waveform.tsx')
| -rw-r--r-- | apps/web/src/components/editor/audio-waveform.tsx | 162 |
1 files changed, 0 insertions, 162 deletions
diff --git a/apps/web/src/components/editor/audio-waveform.tsx b/apps/web/src/components/editor/audio-waveform.tsx deleted file mode 100644 index 60406f61..00000000 --- a/apps/web/src/components/editor/audio-waveform.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { useEffect, useRef, useState } from "react"; -import WaveSurfer from "wavesurfer.js"; - -interface AudioWaveformProps { - audioUrl: string; - height?: number; - className?: string; -} - -const AudioWaveform: React.FC<AudioWaveformProps> = ({ - audioUrl, - height = 32, - className = "", -}) => { - const waveformRef = useRef<HTMLDivElement>(null); - const wavesurfer = useRef<WaveSurfer | null>(null); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(false); - - useEffect(() => { - let mounted = true; - let ws = wavesurfer.current; - - const initWaveSurfer = async () => { - if (!waveformRef.current || !audioUrl) return; - - try { - // Clear any existing instance safely - if (ws) { - // Instead of immediately destroying, just set to null - // We'll destroy it outside this function - wavesurfer.current = null; - } - - // Create a fresh instance - const newWaveSurfer = WaveSurfer.create({ - container: waveformRef.current, - waveColor: "rgba(255, 255, 255, 0.6)", - progressColor: "rgba(255, 255, 255, 0.9)", - cursorColor: "transparent", - barWidth: 2, - barGap: 1, - height, - normalize: true, - interact: false, - }); - - // Assign to ref only if component is still mounted - if (mounted) { - wavesurfer.current = newWaveSurfer; - } else { - // Component unmounted during initialization, clean up - try { - newWaveSurfer.destroy(); - } catch (e) { - // Ignore destroy errors - } - return; - } - - // Event listeners - newWaveSurfer.on("ready", () => { - if (mounted) { - setIsLoading(false); - setError(false); - } - }); - - newWaveSurfer.on("error", (err) => { - if (mounted) { - console.error("WaveSurfer error:", err); - setError(true); - setIsLoading(false); - } - }); - - await newWaveSurfer.load(audioUrl); - } catch (err) { - if (mounted) { - console.error("Failed to initialize WaveSurfer:", err); - setError(true); - setIsLoading(false); - } - } - }; - - // First safely destroy previous instance if it exists - if (ws) { - // Use this pattern to safely destroy the previous instance - const wsToDestroy = ws; - // Detach from ref immediately - wavesurfer.current = null; - - // Wait a tick to destroy so any pending operations can complete - requestAnimationFrame(() => { - try { - wsToDestroy.destroy(); - } catch (e) { - // Ignore errors during destroy - } - // Only initialize new instance after destroying the old one - if (mounted) { - initWaveSurfer(); - } - }); - } else { - // No previous instance to clean up, initialize directly - initWaveSurfer(); - } - - return () => { - // Mark component as unmounted - mounted = false; - - // Store reference to current wavesurfer instance - const wsToDestroy = wavesurfer.current; - - // Immediately clear the ref to prevent accessing it after unmount - wavesurfer.current = null; - - // If we have an instance to clean up, do it safely - if (wsToDestroy) { - // Delay destruction to avoid race conditions - requestAnimationFrame(() => { - try { - wsToDestroy.destroy(); - } catch (e) { - // Ignore destroy errors - they're expected - } - }); - } - }; - }, [audioUrl, height]); - - if (error) { - return ( - <div - className={`flex items-center justify-center ${className}`} - style={{ height }} - > - <span className="text-xs text-foreground/60">Audio unavailable</span> - </div> - ); - } - - return ( - <div className={`relative ${className}`}> - {isLoading && ( - <div className="absolute inset-0 flex items-center justify-center"> - <span className="text-xs text-foreground/60">Loading...</span> - </div> - )} - <div - ref={waveformRef} - className={`w-full transition-opacity duration-200 ${isLoading ? "opacity-0" : "opacity-100"}`} - style={{ height }} - /> - </div> - ); -}; - -export default AudioWaveform; |
