fix: resolve blob URLs in designMD before Remotion render

- introVideoUrl, outroVideoUrl, logoUrl, brandAudioUrl can contain
  blob: URLs from the brand editor that Remotion can't access
- Now uploads these to Express and replaces with persistent URLs
- Uses correct Express origin for Electron compatibility
This commit is contained in:
2026-06-02 04:49:21 -05:00
parent 7c4196475c
commit 0aa44afa43
+35 -1
View File
@@ -124,9 +124,43 @@ export function useExportQueue() {
// Resolve blob: URLs to persistent server URLs before sending to server-side render // Resolve blob: URLs to persistent server URLs before sending to server-side render
const resolvedElements = await resolveBlobUrls(config.timelineElements); 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.) // Strip non-serializable props for render (callbacks, refs, etc.)
const inputProps = { const inputProps = {
designMD: config.designMD, designMD: resolvedDesignMD,
textOverlay: config.textOverlay, textOverlay: config.textOverlay,
timelineElements: resolvedElements, timelineElements: resolvedElements,
layers: config.layers, layers: config.layers,