83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/prisma";
|
|
import type { FeedItem, FeedResponse } from "@/app/types/feed";
|
|
import { getFileUrl } from "@/lib/minio";
|
|
|
|
export async function GET(
|
|
req: NextRequest,
|
|
{ params }: { params: Promise<{ secUid: string }> },
|
|
) {
|
|
const secUid = (await params).secUid;
|
|
const { searchParams } = new URL(req.url);
|
|
const limitParam = searchParams.get("limit");
|
|
const beforeParam = searchParams.get("before");
|
|
|
|
const limit = Math.min(Math.max(Number(limitParam ?? "24"), 1), 60); // 1..60
|
|
const before = beforeParam ? new Date(beforeParam) : null;
|
|
|
|
// fetch chunk from both tables
|
|
const [videos, posts] = await Promise.all([
|
|
prisma.video.findMany({
|
|
where: {
|
|
authorId: secUid,
|
|
...(before ? { created_at: { lt: before } } : {}),
|
|
},
|
|
orderBy: { created_at: "desc" },
|
|
take: limit,
|
|
include: { author: true },
|
|
}),
|
|
prisma.imagePost.findMany({
|
|
where: {
|
|
authorId: secUid,
|
|
...(before ? { created_at: { lt: before } } : {}),
|
|
},
|
|
orderBy: { created_at: "desc" },
|
|
take: limit,
|
|
include: { author: true, images: { orderBy: { order: "asc" }, take: 1 } },
|
|
}),
|
|
]);
|
|
|
|
const merged: FeedItem[] = [
|
|
...videos.map((v) => ({
|
|
type: "video" as const,
|
|
aweme_id: v.aweme_id,
|
|
created_at: v.created_at,
|
|
desc: v.desc,
|
|
video_url: getFileUrl(v.video_url),
|
|
cover_url: getFileUrl(v.cover_url ?? "default_cover.png"),
|
|
width: v.width ?? null,
|
|
height: v.height ?? null,
|
|
author: {
|
|
nickname: v.author.nickname,
|
|
avatar_url: getFileUrl(v.author.avatar_url ?? ""),
|
|
sec_uid: v.author.sec_uid,
|
|
},
|
|
likes: Number(v.digg_count),
|
|
})),
|
|
...posts.map((p) => ({
|
|
type: "image" as const,
|
|
aweme_id: p.aweme_id,
|
|
created_at: p.created_at,
|
|
desc: p.desc,
|
|
cover_url: getFileUrl(p.images?.[0]?.url ?? null),
|
|
width: p.images?.[0]?.width ?? null,
|
|
height: p.images?.[0]?.height ?? null,
|
|
author: {
|
|
nickname: p.author.nickname,
|
|
avatar_url: getFileUrl(p.author.avatar_url ?? ""),
|
|
sec_uid: p.author.sec_uid,
|
|
},
|
|
likes: Number(p.digg_count),
|
|
})),
|
|
]
|
|
.sort((a, b) => +new Date(b.created_at) - +new Date(a.created_at))
|
|
.slice(0, limit);
|
|
|
|
const nextCursor =
|
|
merged.length > 0
|
|
? new Date(merged[merged.length - 1].created_at as any).toISOString()
|
|
: null;
|
|
const payload: FeedResponse = { items: merged, nextCursor };
|
|
return NextResponse.json(payload);
|
|
}
|