120 lines
2.7 KiB
TypeScript
120 lines
2.7 KiB
TypeScript
import { MentionUser } from "@shared/notes/mentions/user";
|
|
import destr from "destr";
|
|
import getUrls from "get-urls";
|
|
import { parseReferences } from "nostr-tools";
|
|
import { ReactNode } from "react";
|
|
import { Link } from "react-router-dom";
|
|
import reactStringReplace from "react-string-replace";
|
|
|
|
function isJsonString(str: string) {
|
|
try {
|
|
JSON.parse(str);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function parser(event: any) {
|
|
if (isJsonString(event.tags)) {
|
|
event["tags"] = destr(event.tags);
|
|
}
|
|
|
|
const references = parseReferences(event);
|
|
const urls = getUrls(event.content);
|
|
|
|
const content: {
|
|
original: string;
|
|
parsed: ReactNode[];
|
|
notes: string[];
|
|
images: string[];
|
|
videos: string[];
|
|
links: string[];
|
|
} = {
|
|
original: event.content,
|
|
parsed: event.content,
|
|
notes: [],
|
|
images: [],
|
|
videos: [],
|
|
links: [],
|
|
};
|
|
|
|
// remove unnecessary whitespaces
|
|
// @ts-ignore
|
|
content.parsed = content.parsed.replace(/\s{2,}/g, " ");
|
|
|
|
// remove unnecessary linebreak
|
|
// @ts-ignore
|
|
content.parsed = content.parsed.replace(/(\r\n|\r|\n){2,}/g, "$1\n");
|
|
|
|
// parse urls
|
|
urls?.forEach((url: string) => {
|
|
if (url.match(/\.(jpg|jpeg|gif|png|webp|avif)$/)) {
|
|
// image url
|
|
content.images.push(url);
|
|
// remove url from original content
|
|
content.parsed = reactStringReplace(content.parsed, url, () => null);
|
|
} else if (url.match(/\.(mp4|webm|mov|ogv|avi|mp3)$/)) {
|
|
// video
|
|
content.videos.push(url);
|
|
// remove url from original content
|
|
content.parsed = reactStringReplace(content.parsed, url, () => null);
|
|
} else {
|
|
if (content.links.length < 1) {
|
|
// push to store
|
|
content.links.push(url);
|
|
// remove url from original content
|
|
content.parsed = reactStringReplace(content.parsed, url, () => null);
|
|
} else {
|
|
content.parsed = reactStringReplace(
|
|
content.parsed,
|
|
/#(\w+)/g,
|
|
(match, i) => (
|
|
<Link
|
|
key={match + i}
|
|
to={match}
|
|
className="text-fuchsia-500 hover:text-fuchsia-600 no-underline font-normal"
|
|
>
|
|
{match}
|
|
</Link>
|
|
),
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
// parse nostr
|
|
references?.forEach((item) => {
|
|
const profile = item.profile;
|
|
const event = item.event;
|
|
if (event) {
|
|
content.notes.push(event.id);
|
|
content.parsed = reactStringReplace(
|
|
content.parsed,
|
|
item.text,
|
|
() => null,
|
|
);
|
|
}
|
|
if (profile) {
|
|
content.parsed = reactStringReplace(
|
|
content.parsed,
|
|
item.text,
|
|
(match, i) => <MentionUser key={match + i} pubkey={profile.pubkey} />,
|
|
);
|
|
}
|
|
});
|
|
|
|
// parse hashtag
|
|
content.parsed = reactStringReplace(content.parsed, /#(\w+)/g, (match, i) => (
|
|
<Link
|
|
key={match + i}
|
|
to={`/search/${match}`}
|
|
className="text-fuchsia-500 hover:text-fuchsia-600 no-underline font-normal"
|
|
>
|
|
#{match}
|
|
</Link>
|
|
));
|
|
|
|
return content;
|
|
}
|