Put default video length on the main Settings panel and let Studio save it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-03 19:47:58 -05:00
co-authored by Cursor
parent 86e23499a9
commit e790c9bff7
3 changed files with 44 additions and 23 deletions
+4 -2
View File
@@ -3,7 +3,7 @@
<Thumbwheel <Thumbwheel
v-model="model" v-model="model"
:label="label || 'Duration'" :label="label || 'Duration'"
lock-key="duration" :lock-key="lockKey || 'duration'"
:min="MIN" :min="MIN"
:max="MAX" :max="MAX"
:step="0.1" :step="0.1"
@@ -24,9 +24,11 @@ const MAX = 120
withDefaults(defineProps<{ withDefaults(defineProps<{
label?: string label?: string
hint?: string hint?: string
lockKey?: string
}>(), { }>(), {
label: '', label: '',
hint: '' hint: '',
lockKey: 'duration'
}) })
const model = defineModel<number>({ required: true }) const model = defineModel<number>({ required: true })
+16 -16
View File
@@ -21,7 +21,7 @@
>{{ notice }}</p> >{{ notice }}</p>
<section v-if="activePanel === 'gpu'" class="glass rounded-3xl p-5 sm:p-6"> <section v-if="activePanel === 'gpu'" class="glass rounded-3xl p-5 sm:p-6">
<h2 class="font-display text-xl font-bold">GPU</h2> <h2 class="font-display text-xl font-bold">GPU & defaults</h2>
<div class="mt-4 space-y-3 rounded-2xl border border-white/10 bg-zinc-950/50 px-4 py-3"> <div class="mt-4 space-y-3 rounded-2xl border border-white/10 bg-zinc-950/50 px-4 py-3">
<p class="text-sm text-zinc-400"> <p class="text-sm text-zinc-400">
Stops Comfy on the desktop GPU so it drops out of VRAM. The PC stays on. Generate or Wake GPU will start it again. Stops Comfy on the desktop GPU so it drops out of VRAM. The PC stays on. Generate or Wake GPU will start it again.
@@ -66,18 +66,19 @@
</span> </span>
</label> </label>
<p v-if="notifyMessage" class="mt-2 text-xs text-zinc-500">{{ notifyMessage }}</p> <p v-if="notifyMessage" class="mt-2 text-xs text-zinc-500">{{ notifyMessage }}</p>
</section>
<section v-if="activePanel === 'studio'" class="glass rounded-3xl p-5 sm:p-6"> <div class="mt-6 border-t border-white/10 pt-5">
<h2 class="font-display text-xl font-bold">Studio</h2> <h3 class="text-sm font-semibold text-zinc-200">Default video length</h3>
<p class="mt-1 text-sm text-zinc-400">Defaults for new video jobs. Extend still copies the length of the clip you are extending.</p> <p class="mt-1 text-xs text-zinc-500">New Studio jobs and new shot cards start at this length. Extend still copies the clip you are extending.</p>
<div class="mt-4 max-w-xs rounded-2xl border border-white/10 bg-zinc-950/50 px-4 py-3"> <div class="mt-3 max-w-xs">
<DurationField <DurationField
v-model="defaultVideoDuration" v-model="defaultVideoDuration"
label="Default video length" label="Seconds"
hint="Used when you open Studio or add a new shot. Extend uses the source clip’s length." lock-key="default-video-duration"
@update:model-value="onDefaultVideoDuration" @update:model-value="onDefaultVideoDuration"
/> />
</div>
<p class="mt-2 text-xs text-zinc-500">Saved as {{ defaultVideoDuration }}s for this browser.</p>
</div> </div>
</section> </section>
@@ -409,7 +410,7 @@ export interface SettingsFolder {
unlocked: boolean unlocked: boolean
} }
type SettingsPanel = 'gpu' | 'studio' | 'storage' | 'login' | 'folders' | 'loras' | 'keeps' | 'prompts' type SettingsPanel = 'gpu' | 'storage' | 'login' | 'folders' | 'loras' | 'keeps' | 'prompts'
type LoraKindFilter = 'all' | 'image' | 'video' type LoraKindFilter = 'all' | 'image' | 'video'
const route = useRoute() const route = useRoute()
@@ -422,7 +423,7 @@ const notice = ref('')
const noticeError = ref(false) const noticeError = ref(false)
let noticeTimer: ReturnType<typeof setTimeout> | null = null let noticeTimer: ReturnType<typeof setTimeout> | null = null
const panelIds: SettingsPanel[] = ['gpu', 'studio', 'storage', 'login', 'folders', 'loras', 'keeps', 'prompts'] const panelIds: SettingsPanel[] = ['gpu', 'storage', 'login', 'folders', 'loras', 'keeps', 'prompts']
function parsePanel(raw: unknown): SettingsPanel { function parsePanel(raw: unknown): SettingsPanel {
const value = String(raw || '') const value = String(raw || '')
@@ -443,8 +444,7 @@ const activePanel = computed({
const navItems = computed(() => { const navItems = computed(() => {
const items: Array<{ id: SettingsPanel; label: string }> = [ const items: Array<{ id: SettingsPanel; label: string }> = [
{ id: 'gpu', label: 'GPU' }, { id: 'gpu', label: 'GPU & defaults' },
{ id: 'studio', label: 'Studio' },
{ id: 'storage', label: 'Storage' } { id: 'storage', label: 'Storage' }
] ]
if (authMode.value === 'password') items.push({ id: 'login', label: 'Site login' }) if (authMode.value === 'password') items.push({ id: 'login', label: 'Site login' })
+24 -5
View File
@@ -1012,10 +1012,20 @@
<div v-if="studioMode === 'video'" class="space-y-4"> <div v-if="studioMode === 'video'" class="space-y-4">
<div class="grid grid-cols-1 items-start gap-3 sm:grid-cols-2"> <div class="grid grid-cols-1 items-start gap-3 sm:grid-cols-2">
<DurationField <div>
v-model="duration" <DurationField
label="Duration" v-model="duration"
/> label="Duration"
/>
<button
type="button"
class="mt-2 text-[11px] text-amber-200/90 hover:text-amber-100"
title="Save this length as the default for new video jobs"
@click="saveDurationAsDefault"
>
Save {{ duration }}s as default
</button>
</div>
<div> <div>
<Thumbwheel <Thumbwheel
v-model="cfg" v-model="cfg"
@@ -2302,7 +2312,8 @@ import {
VIDEO_DURATION_DEFAULT, VIDEO_DURATION_DEFAULT,
clampVideoDuration, clampVideoDuration,
clipPartDuration, clipPartDuration,
defaultVideoDurationPref defaultVideoDurationPref,
setDefaultVideoDurationPref
} from '~/utils/videoDuration' } from '~/utils/videoDuration'
const runtimeConfig = useRuntimeConfig() const runtimeConfig = useRuntimeConfig()
@@ -2579,6 +2590,8 @@ function selectStudioKind(kind: 'video' | 'image') {
studioMode.value = 'editv2' studioMode.value = 'editv2'
outputFocus.value = 'edit' outputFocus.value = 'edit'
} }
outputFocus.value = 'edit'
}
function applyStudioQueryFromRoute() { function applyStudioQueryFromRoute() {
const studio = String(route.query.studio || '').toLowerCase() const studio = String(route.query.studio || '').toLowerCase()
@@ -4109,6 +4122,12 @@ function clampDuration(value: number) {
return clampVideoDuration(value, defaultVideoDurationPref()) return clampVideoDuration(value, defaultVideoDurationPref())
} }
function saveDurationAsDefault() {
const next = setDefaultVideoDurationPref(duration.value)
duration.value = next
toast(`Default video length set to ${next}s`)
}
function clampCfg(value: number) { function clampCfg(value: number) {
return clampVideoCfg(value, turbo.value ? CFG_TURBO : CFG_QUALITY) return clampVideoCfg(value, turbo.value ? CFG_TURBO : CFG_QUALITY)
} }