89 lines
2.4 KiB
TypeScript
89 lines
2.4 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { requirePaidApiUser } from "@/lib/api-auth";
|
|
import { createVideoJob } from "@/lib/jobs/create-job";
|
|
import {
|
|
applyCreatePlaylistToItems,
|
|
parseCreatePlaylistInput,
|
|
} from "@/lib/jobs/resolve-playlist";
|
|
import { prisma } from "@/lib/db";
|
|
import type { CreateJobPayload } from "@/lib/types";
|
|
|
|
export async function POST(req: NextRequest) {
|
|
const { error, user } = await requirePaidApiUser(req);
|
|
if (error || !user) return error!;
|
|
|
|
const body = (await req.json()) as CreateJobPayload & { createPlaylist?: unknown };
|
|
|
|
try {
|
|
const createPlaylist = parseCreatePlaylistInput(body.createPlaylist);
|
|
if (body.createPlaylist && !createPlaylist) {
|
|
return NextResponse.json(
|
|
{
|
|
error:
|
|
"createPlaylist requires a title. Optional: description, privacy (public|unlisted|private)",
|
|
},
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
const { items, playlist } = await applyCreatePlaylistToItems(
|
|
user,
|
|
body.items,
|
|
createPlaylist,
|
|
);
|
|
|
|
const job = await createVideoJob(user, {
|
|
imagePath: body.imagePath,
|
|
items,
|
|
});
|
|
|
|
return NextResponse.json({
|
|
jobId: job.id,
|
|
itemCount: job.items.length,
|
|
status: job.status,
|
|
playlist: playlist
|
|
? { id: playlist.id, title: playlist.title, privacy: playlist.privacy }
|
|
: null,
|
|
});
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : "Failed to create job";
|
|
const status = message.includes("Quota exceeded") ? 403 : 400;
|
|
return NextResponse.json({ error: message }, { status });
|
|
}
|
|
}
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const { error, user } = await requirePaidApiUser(req);
|
|
if (error || !user) return error!;
|
|
|
|
const limit = Math.min(Number(req.nextUrl.searchParams.get("limit")) || 20, 100);
|
|
|
|
const jobs = await prisma.job.findMany({
|
|
where: { userId: user.id },
|
|
orderBy: { createdAt: "desc" },
|
|
take: limit,
|
|
include: {
|
|
items: {
|
|
select: {
|
|
id: true,
|
|
audioFilename: true,
|
|
title: true,
|
|
status: true,
|
|
youtubeVideoId: true,
|
|
error: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
return NextResponse.json({
|
|
jobs: jobs.map((job) => ({
|
|
id: job.id,
|
|
status: job.status,
|
|
createdAt: job.createdAt.toISOString(),
|
|
completedAt: job.completedAt?.toISOString() ?? null,
|
|
items: job.items,
|
|
})),
|
|
});
|
|
}
|