I normally use pinboard.in to manage my bookmarks. But, I’ve been curious about how simple it would be to capture websites directly into a Dendron vault from a Firefox extension.

Looking for a good option, I found this: MarkDownload (addon store link). It’s an extension that runs the site through Readability and Turndown to generate a Markdown document. Sounds perfect!

One of the cool things about MarkDownload is that it’s really configurable — you can write templates for the captured filename, frontmatter, etc. But, it doesn’t quite have the options I wanted for seamless Dendron interop. So, I forked it.

The forked README.md has an explicit list of my new commits and their changes.

I don’t currently plan to submit a pull request for these changes, because they are specific for my use-case and only tested in Firefox.

To install, clone the forked repo and load the src directory as a temporary extension in about:debugging (in Firefox).

Summary of Changes

At a high level, I made the following changes:

Unique IDs

Created an {id} template variable, which injects a unique ID for each capture. Used to generate the Dendron ID for each note.

Slugify

Added a :slug template variable modifier that “slugifies” the value (e.g. {variable:slug} to slugify the value in variable). Slugify means to replace all sequences of non-word characters with -, and then strip any - from the beginning/end of the value. For example, https://example.com/ would be slugified to https-example-com.

Conditional substitutions

Added conditional variable substitutions:

  • {variable:?YES} will insert the raw text YES if variable is non-empty.
  • {variable:!NO} will insert the raw text NO if variable is missing or empty.
  • {variable:?YES:!NO} will insert YES if variable is non-empty, and NO otherwise.

Stacking modifiers

Supported modifier stacking: write {variable:slug:snake} to pass the variable’s value through slug and then snake.

Stacking works with conditional modifiers: {variable:slug:?YES} will insert YES if the slugified string is non-empty.

Usage w/Dendron

I use the following configuration to capture to Dendron.

First, I open Dendron and create a new vault in /home/luke/Dendron/bookmarks.

Then I create a link from /home/luke/Downloads/bookmarks to /home/luke/Dendron/bookmarks:

ln -s /home/luke/Dendron/bookmarks /home/luke/Downloads

(This is necessary because MarkDownload cannot save to folders outside the Downloads directory.)

Then I configure MarkDownload with the following settings:

Template for title/filename:

ref.bookmark.{hostname:slug}{pathname:slug:?.}{pathname:slug}

Folder inside Downloads/ to store MarkDownload clips:

bookmarks

Template for frontmatter:

---
id: {id}
title: {pageTitle}
updated: {date:x}
source_url: {baseURI}
source_author: {byline}
source_captured: {date:YYYY-MM-DDTHH:mm:ss} (UTC {date:Z})
source_keywords: {keywords}
desc: """
{excerpt}
"""
---

Now when I capture a page, MarkDownload generates a Dendron note file with human-readable name and valid frontmatter.

Example

Capturing https://blog.luketurner.org/posts/aftermath/ creates a file named:

~/Downloads/bookmarks/ref.bookmark.blog-luketurner-org.posts-aftermath.md

The content is something like this:

---
id: cdb9081e6d2947fdbd42bfa7253f34ac
title: Compiling Mermaid, KaTeX, and D2 at build-time with aftermath | veni vidi cogitavi
updated: 1673646906526
source_url: https://blog.luketurner.org/posts/aftermath/
source_author: 
source_captured: 2023-01-13T13:55:06 (UTC -08:00)
source_keywords: 
desc: """
I’m happy to report that you no longer need JavaScript to see rendered KaTeX expressions and Mermaid diagrams in my blog posts! I wrote a script aftermath that post-processes my blog posts to compile the following to SVGs at build-time:
"""
---

Page content is captured here -- but snipped from example for brevity.