Is there a way to have org-mode automatically set the description from the html page's when inserting a link into org-mode?
2 Answers
There's a package called org-cliplink precisely for this.
Alternatively, if you'd like to calculate your own title based on DOM queries instead of using org-cliplink's simple logic that just looks at the <title>
, here's a simplified version of how I do this in my config:
(use-package dash :ensure t)
(use-package s :ensure t)
(defun my-org-link-description (url &rest _)
"Return link description for URL in the format I use in my notes."
(require 'cl-lib)
(require 'dash)
(require 's)
(require 'dom)
(let* ((url ; Use old.reddit.com (the new version is a huge JavaScript mess).
(replace-regexp-in-string
"^\\(https?://\\)\\(?:www\\.\\)?\\(reddit.com/r/.+\\)$"
"\\1old.\\2" url))
(html-buffer (url-retrieve-synchronously url))
(dom (with-current-buffer html-buffer
(libxml-parse-html-region (point-min) (point-max) url t)))
(title (s-trim (dom-text (car (dom-by-tag dom 'title)))))
(parsed-url (url-generic-parse-url url))
(host (url-host parsed-url))
(domain-levels ; E.g. '("com" "ycombinator.com" "news.ycombinator.com")
(nreverse (-reduce-r-from
(lambda (new-part accum)
(cons (if accum
(concat new-part "." (car accum))
new-part)
accum))
nil (s-split "\\." host))))
(path (url-filename parsed-url))
match-1 match-2) ; Temporary variables for later use.
(cond
;; Reddit comment thread.
((and (string-equal "reddit.com" (nth 1 domain-levels))
(setq match-1 (s-match "^/r/\\([^/]+\\)/comments/" path))
(setq match-2 (s-match "^\\([^ ]+\\) comments on \\(.+\\)$" title)))
(let ((subreddit (nth 1 match-1))
(commenter (nth 1 match-2))
(top-level-title (nth 2 match-2)))
(concat "Reddit /r/" subreddit ": " commenter " on " top-level-title)))
;; Hacker News comment thread.
((and (string-equal "news.ycombinator.com" (nth 2 domain-levels))
(setq match-1 (dom-by-tag (dom-by-class dom "storyon") 'a)))
(let ((parent-title (dom-text (car match-1)))
(user (dom-text (car (dom-by-class dom "hnuser")))))
(concat "Hacker News: " user " on " parent-title)))
;; Pages whose title probably contains the website's name.
((setq match-1 (s-match "^\\(.*\\) [-–|:•#·»←] \\(.*\\)$" title))
(cl-destructuring-bind (_ first-part second-part) match-1
(let* ((first-longer-p (>= (length first-part) (length second-part)))
(longer (if first-longer-p first-part second-part))
(shorter (if first-longer-p second-part first-part)))
(concat shorter ": " longer))))
;; Others.
(t title))))
(defun my-org-insert-link ()
"Insert link in the format I use in my notes."
(interactive)
(let ((org-make-link-description-function #'my-org-link-description))
(call-interactively #'org-insert-link)))
(with-eval-after-load 'org
(bind-key "C-c M-l" #'my-org-insert-link org-mode-map))
In addition to org-cliplink
I find the asamuzaK/url2clipboard browser extension really useful and actually use it more than org-cliplink
as I can bind the org-mode copying to a key sequence (I use Alt-o
) which places an org-formatted link in the clipboard then in Emacs its your usual C-y
to paste into the buffer.
The browser extension is available for Firefox and Chrome based browsers.