import { basename, parse } from 'node:path' import { upscaleRecords } from '../../../../utils/videoUpscale' import { listStudioJobs } from '../../../../utils/studioQueue' import { listJobs } from '../../../../utils/jobs' export default defineEventHandler(event => { const { owner } = assertLibraryOwner(event) const clip = getClip(owner, String(getRouterParam(event, 'id') || '')) assertFolderAccess(event, clip.folderId) const rows = listStudioJobs(owner) const active = rows.find(row => ['waiting', 'held', 'running'].includes(row.status) && row.payload.upscale?.sourceId === clip.id) const records = upscaleRecords(owner, clip.id) const latest = active || rows.filter(row => row.payload.upscale?.sourceId === clip.id).sort((a, b) => b.createdAt - a.createdAt)[0] const record = records.find(r => !latest || r.id === latest.id) const status = active?.status || record?.status || latest?.status const labels: Record = { waiting: 'queued', held: 'queued', complete: 'done', error: 'failed', cancelled: 'failed', running: 'running' } const generationBusy = rows.some(row => row.status === 'running' && row.payload.extendFromClipId === clip.id) || listJobs().some(job => job.library?.ownerKey === owner && job.clipId === clip.id && ['queued', 'uploading', 'running'].includes(job.status)) return { source: { id: clip.id, name: clip.name, upscaledFromClipId: clip.upscaledFromClipId, stem: parse(basename(clipVideoPath(owner, clip.id))).name, width: clip.width, height: clip.height }, busy: Boolean(active || record?.status === 'running' || generationBusy), job: latest || record ? { id: latest?.id || record.id, status: labels[status || ''] || status, message: record?.message || latest?.waitReason, error: record?.error || latest?.lastError || (status === 'cancelled' ? 'Cancelled. Original video is safe.' : undefined), progress: record?.progress || 0, width: record?.width, height: record?.height, elapsedMs: record?.elapsedMs || (record?.createdAt ? Date.now() - record.createdAt : 0), outputClipId: record?.outputClipId } : null } })