import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { Mic2 } from "lucide-react"; import { prisma } from "@/lib/db"; import { storage } from "@/lib/storage"; import { getActiveBranding, hexToHslTriplet } from "@/lib/branding"; import { WaveformPlayer } from "@/components/app/waveform-player"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import type { StructuredScript } from "@/lib/ai/types"; export const dynamic = "force-dynamic"; async function loadShared(shareId: string) { const episode = await prisma.episode.findUnique({ where: { shareId }, include: { audioAsset: true, coverArt: true, script: true, speakers: true }, }); // 404 when no episode, sharing disabled, or not finished. if (!episode || !episode.shareId || episode.status !== "READY") return null; return episode; } export async function generateMetadata({ params, }: { params: Promise<{ shareId: string }>; }): Promise { const { shareId } = await params; const episode = await loadShared(shareId); if (!episode) return { title: "Episode not found" }; return { title: episode.title, description: episode.topic.slice(0, 160), robots: { index: false }, }; } export default async function PublicSharePage({ params, }: { params: Promise<{ shareId: string }>; }) { const { shareId } = await params; const episode = await loadShared(shareId); if (!episode) notFound(); // Resolve the owning org's white-label branding (Agency custom_branding only). const branding = await getActiveBranding(episode.userId, episode.organizationId); const brandHsl = hexToHslTriplet(branding?.primaryColor); const brandStyle = brandHsl ? ({ "--brand": brandHsl, "--ring": brandHsl } as React.CSSProperties) : undefined; const brandName = branding?.brandName ?? "PodcastYes"; const removePoweredBy = branding?.removePoweredBy ?? false; // Prefer a directly-fetchable public URL (e.g. nginx /media); otherwise fall // back to the share-authorized public cover route. const coverUrl = episode.coverArt ? storage().publicUrl(episode.coverArt.storageKey) ?? `/api/public/episodes/${shareId}/cover` : null; const speakerNames: Record = {}; for (const s of episode.speakers) speakerNames[s.speakerKey] = s.displayName; const script = episode.script?.content as unknown as StructuredScript | undefined; return (
{/* Header / brand wordmark */}
{branding?.logoUrl ? ( // eslint-disable-next-line @next/next/no-img-element {brandName} ) : ( )} {brandName}
{coverUrl ? ( // eslint-disable-next-line @next/next/no-img-element {episode.title} ) : (
)}
Podcast episode

{episode.title}

{episode.format.replace("_", "-").toLowerCase()} · {episode.language.toUpperCase()} ·{" "} {episode.targetLengthMin} min

{episode.audioAsset && ( )}

About this episode

{episode.topic}

{script && script.sections?.length > 0 && (

Show notes

    {script.sections.map((s) => (
  • {s.title}
  • ))}
)}
{!removePoweredBy && ( )}
); }