优化图文页
This commit is contained in:
@@ -5,7 +5,11 @@ import type { Metadata } from "next";
|
||||
import { getFileUrl } from "@/lib/minio";
|
||||
import { AwemeData, VideoTranscript } from "./types";
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ awemeId: string }> }): Promise<Metadata> {
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ awemeId: string }>;
|
||||
}): Promise<Metadata> {
|
||||
const id = (await params).awemeId;
|
||||
|
||||
const [video, post] = await Promise.all([
|
||||
@@ -16,7 +20,7 @@ export async function generateMetadata({ params }: { params: Promise<{ awemeId:
|
||||
prisma.imagePost.findUnique({
|
||||
where: { aweme_id: id },
|
||||
select: { desc: true, author: { select: { nickname: true } } },
|
||||
})
|
||||
}),
|
||||
]);
|
||||
|
||||
const data = video || post;
|
||||
@@ -28,7 +32,10 @@ export async function generateMetadata({ params }: { params: Promise<{ awemeId:
|
||||
|
||||
const desc = data.desc || "查看作品详情";
|
||||
const author = data.author.nickname;
|
||||
const title = desc.length > 50 ? `${desc.slice(0, 50)}... - ${author}` : `${desc} - ${author}`;
|
||||
const title =
|
||||
desc.length > 50
|
||||
? `${desc.slice(0, 50)}... - ${author}`
|
||||
: `${desc} - ${author}`;
|
||||
|
||||
return {
|
||||
title,
|
||||
@@ -36,7 +43,11 @@ export async function generateMetadata({ params }: { params: Promise<{ awemeId:
|
||||
};
|
||||
}
|
||||
|
||||
export default async function AwemeDetail({ params }: { params: Promise<{ awemeId: string }> }) {
|
||||
export default async function AwemeDetail({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ awemeId: string }>;
|
||||
}) {
|
||||
const id = (await params).awemeId;
|
||||
|
||||
const [video, post] = await Promise.all([
|
||||
@@ -47,7 +58,7 @@ export default async function AwemeDetail({ params }: { params: Promise<{ awemeI
|
||||
prisma.imagePost.findUnique({
|
||||
where: { aweme_id: id },
|
||||
include: { author: true, images: { orderBy: { order: "asc" } } },
|
||||
})
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!video && !post) return <main className="p-8">找不到该作品</main>;
|
||||
@@ -66,65 +77,109 @@ export default async function AwemeDetail({ params }: { params: Promise<{ awemeI
|
||||
created_at: aweme!.created_at,
|
||||
likesCount: Number(aweme!.digg_count),
|
||||
commentsCount,
|
||||
author: {
|
||||
nickname: aweme!.author.nickname,
|
||||
avatar_url: getFileUrl(aweme!.author.avatar_url || 'default-avatar.png'),
|
||||
sec_uid: aweme!.author.sec_uid
|
||||
author: {
|
||||
nickname: aweme!.author.nickname,
|
||||
avatar_url: getFileUrl(aweme!.author.avatar_url || "default-avatar.png"),
|
||||
sec_uid: aweme!.author.sec_uid,
|
||||
},
|
||||
...(() => {
|
||||
if (isVideo) {
|
||||
const aweme = video!
|
||||
const aweme = video!;
|
||||
return {
|
||||
type: "video" as const,
|
||||
cover_url: getFileUrl(aweme!.cover_url ?? 'default-cover.png'),
|
||||
cover_url: getFileUrl(aweme!.cover_url ?? "default-cover.png"),
|
||||
cover_size: { h: aweme.height ?? 0, w: aweme.width ?? 0 },
|
||||
duration_ms: aweme!.duration_ms,
|
||||
video_url: getFileUrl(aweme!.video_url),
|
||||
width: aweme!.width ?? null,
|
||||
height: aweme!.height ?? null,
|
||||
}
|
||||
};
|
||||
} else {
|
||||
const aweme = post!
|
||||
const aweme = post!;
|
||||
return {
|
||||
type: "image" as const,
|
||||
cover_url: getFileUrl(aweme!.images[0].url ?? 'default-cover.png'),
|
||||
cover_size: { h: aweme!.images[0].height ?? 0, w: aweme!.images[0].width ?? 0 },
|
||||
images: aweme!.images.map(img => ({ ...img, url: getFileUrl(img.url), animated: img.animated? getFileUrl(img.animated) : null })),
|
||||
music_url: getFileUrl(aweme!.music_url || 'default-music.mp3'),
|
||||
cover_url: getFileUrl(aweme!.images[0].url ?? "default-cover.png"),
|
||||
cover_size: {
|
||||
h: aweme!.images[0].height ?? 0,
|
||||
w: aweme!.images[0].width ?? 0,
|
||||
},
|
||||
images: aweme!.images.map((img) => ({
|
||||
...img,
|
||||
url: getFileUrl(img.url),
|
||||
animated: img.animated ? getFileUrl(img.animated) : null,
|
||||
})),
|
||||
music_url: getFileUrl(aweme!.music_url || "default-music.mp3"),
|
||||
};
|
||||
}
|
||||
})()
|
||||
}
|
||||
})(),
|
||||
};
|
||||
|
||||
const transcript: VideoTranscript | null = isVideo ? await prisma.videoTranscript.findUnique({
|
||||
where: { videoId: id },
|
||||
}) : null;
|
||||
const transcript: VideoTranscript | null = isVideo
|
||||
? await prisma.videoTranscript.findUnique({
|
||||
where: { videoId: id },
|
||||
})
|
||||
: null;
|
||||
|
||||
// Compute prev/next neighbors by created_at across videos and image posts
|
||||
const currentCreatedAt = (isVideo ? video!.created_at : post!.created_at);
|
||||
const currentCreatedAt = isVideo ? video!.created_at : post!.created_at;
|
||||
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 } }),
|
||||
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 });
|
||||
if (newerPost) cands.push({ aweme_id: newerPost.aweme_id, created_at: newerPost.created_at });
|
||||
if (newerVideo)
|
||||
cands.push({
|
||||
aweme_id: newerVideo.aweme_id,
|
||||
created_at: newerVideo.created_at,
|
||||
});
|
||||
if (newerPost)
|
||||
cands.push({
|
||||
aweme_id: newerPost.aweme_id,
|
||||
created_at: newerPost.created_at,
|
||||
});
|
||||
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 });
|
||||
if (olderPost) cands.push({ aweme_id: olderPost.aweme_id, created_at: olderPost.created_at });
|
||||
if (olderVideo)
|
||||
cands.push({
|
||||
aweme_id: olderVideo.aweme_id,
|
||||
created_at: olderVideo.created_at,
|
||||
});
|
||||
if (olderPost)
|
||||
cands.push({
|
||||
aweme_id: olderPost.aweme_id,
|
||||
created_at: olderPost.created_at,
|
||||
});
|
||||
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 };
|
||||
const neighbors: {
|
||||
prev: { aweme_id: string } | null;
|
||||
next: { aweme_id: string } | null;
|
||||
} = { prev: pickPrev, next: pickNext };
|
||||
|
||||
return (
|
||||
<main className="min-h-screen w-full">
|
||||
@@ -135,7 +190,11 @@ export default async function AwemeDetail({ params }: { params: Promise<{ awemeI
|
||||
className="inline-flex items-center justify-center w-9 h-9 rounded-full bg-white/15 text-white border border-white/20 backdrop-blur hover:bg-white/25"
|
||||
/>
|
||||
</div>
|
||||
<AwemeDetailClient data={data} neighbors={neighbors} transcript={transcript} />
|
||||
<AwemeDetailClient
|
||||
data={data}
|
||||
neighbors={neighbors}
|
||||
transcript={transcript}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user