meet/app/api/record/start/route.ts
2024-10-11 16:20:24 -07:00

105 lines
2.8 KiB
TypeScript

import { EgressClient, EncodedFileOutput, S3Upload } from 'livekit-server-sdk';
import { NextRequest, NextResponse } from 'next/server';
export async function GET(req: NextRequest) {
try {
const roomName = req.nextUrl.searchParams.get('roomName');
const now = req.nextUrl.searchParams.get('now');
// new Date(Date.now()).toISOString();
/**
* CAUTION:
* for simplicity this implementation does not authenticate users and therefore allows anyone with knowledge of a roomName
* to start/stop recordings for that room.
* DO NOT USE THIS FOR PRODUCTION PURPOSES AS IS
*/
if (roomName === null) {
return new NextResponse('Missing roomName parameter', { status: 403 });
}
if (now === null) {
return new NextResponse('Missing now parameter', { status: 403 });
}
const {
LIVEKIT_API_KEY,
LIVEKIT_API_SECRET,
LIVEKIT_URL,
S3_KEY_ID,
S3_KEY_SECRET,
S3_BUCKET,
S3_ENDPOINT,
S3_REGION,
RUNNER_URL,
RUNNER_SECRET,
} = process.env;
const hostURL = new URL(LIVEKIT_URL!);
hostURL.protocol = 'https:';
const egressClient = new EgressClient(hostURL.origin, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
const existingEgresses = await egressClient.listEgress({ roomName });
if (existingEgresses.length > 0 && existingEgresses.some((e) => e.status < 2)) {
return new NextResponse('Meeting is already being recorded', { status: 409 });
}
const filepath = `${now}-${roomName}.mp4`;
const fileOutput = new EncodedFileOutput({
filepath: filepath,
output: {
case: 's3',
value: new S3Upload({
// endpoint: S3_ENDPOINT,
accessKey: S3_KEY_ID,
secret: S3_KEY_SECRET,
region: S3_REGION,
bucket: S3_BUCKET,
}),
},
});
await egressClient.startRoomCompositeEgress(
roomName,
{
file: fileOutput,
},
{
layout: 'speaker',
},
);
if (RUNNER_URL && RUNNER_SECRET) {
post_runner(RUNNER_URL, RUNNER_SECRET, filepath);
}
return new NextResponse(null, { status: 200 });
} catch (error) {
if (error instanceof Error) {
return new NextResponse(error.message, { status: 500 });
}
}
}
async function post_runner(url: string, token: string, filepath: string) {
const humanReadableDate = new Date().toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
try {
await fetch(url, {
method: 'POST',
body: JSON.stringify({
filepath,
show_title: 'Meeting',
episode_title: `Live call ${humanReadableDate}`,
}),
headers: { 'x-admin-token': token },
});
} catch (e) {
console.error(e);
}
}