The Complete Computing Environment

org-protocol to quickly annotate web pages

LifeTechEmacsTopicsArcology

In Email and News and Information Pipelines I sketched out a data-flow of information from the internet in to my brain and my exobrain, the Zettelkasten. I am zooming in here on a specific edge of that graph on this page, a direct conduit between Firefox Desktop and my Archive. When I am actively reading a web page, when I need to jot a quick piece of information down, or remember a GitHub project, or capture a YouTube video to add to my queue later in the night, I want to get the information in to Emacs as quickly as possible. For anything that needs longer work or more thinking or will be done at a later date, I put it in to my Read It Later bag.

This page is a CCE module based on two sources12 from the WWW (Probably one of Sacha's Emacs weeklies) and the org-roam documentation.

org-roam provides native functionality for this in the org-roam-protocol library. I create a second capture template that just uses plain old org-protocol on its own to quickly capture YouTube videos or other things I wish to watch.

This desktop file creates an org-protocol:// URL handler and forwards the URL to emacsclient. the roam-ref org-protocol handler will create a document in the wiki, with the title and ROAMREF property keyword filled in. The javascript at the end is saved as bookmark in my Firefox toolbar and can be bound to keyboard with a thing like ShortcutKey2URL (WebExtensions) or the bookmarklets can be placed in the Bookmarks toolbar or to use the Awesomebar as a CLI.

{ pkgs, ... }:

{
  home.packages = [
    (pkgs.makeDesktopItem {
      name = "org-protocol";
      desktopName = "Emacs org-protocol handler";
      exec = "emacsclient -c %u";
      terminal = false;
      categories = ["System"];
      mimeTypes = ["x-scheme-handler/org-protocol"];
    })
  ];

  programs.firefox.profiles.default.settings = {
    "network.protocol-handler.expose.org-protocol" = true;
    "network.protocol-handler.warn-external.org-protocol" = false;
    "security.external_protocol_requires_permission" = false; # sickos.jpg
  }; 
}

DONE figure out why Firefox on Nix always asks if it's okay to open external on each domain despite warn-external set

Capture Templates

org-roam reference capture

Wiring it all together, the org-roam reference capture:

(with-eval-after-load 'org-roam
  (require 'org-roam-protocol)
  (add-to-list 'org-roam-capture-ref-templates
               `("r" "reference" plain 
                 ,(s-join
                   "\n"
                   '("#+BEGIN_QUOTE"
                     "${body}"
                     "#+END_QUOTE"
                     ""
                     "%?"))
                 :unnarrowed t
                 :if-new
                 (file+head
                  "%<%Y%m%d%H%M%S>-${slug}.org"
                  ,(s-join
                    "\n"
                    '(":PROPERTIES:"
                      ":roam_refs: ${ref}"
                      ":END:"
                      "#+title: ${title}"
                      "#+filetags: Archive"
                      "[[file:archive.org][Archive]]"))))))
javascript:location.href = 'org-protocol://roam-ref?template=r&ref='+ encodeURIComponent(location.href) + '&title=' + encodeURIComponent(document.title) + '&body=' + encodeURIComponent(window.getSelection())

org-roam capture to clock

(with-eval-after-load 'org-capture
  (add-to-list 'org-capture-templates
               `("R" "Capture to Clock" entry
                 (clock)
                 ,(s-join "\n"
                          '("* %a %?      :Archive:"
                            ":PROPERTIES:"
                            ":ROAM_REF: %l"
                            ":END:"
                            "%U"))
                 :unnarrowed
                 :jump-to-captured)))
javascript:location.href='org-protocol://capture?template=R&url='+encodeURIComponent(location.href)+'&title='+ encodeURIComponent(document.title)+'&body='+ encodeURIComponent(window.getSelection())

Videos queue capture

And one for capturing videos in to a watch queue.

(with-eval-after-load 'org-roam
  (require 'org-roam-protocol)
  (add-to-list 'org-roam-capture-ref-templates
               `("O" "org-protocol video" plain 
                 ,(s-join
                   "\n"
                   '("* NEXT [[${ref}][${title}]]"
                     ":PROPERTIES:"
                     ":roam_refs: ${ref}"
                     ":END:"
                     ""
                     "${body}"))
                 :if-new
                 (file+head
                  "~/org/Video.org"
                  ,(s-join
                    "\n"
                    '("#+title: Video Queue"
                      "#+ARCHIVE: video_archive.org::"
                      "#+filetags: Archive"))))))
javascript:location.href = 'org-protocol://roam-ref?template=O&ref='+ encodeURIComponent(location.href) + '&title=' + encodeURIComponent(document.title) + '&body=' + encodeURIComponent(window.getSelection())

NEXT Interesting Github Projects collects projects I'm likely to want to use or peruse some day

need to just make this use regular org-protocol capture templates….. or figure out how to use org-roam-capture-ref-templates better…

(with-eval-after-load 'org-roam
  (require 'org-roam-protocol)
  (add-to-list 'org-roam-capture-ref-templates
               `("P" "org-protocol project bookmark" entry
                 ,(s-join
                   "\n"
                   '("* [[${ref}][${title}]]"
                     ":PROPERTIES:"
                     ":roam_refs: ${ref}"
                     ":END:"
                     ""
                     "${body} %?"))
                 :if-new
                 (file+head
                  "~/org/interesting_github_projects.org"
                  ,(s-join
                    "\n"
                    '("#+title: Interesting GitHub Projects"
                      "#+filetags: Archive Topic"))))))
javascript:location.href='org-protocol://capture?template=P&url='+encodeURIComponent(location.href)+'&title='+ encodeURIComponent(document.title)+'&body='+ encodeURIComponent(window.getSelection())

People capture

And one for quickly capturing Facebook friends' list in to People pages

(with-eval-after-load 'org-roam
  (require 'org-roam-protocol)
  (add-to-list 'org-roam-capture-ref-templates
               `("p" "person" plain 
                 ,(s-join
                   "\n"
                   '("[[file:People.org][People]]"
                     "#+BIRTHDAY: %^{Birthday}t%?"
                     "#+BEGIN_QUOTE"
                     "${body}"
                     "#+END_QUOTE"))
                 :unnarrowed t
                 :if-new
                 (file+head
                  "%<%Y%m%d%H%M%S>-${slug}.org"
                  ,(s-join
                    "\n"
                    '(":PROPERTIES:"
                      ":roam_refs: ${ref}"
                      ":END:"
                      "#+title: ${title}"
                      "#+filetags: Person"))))))
javascript:location.href = 'org-protocol://roam-ref?template=p&ref='+ encodeURIComponent(location.href) + '&title=' + encodeURIComponent(document.title) + '&body=' + encodeURIComponent(window.getSelection())

Thread capture

And one for quickly capturing Twitter Threads and posts in to my Archive

(with-eval-after-load 'org-roam
  (require 'org-roam-protocol)
  (add-to-list 'org-roam-capture-ref-templates
               `("t" "thread" plain 
                 ,(s-join
                   "\n"
                   '("[[id:d17a9ccf-0bfe-426e-85b3-d15771d3ee03][Archive]] [[id:threads][Thread]] about $?"
                     "#+BEGIN_QUOTE"
                     "${body}"
                     "#+END_QUOTE"))
                 :unnarrowed t
                 :if-new
                 (file+head
                  "%<%Y%m%d%H%M%S>-${slug}.org"
                  ,(s-join
                    "\n"
                    '(":PROPERTIES:"
                      ":roam_refs: ${ref}"
                      ":END:"
                      "#+title: ${title}"
                      "#+filetags: :Archive:Thread:"))))))

This one extracts the quoted tweet out of the title:

javascript:location.href = 'org-protocol://roam-ref?template=t&ref='+ encodeURIComponent(location.href) + '&title=' + encodeURIComponent(document.title.match(/"(.*)"/)[0].substring(0,64)) + '&body=' + encodeURIComponent(window.getSelection().toString() || document.title.match(/"(.*)"/))

Provide the ELisp feature at the end

This is a stub…

(provide 'cce/org-protocol)

  1. https://cestlaz.github.io/post/using-emacs-70-org-protocol/↩︎

  2. https://org-roam.readthedocs.io/en/develop/roam_protocol/↩︎