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:
+49
-2
@@ -6,6 +6,7 @@ import { randomBytes, scrypt, timingSafeEqual } from 'node:crypto'
|
||||
import { promisify } from 'node:util'
|
||||
import type { H3Event } from 'h3'
|
||||
import { extractFirstFrame, extractLastFrame } from '~/server/utils/ffmpeg'
|
||||
import { normalizePermanenceRefs, type PermanenceRef } from '~/utils/globalLocks'
|
||||
|
||||
const scryptAsync = promisify(scrypt)
|
||||
|
||||
@@ -43,6 +44,8 @@ export interface LibraryClip {
|
||||
stillId?: string
|
||||
sound?: boolean
|
||||
hideInput?: boolean
|
||||
globalLocks?: string
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
}
|
||||
|
||||
export type StillRole = 'input' | 'output'
|
||||
@@ -78,6 +81,7 @@ export interface PublicFolder {
|
||||
export interface QueuedExtension {
|
||||
prompt: string
|
||||
duration: number
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
}
|
||||
|
||||
export interface RetryDraft {
|
||||
@@ -104,6 +108,9 @@ export interface RetryDraft {
|
||||
scheduler?: string
|
||||
extensions?: QueuedExtension[]
|
||||
workflow?: import('~/utils/videoModels').VideoWorkflowId
|
||||
globalLocks?: string
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
shotPermanenceRefs?: PermanenceRef[][]
|
||||
}
|
||||
|
||||
interface Catalog {
|
||||
@@ -1120,6 +1127,9 @@ export async function saveRetryDraft(params: {
|
||||
scheduler?: string
|
||||
extensions?: QueuedExtension[]
|
||||
workflow?: import('~/utils/videoModels').VideoWorkflowId
|
||||
globalLocks?: string
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
shotPermanenceRefs?: PermanenceRef[][]
|
||||
}) {
|
||||
return mutate(params.ownerKey, (catalog) => {
|
||||
const existing = params.id ? catalog.drafts.find(item => item.id === params.id) : undefined
|
||||
@@ -1146,7 +1156,10 @@ export async function saveRetryDraft(params: {
|
||||
samplerName: params.samplerName,
|
||||
scheduler: params.scheduler,
|
||||
extensions: params.extensions?.length ? params.extensions : undefined,
|
||||
workflow: params.workflow
|
||||
workflow: params.workflow,
|
||||
globalLocks: params.globalLocks,
|
||||
permanenceRefs: params.permanenceRefs,
|
||||
shotPermanenceRefs: params.shotPermanenceRefs
|
||||
}
|
||||
catalog.drafts = [draft, ...catalog.drafts.filter(item => item.id !== draft.id)].slice(0, 20)
|
||||
return draft
|
||||
@@ -1298,6 +1311,8 @@ export async function saveClip(params: {
|
||||
workflow?: import('~/utils/videoModels').VideoWorkflowId
|
||||
stillId?: string
|
||||
sound?: boolean
|
||||
globalLocks?: string
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
}) {
|
||||
const catalog = readCatalog(params.ownerKey)
|
||||
const folder = catalog.folders.find(item => item.id === params.folderId) || catalog.folders[0]
|
||||
@@ -1326,7 +1341,9 @@ export async function saveClip(params: {
|
||||
workflow: params.workflow,
|
||||
stillId: params.stillId,
|
||||
sound: params.sound,
|
||||
hideInput: params.hideInput === true
|
||||
hideInput: params.hideInput === true,
|
||||
globalLocks: params.globalLocks,
|
||||
permanenceRefs: params.permanenceRefs?.length ? normalizePermanenceRefs(params.permanenceRefs) : undefined
|
||||
}
|
||||
mkdirSync(clipDir(params.ownerKey, clip.id), { recursive: true })
|
||||
const videoPath = clipVideoPath(params.ownerKey, clip.id)
|
||||
@@ -1413,6 +1430,36 @@ export function moveClipFamily(owner: string, id: string, folderId: string) {
|
||||
})
|
||||
}
|
||||
|
||||
export function patchClipMeta(owner: string, id: string, patch: {
|
||||
globalLocks?: string
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
family?: boolean
|
||||
}) {
|
||||
return mutate(owner, (catalog) => {
|
||||
const clip = catalog.clips.find(item => item.id === id)
|
||||
if (!clip) throw createError({ statusCode: 404, statusMessage: 'Clip not found' })
|
||||
const family = patch.family ? clipsInSameFamily(catalog, clip) : [clip]
|
||||
if (typeof patch.globalLocks === 'string') {
|
||||
const locks = patch.globalLocks.trim()
|
||||
for (const item of family) {
|
||||
if (locks) item.globalLocks = locks
|
||||
else delete item.globalLocks
|
||||
}
|
||||
}
|
||||
if (patch.permanenceRefs) {
|
||||
const refs = normalizePermanenceRefs(patch.permanenceRefs)
|
||||
if (patch.family) {
|
||||
for (const item of family) {
|
||||
if (refs.length) item.permanenceRefs = refs
|
||||
else delete item.permanenceRefs
|
||||
}
|
||||
} else if (refs.length) clip.permanenceRefs = refs
|
||||
else delete clip.permanenceRefs
|
||||
}
|
||||
return patch.family ? family : clip
|
||||
})
|
||||
}
|
||||
|
||||
export function renameClip(owner: string, id: string, name: string) {
|
||||
const trimmed = name.trim().slice(0, 80)
|
||||
if (!trimmed) throw createError({ statusCode: 400, statusMessage: 'A name is required' })
|
||||
|
||||
Reference in New Issue
Block a user