jeff
2024-01-02 88194ac348222f9e3deed92f6e149da23a644311
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
2 files modified
28 ■■■■■ changed files
docs/features/Obsidian compatibility.md 1 ●●●● patch | view | raw | blame | history
quartz/plugins/transformers/ofm.ts 27 ●●●●● patch | view | raw | blame | history
docs/features/Obsidian compatibility.md
@@ -26,6 +26,7 @@
    - `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`
quartz/plugins/transformers/ofm.ts
@@ -25,6 +25,7 @@
  parseTags: boolean
  parseBlockReferences: boolean
  enableInHtmlEmbed: boolean
  enableYouTubeEmbed: boolean
}
const defaultOptions: Options = {
@@ -36,6 +37,7 @@
  parseTags: true,
  parseBlockReferences: true,
  enableInHtmlEmbed: false,
  enableYouTubeEmbed: false,
}
const icons = {
@@ -127,6 +129,7 @@
// (?:\/[-_\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<Partial<Options> | undefined> = (
  userOpts,
@@ -505,6 +508,30 @@
        })
      }
      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() {