diff --git a/src/hooks/useExportQueue.ts b/src/hooks/useExportQueue.ts index 6118a5f..9fa6649 100644 --- a/src/hooks/useExportQueue.ts +++ b/src/hooks/useExportQueue.ts @@ -124,9 +124,43 @@ export function useExportQueue() { // Resolve blob: URLs to persistent server URLs before sending to server-side render const resolvedElements = await resolveBlobUrls(config.timelineElements); + // Also resolve blob URLs in designMD (introVideoUrl, outroVideoUrl, logoUrl) + const resolvedDesignMD = { ...config.designMD }; + const designMDUrlFields: (keyof typeof resolvedDesignMD)[] = [ + 'introVideoUrl', 'outroVideoUrl', 'logoUrl', 'brandAudioUrl', + ]; + for (const field of designMDUrlFields) { + const val = resolvedDesignMD[field]; + if (typeof val === 'string' && val.startsWith('blob:')) { + try { + const res = await fetch(val); + const blob = await res.blob(); + const ext = blob.type.includes('video') ? '.mp4' + : blob.type.includes('audio') ? '.mp3' + : blob.type.includes('png') ? '.png' + : '.jpg'; + const file = new File([blob], `designmd-${String(field)}${ext}`, { type: blob.type }); + const formData = new FormData(); + formData.append('file', file); + const uploadRes = await fetch('/api/upload', { method: 'POST', body: formData }); + if (uploadRes.ok) { + const data = await uploadRes.json(); + // Use Express origin for Remotion compatibility + const electronAPI = (window as any).electronAPI; + const origin = electronAPI?.isElectron + ? 'http://127.0.0.1:3000' + : window.location.origin; + (resolvedDesignMD as any)[field] = `${origin}${data.url}`; + } + } catch (err) { + console.warn(`Failed to resolve blob for designMD.${String(field)}:`, err); + } + } + } + // Strip non-serializable props for render (callbacks, refs, etc.) const inputProps = { - designMD: config.designMD, + designMD: resolvedDesignMD, textOverlay: config.textOverlay, timelineElements: resolvedElements, layers: config.layers,