diff --git a/electron/main.ts b/electron/main.ts index 9d195a9d..c792ba3e 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -882,9 +882,11 @@ app.whenReady().then(async () => { if (IS_SMOKE_EXPORT) { await logSmokeExportGpuDiagnostics(); - console.log( - `[smoke-export] Starting editor smoke export for ${process.env.RECORDLY_SMOKE_EXPORT_INPUT ?? ""}`, - ); + const smokeSource = + process.env.RECORDLY_SMOKE_EXPORT_PROJECT ?? + process.env.RECORDLY_SMOKE_EXPORT_INPUT ?? + ""; + console.log(`[smoke-export] Starting editor smoke export for ${smokeSource}`); createEditorWindowWrapper(); return; } diff --git a/electron/windows.ts b/electron/windows.ts index be618617..5ab6675a 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -89,6 +89,15 @@ function getEditorWindowQuery(): Record { if (process.env.RECORDLY_SMOKE_EXPORT_MAX_PENDING_FRAMES) { query.smokeMaxPendingFrames = process.env.RECORDLY_SMOKE_EXPORT_MAX_PENDING_FRAMES; } + if (process.env.RECORDLY_SMOKE_EXPORT_PROJECT) { + query.smokeProject = process.env.RECORDLY_SMOKE_EXPORT_PROJECT; + } + if (process.env.RECORDLY_SMOKE_EXPORT_QUALITY) { + query.smokeQuality = process.env.RECORDLY_SMOKE_EXPORT_QUALITY; + } + if (process.env.RECORDLY_SMOKE_EXPORT_FPS) { + query.smokeFps = process.env.RECORDLY_SMOKE_EXPORT_FPS; + } } return query; diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index 9d0f4ece..919ed14e 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -57,6 +57,7 @@ import { GifExporter, type GifFrameRate, type GifSizePreset, + isValidMp4FrameRate, ModernVideoExporter, probeSupportedMp4Dimensions, type SupportedMp4Dimensions, @@ -219,6 +220,9 @@ type SmokeExportConfig = { maxEncodeQueue?: number; maxDecodeQueue?: number; maxPendingFrames?: number; + projectPath?: string | null; + quality?: ExportQuality; + fps?: ExportMp4FrameRate; }; async function writeSmokeExportReport( @@ -290,6 +294,19 @@ function parseSmokeExportNonNegativeNumber(value: string | null): number | undef return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined; } +function parseSmokeExportQuality(value: string | null): ExportQuality | undefined { + if (value === "medium" || value === "good" || value === "high" || value === "source") { + return value; + } + return undefined; +} + +function parseSmokeExportFps(value: string | null): ExportMp4FrameRate | undefined { + if (value === null) return undefined; + const parsed = Number.parseInt(value, 10); + return isValidMp4FrameRate(parsed) ? parsed : undefined; +} + function getSmokeExportConfig(search: string): SmokeExportConfig { const params = new URLSearchParams(search); const enabled = params.get("smokeExport") === "1"; @@ -340,6 +357,9 @@ function getSmokeExportConfig(search: string): SmokeExportConfig { maxPendingFrames: enabled ? parseSmokeExportNumber(params.get("smokeMaxPendingFrames")) : undefined, + projectPath: enabled ? params.get("smokeProject") : null, + quality: enabled ? parseSmokeExportQuality(params.get("smokeQuality")) : undefined, + fps: enabled ? parseSmokeExportFps(params.get("smokeFps")) : undefined, }; } @@ -1771,6 +1791,32 @@ export default function VideoEditor() { useEffect(() => { async function loadInitialData() { try { + if (smokeExportConfig.enabled && smokeExportConfig.projectPath) { + const projectResult = await window.electronAPI.openProjectFileAtPath( + smokeExportConfig.projectPath, + ); + if (!projectResult.success || !projectResult.project) { + setError( + `Smoke export failed to load project ${smokeExportConfig.projectPath}: ${ + projectResult.error || projectResult.message || "unknown error" + }`, + ); + return; + } + const restored = await applyLoadedProject( + projectResult.project, + projectResult.path ?? smokeExportConfig.projectPath, + ); + if (!restored) { + setError( + `Smoke export could not apply project ${smokeExportConfig.projectPath}`, + ); + return; + } + setError(null); + return; + } + if (smokeExportConfig.enabled) { if (!smokeExportConfig.inputPath) { setError("Smoke export input path is missing."); @@ -1884,6 +1930,7 @@ export default function VideoEditor() { initialEditorPreferences, smokeExportConfig.enabled, smokeExportConfig.inputPath, + smokeExportConfig.projectPath, smokeExportConfig.webcamInputPath, smokeExportConfig.webcamShadow, smokeExportConfig.webcamSize, @@ -3949,13 +3996,17 @@ export default function VideoEditor() { } } else { // MP4 Export - const quality = settings.quality ?? exportQuality; + const quality = smokeExportConfig.enabled + ? (smokeExportConfig.quality ?? settings.quality ?? exportQuality) + : (settings.quality ?? exportQuality); const encodingMode = smokeExportConfig.enabled ? (smokeExportConfig.encodingMode ?? settings.encodingMode ?? exportEncodingMode) : (settings.encodingMode ?? exportEncodingMode); - const selectedMp4FrameRate = settings.mp4FrameRate ?? mp4FrameRate; + const selectedMp4FrameRate = smokeExportConfig.enabled + ? (smokeExportConfig.fps ?? settings.mp4FrameRate ?? mp4FrameRate) + : (settings.mp4FrameRate ?? mp4FrameRate); const pipelineModel = smokeExportConfig.enabled ? (smokeExportConfig.pipelineModel ?? (smokeExportConfig.useNativeExport ? "modern" : "legacy"))