Add default video length setting and inherit duration when extending.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+27
-16
@@ -238,7 +238,7 @@
|
||||
@remove="deleteDirectorScript"
|
||||
/>
|
||||
<p v-if="shotScriptMode && studioMode === 'video'" class="mb-2 text-xs text-zinc-500">
|
||||
Paste a block, or load a saved Director script. Text before the first marker is shot 1. Put <span class="font-medium text-zinc-300">shot 2</span>, <span class="font-medium text-zinc-300">shot 3</span> on their own lines to queue extensions — a line like <span class="font-medium text-zinc-300">Shot Type</span> will not start a new shot. Every shot uses the duration slider. Global locks are inherited; each shot should add one beat.
|
||||
Paste a block, or load a saved Director script. Text before the first marker is shot 1. Put <span class="font-medium text-zinc-300">shot 2</span>, <span class="font-medium text-zinc-300">shot 3</span> on their own lines to queue extensions — a line like <span class="font-medium text-zinc-300">Shot Type</span> will not start a new shot. Queued shots use the duration slider; Extend copies the length of the clip you are extending. Global locks are inherited; each shot should add one beat.
|
||||
<span v-if="identityPrompting"> Character stills ride along as extra pictures. Picture 1 is the current frame (last frame after shot 1), not the original start still.</span>
|
||||
</p>
|
||||
<p v-else-if="identityPrompting" class="mb-2 text-xs text-zinc-500">
|
||||
@@ -2298,6 +2298,12 @@ import {
|
||||
type VideoEngineId,
|
||||
type VideoStartId
|
||||
} from '~/utils/videoModels'
|
||||
import {
|
||||
VIDEO_DURATION_DEFAULT,
|
||||
clampVideoDuration,
|
||||
clipPartDuration,
|
||||
defaultVideoDurationPref
|
||||
} from '~/utils/videoDuration'
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const route = useRoute()
|
||||
@@ -2537,7 +2543,7 @@ const cfgTouched = ref(false)
|
||||
const fps = ref(24)
|
||||
const samplerName = ref('res_multistep')
|
||||
const scheduler = ref('simple')
|
||||
const duration = ref(5)
|
||||
const duration = ref(VIDEO_DURATION_DEFAULT)
|
||||
const seedInput = ref('random')
|
||||
const inputSeed = ref('')
|
||||
|
||||
@@ -2653,7 +2659,7 @@ const extendClipId = ref('')
|
||||
const extendPrompt = ref('')
|
||||
const extendPromptPre = ref('')
|
||||
const extendPromptPost = ref('')
|
||||
const extendDuration = ref(5)
|
||||
const extendDuration = ref(VIDEO_DURATION_DEFAULT)
|
||||
const lastFrameUrl = ref('')
|
||||
const lastFrameLoading = ref(false)
|
||||
const lastFrameRevealed = ref(false)
|
||||
@@ -3933,6 +3939,8 @@ onMounted(async () => {
|
||||
activeQueueId.value = localStorage.getItem(QUEUE_STORE) || ''
|
||||
const savedPreset = localStorage.getItem('aigen-prompt-preset')
|
||||
if (savedPreset) recommendPresetId.value = savedPreset
|
||||
duration.value = defaultVideoDurationPref()
|
||||
extendDuration.value = duration.value
|
||||
} catch { /* ignore */ }
|
||||
applyInstancePrivacy()
|
||||
bindConcealListeners()
|
||||
@@ -4098,8 +4106,7 @@ watch(imageV2LoraStack, (value) => {
|
||||
}, { deep: true })
|
||||
|
||||
function clampDuration(value: number) {
|
||||
if (!Number.isFinite(value)) return 5
|
||||
return Math.min(120, Math.max(0.5, Math.round(value * 10) / 10))
|
||||
return clampVideoDuration(value, defaultVideoDurationPref())
|
||||
}
|
||||
|
||||
function clampCfg(value: number) {
|
||||
@@ -5188,7 +5195,9 @@ function studioJobStatusLabel(job: { status: string; cutIn?: boolean; holdForCut
|
||||
}
|
||||
|
||||
function studioJobShotLine(job: { kind?: string; shotCount: number; completedCount?: number; status: string }) {
|
||||
if (job.kind === 'music') return 'ACE-Step'
|
||||
if (job.kind === 'music') {
|
||||
return String(job.payload?.engine || '').toLowerCase() === 'yue' ? 'YuE' : 'ACE-Step'
|
||||
}
|
||||
if (job.kind === 'edit') {
|
||||
const total = job.shotCount || 1
|
||||
return total <= 1 ? 'image edit' : `${total} passes`
|
||||
@@ -5588,11 +5597,13 @@ async function resumeActiveJob() {
|
||||
jobId?: string | null
|
||||
video?: { jobId?: string; hideThumbnail?: boolean; folderLocked?: boolean }
|
||||
edit?: { jobId?: string; hideThumbnail?: boolean; folderLocked?: boolean }
|
||||
music?: { jobId?: string }
|
||||
hideThumbnail?: boolean
|
||||
folderLocked?: boolean
|
||||
} | null>('/api/generate/active').catch(() => null)
|
||||
|
||||
const videoId = storedVideo?.jobId || active?.video?.jobId || (!active?.edit?.jobId ? active?.jobId : null) || ''
|
||||
// Never fall back to top-level jobId — that used to steal live music jobs into Video Output.
|
||||
const videoId = storedVideo?.jobId || active?.video?.jobId || ''
|
||||
const editId = storedEdit?.jobId || active?.edit?.jobId || ''
|
||||
|
||||
if (videoId) {
|
||||
@@ -5785,13 +5796,10 @@ function stillFileName(still?: Pick<LibraryStill, 'name' | 'filename'> | null) {
|
||||
}
|
||||
|
||||
function clipGenerateDuration(item: LibraryClip) {
|
||||
if (item.parentClipId) {
|
||||
const parent = clips.value.find(clip => clip.id === item.parentClipId)
|
||||
if (parent?.duration && item.duration && item.duration > parent.duration + 0.4) {
|
||||
return clampDuration(item.duration - parent.duration)
|
||||
}
|
||||
}
|
||||
return clampDuration(Number(item.duration) || 5)
|
||||
const parent = item.parentClipId
|
||||
? clips.value.find(clip => clip.id === item.parentClipId)
|
||||
: null
|
||||
return clipPartDuration(item, parent)
|
||||
}
|
||||
|
||||
function familyPartsFor(item: LibraryClip) {
|
||||
@@ -6043,7 +6051,9 @@ async function openExtend(item?: LibraryClip) {
|
||||
extendPromptPre.value = parts.pre
|
||||
extendPrompt.value = parts.prompt
|
||||
extendPromptPost.value = parts.post
|
||||
extendDuration.value = clampDuration(duration.value)
|
||||
extendDuration.value = clip
|
||||
? clipGenerateDuration(clip)
|
||||
: clampDuration(duration.value)
|
||||
extendLoraStack.value = readLoraStack(clip)
|
||||
lastFrameRevealed.value = false
|
||||
extendOpen.value = true
|
||||
@@ -6752,12 +6762,13 @@ function revealAndPlay() {
|
||||
}
|
||||
|
||||
function queueExtension() {
|
||||
const prior = extensionQueue.value[extensionQueue.value.length - 1]
|
||||
extensionQueue.value.push({
|
||||
id: crypto.randomUUID(),
|
||||
prompt: prompt.value.trim(),
|
||||
promptPre: promptPre.value,
|
||||
promptPost: promptPost.value,
|
||||
duration: duration.value,
|
||||
duration: clampDuration(prior?.duration ?? duration.value),
|
||||
loraStack: []
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user