const RECENT_CLIP_MS = 3 * 60 * 60 * 1000 function recentLibraryClip(event: Parameters[0]) { const { catalog } = assertLibraryOwner(event) const newest = catalog.clips[0] if (!newest || Date.now() - newest.createdAt > RECENT_CLIP_MS) return null return { type: 'complete' as const, status: 'complete' as const, message: newest.hideThumbnail ? 'Video ready. Click the player to reveal it.' : 'Video ready', progress: 100, clipId: newest.id, filename: newest.comfyFilename, hideThumbnail: newest.hideThumbnail, folderLocked: false } } function recentLibraryTrack(event: Parameters[0]) { const { catalog } = assertLibraryOwner(event) const newest = catalog.tracks?.[0] if (!newest || Date.now() - newest.createdAt > RECENT_CLIP_MS) return null return { type: 'complete' as const, status: 'complete' as const, message: 'Track ready', progress: 100, trackId: newest.id, filename: newest.comfyFilename, folderLocked: false } } async function recoverFinishedMedia(event: Parameters[0], opts?: { tags?: string }) { const { owner } = assertLibraryOwner(event) const library = publicLibrary(event) const folderId = library.folders.find(folder => folder.unlocked)?.id const tracks = folderId ? await importMissingComfyAudio(owner, folderId) : [] const want = String(opts?.tags || '').trim() const { catalog } = assertLibraryOwner(event) const match = [...tracks].reverse().find((track) => { if (!want) return true const tags = String(track.tags || '').trim() return tags === want || tags.includes(want) || want.includes(tags) }) || (want ? catalog.tracks.find((track) => { const tags = String(track.tags || '').trim() return Date.now() - track.createdAt < RECENT_CLIP_MS && (tags === want || tags.includes(want) || want.includes(tags)) }) : null) if (match) { return { type: 'complete' as const, status: 'complete' as const, message: 'Recovered track from ComfyUI', progress: 100, trackId: match.id, filename: match.comfyFilename, folderLocked: false } } if (opts?.tags) return null const videos = folderId ? await importMissingComfyVideos(owner, folderId) : [] const newestVideo = videos[videos.length - 1] if (newestVideo) { return { type: 'complete' as const, status: 'complete' as const, message: 'Recovered video from ComfyUI', progress: 100, clipId: newestVideo.id, filename: newestVideo.comfyFilename, hideThumbnail: newestVideo.hideThumbnail } } return recentLibraryTrack(event) || recentLibraryClip(event) } export default defineEventHandler(async (event) => { const body = await readBody<{ jobId?: string }>(event).catch(() => ({} as { jobId?: string })) const jobId = String(body?.jobId || '') const live = jobId ? getJob(jobId) : undefined if (live) { if (live.status === 'complete' || live.status === 'error' || live.trackId || live.clipId) { return jobSnapshot(live) } if (live.kind === 'music' && Date.now() - live.startedAt > 15_000) { const recovered = await recoverFinishedMedia(event, { tags: live.library?.tags }) if (recovered?.trackId) return recovered } return jobSnapshot(live) } if (jobId) { const pending = readPendingJob(jobId) if (pending) { const done = await resolvePendingJob(pending) if (done) return done return jobSnapshot(ensurePendingWatch(pending)) } const recovered = await recoverFinishedMedia(event) if (recovered) return recovered throw createError({ statusCode: 404, statusMessage: 'Job not found' }) } const recovered = await recoverFinishedMedia(event) if (recovered) return recovered throw createError({ statusCode: 404, statusMessage: 'No finished ComfyUI output to recover' }) })