Use the parent clip last frame and new-segment join for extensions, not the stitched file's first frame. Show this account's library storage in Settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-28 10:54:46 -05:00
co-authored by Cursor
parent 231c59a7a7
commit 0af3cddb14
16 changed files with 571 additions and 70 deletions
+39 -3
View File
@@ -59,6 +59,12 @@ function concatPath(filePath: string) {
return filePath.replace(/\\/g, '/').replace(/'/g, "'\\''")
}
function assertFrameFile(path: string, kind: string) {
if (!existsSync(path) || statSync(path).size < 64) {
throw new Error(`Could not extract the ${kind}`)
}
}
export async function extractLastFrame(inputPath: string, outputPath: string) {
if (!existsSync(inputPath)) {
throw new Error('Source video is missing')
@@ -80,7 +86,7 @@ export async function extractLastFrame(inputPath: string, outputPath: string) {
for (const args of attempts) {
try {
await runFfmpeg(args, 60000)
if (existsSync(outputPath)) return
if (existsSync(outputPath) && statSync(outputPath).size >= 64) return
} catch {
// Try the next seek strategy.
}
@@ -102,8 +108,38 @@ export async function extractFirstFrame(inputPath: string, outputPath: string) {
'-q:v', '4',
outputPath
], 20000)
if (!existsSync(outputPath)) {
throw new Error('Could not extract the first frame')
assertFrameFile(outputPath, 'first frame')
}
export async function extractFrameAt(inputPath: string, outputPath: string, seconds: number) {
if (!existsSync(inputPath)) {
throw new Error('Source video is missing')
}
const seek = Math.max(0, seconds)
await runFfmpeg([
'-y',
'-ss', seek.toFixed(3),
'-i', inputPath,
'-frames:v', '1',
'-update', '1',
'-an',
'-q:v', '2',
outputPath
], 60000)
assertFrameFile(outputPath, 'frame')
}
export async function extractFirstFrameFromBuffer(video: Buffer, tmpDir: string) {
if (!video.length) throw new Error('Could not extract the first frame')
const input = join(tmpDir, `seg_head_${Date.now()}.mp4`)
const output = join(tmpDir, `seg_first_${Date.now()}.jpg`)
writeFileSync(input, video)
try {
await extractFirstFrame(input, output)
return readFileSync(output)
} finally {
try { unlinkSync(input) } catch { /* ignore */ }
try { unlinkSync(output) } catch { /* ignore */ }
}
}