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
+54 -2
View File
@@ -1,4 +1,4 @@
import { existsSync, writeFileSync, readFileSync, unlinkSync } from 'node:fs'
import { existsSync, writeFileSync, readFileSync, unlinkSync, statSync, openSync, readSync, closeSync, copyFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { spawn } from 'node:child_process'
@@ -171,6 +171,58 @@ async function probeSize(filePath: string) {
}
}
function mp4MoovIsAtStart(filePath: string) {
const fd = openSync(filePath, 'r')
try {
let offset = 0
const header = Buffer.alloc(16)
for (let i = 0; i < 12; i++) {
if (readSync(fd, header, 0, 8, offset) < 8) return false
let size = header.readUInt32BE(0)
const type = header.toString('ascii', 4, 8)
if (size === 1) {
if (readSync(fd, header, 8, 8, offset + 8) < 8) return false
size = Number(header.readBigUInt64BE(8))
}
if (!size || size < 8) return false
if (type === 'moov') return true
if (type === 'mdat') return false
offset += size
}
return false
} finally {
closeSync(fd)
}
}
export async function remuxFaststart(inputPath: string) {
if (!existsSync(inputPath)) return
try {
if (mp4MoovIsAtStart(inputPath)) return
} catch {
// Fall through and try a remux anyway.
}
const tmp = `${inputPath}.faststart.tmp.mp4`
try {
await runFfmpeg([
'-y',
'-i', inputPath,
'-c', 'copy',
'-map', '0',
'-movflags', '+faststart',
tmp
], 120000)
if (!existsSync(tmp) || statSync(tmp).size < 32) {
try { unlinkSync(tmp) } catch { /* ignore */ }
return
}
copyFileSync(tmp, inputPath)
try { unlinkSync(tmp) } catch { /* ignore */ }
} catch {
try { unlinkSync(tmp) } catch { /* ignore */ }
}
}
function encodeArgs(outputPath: string, withAudio: boolean) {
const args = [
'-c:v', 'libx264',
@@ -271,7 +323,7 @@ export async function concatMp4(part1Path: string, part2Path: string, outputPath
const listPath = join(dirname(outputPath), 'concat_list.txt')
writeFileSync(listPath, `file '${concatPath(part1Path)}'\nfile '${concatPath(part2Path)}'\n`)
try {
await runFfmpeg(['-y', '-f', 'concat', '-safe', '0', '-i', listPath, '-c', 'copy', outputPath], 180000)
await runFfmpeg(['-y', '-f', 'concat', '-safe', '0', '-i', listPath, '-c', 'copy', '-movflags', '+faststart', outputPath], 180000)
await assertStitchLength(part1Path, part2Path, outputPath)
} catch {
await concatReencode(part1Path, part2Path, outputPath)