From 88194ac348222f9e3deed92f6e149da23a644311 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 2 Jan 2024 13:49:14 -0500 Subject: [PATCH] feat: allow embedding youtube videos with the obsidian markdown syntax (#665) * Add option to allow embedding YouTube videos with Obsidian Markdown syntax * Update Obsidian compatability doc page * Switch to converting YT links as an html plugin --- docs/features/Obsidian compatibility.md | 1 + quartz/plugins/transformers/ofm.ts | 27 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/features/Obsidian compatibility.md b/docs/features/Obsidian compatibility.md index 61fcc060d..d519e1779 100644 --- a/docs/features/Obsidian compatibility.md +++ b/docs/features/Obsidian compatibility.md @@ -26,6 +26,7 @@ Finally, Quartz also provides `Plugin.CrawlLinks` which allows you to customize - `mermaid`: whether to enable [[Mermaid diagrams]]. Defaults to `true` - `parseTags`: whether to try and parse tags in the content body. Defaults to `true` - `enableInHtmlEmbed`: whether to try and parse Obsidian flavoured markdown in raw HTML. Defaults to `false` + - `enableYouTubeEmbed`: whether to enable embedded YouTube videos using external image Markdown syntax. Defaults to `false` - Link resolution behaviour: - Disabling: remove all instances of `Plugin.CrawlLinks()` from `quartz.config.ts` - Changing link resolution preference: set `markdownLinkResolution` to one of `absolute`, `relative` or `shortest` diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index 8502440ee..be3344aa4 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -25,6 +25,7 @@ export interface Options { parseTags: boolean parseBlockReferences: boolean enableInHtmlEmbed: boolean + enableYouTubeEmbed: boolean } const defaultOptions: Options = { @@ -36,6 +37,7 @@ const defaultOptions: Options = { parseTags: true, parseBlockReferences: true, enableInHtmlEmbed: false, + enableYouTubeEmbed: false, } const icons = { @@ -127,6 +129,7 @@ const calloutLineRegex = new RegExp(/^> *\[\!\w+\][+-]?.*$/, "gm") // (?:\/[-_\p{L}\d\p{Z}]+)*) -> non-capturing group, matches an arbitrary number of tag strings separated by "/" const tagRegex = new RegExp(/(?:^| )#((?:[-_\p{L}\p{Emoji}\d])+(?:\/[-_\p{L}\p{Emoji}\d]+)*)/, "gu") const blockReferenceRegex = new RegExp(/\^([A-Za-z0-9]+)$/, "g") +const ytLinkRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin | undefined> = ( userOpts, @@ -505,6 +508,30 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin }) } + if (opts.enableYouTubeEmbed) { + plugins.push(() => { + return (tree: HtmlRoot) => { + visit(tree, "element", (node) => { + if (node.tagName === "img" && typeof node.properties.src === "string") { + const match = node.properties.src.match(ytLinkRegex) + const videoId = match && match[2].length == 11 ? match[2] : null + if (videoId) { + node.tagName = "iframe" + node.properties = { + class: "external-embed", + allow: "fullscreen", + frameborder: 0, + width: "600px", + height: "350px", + src: `https://www.youtube.com/embed/${videoId}`, + } + } + } + }) + } + }) + } + return plugins }, externalResources() {