47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import fs from 'fs';
|
|
import { NextResponse } from 'next/server';
|
|
import { transcodeOrchestrator } from '@/lib/transcode/orchestrator';
|
|
import { segmentPath } from '@/lib/transcode/playlist';
|
|
|
|
export const runtime = 'nodejs';
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
async function waitForSegment(filePath: string, timeoutMs = 5000): Promise<boolean> {
|
|
const startedAt = Date.now();
|
|
while (Date.now() - startedAt < timeoutMs) {
|
|
if (fs.existsSync(filePath)) {
|
|
const stat = fs.statSync(filePath);
|
|
if (stat.size > 0) return true;
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 150));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export async function GET(_request: Request, { params }: { params: Promise<{ jobId: string; name: string }> }) {
|
|
const { jobId, name } = await params;
|
|
const job = transcodeOrchestrator.get(jobId);
|
|
|
|
if (!job) {
|
|
return NextResponse.json({ error: 'Transcode job not found' }, { status: 404 });
|
|
}
|
|
|
|
const resolvedPath = segmentPath(job.outDir, name);
|
|
if (!resolvedPath || !(await waitForSegment(resolvedPath))) {
|
|
return new Response(null, { status: 404 });
|
|
}
|
|
|
|
const stat = fs.statSync(resolvedPath);
|
|
const stream = fs.createReadStream(resolvedPath);
|
|
return new Response(stream as any, {
|
|
status: 200,
|
|
headers: {
|
|
'Content-Type': 'video/mp2t',
|
|
'Content-Length': stat.size.toString(),
|
|
'Cache-Control': 'private, max-age=3600',
|
|
'ETag': `"${jobId}-${name}-${stat.size}-${stat.mtimeMs}"`,
|
|
'Access-Control-Allow-Origin': '*',
|
|
},
|
|
});
|
|
}
|