import type { FFmpeg } from '@ffmpeg/ffmpeg'; import type { ConverterEngine, WASMModuleState } from '@/types/conversion'; /** * WASM module loading state */ const moduleState: WASMModuleState = { ffmpeg: false, imagemagick: false, }; /** * Cached WASM instances */ let ffmpegInstance: FFmpeg | null = null; let imagemagickInstance: any = null; /** * Load FFmpeg WASM module */ export async function loadFFmpeg(): Promise { if (ffmpegInstance && moduleState.ffmpeg) { return ffmpegInstance; } try { const { FFmpeg } = await import('@ffmpeg/ffmpeg'); const { toBlobURL } = await import('@ffmpeg/util'); ffmpegInstance = new FFmpeg(); // Load core and dependencies const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd'; ffmpegInstance.on('log', ({ message }) => { console.log('[FFmpeg]', message); }); await ffmpegInstance.load({ coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'), wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'), }); moduleState.ffmpeg = true; console.log('FFmpeg loaded successfully'); return ffmpegInstance; } catch (error) { console.error('Failed to load FFmpeg:', error); throw new Error('Failed to load FFmpeg WASM module'); } } /** * Load ImageMagick WASM module */ export async function loadImageMagick(): Promise { if (imagemagickInstance && moduleState.imagemagick) { return imagemagickInstance; } try { const { initializeImageMagick } = await import('@imagemagick/magick-wasm'); // Initialize ImageMagick with WASM file from public directory // In production (static export), this will be served from /wasm/magick.wasm const wasmUrl = '/wasm/magick.wasm'; console.log('[ImageMagick] Attempting to load WASM from:', wasmUrl); // Test fetch the WASM file first to debug try { const response = await fetch(wasmUrl); console.log('[ImageMagick] WASM fetch response:', { ok: response.ok, status: response.status, contentType: response.headers.get('content-type'), contentLength: response.headers.get('content-length'), }); if (!response.ok) { throw new Error(`Failed to fetch WASM file: ${response.status} ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); console.log('[ImageMagick] WASM file size:', arrayBuffer.byteLength, 'bytes'); if (arrayBuffer.byteLength === 0) { throw new Error('WASM file is empty'); } // Now initialize with the buffer directly await initializeImageMagick(arrayBuffer); } catch (fetchError) { console.error('[ImageMagick] Failed to fetch WASM:', fetchError); throw fetchError; } const ImageMagick = await import('@imagemagick/magick-wasm'); imagemagickInstance = ImageMagick; moduleState.imagemagick = true; console.log('[ImageMagick] Loaded and initialized successfully'); return imagemagickInstance; } catch (error) { console.error('[ImageMagick] Failed to load:', error); throw new Error(`Failed to load ImageMagick WASM module: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Get loaded module state */ export function getModuleState(): WASMModuleState { return { ...moduleState }; } /** * Check if a specific module is loaded */ export function isModuleLoaded(engine: ConverterEngine): boolean { return moduleState[engine]; } /** * Load appropriate WASM module for converter engine */ export async function loadModule(engine: ConverterEngine): Promise { switch (engine) { case 'ffmpeg': return loadFFmpeg(); case 'imagemagick': return loadImageMagick(); default: throw new Error(`Unknown converter engine: ${engine}`); } } /** * Unload all WASM modules and free memory */ export function unloadAll(): void { if (ffmpegInstance) { // FFmpeg doesn't have an explicit unload method // Just null the instance ffmpegInstance = null; moduleState.ffmpeg = false; } if (imagemagickInstance) { imagemagickInstance = null; moduleState.imagemagick = false; } console.log('All WASM modules unloaded'); }