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 textYES
ifvariable
is non-empty.{variable:!NO}
will insert the raw textNO
ifvariable
is missing or empty.{variable:?YES:!NO}
will insertYES
if variable is non-empty, andNO
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.