import type { Event } from 'nostr-tools' import type { Article, KindType, MediaRef, Review, Series } from '@/types/nostr' /** * Parse article metadata from Nostr event */ export function parseArticleFromEvent(event: Event): Article | null { try { const tags = extractTags(event) if (tags.kindType && tags.kindType !== 'article') { return null } const { previewContent } = getPreviewContent(event.content, tags.preview) return buildArticle(event, tags, previewContent) } catch (e) { console.error('Error parsing article:', e) return null } } export function parseSeriesFromEvent(event: Event): Series | null { try { const tags = extractTags(event) if (tags.kindType && tags.kindType !== 'series') { return null } if (!tags.title || !tags.description) { return null } const series: Series = { id: event.id, pubkey: event.pubkey, title: tags.title, description: tags.description, preview: tags.preview ?? event.content.substring(0, 200), ...(tags.category ? { category: tags.category } : { category: 'science-fiction' }), ...(tags.coverUrl ? { coverUrl: tags.coverUrl } : {}), } if (tags.kindType) { series.kindType = tags.kindType } return series } catch (e) { console.error('Error parsing series:', e) return null } } export function parseReviewFromEvent(event: Event): Review | null { try { const tags = extractTags(event) if (tags.kindType && tags.kindType !== 'review') { return null } const articleId = tags.articleId const reviewer = tags.reviewerPubkey if (!articleId || !reviewer) { return null } const rewardedTag = event.tags.find((tag) => tag[0] === 'rewarded' && tag[1] === 'true') const rewardAmountTag = event.tags.find((tag) => tag[0] === 'reward_amount') const review: Review = { id: event.id, articleId, authorPubkey: tags.author ?? event.pubkey, reviewerPubkey: reviewer, content: event.content, createdAt: event.created_at, ...(tags.title ? { title: tags.title } : {}), ...(rewardedTag ? { rewarded: true } : {}), ...(rewardAmountTag ? { rewardAmount: parseInt(rewardAmountTag[1] ?? '0', 10) } : {}), } if (tags.kindType) { review.kindType = tags.kindType } return review } catch (e) { console.error('Error parsing review:', e) return null } } function extractTags(event: Event) { const findTag = (key: string) => event.tags.find((tag) => tag[0] === key)?.[1] const mediaTags = event.tags.filter((tag) => tag[0] === 'media') const media: MediaRef[] = mediaTags .map((tag) => { const url = tag[1] const type = tag[2] === 'video' ? 'video' : 'image' if (!url) { return null } return { url, type } }) .filter(Boolean) as MediaRef[] return { title: findTag('title') ?? 'Untitled', preview: findTag('preview'), description: findTag('description'), zapAmount: parseInt(findTag('zap') ?? '800', 10), invoice: findTag('invoice'), paymentHash: findTag('payment_hash'), category: findTag('category') as import('@/types/nostr').ArticleCategory | undefined, isPresentation: findTag('presentation') === 'true', mainnetAddress: findTag('mainnet_address'), totalSponsoring: parseInt(findTag('total_sponsoring') ?? '0', 10), authorPresentationId: findTag('author_presentation_id'), seriesId: findTag('series'), bannerUrl: findTag('banner'), coverUrl: findTag('cover'), media, kindType: findTag('kind_type') as KindType | undefined, articleId: findTag('article'), reviewerPubkey: findTag('reviewer'), author: findTag('author'), } } function getPreviewContent(content: string, previewTag?: string) { const lines = content.split('\n') const previewContent = previewTag ?? lines[0] ?? content.substring(0, 200) return { previewContent } } function buildArticle(event: Event, tags: ReturnType, preview: string): Article { return { id: event.id, pubkey: event.pubkey, title: tags.title, preview, content: '', createdAt: event.created_at, zapAmount: tags.zapAmount, paid: false, ...(tags.invoice ? { invoice: tags.invoice } : {}), ...(tags.paymentHash ? { paymentHash: tags.paymentHash } : {}), ...(tags.category ? { category: tags.category } : {}), ...(tags.isPresentation ? { isPresentation: tags.isPresentation } : {}), ...(tags.mainnetAddress ? { mainnetAddress: tags.mainnetAddress } : {}), ...(tags.totalSponsoring ? { totalSponsoring: tags.totalSponsoring } : {}), ...(tags.authorPresentationId ? { authorPresentationId: tags.authorPresentationId } : {}), ...(tags.seriesId ? { seriesId: tags.seriesId } : {}), ...(tags.bannerUrl ? { bannerUrl: tags.bannerUrl } : {}), ...(tags.media.length ? { media: tags.media } : {}), ...(tags.kindType ? { kindType: tags.kindType } : {}), } }