Add a persistent clip library with folders, optional password, and hidden-thumbnail glow.

Generated videos save into a chosen folder, sensitive clips skip thumbnails until played, and Docker writes the catalog to a Coolify volume.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-25 18:03:26 -05:00
co-authored by Cursor
parent 30669c7a27
commit 83051e0ea3
20 changed files with 749 additions and 60 deletions
+33 -3
View File
@@ -1,4 +1,4 @@
import { NODE_LABELS } from '~/server/utils/workflow'
import { NODE_LABELS, isEncodingNode } from '~/server/utils/workflow'
import type { Job } from '~/server/utils/jobs'
function classifyError(message: string) {
@@ -39,6 +39,34 @@ export async function watchComfyJob(job: Job) {
return
}
job.video = video
if (job.library) {
emitJob(job, { type: 'status', message: 'Saving to library...', progress: 98 })
try {
const buffer = await downloadComfyVideo(video)
const clip = await saveClip({
folderId: job.library.folderId,
prompt: job.library.prompt,
aspect: job.library.aspect,
width: job.library.width,
height: job.library.height,
steps: job.library.steps,
turbo: job.library.turbo,
seed: job.library.seed,
hideThumbnail: job.library.hideThumbnail,
video: buffer,
thumb: job.library.hideThumbnail ? null : job.library.thumb
})
job.clipId = clip.id
job.hideThumbnail = clip.hideThumbnail
job.library.thumb = undefined
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
job.status = 'error'
job.error = `Video generated but library save failed: ${message}`
emitJob(job, { type: 'error', error: job.error, message: job.error })
return
}
}
job.status = 'complete'
emitJob(job, {
type: 'complete',
@@ -46,7 +74,9 @@ export async function watchComfyJob(job: Job) {
progress: 100,
filename: video.filename,
subfolder: video.subfolder,
mediaType: video.type
mediaType: video.type,
clipId: job.clipId,
hideThumbnail: job.hideThumbnail
})
}
@@ -109,7 +139,7 @@ export async function watchComfyJob(job: Job) {
return
}
const label = NODE_LABELS[node] || `Running node ${node}`
const encoding = node === '16' || node === '17'
const encoding = isEncodingNode(node)
emitJob(job, {
type: 'executing',
node,