Keep pause across Coolify restarts, apply the chosen still from the image picker, and remux clips with Range/faststart so finished video can be scrubbed.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-28 08:15:52 -05:00
co-authored by Cursor
parent 870150f052
commit 7d783bd97e
12 changed files with 338 additions and 49 deletions
+28
View File
@@ -874,7 +874,10 @@
:autoplay="autoplayEnabled && !awaitingReveal"
loop
playsinline
preload="metadata"
@play="onPlayed"
@loadedmetadata="onVideoMeta"
@durationchange="onVideoMeta"
/>
<button
v-if="awaitingReveal && !lockedSave"
@@ -899,6 +902,12 @@
Generated MP4 appears here
</div>
</div>
<p v-if="videoUrl && !lockedSave && !videoSeekable" class="mt-3 text-xs text-amber-200/80">
Encoding… this file cannot be scrubbed until Comfy finishes writing it.
</p>
<p v-else-if="playingLastSavedWhileBusy" class="mt-3 text-xs text-zinc-500">
Playing the last saved part. The shot still encoding cannot be scrubbed until it saves.
</p>
<div v-if="videoUrl && !lockedSave" class="mt-4 flex flex-wrap gap-3">
<a
v-if="!awaitingReveal"
@@ -1648,6 +1657,7 @@ const activeChainPlan = ref<{ label: string; prompt: string; duration: number }[
const expandedFamilies = ref<Record<string, boolean>>({})
const elapsedMs = ref(0)
const videoUrl = ref('')
const videoSeekable = ref(true)
const editResultUrl = ref('')
const editProgress = ref(0)
const editStatusMessage = ref('Waiting for a still.')
@@ -1800,6 +1810,9 @@ const outputPreviewKind = computed<'video' | 'edit'>(() => {
const liveElapsedLabel = computed(() => (
outputProgressKind.value === 'edit' ? editElapsedLabel.value : elapsedLabel.value
))
const playingLastSavedWhileBusy = computed(() => (
videoBusy.value && Boolean(videoUrl.value) && !watchingLibrary.value && !lockedSave.value
))
const liveStatusMessage = computed(() => (
outputProgressKind.value === 'edit' ? editStatusMessage.value : statusMessage.value
))
@@ -2481,6 +2494,10 @@ watch(withSound, (value) => {
} catch { /* ignore */ }
})
watch(videoUrl, () => {
videoSeekable.value = true
})
watch(autoplayEnabled, (value) => {
try {
localStorage.setItem('aigen-autoplay', String(value))
@@ -2809,6 +2826,7 @@ function updateClipRefLabel(clip: LibraryClip, index: number, label: string) {
function onPickedPermanence(still: { id: string }) {
const slot = pickerSlot.value
if (slot === 'main' || slot === 'editRef' || typeof slot === 'number') return
pickerOpen.value = false
if (typeof slot === 'string' && slot.startsWith('clip:')) {
const clipId = slot.slice(5)
@@ -3883,6 +3901,16 @@ function onPlayed() {
awaitingReveal.value = false
}
function onVideoMeta() {
const el = player.value
if (!el) {
videoSeekable.value = true
return
}
const duration = el.duration
videoSeekable.value = Number.isFinite(duration) && duration > 0
}
function revealAndPlay() {
awaitingReveal.value = false
nextTick(() => {