import { NextRequest, NextResponse } from 'next/server'; import { ConcurrencyLimitError, transcodeOrchestrator, TranscodeDisabledError } from '@/lib/transcode/orchestrator'; export const runtime = 'nodejs'; export const dynamic = 'force-dynamic'; export async function POST(request: NextRequest) { try { const body = await request.json(); const mediaId = Number(body.mediaId); const startTime = Number(body.startTime || 0); const profile = typeof body.profile === 'string' ? body.profile : undefined; if (!Number.isInteger(mediaId) || mediaId <= 0) { return NextResponse.json({ error: 'Invalid mediaId' }, { status: 400 }); } if (!Number.isFinite(startTime) || startTime < 0) { return NextResponse.json({ error: 'Invalid startTime' }, { status: 400 }); } const job = await transcodeOrchestrator.start(mediaId, profile, startTime); return NextResponse.json({ jobId: job.id, playlistUrl: `/api/transcode/${job.id}/master.m3u8`, etaSeconds: 1, profile: job.profile, decision: job.decision.kind, duration: job.knownDuration, startTime: job.startTime, }); } catch (error) { if (error instanceof TranscodeDisabledError) { return NextResponse.json({ error: error.message, code: 'TRANSCODE_DISABLED' }, { status: 403 }); } if (error instanceof ConcurrencyLimitError) { return NextResponse.json( { error: error.message, code: 'TRANSCODE_BUSY', retryAfterSeconds: error.retryAfterSeconds }, { status: 503, headers: { 'Retry-After': error.retryAfterSeconds.toString() } }, ); } console.error('[TranscodeAPI] start failed:', error); return NextResponse.json({ error: error instanceof Error ? error.message : 'Failed to start transcode' }, { status: 500 }); } }