diff --git a/src/components/Webmentions.astro b/src/components/Webmentions.astro index 1c1f00f..38732f5 100644 --- a/src/components/Webmentions.astro +++ b/src/components/Webmentions.astro @@ -1,7 +1,21 @@ --- import { DEFAULT_LOCALE, type Locale } from '~/consts'; import { getLocaleFromUrl, t } from '~/i18n/ui'; -import { getMentionsFor, groupMentions, type WMEntry } from '~/lib/webmentions'; + +interface WMAuthor { + name?: string; + url?: string; + photo?: string; +} +interface WMEntry { + author?: WMAuthor; + url: string; + published?: string; + 'wm-received'?: string; + 'wm-id'?: number; + 'wm-property'?: string; + content?: { text?: string }; +} interface Props { target: string | URL; @@ -10,14 +24,43 @@ interface Props { const { target, locale = getLocaleFromUrl(Astro.url) ?? DEFAULT_LOCALE } = Astro.props; -const all = await getMentionsFor(target); -const { likes, reposts, replies, mentions } = groupMentions(all); +async function fetchMentions(target: string): Promise { + const token = import.meta.env.WEBMENTION_TOKEN; + if (!token) return []; + const withSlash = target.endsWith('/') ? target : `${target}/`; + const withoutSlash = target.replace(/\/+$/, ''); + const fetchOne = async (t: string) => { + const url = new URL('https://webmention.io/api/mentions.jf2'); + url.searchParams.set('target', t); + url.searchParams.set('token', token); + url.searchParams.set('per-page', '100'); + const res = await fetch(url); + if (!res.ok) return [] as WMEntry[]; + const json = (await res.json()) as { children?: WMEntry[] }; + return json.children ?? []; + }; + const [a, b] = await Promise.all([fetchOne(withSlash), fetchOne(withoutSlash)]); + const seen = new Set(); + const merged: WMEntry[] = []; + for (const m of [...a, ...b]) { + const id = m['wm-id']; + if (id == null || seen.has(id)) continue; + seen.add(id); + merged.push(m); + } + return merged; +} -const facepile = [...likes, ...reposts]; +const targetStr = target.toString(); +const all = await fetchMentions(targetStr); -console.log( - `[webmentions component] target=${target.toString()} all=${all.length} likes=${likes.length} reposts=${reposts.length} replies=${replies.length} mentions=${mentions.length} facepile=${facepile.length}`, +const likes = all.filter((m) => m['wm-property'] === 'like-of'); +const reposts = all.filter((m) => m['wm-property'] === 'repost-of'); +const replies = all.filter((m) => m['wm-property'] === 'in-reply-to'); +const mentions = all.filter( + (m) => !['like-of', 'repost-of', 'in-reply-to', 'bookmark-of'].includes(m['wm-property'] ?? ''), ); +const facepile = [...likes, ...reposts]; function authorInitial(m: WMEntry) { return m.author?.name?.trim()?.[0]?.toUpperCase() ?? '?'; @@ -34,13 +77,9 @@ function formatDate(iso?: string) { } const hasAny = facepile.length > 0 || replies.length > 0 || mentions.length > 0; - -console.log(`[webmentions component] hasAny=${hasAny}`); --- - -
DEBUG: hasAny={hasAny ? 'true' : 'false'} facepile={facepile.length} likes={likes.length}
- + { hasAny && (