110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
// app/api/videos/[id]/route.ts
|
|
import { NextResponse } from "next/server";
|
|
import { prisma } from "../../../../lib/prisma";
|
|
import { getServerSession } from "next-auth";
|
|
import { authOptions } from "../../../../lib/auth-options";
|
|
import { getVideoUrls } from "../../../../lib/video-urls";
|
|
|
|
export async function GET(req: Request, context: any) {
|
|
try {
|
|
// unwrap params
|
|
let params = context?.params;
|
|
if (typeof params?.then === "function") params = await params;
|
|
|
|
const id = params?.id;
|
|
if (!id) return NextResponse.json({ error: "Missing video id" }, { status: 400 });
|
|
|
|
const session = await getServerSession(authOptions);
|
|
if (!session?.user?.email) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
const user = await prisma.user.findUnique({
|
|
where: { email: session.user.email },
|
|
include: {
|
|
enrollments: true,
|
|
},
|
|
});
|
|
if (!user) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
const video = await prisma.video.findUnique({
|
|
where: { id },
|
|
include: {
|
|
playlist: {
|
|
include: {
|
|
course: true,
|
|
courses: true,
|
|
},
|
|
},
|
|
uploader: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
image: true,
|
|
},
|
|
},
|
|
videoCourses: true,
|
|
},
|
|
});
|
|
if (!video) return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
|
|
const userCourseIds = user.enrollments.map((enrollment) => enrollment.courseId);
|
|
|
|
const playlistCourseIds = new Set<string>([video.playlist.courseId]);
|
|
(video.playlist.courses || []).forEach((mapping) => {
|
|
playlistCourseIds.add(mapping.courseId);
|
|
});
|
|
|
|
const hasPlaylistAccess = [...playlistCourseIds].some((courseId) =>
|
|
userCourseIds.includes(courseId)
|
|
);
|
|
if (!hasPlaylistAccess) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const restrictedCourseIds = (video.videoCourses || [])
|
|
.filter((assignment) => assignment.exclusive)
|
|
.map((assignment) => assignment.courseId);
|
|
if (
|
|
restrictedCourseIds.length > 0 &&
|
|
!restrictedCourseIds.some((courseId) => userCourseIds.includes(courseId))
|
|
) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
// Find the next video (index = current.index + 1)
|
|
const next = await prisma.video.findFirst({
|
|
where: {
|
|
playlistId: video.playlistId,
|
|
index: video.index + 1,
|
|
},
|
|
include: {
|
|
uploader: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
image: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// Add video URLs with HLS support
|
|
const videoUrls = getVideoUrls(video.id, video.url, video.transcodingStatus as any);
|
|
const responseVideo = {
|
|
...video,
|
|
videoUrls,
|
|
transcodingStatus: video.transcodingStatus,
|
|
restrictedCourseIds,
|
|
};
|
|
|
|
// Ensure we return the URL field explicitly (player expects `video.url`).
|
|
return NextResponse.json({ video: responseVideo, next });
|
|
} catch (err: any) {
|
|
console.error("GET /api/videos/[id] error:", err);
|
|
return NextResponse.json({ error: "Server error" }, { status: 500 });
|
|
}
|
|
}
|