diff --git a/packages/producer/src/services/render/shared.ts b/packages/producer/src/services/render/shared.ts index f9f4ac487..1998b123b 100644 --- a/packages/producer/src/services/render/shared.ts +++ b/packages/producer/src/services/render/shared.ts @@ -17,6 +17,7 @@ import type { AudioElement, EngineConfig, ImageElement, VideoElement } from "@hy import type { CompiledComposition } from "../htmlCompiler.js"; import { defaultLogger, type ProducerLogger } from "../../logger.js"; import { isPathInside } from "../../utils/paths.js"; +import type { ProgressCallback, RenderJob, RenderStatus } from "../renderOrchestrator.js"; export interface CompositionMetadata { duration: number; @@ -202,3 +203,26 @@ export function applyRenderModeHints( reasons: compiled.renderModeHints.reasons.map((reason) => reason.message), }); } + +/** + * Mutate the `RenderJob` view of the pipeline's progress and fire the + * caller's `onProgress` callback. Hoisted here (out of `renderOrchestrator.ts`) + * so the stage modules can call it without forming a runtime cycle. + * + * `completedAt` is stamped on the terminal `"failed"` / `"complete"` + * transitions so callers that poll the job state can tell when the + * pipeline finished. + */ +export function updateJobStatus( + job: RenderJob, + status: RenderStatus, + stage: string, + progress: number, + onProgress?: ProgressCallback, +): void { + job.status = status; + job.currentStage = stage; + job.progress = progress; + if (status === "failed" || status === "complete") job.completedAt = new Date(); + if (onProgress) onProgress(job, stage); +} diff --git a/packages/producer/src/services/render/stages/assembleStage.ts b/packages/producer/src/services/render/stages/assembleStage.ts index 0697c5322..004dad3e6 100644 --- a/packages/producer/src/services/render/stages/assembleStage.ts +++ b/packages/producer/src/services/render/stages/assembleStage.ts @@ -17,11 +17,8 @@ */ import { applyFaststart, muxVideoWithAudio } from "@hyperframes/engine"; -import { - updateJobStatus, - type ProgressCallback, - type RenderJob, -} from "../../renderOrchestrator.js"; +import type { ProgressCallback, RenderJob } from "../../renderOrchestrator.js"; +import { updateJobStatus } from "../shared.js"; export interface AssembleStageInput { job: RenderJob; diff --git a/packages/producer/src/services/render/stages/captureHdrStage.ts b/packages/producer/src/services/render/stages/captureHdrStage.ts index ee48c7452..0d7420c87 100644 --- a/packages/producer/src/services/render/stages/captureHdrStage.ts +++ b/packages/producer/src/services/render/stages/captureHdrStage.ts @@ -86,9 +86,8 @@ import { compositeHdrFrame, createHdrPerfCollector, resolveCompositeTransfer, - updateJobStatus, } from "../../renderOrchestrator.js"; -import { type CompositionMetadata } from "../shared.js"; +import { updateJobStatus, type CompositionMetadata } from "../shared.js"; export interface CaptureHdrStageInput { job: RenderJob; diff --git a/packages/producer/src/services/render/stages/captureStage.ts b/packages/producer/src/services/render/stages/captureStage.ts index b0ce1c069..2bc468bf0 100644 --- a/packages/producer/src/services/render/stages/captureStage.ts +++ b/packages/producer/src/services/render/stages/captureStage.ts @@ -51,11 +51,11 @@ import type { FileServerHandle } from "../../fileServer.js"; import type { ProducerLogger } from "../../../logger.js"; import { executeDiskCaptureWithAdaptiveRetry, - updateJobStatus, type CaptureAttemptSummary, type ProgressCallback, type RenderJob, } from "../../renderOrchestrator.js"; +import { updateJobStatus } from "../shared.js"; export interface CaptureStageInput { fileServer: FileServerHandle; diff --git a/packages/producer/src/services/render/stages/captureStreamingStage.ts b/packages/producer/src/services/render/stages/captureStreamingStage.ts index 75bc3a8e0..d1a87eccc 100644 --- a/packages/producer/src/services/render/stages/captureStreamingStage.ts +++ b/packages/producer/src/services/render/stages/captureStreamingStage.ts @@ -58,11 +58,8 @@ import { } from "@hyperframes/engine"; import type { FileServerHandle } from "../../fileServer.js"; import type { ProducerLogger } from "../../../logger.js"; -import { - updateJobStatus, - type ProgressCallback, - type RenderJob, -} from "../../renderOrchestrator.js"; +import type { ProgressCallback, RenderJob } from "../../renderOrchestrator.js"; +import { updateJobStatus } from "../shared.js"; /** * Pre-built ffmpeg streaming-encoder options, exactly matching the diff --git a/packages/producer/src/services/render/stages/encodeStage.ts b/packages/producer/src/services/render/stages/encodeStage.ts index eca96c0cc..aa5b39df7 100644 --- a/packages/producer/src/services/render/stages/encodeStage.ts +++ b/packages/producer/src/services/render/stages/encodeStage.ts @@ -34,11 +34,8 @@ import { getEncoderPreset, } from "@hyperframes/engine"; import type { ProducerLogger } from "../../../logger.js"; -import { - updateJobStatus, - type ProgressCallback, - type RenderJob, -} from "../../renderOrchestrator.js"; +import type { ProgressCallback, RenderJob } from "../../renderOrchestrator.js"; +import { updateJobStatus } from "../shared.js"; export interface EncodeStageInput { job: RenderJob; diff --git a/packages/producer/src/services/renderOrchestrator.ts b/packages/producer/src/services/renderOrchestrator.ts index 22c330e6e..60bfd2467 100644 --- a/packages/producer/src/services/renderOrchestrator.ts +++ b/packages/producer/src/services/renderOrchestrator.ts @@ -92,6 +92,7 @@ import { type CompiledComposition } from "./htmlCompiler.js"; import { defaultLogger, type ProducerLogger } from "../logger.js"; import { isPathInside } from "../utils/paths.js"; import { type HdrImageTransferCache } from "./hdrImageTransferCache.js"; +import { updateJobStatus } from "./render/shared.js"; import { runCompileStage } from "./render/stages/compileStage.js"; import { runProbeStage } from "./render/stages/probeStage.js"; import { runExtractVideosStage } from "./render/stages/extractVideosStage.js"; @@ -544,20 +545,6 @@ export class RenderCancelledError extends Error { } } -export function updateJobStatus( - job: RenderJob, - status: RenderStatus, - stage: string, - progress: number, - onProgress?: ProgressCallback, -): void { - job.status = status; - job.currentStage = stage; - job.progress = progress; - if (status === "failed" || status === "complete") job.completedAt = new Date(); - if (onProgress) onProgress(job, stage); -} - function installDebugLogger(logPath: string, log: ProducerLogger = defaultLogger): () => void { const origLog = console.log; const origError = console.error;