diff --git a/apps/web/src/app/[slug]/page.jsx b/apps/web/src/app/[slug]/page.jsx index 0fd94f1..fbdb1c3 100644 --- a/apps/web/src/app/[slug]/page.jsx +++ b/apps/web/src/app/[slug]/page.jsx @@ -1,5 +1,6 @@ import { notFound } from 'next/navigation'; import { q, alerts, queue, authors as people } from '@rssamplifier/db'; +import { socialDisplayTitle, socialPathFor } from '@rssamplifier/social'; import { db, siteUrl } from '../../lib/db.js'; import { currentUser } from '../../lib/auth.js'; @@ -42,7 +43,7 @@ export async function generateMetadata({ params }) { const feed = await q.feedBySlug(db(), slug); if (!feed) return { title: 'Not found' }; - const title = String(feed.title); + const title = displayTitle(feed); const description = feed.description ? String(feed.description) : `Latest ${(CATEGORIES[String(feed.category)] ?? CATEGORIES.blog).item} from ${feed.title}.`; @@ -232,7 +233,11 @@ export default async function FeedPage({ params }) {

{category.one[0].toUpperCase() + category.one.slice(1)}

-

{feed.title}

+ {/* The canonical name where the stored title says nothing. Most of the + 50,026 imported subreddits have not been crawled yet and carry the + bare host as their title, so this heading read "reddit.com" on every + one of them. A real title always wins; see socialDisplayTitle. */} +

{displayTitle(feed)}

{feed.description &&

{feed.description}

}
@@ -482,6 +487,22 @@ export default async function FeedPage({ params }) { * @param {unknown} iso * @returns {string} */ +/** + * What to call this feed on the page. + * + * Only ever different for a social row whose title was never crawled — every + * other feed, and every crawled social one, gets its own title back unchanged. + * `socialPathFor` supplies the fallback because the ref already encodes the + * canonical name: `/r/programming` becomes `r/programming`. + * + * @param {{ title?: unknown, feed_url?: unknown, social_ref?: unknown, slug?: unknown }} feed + * @returns {string} + */ +function displayTitle(feed) { + if (!feed?.social_ref) return String(feed?.title ?? ''); + return socialDisplayTitle(feed, socialPathFor(feed).replace(/^\//, '')); +} + function formatDate(iso) { if (!iso) return 'undated'; const d = new Date(String(iso)); diff --git a/packages/db/src/queries.js b/packages/db/src/queries.js index bc2f7d3..9c7a007 100644 --- a/packages/db/src/queries.js +++ b/packages/db/src/queries.js @@ -58,7 +58,8 @@ const FEED_COLS = `id, slug, feed_url, site_url, title, description, language, i author, categories, kind, category, category_source, status, last_fetched_at, last_success_at, last_error, error_count, fetch_interval_minutes, next_fetch_at, item_count, last_published_at, created_at, updated_at, source_kind, card_url, card_width, card_height, card_type, authors_checked_at, - http_etag, http_last_modified, content_hash, change_log`; + http_etag, http_last_modified, content_hash, change_log, + social_network, social_ref, social_config`; /** The categories the directory is browsable by. */ export const KINDS = ['blog', 'news', 'podcast', 'music', 'video', 'comic', 'live', 'reel'];