import { nanoid } from 'nanoid'; import { nip19 } from 'nostr-tools'; import { ReactNode } from 'react'; import { Link } from 'react-router-dom'; import reactStringReplace from 'react-string-replace'; import { Hashtag, ImagePreview, LinkPreview, MentionNote, MentionUser, VideoPreview, } from '../components/note'; import { useStorage } from '../provider'; const NOSTR_MENTIONS = [ '@npub1', 'nostr:npub1', 'nostr:nprofile1', 'nostr:naddr1', 'npub1', 'nprofile1', 'naddr1', 'Nostr:npub1', 'Nostr:nprofile1', 'Nostr:naddre1', ]; const NOSTR_EVENTS = [ 'nostr:note1', 'note1', 'nostr:nevent1', 'nevent1', 'Nostr:note1', 'Nostr:nevent1', ]; // const BITCOINS = ['lnbc', 'bc1p', 'bc1q']; const IMAGES = ['.jpg', '.jpeg', '.gif', '.png', '.webp', '.avif', '.tiff']; const VIDEOS = [ '.mp4', '.mov', '.webm', '.wmv', '.flv', '.mts', '.avi', '.ogv', '.mkv', '.mp3', '.m3u8', ]; export function useRichContent(content: string, textmode = false) { const storage = useStorage(); let parsedContent: string | ReactNode[] = content.replace(/\n+/g, '\n'); let linkPreview: string; let images: string[] = []; let videos: string[] = []; let events: string[] = []; const text = parsedContent; const words = text.split(/( |\n)/); if (!textmode) { if (storage.settings.media) { images = words.filter((word) => IMAGES.some((el) => word.endsWith(el))); videos = words.filter((word) => VIDEOS.some((el) => word.endsWith(el))); } events = words.filter((word) => NOSTR_EVENTS.some((el) => word.startsWith(el))); } const hashtags = words.filter((word) => word.startsWith('#')); const mentions = words.filter((word) => NOSTR_MENTIONS.some((el) => word.startsWith(el)) ); try { if (images.length) { for(const image of images) { parsedContent = reactStringReplace(parsedContent, image, (match, i) => ( )); } } if (videos.length) { for(const video of videos) { parsedContent = reactStringReplace(parsedContent, video, (match, i) => ( )); } } if (hashtags.length) { for(const hashtag of hashtags) { parsedContent = reactStringReplace(parsedContent, hashtag, (match, i) => { if (storage.settings.hashtag) return ; return null; }); } } if (events.length) { for(const event of events) { const address = event.replace('nostr:', '').replace(/[^a-zA-Z0-9]/g, ''); const decoded = nip19.decode(address); if (decoded.type === 'note') { parsedContent = reactStringReplace(parsedContent, event, (match, i) => ( )); } if (decoded.type === 'nevent') { parsedContent = reactStringReplace(parsedContent, event, (match, i) => ( )); } } } if (mentions.length) { for(const mention of mentions) { const address = mention .replace('nostr:', '') .replace('@', '') .replace(/[^a-zA-Z0-9]/g, ''); const decoded = nip19.decode(address); if (decoded.type === 'npub') { parsedContent = reactStringReplace(parsedContent, mention, (match, i) => ( )); } if (decoded.type === 'nprofile' || decoded.type === 'naddr') { parsedContent = reactStringReplace(parsedContent, mention, (match, i) => ( )); } } } parsedContent = reactStringReplace(parsedContent, /(https?:\/\/\S+)/g, (match, i) => { const url = new URL(match); url.search = ''; if (!linkPreview && !textmode) { linkPreview = match; return ; } return ( {url.toString()} ); }); parsedContent = reactStringReplace(parsedContent, '\n', () => { return
; }); if (typeof parsedContent[0] === 'string') { parsedContent[0] = parsedContent[0].trimStart(); } return { parsedContent }; } catch (e) { console.warn('[parser] parse failed: ', e); return { parsedContent }; } }