import { prisma } from "@/lib/prisma"; import BackButton from "@/app/components/BackButton"; import AwemeDetailClient from "./Client"; import type { Metadata } from "next"; function ms(v?: number | null) { if (!v) return ""; const s = Math.round(v / 1000); const m = Math.floor(s / 60); const r = s % 60; return `${m}:${r.toString().padStart(2, "0")}`; } export async function generateMetadata({ params }: { params: Promise<{ awemeId: string }> }): Promise { const id = (await params).awemeId; const [video, post] = await Promise.all([ prisma.video.findUnique({ where: { aweme_id: id }, select: { desc: true, author: { select: { nickname: true } } }, }), prisma.imagePost.findUnique({ where: { aweme_id: id }, select: { desc: true, author: { select: { nickname: true } } }, }) ]); const data = video || post; if (!data) { return { title: "作品不存在", }; } const desc = data.desc || "查看作品详情"; const author = data.author.nickname; const title = desc.length > 50 ? `${desc.slice(0, 50)}... - ${author}` : `${desc} - ${author}`; return { title, description: desc, }; } export default async function AwemeDetail({ params }: { params: Promise<{ awemeId: string }> }) { const id = (await params).awemeId; const [video, post] = await Promise.all([ prisma.video.findUnique({ where: { aweme_id: id }, include: { author: true }, }), prisma.imagePost.findUnique({ where: { aweme_id: id }, include: { author: true, images: { orderBy: { order: "asc" } } }, }) ]); if (!video && !post) return
找不到该作品
; const isVideo = !!video; // 获取评论总数 const commentsCount = await prisma.comment.count({ where: isVideo ? { videoId: id } : { imagePostId: id }, }); const data = isVideo ? { type: "video" as const, aweme_id: video!.aweme_id, desc: video!.desc, created_at: video!.created_at, duration_ms: video!.duration_ms, video_url: video!.video_url, width: video!.width ?? null, height: video!.height ?? null, author: { nickname: video!.author.nickname, avatar_url: video!.author.avatar_url }, commentsCount, likesCount: Number(video!.digg_count), } : { type: "image" as const, aweme_id: post!.aweme_id, desc: post!.desc, created_at: post!.created_at, images: post!.images, music_url: post!.music_url, author: { nickname: post!.author.nickname, avatar_url: post!.author.avatar_url }, commentsCount, likesCount: Number(post!.digg_count), }; // Compute prev/next neighbors by created_at across videos and image posts const currentCreatedAt = (isVideo ? video!.created_at : post!.created_at) as unknown as Date; const [newerVideo, newerPost, olderVideo, olderPost] = await Promise.all([ prisma.video.findFirst({ where: { created_at: { gt: currentCreatedAt } }, orderBy: { created_at: "asc" }, select: { aweme_id: true, created_at: true } }), prisma.imagePost.findFirst({ where: { created_at: { gt: currentCreatedAt } }, orderBy: { created_at: "asc" }, select: { aweme_id: true, created_at: true } }), prisma.video.findFirst({ where: { created_at: { lt: currentCreatedAt } }, orderBy: { created_at: "desc" }, select: { aweme_id: true, created_at: true } }), prisma.imagePost.findFirst({ where: { created_at: { lt: currentCreatedAt } }, orderBy: { created_at: "desc" }, select: { aweme_id: true, created_at: true } }), ]); const pickPrev = (() => { const cands: { aweme_id: string; created_at: Date }[] = []; if (newerVideo) cands.push({ aweme_id: newerVideo.aweme_id, created_at: newerVideo.created_at as unknown as Date }); if (newerPost) cands.push({ aweme_id: newerPost.aweme_id, created_at: newerPost.created_at as unknown as Date }); if (cands.length === 0) return null; cands.sort((a, b) => +a.created_at - +b.created_at); return { aweme_id: cands[0].aweme_id }; })(); const pickNext = (() => { const cands: { aweme_id: string; created_at: Date }[] = []; if (olderVideo) cands.push({ aweme_id: olderVideo.aweme_id, created_at: olderVideo.created_at as unknown as Date }); if (olderPost) cands.push({ aweme_id: olderPost.aweme_id, created_at: olderPost.created_at as unknown as Date }); if (cands.length === 0) return null; cands.sort((a, b) => +b.created_at - +a.created_at); return { aweme_id: cands[0].aweme_id }; })(); const neighbors: { prev: { aweme_id: string } | null; next: { aweme_id: string } | null } = { prev: pickPrev, next: pickNext }; return (
{/* 顶部条改为悬浮在媒体区域之上,避免 sticky 造成 Y 方向滚动条 */}
); } export const dynamic = "force-dynamic";