feat: panelden video izleme/indirme/silme + eşzamanlı yayın kapasitesi düzeltmesi
- streamIngest worker concurrency 3'ten sabit değildi, artık MAX_CONCURRENT_CAPTURES (varsayılan 10) ile ayarlanabiliyor. Eskiden 3'ten fazla kanal aynı anda canlıya geçerse fazlası, ilk 3'ten biri bitene kadar (saatlerce) hiç kayda alınmıyordu. - Python worker'larda (signal-detection, stt-scoring) bullmq varsayılan concurrency'si 1'di — WORKER_CONCURRENCY (varsayılan 5) ile paralelleştirildi, birden fazla kanal aynı anda segment/transkript üretirse sıraya takılmasın diye. - Frontend artık shared-media volume'üne bağlı: /api/segments/[id]/video route'u Range destekli video stream/indirme sağlıyor. Segment ve kanal detay sayfalarına <video> oynatıcı, indirme linki ve onaylı silme (RawSegment + CandidateSegment, dosya dahil) eklendi. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { createReadStream, statSync } from "node:fs";
|
||||
import { Readable } from "node:stream";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { prisma } from "@streamclipper/db";
|
||||
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
|
||||
const segment = await prisma.rawSegment.findUnique({ where: { id } });
|
||||
if (!segment) return new Response("Not found", { status: 404 });
|
||||
|
||||
let size: number;
|
||||
try {
|
||||
size = statSync(segment.filePath).size;
|
||||
} catch {
|
||||
return new Response("File not found on disk", { status: 404 });
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "video/mp4",
|
||||
"Accept-Ranges": "bytes",
|
||||
};
|
||||
if (req.nextUrl.searchParams.get("download") === "1") {
|
||||
headers["Content-Disposition"] = `attachment; filename="${id}.mp4"`;
|
||||
}
|
||||
|
||||
const range = req.headers.get("range");
|
||||
const match = range ? /bytes=(\d+)-(\d*)/.exec(range) : null;
|
||||
|
||||
if (match) {
|
||||
const start = Number(match[1]);
|
||||
const end = match[2] ? Number(match[2]) : size - 1;
|
||||
const stream = createReadStream(segment.filePath, { start, end });
|
||||
return new Response(Readable.toWeb(stream) as ReadableStream, {
|
||||
status: 206,
|
||||
headers: {
|
||||
...headers,
|
||||
"Content-Range": `bytes ${start}-${end}/${size}`,
|
||||
"Content-Length": String(end - start + 1),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const stream = createReadStream(segment.filePath);
|
||||
return new Response(Readable.toWeb(stream) as ReadableStream, {
|
||||
headers: { ...headers, "Content-Length": String(size) },
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user