Something went wrong. Try again.
🌿 Collaborative wiki on ATProto forked from juprodh.me/lichen.wiki
Something went wrong. Try again.
2.5 kB · 59 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960import type { MarkdownIt, Token } from "markdown-it";
const YOUTUBE_RE = /^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})(?:[?&]\S*)?$/;
const TWEET_RE = /^https?:\/\/(?:www\.)?(?:x|twitter)\.com\/[^/]+\/status\/\d+/;
// A lone image is the shape Obsidian embeds with; anything alongside it is a real image.function loneImage(inline: Token): Token | null { const only = inline.children?.length === 1 ? inline.children[0] : null; return only?.type === "image" ? only : null;}
// videoId is regex-bound to 11 url-safe chars, so the interpolated iframe src can't break out.function iframeHtml(videoId: string): string { return `<div class="youtube-embed aspect-video my-4"><iframe class="w-full h-full border-0" title="YouTube video player" src="https://www.youtube-nocookie.com/embed/${videoId}" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen loading="lazy"></iframe></div>\n`;}
// Obsidian embeds a video with the image form, ``; a bare URL alone// in a paragraph is Lichen's own syntax. Both mean the same thing, so both become the// iframe. Tweets deliberately become a plain link instead: an x.com embed is a third-party// frame, and `frame-src` (src/lib/response.ts) allows youtube-nocookie only.export function embedPlugin(mdi: MarkdownIt): void { mdi.core.ruler.push("embed", (state) => { const tokens = state.tokens; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token?.type !== "paragraph_open") continue;
const inline = tokens[i + 1]; const close = tokens[i + 2]; if (inline?.type !== "inline" || close?.type !== "paragraph_close") continue;
const image = loneImage(inline); const url = String(image?.attrGet("src") ?? inline.content.trim());
const match = YOUTUBE_RE.exec(url); if (match) { const htmlToken = new state.Token("html_block", "", 0); htmlToken.content = iframeHtml(match[1] as string); tokens.splice(i, 3, htmlToken); // p_open + inline + p_close → html_block continue; }
if (image && TWEET_RE.test(url)) { const linkOpen = new state.Token("link_open", "a", 1); linkOpen.attrSet("href", url); const text = new state.Token("text", "", 0); text.content = url; inline.children = [ linkOpen, text, new state.Token("link_close", "a", -1), ]; } } });}