Pause the queue after the current clip for real, and carry global locks plus labeled permanence stills through generate and shot prompts.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+50
-19
@@ -1,6 +1,6 @@
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { getJob, type Job } from '~/server/utils/jobs'
|
||||
import { getJob, listJobs, type Job } from '~/server/utils/jobs'
|
||||
|
||||
export type ShotQueueStatus = 'idle' | 'running' | 'paused' | 'complete' | 'error'
|
||||
export type ShotSegmentStatus = 'pending' | 'running' | 'complete' | 'error'
|
||||
@@ -12,6 +12,7 @@ export interface ShotQueueSegment {
|
||||
status: ShotSegmentStatus
|
||||
clipId?: string
|
||||
error?: string
|
||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||
}
|
||||
|
||||
export interface ShotQueue {
|
||||
@@ -23,6 +24,7 @@ export interface ShotQueue {
|
||||
updatedAt: number
|
||||
status: ShotQueueStatus
|
||||
autoRun: boolean
|
||||
stopAfterCurrent?: boolean
|
||||
currentClipId?: string
|
||||
currentJobId?: string
|
||||
stillId?: string
|
||||
@@ -42,6 +44,8 @@ export interface ShotQueue {
|
||||
sound?: boolean
|
||||
useIdentityRefs?: boolean
|
||||
referenceStillIds?: Array<string | null>
|
||||
globalLocks?: string
|
||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||
segments: ShotQueueSegment[]
|
||||
lastError?: string
|
||||
}
|
||||
@@ -157,8 +161,10 @@ export async function createShotQueue(params: {
|
||||
sound?: boolean
|
||||
useIdentityRefs?: boolean
|
||||
referenceStillIds?: Array<string | null>
|
||||
initial: { prompt: string; duration: number }
|
||||
extensions: { prompt: string; duration: number }[]
|
||||
globalLocks?: string
|
||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||
initial: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[] }
|
||||
extensions: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[] }[]
|
||||
jobId?: string
|
||||
}): Promise<ShotQueue> {
|
||||
const now = Date.now()
|
||||
@@ -171,6 +177,7 @@ export async function createShotQueue(params: {
|
||||
updatedAt: now,
|
||||
status: 'running',
|
||||
autoRun: params.autoRun,
|
||||
stopAfterCurrent: false,
|
||||
currentJobId: params.jobId,
|
||||
stillId: params.stillId,
|
||||
stillFilename: params.stillFilename,
|
||||
@@ -189,13 +196,16 @@ export async function createShotQueue(params: {
|
||||
sound: params.sound,
|
||||
useIdentityRefs: params.useIdentityRefs,
|
||||
referenceStillIds: params.referenceStillIds,
|
||||
globalLocks: params.globalLocks,
|
||||
permanenceRefs: params.permanenceRefs,
|
||||
segments: [
|
||||
{ index: 0, prompt: params.initial.prompt, duration: params.initial.duration, status: 'running' },
|
||||
{ index: 0, prompt: params.initial.prompt, duration: params.initial.duration, status: 'running', permanenceRefs: params.initial.permanenceRefs },
|
||||
...params.extensions.map((item, index) => ({
|
||||
index: index + 1,
|
||||
prompt: item.prompt,
|
||||
duration: item.duration,
|
||||
status: 'pending' as const
|
||||
status: 'pending' as const,
|
||||
permanenceRefs: item.permanenceRefs
|
||||
}))
|
||||
]
|
||||
}
|
||||
@@ -305,6 +315,7 @@ export async function prepareQueueBurst(owner: string, id: string, count: number
|
||||
delete segment.error
|
||||
})
|
||||
queue.autoRun = count === 'all'
|
||||
queue.stopAfterCurrent = false
|
||||
queue.status = 'running'
|
||||
queue.lastError = undefined
|
||||
queue.updatedAt = Date.now()
|
||||
@@ -341,23 +352,42 @@ export async function finishQueueBurst(owner: string, id: string, paused: boolea
|
||||
})
|
||||
}
|
||||
|
||||
export async function pauseShotQueue(owner: string, id: string) {
|
||||
const jobId = activeJobs.get(id)
|
||||
if (jobId) {
|
||||
const job = getJob(jobId)
|
||||
if (job?.library) job.library.stopAfterCurrent = true
|
||||
if (job?.library) job.library.queueAutoRun = false
|
||||
function liveJobForQueue(id: string): Job | undefined {
|
||||
const mapped = activeJobs.get(id)
|
||||
if (mapped) {
|
||||
const job = getJob(mapped)
|
||||
if (job) return job
|
||||
}
|
||||
return listJobs().find(job => (
|
||||
job.library?.queueId === id
|
||||
&& (job.status === 'queued' || job.status === 'uploading' || job.status === 'running')
|
||||
))
|
||||
}
|
||||
|
||||
export async function setShotQueuePause(owner: string, id: string, pause: boolean) {
|
||||
const live = liveJobForQueue(id)
|
||||
if (live?.library) {
|
||||
live.library.stopAfterCurrent = pause
|
||||
if (pause) live.library.queueAutoRun = false
|
||||
}
|
||||
return updateShotQueue(owner, id, (queue) => {
|
||||
queue.autoRun = false
|
||||
if (queue.status === 'running') {
|
||||
queue.lastError = undefined
|
||||
} else if (queue.status !== 'complete') {
|
||||
queue.status = 'paused'
|
||||
if (pause) {
|
||||
queue.autoRun = false
|
||||
queue.stopAfterCurrent = true
|
||||
if (queue.status === 'running') queue.lastError = undefined
|
||||
else if (queue.status !== 'complete') queue.status = 'paused'
|
||||
} else {
|
||||
queue.stopAfterCurrent = false
|
||||
if (live?.library) live.library.queueAutoRun = queue.autoRun === true
|
||||
if (queue.status === 'paused') queue.status = 'idle'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function pauseShotQueue(owner: string, id: string) {
|
||||
return setShotQueuePause(owner, id, true)
|
||||
}
|
||||
|
||||
export async function deleteShotQueue(owner: string, id: string) {
|
||||
if (activeJobs.has(id)) {
|
||||
throw createError({ statusCode: 409, statusMessage: 'Stop this batch before deleting it' })
|
||||
@@ -395,10 +425,10 @@ export function listOwnersWithQueues() {
|
||||
.filter(owner => existsSync(queuesPath(owner)))
|
||||
}
|
||||
|
||||
export function remainingFromQueue(queue: ShotQueue): { prompt: string; duration: number }[] {
|
||||
export function remainingFromQueue(queue: ShotQueue): { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[] }[] {
|
||||
return queue.segments
|
||||
.filter(segment => segment.index > 0)
|
||||
.map(segment => ({ prompt: segment.prompt, duration: segment.duration }))
|
||||
.map(segment => ({ prompt: segment.prompt, duration: segment.duration, permanenceRefs: segment.permanenceRefs }))
|
||||
}
|
||||
|
||||
export function lastCompletedIndex(queue: ShotQueue) {
|
||||
@@ -411,6 +441,7 @@ export function liveSegmentPrompt(queue: ShotQueue, extensionIndex: number) {
|
||||
const segment = queue.segments.find(item => item.index === extensionIndex + 1)
|
||||
return {
|
||||
prompt: segment?.prompt || '',
|
||||
duration: segment?.duration || 5
|
||||
duration: segment?.duration || 5,
|
||||
permanenceRefs: segment?.permanenceRefs
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user