fix: og image generation

This commit is contained in:
gosangam
2026-05-06 01:45:47 +05:30
parent de374eab8b
commit 7361f9c14a
28 changed files with 221 additions and 45 deletions
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type BbdChapter, type BbdChapter,
type BbdSidebarItem, type BbdSidebarItem,
} from "@/lib/bbd"; } from "@/lib/bbd";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -29,8 +30,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("bbd", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["bbd"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["bbd"], quote: hlQuote });
} }
+8 -1
View File
@@ -18,7 +18,14 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter, verse } = await params; const { chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getSingleVerse(
"bg",
null,
parseInt(chapter),
parseInt(verse),
);
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Bhagavad-gītā As It Is", title: "Bhagavad-gītā As It Is",
+4 -1
View File
@@ -7,6 +7,7 @@ import {
type BkChapter, type BkChapter,
type BkSidebarItem, type BkSidebarItem,
} from "@/lib/bk"; } from "@/lib/bk";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -25,8 +26,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("bk", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["bk"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["bk"], quote: hlQuote });
} }
+3 -1
View File
@@ -123,7 +123,9 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter, verse } = await params; const { chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getVerseWithFallback(parseInt(chapter), parseInt(verse));
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Śrī Brahma-saṁhitā", title: "Śrī Brahma-saṁhitā",
+4 -1
View File
@@ -7,6 +7,7 @@ import {
type CbhcChapter, type CbhcChapter,
type CbhcSidebarItem, type CbhcSidebarItem,
} from "@/lib/cbhc"; } from "@/lib/cbhc";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -25,8 +26,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("cbhc", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["cbhc"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["cbhc"], quote: hlQuote });
} }
@@ -32,7 +32,14 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { lila, chapter, verse } = await params; const { lila, chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getSingleVerse(
"cc",
lila,
parseInt(chapter),
parseInt(verse),
);
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
const bookTitle = "Śrī Caitanya-caritāmṛta"; const bookTitle = "Śrī Caitanya-caritāmṛta";
return buildOgMeta({ return buildOgMeta({
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type DsChapter, type DsChapter,
type DsSidebarItem, type DsSidebarItem,
} from "@/lib/ds"; } from "@/lib/ds";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -29,8 +30,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("ds", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["ds"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["ds"], quote: hlQuote });
} }
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type EjChapter, type EjChapter,
type EjSidebarItem, type EjSidebarItem,
} from "@/lib/ej"; } from "@/lib/ej";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -29,8 +30,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("ej", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["ej"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["ej"], quote: hlQuote });
} }
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type EkChapter, type EkChapter,
type EkSidebarItem, type EkSidebarItem,
} from "@/lib/ek"; } from "@/lib/ek";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -29,8 +30,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("ek", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["ek"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["ek"], quote: hlQuote });
} }
+4 -1
View File
@@ -7,6 +7,7 @@ import {
type GgChapter, type GgChapter,
type GgSidebarItem, type GgSidebarItem,
} from "@/lib/gg"; } from "@/lib/gg";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -25,8 +26,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("gg", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["gg"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["gg"], quote: hlQuote });
} }
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type HkhChapter, type HkhChapter,
type HkhSidebarItem, type HkhSidebarItem,
} from "@/lib/hkh"; } from "@/lib/hkh";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -29,8 +30,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("hkh", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["hkh"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["hkh"], quote: hlQuote });
} }
+9 -3
View File
@@ -46,7 +46,15 @@ export async function generateMetadata({
const { mantra: slug } = await params; const { mantra: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const content = await getIsoContent(slug);
const isVerse_ = content && "mantra" in content && "devanagari" in content;
const paragraphs = content
? isVerse_
? [(content as IsoVerse).translation, ...(content as IsoVerse).purport]
: (content as IsoIntroSegment).paragraphs
: undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Śrī Īśopaniṣad", title: "Śrī Īśopaniṣad",
@@ -55,8 +63,6 @@ export async function generateMetadata({
}); });
} }
const content = await getIsoContent(slug);
const isVerse_ = content && "mantra" in content && "devanagari" in content;
const title = isVerse_ const title = isVerse_
? `${(content as IsoVerse).reference}: ${(content as IsoVerse).title}` ? `${(content as IsoVerse).reference}: ${(content as IsoVerse).title}`
: content && "title" in content : content && "title" in content
+1 -1
View File
@@ -24,7 +24,7 @@ export async function generateMetadata({
const sp = await searchParams; const sp = await searchParams;
const vol = parseInt(volume); const vol = parseInt(volume);
const chapter = !isNaN(vol) ? await getProseChapter("kb", vol, slug) : null; const chapter = !isNaN(vol) ? await getProseChapter("kb", vol, slug) : null;
const hlQuote = extractQuoteFromHl(sp); const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ return buildOgMeta({
title: BOOK_NAMES["kb"], title: BOOK_NAMES["kb"],
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type LclChapter, type LclChapter,
type LclSidebarItem, type LclSidebarItem,
} from "@/lib/lcl"; } from "@/lib/lcl";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -29,8 +30,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("lcl", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["lcl"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["lcl"], quote: hlQuote });
} }
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type LobChapter, type LobChapter,
type LobSidebarItem, type LobSidebarItem,
} from "@/lib/lob"; } from "@/lib/lob";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -25,8 +26,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("lob", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["lob"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["lob"], quote: hlQuote });
} }
+4 -1
View File
@@ -9,6 +9,7 @@ import {
type MgChapter, type MgChapter,
type MgSidebarItem, type MgSidebarItem,
} from "@/lib/mg"; } from "@/lib/mg";
import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/page-header"; import { PageHeader } from "@/components/page-header";
@@ -25,8 +26,10 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>; searchParams: Promise<Record<string, string | string[] | undefined>>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const hlQuote = extractQuoteFromHl(sp); const chapter = await getProseChapter("mg", 0, slug);
const hlQuote = extractQuoteFromHl(sp, chapter?.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ title: BOOK_NAMES["mg"], quote: hlQuote }); return buildOgMeta({ title: BOOK_NAMES["mg"], quote: hlQuote });
} }
+3 -1
View File
@@ -26,7 +26,9 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter, verse } = await params; const { chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getVerseWithFallback(parseInt(chapter), parseInt(verse));
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Mukunda-mālā-stotra", title: "Mukunda-mālā-stotra",
+8 -1
View File
@@ -123,7 +123,14 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter, verse } = await params; const { chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getSingleVerse(
"nbs",
null,
parseInt(chapter),
parseInt(verse),
);
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Nārada-bhakti-sūtra", title: "Nārada-bhakti-sūtra",
+13 -1
View File
@@ -46,7 +46,19 @@ export async function generateMetadata({
const { text: slug } = await params; const { text: slug } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const content = await getNoiContent(slug);
let paragraphs: string[] | undefined;
if (content) {
if ("devanagari" in content) {
// It's a verse
paragraphs = [content.translation, ...content.purport];
} else if ("paragraphs" in content) {
// It's an intro segment
paragraphs = content.paragraphs;
}
}
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "The Nectar of Instruction", title: "The Nectar of Instruction",
@@ -31,7 +31,14 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { canto, chapter, verse } = await params; const { canto, chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getSingleVerse(
"sb",
canto,
parseInt(chapter),
parseInt(verse),
);
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Śrīmad-Bhāgavatam", title: "Śrīmad-Bhāgavatam",
+8 -1
View File
@@ -26,7 +26,14 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter, verse } = await params; const { chapter, verse } = await params;
const sp = await searchParams; const sp = await searchParams;
const quote = extractQuoteFromHl(sp); const v = await getSingleVerse(
"sb1962",
null,
parseInt(chapter),
parseInt(verse),
);
const paragraphs = v ? [v.translation, ...v.purport] : undefined;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: "Śrīmad-Bhāgavatam (1962)", title: "Śrīmad-Bhāgavatam (1962)",
+1 -1
View File
@@ -104,7 +104,7 @@ export async function generateMetadata({
const essay = await getEssay(slug); const essay = await getEssay(slug);
if (!essay) return {}; if (!essay) return {};
const hlQuote = extractQuoteFromHl(sp); const hlQuote = extractQuoteFromHl(sp, essay.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ return buildOgMeta({
title: essay.title, title: essay.title,
+1 -1
View File
@@ -37,7 +37,7 @@ export async function generateMetadata({
const journalTitle = meta?.title || slug; const journalTitle = meta?.title || slug;
const entryTitle = content?.title || chapterSlug; const entryTitle = content?.title || chapterSlug;
const quote = extractQuoteFromHl(sp); const quote = extractQuoteFromHl(sp, content?.paragraphs);
if (quote) { if (quote) {
return buildOgMeta({ return buildOgMeta({
title: journalTitle, title: journalTitle,
+1 -1
View File
@@ -24,7 +24,7 @@ export async function generateMetadata({
if (!letter) return {}; if (!letter) return {};
const meta = [letter.date, letter.location].filter(Boolean).join(" · "); const meta = [letter.date, letter.location].filter(Boolean).join(" · ");
const hlQuote = extractQuoteFromHl(sp); const hlQuote = extractQuoteFromHl(sp, letter.paragraphs);
if (hlQuote) { if (hlQuote) {
return buildOgMeta({ return buildOgMeta({
+7 -7
View File
@@ -29,19 +29,19 @@ export async function generateMetadata({
const sp = await searchParams; const sp = await searchParams;
const bookCode = slugToBookCode(slug); const bookCode = slugToBookCode(slug);
const quote = extractQuoteFromHl(sp);
if (quote) {
const meta = await getMagazineMeta(bookCode);
const title = meta?.title ?? slug;
return buildOgMeta({ title, quote });
}
const [meta, content] = await Promise.all([ const [meta, content] = await Promise.all([
getMagazineMeta(bookCode), getMagazineMeta(bookCode),
getMagazineContent(bookCode, issueSlug), getMagazineContent(bookCode, issueSlug),
]); ]);
const magTitle = meta?.title ?? slug; const magTitle = meta?.title ?? slug;
const paragraphs = content?.paragraphs;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) {
return buildOgMeta({ title: magTitle, quote });
}
const issueTitle = content?.title ?? undefined; const issueTitle = content?.title ?? undefined;
return ogForMagazine(magTitle, issueTitle); return ogForMagazine(magTitle, issueTitle);
@@ -33,20 +33,19 @@ export async function generateMetadata({
const sp = await searchParams; const sp = await searchParams;
const bookCode = slugToBookCode(slug); const bookCode = slugToBookCode(slug);
const quote = extractQuoteFromHl(sp);
if (quote) {
const meta = await getOtherDocumentMeta(bookCode);
const content = await getOtherDocumentContent(bookCode, chapterSlug);
const title = meta?.title ?? slug;
const detail = content?.title ?? `Chapter ${chapterSlug}`;
return buildOgMeta({ title, detail, quote });
}
const [meta, content] = await Promise.all([ const [meta, content] = await Promise.all([
getOtherDocumentMeta(bookCode), getOtherDocumentMeta(bookCode),
getOtherDocumentContent(bookCode, chapterSlug), getOtherDocumentContent(bookCode, chapterSlug),
]); ]);
const paragraphs = content?.paragraphs;
const quote = extractQuoteFromHl(sp, paragraphs);
if (quote) {
const title = meta?.title ?? slug;
const detail = content?.title ?? `Chapter ${chapterSlug}`;
return buildOgMeta({ title, detail, quote });
}
return ogForOtherDocument(meta?.title ?? slug, content?.title ?? undefined); return ogForOtherDocument(meta?.title ?? slug, content?.title ?? undefined);
} }
+25 -3
View File
@@ -6,7 +6,7 @@
*/ */
import { BOOK_NAMES, CC_LILAS } from "@/lib/constants"; import { BOOK_NAMES, CC_LILAS } from "@/lib/constants";
import { decodeTextFragment } from "@/lib/text-highlight"; import { decodeTextFragment, extractMatchedText } from "@/lib/text-highlight";
const SITE_URL = const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL || "https://prabhupadasays.org"; process.env.NEXT_PUBLIC_SITE_URL || "https://prabhupadasays.org";
@@ -305,13 +305,18 @@ export function ogForLettersByLocation(location: string, count: number) {
/** /**
* Extract a display quote from the `?hl=` search param. * Extract a display quote from the `?hl=` search param.
* *
* The `hl` param encodes `prefix,suffix,length`. We reconstruct a readable * When `paragraphs` are provided (from the database), the full matched text
* snippet from the prefix + suffix: "first few words ... last few words" * is extracted by searching the content — giving the OG image the actual
* selected quote, not just the prefix/suffix.
*
* When `paragraphs` are not provided, falls back to reconstructing a
* readable snippet from prefix + suffix: "first few words ... last few words"
* *
* Returns null if hl is missing or invalid. * Returns null if hl is missing or invalid.
*/ */
export function extractQuoteFromHl( export function extractQuoteFromHl(
searchParams: Record<string, string | string[] | undefined> | URLSearchParams, searchParams: Record<string, string | string[] | undefined> | URLSearchParams,
paragraphs?: string[],
): string | null { ): string | null {
const raw = const raw =
searchParams instanceof URLSearchParams searchParams instanceof URLSearchParams
@@ -325,6 +330,23 @@ export function extractQuoteFromHl(
const fragment = decodeTextFragment(raw); const fragment = decodeTextFragment(raw);
if (!fragment) return null; if (!fragment) return null;
// If paragraphs are available, extract the full matched text
if (paragraphs && paragraphs.length > 0) {
const fullMatch = extractMatchedText(fragment, paragraphs);
if (fullMatch) {
// Truncate at word boundary if too long for OG image
if (fullMatch.length > 280) {
const truncated = fullMatch.slice(0, 277);
const lastSpace = truncated.lastIndexOf(" ");
return (
(lastSpace > 200 ? truncated.slice(0, lastSpace) : truncated) + "..."
);
}
return fullMatch;
}
}
// Fallback: reconstruct from prefix + suffix
const { prefix, suffix } = fragment; const { prefix, suffix } = fragment;
if (!prefix) return null; if (!prefix) return null;
+65
View File
@@ -1,5 +1,9 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Text Fragment Highlight — compact URL encoding for selected text // Text Fragment Highlight — compact URL encoding for selected text
//
// These utilities work in both browser and server environments.
// The DOM-based findAndHighlightText() is browser-only.
// The string-based extractMatchedText() is server-safe (for OG image generation).
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
@@ -52,6 +56,67 @@ export function decodeTextFragment(
return { prefix, suffix, length }; return { prefix, suffix, length };
} }
/**
* Server-side: extract the full matched text from an array of paragraph strings
* using a decoded text fragment (prefix, suffix, length).
*
* This is the server equivalent of findAndHighlightText() — instead of
* walking the DOM, it searches a flat array of HTML paragraph strings.
* HTML tags are stripped before matching.
*
* Returns the matched text string, or null if not found.
*/
export function extractMatchedText(
fragment: { prefix: string; suffix: string; length: number },
paragraphs: string[],
): string | null {
// Strip HTML tags to get plain text
const plainParagraphs = paragraphs.map((p) =>
p.replace(/<[^>]*>/g, "").replace(/&[^;]+;/g, " "),
);
// Build a single string with paragraph breaks
const fullText = plainParagraphs.join(" ");
const normalized = fullText.replace(/\s+/g, " ");
const normalizedPrefix = fragment.prefix.replace(/\s+/g, " ");
let searchFrom = 0;
let matchStart = -1;
while (searchFrom < normalized.length) {
const idx = normalized.indexOf(normalizedPrefix, searchFrom);
if (idx === -1) break;
if (fragment.suffix) {
const normalizedSuffix = fragment.suffix.replace(/\s+/g, " ");
const expectedEnd = idx + fragment.length;
const suffixSearchStart = Math.max(
idx,
expectedEnd - normalizedSuffix.length - 20,
);
const suffixSearchEnd = Math.min(normalized.length, expectedEnd + 20);
const searchWindow = normalized.slice(suffixSearchStart, suffixSearchEnd);
if (searchWindow.includes(normalizedSuffix)) {
matchStart = idx;
break;
}
} else {
matchStart = idx;
break;
}
searchFrom = idx + 1;
}
if (matchStart === -1) return null;
const matchEnd = Math.min(matchStart + fragment.length, normalized.length);
const matched = normalized.slice(matchStart, matchEnd).trim();
if (matched.length === 0) return null;
return matched;
}
/** /**
* Build the full URL with highlight fragment for the selected text. * Build the full URL with highlight fragment for the selected text.
*/ */