Keep queueing video extensions while a clip is already generating.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+44
-30
@@ -261,7 +261,6 @@
|
||||
:scripts="directorScripts"
|
||||
v-model:selected-id="directorScriptId"
|
||||
v-model:name="directorScriptName"
|
||||
:disabled="videoBusy"
|
||||
@load="loadDirectorScript"
|
||||
@save="saveDirectorScript"
|
||||
@remove="deleteDirectorScript"
|
||||
@@ -402,7 +401,6 @@
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs text-red-300 hover:text-red-200"
|
||||
:disabled="editBusy"
|
||||
@click="removeEditPass(item.id)"
|
||||
>
|
||||
Remove
|
||||
@@ -415,13 +413,11 @@
|
||||
:placeholder="extraPassPlaceholder"
|
||||
:keep-items="activeKeepPrompts"
|
||||
:keep-heading="keepPromptHeading"
|
||||
:disabled="editBusy"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="w-full rounded-2xl border border-dashed border-white/15 px-4 py-2.5 text-sm text-zinc-300 transition hover:border-amber-300/40 hover:text-amber-100 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="editBusy"
|
||||
@click="queueEditPass"
|
||||
>
|
||||
{{ extraPassButtonLabel }}
|
||||
@@ -521,7 +517,6 @@
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs text-red-300 hover:text-red-200"
|
||||
:disabled="videoBusy"
|
||||
@click="removeQueuedExtension(item.id)"
|
||||
>
|
||||
Remove
|
||||
@@ -569,7 +564,6 @@
|
||||
<button
|
||||
type="button"
|
||||
class="w-full rounded-2xl border border-dashed border-white/15 px-4 py-2.5 text-sm text-zinc-300 transition hover:border-amber-300/40 hover:text-amber-100 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="videoBusy"
|
||||
@click="queueExtension"
|
||||
>
|
||||
+ Queue Extension
|
||||
@@ -1443,11 +1437,12 @@
|
||||
<button
|
||||
type="button"
|
||||
class="w-full rounded-2xl bg-amber-400 px-4 py-2.5 text-sm font-semibold text-zinc-950 transition hover:bg-amber-300 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="!extendPrompt.trim() || lastFrameLoading || videoBusy"
|
||||
:disabled="!extendPrompt.trim()"
|
||||
@click="generateExtension"
|
||||
>
|
||||
Generate Extension
|
||||
{{ videoBusy ? 'Queue extension' : 'Generate Extension' }}
|
||||
</button>
|
||||
<p v-if="videoBusy" class="text-xs text-zinc-500">The current job keeps running in Output. This extension waits in the job queue.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5744,27 +5739,19 @@ async function openExtend(item?: LibraryClip) {
|
||||
async function generateExtension() {
|
||||
const id = clipIdFromPlayer()
|
||||
if (!id || !extendPrompt.value.trim()) return
|
||||
const switching = videoBusy.value
|
||||
statusBusy.value = false
|
||||
videoBusy.value = true
|
||||
watchingLibrary.value = false
|
||||
stopListen('video')
|
||||
videoSettledUi = false
|
||||
progress.value = 1
|
||||
awaitingReveal.value = false
|
||||
concealOutput.value = hideThumbnail.value || currentClip.value?.hideThumbnail === true
|
||||
lockedSave.value = false
|
||||
chainStep.value = 1
|
||||
chainTotal.value = 1
|
||||
chainLabel.value = ''
|
||||
overallProgress.value = 0
|
||||
completedChainStep.value = 0
|
||||
activeChainPlan.value = []
|
||||
statusMessage.value = 'Extracting last frame & stitching extension...'
|
||||
startTimer('video')
|
||||
const hideOut = hideThumbnail.value
|
||||
try {
|
||||
await ensureGenerationNotifyPermission()
|
||||
const started = await $fetch<{ jobId: string; steps: number; hideThumbnail?: boolean; folderLocked?: boolean }>('/api/extend', {
|
||||
const started = await $fetch<{
|
||||
jobId: string
|
||||
studioJobId?: string
|
||||
queued?: boolean
|
||||
steps: number
|
||||
hideThumbnail?: boolean
|
||||
folderLocked?: boolean
|
||||
width?: number
|
||||
height?: number
|
||||
}>('/api/extend', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
clipId: id,
|
||||
@@ -5776,13 +5763,40 @@ async function generateExtension() {
|
||||
}
|
||||
})
|
||||
closeExtend()
|
||||
if (switching) toast('Switched to this extension. The other job will keep saving to the library.')
|
||||
videoJobId.value = started.jobId
|
||||
maxStep.value = started.steps
|
||||
if (started.queued) {
|
||||
outputStudioJobId.value = started.studioJobId || ''
|
||||
outputFocus.value = 'video'
|
||||
videoAwaitingBeast.value = true
|
||||
statusMessage.value = 'Queued. Waiting for Beast to be free.'
|
||||
toast('Queued behind the current job.')
|
||||
await refreshStudioQueue()
|
||||
return
|
||||
}
|
||||
statusBusy.value = false
|
||||
videoBusy.value = true
|
||||
watchingLibrary.value = false
|
||||
stopListen('video')
|
||||
videoSettledUi = false
|
||||
progress.value = 1
|
||||
awaitingReveal.value = false
|
||||
concealOutput.value = started.hideThumbnail === true || hideOut
|
||||
lockedSave.value = false
|
||||
chainStep.value = 1
|
||||
chainTotal.value = 1
|
||||
chainLabel.value = ''
|
||||
overallProgress.value = 0
|
||||
completedChainStep.value = 0
|
||||
activeChainPlan.value = []
|
||||
statusMessage.value = 'Extracting last frame & stitching extension...'
|
||||
startTimer('video')
|
||||
if (started.width && started.height) playerSize.value = { width: started.width, height: started.height }
|
||||
videoJobId.value = started.jobId
|
||||
outputStudioJobId.value = started.studioJobId || ''
|
||||
maxStep.value = started.steps
|
||||
persistActiveJob('video', started.jobId, started.hideThumbnail === true || concealOutput.value, started.folderLocked === true)
|
||||
listen('video', started.jobId, started.hideThumbnail === true || concealOutput.value, started.folderLocked === true)
|
||||
void pollComfyHealth()
|
||||
void refreshStudioQueue()
|
||||
} catch (error: any) {
|
||||
videoBusy.value = false
|
||||
statusBusy.value = false
|
||||
|
||||
Reference in New Issue
Block a user