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 textYESifvariableis non-empty.{variable:!NO}will insert the raw textNOifvariableis missing or empty.{variable:?YES:!NO}will insertYESif variable is non-empty, andNOotherwise.
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.