diff --git a/server/utils/studioQueue.ts b/server/utils/studioQueue.ts index e2a5e67..f73de79 100644 --- a/server/utils/studioQueue.ts +++ b/server/utils/studioQueue.ts @@ -1869,8 +1869,9 @@ export async function toggleStudioQueuePause(owner: string, options: { } export async function onStudioQueueBurstStarted(owner: string, queueId: string, liveJobId: string) { - const { isShotQueueCancelled } = await import('~/server/utils/shotQueue') + const { isShotQueueCancelled, getShotQueue } = await import('~/server/utils/shotQueue') if (isShotQueueCancelled(queueId)) return + const queue = getShotQueue(owner, queueId) await mutateStore(owner, (store) => { const row = store.jobs.find(job => job.shotQueueId === queueId) if (!row || row.status === 'cancelled') { @@ -1882,6 +1883,11 @@ export async function onStudioQueueBurstStarted(owner: string, queueId: string, row.pauseAfterCurrent = false row.pausedByUser = false row.holdForCutIn = false + // Run remaining / auto-run bursts must resume the rest without another click. + if (queue?.autoRun === true) { + row.resumeAutoRun = true + row.payload.queueAutoRun = true + } row.updatedAt = Date.now() syncPausedFlag(store) }) diff --git a/server/utils/videoChain.ts b/server/utils/videoChain.ts index c13c260..80a7345 100644 --- a/server/utils/videoChain.ts +++ b/server/utils/videoChain.ts @@ -20,6 +20,7 @@ import { isShotQueueCancelled, lastCompletedIndex, liveSegmentPrompt, + pendingSegmentCount, prepareQueueBurst, remainingFromQueue, setQueueJob, @@ -276,7 +277,10 @@ function chainShouldHold(job: Job) { ? getShotQueue(job.library.ownerKey, job.library.queueId) : null if (job.library.queueId && !queue) return true - if (queue?.stopAfterCurrent || queue?.status === 'paused') return true + if (queue?.stopAfterCurrent) return true + // A stale "paused" flag used to abort auto-run mid-batch after finishQueueBurst. + // Only honor paused when this live job is not explicitly auto-running. + if (queue?.status === 'paused' && job.library.queueAutoRun !== true) return true return false } @@ -319,9 +323,12 @@ export async function continueQueuedExtensions( const liveQueue = job.library.queueId ? getShotQueue(job.library.ownerKey, job.library.queueId) : null - if (liveQueue?.stopAfterCurrent || liveQueue?.autoRun === false) { - if (liveQueue.stopAfterCurrent) job.library.stopAfterCurrent = true - if (liveQueue.autoRun === false) job.library.queueAutoRun = false + // User pause / cut-in only. Do not let a stale autoRun=false on disk cancel an + // in-flight "run remaining" / checkbox auto-run batch (options.autoRun). + if (liveQueue?.stopAfterCurrent) { + job.library.stopAfterCurrent = true + } else if (liveQueue?.autoRun === false && options.autoRun !== true) { + job.library.queueAutoRun = false } if (chainShouldHold(job)) { job.library.stopAfterCurrent = true @@ -494,12 +501,24 @@ export async function continueQueuedExtensions( const paused = job.status !== 'error' && job.status !== 'cancelled' const hold = job.library.stopAfterCurrent === true && paused if (hold && job.status === 'running') job.status = 'complete' + // Keep autoRun on the shot queue when this burst was an explicit run-all and more + // shots remain — finishQueueBurst used to clear it and force one-click-per-shot. + const keepAuto = autoRun && !hold && job.status !== 'error' && job.status !== 'cancelled' + if (keepAuto && job.library) job.library.queueAutoRun = true await finishQueueBurst( job.library.ownerKey, job.library.queueId, hold || (paused && !job.library.queueAutoRun), job.status === 'error' || job.status === 'cancelled' ? (job.error || 'Stopped') : undefined ).catch(() => null) + if (keepAuto) { + await updateShotQueue(job.library.ownerKey, job.library.queueId, (queue) => { + if (pendingSegmentCount(queue) > 0 && queue.status !== 'complete' && queue.status !== 'error') { + queue.autoRun = true + if (queue.status === 'paused') queue.status = 'idle' + } + }).catch(() => null) + } setQueueJob(job.library.queueId, null) } } diff --git a/server/utils/watch.ts b/server/utils/watch.ts index acc2bd8..d07649d 100644 --- a/server/utils/watch.ts +++ b/server/utils/watch.ts @@ -363,9 +363,9 @@ export function watchComfyJob(job: Job, options: { persist?: boolean } = {}): Pr }) deletePendingJob(job.id) job.saving = false - // Persist path: clear the studio "Generating" row as soon as the library save - // finishes. Waiting for runGeneration's finally used to leave jobs stuck in the queue. - if (persist && job.library?.ownerKey) { + // Only settle the studio row when this live job is done with the chain. + // Settling while chainContinuing killed overnight auto-run after every shot. + if (persist && job.library?.ownerKey && !job.library.chainContinuing) { const { onLiveVideoSettled } = await import('~/server/utils/studioQueue') await onLiveVideoSettled(job).catch(() => null) }